#!/usr/bin/env python ## @file csbackgen.py # @brief Generate checksum files. # # ----------------------------------------------------------------------------- # # $Id$ # @author Daniel Armbruster # \date 11/09/2011 # # Purpose: Generate checksum files. # # ---- # This file is part of csback. # # csback is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # csback is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with csback. If not, see . # ---- # # Copyright (c) 2012 by Daniel Armbruster # # REVISIONS and CHANGES # 02/01/2012 V0.1 Daniel Armbruster # 05/01/2012 V0.2 added logging flag to enable a file logging mechanism # 10/01/2012 V0.3 introduced --hash flag # # ============================================================================= import getopt import os import sys import re import pwd import logging import csfile import csbacklog __version__ = "V0.1" __subversion__ = "$Id$" __license__ = "GPLv2" __author__ = "Daniel Armbruster" __copyright__ = "Copyright (c) 2012 by Daniel Armbruster" # ----------------------------------------------------------------------------- class Error(Exception): def __init__(self, msg): self.msg = msg def display(self): sys.stderr.write("csbackgen (ERROR): " + self.msg + "\n") class Usage(Error): def display(self): usage_text = "Version: "+__version__+"\nLicense: "+__license__+ \ "\n"+__subversion__+"\nAuthor: "+__author__+ """ Usage: csbackgen [-v|--verbose] [-e REGEX [-e REGEX [...]]] [-R|--notrecursive] [-d|--debug] [-f|--followlinks] [-t|--target DIR] [-l|--logging] [--hash ARG] PATH or: csbackgen -h|--help\n""" sys.stderr.write("csbackgen: " + self.msg + "\n") sys.stderr.write(usage_text) # ----------------------------------------------------------------------------- def help(): """ Printing helptext to stdout. """ help_text = "Version: "+__version__+"\nLicense: "+__license__+"\n"+ \ __subversion__+"\nAuthor: "+__author__+""" Usage: csbackgen [-v|--verbose] [-e REGEX [-e REGEX [...]]] [-R|--notrecursive] [-d|--debug] [-f|--followlinks] [-t|--target ROOTDIR] [-l|--logging] [--hash ARG] PATH or: csbackgen -h|--help ------------------------------------------------------------------------------- -v|--verbose Be verbose. -h|--help Display this help. -e REGEX While generating a checksumfile exclude files matching REGEX(s). -R|--notrecursive Do not generate checksumfiles for subdirectories of PATH. -d|--debug Debug mode. Be really verbose. -f|--followlinks Follow symbolic links. Only available if option -R is not set. Note that this option can lead to infinite recursion. -t|--target ROOTDIR Root target directory for checksumfile. The checksumfile will be put to the appropiated location as the files had in PATH or rather Path's subdirectories. So target must have the same subdirectory structure as PATH. -l|--logging Switch on logging to files. Logfiles will be located in ~/.csback/log/. --hash ARG Set the hash function algorithm. Valid values are: sha224, sha256, sha384, sha512. (default: sha256) PATH Path to generate checksumfile(s) for including its subdirectories if option '-R' is not set. ------------------------------------------------------------------------------- csbackgen.py will either generate a checksumfile if still no checksumfile is available or in case there is an existing checksumfile csbackgen.py will append the not yet registered files to the current checksumfile. In the latter case csbackgen.py is working in its update mode. Notice that in case PATH contains subdirectories and either option '-R' is set or the subdirectory is excluded by a matching regular expression every subdirectory will contain a checksumfile.\n""" sys.stdout.write(help_text) # ----------------------------------------------------------------------------- # global variables VALIDHASHES = ['sha224', 'sha256', 'sha384', 'sha512'] # ----------------------------------------------------------------------------- def main(argv=None): # configure logger logger = csbacklog.CsbackLog('csbackgen') console = logging.StreamHandler() console.setFormatter(logging.Formatter( \ '%(name)-8s [%(lineno)d]: %(levelname)-8s %(message)s')) if argv is None: argv = sys.argv try: try: opts, args = getopt.getopt(argv[1:], "vhe:Rdft:l", ["help", "verbose", \ "notrecursive", "debug", "followlinks", "target=", "logging", \ "hash="]) except getopt.GetoptError as err: raise Usage(err.msg) verbose = False debugMode = False notRecursive = False followLinks = False regexes = [] targetSet = False enableLogging = False hashfunc = 'sha256' for opt, arg in opts: if opt in ("-v", "--verbose"): verbose = True console.setLevel(logging.INFO) elif opt in ("-h", "--help"): sys.exit(help()) elif opt in ("-R", "--notrecursive"): notRecursive = True elif opt in ("-e"): regexes.append(arg) elif opt in ("-d", "--debug"): debugMode = True console.setLevel(logging.DEBUG) elif opt in ("-f", "--followlinks"): followLinks = True elif opt in ("-t", "--target"): targetSet = True targetDirectory = arg.rstrip(os.sep)+os.sep elif opt in ("-l", "--logging"): logger.configure() elif opt in ("--hash",): if arg in VALIDHASHES: hashfunc = arg else: raise Usage("Invalid argument (hash).") else: raise Usage("Unhandled option chosen.") if verbose or debugMode: logger.addHandler(console) # fetch arguments if 1 == len(args): srcpath = str(args[0]).rstrip(os.sep)+os.sep else: raise Usage("Invalid argument.") if not os.path.isdir(srcpath): raise Usage("PATH not a valid directory.") # major part logger.getLogger().debug("Start collecting subdirectories ...") dirs = [srcpath] if not targetSet: targetDirectory = srcpath targetdirs = dirs else: targetdirs = [targetDirectory] if not os.path.isdir(targetDirectory): raise Usage("Target directory not a valid directory.") # recursive if not notRecursive: dirs.extend(csfile.getSubDirectories(srcpath, regexes, followLinks)) if targetSet: targetdirs.extend([dir.replace(dirs[0],targetDirectory,1) \ for dir in dirs[1:]]) pathes = list(zip(targetdirs, dirs)) logger.getLogger().debug("Directories arranged.") logger.getLogger().info("Start updating checksumfile(s) ...") for path in pathes: logger.getLogger().debug( \ "Updating checksumfile in '{0}' with files from '{1}' ...".format( \ path[0], path[1])) csfile.CsFile(path[0], path[1], hashfunc=hashfunc).update(regexes) except Usage as err: err.display() return 2 except csfile.CsFileError as err: logger.getLogger().error("{0}".format(err.msg)) err.display() return 2 else: logger.getLogger().info("Checksumfile(s) updated.") return 0 # ----------------------------------------------------------------------------- if __name__ == "__main__": sys.exit(main()) # ----- END OF csbackgen.py -----