mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-24 15:16:41 +00:00
overhaul CLI: not quite complete but it works a lot better than it used to. The new scheme uses 'tahoe add-alias' and rsync/scp-style 'alias:foo/bar.txt' arguments
This commit is contained in:
parent
9662e6d986
commit
8e92dfcb50
@ -140,7 +140,7 @@ use the following command to create a new directory and set it as your
|
|||||||
|
|
||||||
tahoe set-alias tahoe `tahoe mkdir`
|
tahoe set-alias tahoe `tahoe mkdir`
|
||||||
|
|
||||||
After thatm you can use "tahoe ls tahoe:" and "tahoe cp local.txt tahoe:",
|
After that you can use "tahoe ls tahoe:" and "tahoe cp local.txt tahoe:",
|
||||||
and both will refer to the directory that you've just created.
|
and both will refer to the directory that you've just created.
|
||||||
|
|
||||||
=== Command Syntax Summary ===
|
=== Command Syntax Summary ===
|
||||||
|
@ -17,11 +17,8 @@ class VDriveOptions(BaseOptions, usage.Options):
|
|||||||
["node-url", "u", None,
|
["node-url", "u", None,
|
||||||
"URL of the tahoe node to use, a URL like \"http://127.0.0.1:8123\". "
|
"URL of the tahoe node to use, a URL like \"http://127.0.0.1:8123\". "
|
||||||
"This overrides the URL found in the --node-directory ."],
|
"This overrides the URL found in the --node-directory ."],
|
||||||
["dir-cap", "r", "root",
|
["dir-cap", "r", None,
|
||||||
"Which dirnode URI should be used as a root directory. The "
|
"Which dirnode URI should be used as the 'tahoe' alias."]
|
||||||
"string 'root' is special, and means we should use the "
|
|
||||||
"directory found in the 'root_dir.cap' file in the 'private' "
|
|
||||||
"subdirectory of the --node-directory ."],
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def postOptions(self):
|
def postOptions(self):
|
||||||
@ -43,46 +40,71 @@ class VDriveOptions(BaseOptions, usage.Options):
|
|||||||
node_url_file = os.path.join(self['node-directory'], "node.url")
|
node_url_file = os.path.join(self['node-directory'], "node.url")
|
||||||
self['node-url'] = open(node_url_file, "r").read().strip()
|
self['node-url'] = open(node_url_file, "r").read().strip()
|
||||||
|
|
||||||
rootdircap = None
|
aliases = self.get_aliases(self['node-directory'])
|
||||||
if self['dir-cap'] == 'root':
|
if self['dir-cap']:
|
||||||
uri_file = os.path.join(self['node-directory'], 'private', "root_dir.cap")
|
aliases["tahoe"] = self['dir-cap']
|
||||||
try:
|
self.aliases = aliases # maps alias name to dircap
|
||||||
rootdircap = open(uri_file, "r").read().strip()
|
|
||||||
except EnvironmentError, le:
|
|
||||||
raise usage.UsageError("\n"
|
|
||||||
"If --dir-cap is absent or is 'root', then the node directory's 'private'\n"
|
|
||||||
"subdirectory is required to contain a file named 'root_dir.cap' which is\n"
|
|
||||||
"required to contain a dir cap, but when we tried to open that file we got:\n"
|
|
||||||
"'%s'." % (le,))
|
|
||||||
else:
|
|
||||||
rootdircap = self['dir-cap']
|
|
||||||
from allmydata import uri
|
|
||||||
try:
|
|
||||||
parsed = uri.NewDirectoryURI.init_from_human_encoding(rootdircap)
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
parsed = uri.ReadonlyNewDirectoryURI.init_from_human_encoding(rootdircap)
|
|
||||||
except:
|
|
||||||
if self['dir-cap'] == 'root':
|
|
||||||
raise usage.UsageError("\n"
|
|
||||||
"If --dir-cap is absent or is 'root', then the node directory's 'private'\n"
|
|
||||||
"subdirectory's 'root_dir.cap' is required to contain a dir cap, but we found\n"
|
|
||||||
"'%s'." % (rootdircap,))
|
|
||||||
else:
|
|
||||||
raise usage.UsageError("--dir-cap is required to be a dir cap (or \"root\"), but we got '%s'." % (self['dir-cap'],))
|
|
||||||
|
|
||||||
self['dir-cap'] = parsed.to_string()
|
|
||||||
|
def get_aliases(self, nodedir):
|
||||||
|
from allmydata import uri
|
||||||
|
aliases = {}
|
||||||
|
aliasfile = os.path.join(nodedir, "private", "aliases")
|
||||||
|
rootfile = os.path.join(nodedir, "private", "root_dir.cap")
|
||||||
|
try:
|
||||||
|
f = open(rootfile, "r")
|
||||||
|
rootcap = f.read().strip()
|
||||||
|
if rootcap:
|
||||||
|
aliases["tahoe"] = uri.from_string_dirnode(rootcap).to_string()
|
||||||
|
except EnvironmentError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
f = open(aliasfile, "r")
|
||||||
|
for line in f.readlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("#"):
|
||||||
|
continue
|
||||||
|
name, cap = line.split(":", 1)
|
||||||
|
# normalize it: remove http: prefix, urldecode
|
||||||
|
cap = cap.strip()
|
||||||
|
aliases[name] = uri.from_string_dirnode(cap).to_string()
|
||||||
|
except EnvironmentError:
|
||||||
|
pass
|
||||||
|
return aliases
|
||||||
|
|
||||||
|
class MakeDirectoryOptions(VDriveOptions):
|
||||||
|
def parseArgs(self, where=""):
|
||||||
|
self.where = where
|
||||||
|
longdesc = """Create a new directory, either unlinked or as a subdirectory."""
|
||||||
|
|
||||||
|
class AddAliasOptions(VDriveOptions):
|
||||||
|
def parseArgs(self, alias, cap):
|
||||||
|
self.alias = alias
|
||||||
|
self.cap = cap
|
||||||
|
|
||||||
class ListOptions(VDriveOptions):
|
class ListOptions(VDriveOptions):
|
||||||
def parseArgs(self, vdrive_pathname=""):
|
optFlags = [
|
||||||
self['vdrive_pathname'] = vdrive_pathname
|
("long", "l", "Use long format: show file sizes, and timestamps"),
|
||||||
|
("uri", "u", "Show file URIs"),
|
||||||
|
("classify", "F", "Append '/' to directory names, and '*' to mutable"),
|
||||||
|
("json", None, "Show the raw JSON output"),
|
||||||
|
]
|
||||||
|
def parseArgs(self, where=""):
|
||||||
|
self.where = where
|
||||||
|
|
||||||
longdesc = """List the contents of some portion of the virtual drive."""
|
longdesc = """List the contents of some portion of the virtual drive."""
|
||||||
|
|
||||||
class GetOptions(VDriveOptions):
|
class GetOptions(VDriveOptions):
|
||||||
def parseArgs(self, vdrive_filename, local_filename="-"):
|
def parseArgs(self, arg1, arg2=None):
|
||||||
self['vdrive_filename'] = vdrive_filename
|
# tahoe get FOO |less # write to stdout
|
||||||
self['local_filename'] = local_filename
|
# tahoe get tahoe:FOO |less # same
|
||||||
|
# tahoe get FOO bar # write to local file
|
||||||
|
# tahoe get tahoe:FOO bar # same
|
||||||
|
|
||||||
|
self.from_file = arg1
|
||||||
|
self.to_file = arg2
|
||||||
|
if self.to_file == "-":
|
||||||
|
self.to_file = None
|
||||||
|
|
||||||
def getSynopsis(self):
|
def getSynopsis(self):
|
||||||
return "%s get VDRIVE_FILE LOCAL_FILE" % (os.path.basename(sys.argv[0]),)
|
return "%s get VDRIVE_FILE LOCAL_FILE" % (os.path.basename(sys.argv[0]),)
|
||||||
@ -92,9 +114,24 @@ class GetOptions(VDriveOptions):
|
|||||||
will be written to stdout."""
|
will be written to stdout."""
|
||||||
|
|
||||||
class PutOptions(VDriveOptions):
|
class PutOptions(VDriveOptions):
|
||||||
def parseArgs(self, local_filename, vdrive_filename):
|
def parseArgs(self, arg1=None, arg2=None):
|
||||||
self['local_filename'] = local_filename
|
# cat FILE > tahoe put # create unlinked file from stdin
|
||||||
self['vdrive_filename'] = vdrive_filename
|
# cat FILE > tahoe put FOO # create tahoe:FOO from stdin
|
||||||
|
# cat FILE > tahoe put tahoe:FOO # same
|
||||||
|
# tahoe put bar FOO # copy local 'bar' to tahoe:FOO
|
||||||
|
# tahoe put bar tahoe:FOO # same
|
||||||
|
|
||||||
|
if arg1 is not None and arg2 is not None:
|
||||||
|
self.from_file = arg1
|
||||||
|
self.to_file = arg2
|
||||||
|
elif arg1 is not None and arg2 is None:
|
||||||
|
self.from_file = None
|
||||||
|
self.to_file = arg1
|
||||||
|
else:
|
||||||
|
self.from_file = arg1
|
||||||
|
self.to_file = arg2
|
||||||
|
if self.from_file == "-":
|
||||||
|
self.from_file = None
|
||||||
|
|
||||||
def getSynopsis(self):
|
def getSynopsis(self):
|
||||||
return "%s put LOCAL_FILE VDRIVE_FILE" % (os.path.basename(sys.argv[0]),)
|
return "%s put LOCAL_FILE VDRIVE_FILE" % (os.path.basename(sys.argv[0]),)
|
||||||
@ -104,16 +141,16 @@ class PutOptions(VDriveOptions):
|
|||||||
local file (it can't be stdin)."""
|
local file (it can't be stdin)."""
|
||||||
|
|
||||||
class RmOptions(VDriveOptions):
|
class RmOptions(VDriveOptions):
|
||||||
def parseArgs(self, vdrive_pathname):
|
def parseArgs(self, where):
|
||||||
self['vdrive_pathname'] = vdrive_pathname
|
self.where = where
|
||||||
|
|
||||||
def getSynopsis(self):
|
def getSynopsis(self):
|
||||||
return "%s rm VE_FILE" % (os.path.basename(sys.argv[0]),)
|
return "%s rm VE_FILE" % (os.path.basename(sys.argv[0]),)
|
||||||
|
|
||||||
class MvOptions(VDriveOptions):
|
class MvOptions(VDriveOptions):
|
||||||
def parseArgs(self, frompath, topath):
|
def parseArgs(self, frompath, topath):
|
||||||
self['from'] = frompath
|
self.from_file = frompath
|
||||||
self['to'] = topath
|
self.to_file = topath
|
||||||
|
|
||||||
def getSynopsis(self):
|
def getSynopsis(self):
|
||||||
return "%s mv FROM TO" % (os.path.basename(sys.argv[0]),)
|
return "%s mv FROM TO" % (os.path.basename(sys.argv[0]),)
|
||||||
@ -128,6 +165,8 @@ class ReplOptions(usage.Options):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
subCommands = [
|
subCommands = [
|
||||||
|
["mkdir", None, MakeDirectoryOptions, "Create a new directory"],
|
||||||
|
["add-alias", None, AddAliasOptions, "Add a new alias cap"],
|
||||||
["ls", None, ListOptions, "List a directory"],
|
["ls", None, ListOptions, "List a directory"],
|
||||||
["get", None, GetOptions, "Retrieve a file from the virtual drive."],
|
["get", None, GetOptions, "Retrieve a file from the virtual drive."],
|
||||||
["put", None, PutOptions, "Upload a file into the virtual drive."],
|
["put", None, PutOptions, "Upload a file into the virtual drive."],
|
||||||
@ -137,72 +176,82 @@ subCommands = [
|
|||||||
["repl", None, ReplOptions, "Open a python interpreter"],
|
["repl", None, ReplOptions, "Open a python interpreter"],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def mkdir(config, stdout, stderr):
|
||||||
|
from allmydata.scripts import tahoe_mkdir
|
||||||
|
rc = tahoe_mkdir.mkdir(config['node-url'],
|
||||||
|
config.aliases,
|
||||||
|
config.where,
|
||||||
|
stdout, stderr)
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def add_alias(config, stdout, stderr):
|
||||||
|
from allmydata.scripts import tahoe_add_alias
|
||||||
|
rc = tahoe_add_alias.add_alias(config['node-directory'],
|
||||||
|
config.alias,
|
||||||
|
config.cap,
|
||||||
|
stdout, stderr)
|
||||||
|
return rc
|
||||||
|
|
||||||
def list(config, stdout, stderr):
|
def list(config, stdout, stderr):
|
||||||
from allmydata.scripts import tahoe_ls
|
from allmydata.scripts import tahoe_ls
|
||||||
rc = tahoe_ls.list(config['node-url'],
|
rc = tahoe_ls.list(config['node-url'],
|
||||||
config['dir-cap'],
|
config.aliases,
|
||||||
config['vdrive_pathname'],
|
config.where,
|
||||||
|
config,
|
||||||
stdout, stderr)
|
stdout, stderr)
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def get(config, stdout, stderr):
|
def get(config, stdout, stderr):
|
||||||
from allmydata.scripts import tahoe_get
|
from allmydata.scripts import tahoe_get
|
||||||
vdrive_filename = config['vdrive_filename']
|
|
||||||
local_filename = config['local_filename']
|
|
||||||
rc = tahoe_get.get(config['node-url'],
|
rc = tahoe_get.get(config['node-url'],
|
||||||
config['dir-cap'],
|
config.aliases,
|
||||||
vdrive_filename,
|
config.from_file,
|
||||||
local_filename,
|
config.to_file,
|
||||||
stdout, stderr)
|
stdout, stderr)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
if local_filename is None or local_filename == "-":
|
if config.to_file is None:
|
||||||
# be quiet, since the file being written to stdout should be
|
# be quiet, since the file being written to stdout should be
|
||||||
# proof enough that it worked, unless the user is unlucky
|
# proof enough that it worked, unless the user is unlucky
|
||||||
# enough to have picked an empty file
|
# enough to have picked an empty file
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
print >>stderr, "%s retrieved and written to %s" % \
|
print >>stderr, "%s retrieved and written to %s" % \
|
||||||
(vdrive_filename, local_filename)
|
(config.from_file, config.to_file)
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def put(config, stdout, stderr):
|
def put(config, stdout, stderr, stdin=sys.stdin):
|
||||||
from allmydata.scripts import tahoe_put
|
from allmydata.scripts import tahoe_put
|
||||||
vdrive_filename = config['vdrive_filename']
|
|
||||||
local_filename = config['local_filename']
|
|
||||||
if config['quiet']:
|
if config['quiet']:
|
||||||
verbosity = 0
|
verbosity = 0
|
||||||
else:
|
else:
|
||||||
verbosity = 2
|
verbosity = 2
|
||||||
rc = tahoe_put.put(config['node-url'],
|
rc = tahoe_put.put(config['node-url'],
|
||||||
config['dir-cap'],
|
config.aliases,
|
||||||
local_filename,
|
config.from_file,
|
||||||
vdrive_filename,
|
config.to_file,
|
||||||
verbosity,
|
verbosity,
|
||||||
stdout, stderr)
|
stdin, stdout, stderr)
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def rm(config, stdout, stderr):
|
def rm(config, stdout, stderr):
|
||||||
from allmydata.scripts import tahoe_rm
|
from allmydata.scripts import tahoe_rm
|
||||||
vdrive_pathname = config['vdrive_pathname']
|
|
||||||
if config['quiet']:
|
if config['quiet']:
|
||||||
verbosity = 0
|
verbosity = 0
|
||||||
else:
|
else:
|
||||||
verbosity = 2
|
verbosity = 2
|
||||||
rc = tahoe_rm.rm(config['node-url'],
|
rc = tahoe_rm.rm(config['node-url'],
|
||||||
config['dir-cap'],
|
config.aliases,
|
||||||
vdrive_pathname,
|
config.where,
|
||||||
verbosity,
|
verbosity,
|
||||||
stdout, stderr)
|
stdout, stderr)
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def mv(config, stdout, stderr):
|
def mv(config, stdout, stderr):
|
||||||
from allmydata.scripts import tahoe_mv
|
from allmydata.scripts import tahoe_mv
|
||||||
frompath = config['from']
|
|
||||||
topath = config['to']
|
|
||||||
rc = tahoe_mv.mv(config['node-url'],
|
rc = tahoe_mv.mv(config['node-url'],
|
||||||
config['dir-cap'],
|
config.aliases,
|
||||||
frompath,
|
config.from_file,
|
||||||
topath,
|
config.to_file,
|
||||||
stdout, stderr)
|
stdout, stderr)
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
@ -222,6 +271,8 @@ def repl(config, stdout, stderr):
|
|||||||
return code.interact()
|
return code.interact()
|
||||||
|
|
||||||
dispatch = {
|
dispatch = {
|
||||||
|
"mkdir": mkdir,
|
||||||
|
"add-alias": add_alias,
|
||||||
"ls": list,
|
"ls": list,
|
||||||
"get": get,
|
"get": get,
|
||||||
"put": put,
|
"put": put,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import os, sys
|
import os, sys, urllib
|
||||||
from twisted.python import usage
|
from twisted.python import usage
|
||||||
|
|
||||||
|
|
||||||
@ -62,4 +62,29 @@ class NoDefaultBasedirMixin(BasedirMixin):
|
|||||||
if not self.basedirs:
|
if not self.basedirs:
|
||||||
raise usage.UsageError("--basedir must be provided")
|
raise usage.UsageError("--basedir must be provided")
|
||||||
|
|
||||||
|
DEFAULT_ALIAS = "tahoe"
|
||||||
|
|
||||||
|
def get_alias(aliases, path, default):
|
||||||
|
# transform "work:path/filename" into (aliases["work"], "path/filename")
|
||||||
|
# We special-case URI:
|
||||||
|
if path.startswith("URI:"):
|
||||||
|
# The only way to get a sub-path is to use URI:blah:./foo, and we
|
||||||
|
# strip out the :./ sequence.
|
||||||
|
sep = path.find(":./")
|
||||||
|
if sep != -1:
|
||||||
|
return path[:sep], path[sep+3:]
|
||||||
|
return path, ""
|
||||||
|
colon = path.find(":")
|
||||||
|
if colon == -1:
|
||||||
|
# no alias
|
||||||
|
return aliases[default], path
|
||||||
|
alias = path[:colon]
|
||||||
|
if "/" in alias:
|
||||||
|
# no alias, but there's a colon in a dirname/filename, like
|
||||||
|
# "foo/bar:7"
|
||||||
|
return aliases[default], path
|
||||||
|
return aliases[alias], path[colon+1:]
|
||||||
|
|
||||||
|
def escape_path(path):
|
||||||
|
segments = path.split("/")
|
||||||
|
return "/".join([urllib.quote(s) for s in segments])
|
||||||
|
@ -58,3 +58,8 @@ def do_http(method, url, body=""):
|
|||||||
c.send(data)
|
c.send(data)
|
||||||
|
|
||||||
return c.getresponse()
|
return c.getresponse()
|
||||||
|
|
||||||
|
def check_http_error(resp, stderr):
|
||||||
|
if resp.status < 200 or resp.status >= 300:
|
||||||
|
print >>stderr, "error %d during HTTP request" % resp.status
|
||||||
|
return 1
|
||||||
|
@ -56,11 +56,8 @@ def create_client(basedir, config, out=sys.stdout, err=sys.stderr):
|
|||||||
f = open(os.path.join(basedir, "webport"), "w")
|
f = open(os.path.join(basedir, "webport"), "w")
|
||||||
f.write(config['webport'] + "\n")
|
f.write(config['webport'] + "\n")
|
||||||
f.close()
|
f.close()
|
||||||
# Create an empty root_dir.cap file, indicating that the node
|
|
||||||
# should fill it with the URI after creating the directory.
|
|
||||||
from allmydata.util import fileutil
|
from allmydata.util import fileutil
|
||||||
fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
|
fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
|
||||||
open(os.path.join(basedir, "private", "root_dir.cap"), "w")
|
|
||||||
print >>out, "client created in %s" % basedir
|
print >>out, "client created in %s" % basedir
|
||||||
print >>out, " please copy introducer.furl into the directory"
|
print >>out, " please copy introducer.furl into the directory"
|
||||||
|
|
||||||
|
16
src/allmydata/scripts/tahoe_add_alias.py
Normal file
16
src/allmydata/scripts/tahoe_add_alias.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
import os.path
|
||||||
|
from allmydata import uri
|
||||||
|
|
||||||
|
def add_alias(nodedir, alias, cap, stdout, stderr):
|
||||||
|
aliasfile = os.path.join(nodedir, "private", "aliases")
|
||||||
|
cap = uri.from_string_dirnode(cap).to_string()
|
||||||
|
assert ":" not in alias
|
||||||
|
assert " " not in alias
|
||||||
|
# probably check for others..
|
||||||
|
f = open(aliasfile, "a")
|
||||||
|
f.write("%s: %s\n" % (alias, cap))
|
||||||
|
f.close()
|
||||||
|
print >>stdout, "Alias '%s' added" % (alias,)
|
||||||
|
return 0
|
||||||
|
|
@ -1,26 +1,37 @@
|
|||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
|
from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
|
||||||
|
from allmydata.scripts.common_http import do_http
|
||||||
|
|
||||||
def get(nodeurl, dir_uri, vdrive_fname, local_file, stdout, stderr):
|
def get(nodeurl, aliases, from_file, to_file, stdout, stderr):
|
||||||
if nodeurl[-1] != "/":
|
if nodeurl[-1] != "/":
|
||||||
nodeurl += "/"
|
nodeurl += "/"
|
||||||
url = nodeurl + "uri/%s/" % urllib.quote(dir_uri)
|
rootcap, path = get_alias(aliases, from_file, DEFAULT_ALIAS)
|
||||||
if vdrive_fname:
|
url = nodeurl + "uri/%s" % urllib.quote(rootcap)
|
||||||
url += urllib.quote(vdrive_fname)
|
if path:
|
||||||
|
url += "/" + escape_path(path)
|
||||||
|
|
||||||
if local_file is None or local_file == "-":
|
if to_file:
|
||||||
|
outf = open(to_file, "wb")
|
||||||
|
close_outf = True
|
||||||
|
else:
|
||||||
outf = stdout
|
outf = stdout
|
||||||
close_outf = False
|
close_outf = False
|
||||||
else:
|
|
||||||
outf = open(local_file, "wb")
|
resp = do_http("GET", url)
|
||||||
close_outf = True
|
if resp.status in (200, 201,):
|
||||||
inf = urllib.urlopen(url)
|
|
||||||
while True:
|
while True:
|
||||||
data = inf.read(4096)
|
data = resp.read(4096)
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
outf.write(data)
|
outf.write(data)
|
||||||
|
rc = 0
|
||||||
|
else:
|
||||||
|
print >>stderr, "Error, got %s %s" % (resp.status, resp.reason)
|
||||||
|
print >>stderr, resp.read()
|
||||||
|
rc = 1
|
||||||
|
|
||||||
if close_outf:
|
if close_outf:
|
||||||
outf.close()
|
outf.close()
|
||||||
|
|
||||||
return 0
|
return rc
|
||||||
|
@ -1,28 +1,71 @@
|
|||||||
|
|
||||||
import urllib
|
import urllib, time
|
||||||
import simplejson
|
import simplejson
|
||||||
|
from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
|
||||||
|
|
||||||
def list(nodeurl, dir_uri, vdrive_pathname, stdout, stderr):
|
def list(nodeurl, aliases, where, config, stdout, stderr):
|
||||||
if nodeurl[-1] != "/":
|
if not nodeurl.endswith("/"):
|
||||||
nodeurl += "/"
|
nodeurl += "/"
|
||||||
url = nodeurl + "uri/%s/" % urllib.quote(dir_uri)
|
if where.endswith("/"):
|
||||||
if vdrive_pathname:
|
where = where[:-1]
|
||||||
url += urllib.quote(vdrive_pathname)
|
rootcap, path = get_alias(aliases, where, DEFAULT_ALIAS)
|
||||||
|
url = nodeurl + "uri/%s" % urllib.quote(rootcap)
|
||||||
|
if path:
|
||||||
|
# move where.endswith check here?
|
||||||
|
url += "/" + escape_path(path)
|
||||||
|
assert not url.endswith("/")
|
||||||
url += "?t=json"
|
url += "?t=json"
|
||||||
data = urllib.urlopen(url).read()
|
data = urllib.urlopen(url).read()
|
||||||
|
|
||||||
|
if config['json']:
|
||||||
|
print >>stdout, data
|
||||||
|
return
|
||||||
|
|
||||||
parsed = simplejson.loads(data)
|
parsed = simplejson.loads(data)
|
||||||
nodetype, d = parsed
|
nodetype, d = parsed
|
||||||
|
children = {}
|
||||||
if nodetype == "dirnode":
|
if nodetype == "dirnode":
|
||||||
childnames = sorted(d['children'].keys())
|
children = d['children']
|
||||||
for name in childnames:
|
|
||||||
child = d['children'][name]
|
|
||||||
childtype = child[0]
|
|
||||||
if childtype == "dirnode":
|
|
||||||
print >>stdout, "%10s %s/" % ("", name)
|
|
||||||
else:
|
|
||||||
assert childtype == "filenode"
|
|
||||||
size = child[1]['size']
|
|
||||||
print >>stdout, "%10s %s" % (size, name)
|
|
||||||
elif nodetype == "filenode":
|
elif nodetype == "filenode":
|
||||||
print >>stdout, "%10s %s" % (d['size'], vdrive_pathname)
|
childname = path.split("/")[-1]
|
||||||
|
children = {childname: d}
|
||||||
|
childnames = sorted(children.keys())
|
||||||
|
now = time.time()
|
||||||
|
for name in childnames:
|
||||||
|
child = children[name]
|
||||||
|
childtype = child[0]
|
||||||
|
ctime = child[1]["metadata"].get("ctime")
|
||||||
|
mtime = child[1]["metadata"].get("mtime")
|
||||||
|
if ctime:
|
||||||
|
# match for formatting that GNU 'ls' does
|
||||||
|
if (now - ctime) > 6*30*24*60*60:
|
||||||
|
# old files
|
||||||
|
fmt = "%b %d %Y"
|
||||||
|
else:
|
||||||
|
fmt = "%b %d %H:%M"
|
||||||
|
ctime_s = time.strftime(fmt, time.localtime(ctime))
|
||||||
|
else:
|
||||||
|
ctime_s = "-"
|
||||||
|
if childtype == "dirnode":
|
||||||
|
t = "d---------"
|
||||||
|
size = "-"
|
||||||
|
classify = "/"
|
||||||
|
elif childtype == "filenode":
|
||||||
|
t = "----------"
|
||||||
|
size = child[1]['size']
|
||||||
|
classify = ""
|
||||||
|
if "rw_uri" in child[1]:
|
||||||
|
classify = "*" # mutable
|
||||||
|
|
||||||
|
uri = child[1].get("rw_uri", child[1].get("ro_uri", "-"))
|
||||||
|
|
||||||
|
line = []
|
||||||
|
if config["long"]:
|
||||||
|
line.append("%s %10s %12s" % (t, size, ctime_s))
|
||||||
|
if config["uri"]:
|
||||||
|
line.append(uri)
|
||||||
|
line.append(name)
|
||||||
|
if config["classify"]:
|
||||||
|
line[-1] += classify
|
||||||
|
|
||||||
|
print >>stdout, " ".join(line)
|
||||||
|
34
src/allmydata/scripts/tahoe_mkdir.py
Normal file
34
src/allmydata/scripts/tahoe_mkdir.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
import urllib
|
||||||
|
from allmydata.scripts.common_http import do_http, check_http_error
|
||||||
|
from allmydata.scripts.common import get_alias, DEFAULT_ALIAS
|
||||||
|
|
||||||
|
def mkdir(nodeurl, aliases, where, stdout, stderr):
|
||||||
|
if not nodeurl.endswith("/"):
|
||||||
|
nodeurl += "/"
|
||||||
|
if where:
|
||||||
|
rootcap, path = get_alias(aliases, where, DEFAULT_ALIAS)
|
||||||
|
|
||||||
|
if not where or not path:
|
||||||
|
# create a new unlinked directory
|
||||||
|
url = nodeurl + "uri?t=mkdir"
|
||||||
|
resp = do_http("POST", url)
|
||||||
|
rc = check_http_error(resp, stderr)
|
||||||
|
if rc:
|
||||||
|
return rc
|
||||||
|
new_uri = resp.read().strip()
|
||||||
|
# emit its write-cap
|
||||||
|
print >>stdout, new_uri
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# create a new directory at the given location
|
||||||
|
if path.endswith("/"):
|
||||||
|
path = path[:-1]
|
||||||
|
# path (in argv) must be "/".join([s.encode("utf-8") for s in segments])
|
||||||
|
url = nodeurl + "uri/%s/%s?t=mkdir" % (urllib.quote(rootcap),
|
||||||
|
urllib.quote(path))
|
||||||
|
resp = do_http("POST", url)
|
||||||
|
check_http_error(resp, stderr)
|
||||||
|
new_uri = resp.read().strip()
|
||||||
|
print >>stdout, new_uri
|
||||||
|
return 0
|
@ -2,31 +2,42 @@
|
|||||||
import re
|
import re
|
||||||
import urllib
|
import urllib
|
||||||
import simplejson
|
import simplejson
|
||||||
|
from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
|
||||||
from allmydata.scripts.common_http import do_http
|
from allmydata.scripts.common_http import do_http
|
||||||
|
|
||||||
def mv(nodeurl, dir_uri, frompath, topath, stdout, stderr):
|
def mv(nodeurl, aliases, from_file, to_file, stdout, stderr):
|
||||||
frompath = urllib.quote(frompath)
|
|
||||||
topath = urllib.quote(topath)
|
|
||||||
if nodeurl[-1] != "/":
|
if nodeurl[-1] != "/":
|
||||||
nodeurl += "/"
|
nodeurl += "/"
|
||||||
url = nodeurl + "uri/%s/" % urllib.quote(dir_uri)
|
rootcap, path = get_alias(aliases, from_file, DEFAULT_ALIAS)
|
||||||
data = urllib.urlopen(url + frompath + "?t=json").read()
|
from_url = nodeurl + "uri/%s" % urllib.quote(rootcap)
|
||||||
|
if path:
|
||||||
|
from_url += "/" + escape_path(path)
|
||||||
|
# figure out the source cap
|
||||||
|
data = urllib.urlopen(from_url + "?t=json").read()
|
||||||
nodetype, attrs = simplejson.loads(data)
|
nodetype, attrs = simplejson.loads(data)
|
||||||
uri = attrs.get("rw_uri") or attrs["ro_uri"]
|
cap = attrs.get("rw_uri") or attrs["ro_uri"]
|
||||||
# simplejson always returns unicode, but we know that it's really just a
|
# simplejson always returns unicode, but we know that it's really just an
|
||||||
# bytestring.
|
# ASCII file-cap.
|
||||||
uri = str(uri)
|
cap = str(cap)
|
||||||
|
|
||||||
put_url = url + topath + "?t=uri"
|
# now get the target
|
||||||
resp = do_http("PUT", put_url, uri)
|
rootcap, path = get_alias(aliases, to_file, DEFAULT_ALIAS)
|
||||||
|
to_url = nodeurl + "uri/%s" % urllib.quote(rootcap)
|
||||||
|
if path:
|
||||||
|
to_url += "/" + escape_path(path)
|
||||||
|
if path.endswith("/"):
|
||||||
|
# "mv foo.txt bar/" == "mv foo.txt bar/foo.txt"
|
||||||
|
pass # TODO
|
||||||
|
to_url += "?t=uri"
|
||||||
|
|
||||||
|
resp = do_http("PUT", to_url, cap)
|
||||||
status = resp.status
|
status = resp.status
|
||||||
if not re.search(r'^2\d\d$', str(status)):
|
if not re.search(r'^2\d\d$', str(status)):
|
||||||
print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
|
print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
|
||||||
print >>stderr, resp.read()
|
print >>stderr, resp.read()
|
||||||
|
|
||||||
# now remove the original
|
# now remove the original
|
||||||
resp = do_http("DELETE", url + frompath)
|
resp = do_http("DELETE", from_url)
|
||||||
if not re.search(r'^2\d\d$', str(status)):
|
if not re.search(r'^2\d\d$', str(status)):
|
||||||
print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
|
print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
|
||||||
print >>stderr, resp.read()
|
print >>stderr, resp.read()
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
|
from cStringIO import StringIO
|
||||||
import urllib
|
import urllib
|
||||||
from allmydata.scripts.common_http import do_http
|
from allmydata.scripts.common_http import do_http
|
||||||
|
from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
|
||||||
|
|
||||||
def put(nodeurl, dir_uri, local_fname, vdrive_fname, verbosity,
|
def put(nodeurl, aliases, from_file, to_file, verbosity,
|
||||||
stdout, stderr):
|
stdin, stdout, stderr):
|
||||||
"""
|
"""
|
||||||
@param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose
|
@param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose
|
||||||
|
|
||||||
@ -11,15 +13,28 @@ def put(nodeurl, dir_uri, local_fname, vdrive_fname, verbosity,
|
|||||||
"""
|
"""
|
||||||
if nodeurl[-1] != "/":
|
if nodeurl[-1] != "/":
|
||||||
nodeurl += "/"
|
nodeurl += "/"
|
||||||
url = nodeurl + "uri/%s/" % urllib.quote(dir_uri)
|
if to_file:
|
||||||
if vdrive_fname:
|
rootcap, path = get_alias(aliases, to_file, DEFAULT_ALIAS)
|
||||||
url += urllib.quote(vdrive_fname)
|
url = nodeurl + "uri/%s/" % urllib.quote(rootcap)
|
||||||
|
if path:
|
||||||
|
url += escape_path(path)
|
||||||
|
else:
|
||||||
|
url = nodeurl + "uri"
|
||||||
|
if from_file:
|
||||||
|
infileobj = open(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)
|
||||||
|
|
||||||
infileobj = open(local_fname, "rb")
|
|
||||||
resp = do_http("PUT", url, infileobj)
|
resp = do_http("PUT", url, infileobj)
|
||||||
|
|
||||||
if resp.status in (200, 201,):
|
if resp.status in (200, 201,):
|
||||||
print >>stdout, "%s %s" % (resp.status, resp.reason)
|
print >>stderr, "%s %s" % (resp.status, resp.reason)
|
||||||
|
print >>stdout, resp.read()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
|
print >>stderr, "error, got %s %s" % (resp.status, resp.reason)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
from allmydata.scripts.common_http import do_http
|
from allmydata.scripts.common_http import do_http
|
||||||
|
from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
|
||||||
|
|
||||||
def rm(nodeurl, dir_uri, vdrive_pathname, verbosity, stdout, stderr):
|
def rm(nodeurl, aliases, where, verbosity, stdout, stderr):
|
||||||
"""
|
"""
|
||||||
@param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose
|
@param verbosity: 0, 1, or 2, meaning quiet, verbose, or very verbose
|
||||||
|
|
||||||
@ -10,9 +11,10 @@ def rm(nodeurl, dir_uri, vdrive_pathname, verbosity, stdout, stderr):
|
|||||||
"""
|
"""
|
||||||
if nodeurl[-1] != "/":
|
if nodeurl[-1] != "/":
|
||||||
nodeurl += "/"
|
nodeurl += "/"
|
||||||
url = nodeurl + "uri/%s/" % urllib.quote(dir_uri)
|
rootcap, path = get_alias(aliases, where, DEFAULT_ALIAS)
|
||||||
if vdrive_pathname:
|
assert path
|
||||||
url += urllib.quote(vdrive_pathname)
|
url = nodeurl + "uri/%s" % urllib.quote(rootcap)
|
||||||
|
url += "/" + escape_path(path)
|
||||||
|
|
||||||
resp = do_http("DELETE", url)
|
resp = do_http("DELETE", url)
|
||||||
|
|
||||||
|
@ -9,10 +9,13 @@ from allmydata import uri
|
|||||||
# at least import the CLI scripts, even if we don't have any real tests for
|
# at least import the CLI scripts, even if we don't have any real tests for
|
||||||
# them yet.
|
# them yet.
|
||||||
from allmydata.scripts import tahoe_ls, tahoe_get, tahoe_put, tahoe_rm
|
from allmydata.scripts import tahoe_ls, tahoe_get, tahoe_put, tahoe_rm
|
||||||
|
from allmydata.scripts.common import DEFAULT_ALIAS
|
||||||
_hush_pyflakes = [tahoe_ls, tahoe_get, tahoe_put, tahoe_rm]
|
_hush_pyflakes = [tahoe_ls, tahoe_get, tahoe_put, tahoe_rm]
|
||||||
|
|
||||||
from allmydata.scripts import cli, debug
|
from allmydata.scripts import cli, debug
|
||||||
|
|
||||||
|
# this test case only looks at argument-processing and simple stuff.
|
||||||
|
# test_system contains all the CLI tests that actually use a real node.
|
||||||
|
|
||||||
class CLI(unittest.TestCase):
|
class CLI(unittest.TestCase):
|
||||||
def test_options(self):
|
def test_options(self):
|
||||||
@ -27,27 +30,22 @@ class CLI(unittest.TestCase):
|
|||||||
o = cli.ListOptions()
|
o = cli.ListOptions()
|
||||||
o.parseOptions(["--node-directory", "cli/test_options"])
|
o.parseOptions(["--node-directory", "cli/test_options"])
|
||||||
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
||||||
self.failUnlessEqual(o['dir-cap'], private_uri)
|
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
|
||||||
self.failUnlessEqual(o['vdrive_pathname'], "")
|
self.failUnlessEqual(o.where, "")
|
||||||
|
|
||||||
o = cli.ListOptions()
|
o = cli.ListOptions()
|
||||||
o.parseOptions(["--node-directory", "cli/test_options",
|
o.parseOptions(["--node-directory", "cli/test_options",
|
||||||
"--node-url", "http://example.org:8111/"])
|
"--node-url", "http://example.org:8111/"])
|
||||||
self.failUnlessEqual(o['node-url'], "http://example.org:8111/")
|
self.failUnlessEqual(o['node-url'], "http://example.org:8111/")
|
||||||
self.failUnlessEqual(o['dir-cap'], private_uri)
|
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
|
||||||
self.failUnlessEqual(o['vdrive_pathname'], "")
|
self.failUnlessEqual(o.where, "")
|
||||||
|
|
||||||
o = cli.ListOptions()
|
o = cli.ListOptions()
|
||||||
o.parseOptions(["--node-directory", "cli/test_options",
|
o.parseOptions(["--node-directory", "cli/test_options",
|
||||||
"--dir-cap", "root"])
|
"--dir-cap", "root"])
|
||||||
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
||||||
self.failUnlessEqual(o['dir-cap'], private_uri)
|
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], "root")
|
||||||
self.failUnlessEqual(o['vdrive_pathname'], "")
|
self.failUnlessEqual(o.where, "")
|
||||||
|
|
||||||
o = cli.ListOptions()
|
|
||||||
o.parseOptions(["--node-directory", "cli/test_options"])
|
|
||||||
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
|
||||||
self.failUnlessEqual(o['vdrive_pathname'], "")
|
|
||||||
|
|
||||||
o = cli.ListOptions()
|
o = cli.ListOptions()
|
||||||
other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
|
other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
|
||||||
@ -56,15 +54,15 @@ class CLI(unittest.TestCase):
|
|||||||
o.parseOptions(["--node-directory", "cli/test_options",
|
o.parseOptions(["--node-directory", "cli/test_options",
|
||||||
"--dir-cap", other_uri])
|
"--dir-cap", other_uri])
|
||||||
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
||||||
self.failUnlessEqual(o['dir-cap'], other_uri)
|
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
|
||||||
self.failUnlessEqual(o['vdrive_pathname'], "")
|
self.failUnlessEqual(o.where, "")
|
||||||
|
|
||||||
o = cli.ListOptions()
|
o = cli.ListOptions()
|
||||||
o.parseOptions(["--node-directory", "cli/test_options",
|
o.parseOptions(["--node-directory", "cli/test_options",
|
||||||
"--dir-cap", other_uri, "subdir"])
|
"--dir-cap", other_uri, "subdir"])
|
||||||
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
|
||||||
self.failUnlessEqual(o['dir-cap'], other_uri)
|
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
|
||||||
self.failUnlessEqual(o['vdrive_pathname'], "subdir")
|
self.failUnlessEqual(o.where, "subdir")
|
||||||
|
|
||||||
def _dump_cap(self, *args):
|
def _dump_cap(self, *args):
|
||||||
out,err = StringIO(), StringIO()
|
out,err = StringIO(), StringIO()
|
||||||
|
@ -12,7 +12,7 @@ from allmydata import client, uri, download, upload, storage, offloaded
|
|||||||
from allmydata.introducer import IntroducerNode
|
from allmydata.introducer import IntroducerNode
|
||||||
from allmydata.util import deferredutil, fileutil, idlib, mathutil, testutil
|
from allmydata.util import deferredutil, fileutil, idlib, mathutil, testutil
|
||||||
from allmydata.util import log
|
from allmydata.util import log
|
||||||
from allmydata.scripts import runner
|
from allmydata.scripts import runner, cli
|
||||||
from allmydata.interfaces import IDirectoryNode, IFileNode, IFileURI
|
from allmydata.interfaces import IDirectoryNode, IFileNode, IFileURI
|
||||||
from allmydata.mutable.common import NotMutableError
|
from allmydata.mutable.common import NotMutableError
|
||||||
from allmydata.mutable import layout as mutable_layout
|
from allmydata.mutable import layout as mutable_layout
|
||||||
@ -69,9 +69,8 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
|
|||||||
s.setServiceParent(self.sparent)
|
s.setServiceParent(self.sparent)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def set_up_nodes(self, NUMCLIENTS=5, createprivdir=False):
|
def set_up_nodes(self, NUMCLIENTS=5):
|
||||||
self.numclients = NUMCLIENTS
|
self.numclients = NUMCLIENTS
|
||||||
self.createprivdir = createprivdir
|
|
||||||
iv_dir = self.getdir("introducer")
|
iv_dir = self.getdir("introducer")
|
||||||
if not os.path.isdir(iv_dir):
|
if not os.path.isdir(iv_dir):
|
||||||
fileutil.make_dirs(iv_dir)
|
fileutil.make_dirs(iv_dir)
|
||||||
@ -143,9 +142,6 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
|
|||||||
open(os.path.join(basedir, "webport"), "w").write("tcp:0:interface=127.0.0.1")
|
open(os.path.join(basedir, "webport"), "w").write("tcp:0:interface=127.0.0.1")
|
||||||
kgf = "%s\n" % (self.key_generator_furl,)
|
kgf = "%s\n" % (self.key_generator_furl,)
|
||||||
open(os.path.join(basedir, "key_generator.furl"), "w").write(kgf)
|
open(os.path.join(basedir, "key_generator.furl"), "w").write(kgf)
|
||||||
if self.createprivdir:
|
|
||||||
fileutil.make_dirs(os.path.join(basedir, "private"))
|
|
||||||
open(os.path.join(basedir, "private", "root_dir.cap"), "w")
|
|
||||||
open(os.path.join(basedir, "introducer.furl"), "w").write(self.introducer_furl)
|
open(os.path.join(basedir, "introducer.furl"), "w").write(self.introducer_furl)
|
||||||
open(os.path.join(basedir, "stats_gatherer.furl"), "w").write(self.stats_gatherer_furl)
|
open(os.path.join(basedir, "stats_gatherer.furl"), "w").write(self.stats_gatherer_furl)
|
||||||
|
|
||||||
@ -875,7 +871,7 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
|
|||||||
def test_vdrive(self):
|
def test_vdrive(self):
|
||||||
self.basedir = "system/SystemTest/test_vdrive"
|
self.basedir = "system/SystemTest/test_vdrive"
|
||||||
self.data = LARGE_DATA
|
self.data = LARGE_DATA
|
||||||
d = self.set_up_nodes(createprivdir=True)
|
d = self.set_up_nodes()
|
||||||
d.addCallback(self._test_introweb)
|
d.addCallback(self._test_introweb)
|
||||||
d.addCallback(self.log, "starting publish")
|
d.addCallback(self.log, "starting publish")
|
||||||
d.addCallback(self._do_publish1)
|
d.addCallback(self._do_publish1)
|
||||||
@ -1528,7 +1524,7 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
|
|||||||
|
|
||||||
nodeargs = [
|
nodeargs = [
|
||||||
"--node-directory", client0_basedir,
|
"--node-directory", client0_basedir,
|
||||||
"--dir-cap", private_uri,
|
#"--dir-cap", private_uri,
|
||||||
]
|
]
|
||||||
public_nodeargs = [
|
public_nodeargs = [
|
||||||
"--node-url", self.webish_url,
|
"--node-url", self.webish_url,
|
||||||
@ -1538,44 +1534,147 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
|
|||||||
|
|
||||||
d = defer.succeed(None)
|
d = defer.succeed(None)
|
||||||
|
|
||||||
def _ls_root(res):
|
# for compatibility with earlier versions, private/root_dir.cap is
|
||||||
argv = ["ls"] + nodeargs
|
# supposed to be treated as an alias named "tahoe:". Start by making
|
||||||
return self._run_cli(argv)
|
# sure that works, before we add other aliases.
|
||||||
d.addCallback(_ls_root)
|
|
||||||
|
root_file = os.path.join(client0_basedir, "private", "root_dir.cap")
|
||||||
|
f = open(root_file, "w")
|
||||||
|
f.write(private_uri)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def run(ignored, verb, *args):
|
||||||
|
newargs = [verb] + nodeargs + list(args)
|
||||||
|
return self._run_cli(newargs)
|
||||||
|
|
||||||
|
def _check_ls((out,err), expected_children, unexpected_children=[]):
|
||||||
|
self.failUnlessEqual(err, "")
|
||||||
|
for s in expected_children:
|
||||||
|
self.failUnless(s in out, s)
|
||||||
|
for s in unexpected_children:
|
||||||
|
self.failIf(s in out, s)
|
||||||
|
|
||||||
def _check_ls_root((out,err)):
|
def _check_ls_root((out,err)):
|
||||||
self.failUnless("personal" in out)
|
self.failUnless("personal" in out)
|
||||||
self.failUnless("s2-ro" in out)
|
self.failUnless("s2-ro" in out)
|
||||||
self.failUnless("s2-rw" in out)
|
self.failUnless("s2-rw" in out)
|
||||||
self.failUnlessEqual(err, "")
|
self.failUnlessEqual(err, "")
|
||||||
d.addCallback(_check_ls_root)
|
|
||||||
|
|
||||||
def _ls_subdir(res):
|
# this should reference private_uri
|
||||||
argv = ["ls"] + nodeargs + ["personal"]
|
d.addCallback(run, "ls")
|
||||||
return self._run_cli(argv)
|
d.addCallback(_check_ls, ["personal", "s2-ro", "s2-rw"])
|
||||||
d.addCallback(_ls_subdir)
|
|
||||||
def _check_ls_subdir((out,err)):
|
|
||||||
self.failUnless("sekrit data" in out)
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
d.addCallback(_check_ls_subdir)
|
|
||||||
|
|
||||||
def _ls_public_subdir(res):
|
# now that that's out of the way, remove root_dir.cap and work with
|
||||||
argv = ["ls"] + public_nodeargs + ["subdir1"]
|
# new files
|
||||||
return self._run_cli(argv)
|
d.addCallback(lambda res: os.unlink(root_file))
|
||||||
d.addCallback(_ls_public_subdir)
|
|
||||||
def _check_ls_public_subdir((out,err)):
|
|
||||||
self.failUnless("subdir2" in out)
|
|
||||||
self.failUnless("mydata567" in out)
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
d.addCallback(_check_ls_public_subdir)
|
|
||||||
|
|
||||||
def _ls_file(res):
|
d.addCallback(run, "mkdir")
|
||||||
argv = ["ls"] + public_nodeargs + ["subdir1/mydata567"]
|
def _got_dir( (out,err) ):
|
||||||
return self._run_cli(argv)
|
self.failUnless(uri.from_string_dirnode(out.strip()))
|
||||||
d.addCallback(_ls_file)
|
return out.strip()
|
||||||
def _check_ls_file((out,err)):
|
d.addCallback(_got_dir)
|
||||||
self.failUnlessEqual(out.strip(), "112 subdir1/mydata567")
|
d.addCallback(lambda newcap: run(None, "add-alias", "tahoe", newcap))
|
||||||
|
def _check_empty_dir((out,err)):
|
||||||
|
self.failUnlessEqual(out, "")
|
||||||
self.failUnlessEqual(err, "")
|
self.failUnlessEqual(err, "")
|
||||||
d.addCallback(_check_ls_file)
|
d.addCallback(run, "ls")
|
||||||
|
d.addCallback(_check_empty_dir)
|
||||||
|
|
||||||
|
files = []
|
||||||
|
datas = []
|
||||||
|
for i in range(10):
|
||||||
|
fn = os.path.join(self.basedir, "file%d" % i)
|
||||||
|
files.append(fn)
|
||||||
|
data = "data to be uploaded: file%d\n" % i
|
||||||
|
datas.append(data)
|
||||||
|
open(fn,"w").write(data)
|
||||||
|
|
||||||
|
# test all both forms of put: from a file, and from stdin
|
||||||
|
# tahoe put bar FOO
|
||||||
|
d.addCallback(run, "put", files[0], "tahoe-file0")
|
||||||
|
def _put_out((out,err)):
|
||||||
|
self.failUnless("URI:LIT:" in out, out)
|
||||||
|
self.failUnless("201 Created" in err, err)
|
||||||
|
uri0 = out.strip()
|
||||||
|
return run(None, "get", uri0)
|
||||||
|
d.addCallback(_put_out)
|
||||||
|
d.addCallback(lambda (out,err): self.failUnlessEqual(out, datas[0]))
|
||||||
|
|
||||||
|
d.addCallback(run, "put", files[1], "subdir/tahoe-file1")
|
||||||
|
# tahoe put bar tahoe:FOO
|
||||||
|
d.addCallback(run, "put", files[2], "tahoe:file2")
|
||||||
|
|
||||||
|
def _put_from_stdin(res, data, *args):
|
||||||
|
args = nodeargs + list(args)
|
||||||
|
o = cli.PutOptions()
|
||||||
|
o.parseOptions(args)
|
||||||
|
stdin = StringIO(data)
|
||||||
|
stdout, stderr = StringIO(), StringIO()
|
||||||
|
d = threads.deferToThread(cli.put, o,
|
||||||
|
stdout=stdout, stderr=stderr, stdin=stdin)
|
||||||
|
def _done(res):
|
||||||
|
return stdout.getvalue(), stderr.getvalue()
|
||||||
|
d.addCallback(_done)
|
||||||
|
return d
|
||||||
|
|
||||||
|
# tahoe put FOO
|
||||||
|
STDIN_DATA = "This is the file to upload from stdin."
|
||||||
|
d.addCallback(_put_from_stdin,
|
||||||
|
STDIN_DATA,
|
||||||
|
"tahoe-file-stdin")
|
||||||
|
# tahoe put tahoe:FOO
|
||||||
|
d.addCallback(_put_from_stdin,
|
||||||
|
"Other file from stdin.",
|
||||||
|
"tahoe:from-stdin")
|
||||||
|
|
||||||
|
d.addCallback(run, "ls")
|
||||||
|
d.addCallback(_check_ls, ["tahoe-file0", "file2", "subdir",
|
||||||
|
"tahoe-file-stdin", "from-stdin"])
|
||||||
|
d.addCallback(run, "ls", "subdir")
|
||||||
|
d.addCallback(_check_ls, ["tahoe-file1"])
|
||||||
|
|
||||||
|
# tahoe mkdir FOO
|
||||||
|
d.addCallback(run, "mkdir", "subdir2")
|
||||||
|
d.addCallback(run, "ls")
|
||||||
|
# TODO: extract the URI, set an alias with it
|
||||||
|
d.addCallback(_check_ls, ["subdir2"])
|
||||||
|
|
||||||
|
# tahoe get: (to stdin and to a file)
|
||||||
|
d.addCallback(run, "get", "tahoe-file0")
|
||||||
|
d.addCallback(lambda (out,err):
|
||||||
|
self.failUnlessEqual(out, "data to be uploaded: file0\n"))
|
||||||
|
d.addCallback(run, "get", "tahoe:subdir/tahoe-file1")
|
||||||
|
d.addCallback(lambda (out,err):
|
||||||
|
self.failUnlessEqual(out, "data to be uploaded: file1\n"))
|
||||||
|
outfile0 = os.path.join(self.basedir, "outfile0")
|
||||||
|
d.addCallback(run, "get", "file2", outfile0)
|
||||||
|
def _check_outfile0((out,err)):
|
||||||
|
data = open(outfile0,"rb").read()
|
||||||
|
self.failUnlessEqual(data, "data to be uploaded: file2\n")
|
||||||
|
d.addCallback(_check_outfile0)
|
||||||
|
outfile1 = os.path.join(self.basedir, "outfile0")
|
||||||
|
d.addCallback(run, "get", "tahoe:subdir/tahoe-file1", outfile1)
|
||||||
|
def _check_outfile1((out,err)):
|
||||||
|
data = open(outfile1,"rb").read()
|
||||||
|
self.failUnlessEqual(data, "data to be uploaded: file1\n")
|
||||||
|
d.addCallback(_check_outfile1)
|
||||||
|
|
||||||
|
d.addCallback(run, "rm", "tahoe-file0")
|
||||||
|
d.addCallback(run, "rm", "tahoe:file2")
|
||||||
|
d.addCallback(run, "ls")
|
||||||
|
d.addCallback(_check_ls, [], ["tahoe-file0", "file2"])
|
||||||
|
|
||||||
|
d.addCallback(run, "ls", "-l")
|
||||||
|
def _check_ls_l((out,err)):
|
||||||
|
lines = out.split("\n")
|
||||||
|
for l in lines:
|
||||||
|
if "tahoe-file-stdin" in l:
|
||||||
|
self.failUnless(" %d " % len(STDIN_DATA) in l)
|
||||||
|
d.addCallback(_check_ls_l)
|
||||||
|
|
||||||
|
d.addCallback(run, "mv", "tahoe-file-stdin", "tahoe-moved")
|
||||||
|
d.addCallback(run, "ls")
|
||||||
|
d.addCallback(_check_ls, ["tahoe-moved"], ["tahoe-file-stdin"])
|
||||||
|
|
||||||
# tahoe_ls doesn't currently handle the error correctly: it tries to
|
# tahoe_ls doesn't currently handle the error correctly: it tries to
|
||||||
# JSON-parse a traceback.
|
# JSON-parse a traceback.
|
||||||
@ -1589,82 +1688,10 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
|
|||||||
## self.failUnlessEqual(err, "")
|
## self.failUnlessEqual(err, "")
|
||||||
## d.addCallback(_check_ls_missing)
|
## d.addCallback(_check_ls_missing)
|
||||||
|
|
||||||
def _put(res):
|
|
||||||
tdir = self.getdir("cli_put")
|
|
||||||
fileutil.make_dirs(tdir)
|
|
||||||
fn = os.path.join(tdir, "upload_me")
|
|
||||||
f = open(fn, "wb")
|
|
||||||
f.write(TESTDATA)
|
|
||||||
f.close()
|
|
||||||
argv = ["put"] + nodeargs + [fn, "test_put/upload.txt"]
|
|
||||||
return self._run_cli(argv)
|
|
||||||
d.addCallback(_put)
|
|
||||||
def _check_put((out,err)):
|
|
||||||
self.failUnless("201 Created" in out, out)
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
d = self._private_node.get_child_at_path(u"test_put/upload.txt")
|
|
||||||
d.addCallback(lambda filenode: filenode.download_to_data())
|
|
||||||
def _check_put2(res):
|
|
||||||
self.failUnlessEqual(res, TESTDATA)
|
|
||||||
d.addCallback(_check_put2)
|
|
||||||
return d
|
|
||||||
d.addCallback(_check_put)
|
|
||||||
|
|
||||||
def _get_to_stdout(res):
|
|
||||||
argv = ["get"] + nodeargs + ["test_put/upload.txt"]
|
|
||||||
return self._run_cli(argv)
|
|
||||||
d.addCallback(_get_to_stdout)
|
|
||||||
def _check_get_to_stdout((out,err)):
|
|
||||||
self.failUnlessEqual(out, TESTDATA)
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
d.addCallback(_check_get_to_stdout)
|
|
||||||
|
|
||||||
get_to_file_target = self.basedir + "/get.downfile"
|
|
||||||
def _get_to_file(res):
|
|
||||||
argv = ["get"] + nodeargs + ["test_put/upload.txt",
|
|
||||||
get_to_file_target]
|
|
||||||
return self._run_cli(argv)
|
|
||||||
d.addCallback(_get_to_file)
|
|
||||||
def _check_get_to_file((out,err)):
|
|
||||||
data = open(get_to_file_target, "rb").read()
|
|
||||||
self.failUnlessEqual(data, TESTDATA)
|
|
||||||
self.failUnlessEqual(out, "")
|
|
||||||
self.failUnlessEqual(err, "test_put/upload.txt retrieved and written to system/SystemTest/test_vdrive/get.downfile\n")
|
|
||||||
d.addCallback(_check_get_to_file)
|
|
||||||
|
|
||||||
|
|
||||||
def _mv(res):
|
|
||||||
argv = ["mv"] + nodeargs + ["test_put/upload.txt",
|
|
||||||
"test_put/moved.txt"]
|
|
||||||
return self._run_cli(argv)
|
|
||||||
d.addCallback(_mv)
|
|
||||||
def _check_mv((out,err)):
|
|
||||||
self.failUnless("OK" in out)
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
d = self.shouldFail2(KeyError, "test_cli._check_rm", "'upload.txt'", self._private_node.get_child_at_path, u"test_put/upload.txt")
|
|
||||||
|
|
||||||
d.addCallback(lambda res:
|
|
||||||
self._private_node.get_child_at_path(u"test_put/moved.txt"))
|
|
||||||
d.addCallback(lambda filenode: filenode.download_to_data())
|
|
||||||
def _check_mv2(res):
|
|
||||||
self.failUnlessEqual(res, TESTDATA)
|
|
||||||
d.addCallback(_check_mv2)
|
|
||||||
return d
|
|
||||||
d.addCallback(_check_mv)
|
|
||||||
|
|
||||||
def _rm(res):
|
|
||||||
argv = ["rm"] + nodeargs + ["test_put/moved.txt"]
|
|
||||||
return self._run_cli(argv)
|
|
||||||
d.addCallback(_rm)
|
|
||||||
def _check_rm((out,err)):
|
|
||||||
self.failUnless("200 OK" in out)
|
|
||||||
self.failUnlessEqual(err, "")
|
|
||||||
d = self.shouldFail2(KeyError, "test_cli._check_rm", "'moved.txt'", self._private_node.get_child_at_path, u"test_put/moved.txt")
|
|
||||||
return d
|
|
||||||
d.addCallback(_check_rm)
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _run_cli(self, argv):
|
def _run_cli(self, argv):
|
||||||
|
#print "CLI:", argv
|
||||||
stdout, stderr = StringIO(), StringIO()
|
stdout, stderr = StringIO(), StringIO()
|
||||||
d = threads.deferToThread(runner.runner, argv, run_by_human=False,
|
d = threads.deferToThread(runner.runner, argv, run_by_human=False,
|
||||||
stdout=stdout, stderr=stderr)
|
stdout=stdout, stderr=stderr)
|
||||||
|
Loading…
Reference in New Issue
Block a user