bin/tahoe: clean up global-vs-subcommand arguments like --node-directory

The new rules for "bin/tahoe ARG1.. SUBCOMMAND ARG2.." arg:

* --node-directory is only accepted in ARG1, not ARG2
* create-*/start/stop/restart accept --basedir in ARG2, or an explicit
  basedir argument
* only one of --node-directory/--basedir/explicit-basedir is accepted
* --quiet/--version is only accepted in ARG1, not ARG2

Closes #166
This commit is contained in:
Brian Warner 2012-06-18 10:43:49 -07:00
parent 643eb4f372
commit 5874a7d3a7
13 changed files with 250 additions and 212 deletions

View File

@ -1,12 +1,13 @@
from twisted.python import usage
from allmydata.scripts.common import BaseOptions
class GenerateKeypairOptions(usage.Options):
class GenerateKeypairOptions(BaseOptions):
def getSynopsis(self):
return "Usage: tahoe admin generate-keypair"
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Generate a public/private keypair, dumped to stdout as two lines of ASCII..
@ -20,7 +21,7 @@ def print_keypair(options):
print >>out, "private:", privkey_vs
print >>out, "public:", pubkey_vs
class DerivePubkeyOptions(usage.Options):
class DerivePubkeyOptions(BaseOptions):
def parseArgs(self, privkey):
self.privkey = privkey
@ -28,7 +29,7 @@ class DerivePubkeyOptions(usage.Options):
return "Usage: tahoe admin derive-pubkey PRIVKEY"
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Given a private (signing) key that was previously generated with
generate-keypair, derive the public key and print it to stdout.
@ -45,7 +46,7 @@ def derive_pubkey(options):
print >>out, "public:", pubkey_vs
return 0
class AdminCommand(usage.Options):
class AdminCommand(BaseOptions):
subCommands = [
("generate-keypair", None, GenerateKeypairOptions,
"Generate a public/private keypair, write to stdout."),
@ -58,7 +59,7 @@ class AdminCommand(usage.Options):
def getSynopsis(self):
return "Usage: tahoe admin SUBCOMMAND"
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Please run e.g. 'tahoe admin generate-keypair --help' for more details on
each subcommand.

View File

@ -1,6 +1,7 @@
import os.path, re, fnmatch
from twisted.python import usage
from allmydata.scripts.common import BaseOptions, get_aliases, get_default_nodedir, DEFAULT_ALIAS
from allmydata.scripts.common import get_aliases, get_default_nodedir, \
DEFAULT_ALIAS, BaseOptions
from allmydata.util.encodingutil import argv_to_unicode, argv_to_abspath, quote_output
NODEURL_RE=re.compile("http(s?)://([^:]*)(:([1-9][0-9]*))?")
@ -9,23 +10,18 @@ _default_nodedir = get_default_nodedir()
class VDriveOptions(BaseOptions):
optParameters = [
["node-directory", "d", None,
"Specify which Tahoe node directory should be used. The directory "
"should either contain a full Tahoe node, or a file named node.url "
"that points to some other Tahoe node. It should also contain a file "
"named '" + os.path.join('private', 'aliases') + "' which contains the "
"mapping from alias name to root dirnode URI." + (
_default_nodedir and (" [default: " + quote_output(_default_nodedir) + "]") or "")],
["node-url", "u", None,
"Specify the URL of the Tahoe gateway node, such as 'http://127.0.0.1:3456'. "
"Specify the URL of the Tahoe gateway node, such as "
"'http://127.0.0.1:3456'. "
"This overrides the URL found in the --node-directory ."],
["dir-cap", None, None,
"Specify which dirnode URI should be used as the 'tahoe' alias."]
]
def postOptions(self):
if self['node-directory']:
self['node-directory'] = argv_to_abspath(self['node-directory'])
self["quiet"] = self.parent["quiet"]
if self.parent['node-directory']:
self['node-directory'] = argv_to_abspath(self.parent['node-directory'])
else:
self['node-directory'] = _default_nodedir

View File

@ -25,58 +25,42 @@ def get_default_nodedir():
class BaseOptions(usage.Options):
# unit tests can override these to point at StringIO instances
stdin = sys.stdin
stdout = sys.stdout
stderr = sys.stderr
optFlags = [
["quiet", "q", "Operate silently."],
["version", "V", "Display version numbers."],
["version-and-path", None, "Display version numbers and paths to their locations."],
]
optParameters = [
["node-directory", "d", None, "Specify which Tahoe node directory should be used." + (
_default_nodedir and (" [default for most commands: " + quote_output(_default_nodedir) + "]") or "")],
]
def __init__(self):
super(BaseOptions, self).__init__()
self.command_name = os.path.basename(sys.argv[0])
if self.command_name == 'trial':
self.command_name = 'tahoe'
# Only allow "tahoe --version", not e.g. "tahoe start --version"
def opt_version(self):
import allmydata
print >>self.stdout, allmydata.get_package_versions_string(debug=True)
self.no_command_needed = True
raise usage.UsageError("--version not allowed on subcommands")
def opt_version_and_path(self):
import allmydata
print >>self.stdout, allmydata.get_package_versions_string(show_paths=True, debug=True)
self.no_command_needed = True
class BasedirMixin:
class BasedirOptions(BaseOptions):
default_nodedir = _default_nodedir
optParameters = [
["basedir", "C", None, "Same as --node-directory."],
["basedir", "C", None, "Same as --node-directory (default %s)."
% get_default_nodedir()],
]
def parseArgs(self, basedir=None):
if self['node-directory'] and self['basedir']:
raise usage.UsageError("The --node-directory (or -d) and --basedir (or -C) "
"options cannot both be used.")
if self.parent['node-directory'] and self['basedir']:
raise usage.UsageError("The --node-directory (or -d) and --basedir (or -C) options cannot both be used.")
if self.parent['node-directory'] and basedir:
raise usage.UsageError("The --node-directory (or -d) option and a basedir argument cannot both be used.")
if self['basedir'] and basedir:
raise usage.UsageError("The --basedir (or -C) option and a basedir argument cannot both be used.")
if basedir:
b = argv_to_abspath(basedir)
elif self['basedir']:
b = argv_to_abspath(self['basedir'])
elif self['node-directory']:
b = argv_to_abspath(self['node-directory'])
else:
elif self.parent['node-directory']:
b = argv_to_abspath(self.parent['node-directory'])
elif self.default_nodedir:
b = self.default_nodedir
else:
raise usage.UsageError("No default basedir available, you must provide one with --node-directory, --basedir, or a basedir argument")
self['basedir'] = b
def postOptions(self):

View File

@ -1,11 +1,11 @@
import os, sys
from allmydata.scripts.common import BasedirMixin, BaseOptions
from allmydata.scripts.common import BasedirOptions
from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
import allmydata
class CreateClientOptions(BasedirMixin, BaseOptions):
class CreateClientOptions(BasedirOptions):
optParameters = [
# we provide 'create-node'-time options for the most common
# configuration knobs. The rest can be controlled by editing
@ -29,13 +29,9 @@ class CreateNodeOptions(CreateClientOptions):
return "Usage: %s create-node [options] [NODEDIR]" % (self.command_name,)
class CreateIntroducerOptions(BasedirMixin, BaseOptions):
class CreateIntroducerOptions(BasedirOptions):
default_nodedir = None
optParameters = [
["node-directory", "d", None, "Specify which directory the introducer should be created in. [no default]"],
]
def getSynopsis(self):
return "Usage: %s create-introducer [options] NODEDIR" % (self.command_name,)

View File

@ -6,9 +6,10 @@ from twisted.python import usage, failure
from twisted.internet import defer
from twisted.scripts import trial as twisted_trial
from foolscap.logging import cli as foolscap_cli
from allmydata.scripts.common import BaseOptions
class DumpOptions(usage.Options):
class DumpOptions(BaseOptions):
def getSynopsis(self):
return "Usage: tahoe debug dump-share SHARE_FILENAME"
@ -18,7 +19,7 @@ class DumpOptions(usage.Options):
]
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Print lots of information about the given share, by parsing the share's
contents. This includes share type, lease information, encoding parameters,
@ -405,7 +406,7 @@ def dump_MDMF_share(m, length, options):
class DumpCapOptions(usage.Options):
class DumpCapOptions(BaseOptions):
def getSynopsis(self):
return "Usage: tahoe debug dump-cap [options] FILECAP"
optParameters = [
@ -420,7 +421,7 @@ class DumpCapOptions(usage.Options):
self.cap = cap
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Print information about the given cap-string (aka: URI, file-cap, dir-cap,
read-cap, write-cap). The URI string is parsed and unpacked. This prints the
@ -607,7 +608,7 @@ def dump_uri_instance(u, nodeid, secret, out, show_header=True):
else:
print >>out, "unknown cap type"
class FindSharesOptions(usage.Options):
class FindSharesOptions(BaseOptions):
def getSynopsis(self):
return "Usage: tahoe debug find-shares STORAGE_INDEX NODEDIRS.."
@ -617,7 +618,7 @@ class FindSharesOptions(usage.Options):
self.nodedirs = map(argv_to_abspath, nodedirs)
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Locate all shares for the given storage index. This command looks through one
or more node directories to find the shares. It returns a list of filenames,
@ -657,7 +658,7 @@ def find_shares(options):
return 0
class CatalogSharesOptions(usage.Options):
class CatalogSharesOptions(BaseOptions):
"""
"""
@ -671,7 +672,7 @@ class CatalogSharesOptions(usage.Options):
return "Usage: tahoe debug catalog-shares NODEDIRS.."
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Locate all shares in the given node directories, and emit a one-line summary
of each share. Run it like this:
@ -879,7 +880,7 @@ def catalog_shares_one_abbrevdir(si_s, si_dir, now, out, err):
print >>err, "Error processing %s" % quote_output(si_dir)
failure.Failure().printTraceback(err)
class CorruptShareOptions(usage.Options):
class CorruptShareOptions(BaseOptions):
def getSynopsis(self):
return "Usage: tahoe debug corrupt-share SHARE_FILENAME"
@ -888,7 +889,7 @@ class CorruptShareOptions(usage.Options):
]
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t = BaseOptions.getUsage(self, width)
t += """
Corrupt the given share by flipping a bit. This will cause a
verifying/downloading client to log an integrity-check failure incident, and
@ -959,7 +960,7 @@ def corrupt_share(options):
class ReplOptions(usage.Options):
class ReplOptions(BaseOptions):
def getSynopsis(self):
return "Usage: tahoe debug repl"
@ -1042,7 +1043,7 @@ def flogtool(config):
return foolscap_cli.run_flogtool()
class DebugCommand(usage.Options):
class DebugCommand(BaseOptions):
subCommands = [
["dump-share", None, DumpOptions,
"Unpack and display the contents of a share (uri_extension and leases)."],
@ -1060,7 +1061,7 @@ class DebugCommand(usage.Options):
def getSynopsis(self):
return ""
def getUsage(self, width=None):
#t = usage.Options.getUsage(self, width)
#t = BaseOptions.getUsage(self, width)
t = """Usage: tahoe debug SUBCOMMAND
Subcommands:
tahoe debug dump-share Unpack and display the contents of a share.

View File

@ -1,16 +1,12 @@
import os, sys
from allmydata.scripts.common import BasedirMixin, BaseOptions
from allmydata.scripts.common import BasedirOptions
from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, quote_output
class CreateKeyGeneratorOptions(BasedirMixin, BaseOptions):
class CreateKeyGeneratorOptions(BasedirOptions):
default_nodedir = None
optParameters = [
["node-directory", "d", None, "Specify which directory the key-generator should be created in. [no default]"],
]
def getSynopsis(self):
return "Usage: %s create-key-generator [options] NODEDIR" % (self.command_name,)

View File

@ -1,10 +1,10 @@
import sys
import os, sys
from cStringIO import StringIO
from twisted.python import usage
from allmydata.scripts.common import BaseOptions
from allmydata.scripts.common import get_default_nodedir
from allmydata.scripts import debug, create_node, startstop_node, cli, keygen, stats_gatherer, admin
from allmydata.util.encodingutil import quote_output, get_io_encoding
@ -15,7 +15,24 @@ def GROUP(s):
return [("\n" + s, None, None, None)]
class Options(BaseOptions, usage.Options):
_default_nodedir = get_default_nodedir()
NODEDIR_HELP = ("Specify which Tahoe node directory should be used. The "
"directory should either contain a full Tahoe node, or a "
"file named node.url that points to some other Tahoe node. "
"It should also contain a file named '"
+ os.path.join('private', 'aliases') +
"' which contains the mapping from alias name to root "
"dirnode URI.")
if _default_nodedir:
NODEDIR_HELP += " [default for most commands: " + quote_output(_default_nodedir) + "]"
class Options(usage.Options):
# unit tests can override these to point at StringIO instances
stdin = sys.stdin
stdout = sys.stdout
stderr = sys.stderr
synopsis = "\nUsage: tahoe <command> [command options]"
subCommands = ( GROUP("Administration")
+ create_node.subCommands
@ -30,6 +47,28 @@ class Options(BaseOptions, usage.Options):
+ cli.subCommands
)
optFlags = [
["quiet", "q", "Operate silently."],
["version", "V", "Display version numbers."],
["version-and-path", None, "Display version numbers and paths to their locations."],
]
optParameters = [
["node-directory", "d", None, NODEDIR_HELP],
]
def opt_version(self):
import allmydata
print >>self.stdout, allmydata.get_package_versions_string(debug=True)
self.no_command_needed = True
def opt_version_and_path(self):
import allmydata
print >>self.stdout, allmydata.get_package_versions_string(show_paths=True, debug=True)
self.no_command_needed = True
def getSynopsis(self):
return "\nUsage: tahoe [global-options] <command> [command-options]"
def getUsage(self, **kwargs):
t = usage.Options.getUsage(self, **kwargs)
return t + "\nPlease run 'tahoe <command> --help' for more details on each command.\n"

View File

@ -1,12 +1,12 @@
import os, sys, signal, time
from allmydata.scripts.common import BasedirMixin, BaseOptions
from allmydata.scripts.common import BasedirOptions
from allmydata.util import fileutil
from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, quote_output
class StartOptions(BasedirMixin, BaseOptions):
class StartOptions(BasedirOptions):
optFlags = [
["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
["syslog", None, "Tell the node to log to syslog, not a file."],
@ -16,12 +16,12 @@ class StartOptions(BasedirMixin, BaseOptions):
return "Usage: %s start [options] [NODEDIR]" % (self.command_name,)
class StopOptions(BasedirMixin, BaseOptions):
class StopOptions(BasedirOptions):
def getSynopsis(self):
return "Usage: %s stop [options] [NODEDIR]" % (self.command_name,)
class RestartOptions(BasedirMixin, BaseOptions):
class RestartOptions(BasedirOptions):
optFlags = [
["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
["syslog", None, "Tell the node to log to syslog, not a file."],
@ -31,13 +31,9 @@ class RestartOptions(BasedirMixin, BaseOptions):
return "Usage: %s restart [options] [NODEDIR]" % (self.command_name,)
class RunOptions(BasedirMixin, BaseOptions):
class RunOptions(BasedirOptions):
default_nodedir = u"."
optParameters = [
["node-directory", "d", None, "Specify the directory of the node to be run. [default, for 'tahoe run' only: current directory]"],
]
def getSynopsis(self):
return "Usage: %s run [options] [NODEDIR]" % (self.command_name,)

View File

@ -1,16 +1,12 @@
import os, sys
from allmydata.scripts.common import BasedirMixin, BaseOptions
from allmydata.scripts.common import BasedirOptions
from allmydata.util.assertutil import precondition
from allmydata.util.encodingutil import listdir_unicode, quote_output
class CreateStatsGathererOptions(BasedirMixin, BaseOptions):
class CreateStatsGathererOptions(BasedirOptions):
default_nodedir = None
optParameters = [
["node-directory", "d", None, "Specify which directory the stats-gatherer should be created in. [no default]"],
]
def getSynopsis(self):
return "Usage: %s create-stats-gatherer [options] NODEDIR" % (self.command_name,)

View File

@ -44,13 +44,19 @@ from allmydata.util.fileutil import abspath_expanduser_unicode
timeout = 480 # deep_check takes 360s on Zandr's linksys box, others take > 240s
def parse_options(basedir, command, args):
o = runner.Options()
o.parseOptions(["--node-directory", basedir, command] + args)
while hasattr(o, "subOptions"):
o = o.subOptions
return o
class CLITestMixin(ReallyEqualMixin):
def do_cli(self, verb, *args, **kwargs):
nodeargs = [
"--node-directory", self.get_clientdir(),
]
argv = [verb] + nodeargs + list(args)
argv = nodeargs + [verb] + list(args)
stdin = kwargs.get("stdin", "")
stdout, stderr = StringIO(), StringIO()
d = threads.deferToThread(runner.runner, argv, run_by_human=False,
@ -73,69 +79,6 @@ class CLITestMixin(ReallyEqualMixin):
class CLI(CLITestMixin, unittest.TestCase):
# this test case only looks at argument-processing and simple stuff.
def test_options(self):
fileutil.rm_dir("cli/test_options")
fileutil.make_dirs("cli/test_options")
fileutil.make_dirs("cli/test_options/private")
fileutil.write("cli/test_options/node.url", "http://localhost:8080/\n")
filenode_uri = uri.WriteableSSKFileURI(writekey="\x00"*16,
fingerprint="\x00"*32)
private_uri = uri.DirectoryURI(filenode_uri).to_string()
fileutil.write("cli/test_options/private/root_dir.cap", private_uri + "\n")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options"])
self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], private_uri)
self.failUnlessReallyEqual(o.where, u"")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--node-url", "http://example.org:8111/"])
self.failUnlessReallyEqual(o['node-url'], "http://example.org:8111/")
self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], private_uri)
self.failUnlessReallyEqual(o.where, u"")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--dir-cap", "root"])
self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], "root")
self.failUnlessReallyEqual(o.where, u"")
o = cli.ListOptions()
other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
fingerprint="\x11"*32)
other_uri = uri.DirectoryURI(other_filenode_uri).to_string()
o.parseOptions(["--node-directory", "cli/test_options",
"--dir-cap", other_uri])
self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], other_uri)
self.failUnlessReallyEqual(o.where, u"")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--dir-cap", other_uri, "subdir"])
self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], other_uri)
self.failUnlessReallyEqual(o.where, u"subdir")
o = cli.ListOptions()
self.failUnlessRaises(usage.UsageError,
o.parseOptions,
["--node-directory", "cli/test_options",
"--node-url", "NOT-A-URL"])
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--node-url", "http://localhost:8080"])
self.failUnlessReallyEqual(o["node-url"], "http://localhost:8080/")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--node-url", "https://localhost/"])
self.failUnlessReallyEqual(o["node-url"], "https://localhost/")
def _dump_cap(self, *args):
config = debug.DumpCapOptions()
config.stdout,config.stderr = StringIO(), StringIO()
@ -730,11 +673,11 @@ class Help(unittest.TestCase):
class CreateAlias(GridTestMixin, CLITestMixin, unittest.TestCase):
def _test_webopen(self, args, expected_url):
woo = cli.WebopenOptions()
all_args = ["--node-directory", self.get_clientdir()] + list(args)
woo.parseOptions(all_args)
o = runner.Options()
o.parseOptions(["--node-directory", self.get_clientdir(), "webopen"]
+ list(args))
urls = []
rc = cli.webopen(woo, urls.append)
rc = cli.webopen(o, urls.append)
self.failUnlessReallyEqual(rc, 0)
self.failUnlessReallyEqual(len(urls), 1)
self.failUnlessReallyEqual(urls[0], expected_url)
@ -2747,25 +2690,20 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase):
fileutil.make_dirs(basedir)
nodeurl_path = os.path.join(basedir, 'node.url')
fileutil.write(nodeurl_path, 'http://example.net:2357/')
def parse(args): return parse_options(basedir, "backup", args)
# test simple exclude
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude', '*lyx', '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude', '*lyx', 'from', 'to'])
filtered = list(backup_options.filter_listdir(root_listdir))
self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
(u'nice_doc.lyx',))
# multiple exclude
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude', '*lyx', '--exclude', 'lib.?', '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude', '*lyx', '--exclude', 'lib.?', 'from', 'to'])
filtered = list(backup_options.filter_listdir(root_listdir))
self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'),
(u'nice_doc.lyx', u'lib.a'))
# vcs metadata exclusion
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude-vcs', '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude-vcs', 'from', 'to'])
filtered = list(backup_options.filter_listdir(subdir_listdir))
self._check_filtering(filtered, subdir_listdir, (u'another_doc.lyx', u'run_snake_run.py',),
(u'CVS', u'.svn', u'_darcs'))
@ -2773,22 +2711,17 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase):
exclusion_string = "_darcs\n*py\n.svn"
excl_filepath = os.path.join(basedir, 'exclusion')
fileutil.write(excl_filepath, exclusion_string)
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude-from', excl_filepath, '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude-from', excl_filepath, 'from', 'to'])
filtered = list(backup_options.filter_listdir(subdir_listdir))
self._check_filtering(filtered, subdir_listdir, (u'another_doc.lyx', u'CVS'),
(u'.svn', u'_darcs', u'run_snake_run.py'))
# test BackupConfigurationError
self.failUnlessRaises(cli.BackupConfigurationError,
backup_options.parseOptions,
['--exclude-from', excl_filepath + '.no', '--node-directory',
basedir, 'from', 'to'])
parse,
['--exclude-from', excl_filepath + '.no', 'from', 'to'])
# test that an iterator works too
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude', '*lyx', '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude', '*lyx', 'from', 'to'])
filtered = list(backup_options.filter_listdir(iter(root_listdir)))
self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
(u'nice_doc.lyx',))
@ -2805,18 +2738,15 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase):
fileutil.make_dirs(basedir)
nodeurl_path = os.path.join(basedir, 'node.url')
fileutil.write(nodeurl_path, 'http://example.net:2357/')
def parse(args): return parse_options(basedir, "backup", args)
# test simple exclude
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude', doc_pattern_arg, '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude', doc_pattern_arg, 'from', 'to'])
filtered = list(backup_options.filter_listdir(root_listdir))
self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
(nice_doc,))
# multiple exclude
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude', doc_pattern_arg, '--exclude', 'lib.?', '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude', doc_pattern_arg, '--exclude', 'lib.?', 'from', 'to'])
filtered = list(backup_options.filter_listdir(root_listdir))
self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'),
(nice_doc, u'lib.a'))
@ -2824,17 +2754,13 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase):
exclusion_string = doc_pattern_arg + "\nlib.?"
excl_filepath = os.path.join(basedir, 'exclusion')
fileutil.write(excl_filepath, exclusion_string)
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude-from', excl_filepath, '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude-from', excl_filepath, 'from', 'to'])
filtered = list(backup_options.filter_listdir(root_listdir))
self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'),
(nice_doc, u'lib.a'))
# test that an iterator works too
backup_options = cli.BackupOptions()
backup_options.parseOptions(['--exclude', doc_pattern_arg, '--node-directory',
basedir, 'from', 'to'])
backup_options = parse(['--exclude', doc_pattern_arg, 'from', 'to'])
filtered = list(backup_options.filter_listdir(iter(root_listdir)))
self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
(nice_doc,))
@ -2845,14 +2771,13 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase):
fileutil.make_dirs(basedir)
nodeurl_path = os.path.join(basedir, 'node.url')
fileutil.write(nodeurl_path, 'http://example.net:2357/')
def parse(args): return parse_options(basedir, "backup", args)
# ensure that tilde expansion is performed on exclude-from argument
exclude_file = u'~/.tahoe/excludes.dummy'
backup_options = cli.BackupOptions()
mock.return_value = StringIO()
backup_options.parseOptions(['--exclude-from', unicode_to_argv(exclude_file),
'--node-directory', basedir, 'from', 'to'])
parse(['--exclude-from', unicode_to_argv(exclude_file), 'from', 'to'])
self.failUnlessIn(((abspath_expanduser_unicode(exclude_file),), {}), mock.call_args_list)
def test_ignore_symlinks(self):
@ -3765,3 +3690,111 @@ class Webopen(GridTestMixin, CLITestMixin, unittest.TestCase):
_cleanup(None)
raise
return d
class Options(unittest.TestCase):
# this test case only looks at argument-processing and simple stuff.
def parse(self, args, stdout=None):
o = runner.Options()
if stdout is not None:
o.stdout = stdout
o.parseOptions(args)
while hasattr(o, "subOptions"):
o = o.subOptions
return o
def test_list(self):
fileutil.rm_dir("cli/test_options")
fileutil.make_dirs("cli/test_options")
fileutil.make_dirs("cli/test_options/private")
fileutil.write("cli/test_options/node.url", "http://localhost:8080/\n")
filenode_uri = uri.WriteableSSKFileURI(writekey="\x00"*16,
fingerprint="\x00"*32)
private_uri = uri.DirectoryURI(filenode_uri).to_string()
fileutil.write("cli/test_options/private/root_dir.cap", private_uri + "\n")
def parse2(args): return parse_options("cli/test_options", "ls", args)
o = parse2([])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
self.failUnlessEqual(o.where, u"")
o = parse2(["--node-url", "http://example.org:8111/"])
self.failUnlessEqual(o['node-url'], "http://example.org:8111/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
self.failUnlessEqual(o.where, u"")
o = parse2(["--dir-cap", "root"])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], "root")
self.failUnlessEqual(o.where, u"")
other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
fingerprint="\x11"*32)
other_uri = uri.DirectoryURI(other_filenode_uri).to_string()
o = parse2(["--dir-cap", other_uri])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
self.failUnlessEqual(o.where, u"")
o = parse2(["--dir-cap", other_uri, "subdir"])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
self.failUnlessEqual(o.where, u"subdir")
self.failUnlessRaises(usage.UsageError, parse2,
["--node-url", "NOT-A-URL"])
o = parse2(["--node-url", "http://localhost:8080"])
self.failUnlessEqual(o["node-url"], "http://localhost:8080/")
o = parse2(["--node-url", "https://localhost/"])
self.failUnlessEqual(o["node-url"], "https://localhost/")
def test_version(self):
# "tahoe --version" dumps text to stdout and exits
stdout = StringIO()
self.failUnlessRaises(SystemExit, self.parse, ["--version"], stdout)
self.failUnlessIn("allmydata-tahoe", stdout.getvalue())
# but "tahoe SUBCOMMAND --version" should be rejected
self.failUnlessRaises(usage.UsageError, self.parse,
["start", "--version"])
self.failUnlessRaises(usage.UsageError, self.parse,
["start", "--version-and-path"])
def test_quiet(self):
# accepted as an overall option, but not on subcommands
o = self.parse(["--quiet", "start"])
self.failUnless(o.parent["quiet"])
self.failUnlessRaises(usage.UsageError, self.parse,
["start", "--quiet"])
def test_basedir(self):
# accept a --node-directory option before the verb, or a --basedir
# option after, or a basedir argument after, but none in the wrong
# place, and not more than one of the three.
o = self.parse(["start"])
self.failUnlessEqual(o["basedir"], os.path.expanduser("~/.tahoe"))
o = self.parse(["start", "here"])
self.failUnlessEqual(o["basedir"], os.path.abspath("here"))
o = self.parse(["start", "--basedir", "there"])
self.failUnlessEqual(o["basedir"], os.path.abspath("there"))
o = self.parse(["--node-directory", "there", "start"])
self.failUnlessEqual(o["basedir"], os.path.abspath("there"))
self.failUnlessRaises(usage.UsageError, self.parse,
["--basedir", "there", "start"])
self.failUnlessRaises(usage.UsageError, self.parse,
["start", "--node-directory", "there"])
self.failUnlessRaises(usage.UsageError, self.parse,
["--node-directory=there",
"start", "--basedir=here"])
self.failUnlessRaises(usage.UsageError, self.parse,
["start", "--basedir=here", "anywhere"])
self.failUnlessRaises(usage.UsageError, self.parse,
["--node-directory=there",
"start", "anywhere"])
self.failUnlessRaises(usage.UsageError, self.parse,
["--node-directory=there",
"start", "--basedir=here", "anywhere"])

