#!/usr/bin/env python # Copyright (C) 2006-2007 Richard Purdie # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License version 2 as published by the Free # Software Foundation; # # This program 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. import optparse import os, sys, stat __version__ = "0.0.1" def write_cache(cachefile, cachedata): fd = open(cachefile, 'w') for f in cachedata: s = f + '|' + str(cachedata[f]['ts']) + '|' + str(cachedata[f]['size']) fd.write(s + '\n') fd.close() def read_cache(cachefile): cache = {} f = open(cachefile, 'r') lines = f.readlines() f.close() for l in lines: data = l.split('|') cache[data[0]] = {} cache[data[0]]['ts'] = int(data[1]) cache[data[0]]['size'] = int(data[2]) cache[data[0]]['seen'] = False return cache def mkdirhier(dir): """Create a directory like 'mkdir -p', but does not complain if directory already exists like os.makedirs """ try: os.makedirs(dir) except OSError, e: if e.errno != 17: raise e if __name__ == "__main__": parser = optparse.OptionParser( version = "Metadata Stage Manager version %s" % ( __version__ ), usage = """%prog [options]\n\nPerforms mamagement tasks on a metadata staging area.""" ) parser.add_option( "-p", "--parentdir", help = "the path to the metadata parent directory", action = "store", dest = "parentdir", default = None) parser.add_option( "-c", "--cachefile", help = "the cache file to use", action = "store", dest = "cachefile", default = None) parser.add_option( "-d", "--copydir", help = "copy changed files to this directory", action = "store", dest = "copydir", default = None) parser.add_option( "-u", "--update", help = "update the cache file", action = "store_true", dest = "update", default = False) (options, args) = parser.parse_args() if options.parentdir is None: print("Error, --parentdir option not supplied") sys.exit(1) if options.cachefile is None: print("Error, --cachefile option not supplied") sys.exit(1) if not options.parentdir.endswith('/'): options.parentdir = options.parentdir + '/' cache = {} if os.access(options.cachefile, os.F_OK): cache = read_cache(options.cachefile) found_difference = False def updateCache(path, fstamp): cache[path] = {} cache[path]['ts'] = fstamp[stat.ST_MTIME] cache[path]['size'] = fstamp[stat.ST_SIZE] cache[path]['seen'] = True found_difference = True def copyfile(path): if options.copydir: copypath = os.path.join(options.copydir, path.replace(options.parentdir, '', 1)) mkdirhier(os.path.split(copypath)[0]) os.system("cp -dp " + path + " " + copypath) def copydir(path, fstamp): if options.copydir: copypath = os.path.join(options.copydir, path.replace(options.parentdir, '', 1)) if os.path.exists(copypath): os.system("rm -rf " + copypath) if os.path.islink(path): os.symlink(os.readlink(path), copypath) else: mkdirhier(copypath) os.utime(copypath, (fstamp[stat.ST_ATIME], fstamp[stat.ST_MTIME])) for root, dirs, files in os.walk(options.parentdir): for f in files: path = os.path.join(root, f) if not os.access(path, os.R_OK): continue fstamp = os.lstat(path) if path not in cache: print "new file %s" % path updateCache(path, fstamp) copyfile(path) else: if cache[path]['ts'] != fstamp[stat.ST_MTIME] or cache[path]['size'] != fstamp[stat.ST_SIZE]: print "file %s changed" % path updateCache(path, fstamp) copyfile(path) cache[path]['seen'] = True for d in dirs: path = os.path.join(root, d) fstamp = os.lstat(path) if path not in cache: print "new dir %s" % path updateCache(path, fstamp) copydir(path, fstamp) else: if cache[path]['ts'] != fstamp[stat.ST_MTIME]: print "dir %s changed" % path updateCache(path, fstamp) copydir(path, fstamp) cache[path]['seen'] = True todel = [] for path in cache: if not cache[path]['seen']: print "%s removed" % path found_difference = True todel.append(path) if options.update: print "Updating" for path in todel: del cache[path] mkdirhier(os.path.split(options.cachefile)[0]) write_cache(options.cachefile, cache) if found_difference: sys.exit(5) sys.exit(0)