From a12ef1ae82a6d07ea96aa736b9708e33c7a8aea8 Mon Sep 17 00:00:00 2001 From: Zooko O'Whielacronx Date: Fri, 17 Aug 2007 13:23:16 -0700 Subject: [PATCH] command-line: add "rm", and tidy-up variable names, and make it so "allmydata-tahoe spam" prints a usage message instead of returning silently --- relnotes.txt | 9 ++-- src/allmydata/scripts/cli.py | 31 ++++++++++-- src/allmydata/scripts/runner.py | 2 + src/allmydata/scripts/tahoe_get.py | 10 ++-- src/allmydata/scripts/tahoe_ls.py | 12 ++--- src/allmydata/scripts/tahoe_put.py | 8 ++-- src/allmydata/scripts/tahoe_rm.py | 77 ++++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 src/allmydata/scripts/tahoe_rm.py diff --git a/relnotes.txt b/relnotes.txt index 42588484..7bed667c 100644 --- a/relnotes.txt +++ b/relnotes.txt @@ -104,10 +104,11 @@ available there, with download links, and forms to upload new files. USAGE - command-line interface -Run "allmydata-tahoe ls [VIRTUAL DIRECTORY NAME]" to list the contents -of a virtual directory. Run "allmydata-tahoe get [VIRTUAL FILE NAME] -[LOCAL FILE NAME]" to download a file. Run "allmydata-tahoe put -[LOCAL FILE NAME] [VIRTUAL FILE NAME]" to upload a file. +Run "allmydata-tahoe ls [VIRTUAL PATH NAME]" to list the contents of a +virtual directory. Run "allmydata-tahoe get [VIRTUAL FILE NAME] [LOCAL FILE +NAME]" to download a file. Run "allmydata-tahoe put [LOCAL FILE NAME] +[VIRTUAL FILE NAME]" to upload a file. Run "allmydata-tahoe rm [VIRTUAL PATH +NAME]" to unlink a file or directory in the virtual drive. USAGE - other diff --git a/src/allmydata/scripts/cli.py b/src/allmydata/scripts/cli.py index 61180061..80d355d7 100644 --- a/src/allmydata/scripts/cli.py +++ b/src/allmydata/scripts/cli.py @@ -19,8 +19,8 @@ class VDriveOptions(BaseOptions, usage.Options): raise usage.UsageError("--node-url is required to be a string and look like \"http://HOSTNAMEORADDR:PORT\", not: %r" % (self['node-url'],)) class ListOptions(VDriveOptions): - def parseArgs(self, vdrive_filename=""): - self['vdrive_filename'] = vdrive_filename + def parseArgs(self, vdrive_pathname=""): + self['vdrive_pathname'] = vdrive_pathname longdesc = """List the contents of some portion of the virtual drive.""" @@ -38,8 +38,8 @@ class GetOptions(VDriveOptions): class PutOptions(VDriveOptions): def parseArgs(self, local_filename, vdrive_filename): - self['vdrive_filename'] = vdrive_filename self['local_filename'] = local_filename + self['vdrive_filename'] = vdrive_filename def getSynopsis(self): return "%s put LOCAL_FILEVDRI VE_FILE" % (os.path.basename(sys.argv[0]),) @@ -48,19 +48,26 @@ class PutOptions(VDriveOptions): contents from the local filesystem). If LOCAL_FILE is omitted or '-', the contents of the file will be read from stdin.""" +class RmOptions(VDriveOptions): + def parseArgs(self, vdrive_pathname): + self['vdrive_pathname'] = vdrive_pathname + + def getSynopsis(self): + return "%s rm VE_FILE" % (os.path.basename(sys.argv[0]),) subCommands = [ ["ls", None, ListOptions, "List a directory"], ["get", None, GetOptions, "Retrieve a file from the virtual drive."], ["put", None, PutOptions, "Upload a file into the virtual drive."], + ["rm", None, RmOptions, "Unlink a file or directory in the virtual drive."], ] def list(config, stdout, stderr): from allmydata.scripts import tahoe_ls rc = tahoe_ls.list(config['node-url'], config['vdrive'], - config['vdrive_filename']) + config['vdrive_pathname']) return rc def get(config, stdout, stderr): @@ -92,8 +99,21 @@ def put(config, stdout, stderr): verbosity = 2 rc = tahoe_put.put(config['node-url'], config['vdrive'], - vdrive_filename, local_filename, + vdrive_filename, + verbosity) + return rc + +def rm(config, stdout, stderr): + from allmydata.scripts import tahoe_rm + vdrive_pathname = config['vdrive_pathname'] + if config['quiet']: + verbosity = 0 + else: + verbosity = 2 + rc = tahoe_rm.rm(config['node-url'], + config['vdrive'], + vdrive_pathname, verbosity) return rc @@ -101,5 +121,6 @@ dispatch = { "ls": list, "get": get, "put": put, + "rm": rm, } diff --git a/src/allmydata/scripts/runner.py b/src/allmydata/scripts/runner.py index 72935fa7..c6a9d490 100644 --- a/src/allmydata/scripts/runner.py +++ b/src/allmydata/scripts/runner.py @@ -49,6 +49,8 @@ def runner(argv, run_by_human=True, stdout=sys.stdout, stderr=sys.stderr): rc = debug.dispatch[command](so, stdout, stderr) elif command in cli.dispatch: rc = cli.dispatch[command](so, stdout, stderr) + else: + raise usage.UsageError() return rc diff --git a/src/allmydata/scripts/tahoe_get.py b/src/allmydata/scripts/tahoe_get.py index 66e98313..9a299230 100644 --- a/src/allmydata/scripts/tahoe_get.py +++ b/src/allmydata/scripts/tahoe_get.py @@ -2,12 +2,12 @@ import sys, urllib -def get(nodeurl, vdrive, vdrive_file, local_file): +def get(nodeurl, vdrive, vdrive_fname, local_file): if nodeurl[-1] != "/": nodeurl += "/" url = nodeurl + "vdrive/" + vdrive + "/" - if vdrive_file: - url += vdrive_file + if vdrive_fname: + url += vdrive_fname if local_file is None or local_file == "-": outf = sys.stdout @@ -36,12 +36,12 @@ def main(): if not isinstance(options.nodeurl, basestring) or not NODEURL_RE.match(options.nodeurl): raise ValueError("--node-url is required to be a string and look like \"http://HOSTNAMEORADDR:PORT\", not: %r" % (options.nodeurl,)) - vdrive_file = args[0] + vdrive_fname = args[0] local_file = None if len(args) > 1: local_file = args[1] - get(options.nodeurl, options.vdrive, vdrive_file, local_file) + get(options.nodeurl, options.vdrive, vdrive_fname, local_file) if __name__ == '__main__': main() diff --git a/src/allmydata/scripts/tahoe_ls.py b/src/allmydata/scripts/tahoe_ls.py index 473d9804..bea86b62 100644 --- a/src/allmydata/scripts/tahoe_ls.py +++ b/src/allmydata/scripts/tahoe_ls.py @@ -3,12 +3,12 @@ import urllib import simplejson -def list(nodeurl, vdrive, vdrive_file): +def list(nodeurl, vdrive, vdrive_pathname): if nodeurl[-1] != "/": nodeurl += "/" url = nodeurl + "vdrive/" + vdrive + "/" - if vdrive_file: - url += vdrive_file + if vdrive_pathname: + url += vdrive_pathname url += "?t=json" data = urllib.urlopen(url).read() @@ -40,11 +40,11 @@ def main(): if not isinstance(options.nodeurl, basestring) or not NODEURL_RE.match(options.nodeurl): raise ValueError("--node-url is required to be a string and look like \"http://HOSTNAMEORADDR:PORT\", not: %r" % (options.nodeurl,)) - vdrive_file = "" + vdrive_pathname = "" if args: - vdrive_file = args[0] + vdrive_pathname = args[0] - list(options.nodeurl, options.vdrive, vdrive_file) + list(options.nodeurl, options.vdrive, vdrive_pathname) if __name__ == '__main__': main() diff --git a/src/allmydata/scripts/tahoe_put.py b/src/allmydata/scripts/tahoe_put.py index 6a419740..4b548004 100644 --- a/src/allmydata/scripts/tahoe_put.py +++ b/src/allmydata/scripts/tahoe_put.py @@ -4,7 +4,7 @@ import re, socket, sys NODEURL_RE=re.compile("http://([^:]*)(:([1-9][0-9]*))?") -def put(nodeurl, vdrive, vdrive_fname, local_fname, verbosity): +def put(nodeurl, vdrive, local_fname, vdrive_fname, verbosity): """ @param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose @@ -85,11 +85,11 @@ def main(): raise ValueError("--node-url is required to be a string and look like \"http://HOSTNAMEORADDR:PORT\", not: %r" % (options.nodeurl,)) local_file = args[0] - vdrive_file = None + vdrive_fname = None if len(args) > 1: - vdrive_file = args[1] + vdrive_fname = args[1] - return put(options.nodeurl, options.vdrive, vdrive_file, local_file) + return put(options.nodeurl, options.vdrive, vdrive_fname, local_file) if __name__ == '__main__': main() diff --git a/src/allmydata/scripts/tahoe_rm.py b/src/allmydata/scripts/tahoe_rm.py new file mode 100644 index 00000000..c9be8457 --- /dev/null +++ b/src/allmydata/scripts/tahoe_rm.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +import re, socket, sys + +NODEURL_RE=re.compile("http://([^:]*)(:([1-9][0-9]*))?") + +def rm(nodeurl, vdrive, vdrive_pathname, verbosity): + """ + @param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose + + @return: a Deferred which eventually fires with the exit code + """ + mo = NODEURL_RE.match(nodeurl) + host = mo.group(1) + port = int(mo.group(3)) + + url = "/vdrive/" + vdrive + "/" + if vdrive_pathname: + url += vdrive_pathname + + so = socket.socket() + so.connect((host, port,)) + + CHUNKSIZE=2**16 + data = "DELETE %s HTTP/1.1\r\nConnection: close\r\nHostname: %s\r\n\r\n" % (url, host,) + sent = so.send(data) + + respbuf = [] + data = so.recv(CHUNKSIZE) + while data: + respbuf.append(data) + data = so.recv(CHUNKSIZE) + + so.shutdown(socket.SHUT_WR) + + data = so.recv(CHUNKSIZE) + while data: + respbuf.append(data) + data = so.recv(CHUNKSIZE) + + respstr = ''.join(respbuf) + + headerend = respstr.find('\r\n\r\n') + if headerend == -1: + headerend = len(respstr) + header = respstr[:headerend] + RESP_RE=re.compile("^HTTP/[0-9]\.[0-9] ([0-9]*) *([A-Za-z_ ]*)") # This regex is soooo ad hoc... --Zooko 2007-08-16 + mo = RESP_RE.match(header) + if mo: + code = int(mo.group(1)) + word = mo.group(2) + + if code == 200: + print "%s %s" % (code, word,) + return 0 + + print respstr[headerend:] + return 1 + +def main(): + import optparse, re + parser = optparse.OptionParser() + parser.add_option("-d", "--vdrive", dest="vdrive", default="global") + parser.add_option("-u", "--node-url", dest="nodeurl") + + (options, args) = parser.parse_args() + + NODEURL_RE=re.compile("http://([^:]*)(:([1-9][0-9]*))?") + if not isinstance(options.nodeurl, basestring) or not NODEURL_RE.match(options.nodeurl): + raise ValueError("--node-url is required to be a string and look like \"http://HOSTNAMEORADDR:PORT\", not: %r" % (options.nodeurl,)) + + vdrive_pathname = args[0] + + return put(options.nodeurl, options.vdrive, vdrive_pathname, local_file) + +if __name__ == '__main__': + main() -- 2.45.2