Ticket #166: fix-args.diff

File fix-args.diff, 42.4 KB (added by warner, at 2012-05-31T21:55:55Z)

fix handling of --node-directory

  • src/allmydata/scripts/admin.py

    diff --git a/src/allmydata/scripts/admin.py b/src/allmydata/scripts/admin.py
    index 581224d..1a6c985 100644
    a b  
    11
    22from twisted.python import usage
     3from allmydata.scripts.common import BaseOptions
    34
    4 class GenerateKeypairOptions(usage.Options):
     5class GenerateKeypairOptions(BaseOptions):
    56    def getSynopsis(self):
    67        return "Usage: tahoe admin generate-keypair"
    78
    89    def getUsage(self, width=None):
    9         t = usage.Options.getUsage(self, width)
     10        t = BaseOptions.getUsage(self, width)
    1011        t += """
    1112Generate a public/private keypair, dumped to stdout as two lines of ASCII..
    1213
    def print_keypair(options): 
    2021    print >>out, "private:", privkey_vs
    2122    print >>out, "public:", pubkey_vs
    2223
    23 class DerivePubkeyOptions(usage.Options):
     24class DerivePubkeyOptions(BaseOptions):
    2425    def parseArgs(self, privkey):
    2526        self.privkey = privkey
    2627
    class DerivePubkeyOptions(usage.Options): 
    2829        return "Usage: tahoe admin derive-pubkey PRIVKEY"
    2930
    3031    def getUsage(self, width=None):
    31         t = usage.Options.getUsage(self, width)
     32        t = BaseOptions.getUsage(self, width)
    3233        t += """
    3334Given a private (signing) key that was previously generated with
    3435generate-keypair, derive the public key and print it to stdout.
    def derive_pubkey(options): 
    4546    print >>out, "public:", pubkey_vs
    4647    return 0
    4748
    48 class AdminCommand(usage.Options):
     49class AdminCommand(BaseOptions):
    4950    subCommands = [
    5051        ("generate-keypair", None, GenerateKeypairOptions,
    5152         "Generate a public/private keypair, write to stdout."),
    class AdminCommand(usage.Options): 
    5859    def getSynopsis(self):
    5960        return "Usage: tahoe admin SUBCOMMAND"
    6061    def getUsage(self, width=None):
    61         t = usage.Options.getUsage(self, width)
     62        t = BaseOptions.getUsage(self, width)
    6263        t += """
    6364Please run e.g. 'tahoe admin generate-keypair --help' for more details on
    6465each subcommand.
  • src/allmydata/scripts/cli.py

    diff --git a/src/allmydata/scripts/cli.py b/src/allmydata/scripts/cli.py
    index bb48ef4..e26b401 100644
    a b  
    11import os.path, re, fnmatch
    22from twisted.python import usage
    3 from allmydata.scripts.common import BaseOptions, get_aliases, get_default_nodedir, DEFAULT_ALIAS
     3from allmydata.scripts.common import get_aliases, get_default_nodedir, \
     4     DEFAULT_ALIAS, BaseOptions
    45from allmydata.util.encodingutil import argv_to_unicode, argv_to_abspath, quote_output
    56
    67NODEURL_RE=re.compile("http(s?)://([^:]*)(:([1-9][0-9]*))?")
    _default_nodedir = get_default_nodedir() 
    910
    1011class VDriveOptions(BaseOptions):
    1112    optParameters = [
    12         ["node-directory", "d", None,
    13          "Specify which Tahoe node directory should be used. The directory "
    14          "should either contain a full Tahoe node, or a file named node.url "
    15          "that points to some other Tahoe node. It should also contain a file "
    16          "named '" + os.path.join('private', 'aliases') + "' which contains the "
    17          "mapping from alias name to root dirnode URI." + (
    18             _default_nodedir and (" [default: " + quote_output(_default_nodedir) + "]") or "")],
    1913        ["node-url", "u", None,
    20          "Specify the URL of the Tahoe gateway node, such as 'http://127.0.0.1:3456'. "
     14         "Specify the URL of the Tahoe gateway node, such as "
     15         "'http://127.0.0.1:3456'. "
    2116         "This overrides the URL found in the --node-directory ."],
    2217        ["dir-cap", None, None,
    2318         "Specify which dirnode URI should be used as the 'tahoe' alias."]
    2419        ]
    2520
    2621    def postOptions(self):
    27         if self['node-directory']:
    28             self['node-directory'] = argv_to_abspath(self['node-directory'])
     22        self["quiet"] = self.parent["quiet"]
     23        if self.parent['node-directory']:
     24            self['node-directory'] = argv_to_abspath(self.parent['node-directory'])
    2925        else:
    3026            self['node-directory'] = _default_nodedir
    3127
  • src/allmydata/scripts/common.py

    diff --git a/src/allmydata/scripts/common.py b/src/allmydata/scripts/common.py
    index cd545c3..25de448 100644
    a b def get_default_nodedir(): 
    2525
    2626
    2727class BaseOptions(usage.Options):
    28     # unit tests can override these to point at StringIO instances
    29     stdin = sys.stdin
    30     stdout = sys.stdout
    31     stderr = sys.stderr
    32 
    33     optFlags = [
    34         ["quiet", "q", "Operate silently."],
    35         ["version", "V", "Display version numbers."],
    36         ["version-and-path", None, "Display version numbers and paths to their locations."],
    37     ]
    38     optParameters = [
    39         ["node-directory", "d", None, "Specify which Tahoe node directory should be used." + (
    40             _default_nodedir and (" [default for most commands: " + quote_output(_default_nodedir) + "]") or "")],
    41     ]
    42 
    4328    def __init__(self):
    4429        super(BaseOptions, self).__init__()
    4530        self.command_name = os.path.basename(sys.argv[0])
    4631        if self.command_name == 'trial':
    4732            self.command_name = 'tahoe'
    4833
     34    # Only allow "tahoe --version", not e.g. "tahoe start --version"
    4935    def opt_version(self):
    50         import allmydata
    51         print >>self.stdout, allmydata.get_package_versions_string(debug=True)
    52         self.no_command_needed = True
     36        raise usage.UsageError("--version not allowed on subcommands")
    5337
    54     def opt_version_and_path(self):
    55         import allmydata
    56         print >>self.stdout, allmydata.get_package_versions_string(show_paths=True, debug=True)
    57         self.no_command_needed = True
    58 
    59 
    60 class BasedirMixin:
     38class BasedirOptions(BaseOptions):
    6139    default_nodedir = _default_nodedir
    6240
    6341    optParameters = [
    class BasedirMixin: 
    6543    ]
    6644
    6745    def parseArgs(self, basedir=None):
    68         if self['node-directory'] and self['basedir']:
    69             raise usage.UsageError("The --node-directory (or -d) and --basedir (or -C) "
    70                                    "options cannot both be used.")
     46        if self.parent['node-directory'] and self['basedir']:
     47            raise usage.UsageError("The --node-directory (or -d) and --basedir (or -C) options cannot both be used.")
     48        if self.parent['node-directory'] and basedir:
     49            raise usage.UsageError("The --node-directory (or -d) option and a basedir argumnent cannot both be used.")
     50        if self['basedir'] and basedir:
     51            raise usage.UsageError("The --basedir (or -C) option and a basedir argument cannot both be used.")
    7152
    7253        if basedir:
    7354            b = argv_to_abspath(basedir)
    7455        elif self['basedir']:
    7556            b = argv_to_abspath(self['basedir'])
    76         elif self['node-directory']:
    77             b = argv_to_abspath(self['node-directory'])
    78         else:
     57        elif self.parent['node-directory']:
     58            b = argv_to_abspath(self.parent['node-directory'])
     59        elif self.default_nodedir:
    7960            b = self.default_nodedir
     61        else:
     62            raise usage.UsageError("No default basedir available, you must provide one with --node-directory, --basedir, or a basedir argument")
    8063        self['basedir'] = b
    8164
    8265    def postOptions(self):
  • src/allmydata/scripts/create_node.py

    diff --git a/src/allmydata/scripts/create_node.py b/src/allmydata/scripts/create_node.py
    index 7e9dcf7..893bf08 100644
    a b  
    11
    22import os, sys
    3 from allmydata.scripts.common import BasedirMixin, BaseOptions
     3from allmydata.scripts.common import BasedirOptions
    44from allmydata.util.assertutil import precondition
    55from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
    66import allmydata
    77
    8 class CreateClientOptions(BasedirMixin, BaseOptions):
     8class CreateClientOptions(BasedirOptions):
    99    optParameters = [
    1010        # we provide 'create-node'-time options for the most common
    1111        # configuration knobs. The rest can be controlled by editing
    class CreateNodeOptions(CreateClientOptions): 
    2929        return "Usage:  %s create-node [options] [NODEDIR]" % (self.command_name,)
    3030
    3131
    32 class CreateIntroducerOptions(BasedirMixin, BaseOptions):
     32class CreateIntroducerOptions(BasedirOptions):
    3333    default_nodedir = None
    3434
    35     optParameters = [
    36         ["node-directory", "d", None, "Specify which directory the introducer should be created in. [no default]"],
    37     ]
    38 
    3935    def getSynopsis(self):
    4036        return "Usage:  %s create-introducer [options] NODEDIR" % (self.command_name,)
    4137
  • src/allmydata/scripts/debug.py

    diff --git a/src/allmydata/scripts/debug.py b/src/allmydata/scripts/debug.py
    index f7749cd..cb8e986 100644
    a b from twisted.python import usage, failure 
    66from twisted.internet import defer
    77from twisted.scripts import trial as twisted_trial
    88from foolscap.logging import cli as foolscap_cli
     9from allmydata.scripts.common import BaseOptions
    910
    1011
    11 class DumpOptions(usage.Options):
     12class DumpOptions(BaseOptions):
    1213    def getSynopsis(self):
    1314        return "Usage: tahoe debug dump-share SHARE_FILENAME"
    1415
    class DumpOptions(usage.Options): 
    1819        ]
    1920
    2021    def getUsage(self, width=None):
    21         t = usage.Options.getUsage(self, width)
     22        t = BaseOptions.getUsage(self, width)
    2223        t += """
    2324Print lots of information about the given share, by parsing the share's
    2425contents. This includes share type, lease information, encoding parameters,
    def dump_MDMF_share(m, length, options): 
    405406
    406407
    407408
    408 class DumpCapOptions(usage.Options):
     409class DumpCapOptions(BaseOptions):
    409410    def getSynopsis(self):
    410411        return "Usage: tahoe debug dump-cap [options] FILECAP"
    411412    optParameters = [
    class DumpCapOptions(usage.Options): 
    420421        self.cap = cap
    421422
    422423    def getUsage(self, width=None):
    423         t = usage.Options.getUsage(self, width)
     424        t = BaseOptions.getUsage(self, width)
    424425        t += """
    425426Print information about the given cap-string (aka: URI, file-cap, dir-cap,
    426427read-cap, write-cap). The URI string is parsed and unpacked. This prints the
    def dump_uri_instance(u, nodeid, secret, out, show_header=True): 
    607608    else:
    608609        print >>out, "unknown cap type"
    609610
    610 class FindSharesOptions(usage.Options):
     611class FindSharesOptions(BaseOptions):
    611612    def getSynopsis(self):
    612613        return "Usage: tahoe debug find-shares STORAGE_INDEX NODEDIRS.."
    613614
    class FindSharesOptions(usage.Options): 
    617618        self.nodedirs = map(argv_to_abspath, nodedirs)
    618619
    619620    def getUsage(self, width=None):
    620         t = usage.Options.getUsage(self, width)
     621        t = BaseOptions.getUsage(self, width)
    621622        t += """
    622623Locate all shares for the given storage index. This command looks through one
    623624or more node directories to find the shares. It returns a list of filenames,
    def find_shares(options): 
    657658    return 0
    658659
    659660
    660 class CatalogSharesOptions(usage.Options):
     661class CatalogSharesOptions(BaseOptions):
    661662    """
    662663
    663664    """
    class CatalogSharesOptions(usage.Options): 
    671672        return "Usage: tahoe debug catalog-shares NODEDIRS.."
    672673
    673674    def getUsage(self, width=None):
    674         t = usage.Options.getUsage(self, width)
     675        t = BaseOptions.getUsage(self, width)
    675676        t += """
    676677Locate all shares in the given node directories, and emit a one-line summary
    677678of each share. Run it like this:
    def catalog_shares_one_abbrevdir(si_s, si_dir, now, out, err): 
    879880        print >>err, "Error processing %s" % quote_output(si_dir)
    880881        failure.Failure().printTraceback(err)
    881882
    882 class CorruptShareOptions(usage.Options):
     883class CorruptShareOptions(BaseOptions):
    883884    def getSynopsis(self):
    884885        return "Usage: tahoe debug corrupt-share SHARE_FILENAME"
    885886
    class CorruptShareOptions(usage.Options): 
    888889        ]
    889890
    890891    def getUsage(self, width=None):
    891         t = usage.Options.getUsage(self, width)
     892        t = BaseOptions.getUsage(self, width)
    892893        t += """
    893894Corrupt the given share by flipping a bit. This will cause a
    894895verifying/downloading client to log an integrity-check failure incident, and
    def corrupt_share(options): 
    959960
    960961
    961962
    962 class ReplOptions(usage.Options):
     963class ReplOptions(BaseOptions):
    963964    def getSynopsis(self):
    964965        return "Usage: tahoe debug repl"
    965966
    def flogtool(config): 
    10421043    return foolscap_cli.run_flogtool()
    10431044
    10441045
    1045 class DebugCommand(usage.Options):
     1046class DebugCommand(BaseOptions):
    10461047    subCommands = [
    10471048        ["dump-share", None, DumpOptions,
    10481049         "Unpack and display the contents of a share (uri_extension and leases)."],
    class DebugCommand(usage.Options): 
    10601061    def getSynopsis(self):
    10611062        return ""
    10621063    def getUsage(self, width=None):
    1063         #t = usage.Options.getUsage(self, width)
     1064        #t = BaseOptions.getUsage(self, width)
    10641065        t = """Usage: tahoe debug SUBCOMMAND
    10651066Subcommands:
    10661067    tahoe debug dump-share      Unpack and display the contents of a share.
  • src/allmydata/scripts/keygen.py

    diff --git a/src/allmydata/scripts/keygen.py b/src/allmydata/scripts/keygen.py
    index 1f5c30f..5b1c9ab 100644
    a b  
    11
    22import os, sys
    3 from allmydata.scripts.common import BasedirMixin, BaseOptions
     3from allmydata.scripts.common import BasedirOptions
    44from allmydata.util.assertutil import precondition
    55from allmydata.util.encodingutil import listdir_unicode, quote_output
    66
    7 class CreateKeyGeneratorOptions(BasedirMixin, BaseOptions):
     7class CreateKeyGeneratorOptions(BasedirOptions):
    88    default_nodedir = None
    99
    10     optParameters = [
    11         ["node-directory", "d", None, "Specify which directory the key-generator should be created in. [no default]"],
    12     ]
    13 
    1410    def getSynopsis(self):
    1511        return "Usage:  %s create-key-generator [options] NODEDIR" % (self.command_name,)
    1612
  • src/allmydata/scripts/runner.py

    diff --git a/src/allmydata/scripts/runner.py b/src/allmydata/scripts/runner.py
    index e66f8d3..e4eb67e 100644
    a b  
    11
    2 import sys
     2import os, sys
    33from cStringIO import StringIO
    44
    55from twisted.python import usage
    66
    7 from allmydata.scripts.common import BaseOptions
     7from allmydata.scripts.common import get_default_nodedir
    88from allmydata.scripts import debug, create_node, startstop_node, cli, keygen, stats_gatherer, admin
    99from allmydata.util.encodingutil import quote_output, get_io_encoding
    1010
    def GROUP(s): 
    1515    return [("\n" + s, None, None, None)]
    1616
    1717
    18 class Options(BaseOptions, usage.Options):
     18_default_nodedir = get_default_nodedir()
     19
     20NODEDIR_HELP = ("Specify which Tahoe node directory should be used. The "
     21                "directory should either contain a full Tahoe node, or a "
     22                "file named node.url that points to some other Tahoe node. "
     23                "It should also contain a file named '"
     24                + os.path.join('private', 'aliases') +
     25                "' which contains the mapping from alias name to root "
     26                "dirnode URI.")
     27if _default_nodedir:
     28    NODEDIR_HELP += " [default for most commands: " + quote_output(_default_nodedir) + "]"
     29
     30class Options(usage.Options):
     31    # unit tests can override these to point at StringIO instances
     32    stdin = sys.stdin
     33    stdout = sys.stdout
     34    stderr = sys.stderr
     35
    1936    synopsis = "\nUsage:  tahoe <command> [command options]"
    2037    subCommands = ( GROUP("Administration")
    2138                    +   create_node.subCommands
    class Options(BaseOptions, usage.Options): 
    3047                    +   cli.subCommands
    3148                    )
    3249
     50    optFlags = [
     51        ["quiet", "q", "Operate silently."],
     52        ["version", "V", "Display version numbers."],
     53        ["version-and-path", None, "Display version numbers and paths to their locations."],
     54    ]
     55    optParameters = [
     56        ["node-directory", "d", None, NODEDIR_HELP],
     57    ]
     58
     59    def opt_version(self):
     60        import allmydata
     61        print >>self.stdout, allmydata.get_package_versions_string(debug=True)
     62        self.no_command_needed = True
     63
     64    def opt_version_and_path(self):
     65        import allmydata
     66        print >>self.stdout, allmydata.get_package_versions_string(show_paths=True, debug=True)
     67        self.no_command_needed = True
     68
     69    def getSynopsis(self):
     70        return "\nUsage: tahoe [global-options] <command> [command-options]"
     71
    3372    def getUsage(self, **kwargs):
    3473        t = usage.Options.getUsage(self, **kwargs)
    3574        return t + "\nPlease run 'tahoe <command> --help' for more details on each command.\n"
  • src/allmydata/scripts/startstop_node.py

    diff --git a/src/allmydata/scripts/startstop_node.py b/src/allmydata/scripts/startstop_node.py
    index 5045bd6..36138e0 100644
    a b  
    11
    22import os, sys, signal, time
    3 from allmydata.scripts.common import BasedirMixin, BaseOptions
     3from allmydata.scripts.common import BasedirOptions
    44from allmydata.util import fileutil
    55from allmydata.util.assertutil import precondition
    66from allmydata.util.encodingutil import listdir_unicode, quote_output
    77
    88
    9 class StartOptions(BasedirMixin, BaseOptions):
     9class StartOptions(BasedirOptions):
    1010    optFlags = [
    1111        ["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
    1212        ["syslog", None, "Tell the node to log to syslog, not a file."],
    class StartOptions(BasedirMixin, BaseOptions): 
    1616        return "Usage:  %s start [options] [NODEDIR]" % (self.command_name,)
    1717
    1818
    19 class StopOptions(BasedirMixin, BaseOptions):
     19class StopOptions(BasedirOptions):
    2020    def getSynopsis(self):
    2121        return "Usage:  %s stop [options] [NODEDIR]" % (self.command_name,)
    2222
    2323
    24 class RestartOptions(BasedirMixin, BaseOptions):
     24class RestartOptions(BasedirOptions):
    2525    optFlags = [
    2626        ["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
    2727        ["syslog", None, "Tell the node to log to syslog, not a file."],
    class RestartOptions(BasedirMixin, BaseOptions): 
    3131        return "Usage:  %s restart [options] [NODEDIR]" % (self.command_name,)
    3232
    3333
    34 class RunOptions(BasedirMixin, BaseOptions):
     34class RunOptions(BasedirOptions):
    3535    default_nodedir = u"."
    3636
    37     optParameters = [
    38         ["node-directory", "d", None, "Specify the directory of the node to be run. [default, for 'tahoe run' only: current directory]"],
    39     ]
    40 
    4137    def getSynopsis(self):
    4238        return "Usage:  %s run [options] [NODEDIR]" % (self.command_name,)
    4339
  • src/allmydata/scripts/stats_gatherer.py

    diff --git a/src/allmydata/scripts/stats_gatherer.py b/src/allmydata/scripts/stats_gatherer.py
    index 230d4a9..bdb3576 100644
    a b  
    11
    22import os, sys
    3 from allmydata.scripts.common import BasedirMixin, BaseOptions
     3from allmydata.scripts.common import BasedirOptions
    44from allmydata.util.assertutil import precondition
    55from allmydata.util.encodingutil import listdir_unicode, quote_output
    66
    7 class CreateStatsGathererOptions(BasedirMixin, BaseOptions):
     7class CreateStatsGathererOptions(BasedirOptions):
    88    default_nodedir = None
    99
    10     optParameters = [
    11         ["node-directory", "d", None, "Specify which directory the stats-gatherer should be created in. [no default]"],
    12     ]
    13 
    1410    def getSynopsis(self):
    1511        return "Usage:  %s create-stats-gatherer [options] NODEDIR" % (self.command_name,)
    1612
  • src/allmydata/test/test_cli.py

    diff --git a/src/allmydata/test/test_cli.py b/src/allmydata/test/test_cli.py
    index c88d00b..d0906a2 100644
    a b from allmydata.util.fileutil import abspath_expanduser_unicode 
    4242
    4343timeout = 480 # deep_check takes 360s on Zandr's linksys box, others take > 240s
    4444
     45def parse_options(basedir, command, args):
     46    o = runner.Options()
     47    o.parseOptions(["--node-directory", basedir, command] + args)
     48    while hasattr(o, "subOptions"):
     49        o = o.subOptions
     50    return o
    4551
    4652class CLITestMixin(ReallyEqualMixin):
    4753    def do_cli(self, verb, *args, **kwargs):
    4854        nodeargs = [
    4955            "--node-directory", self.get_clientdir(),
    5056            ]
    51         argv = [verb] + nodeargs + list(args)
     57        argv = nodeargs + [verb] + list(args)
    5258        stdin = kwargs.get("stdin", "")
    5359        stdout, stderr = StringIO(), StringIO()
    5460        d = threads.deferToThread(runner.runner, argv, run_by_human=False,
    class CLITestMixin(ReallyEqualMixin): 
    7177
    7278
    7379class CLI(CLITestMixin, unittest.TestCase):
    74     # this test case only looks at argument-processing and simple stuff.
    75     def test_options(self):
    76         fileutil.rm_dir("cli/test_options")
    77         fileutil.make_dirs("cli/test_options")
    78         fileutil.make_dirs("cli/test_options/private")
    79         fileutil.write("cli/test_options/node.url", "http://localhost:8080/\n")
    80         filenode_uri = uri.WriteableSSKFileURI(writekey="\x00"*16,
    81                                                fingerprint="\x00"*32)
    82         private_uri = uri.DirectoryURI(filenode_uri).to_string()
    83         fileutil.write("cli/test_options/private/root_dir.cap", private_uri + "\n")
    84         o = cli.ListOptions()
    85         o.parseOptions(["--node-directory", "cli/test_options"])
    86         self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
    87         self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], private_uri)
    88         self.failUnlessReallyEqual(o.where, u"")
    89 
    90         o = cli.ListOptions()
    91         o.parseOptions(["--node-directory", "cli/test_options",
    92                         "--node-url", "http://example.org:8111/"])
    93         self.failUnlessReallyEqual(o['node-url'], "http://example.org:8111/")
    94         self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], private_uri)
    95         self.failUnlessReallyEqual(o.where, u"")
    96 
    97         o = cli.ListOptions()
    98         o.parseOptions(["--node-directory", "cli/test_options",
    99                         "--dir-cap", "root"])
    100         self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
    101         self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], "root")
    102         self.failUnlessReallyEqual(o.where, u"")
    103 
    104         o = cli.ListOptions()
    105         other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
    106                                                      fingerprint="\x11"*32)
    107         other_uri = uri.DirectoryURI(other_filenode_uri).to_string()
    108         o.parseOptions(["--node-directory", "cli/test_options",
    109                         "--dir-cap", other_uri])
    110         self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
    111         self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], other_uri)
    112         self.failUnlessReallyEqual(o.where, u"")
    113 
    114         o = cli.ListOptions()
    115         o.parseOptions(["--node-directory", "cli/test_options",
    116                         "--dir-cap", other_uri, "subdir"])
    117         self.failUnlessReallyEqual(o['node-url'], "http://localhost:8080/")
    118         self.failUnlessReallyEqual(o.aliases[DEFAULT_ALIAS], other_uri)
    119         self.failUnlessReallyEqual(o.where, u"subdir")
    120 
    121         o = cli.ListOptions()
    122         self.failUnlessRaises(usage.UsageError,
    123                               o.parseOptions,
    124                               ["--node-directory", "cli/test_options",
    125                                "--node-url", "NOT-A-URL"])
    126 
    127         o = cli.ListOptions()
    128         o.parseOptions(["--node-directory", "cli/test_options",
    129                         "--node-url", "http://localhost:8080"])
    130         self.failUnlessReallyEqual(o["node-url"], "http://localhost:8080/")
    131 
    132         o = cli.ListOptions()
    133         o.parseOptions(["--node-directory", "cli/test_options",
    134                         "--node-url", "https://localhost/"])
    135         self.failUnlessReallyEqual(o["node-url"], "https://localhost/")
    136 
    13780    def _dump_cap(self, *args):
    13881        config = debug.DumpCapOptions()
    13982        config.stdout,config.stderr = StringIO(), StringIO()
    class Help(unittest.TestCase): 
    703646class CreateAlias(GridTestMixin, CLITestMixin, unittest.TestCase):
    704647
    705648    def _test_webopen(self, args, expected_url):
    706         woo = cli.WebopenOptions()
    707         all_args = ["--node-directory", self.get_clientdir()] + list(args)
    708         woo.parseOptions(all_args)
     649        o = runner.Options()
     650        o.parseOptions(["--node-directory", self.get_clientdir(), "webopen"]
     651                       + list(args))
    709652        urls = []
    710         rc = cli.webopen(woo, urls.append)
     653        rc = cli.webopen(o, urls.append)
    711654        self.failUnlessReallyEqual(rc, 0)
    712655        self.failUnlessReallyEqual(len(urls), 1)
    713656        self.failUnlessReallyEqual(urls[0], expected_url)
    class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): 
    26742617        fileutil.make_dirs(basedir)
    26752618        nodeurl_path = os.path.join(basedir, 'node.url')
    26762619        fileutil.write(nodeurl_path, 'http://example.net:2357/')
     2620        def parse(args): return parse_options(basedir, "backup", args)
    26772621
    26782622        # test simple exclude
    2679         backup_options = cli.BackupOptions()
    2680         backup_options.parseOptions(['--exclude', '*lyx', '--node-directory',
    2681                                      basedir, 'from', 'to'])
     2623        backup_options = parse(['--exclude', '*lyx', 'from', 'to'])
    26822624        filtered = list(backup_options.filter_listdir(root_listdir))
    26832625        self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
    26842626                              (u'nice_doc.lyx',))
    26852627        # multiple exclude
    2686         backup_options = cli.BackupOptions()
    2687         backup_options.parseOptions(['--exclude', '*lyx', '--exclude', 'lib.?', '--node-directory',
    2688                                      basedir, 'from', 'to'])
     2628        backup_options = parse(['--exclude', '*lyx', '--exclude', 'lib.?', 'from', 'to'])
    26892629        filtered = list(backup_options.filter_listdir(root_listdir))
    26902630        self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'),
    26912631                              (u'nice_doc.lyx', u'lib.a'))
    26922632        # vcs metadata exclusion
    2693         backup_options = cli.BackupOptions()
    2694         backup_options.parseOptions(['--exclude-vcs', '--node-directory',
    2695                                      basedir, 'from', 'to'])
     2633        backup_options = parse(['--exclude-vcs', 'from', 'to'])
    26962634        filtered = list(backup_options.filter_listdir(subdir_listdir))
    26972635        self._check_filtering(filtered, subdir_listdir, (u'another_doc.lyx', u'run_snake_run.py',),
    26982636                              (u'CVS', u'.svn', u'_darcs'))
    class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): 
    27002638        exclusion_string = "_darcs\n*py\n.svn"
    27012639        excl_filepath = os.path.join(basedir, 'exclusion')
    27022640        fileutil.write(excl_filepath, exclusion_string)
    2703         backup_options = cli.BackupOptions()
    2704         backup_options.parseOptions(['--exclude-from', excl_filepath, '--node-directory',
    2705                                      basedir, 'from', 'to'])
     2641        backup_options = parse(['--exclude-from', excl_filepath, 'from', 'to'])
    27062642        filtered = list(backup_options.filter_listdir(subdir_listdir))
    27072643        self._check_filtering(filtered, subdir_listdir, (u'another_doc.lyx', u'CVS'),
    27082644                              (u'.svn', u'_darcs', u'run_snake_run.py'))
    27092645        # test BackupConfigurationError
    27102646        self.failUnlessRaises(cli.BackupConfigurationError,
    2711                               backup_options.parseOptions,
    2712                               ['--exclude-from', excl_filepath + '.no', '--node-directory',
    2713                                basedir, 'from', 'to'])
     2647                              parse,
     2648                              ['--exclude-from', excl_filepath + '.no', 'from', 'to'])
    27142649
    27152650        # test that an iterator works too
    2716         backup_options = cli.BackupOptions()
    2717         backup_options.parseOptions(['--exclude', '*lyx', '--node-directory',
    2718                                      basedir, 'from', 'to'])
     2651        backup_options = parse(['--exclude', '*lyx', 'from', 'to'])
    27192652        filtered = list(backup_options.filter_listdir(iter(root_listdir)))
    27202653        self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
    27212654                              (u'nice_doc.lyx',))
    class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): 
    27322665        fileutil.make_dirs(basedir)
    27332666        nodeurl_path = os.path.join(basedir, 'node.url')
    27342667        fileutil.write(nodeurl_path, 'http://example.net:2357/')
     2668        def parse(args): return parse_options(basedir, "backup", args)
    27352669
    27362670        # test simple exclude
    2737         backup_options = cli.BackupOptions()
    2738         backup_options.parseOptions(['--exclude', doc_pattern_arg, '--node-directory',
    2739                                      basedir, 'from', 'to'])
     2671        backup_options = parse(['--exclude', doc_pattern_arg, 'from', 'to'])
    27402672        filtered = list(backup_options.filter_listdir(root_listdir))
    27412673        self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
    27422674                              (nice_doc,))
    27432675        # multiple exclude
    2744         backup_options = cli.BackupOptions()
    2745         backup_options.parseOptions(['--exclude', doc_pattern_arg, '--exclude', 'lib.?', '--node-directory',
    2746                                      basedir, 'from', 'to'])
     2676        backup_options = parse(['--exclude', doc_pattern_arg, '--exclude', 'lib.?', 'from', 'to'])
    27472677        filtered = list(backup_options.filter_listdir(root_listdir))
    27482678        self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'),
    27492679                             (nice_doc, u'lib.a'))
    class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): 
    27512681        exclusion_string = doc_pattern_arg + "\nlib.?"
    27522682        excl_filepath = os.path.join(basedir, 'exclusion')
    27532683        fileutil.write(excl_filepath, exclusion_string)
    2754         backup_options = cli.BackupOptions()
    2755         backup_options.parseOptions(['--exclude-from', excl_filepath, '--node-directory',
    2756                                      basedir, 'from', 'to'])
     2684        backup_options = parse(['--exclude-from', excl_filepath, 'from', 'to'])
    27572685        filtered = list(backup_options.filter_listdir(root_listdir))
    27582686        self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'),
    27592687                             (nice_doc, u'lib.a'))
    27602688
    27612689        # test that an iterator works too
    2762         backup_options = cli.BackupOptions()
    2763         backup_options.parseOptions(['--exclude', doc_pattern_arg, '--node-directory',
    2764                                      basedir, 'from', 'to'])
     2690        backup_options = parse(['--exclude', doc_pattern_arg, 'from', 'to'])
    27652691        filtered = list(backup_options.filter_listdir(iter(root_listdir)))
    27662692        self._check_filtering(filtered, root_listdir, (u'lib.a', u'_darcs', u'subdir'),
    27672693                              (nice_doc,))
    class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): 
    27722698        fileutil.make_dirs(basedir)
    27732699        nodeurl_path = os.path.join(basedir, 'node.url')
    27742700        fileutil.write(nodeurl_path, 'http://example.net:2357/')
     2701        def parse(args): return parse_options(basedir, "backup", args)
    27752702
    27762703        # ensure that tilde expansion is performed on exclude-from argument
    27772704        exclude_file = u'~/.tahoe/excludes.dummy'
    2778         backup_options = cli.BackupOptions()
    27792705
    27802706        mock.return_value = StringIO()
    2781         backup_options.parseOptions(['--exclude-from', unicode_to_argv(exclude_file),
    2782                                      '--node-directory', basedir, 'from', 'to'])
     2707        parse(['--exclude-from', unicode_to_argv(exclude_file), 'from', 'to'])
    27832708        self.failUnlessIn(((abspath_expanduser_unicode(exclude_file),), {}), mock.call_args_list)
    27842709
    27852710    def test_ignore_symlinks(self):
    class Webopen(GridTestMixin, CLITestMixin, unittest.TestCase): 
    36283553            _cleanup(None)
    36293554            raise
    36303555        return d
     3556
     3557class Options(unittest.TestCase):
     3558    # this test case only looks at argument-processing and simple stuff.
     3559
     3560    def parse(self, args, stdout=None):
     3561        o = runner.Options()
     3562        if stdout is not None:
     3563            o.stdout = stdout
     3564        o.parseOptions(args)
     3565        while hasattr(o, "subOptions"):
     3566            o = o.subOptions
     3567        return o
     3568
     3569    def test_list(self):
     3570        fileutil.rm_dir("cli/test_options")
     3571        fileutil.make_dirs("cli/test_options")
     3572        fileutil.make_dirs("cli/test_options/private")
     3573        fileutil.write("cli/test_options/node.url", "http://localhost:8080/\n")
     3574        filenode_uri = uri.WriteableSSKFileURI(writekey="\x00"*16,
     3575                                               fingerprint="\x00"*32)
     3576        private_uri = uri.DirectoryURI(filenode_uri).to_string()
     3577        fileutil.write("cli/test_options/private/root_dir.cap", private_uri + "\n")
     3578        def parse2(args): return parse_options("cli/test_options", "ls", args)
     3579        o = parse2([])
     3580        self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
     3581        self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
     3582        self.failUnlessEqual(o.where, u"")
     3583
     3584        o = parse2(["--node-url", "http://example.org:8111/"])
     3585        self.failUnlessEqual(o['node-url'], "http://example.org:8111/")
     3586        self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
     3587        self.failUnlessEqual(o.where, u"")
     3588
     3589        o = parse2(["--dir-cap", "root"])
     3590        self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
     3591        self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], "root")
     3592        self.failUnlessEqual(o.where, u"")
     3593
     3594        other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
     3595                                                     fingerprint="\x11"*32)
     3596        other_uri = uri.DirectoryURI(other_filenode_uri).to_string()
     3597        o = parse2(["--dir-cap", other_uri])
     3598        self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
     3599        self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
     3600        self.failUnlessEqual(o.where, u"")
     3601
     3602        o = parse2(["--dir-cap", other_uri, "subdir"])
     3603        self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
     3604        self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
     3605        self.failUnlessEqual(o.where, u"subdir")
     3606
     3607        self.failUnlessRaises(usage.UsageError, parse2,
     3608                              ["--node-url", "NOT-A-URL"])
     3609
     3610        o = parse2(["--node-url", "http://localhost:8080"])
     3611        self.failUnlessEqual(o["node-url"], "http://localhost:8080/")
     3612
     3613        o = parse2(["--node-url", "https://localhost/"])
     3614        self.failUnlessEqual(o["node-url"], "https://localhost/")
     3615
     3616    def test_version(self):
     3617        # "tahoe --version" dumps text to stdout and exits
     3618        stdout = StringIO()
     3619        self.failUnlessRaises(SystemExit, self.parse, ["--version"], stdout)
     3620        self.failUnlessIn("allmydata-tahoe", stdout.getvalue())
     3621        # but "tahoe SUBCOMMAND --version" should be rejected
     3622        self.failUnlessRaises(usage.UsageError, self.parse,
     3623                              ["start", "--version"])
     3624        self.failUnlessRaises(usage.UsageError, self.parse,
     3625                              ["start", "--version-and-path"])
     3626
     3627    def test_quiet(self):
     3628        # accepted as an overall option, but not on subcommands
     3629        o = self.parse(["--quiet", "start"])
     3630        self.failUnless(o.parent["quiet"])
     3631        self.failUnlessRaises(usage.UsageError, self.parse,
     3632                              ["start", "--quiet"])
     3633
     3634    def test_basedir(self):
     3635        # accept a --node-directory option before the verb, or a --basedir
     3636        # option after, or a basedir argument after, but none in the wrong
     3637        # place, and not more than one of the three.
     3638        o = self.parse(["start"])
     3639        self.failUnlessEqual(o["basedir"], os.path.expanduser("~/.tahoe"))
     3640        o = self.parse(["start", "here"])
     3641        self.failUnlessEqual(o["basedir"], os.path.abspath("here"))
     3642        o = self.parse(["start", "--basedir", "there"])
     3643        self.failUnlessEqual(o["basedir"], os.path.abspath("there"))
     3644        o = self.parse(["--node-directory", "there", "start"])
     3645        self.failUnlessEqual(o["basedir"], os.path.abspath("there"))
     3646
     3647        self.failUnlessRaises(usage.UsageError, self.parse,
     3648                              ["--basedir", "there", "start"])
     3649        self.failUnlessRaises(usage.UsageError, self.parse,
     3650                              ["start", "--node-directory", "there"])
     3651
     3652        self.failUnlessRaises(usage.UsageError, self.parse,
     3653                              ["--node-directory=there",
     3654                               "start", "--basedir=here"])
     3655        self.failUnlessRaises(usage.UsageError, self.parse,
     3656                              ["start", "--basedir=here", "anywhere"])
     3657        self.failUnlessRaises(usage.UsageError, self.parse,
     3658                              ["--node-directory=there",
     3659                               "start", "anywhere"])
     3660        self.failUnlessRaises(usage.UsageError, self.parse,
     3661                              ["--node-directory=there",
     3662                               "start", "--basedir=here", "anywhere"])
     3663
  • src/allmydata/test/test_deepcheck.py

    diff --git a/src/allmydata/test/test_deepcheck.py b/src/allmydata/test/test_deepcheck.py
    index 669a6d5..f29a688 100644
    a b class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    761761
    762762    def do_cli_manifest_stream1(self):
    763763        basedir = self.get_clientdir(0)
    764         d = self._run_cli(["manifest",
    765                            "--node-directory", basedir,
     764        d = self._run_cli(["--node-directory", basedir,
     765                           "manifest",
    766766                           self.root_uri])
    767767        def _check((out,err)):
    768768            self.failUnlessEqual(err, "")
    class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    789789
    790790    def do_cli_manifest_stream2(self):
    791791        basedir = self.get_clientdir(0)
    792         d = self._run_cli(["manifest",
    793                            "--node-directory", basedir,
     792        d = self._run_cli(["--node-directory", basedir,
     793                           "manifest",
    794794                           "--raw",
    795795                           self.root_uri])
    796796        def _check((out,err)):
    class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    802802
    803803    def do_cli_manifest_stream3(self):
    804804        basedir = self.get_clientdir(0)
    805         d = self._run_cli(["manifest",
    806                            "--node-directory", basedir,
     805        d = self._run_cli(["--node-directory", basedir,
     806                           "manifest",
    807807                           "--storage-index",
    808808                           self.root_uri])
    809809        def _check((out,err)):
    class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    814814
    815815    def do_cli_manifest_stream4(self):
    816816        basedir = self.get_clientdir(0)
    817         d = self._run_cli(["manifest",
    818                            "--node-directory", basedir,
     817        d = self._run_cli(["--node-directory", basedir,
     818                           "manifest",
    819819                           "--verify-cap",
    820820                           self.root_uri])
    821821        def _check((out,err)):
    class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    830830
    831831    def do_cli_manifest_stream5(self):
    832832        basedir = self.get_clientdir(0)
    833         d = self._run_cli(["manifest",
    834                            "--node-directory", basedir,
     833        d = self._run_cli(["--node-directory", basedir,
     834                           "manifest",
    835835                           "--repair-cap",
    836836                           self.root_uri])
    837837        def _check((out,err)):
    class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    846846
    847847    def do_cli_stats1(self):
    848848        basedir = self.get_clientdir(0)
    849         d = self._run_cli(["stats",
    850                            "--node-directory", basedir,
     849        d = self._run_cli(["--node-directory", basedir,
     850                           "stats",
    851851                           self.root_uri])
    852852        def _check3((out,err)):
    853853            lines = [l.strip() for l in out.split("\n") if l]
    class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): 
    866866
    867867    def do_cli_stats2(self):
    868868        basedir = self.get_clientdir(0)
    869         d = self._run_cli(["stats",
    870                            "--node-directory", basedir,
     869        d = self._run_cli(["--node-directory", basedir,
     870                           "stats",
    871871                           "--raw",
    872872                           self.root_uri])
    873873        def _check4((out,err)):
  • src/allmydata/test/test_runner.py

    diff --git a/src/allmydata/test/test_runner.py b/src/allmydata/test/test_runner.py
    index 4e9f683..96894e8 100644
    a b class CreateNode(unittest.TestCase): 
    282282
    283283        # test the --node-directory form
    284284        n3 = os.path.join(basedir, command + "-n3")
    285         argv = ["--quiet", command, "--node-directory", n3]
     285        argv = ["--quiet", "--node-directory", n3, command]
    286286        rc, out, err = self.run_tahoe(argv)
    287287        self.failUnlessEqual(err, "")
    288288        self.failUnlessEqual(out, "")
  • src/allmydata/test/test_system.py

    diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py
    index f3b72f5..5c19e16 100644
    a b class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): 
    14311431
    14321432        def run(ignored, verb, *args, **kwargs):
    14331433            stdin = kwargs.get("stdin", "")
    1434             newargs = [verb] + nodeargs + list(args)
     1434            newargs = nodeargs + [verb] + list(args)
    14351435            return self._run_cli(newargs, stdin=stdin)
    14361436
    14371437        def _check_ls((out,err), expected_children, unexpected_children=[]):
    class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): 
    17361736        # tahoe_ls doesn't currently handle the error correctly: it tries to
    17371737        # JSON-parse a traceback.
    17381738##         def _ls_missing(res):
    1739 ##             argv = ["ls"] + nodeargs + ["bogus"]
     1739##             argv = nodeargs + ["ls", "bogus"]
    17401740##             return self._run_cli(argv)
    17411741##         d.addCallback(_ls_missing)
    17421742##         def _check_ls_missing((out,err)):
    class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): 
    17601760        def _run_in_subprocess(ignored, verb, *args, **kwargs):
    17611761            stdin = kwargs.get("stdin")
    17621762            env = kwargs.get("env")
    1763             newargs = [verb, "--node-directory", self.getdir("client0")] + list(args)
     1763            newargs = ["--node-directory", self.getdir("client0"), verb] + list(args)
    17641764            return self.run_bintahoe(newargs, stdin=stdin, env=env)
    17651765
    17661766        def _check_succeeded(res, check_stderr=True):