import py import vsync rsync = py.path.local.sysfind('rsync') def debug(msg): """ report debug output. """ pass # print "DEBUG:", msg def warn(msg): """ report warnings. """ print "WARN:", msg def info(msg): """ report warnings. """ print "INFO:", msg def error(msg): """ report errors. """ print "ERROR:", msg def getdatepaths(backupdir, name): l = [] for x in backupdir.listdir(): if x.basename.startswith(name): try: date = vsync.parsedate(x.basename[len(name)+1:]) except ValueError: warn("parse-error (ignore) %s" % str(x)) continue l.append(vsync.DatedPath(x, date)) return l def cleanupbyconf(cfg, date): datepaths = getdatepaths(py.path.local(cfg.backupdir), cfg.name) l = [] for x in ('years', 'months', 'weeks', 'days'): value = int(getattr(cfg, x, 2)) l.append((x, value)) kw = dict(l) remaining, removable = vsync.sortout(date, datepaths, **kw) for x in removable: info("renaming and then removing %s" % x.path.basename) y = x.path + '_temp' x.path.rename(y) y.remove() def make_new_datepath(backupdir, name, date): datestring = vsync.unparsedate(date) p = backupdir.join("%s-%s" %(name, datestring)) dp = vsync.DatedPath(p, date) assert not dp.path.check() return dp def getyoungest(backupdir, name): l = getdatepaths(backupdir, name) l.sort() if l: return l[-1] def syncbyconf(cfg, date): """ rsync according to the given specification. """ backupdir = py.path.local(cfg.backupdir) assert backupdir.dirpath().check() backupdir.ensure(dir=1) name = cfg.name youngestpath = getyoungest(backupdir, name) dp = make_new_datepath(backupdir, name, date) if youngestpath: assert youngestpath.date < dp.date, "date confusion!" source = cfg.source tempdest = dp.path + '_temp' if '@' in str(source) or ':' in str(source): compress = 'z' else: compress = '' options = ['--delete', '--numeric-ids', '-ax' + compress, ] exclude = getattr(cfg, 'exclude', None) if exclude: l = [("--exclude=%s" % x) for x in exclude.split()] options.extend(l) ssh = getattr(cfg, 'ssh', None) if ssh: l = ["-e", str(ssh)] options.extend(l) if youngestpath: options.append("--link-dest=%s" % str(youngestpath.path)) options.extend([str(source), str(tempdest)]) debug("executing: rsync " + " ".join(options)) try: info("starting sync to %s from %s" %(tempdest.basename, source)) rsync.sysexec(*options) except py.process.cmdexec.Error, ex: s = str(ex) if ex.status == 24 or ex.status == 23: warn("flakey: rsync %s\n%s" % (" ".join(options), s)) else: error("FAILED rsync %s \n%s" % (" ".join(options), s)) if tempdest.check(): warn("removing temp directory %s" % tempdest) tempdest.remove() raise tempdest.rename(dp.path) info("sucessfully synced %s from %s" % (dp.path.basename, source))