X-Git-Url: https://git.sthu.org/?p=sitarba.git;a=blobdiff_plain;f=shbackup.py;h=e1f038d559708119baa96f8b2522ee4397ea68b0;hp=0aedc6f623589bdc79b872245ec09f744bb19dec;hb=212160362993410e7ee742a7f6546ef3d6d171a3;hpb=391d27ec791eed92fa8baa8a398245bf15684680 diff --git a/shbackup.py b/shbackup.py index 0aedc6f..e1f038d 100755 --- a/shbackup.py +++ b/shbackup.py @@ -9,6 +9,41 @@ import subprocess import random, re +Mode = ["full", "incr", "diff"] + +Epoch = { "hour" : datetime.timedelta(0, 3600), \ + "day" : datetime.timedelta(1), \ + "week" : datetime.timedelta(7), \ + "month" : datetime.timedelta(30), \ + "year" : datetime.timedelta(365) } + +class Backup: + """A single backup has a date, an epoch and a mode.""" + + def __init__(self, date, epoch, mode): + self.date = date + self.epoch = epoch + self.mode = mode + + def __str__(self): + return "[date: " + self.date.ctime() + \ + ", epoch: " + self.epoch + \ + ", mode: " + self.mode + "]" + + @staticmethod + def getDirName(date, epoch, mode): + """Get directory name of backup by given properties.""" + return date.strftime("%Y%m%d-%H%M") + "-" + epoch + "-" + mode + + @staticmethod + def isBackupDir(dirname): + """Is directory a backup directory?""" + p = re.compile(r'^\d\d\d\d\d\d\d\d-\d\d\d\d-\w+-\w+$') + return p.match(dirname) + + + + class Config: """Encapsules the configuration for the backup program.""" @@ -46,11 +81,13 @@ class Config: ", keeps: " + str(self.epochkeeps) + \ ", modes: " + str(self.epochmodes) + \ ", exclpatterns: " + str(self.exclpatterns) + \ - ", sets: " + str([str(s) for s in self.sets]) + "]"; + ", sets: " + str([str(s) for s in self.sets]) + "]" def read(self, filename): """Read configuration from file""" + if not os.path.isfile(filename): + raise Config.ReadException("No file '" + filename + "'.") config = configparser.RawConfigParser() config.read(filename) @@ -123,39 +160,6 @@ class Config: self.lastchecksum = None -Mode = ["full", "incr", "diff"] - -Epoch = { "hour" : datetime.timedelta(0, 3600), \ - "day" : datetime.timedelta(1), \ - "week" : datetime.timedelta(7), \ - "month" : datetime.timedelta(30), \ - "year" : datetime.timedelta(365) } - -class Backup: - """A single backup has a date, an epoch and a mode.""" - - def __init__(self, date, epoch, mode): - self.date = date - self.epoch = epoch - self.mode = mode - - def __str__(self): - return "[date: " + self.date.ctime() + \ - ", epoch: " + self.epoch + \ - ", mode: " + self.mode + "]" - - @staticmethod - def getDirName(date, epoch, mode): - """Get directory name of backup by given properties.""" - return date.strftime("%Y%m%d-%H%M") + "-" + epoch + "-" + mode - - @staticmethod - def isBackupDir(dirname): - """Is directory a backup directory?""" - p = re.compile(r'^\d\d\d\d\d\d\d\d-\d\d\d\d-\w+-\w+$') - return p.match(dirname) - - class BackupManager: """List and create backups""" @@ -171,14 +175,14 @@ class BackupManager: basedir = self.conf.directory dirs = os.listdir(basedir) # Filter directories - return filter( lambda d: os.path.isdir(os.path.join(basedir, d)), dirs) + return [ d for d in dirs if os.path.isdir(os.path.join(basedir, d)) ] def listOldBackups(self): """Returns a list of old backups.""" backups = [] - for entry in filter(Backup.isBackupDir, self.listAllDirs()): + for entry in [ b for b in self.listAllDirs() if Backup.isBackupDir(b) ]: [strdate, strtime, epoch, mode] = entry.split("-") if not epoch in Epoch.keys(): @@ -206,7 +210,7 @@ class BackupManager: continue # Get backups of that epoch - byepoch = list(sorted(filter( lambda b: b.epoch==e, backups), \ + byepoch = list(sorted( [ b for b in backups if b.epoch==e], \ key=lambda b: b.date)) # If there are any, determine the latest @@ -278,7 +282,7 @@ class BackupManager: mode = self.conf.epochmodes[epoch] print("Making a backup. Epoch: " + epoch + ", mode: " + mode) - oldfullbackups = list(filter(lambda b: b.mode=="full", oldbackups)) + oldfullbackups = [ b for b in oldbackups if b.mode == "full" ] # No old full backups existing if mode != "full" and len(oldfullbackups)==0: @@ -324,12 +328,13 @@ class BackupManager: def prune(self): """Prune old backup files""" - noBackupDir = lambda d: not Backup.isBackupDir(d) - dirs = list(filter(noBackupDir, self.listAllDirs())) + # Collect all directories not matching backup name + dirs = [ d for d in self.listAllDirs() if not Backup.isBackupDir(d) ] + # Get all directories which are outdated backups = self.listOldBackups() - byepoch = { e : list(reversed(sorted(filter(lambda b: b.epoch==e, backups), \ - key=lambda b : b.date))) for e in Epoch } + byepoch = { e : list(sorted( [ b for b in backups if b.epoch == e ], \ + key=lambda b : b.date, reverse=True)) for e in Epoch } for e in byepoch: keep = self.conf.epochkeeps[e] old = byepoch[e][keep:] @@ -344,22 +349,57 @@ class BackupManager: print(" " + d) basedir = self.conf.directory - yesno = input("Remove listed entries? [y,N] ") + yesno = input("Remove listed entries? [y, N] ") if yesno == "y": for d in dirs: - shutil.rmtree(os.path.join(basedir,d)) + shutil.rmtree(os.path.join(basedir, d)) + + +def printUsage(): + """Print --help text""" + + print("shbackup - a simple backup solution.") + print("") + print("Usage:") + print(" " + sys.argv[0] + " [-C ") + print(" " + sys.argv[0] + " --help") + print("") + print("Options:") + print(" -C default: /etc/shbackup.conf") if __name__ == "__main__": - conffn = "shbackup.conf" + conffn = "/etc/shbackup.conf" + + i = 0 + while i < len(sys.argv)-1: + i += 1 + opt = sys.argv[i] + + if opt in ["-h", "--help"]: + printUsage() + exit(0) + + elif opt in ["-C", "--config"]: + i += 1 + conffn = sys.argv[i] + continue + + else: + print("Unknown option: " + opt) + exit(1) - if len(sys.argv) > 1: - conffn = sys.argv[1] + try: + man = BackupManager(conffn) + man.backup() + man.prune() - man = BackupManager(conffn) - man.backup() - man.prune() + except Config.ReadException as e: + print("Error reading config file: ", end="") + for a in e.args: + print(a, end=" ") + print()