View File

@ -759,8 +759,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_manifest_stream1(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["manifest",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"manifest",
self.root_uri])
def _check((out,err)):
self.failUnlessEqual(err, "")
@ -787,8 +787,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_manifest_stream2(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["manifest",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"manifest",
"--raw",
self.root_uri])
def _check((out,err)):
@ -800,8 +800,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_manifest_stream3(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["manifest",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"manifest",
"--storage-index",
self.root_uri])
def _check((out,err)):
@ -812,8 +812,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_manifest_stream4(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["manifest",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"manifest",
"--verify-cap",
self.root_uri])
def _check((out,err)):
@ -828,8 +828,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_manifest_stream5(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["manifest",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"manifest",
"--repair-cap",
self.root_uri])
def _check((out,err)):
@ -844,8 +844,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_stats1(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["stats",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"stats",
self.root_uri])
def _check3((out,err)):
lines = [l.strip() for l in out.split("\n") if l]
@ -864,8 +864,8 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
def do_cli_stats2(self):
basedir = self.get_clientdir(0)
d = self._run_cli(["stats",
"--node-directory", basedir,
d = self._run_cli(["--node-directory", basedir,
"stats",
"--raw",
self.root_uri])
def _check4((out,err)):

View File

@ -284,7 +284,7 @@ class CreateNode(unittest.TestCase):
# test the --node-directory form
n3 = os.path.join(basedir, command + "-n3")
argv = ["--quiet", command, "--node-directory", n3]
argv = ["--quiet", "--node-directory", n3, command]
rc, out, err = self.run_tahoe(argv)
self.failUnlessEqual(err, "")
self.failUnlessEqual(out, "")

View File

@ -1440,7 +1440,7 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase):
def run(ignored, verb, *args, **kwargs):
stdin = kwargs.get("stdin", "")
newargs = [verb] + nodeargs + list(args)
newargs = nodeargs + [verb] + list(args)
return self._run_cli(newargs, stdin=stdin)
def _check_ls((out,err), expected_children, unexpected_children=[]):
@ -1745,7 +1745,7 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase):
# tahoe_ls doesn't currently handle the error correctly: it tries to
# JSON-parse a traceback.
## def _ls_missing(res):
## argv = ["ls"] + nodeargs + ["bogus"]
## argv = nodeargs + ["ls", "bogus"]
## return self._run_cli(argv)
## d.addCallback(_ls_missing)
## def _check_ls_missing((out,err)):
@ -1769,7 +1769,7 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase):
def _run_in_subprocess(ignored, verb, *args, **kwargs):
stdin = kwargs.get("stdin")
env = kwargs.get("env")
newargs = [verb, "--node-directory", self.getdir("client0")] + list(args)
newargs = ["--node-directory", self.getdir("client0"), verb] + list(args)
return self.run_bintahoe(newargs, stdin=stdin, env=env)
def _check_succeeded(res, check_stderr=True):