]> scripts.mit.edu Git - wizard.git/blob - bin/wizard
Set admin e-mail address properly on MediaWiki >= 1.18.0
[wizard.git] / bin / wizard
1 #!/usr/bin/env python
2
3 """
4 Wizard is a next-generation autoinstall management system with an
5 eye towards flexibility and scalability.
6
7 Copyright (c) 2009-2010 the Wizard development team
8
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:
16
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
19
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.
27 """
28
29 import os
30 import optparse
31 import sys
32 import logging
33 import traceback
34
35 # import some non-standard modules to make it fail out early
36 import decorator
37
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
41
42 import wizard
43 from wizard import command, prompt
44
45 def main():
46     usage = """usage: %prog COMMAND [ARGS]
47
48 Wizard is a Git-based autoinstall management system for scripts.
49
50 User commands:
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
57
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)
67
68 Plumbing commands:
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
72
73 See '%prog help COMMAND' for more information on a specific command."""
74
75     parser = optparse.OptionParser(usage)
76     parser.disable_interspersed_args()
77     _, args = parser.parse_args() # no global options
78     rest_argv = args[1:]
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.")
100     try:
101         command_name = args[0]
102     except IndexError:
103         parser.print_help()
104         sys.exit(1)
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":
109         try:
110             help_module = get_command(rest_argv[0])
111         except ImportError:
112             parser.error("invalid action")
113         except IndexError:
114             parser.print_help()
115             sys.exit(1)
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')
125     # Dispatch commands
126     command_module = get_command(command_name)
127     try:
128         command_module.main(rest_argv, baton)
129     except prompt.UserCancel as e:
130         print str(e)
131         sys.exit(1)
132     except Exception as e:
133         # log the exception
134         msg = traceback.format_exc()
135         if command.logging_setup:
136             outfun = logging.error
137         else:
138             outfun = sys.stderr.write
139         if isinstance(e, wizard.Error):
140             if e.quiet and not command.debug:
141                 msg = str(e)
142                 if command.logging_setup:
143                     msg = msg.replace("ERROR: ", "")
144             outfun(msg)
145             sys.exit(e.exitcode)
146         else:
147             outfun(msg)
148             sys.exit(1)
149
150 def get_command(name):
151     name = name.replace("-", "_")
152     __import__("wizard.command." + name)
153     return getattr(wizard.command, name)
154
155 def getenvpath(name):
156     val = os.getenv(name)
157     if val:
158         val = os.path.abspath(val)
159     return val
160
161 if __name__ == "__main__":
162     main()
163