import glob import os import subprocess import sys import time from collections import deque server = False def msg(data): print("\n\033[1;34m:: \033[1;37m{}\033[0m".format(data)) def sync(source, dest, ignoreFile=None, verbose=False): """Synchronizes data between a source and a target.""" args = ["rsync", "--delete", "-zHaAXS", source, dest] if ignoreFile is not None: args.append("--exclude-from="+ignoreFile) if verbose: args[2] += "v" return subprocess.call(args) def getTab(name="", elements=[]): """Get entries""" tabData = {} if name == "": tabFile = os.path.join(os.environ["HOME"], ".autoSync.tab") else: tabFile = os.path.join(os.environ["HOME"], ".autoSync.{}.tab".format(name)) with open(tabFile, "r") as f: for line in f.readlines(): name, src, dst = filter(lambda i: len(i) > 0, line.rstrip("\n").split("\t")) tabData[name] = (os.path.expandvars(os.path.expanduser(src)), os.path.expandvars(os.path.expanduser(dst))) if len(elements) < 1: elements = list(tabData.keys()) for itemName in elements: if itemName in tabData.keys(): yield (itemName, *tabData[itemName]) def getTimestamp(source, dest): """Get source and destination timestamps""" sourceTS = os.path.join(source, ".lastsync") destTS = os.path.join(dest, ".lastsync") if sync(sourceTS, "/tmp/source.ts") != 0: with open("/tmp/source.ts", "w") as f: f.write("0") if sync(destTS, "/tmp/dest.ts") != 0: with open("/tmp/dest.ts", "w") as f: f.write("0") with open("/tmp/source.ts", "r") as sourceF, open("/tmp/dest.ts", "r") as destF: return (float(sourceF.read()), float(destF.read())) def run(): global server args = deque(sys.argv[1:]) if len(args) < 1: print("{0} @ – list available tab names\n{0} @@tabname – list available entries under tabname\n{0} @tabname entry1 entry2 – synchronizes entry1 and entry2 from tabname\n{0} @tabname – synchronizes every entry found in tabname\n{0} -s @[tabname][ entry1[ entry2[ …]]] – synchronizes in server mode (ie don't refresh timestamp)".format(os.path.basename(sys.argv[0]))) return firstArg = args.popleft() if firstArg == "-s": server = True firstArg = args.popleft() if firstArg.startswith("@"): if firstArg.startswith("@@"): # list available entries for tabfile elts = list(getTab(name=firstArg.lstrip("@"))) maxLenName = max(len(line[0]) for line in elts) maxLenSrc = max(len(line[1]) for line in elts) maxLenDst = max(len(line[1]) for line in elts) msg("Available entries for tabfile {}:".format(firstArg.lstrip("@"))) print("\n\033[1;37m%-*s %-*s %-*s\033[0m" % (maxLenName, "Name", maxLenSrc, "Source", maxLenDst, "Target")) for ename, esrc, edst in elts: print("%-*s %-*s %-*s" % (maxLenName, ename, maxLenSrc, esrc, maxLenDst, edst)) elif firstArg == "@": # lists all available tabFiles files = glob.glob(os.path.join(os.environ["HOME"], ".autoSync.*.tab")) msg("Available tables:") print("\n".join("– " + os.path.basename(fileName).split(".", 2)[2][:-4] for fileName in files)) else: firstArg = firstArg.lstrip("@") for name, src, dst in getTab(firstArg, args): srcT, dstT = getTimestamp(src, dst) ignoreFile = os.path.join(src, ".ignore.lst") if not os.path.exists(ignoreFile): ignoreFile = None if srcT >= dstT: msg("[{} @ {}] sending data to destination".format(name, firstArg)) if not server: with open(os.path.join(src, ".lastsync"), "w") as f: f.write(str(time.time())) sync(src, dst, ignoreFile, True) else: msg("[{} @ {}] gathering data from destination".format(name, firstArg)) sync(dst, src, ignoreFile, True) if not server: with open(os.path.join(src, ".lastsync"), "w") as f: f.write(str(time.time())) if os.path.exists("/tmp/source.ts"): os.unlink("/tmp/source.ts") if os.path.exists("/tmp/dest.ts"): os.unlink("/tmp/dest.ts")