]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/scripts/startstop_node.py
CLI: put "[global-opts]" in all command synopses
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / startstop_node.py
index df7a68215f5d5a20d1d90fc871c499da127100b7..9ecbf06924f739b7a8491face29352dd874a1491 100644 (file)
@@ -1,49 +1,55 @@
 
 import os, sys, signal, time
-from allmydata.scripts.common import BasedirMixin, BaseOptions
-from allmydata.util import fileutil, find_exe
+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):
-    optParameters = [
-        ["basedir", "C", None, "which directory to start the node in"],
-        ]
+
+class StartOptions(BasedirOptions):
     optFlags = [
-        ["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
-        ["syslog", None, "tell the node to log to syslog, not a file"],
+        ["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."],
         ]
 
-class StopOptions(BasedirMixin, BaseOptions):
-    optParameters = [
-        ["basedir", "C", None, "which directory to stop the node in"],
-        ]
+    def getSynopsis(self):
+        return "Usage:  %s [global-opts] start [options] [NODEDIR]" % (self.command_name,)
 
-class RestartOptions(BasedirMixin, BaseOptions):
-    optParameters = [
-        ["basedir", "C", None, "which directory to restart the node in"],
-        ]
+
+class StopOptions(BasedirOptions):
+    def getSynopsis(self):
+        return "Usage:  %s [global-opts] stop [options] [NODEDIR]" % (self.command_name,)
+
+
+class RestartOptions(BasedirOptions):
     optFlags = [
-        ["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
-        ["syslog", None, "tell the node to log to syslog, not a file"],
+        ["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."],
         ]
 
-class RunOptions(BasedirMixin, BaseOptions):
+    def getSynopsis(self):
+        return "Usage:  %s [global-opts] restart [options] [NODEDIR]" % (self.command_name,)
+
+
+class RunOptions(BasedirOptions):
     default_nodedir = u"."
 
-    optParameters = [
-        ["basedir", "C", None, "which directory to run the node in, CWD by default"],
-        ]
+    def getSynopsis(self):
+        return "Usage:  %s [global-opts] run [options] [NODEDIR]" % (self.command_name,)
+
 
-def do_start(basedir, opts, out=sys.stdout, err=sys.stderr):
-    print >>out, "STARTING", basedir
+def start(opts, out=sys.stdout, err=sys.stderr):
+    basedir = opts['basedir']
+    print >>out, "STARTING", quote_output(basedir)
     if not os.path.isdir(basedir):
-        print >>err, "%s does not look like a directory at all" % basedir
+        print >>err, "%s does not look like a directory at all" % quote_output(basedir)
         return 1
-    for fn in os.listdir(basedir):
-        if fn.endswith(".tac"):
-            tac = fn
+    for fn in listdir_unicode(basedir):
+        if fn.endswith(u".tac"):
+            tac = str(fn)
             break
     else:
-        print >>err, "%s does not look like a node directory (no .tac file)" % basedir
+        print >>err, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
         return 1
     if "client" in tac:
         nodetype = "client"
@@ -52,66 +58,29 @@ def do_start(basedir, opts, out=sys.stdout, err=sys.stderr):
     else:
         nodetype = "unknown (%s)" % tac
 
-    cmd = find_exe.find_exe('twistd')
-    if not cmd:
-        # If 'twistd' wasn't on $PATH, maybe we're running from source and
-        # Twisted was built as one of our dependencies. If so, we're at
-        # BASEDIR/src/allmydata/scripts/startstop_node.py, and it's at
-        # BASEDIR/support/$BINDIR/twistd
-        up = os.path.dirname
-        TAHOEDIR = up(up(up(up(os.path.abspath(__file__)))))
-        if sys.platform == "win32":
-            bin_dir = "Scripts"
-        else:
-            bin_dir = "bin"
-        bindir = os.path.join(TAHOEDIR, "support", bin_dir)
-
-        maybe = os.path.join(bindir, "twistd")
-        if os.path.exists(maybe):
-            cmd = [maybe]
-            oldpath = os.environ.get("PATH", "").split(os.pathsep)
-            os.environ["PATH"] = os.pathsep.join(oldpath + [bindir])
-            # sys.path and $PYTHONPATH are taken care of by the extra code in
-            # 'setup.py trial'
-        else:
-            maybe = maybe+'.py'
-            if os.path.exists(maybe):
-                cmd = [sys.executable, maybe]
-                oldpath = os.environ.get("PATH", "").split(os.pathsep)
-                os.environ["PATH"] = os.pathsep.join(oldpath + [bindir])
-                # sys.path and $PYTHONPATH are taken care of by the extra code in
-                # 'setup.py trial'
-
-    if not cmd:
-        print "Can't find twistd (it comes with Twisted).  Aborting."
-        sys.exit(1)
-
-    cmd.extend(["-y", tac])
+    args = ["twistd", "-y", tac]
     if opts["syslog"]:
-        cmd.append("--syslog")
+        args.append("--syslog")
     elif nodetype in ("client", "introducer"):
         fileutil.make_dirs(os.path.join(basedir, "logs"))
-        cmd.extend(["--logfile", os.path.join("logs", "twistd.log")])
+        args.extend(["--logfile", os.path.join("logs", "twistd.log")])
     if opts["profile"]:
-        cmd.extend(["--profile=profiling_results.prof", "--savestats",])
-    curdir = os.getcwd()
-    try:
-        os.chdir(basedir)
-        rc = os.system(' '.join(cmd))
-    finally:
-        os.chdir(curdir)
-    if rc == 0:
-        print >>out, "%s node probably started" % nodetype
-        return 0
-    else:
-        print >>err, "%s node probably not started" % nodetype
-        return 1
-
-def do_stop(basedir, out=sys.stdout, err=sys.stderr):
-    print >>out, "STOPPING", basedir
+        args.extend(["--profile=profiling_results.prof", "--savestats",])
+    # now we're committed
+    os.chdir(basedir)
+    from twisted.scripts import twistd
+    sys.argv = args
+    twistd.run()
+    # run() doesn't return: the parent does os._exit(0) in daemonize(), so
+    # we'll never get here. If application setup fails (e.g. ImportError),
+    # run() will raise an exception.
+
+def stop(config, out=sys.stdout, err=sys.stderr):
+    basedir = config['basedir']
+    print >>out, "STOPPING", quote_output(basedir)
     pidfile = os.path.join(basedir, "twistd.pid")
     if not os.path.exists(pidfile):
-        print >>err, "%s does not look like a running node directory (no twistd.pid)" % basedir
+        print >>err, "%s does not look like a running node directory (no twistd.pid)" % quote_output(basedir)
         # we define rc=2 to mean "nothing is running, but it wasn't me who
         # stopped it"
         return 2
@@ -163,31 +132,15 @@ def do_stop(basedir, out=sys.stdout, err=sys.stderr):
     # we define rc=1 to mean "I think something is still running, sorry"
     return 1
 
-def start(config, stdout, stderr):
-    rc = 0
-    for basedir in config['basedirs']:
-        rc = do_start(basedir, config, stdout, stderr) or rc
-    return rc
-
-def stop(config, stdout, stderr):
-    rc = 0
-    for basedir in config['basedirs']:
-        rc = do_stop(basedir, stdout, stderr) or rc
-    return rc
-
 def restart(config, stdout, stderr):
-    rc = 0
-    for basedir in config['basedirs']:
-        rc = do_stop(basedir, stdout, stderr) or rc
+    rc = stop(config, stdout, stderr)
     if rc == 2:
         print >>stderr, "ignoring couldn't-stop"
         rc = 0
     if rc:
         print >>stderr, "not restarting"
         return rc
-    for basedir in config['basedirs']:
-        rc = do_start(basedir, config, stdout, stderr) or rc
-    return rc
+    return start(config, stdout, stderr)
 
 def run(config, stdout, stderr):
     from twisted.internet import reactor
@@ -195,10 +148,25 @@ def run(config, stdout, stderr):
     from allmydata import client
 
     basedir = config['basedir']
-    if basedir is None:
-        basedir = '.'
+    precondition(isinstance(basedir, unicode), basedir)
+
+    if not os.path.isdir(basedir):
+        print >>stderr, "%s does not look like a directory at all" % quote_output(basedir)
+        return 1
+    for fn in listdir_unicode(basedir):
+        if fn.endswith(u".tac"):
+            tac = str(fn)
+            break
     else:
-        os.chdir(basedir)
+        print >>stderr, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
+        return 1
+    if "client" not in tac:
+        print >>stderr, ("%s looks like it contains a non-client node (%s).\n"
+                         "Use 'tahoe start' instead of 'tahoe run'."
+                         % (quote_output(basedir), tac))
+        return 1
+
+    os.chdir(basedir)
 
     # set up twisted logging. this will become part of the node rsn.
     logdir = os.path.join(basedir, 'logs')