Basedir/node directory option improvements for ticket798 branch. addresses #188,...
authordavid-sarah <david-sarah@jacaranda.org>
Mon, 2 Aug 2010 04:30:04 +0000 (21:30 -0700)
committerdavid-sarah <david-sarah@jacaranda.org>
Mon, 2 Aug 2010 04:30:04 +0000 (21:30 -0700)
src/allmydata/scripts/cli.py
src/allmydata/scripts/common.py
src/allmydata/scripts/create_node.py
src/allmydata/scripts/keygen.py
src/allmydata/scripts/startstop_node.py
src/allmydata/test/test_runner.py

index 8dff5de2d409ab61db01432eca2cb6efbeb5b3de..62994de4896d6f5812633c71347db0b936a78ab2 100644 (file)
@@ -1,19 +1,21 @@
 import os.path, re, sys, fnmatch
 from twisted.python import usage
-from allmydata.scripts.common import BaseOptions, get_aliases
-from allmydata.util.encodingutil import argv_to_unicode, argv_to_abspath
+from allmydata.scripts.common import BaseOptions, get_aliases, get_default_nodedir, DEFAULT_ALIAS
+from allmydata.util.encodingutil import argv_to_unicode, argv_to_abspath, quote_output
 
 NODEURL_RE=re.compile("http(s?)://([^:]*)(:([1-9][0-9]*))?")
 
-class VDriveOptions(BaseOptions, usage.Options):
+_default_nodedir = get_default_nodedir()
+
+class VDriveOptions(BaseOptions):
     optParameters = [
-        ["node-directory", "d", "~/.tahoe",
-         "Look here to find out which Tahoe node should be used for all "
-         "operations. The directory should either contain a full Tahoe node, "
-         "or a file named node.url which points to some other Tahoe node. "
-         "It should also contain a file named private/aliases which contains "
-         "the mapping from alias name to root dirnode URI."
-         ],
+        ["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 private/aliases which contains the mapping from alias name "
+         "to root dirnode URI." + (
+            _default_nodedir and (" [default for most commands: " + quote_output(_default_nodedir) + "]") or "")],
         ["node-url", "u", None,
          "URL of the tahoe node to use, a URL like \"http://127.0.0.1:3456\". "
          "This overrides the URL found in the --node-directory ."],
@@ -22,13 +24,12 @@ class VDriveOptions(BaseOptions, usage.Options):
         ]
 
     def postOptions(self):
-        # compute a node-url from the existing options, put in self['node-url']
         if self['node-directory']:
-            if sys.platform == 'win32' and self['node-directory'] == '~/.tahoe':
-                from allmydata.windows import registry
-                self['node-directory'] = registry.get_base_dir_path()
-            else:
-                self['node-directory'] = argv_to_abspath(self['node-directory'])
+            self['node-directory'] = argv_to_abspath(self['node-directory'])
+        else:
+            self['node-directory'] = _default_nodedir
+
+        # compute a node-url from the existing options, put in self['node-url']
         if self['node-url']:
             if (not isinstance(self['node-url'], basestring)
                 or not NODEURL_RE.match(self['node-url'])):
@@ -44,7 +45,7 @@ class VDriveOptions(BaseOptions, usage.Options):
 
         aliases = get_aliases(self['node-directory'])
         if self['dir-cap']:
-            aliases["tahoe"] = self['dir-cap']
+            aliases[DEFAULT_ALIAS] = self['dir-cap']
         self.aliases = aliases # maps alias name to dircap
 
 
index f4d81108b75d82cbd6b1742518f3b945757ea3aa..9987ffb7a6152fe29fc068b55c740ae0fc49e0e4 100644 (file)
@@ -6,7 +6,25 @@ from allmydata.util.assertutil import precondition
 from allmydata.util.encodingutil import unicode_to_url, quote_output, argv_to_abspath
 from allmydata.util.fileutil import abspath_expanduser_unicode
 
-class BaseOptions:
+
+_default_nodedir = None
+if sys.platform == 'win32':
+    from allmydata.windows import registry
+    path = registry.get_base_dir_path()
+    if path:
+        precondition(isinstance(path, unicode), path)
+        _default_nodedir = abspath_expanduser_unicode(path)
+
+if _default_nodedir is None:
+    path = abspath_expanduser_unicode(u"~/.tahoe")
+    precondition(isinstance(path, unicode), path)
+    _default_nodedir = path
+
+def get_default_nodedir():
+    return _default_nodedir
+
+
+class BaseOptions(usage.Options):
     # unit tests can override these to point at StringIO instances
     stdin = sys.stdin
     stdout = sys.stdout
