Mercurial > hrm
view kharon.py @ 11:220a8a38dedd
Changed display strings a bit.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Mon, 08 Dec 2008 15:41:38 -0800 |
parents | 0220e43e5d8e |
children | 97fb91f12cb7 |
line wrap: on
line source
#! /usr/bin/env python3.0 ''' This is a drop-in replacement for rm, with support for undo. ''' import os import re import sys import json import subprocess import distutils.dir_util from optparse import OptionParser HADES_DIR = os.path.expanduser('~/.Hades') STATE_FILENAME = os.path.join(HADES_DIR, 'state.json') class Config(object): def __init__(self, filename): self.__filename = filename self.nextid = 0 if os.path.exists(self.__filename): self.__dict__.update(json.load(open(self.__filename, 'r'))) else: self.save() def save(self): state = {} keys = [key for key in self.__dict__ if not key.startswith('__')] for key in keys: state[key] = self.__dict__[key] json.dump(state, open(self.__filename, 'w')) def shell(*params): popen = subprocess.Popen(params) popen.wait() if popen.returncode: raise Exception('Process failed: %s' % repr(params)) def dir_for_trans(transid): return os.path.join(HADES_DIR, '%.9d' % transid) if __name__ == '__main__': if not (os.path.exists(HADES_DIR) and os.path.isdir(HADES_DIR)): shell('mkdir', HADES_DIR) parser = OptionParser(description=__import__(__name__).__doc__) parser.add_option('-u', '--undo', dest='undo', action='store_true', default=False, help='undo a transaction (default is latest).') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='be verbose.') args = [] for arg in sys.argv[1:]: # Filter out redundant parameters to the traditional 'rm' # command. if not re.match('-[dfiRrv]+', arg): args.append(arg) elif 'v' in arg: args.append('-v') (options, args) = parser.parse_args(args) config = Config(STATE_FILENAME) if options.undo: transactions = [] for arg in args: try: transid = int(arg) except ValueError: print('Unknown transaction ID: %s' % arg) sys.exit(-1) transactions.append(transid) if not transactions and config.nextid: transactions.append(config.nextid - 1) for transid in transactions: dirname = dir_for_trans(transid) if not os.path.exists(dirname): print('Transaction ID %d does not exist.' % transid) sys.exit(-1) transactions.sort(reverse=True) for transid in transactions: transdirname = dir_for_trans(transid) for dirpath, dirnames, filenames in os.walk(transdirname): relpath = dirpath[len(transdirname)+1:] contents = dirnames + filenames for name in contents: srcpath = os.path.join(dirpath, name) destpath = os.path.join('/', relpath, name) if not os.path.exists(destpath): if os.path.isdir(srcpath): dirnames.remove(name) print('Restoring %s.' % destpath) shell('mv', srcpath, destpath) print('Done.') else: if not args: parser.print_help() sys.exit(-1) files = [] for arg in args: filename = os.path.abspath(os.path.expanduser(arg)) if not os.path.exists(filename): print('File does not exist: %s' % arg) sys.exit(-1) realpath = os.path.realpath(filename) if (realpath.startswith(HADES_DIR) or HADES_DIR.startswith(realpath)): print('Cannot move files in or above %s.' % HADES_DIR) sys.exit(-1) files.append(filename) thisid = config.nextid basedir = dir_for_trans(thisid) shell('mkdir', basedir) config.nextid = thisid + 1 config.save() print('The transaction ID for this operation is %s.' % thisid) for source in files: if options.verbose: print('Removing %s.' % source) dest = os.path.join(basedir, source[1:]) distutils.dir_util.mkpath(os.path.dirname(dest)) shell('mv', source, dest)