aboutsummaryrefslogtreecommitdiff
path: root/synchronise.py
diff options
context:
space:
mode:
Diffstat (limited to 'synchronise.py')
-rw-r--r--synchronise.py231
1 files changed, 231 insertions, 0 deletions
diff --git a/synchronise.py b/synchronise.py
new file mode 100644
index 000000000..305583bd8
--- /dev/null
+++ b/synchronise.py
@@ -0,0 +1,231 @@
+import os,sys,shutil,re,stat
+
+from optparse import OptionParser
+
+usage = "usage: %prog [options] <SrcDir> <DestDir>"
+parser = OptionParser(usage=usage)
+parser.add_option("-n", "--donothing", action='store_true', dest="DoNothing", default=False, help="Do not copy the files.")
+parser.add_option("", "--extension", action='store', dest="Extension", default=None, help="Copy only files with this extension.")
+parser.add_option("-y", "--ask", action='store_true', dest="Ask", default=False, help="Ask confirmation to copy.")
+parser.add_option("-a", "--ask-file", action='append', dest="FilesToConfirm", default=[], help="Ask confirmation to copy for this speicific file (only useful if -y is not used).")
+parser.add_option("-d", "--delete-file_re", dest="FilesToDeleteRe", default="", help="Regular expression of files to delete.")
+parser.add_option("-s", "--no-skip-svn", dest="NoSkipSvn", action='store_true', default=False, help="Do not Skip .svn directories.")
+parser.add_option("-g", "--no-skip-git", dest="NoSkipGit", action='store_true', default=False, help="Do not Skip .git directories.")
+parser.add_option("-e", "--del-exist-only-dest", dest="DelExistOnlyDest", action='store_true', default=False, help="Delete files that exist only in the destination directory.")
+parser.add_option( "" , "--skip-dir", dest="SkipDirs", action='append', default=[], help="Adds a directory name to skip.")
+parser.add_option( "" , "--skip-file", dest="SkipFiles", action='append', default=[], help="Adds a file name to skip.")
+
+(g_Options, g_Args) = parser.parse_args()
+
+if g_Options.FilesToDeleteRe:
+ try:
+ g_FilesToDelete=re.compile(g_Options.FilesToDeleteRe,re.I)
+ except:
+ print 'Wrong regular expression:',g_Options.FilesToDeleteRe
+ sys.exit(1)
+else:
+ g_FilesToDelete=None
+
+if len(g_Args)!=2:
+ parser.error("Wrong number of arguments: "+repr(g_Args))
+ sys.exit(1)
+
+g_FilesToConfirm={}
+for File in g_Options.FilesToConfirm:
+ g_FilesToConfirm[File]=1
+
+g_DirsToSkip={}
+for Dir in g_Options.SkipDirs:
+ g_DirsToSkip[Dir]=1
+
+g_FilesToSkip={}
+for File in g_Options.SkipFiles:
+ g_FilesToSkip[File]=1
+
+g_Ask=g_Options.Ask
+g_DoNothing=g_Options.DoNothing
+g_NoSkipSvn=g_Options.NoSkipSvn
+g_NoSkipGit=g_Options.NoSkipGit
+
+g_WriteMask=stat.S_IWUSR|stat.S_IWGRP|stat.S_IWOTH
+
+SrcDir=g_Args[0]
+DestDir=g_Args[1]
+
+if g_Options.Extension:
+ g_Extre=re.compile('.*\.%s$'%g_Options.Extension,re.I)
+else:
+ g_Extre=None
+
+###############################################################################
+def SkipDir(SrcDir,File):
+ Ret = g_DirsToSkip.has_key(File)
+ if SrcDir[1]==':':
+ SrcDir=SrcDir[3:]
+ while not Ret and SrcDir:
+ SrcDir,Part=os.path.split(SrcDir)
+ File=os.path.join(Part,File)
+ Ret = g_DirsToSkip.has_key(File)
+ return Ret
+
+###############################################################################
+def DeleteFiles(SrcFile,DestFile):
+ print 'Deleting %s'%(SrcFile)
+ os.remove(SrcFile)
+ print 'Deleting %s'%(DestFile)
+ try:
+ os.remove(DestFile)
+ except:
+ print DestFile,'does not exist'
+
+###############################################################################
+#characters=['|','/','-','\\']
+#chariter=iter(characters)
+#def PrintBusy():
+# global characters
+# global chariter
+#
+# try:
+# char=chariter.next()
+# except StopIteration:
+# chariter=iter(characters)
+# char=chariter.next()
+#
+# sys.stdout.write(char)
+# sys.stdout.write(chr(8))
+count=0
+def PrintBusy():
+ global count
+ count+=1
+ item=str(count)
+ sys.stdout.write(item)
+ sys.stdout.write(chr(8)*len(item))
+###############################################################################
+
+if not os.path.isdir(DestDir):
+ print DestDir,"is not a directory"
+ sys.exit(1)
+
+def FileDiff(SrcFile,DestFile):
+ try:
+ Src=open(SrcFile,'rb')
+ Dest=open(DestFile,'rb')
+ while 1:
+ SrcLine=Src.read(4096)
+ DestLine=Dest.read(4096)
+ if SrcLine!=DestLine:
+ return 1
+ if not SrcLine:
+ return 0
+ except Exception,Object:
+ #print "Exception occured"
+ #print Object
+ return 1
+
+g_Dot=0
+def SynchroniseDir(SrcDir,DestDir):
+ global g_Dot
+ SrcFiles=os.listdir(SrcDir)
+ if g_Options.DelExistOnlyDest:
+ DstFiles=os.listdir(DestDir)
+ for File in DstFiles:
+ DestFile=os.path.join(DestDir,File)
+ try:
+ Index=SrcFiles.index(File)
+ except ValueError:
+ if os.path.isdir(DestFile):
+ if not g_NoSkipSvn and File=='.svn':
+ continue # Skip svn administration dirs
+ if not g_NoSkipGit and File=='.git':
+ continue # Skip svn administration dirs
+ if SkipDir(SrcDir,File):
+ continue
+ print 'Deleting directory',DestFile
+ shutil.rmtree(DestFile)
+ else:
+ if g_FilesToSkip.has_key(File):
+ continue
+ print 'Deleting file',DestFile
+ os.remove(DestFile)
+
+ for File in SrcFiles:
+ SrcFile=os.path.join(SrcDir,File)
+ DestFile=os.path.join(DestDir,File)
+ if os.path.isdir(SrcFile):
+ if not g_NoSkipSvn and File=='.svn':
+ continue # Skip svn administration dirs
+ if not g_NoSkipGit and File=='.git':
+ continue # Skip svn administration dirs
+ if SkipDir(SrcDir,File):
+ continue
+ if not os.path.isdir(DestFile):
+ if g_Dot:
+ sys.stdout.write('\n')
+ g_Dot=0
+ if not g_DoNothing:
+ if g_Ask:
+ sys.stdout.write("Create directory %s? (y/n)"%DestFile)
+ if sys.stdin.read(1)=='y':
+ print "Creating dir",DestFile
+ os.mkdir(DestFile)
+ sys.stdin.read(1)
+ else:
+ print "Creating dir",DestFile
+ os.mkdir(DestFile)
+ else:
+ print "Creating dir",DestFile
+ SynchroniseDir(SrcFile,DestFile)
+ else:
+ if g_Extre and not g_Extre.search(File):
+ continue
+ if g_FilesToSkip.has_key(File):
+ continue
+ if g_FilesToDelete:
+ if g_FilesToDelete.search(File):
+ if g_Dot:
+ sys.stdout.write('\n')
+ g_Dot=0
+ DeleteFiles(SrcFile,DestFile)
+ continue
+ if FileDiff(SrcFile,DestFile):
+ #if os.system('fc /b "%s" "%s" >& nul'%(SrcFile,DestFile)):
+ if g_Dot:
+ sys.stdout.write('\n')
+ g_Dot=0
+ if not g_DoNothing:
+ if g_Ask or g_FilesToConfirm.has_key(File):
+ sys.stdout.write("Copy/Merge %s to %s? (y/n/m/d)"%(SrcFile,DestFile))
+ R=sys.stdin.read(1)
+ if R=='y':
+ print '%s -> %s'%(SrcFile,DestFile)
+ shutil.copyfile(SrcFile,DestFile)
+ elif R=='m':
+ print '%s -> %s'%(SrcFile,DestFile)
+ os.system('fcg "%s" "%s"'%(SrcFile,DestFile))
+ elif R=='d':
+ DeleteFiles(SrcFile,DestFile)
+ sys.stdin.read(1)
+ else:
+ print '%s -> %s'%(SrcFile,DestFile)
+ # check if the file is read-only
+ try:
+ Mode=os.stat(DestFile).st_mode
+ except OSError:
+ Mode=g_WriteMask
+ if not g_WriteMask&Mode:
+ ReadOnly=True
+ os.chmod(DestFile,Mode|g_WriteMask)
+ else:
+ ReadOnly=False
+ shutil.copyfile(SrcFile,DestFile)
+ if ReadOnly:
+ os.chmod(DestFile,Mode & (~g_WriteMask) )
+
+ else:
+ print '%s -> %s'%(SrcFile,DestFile)
+ else:
+ PrintBusy()
+ g_Dot=1
+
+SynchroniseDir(SrcDir,DestDir)
+sys.stdout.write("\n")