@@ -16,7 +34,11 @@ class BaseOptions:
         ["quiet", "q", "Operate silently."],
         ["version", "V", "Display version numbers and exit."],
         ["version-and-path", None, "Display version numbers and paths to their locations and exit."],
-        ]
+    ]
+    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 opt_version(self):
         import allmydata
@@ -30,54 +52,47 @@ class BaseOptions:
 
 
 class BasedirMixin:
-    optFlags = [
-        ["multiple", "m", "allow multiple basedirs to be specified at once"],
-        ]
+    default_nodedir = _default_nodedir
+    allow_multiple = True
 
-    def postOptions(self):
-        if not self.basedirs:
-            raise usage.UsageError("<basedir> parameter is required")
-        if self['basedir']:
-            del self['basedir']
-        self['basedirs'] = self.basedirs
+    optParameters = [
+        ["basedir", "C", None, "Same as --node-directory."],
+    ]
+    optFlags = [
+        ["multiple", "m", "Specify multiple node directories at once"],
+    ]
 
     def parseArgs(self, *args):
-        self.basedirs = []
-        if self['basedir']:
-            precondition(isinstance(self['basedir'], str), self['basedir'])
-            self.basedirs.append(argv_to_abspath(self['basedir']))
-        if self['multiple']:
-            self.basedirs.extend(map(argv_to_abspath, args))
+        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['node-directory'] or self['basedir']:
+            self.basedirs = [argv_to_abspath(self['node-directory'] or self['basedir'])]
         else:
-            if len(args) == 0 and not self.basedirs:
-                if sys.platform == 'win32':
-                    from allmydata.windows import registry
-                    rbdp = registry.get_base_dir_path()
-                    if rbdp:
-                        precondition(isinstance(registry.get_base_dir_path(), unicode), registry.get_base_dir_path())
-                        self.basedirs.append(rbdp)
-                else:
-                    self.basedirs.append(abspath_expanduser_unicode(u"~/.tahoe"))
-            if len(args) > 0:
-                self.basedirs.append(argv_to_abspath(args[0]))
-            if len(args) > 1:
-                raise usage.UsageError("I wasn't expecting so many arguments")
+            self.basedirs = []
 
-class NoDefaultBasedirMixin(BasedirMixin):
-    def parseArgs(self, *args):
-        # create-client won't default to --basedir=~/.tahoe
-        self.basedirs = []
-        if self['basedir']:
-            self.basedirs.append(argv_to_abspath(self['basedir']))
-        if self['multiple']:
+        if self.allow_multiple and self['multiple']:
             self.basedirs.extend(map(argv_to_abspath, args))
         else:
             if len(args) > 0:
                 self.basedirs.append(argv_to_abspath(args[0]))
             if len(args) > 1:
-                raise usage.UsageError("I wasn't expecting so many arguments")
+                raise usage.UsageError("I wasn't expecting so many arguments." +
+                    (self.allow_multiple and
+                     " Use the --multiple option to specify more than one node directory." or ""))
+
+            if len(args) == 0 and self.default_nodedir and not self.basedirs:
+                self.basedirs.append(self.default_nodedir)
+            elif len(args) > 0:
+                self.basedirs.append(argv_to_abspath(args[0]))
+
+    def postOptions(self):
         if not self.basedirs:
-            raise usage.UsageError("--basedir must be provided")
+            raise usage.UsageError("A base directory for the node must be provided.")
+        del self['basedir']
+        self['basedirs'] = self.basedirs
+
 
 DEFAULT_ALIAS = u"tahoe"
 
@@ -91,7 +106,7 @@ def get_aliases(nodedir):
         f = open(rootfile, "r")
         rootcap = f.read().strip()
         if rootcap:
-            aliases[u"tahoe"] = uri.from_string_dirnode(rootcap).to_string()
+            aliases[DEFAULT_ALIAS] = uri.from_string_dirnode(rootcap).to_string()
     except EnvironmentError:
         pass
     try:
index 8841d35041646759216b2d3e9b6248a59a5bf13a..de356c5d8c28d2bfd52fd7c42133539994c34980 100644 (file)
@@ -1,12 +1,11 @@
 
 import os, sys
-from twisted.python import usage
-from allmydata.scripts.common import BasedirMixin, NoDefaultBasedirMixin
+from allmydata.scripts.common import BasedirMixin, BaseOptions
 from allmydata.util.assertutil import precondition
 from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
 import allmydata
 
