#!/usr/bin/env python import os import optparse import sys import logging import traceback # import some non-standard modules to make it fail out early import decorator sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import wizard from wizard import command, prompt def main(): usage = """usage: %prog COMMAND [ARGS] Wizard is a Git-based autoinstall management system for scripts. User commands: backup Backup data not on filesystem (database, etc) install Installs an application migrate Migrate autoinstalls from old format to Git-based format remove Removes an autoinstall, databases and other files restore Restores files and database to previous version upgrade Upgrades an autoinstall to the latest version Administrative commands: blacklist Marks an autoinstall to not try upgrades errors Lists all broken autoinstall metadata list Lists autoinstalls, with optional filtering mass-migrate Performs mass migration of autoinstalls of an application mass-upgrade Performs mass upgrade of autoinstalls of an application research Print statistics about a possible upgrade summary Generate statistics (see help for subcommands) Utility commands: prepare-pristine Downloads and extracts pristine upstream files prepare-new Prepares a new repository prepare-config Prepares configuration files for versioning quota Prints the usage and available quota of a directory See '%prog help COMMAND' for more information on a specific command.""" parser = optparse.OptionParser(usage) parser.disable_interspersed_args() _, args = parser.parse_args() # no global options rest_argv = args[1:] baton = command.OptionBaton() baton.add("--versions-path", dest="versions_path", metavar="PATH", default=getenvpath("WIZARD_VERSIONS_PATH") or "/afs/athena.mit.edu/contrib/scripts/sec-tools/store/versions", help="Location of parallel-find output directory, or a file containing a newline separated list of 'all autoinstalls' (for development work). Environment variable is WIZARD_VERSIONS_PATH.") baton.add("--srv-path", dest="srv_path", metavar="PATH", default=getenvpath("WIZARD_SRV_PATH") or "/afs/athena.mit.edu/contrib/scripts/git/autoinstalls", help="Location of autoinstall Git repositories, such that $REPO_PATH/$APP.git is a repository (for development work). Environment variable is WIZARD_SRV_PATH.") baton.add("--dry-run", dest="dry_run", action="store_true", default=False, help="Performs the operation without actually modifying any files. Use in combination with --verbose to see commands that will be run.") # common variables for mass commands baton.add("--seen", dest="seen", default=None, help="File to read/write paths of successfully modified installs;" "these will be skipped on re-runs. If --log-dir is specified, this is automatically enabled.") baton.add("--no-parallelize", dest="no_parallelize", action="store_true", default=False, help="Turn off parallelization") baton.add("--max-processes", dest="max_processes", type="int", metavar="N", default=10, help="Maximum subprocesses to run concurrently") baton.add("--limit", dest="limit", type="int", default=None, help="Limit the number of autoinstalls to look at.") baton.add("--user", "-u", dest="user", default=None, help="Only mass migrate a certain user's installs. No effect if versions_path is a file.") try: command_name = args[0] except IndexError: parser.print_help() sys.exit(1) baton.add("--log-dir", dest="log_dir", default=getenvpath("WIZARD_LOG_DIR") or "/tmp/wizard-%s" % command_name, help="Log files for Wizard children processes are placed here.") if command_name == "help": try: help_module = get_command(rest_argv[0]) except ImportError: parser.error("invalid action") except IndexError: parser.print_help() sys.exit(1) help_module.main(['--help'], baton) # Dispatch commands command_module = get_command(command_name) try: command_module.main(rest_argv, baton) except prompt.UserCancel as e: print str(e) sys.exit(1) except Exception as e: # log the exception msg = traceback.format_exc() if command.logging_setup: outfun = logging.error else: outfun = sys.stderr.write if isinstance(e, wizard.Error): if e.quiet and not command.debug: msg = str(e) if command.logging_setup: msg = msg.replace("ERROR: ", "") outfun(msg) sys.exit(e.exitcode) else: outfun(msg) sys.exit(1) def get_command(name): name = name.replace("-", "_") __import__("wizard.command." + name) return getattr(wizard.command, name) def getenvpath(name): val = os.getenv(name) if val: val = os.path.abspath(val) return val if __name__ == "__main__": main()