]> scripts.mit.edu Git - wizard.git/blob - wizard/command/__init__.py
Refactor to get rid of _package.py using __import__ magic.
[wizard.git] / wizard / command / __init__.py
1 import logging
2 import os
3 import sys
4 import optparse
5 import errno
6
7 import wizard
8
9 logging_setup = False
10
11 class Error(wizard.Error):
12     """Base error class for all command errors"""
13     pass
14
15 class PermissionsError(Error):
16     def __init__(self, dir):
17         self.dir = dir
18     def __str__(self):
19         return """
20
21 ERROR: You don't have permissions to access this directory.
22 Do you have tokens for AFS with your root instance, and
23 is your root instance on scripts-security-upd?
24
25 You can check by running the commands 'klist' and
26 'blanche scripts-security-upd'.
27 """
28
29 class NoSuchDirectoryError(Error):
30     def __init__(self, dir):
31         self.dir = dir
32     def __str__(self):
33         return """
34
35 ERROR: No such directory... check your typing
36 """
37
38 def chdir(dir):
39     try:
40         os.chdir(dir)
41     except OSError as e:
42         if e.errno == errno.EACCES:
43             raise PermissionsError(dir)
44         elif e.errno == errno.ENOENT:
45             raise NoSuchDirectoryError(dir)
46         else: raise e
47
48 def makeLogger(options, numeric_args):
49     global logging_setup
50     if logging_setup: return logging.getLogger()
51     context = " ".join(numeric_args)
52     logger = logging.getLogger()
53     logger.setLevel(logging.INFO)
54     stderr = logging.StreamHandler(sys.stderr)
55     stderr.setFormatter(logging.Formatter(" " * int(options.indent) + '%(levelname)s: %(message)s'))
56     dateFormat = "%H:%M:%S"
57     if options.context:
58         logformatter = logging.Formatter("%(asctime)s %(levelname)s -- " + context + ": %(message)s", dateFormat)
59     else:
60         logformatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", dateFormat)
61     if not options.quiet: logger.addHandler(stderr)
62     else: logger.addHandler(NullLogHandler()) # prevent default
63     if options.log_file:
64         file = logging.FileHandler(options.log_file)
65         file.setFormatter(logformatter)
66         logger.addHandler(file)
67         if options.log_file_chmod:
68             os.chmod(options.log_file, int(options.log_file_chmod, 8))
69     if options.debug:
70         logger.setLevel(logging.DEBUG)
71     else:
72         stderr.setLevel(logging.WARNING)
73         if options.verbose or hasattr(options, "dry_run"):
74             stderr.setLevel(logging.INFO)
75         if options.log_file:
76             file.setLevel(logging.INFO)
77     logging_setup = True
78     return logger
79
80 def makeBaseArgs(options, **grab):
81     """Takes parsed options, and breaks them back into a command
82     line string that we can pass into a subcommand"""
83     args = []
84     grab["log_file"]= "--log-file"
85     grab["debug"]   = "--debug"
86     grab["verbose"] = "--verbose"
87     grab["indent"]  = "--indent"
88     grab["quiet"]   = "--quiet"
89     #grab["log_db"] = "--log-db"
90     for k,flag in grab.items():
91         value = getattr(options, k)
92         if not value and k != "indent": continue
93         args.append(flag)
94         if type(value) is not bool:
95             if k == "indent":
96                 value += 4
97             args.append(str(value))
98     args.append("--context") # always have context for a subcommand
99     return args
100
101 class NullLogHandler(logging.Handler):
102     """Log handler that doesn't do anything"""
103     def emit(self, record):
104         pass
105
106 class WizardOptionParser(optparse.OptionParser):
107     """Configures some default user-level options"""
108     def __init__(self, *args, **kwargs):
109         kwargs["add_help_option"] = False
110         optparse.OptionParser.__init__(self, *args, **kwargs)
111     def parse_all(self, argv):
112         self.add_option("-h", "--help", action="help", help=optparse.SUPPRESS_HELP)
113         group = optparse.OptionGroup(self, "Common Options")
114         group.add_option("-v", "--verbose", dest="verbose", action="store_true",
115                 default=False, help="Turns on verbose output")
116         group.add_option("--debug", dest="debug", action="store_true",
117                 default=False, help="Turns on debugging output")
118         group.add_option("-q", "--quiet", dest="quiet", action="store_true",
119                 default=False, help="Turns off output to stdout")
120         group.add_option("--log-file", dest="log_file",
121                 default=None, help="Logs verbose output to file")
122         group.add_option("--log-file-chmod", dest="log_file_chmod",
123                 default=None, help="Chmod the log file after opening.  Number is octal. You must chmod the log file 666 and place the file in /tmp if subprocesses are running as different users.")
124         group.add_option("--indent", dest="indent",
125                 default=0, help="Indents stdout, useful for nested calls")
126         group.add_option("--context", dest="context", action="store_true",
127                 default=False, help="Adds context to logs, useful for parallel processing")
128         self.add_option_group(group)
129         options, numeric_args = self.parse_args(argv)
130         makeLogger(options, numeric_args)
131         return options, numeric_args
132
133 class OptionBaton(object):
134     """Command classes may define options that they sub-commands may
135     use.  Since wizard --global-command subcommand is not a supported
136     mode of operation, these options have to be passed down the command
137     chain until a option parser is ready to take it; this baton is
138     what is passed down."""
139     def __init__(self):
140         self.store = {}
141     def add(self, *args, **kwargs):
142         key = kwargs["dest"] # require this to be set
143         self.store[key] = optparse.make_option(*args, **kwargs)
144     def push(self, option_parser, *args):
145         """Hands off parameters to option parser"""
146         for key in args:
147             option_parser.add_option(self.store[key])