]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/cli.py
CLI: make 'tahoe webopen' use the 'tahoe:' alias properly, instead of the old --dir...
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / cli.py
1
2 import os.path, re, sys
3 from twisted.python import usage
4 from allmydata.scripts.common import BaseOptions, get_aliases
5
6 NODEURL_RE=re.compile("http://([^:]*)(:([1-9][0-9]*))?")
7
8 class VDriveOptions(BaseOptions, usage.Options):
9     optParameters = [
10         ["node-directory", "d", "~/.tahoe",
11          "Look here to find out which Tahoe node should be used for all "
12          "operations. The directory should either contain a full Tahoe node, "
13          "or a file named node.url which points to some other Tahoe node. "
14          "It should also contain a file named private/aliases which contains "
15          "the mapping from alias name to root dirnode URI."
16          ],
17         ["node-url", "u", None,
18          "URL of the tahoe node to use, a URL like \"http://127.0.0.1:8123\". "
19          "This overrides the URL found in the --node-directory ."],
20         ["dir-cap", None, None,
21          "Which dirnode URI should be used as the 'tahoe' alias."]
22         ]
23
24     def postOptions(self):
25         # compute a node-url from the existing options, put in self['node-url']
26         if self['node-directory']:
27             if sys.platform == 'win32' and self['node-directory'] == '~/.tahoe':
28                 from allmydata.windows import registry
29                 self['node-directory'] = registry.get_base_dir_path()
30             else:
31                 self['node-directory'] = os.path.expanduser(self['node-directory'])
32         if self['node-url']:
33             if (not isinstance(self['node-url'], basestring)
34                 or not NODEURL_RE.match(self['node-url'])):
35                 msg = ("--node-url is required to be a string and look like "
36                        "\"http://HOSTNAMEORADDR:PORT\", not: %r" %
37                        (self['node-url'],))
38                 raise usage.UsageError(msg)
39         else:
40             node_url_file = os.path.join(self['node-directory'], "node.url")
41             self['node-url'] = open(node_url_file, "r").read().strip()
42
43         aliases = get_aliases(self['node-directory'])
44         if self['dir-cap']:
45             aliases["tahoe"] = self['dir-cap']
46         self.aliases = aliases # maps alias name to dircap
47
48
49 class MakeDirectoryOptions(VDriveOptions):
50     def parseArgs(self, where=""):
51         self.where = where
52     longdesc = """Create a new directory, either unlinked or as a subdirectory."""
53
54 class AddAliasOptions(VDriveOptions):
55     def parseArgs(self, alias, cap):
56         self.alias = alias
57         self.cap = cap
58
59 class ListAliasOptions(VDriveOptions):
60     pass
61
62 class ListOptions(VDriveOptions):
63     optFlags = [
64         ("long", "l", "Use long format: show file sizes, and timestamps"),
65         ("uri", "u", "Show file/directory URIs"),
66         ("readonly-uri", None, "Show readonly file/directory URIs"),
67         ("classify", "F", "Append '/' to directory names, and '*' to mutable"),
68         ("json", None, "Show the raw JSON output"),
69         ]
70     def parseArgs(self, where=""):
71         self.where = where
72
73     longdesc = """List the contents of some portion of the virtual drive."""
74
75 class GetOptions(VDriveOptions):
76     def parseArgs(self, arg1, arg2=None):
77         # tahoe get FOO |less            # write to stdout
78         # tahoe get tahoe:FOO |less      # same
79         # tahoe get FOO bar              # write to local file
80         # tahoe get tahoe:FOO bar        # same
81
82         self.from_file = arg1
83         self.to_file = arg2
84         if self.to_file == "-":
85             self.to_file = None
86
87     def getSynopsis(self):
88         return "%s get VDRIVE_FILE LOCAL_FILE" % (os.path.basename(sys.argv[0]),)
89
90     longdesc = """Retrieve a file from the virtual drive and write it to the
91     local filesystem. If LOCAL_FILE is omitted or '-', the contents of the file
92     will be written to stdout."""
93
94     def getUsage(self, width=None):
95         t = VDriveOptions.getUsage(self, width)
96         t += """
97 Examples:
98  % tahoe get FOO |less            # write to stdout
99  % tahoe get tahoe:FOO |less      # same
100  % tahoe get FOO bar              # write to local file
101  % tahoe get tahoe:FOO bar        # same
102 """
103         return t
104
105 class PutOptions(VDriveOptions):
106     optFlags = [
107         ("mutable", "m", "Create a mutable file instead of an immutable one."),
108         ]
109
110     def parseArgs(self, arg1=None, arg2=None):
111         # cat FILE > tahoe put           # create unlinked file from stdin
112         # cat FILE > tahoe put FOO       # create tahoe:FOO from stdin
113         # cat FILE > tahoe put tahoe:FOO # same
114         # tahoe put bar FOO              # copy local 'bar' to tahoe:FOO
115         # tahoe put bar tahoe:FOO        # same
116
117         if arg1 is not None and arg2 is not None:
118             self.from_file = arg1
119             self.to_file = arg2
120         elif arg1 is not None and arg2 is None:
121             self.from_file = None
122             self.to_file = arg1
123         else:
124             self.from_file = arg1
125             self.to_file = arg2
126         if self.from_file == "-":
127             self.from_file = None
128
129     def getSynopsis(self):
130         return "%s put LOCAL_FILE VDRIVE_FILE" % (os.path.basename(sys.argv[0]),)
131
132     longdesc = """Put a file into the virtual drive (copying the file's
133     contents from the local filesystem). If LOCAL_FILE is missing or '-',
134     data will be copied from stdin. VDRIVE_FILE is assumed to start with
135     tahoe: unless otherwise specified."""
136
137     def getUsage(self, width=None):
138         t = VDriveOptions.getUsage(self, width)
139         t += """
140 Examples:
141  % cat FILE > tahoe put           # create unlinked file from stdin
142  % cat FILE > tahoe put FOO       # create tahoe:FOO from stdin
143  % cat FILE > tahoe put tahoe:FOO # same
144  % tahoe put bar FOO              # copy local 'bar' to tahoe:FOO
145  % tahoe put bar tahoe:FOO        # same
146 """
147         return t
148
149 class CpOptions(VDriveOptions):
150     optFlags = [
151         ("recursive", "r", "Copy source directory recursively."),
152         ("verbose", "v", "Be noisy about what is happening."),
153         ]
154     def parseArgs(self, *args):
155         if len(args) < 2:
156             raise usage.UsageError("cp requires at least two arguments")
157         self.sources = args[:-1]
158         self.destination = args[-1]
159
160 class RmOptions(VDriveOptions):
161     def parseArgs(self, where):
162         self.where = where
163
164     def getSynopsis(self):
165         return "%s rm VE_FILE" % (os.path.basename(sys.argv[0]),)
166
167 class MvOptions(VDriveOptions):
168     def parseArgs(self, frompath, topath):
169         self.from_file = frompath
170         self.to_file = topath
171
172     def getSynopsis(self):
173         return "%s mv FROM TO" % (os.path.basename(sys.argv[0]),)
174
175 class LnOptions(VDriveOptions):
176     def parseArgs(self, frompath, topath):
177         self.from_file = frompath
178         self.to_file = topath
179
180     def getSynopsis(self):
181         return "%s ln FROM TO" % (os.path.basename(sys.argv[0]),)
182
183 class WebopenOptions(VDriveOptions):
184     def parseArgs(self, vdrive_pathname=""):
185         self['vdrive_pathname'] = vdrive_pathname
186
187     longdesc = """Opens a webbrowser to the contents of some portion of the virtual drive."""
188
189 class ReplOptions(usage.Options):
190     pass
191
192 subCommands = [
193     ["mkdir", None, MakeDirectoryOptions, "Create a new directory"],
194     ["add-alias", None, AddAliasOptions, "Add a new alias cap"],
195     ["list-aliases", None, ListAliasOptions, "List all alias caps"],
196     ["ls", None, ListOptions, "List a directory"],
197     ["get", None, GetOptions, "Retrieve a file from the virtual drive."],
198     ["put", None, PutOptions, "Upload a file into the virtual drive."],
199     ["cp", None, CpOptions, "Copy one or more files."],
200     ["rm", None, RmOptions, "Unlink a file or directory in the virtual drive."],
201     ["mv", None, MvOptions, "Move a file within the virtual drive."],
202     ["ln", None, LnOptions, "Make an additional link to an existing file."],
203     ["webopen", None, WebopenOptions, "Open a webbrowser to the root_dir"],
204     ["repl", None, ReplOptions, "Open a python interpreter"],
205     ]
206
207 def mkdir(config, stdout, stderr):
208     from allmydata.scripts import tahoe_mkdir
209     rc = tahoe_mkdir.mkdir(config['node-url'],
210                            config.aliases,
211                            config.where,
212                            stdout, stderr)
213     return rc
214
215 def add_alias(config, stdout, stderr):
216     from allmydata.scripts import tahoe_add_alias
217     rc = tahoe_add_alias.add_alias(config['node-directory'],
218                                    config.alias,
219                                    config.cap,
220                                    stdout, stderr)
221     return rc
222
223 def list_aliases(config, stdout, stderr):
224     from allmydata.scripts import tahoe_add_alias
225     rc = tahoe_add_alias.list_aliases(config['node-directory'],
226                                       stdout, stderr)
227     return rc
228
229 def list(config, stdout, stderr):
230     from allmydata.scripts import tahoe_ls
231     rc = tahoe_ls.list(config['node-url'],
232                        config.aliases,
233                        config.where,
234                        config,
235                        stdout, stderr)
236     return rc
237
238 def get(config, stdout, stderr):
239     from allmydata.scripts import tahoe_get
240     rc = tahoe_get.get(config['node-url'],
241                        config.aliases,
242                        config.from_file,
243                        config.to_file,
244                        stdout, stderr)
245     if rc == 0:
246         if config.to_file is None:
247             # be quiet, since the file being written to stdout should be
248             # proof enough that it worked, unless the user is unlucky
249             # enough to have picked an empty file
250             pass
251         else:
252             print >>stderr, "%s retrieved and written to %s" % \
253                   (config.from_file, config.to_file)
254     return rc
255
256 def put(config, stdout, stderr, stdin=sys.stdin):
257     from allmydata.scripts import tahoe_put
258     if config['quiet']:
259         verbosity = 0
260     else:
261         verbosity = 2
262     rc = tahoe_put.put(config['node-url'],
263                        config.aliases,
264                        config.from_file,
265                        config.to_file,
266                        config['mutable'],
267                        verbosity,
268                        stdin, stdout, stderr)
269     return rc
270
271 def cp(config, stdout, stderr):
272     from allmydata.scripts import tahoe_cp
273     if config['quiet']:
274         verbosity = 0
275     else:
276         verbosity = 2
277     rc = tahoe_cp.copy(config['node-url'],
278                        config,
279                        config.aliases,
280                        config.sources,
281                        config.destination,
282                        verbosity,
283                        stdout, stderr)
284     return rc
285
286 def rm(config, stdout, stderr):
287     from allmydata.scripts import tahoe_rm
288     if config['quiet']:
289         verbosity = 0
290     else:
291         verbosity = 2
292     rc = tahoe_rm.rm(config['node-url'],
293                      config.aliases,
294                      config.where,
295                      verbosity,
296                      stdout, stderr)
297     return rc
298
299 def mv(config, stdout, stderr):
300     from allmydata.scripts import tahoe_mv
301     rc = tahoe_mv.mv(config['node-url'],
302                      config.aliases,
303                      config.from_file,
304                      config.to_file,
305                      stdout, stderr,
306                      mode="move")
307     return rc
308
309 def ln(config, stdout, stderr):
310     from allmydata.scripts import tahoe_mv
311     rc = tahoe_mv.mv(config['node-url'],
312                      config.aliases,
313                      config.from_file,
314                      config.to_file,
315                      stdout, stderr,
316                      mode="link")
317     return rc
318
319 def webopen(config, stdout, stderr):
320     import urllib, webbrowser
321     nodeurl = config['node-url']
322     if nodeurl[-1] != "/":
323         nodeurl += "/"
324     root_cap = config.aliases["tahoe"]
325     url = nodeurl + "uri/%s/" % urllib.quote(root_cap)
326     if config['vdrive_pathname']:
327         url += urllib.quote(config['vdrive_pathname'])
328     webbrowser.open(url)
329     return 0
330
331 def repl(config, stdout, stderr):
332     import code
333     return code.interact()
334
335 dispatch = {
336     "mkdir": mkdir,
337     "add-alias": add_alias,
338     "list-aliases": list_aliases,
339     "ls": list,
340     "get": get,
341     "put": put,
342     "cp": cp,
343     "rm": rm,
344     "mv": mv,
345     "ln": ln,
346     "webopen": webopen,
347     "repl": repl,
348     }
349