]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/runner.py
1a6de258ed6e6826fa6d3aad012df1435991d5b7
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / runner.py
1
2 import os, sys
3 from cStringIO import StringIO
4
5 from twisted.python import usage
6
7 from allmydata.scripts.common import get_default_nodedir
8 from allmydata.scripts import debug, create_node, startstop_node, cli, keygen, stats_gatherer, admin
9 from allmydata.util.encodingutil import quote_output, quote_local_unicode_path, get_io_encoding
10
11 def GROUP(s):
12     # Usage.parseOptions compares argv[1] against command[0], so it will
13     # effectively ignore any "subcommand" that starts with a newline. We use
14     # these to insert section headers into the --help output.
15     return [("\n" + s, None, None, None)]
16
17
18 _default_nodedir = get_default_nodedir()
19
20 NODEDIR_HELP = ("Specify which Tahoe node directory should be used. The "
21                 "directory should either contain a full Tahoe node, or a "
22                 "file named node.url that points to some other Tahoe node. "
23                 "It should also contain a file named '"
24                 + os.path.join('private', 'aliases') +
25                 "' which contains the mapping from alias name to root "
26                 "dirnode URI.")
27 if _default_nodedir:
28     NODEDIR_HELP += " [default for most commands: " + quote_local_unicode_path(_default_nodedir) + "]"
29
30 class Options(usage.Options):
31     # unit tests can override these to point at StringIO instances
32     stdin = sys.stdin
33     stdout = sys.stdout
34     stderr = sys.stderr
35
36     synopsis = "\nUsage:  tahoe <command> [command options]"
37     subCommands = ( GROUP("Administration")
38                     +   create_node.subCommands
39                     +   keygen.subCommands
40                     +   stats_gatherer.subCommands
41                     +   admin.subCommands
42                     + GROUP("Controlling a node")
43                     +   startstop_node.subCommands
44                     + GROUP("Debugging")
45                     +   debug.subCommands
46                     + GROUP("Using the filesystem")
47                     +   cli.subCommands
48                     )
49
50     optFlags = [
51         ["quiet", "q", "Operate silently."],
52         ["version", "V", "Display version numbers."],
53         ["version-and-path", None, "Display version numbers and paths to their locations."],
54     ]
55     optParameters = [
56         ["node-directory", "d", None, NODEDIR_HELP],
57     ]
58
59     def opt_version(self):
60         import allmydata
61         print >>self.stdout, allmydata.get_package_versions_string(debug=True)
62         self.no_command_needed = True
63
64     def opt_version_and_path(self):
65         import allmydata
66         print >>self.stdout, allmydata.get_package_versions_string(show_paths=True, debug=True)
67         self.no_command_needed = True
68
69     def getSynopsis(self):
70         return "\nUsage: tahoe [global-opts] <command> [command-options]"
71
72     def getUsage(self, **kwargs):
73         t = usage.Options.getUsage(self, **kwargs)
74         return t + "\nPlease run 'tahoe <command> --help' for more details on each command.\n"
75
76     def postOptions(self):
77         if not hasattr(self, 'subOptions'):
78             if not hasattr(self, 'no_command_needed'):
79                 raise usage.UsageError("must specify a command")
80             sys.exit(0)
81
82
83 create_dispatch = {}
84 for module in (create_node, keygen, stats_gatherer):
85     create_dispatch.update(module.dispatch)
86
87 def runner(argv,
88            run_by_human=True,
89            stdin=None, stdout=None, stderr=None,
90            install_node_control=True, additional_commands=None):
91
92     stdin  = stdin  or sys.stdin
93     stdout = stdout or sys.stdout
94     stderr = stderr or sys.stderr
95
96     config = Options()
97     if install_node_control:
98         config.subCommands.extend(startstop_node.subCommands)
99
100     ac_dispatch = {}
101     if additional_commands:
102         for ac in additional_commands:
103             config.subCommands.extend(ac.subCommands)
104             ac_dispatch.update(ac.dispatch)
105
106     try:
107         config.parseOptions(argv)
108     except usage.error, e:
109         if not run_by_human:
110             raise
111         c = config
112         while hasattr(c, 'subOptions'):
113             c = c.subOptions
114         print >>stdout, str(c)
115         try:
116             msg = e.args[0].decode(get_io_encoding())
117         except Exception:
118             msg = repr(e)
119         print >>stdout, "%s:  %s\n" % (sys.argv[0], quote_output(msg, quotemarks=False))
120         return 1
121
122     command = config.subCommand
123     so = config.subOptions
124
125     if config['quiet']:
126         stdout = StringIO()
127
128     so.stdout = stdout
129     so.stderr = stderr
130     so.stdin = stdin
131
132     if command in create_dispatch:
133         rc = create_dispatch[command](so, stdout, stderr)
134     elif command in startstop_node.dispatch:
135         rc = startstop_node.dispatch[command](so, stdout, stderr)
136     elif command in debug.dispatch:
137         rc = debug.dispatch[command](so)
138     elif command in admin.dispatch:
139         rc = admin.dispatch[command](so)
140     elif command in cli.dispatch:
141         rc = cli.dispatch[command](so)
142     elif command in ac_dispatch:
143         rc = ac_dispatch[command](so, stdout, stderr)
144     else:
145         raise usage.UsageError()
146
147     return rc
148
149
150 def run(install_node_control=True):
151     try:
152         if sys.platform == "win32":
153             from allmydata.windows.fixups import initialize
154             initialize()
155
156         rc = runner(sys.argv[1:], install_node_control=install_node_control)
157     except Exception:
158         import traceback
159         traceback.print_exc()
160         rc = 1
161
162     sys.exit(rc)