]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/cli.py
wui/wapi: change the default port number from 8123 to 3456 to avoid conflict with...
[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:3456\". "
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 CreateAliasOptions(VDriveOptions):
60     def parseArgs(self, alias):
61         self.alias = alias
62
63 class ListAliasOptions(VDriveOptions):
64     pass
65
66 class ListOptions(VDriveOptions):
67     optFlags = [
68         ("long", "l", "Use long format: show file sizes, and timestamps"),
69         ("uri", "u", "Show file/directory URIs"),
70         ("readonly-uri", None, "Show readonly file/directory URIs"),
71         ("classify", "F", "Append '/' to directory names, and '*' to mutable"),
72         ("json", None, "Show the raw JSON output"),
73         ]
74     def parseArgs(self, where=""):
75         self.where = where
76
77     longdesc = """List the contents of some portion of the virtual drive."""
78
79 class GetOptions(VDriveOptions):
80     def parseArgs(self, arg1, arg2=None):
81         # tahoe get FOO |less            # write to stdout
82         # tahoe get tahoe:FOO |less      # same
83         # tahoe get FOO bar              # write to local file
84         # tahoe get tahoe:FOO bar        # same
85
86         self.from_file = arg1
87         self.to_file = arg2
88         if self.to_file == "-":
89             self.to_file = None
90
91     def getSynopsis(self):
92         return "%s get VDRIVE_FILE LOCAL_FILE" % (os.path.basename(sys.argv[0]),)
93
94     longdesc = """Retrieve a file from the virtual drive and write it to the
95     local filesystem. If LOCAL_FILE is omitted or '-', the contents of the file
96     will be written to stdout."""
97
98     def getUsage(self, width=None):
99         t = VDriveOptions.getUsage(self, width)
100         t += """
101 Examples:
102  % tahoe get FOO |less            # write to stdout
103  % tahoe get tahoe:FOO |less      # same
104  % tahoe get FOO bar              # write to local file
105  % tahoe get tahoe:FOO bar        # same
106 """
107         return t
108
109 class PutOptions(VDriveOptions):
110     optFlags = [
111         ("mutable", "m", "Create a mutable file instead of an immutable one."),
112         ]
113
114     def parseArgs(self, arg1=None, arg2=None):
115         # cat FILE > tahoe put           # create unlinked file from stdin
116         # cat FILE > tahoe put -         # same
117         # tahoe put bar                  # create unlinked file from local 'bar'
118         # cat FILE > tahoe put - FOO     # create tahoe:FOO from stdin
119         # tahoe put bar FOO              # copy local 'bar' to tahoe:FOO
120         # tahoe put bar tahoe:FOO        # same
121
122         if arg1 is not None and arg2 is not None:
123             self.from_file = arg1
124             self.to_file = arg2
125         elif arg1 is not None and arg2 is None:
126             self.from_file = arg1 # might be "-"
127             self.to_file = None
128         else:
129             self.from_file = None
130             self.to_file = None
131         if self.from_file == "-":
132             self.from_file = None
133
134     def getSynopsis(self):
135         return "%s put LOCAL_FILE VDRIVE_FILE" % (os.path.basename(sys.argv[0]),)
136
137     longdesc = """Put a file into the virtual drive (copying the file's
138     contents from the local filesystem). If VDRIVE_FILE is missing, upload
139     the file but do not link it into a directory: prints the new filecap to
140     stdout. If LOCAL_FILE is missing or '-', data will be copied from stdin.
141     VDRIVE_FILE is assumed to start with tahoe: unless otherwise specified."""
142
143     def getUsage(self, width=None):
144         t = VDriveOptions.getUsage(self, width)
145         t += """
146 Examples:
147  % cat FILE > tahoe put                # create unlinked file from stdin
148  % cat FILE > tahoe -                  # same
149  % tahoe put bar                       # create unlinked file from local 'bar'
150  % cat FILE > tahoe put - FOO          # create tahoe:FOO from stdin
151  % tahoe put bar FOO                   # copy local 'bar' to tahoe:FOO
152  % tahoe put bar tahoe:FOO             # same
153  % tahoe put bar MUTABLE-FILE-WRITECAP # modify the mutable file in-place
154 """
155         return t
156
157 class CpOptions(VDriveOptions):
158     optFlags = [
159         ("recursive", "r", "Copy source directory recursively."),
160         ("verbose", "v", "Be noisy about what is happening."),
161         ]
162     def parseArgs(self, *args):
163         if len(args) < 2:
164             raise usage.UsageError("cp requires at least two arguments")
165         self.sources = args[:-1]
166         self.destination = args[-1]
167
168 class RmOptions(VDriveOptions):
169     def parseArgs(self, where):
170         self.where = where
171
172     def getSynopsis(self):
173         return "%s rm VE_FILE" % (os.path.basename(sys.argv[0]),)
174
175 class MvOptions(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 mv FROM TO" % (os.path.basename(sys.argv[0]),)
182
183 class LnOptions(VDriveOptions):
184     def parseArgs(self, frompath, topath):
185         self.from_file = frompath
186         self.to_file = topath
187
188     def getSynopsis(self):
189         return "%s ln FROM TO" % (os.path.basename(sys.argv[0]),)
190
191 class WebopenOptions(VDriveOptions):
192     def parseArgs(self, where=''):
193         self.where = where
194
195     def getSynopsis(self):
196         return "%s webopen [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
197
198     longdesc = """Opens a webbrowser to the contents of some portion of the virtual drive."""
199
200 class ManifestOptions(VDriveOptions):
201     optFlags = [
202         ("storage-index", "s", "Only print storage index strings, not pathname+cap"),
203         ("raw", "r", "Display raw JSON data instead of parsed"),
204         ]
205     def parseArgs(self, where=''):
206         self.where = where
207
208     def getSynopsis(self):
209         return "%s manifest [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
210
211     longdesc = """Print a list of all files/directories reachable from the given starting point."""
212
213 class StatsOptions(VDriveOptions):
214     optFlags = [
215         ("raw", "r", "Display raw JSON data instead of parsed"),
216         ]
217     def parseArgs(self, where=''):
218         self.where = where
219
220     def getSynopsis(self):
221         return "%s stats [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
222
223     longdesc = """Print statistics about of all files/directories reachable from the given starting point."""
224
225 class CheckOptions(VDriveOptions):
226     optFlags = [
227         ("raw", "r", "Display raw JSON data instead of parsed"),
228         ("verify", "v", "Verify all hashes, instead of merely querying share presence"),
229         ("repair", "r", "Automatically repair any problems found"),
230         ]
231     def parseArgs(self, where=''):
232         self.where = where
233
234     def getSynopsis(self):
235         return "%s check [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
236
237     longdesc = """Check a single file or directory: count how many shares are available, verify their hashes. Optionally repair the file if any problems were found."""
238
239 class DeepCheckOptions(VDriveOptions):
240     optFlags = [
241         ("raw", "r", "Display raw JSON data instead of parsed"),
242         ("verify", "v", "Verify all hashes, instead of merely querying share presence"),
243         ("repair", "r", "Automatically repair any problems found"),
244         ]
245     def parseArgs(self, where=''):
246         self.where = where
247
248     def getSynopsis(self):
249         return "%s deep-check [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
250
251     longdesc = """Check all files/directories reachable from the given starting point (which must be a directory), like 'tahoe check' but for multiple files. Optionally repair any problems found."""
252
253 subCommands = [
254     ["mkdir", None, MakeDirectoryOptions, "Create a new directory"],
255     ["add-alias", None, AddAliasOptions, "Add a new alias cap"],
256     ["create-alias", None, CreateAliasOptions, "Create a new alias cap"],
257     ["list-aliases", None, ListAliasOptions, "List all alias caps"],
258     ["ls", None, ListOptions, "List a directory"],
259     ["get", None, GetOptions, "Retrieve a file from the virtual drive."],
260     ["put", None, PutOptions, "Upload a file into the virtual drive."],
261     ["cp", None, CpOptions, "Copy one or more files."],
262     ["rm", None, RmOptions, "Unlink a file or directory in the virtual drive."],
263     ["mv", None, MvOptions, "Move a file within the virtual drive."],
264     ["ln", None, LnOptions, "Make an additional link to an existing file."],
265     ["webopen", None, WebopenOptions, "Open a webbrowser to the root_dir"],
266     ["manifest", None, ManifestOptions, "List all files/dirs in a subtree"],
267     ["stats", None, StatsOptions, "Print statistics about all files/dirs in a subtree"],
268     ["check", None, CheckOptions, "Check a single file or directory"],
269     ["deep-check", None, DeepCheckOptions, "Check all files/directories reachable from a starting point"],
270     ]
271
272 def mkdir(options):
273     from allmydata.scripts import tahoe_mkdir
274     rc = tahoe_mkdir.mkdir(options)
275     return rc
276
277 def add_alias(options):
278     from allmydata.scripts import tahoe_add_alias
279     rc = tahoe_add_alias.add_alias(options)
280     return rc
281
282 def create_alias(options):
283     from allmydata.scripts import tahoe_add_alias
284     rc = tahoe_add_alias.create_alias(options)
285     return rc
286
287 def list_aliases(options):
288     from allmydata.scripts import tahoe_add_alias
289     rc = tahoe_add_alias.list_aliases(options)
290     return rc
291
292 def list(options):
293     from allmydata.scripts import tahoe_ls
294     rc = tahoe_ls.list(options)
295     return rc
296
297 def get(options):
298     from allmydata.scripts import tahoe_get
299     rc = tahoe_get.get(options)
300     if rc == 0:
301         if options.to_file is None:
302             # be quiet, since the file being written to stdout should be
303             # proof enough that it worked, unless the user is unlucky
304             # enough to have picked an empty file
305             pass
306         else:
307             print >>options.stderr, "%s retrieved and written to %s" % \
308                   (options.from_file, options.to_file)
309     return rc
310
311 def put(options):
312     from allmydata.scripts import tahoe_put
313     rc = tahoe_put.put(options)
314     return rc
315
316 def cp(options):
317     from allmydata.scripts import tahoe_cp
318     rc = tahoe_cp.copy(options)
319     return rc
320
321 def rm(options):
322     from allmydata.scripts import tahoe_rm
323     rc = tahoe_rm.rm(options)
324     return rc
325
326 def mv(options):
327     from allmydata.scripts import tahoe_mv
328     rc = tahoe_mv.mv(options, mode="move")
329     return rc
330
331 def ln(options):
332     from allmydata.scripts import tahoe_mv
333     rc = tahoe_mv.mv(options, mode="link")
334     return rc
335
336 def webopen(options, opener=None):
337     from allmydata.scripts import tahoe_webopen
338     rc = tahoe_webopen.webopen(options, opener=opener)
339     return rc
340
341 def manifest(options):
342     from allmydata.scripts import tahoe_manifest
343     rc = tahoe_manifest.manifest(options)
344     return rc
345
346 def stats(options):
347     from allmydata.scripts import tahoe_manifest
348     rc = tahoe_manifest.stats(options)
349     return rc
350
351 def check(options):
352     from allmydata.scripts import tahoe_check
353     rc = tahoe_check.check(options)
354     return rc
355
356 def deepcheck(options):
357     from allmydata.scripts import tahoe_check
358     rc = tahoe_check.deepcheck(options)
359     return rc
360
361 dispatch = {
362     "mkdir": mkdir,
363     "add-alias": add_alias,
364     "create-alias": create_alias,
365     "list-aliases": list_aliases,
366     "ls": list,
367     "get": get,
368     "put": put,
369     "cp": cp,
370     "rm": rm,
371     "mv": mv,
372     "ln": ln,
373     "webopen": webopen,
374     "manifest": manifest,
375     "stats": stats,
376     "check": check,
377     "deep-check": deepcheck,
378     }
379