4 Wizard is a next-generation autoinstall management system with an
5 eye towards flexibility and scalability.
7 Copyright (c) 2009-2010 the Wizard development team
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 # import some non-standard modules to make it fail out early
38 _root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
39 sys.path.insert(0, _root_dir)
40 sys.path.insert(0, os.path.join(_root_dir, "plugins/scripts")) # hack to load scripts plugins for now
43 from wizard import command, prompt
46 usage = """usage: %prog COMMAND [ARGS]
48 Wizard is a Git-based autoinstall management system for scripts.
51 backup Backup data not on filesystem (database, etc)
52 install Installs an application
53 migrate Migrate autoinstalls from old format to Git-based format
54 remove Removes an autoinstall, databases and other files
55 restore Restores files and database to previous version
56 upgrade Upgrades an autoinstall to the latest version
58 Administrative commands:
59 prepare-upgrade Downloads and tests a software upgrade
60 blacklist Marks an autoinstall to not try upgrades
61 errors Lists all broken autoinstall metadata
62 list Lists autoinstalls, with optional filtering
63 mass-migrate Performs mass migration of autoinstalls of an application
64 mass-upgrade Performs mass upgrade of autoinstalls of an application
65 research Print statistics about a possible upgrade
66 summary Generate statistics (see help for subcommands)
69 prepare-pristine Downloads and extracts pristine upstream files
70 prepare-config Prepares configuration files for versioning
71 quota Prints the usage and available quota of a directory
73 See '%prog help COMMAND' for more information on a specific command."""
75 parser = optparse.OptionParser(usage)
76 parser.disable_interspersed_args()
77 _, args = parser.parse_args() # no global options
79 baton = command.OptionBaton()
80 baton.add("--versions-path", dest="versions_path", metavar="PATH",
81 default=getenvpath("WIZARD_VERSIONS_PATH") or "/afs/athena.mit.edu/contrib/scripts/sec-tools/store/versions",
82 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.")
83 baton.add("--srv-path", dest="srv_path", metavar="PATH",
84 default=getenvpath("WIZARD_SRV_PATH") or "/afs/athena.mit.edu/contrib/scripts/git/autoinstalls",
85 help="Location of autoinstall Git repositories, such that $REPO_PATH/$APP.git is a repository (for development work). Environment variable is WIZARD_SRV_PATH.")
86 baton.add("--dry-run", dest="dry_run", action="store_true",
87 default=False, help="Performs the operation without actually modifying any files. Use in combination with --verbose to see commands that will be run.")
88 # common variables for mass commands
89 baton.add("--seen", dest="seen",
90 default=None, help="File to read/write paths of successfully modified installs;"
91 "these will be skipped on re-runs. If --log-dir is specified, this is automatically enabled.")
92 baton.add("--no-parallelize", dest="no_parallelize", action="store_true",
93 default=False, help="Turn off parallelization")
94 baton.add("--max-processes", dest="max_processes", type="int", metavar="N",
95 default=5, help="Maximum subprocesses to run concurrently")
96 baton.add("--limit", dest="limit", type="int",
97 default=None, help="Limit the number of autoinstalls to look at.")
98 baton.add("--user", "-u", dest="user",
99 default=None, help="Only mass migrate a certain user's installs. No effect if versions_path is a file.")
101 command_name = args[0]
105 baton.add("--log-dir", dest="log_dir",
106 default=getenvpath("WIZARD_LOG_DIR") or "/tmp/wizard-%s" % command_name,
107 help="Log files for Wizard children processes are placed here.")
108 if command_name == "help":
110 help_module = get_command(rest_argv[0])
112 parser.error("invalid action")
116 help_module.main(['--help'], baton)
117 # This is a gigantic hack to handle the case of AFS + Scripts style
118 # permissions, where we usually don't have access to the HOME
119 # directory. AFS will throttle you if you trigger too many
120 # lack of permissions, and since we run Git a lot and Git
121 # persistently stats the home directory, this can cause pretty
122 # big problems for our performance.
123 if not os.access(os.environ['HOME'], os.R_OK):
124 os.putenv('HOME', '/disabled')
126 command_module = get_command(command_name)
128 command_module.main(rest_argv, baton)
129 except prompt.UserCancel as e:
132 except Exception as e:
134 msg = traceback.format_exc()
135 if command.logging_setup:
136 outfun = logging.error
138 outfun = sys.stderr.write
139 if isinstance(e, wizard.Error):
140 if e.quiet and not command.debug:
142 if command.logging_setup:
143 msg = msg.replace("ERROR: ", "")
150 def get_command(name):
151 name = name.replace("-", "_")
152 __import__("wizard.command." + name)
153 return getattr(wizard.command, name)
155 def getenvpath(name):
156 val = os.getenv(name)
158 val = os.path.abspath(val)
161 if __name__ == "__main__":