-#!/usr/bin/env python
+import os
+from cStringIO import StringIO
import urllib
-from allmydata.scripts.common_http import do_http
+from allmydata.scripts.common_http import do_http, format_http_success, format_http_error
+from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
+ UnknownAliasError
+from allmydata.util.encodingutil import quote_output
-def put(nodeurl, root_uri, local_fname, vdrive_fname, verbosity,
- stdout, stderr):
+def put(options):
"""
@param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose
@return: a Deferred which eventually fires with the exit code
"""
+ nodeurl = options['node-url']
+ aliases = options.aliases
+ from_file = options.from_file
+ to_file = options.to_file
+ mutable = options['mutable']
+ format = options['format']
+ if options['quiet']:
+ verbosity = 0
+ else:
+ verbosity = 2
+ stdin = options.stdin
+ stdout = options.stdout
+ stderr = options.stderr
+
if nodeurl[-1] != "/":
nodeurl += "/"
- url = nodeurl + "uri/%s/" % urllib.quote(root_uri)
- if vdrive_fname:
- url += urllib.quote(vdrive_fname)
-
- infileobj = open(local_fname, "rb")
- resp = do_http("PUT", url, infileobj)
-
- if resp.status in (200, 201,):
- print >>stdout, "%s %s" % (resp.status, resp.reason)
- return 0
+ if to_file:
+ # several possibilities for the TO_FILE argument.
+ # <none> : unlinked upload
+ # foo : TAHOE_ALIAS/foo
+ # subdir/foo : TAHOE_ALIAS/subdir/foo
+ # /oops/subdir/foo : DISALLOWED
+ # ALIAS:foo : aliases[ALIAS]/foo
+ # ALIAS:subdir/foo : aliases[ALIAS]/subdir/foo
- print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
- print >>stderr, resp.read()
- return 1
-
-def main():
- import optparse, re
- parser = optparse.OptionParser()
- parser.add_option("-u", "--node-url", dest="nodeurl")
- parser.add_option("-r", "--root-uri", dest="rooturi")
+ # ALIAS:/oops/subdir/foo : DISALLOWED
+ # DIRCAP:./foo : DIRCAP/foo
+ # DIRCAP:./subdir/foo : DIRCAP/subdir/foo
+ # MUTABLE-FILE-WRITECAP : filecap
- (options, args) = parser.parse_args()
+ # FIXME: don't hardcode cap format.
+ if to_file.startswith("URI:MDMF:") or to_file.startswith("URI:SSK:"):
+ url = nodeurl + "uri/%s" % urllib.quote(to_file)
+ else:
+ try:
+ rootcap, path = get_alias(aliases, to_file, DEFAULT_ALIAS)
+ except UnknownAliasError, e:
+ e.display(stderr)
+ return 1
+ if path.startswith("/"):
+ suggestion = to_file.replace(u"/", u"", 1)
+ print >>stderr, "Error: The remote filename must not start with a slash"
+ print >>stderr, "Please try again, perhaps with %s" % quote_output(suggestion)
+ return 1
+ url = nodeurl + "uri/%s/" % urllib.quote(rootcap)
+ if path:
+ url += escape_path(path)
+ else:
+ # unlinked upload
+ url = nodeurl + "uri"
- 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,))
+ queryargs = []
+ if mutable:
+ queryargs.append("mutable=true")
+ if format:
+ queryargs.append("format=%s" % format)
+ if queryargs:
+ url += "?" + "&".join(queryargs)
- if not options.rooturi:
- raise ValueError("must provide --root-uri")
+ if from_file:
+ infileobj = open(os.path.expanduser(from_file), "rb")
+ else:
+ # do_http() can't use stdin directly: for one thing, we need a
+ # Content-Length field. So we currently must copy it.
+ if verbosity > 0:
+ print >>stderr, "waiting for file data on stdin.."
+ data = stdin.read()
+ infileobj = StringIO(data)
- local_file = args[0]
- vdrive_fname = None
- if len(args) > 1:
- vdrive_fname = args[1]
+ resp = do_http("PUT", url, infileobj)
- return put(options.nodeurl, options.rooturi, vdrive_fname, local_file)
+ if resp.status in (200, 201,):
+ print >>stderr, format_http_success(resp)
+ print >>stdout, quote_output(resp.read(), quotemarks=False)
+ return 0
-if __name__ == '__main__':
- main()
+ print >>stderr, format_http_error("Error", resp)
+ return 1