-class CreateClientOptions(BasedirMixin, usage.Options):
+class CreateClientOptions(BasedirMixin, BaseOptions):
     optParameters = [
         ("basedir", "C", None, "which directory to create the node in"),
         # we provide 'create-node'-time options for the most common
@@ -23,7 +22,9 @@ class CreateNodeOptions(CreateClientOptions):
         ("no-storage", None, "do not offer storage service to other nodes"),
         ]
 
-class CreateIntroducerOptions(NoDefaultBasedirMixin, usage.Options):
+class CreateIntroducerOptions(BasedirMixin, BaseOptions):
+    default_nodedir = None
+
     optParameters = [
         ["basedir", "C", None, "which directory to create the introducer in"],
         ]
index cd8ff364343f0e0afd4db4bfcfec902044a8cfa6..a8fd7fc191cf1de7dccefaac0df5434712a2c98e 100644 (file)
@@ -1,13 +1,15 @@
 
 import os, sys
-from twisted.python import usage
-#from allmydata.scripts.common import BasedirMixin, NoDefaultBasedirMixin
-from allmydata.util.encodingutil import listdir_unicode, argv_to_abspath, quote_output
+from allmydata.scripts.common import BasedirMixin, BaseOptions
+from allmydata.util.encodingutil import listdir_unicode, quote_output
+
+class CreateKeyGeneratorOptions(BasedirMixin, BaseOptions):
+    default_nodedir = None
+    allow_multiple = False
 
-class CreateKeyGeneratorOptions(usage.Options):
     optParameters = [
         ["basedir", "C", None, "which directory to create the key-generator in"],
-        ]
+    ]
 
 keygen_tac = """
 # -*- python -*-
@@ -25,10 +27,7 @@ k.setServiceParent(application)
 """
 
 def create_key_generator(config, out=sys.stdout, err=sys.stderr):
-    if not config['basedir']:
-        print >>err, "a basedir was not provided, please use --basedir or -C"
-        return -1
-    basedir = argv_to_abspath(config['basedir'])
+    basedir = config['basedirs'][0]
     if os.path.exists(basedir):
         if listdir_unicode(basedir):
             print >>err, "The base directory %s is not empty." % quote_output(basedir)
index 3cfc0845f2c16222af34591b81b332523ef6f5a6..df7a68215f5d5a20d1d90fc871c499da127100b7 100644 (file)
@@ -1,10 +1,9 @@
 
 import os, sys, signal, time
-from twisted.python import usage
-from allmydata.scripts.common import BasedirMixin
+from allmydata.scripts.common import BasedirMixin, BaseOptions
 from allmydata.util import fileutil, find_exe
 
-class StartOptions(BasedirMixin, usage.Options):
+class StartOptions(BasedirMixin, BaseOptions):
     optParameters = [
         ["basedir", "C", None, "which directory to start the node in"],
         ]
@@ -13,12 +12,12 @@ class StartOptions(BasedirMixin, usage.Options):
         ["syslog", None, "tell the node to log to syslog, not a file"],
         ]
 
-class StopOptions(BasedirMixin, usage.Options):
+class StopOptions(BasedirMixin, BaseOptions):
     optParameters = [
         ["basedir", "C", None, "which directory to stop the node in"],
         ]
 
-class RestartOptions(BasedirMixin, usage.Options):
+class RestartOptions(BasedirMixin, BaseOptions):
     optParameters = [
         ["basedir", "C", None, "which directory to restart the node in"],
         ]
@@ -27,7 +26,9 @@ class RestartOptions(BasedirMixin, usage.Options):
         ["syslog", None, "tell the node to log to syslog, not a file"],
         ]
 
-class RunOptions(usage.Options):
+class RunOptions(BasedirMixin, BaseOptions):
+    default_nodedir = u"."
+
     optParameters = [
         ["basedir", "C", None, "which directory to run the node in, CWD by default"],
         ]
index 458a70174a52f69550f16f7e22583c0e69463856..ab986c9ffc32a7c3607b76bf4c4ba8940b19cd0d 100644 (file)
@@ -202,10 +202,9 @@ class CreateNode(unittest.TestCase):
 
         # make sure it rejects a missing basedir specification
         argv = ["create-key-generator"]
-        rc, out, err = self.run_tahoe(argv)
-        self.failIfEqual(rc, 0, str((out, err, rc)))
-        self.failUnlessEqual(out, "")
-        self.failUnless("a basedir was not provided" in err)
+        self.failUnlessRaises(usage.UsageError,
+                              runner.runner, argv,
+                              run_by_human=False)
 
     def test_stats_gatherer(self):
         basedir = self.workdir("test_stats_gatherer")