rewrite CLI tools to use argparse, remove Twisted dependency
We used to use twisted.python.usage.Options, hence we depended upon Twisted. Now we depend upon "argparse" instead, which is in the py2.7 stdlib (and on pypi for 2.6). This package will still (eventually) provide Twisted support, but applications which need it will already express a dependency on twisted themselves, so by removing the dependency here, we make life easier for applications that don't use it.
This commit is contained in:
parent
9e7d807171
commit
8e456dea5e
2
setup.py
2
setup.py
|
@ -23,7 +23,7 @@ setup(name="wormhole-sync",
|
||||||
"wormhole.test", "wormhole.util"],
|
"wormhole.test", "wormhole.util"],
|
||||||
entry_points={"console_scripts":
|
entry_points={"console_scripts":
|
||||||
["wormhole = wormhole.scripts.runner:entry"]},
|
["wormhole = wormhole.scripts.runner:entry"]},
|
||||||
install_requires=["spake2", "pynacl", "requests", "twisted"],
|
install_requires=["spake2", "pynacl", "requests", "argparse"],
|
||||||
test_suite="wormhole.test",
|
test_suite="wormhole.test",
|
||||||
cmdclass=commands,
|
cmdclass=commands,
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,9 +6,9 @@ from .progress import start_progress, update_progress, finish_progress
|
||||||
|
|
||||||
APPID = "lothar.com/wormhole/file-xfer"
|
APPID = "lothar.com/wormhole/file-xfer"
|
||||||
|
|
||||||
def receive_file(so):
|
def receive_file(args):
|
||||||
# we're receiving
|
# we're receiving
|
||||||
transit_receiver = TransitReceiver(transit_relay=so.parent["transit-helper"])
|
transit_receiver = TransitReceiver(transit_relay=args.transit_helper)
|
||||||
|
|
||||||
mydata = json.dumps({
|
mydata = json.dumps({
|
||||||
"transit": {
|
"transit": {
|
||||||
|
@ -16,8 +16,8 @@ def receive_file(so):
|
||||||
"relay_connection_hints": transit_receiver.get_relay_hints(),
|
"relay_connection_hints": transit_receiver.get_relay_hints(),
|
||||||
},
|
},
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
r = Receiver(APPID, mydata, so.parent["relay-url"])
|
r = Receiver(APPID, mydata, args.relay_url)
|
||||||
code = so["code"]
|
code = args.code
|
||||||
if not code:
|
if not code:
|
||||||
code = r.input_code("Enter receive-file wormhole code: ")
|
code = r.input_code("Enter receive-file wormhole code: ")
|
||||||
r.set_code(code)
|
r.set_code(code)
|
||||||
|
@ -44,7 +44,7 @@ def receive_file(so):
|
||||||
print("Receiving %d bytes for '%s' (%s).." % (filesize, filename,
|
print("Receiving %d bytes for '%s' (%s).." % (filesize, filename,
|
||||||
transit_receiver.describe()))
|
transit_receiver.describe()))
|
||||||
|
|
||||||
target = so["output-file"]
|
target = args.output_file
|
||||||
if not target:
|
if not target:
|
||||||
# allow the sender to specify the filename, but only write to the
|
# allow the sender to specify the filename, but only write to the
|
||||||
# current directory, and never overwrite anything
|
# current directory, and never overwrite anything
|
||||||
|
|
|
@ -4,11 +4,11 @@ from wormhole.blocking.transcribe import Receiver, WrongPasswordError
|
||||||
|
|
||||||
APPID = "lothar.com/wormhole/text-xfer"
|
APPID = "lothar.com/wormhole/text-xfer"
|
||||||
|
|
||||||
def receive_text(so):
|
def receive_text(args):
|
||||||
# we're receiving
|
# we're receiving
|
||||||
data = json.dumps({"message": "ok"}).encode("utf-8")
|
data = json.dumps({"message": "ok"}).encode("utf-8")
|
||||||
r = Receiver(APPID, data, so.parent["relay-url"])
|
r = Receiver(APPID, data, args.relay_url)
|
||||||
code = so["code"]
|
code = args.code
|
||||||
if not code:
|
if not code:
|
||||||
code = r.input_code("Enter receive-text wormhole code: ")
|
code = r.input_code("Enter receive-text wormhole code: ")
|
||||||
r.set_code(code)
|
r.set_code(code)
|
||||||
|
|
|
@ -6,11 +6,11 @@ from .progress import start_progress, update_progress, finish_progress
|
||||||
|
|
||||||
APPID = "lothar.com/wormhole/file-xfer"
|
APPID = "lothar.com/wormhole/file-xfer"
|
||||||
|
|
||||||
def send_file(so):
|
def send_file(args):
|
||||||
# we're sending
|
# we're sending
|
||||||
filename = so["filename"]
|
filename = args.filename
|
||||||
assert os.path.isfile(filename)
|
assert os.path.isfile(filename)
|
||||||
transit_sender = TransitSender(transit_relay=so.parent["transit-helper"])
|
transit_sender = TransitSender(transit_relay=args.transit_helper)
|
||||||
|
|
||||||
filesize = os.stat(filename).st_size
|
filesize = os.stat(filename).st_size
|
||||||
data = json.dumps({
|
data = json.dumps({
|
||||||
|
@ -24,7 +24,7 @@ def send_file(so):
|
||||||
},
|
},
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
|
|
||||||
i = Initiator(APPID, data, so.parent["relay-url"])
|
i = Initiator(APPID, data, args.relay_url)
|
||||||
code = i.get_code()
|
code = i.get_code()
|
||||||
print("On the other computer, please run: wormhole receive-file")
|
print("On the other computer, please run: wormhole receive-file")
|
||||||
print("Wormhole code is '%s'" % code)
|
print("Wormhole code is '%s'" % code)
|
||||||
|
|
|
@ -4,12 +4,12 @@ from wormhole.blocking.transcribe import Initiator, WrongPasswordError
|
||||||
|
|
||||||
APPID = "lothar.com/wormhole/text-xfer"
|
APPID = "lothar.com/wormhole/text-xfer"
|
||||||
|
|
||||||
def send_text(so):
|
def send_text(args):
|
||||||
# we're sending
|
# we're sending
|
||||||
message = so["text"]
|
message = args.text
|
||||||
data = json.dumps({"message": message,
|
data = json.dumps({"message": message,
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
i = Initiator(APPID, data, so.parent["relay-url"])
|
i = Initiator(APPID, data, args.relay_url)
|
||||||
code = i.get_code()
|
code = i.get_code()
|
||||||
print("On the other computer, please run: wormhole receive-text")
|
print("On the other computer, please run: wormhole receive-text")
|
||||||
print("Wormhole code is: %s" % code)
|
print("Wormhole code is: %s" % code)
|
||||||
|
|
|
@ -1,93 +1,69 @@
|
||||||
import sys
|
import sys, argparse
|
||||||
from twisted.python import usage
|
from textwrap import dedent
|
||||||
from .. import public_relay
|
from .. import public_relay
|
||||||
|
from .. import __version__
|
||||||
|
from . import cmd_send_text, cmd_receive_text, cmd_send_file, cmd_receive_file
|
||||||
|
|
||||||
class SendTextOptions(usage.Options):
|
parser = argparse.ArgumentParser(
|
||||||
def parseArgs(self, text):
|
usage="wormhole SUBCOMMAND (subcommand-options)",
|
||||||
self["text"] = text
|
description=dedent("""
|
||||||
synopsis = "TEXT"
|
Create a Magic Wormhole and communicate through it. Wormholes are created
|
||||||
|
by speaking the same magic CODE in two different places at the same time.
|
||||||
|
Wormholes are secure against anyone who doesn't use the same code."""),
|
||||||
|
)
|
||||||
|
parser.add_argument("--version", action="version",
|
||||||
|
version="magic-wormhole "+ __version__)
|
||||||
|
g = parser.add_argument_group("wormhole configuration options")
|
||||||
|
g.add_argument("--relay-url", default=public_relay.RENDEZVOUS_RELAY,
|
||||||
|
metavar="URL", help="rendezvous relay to use")
|
||||||
|
g.add_argument("--transit-helper", default=public_relay.TRANSIT_RELAY,
|
||||||
|
metavar="tcp:HOST:PORT", help="transit relay to use")
|
||||||
|
subparsers = parser.add_subparsers(title="subcommands",
|
||||||
|
dest="subcommand")
|
||||||
|
|
||||||
class ReceiveTextOptions(usage.Options):
|
|
||||||
def parseArgs(self, code=None):
|
|
||||||
self["code"] = code
|
|
||||||
synopsis = "[CODE]"
|
|
||||||
|
|
||||||
class SendFileOptions(usage.Options):
|
p = subparsers.add_parser("send-text", description="Send a text mesasge",
|
||||||
def parseArgs(self, filename):
|
usage="wormhole send-text TEXT")
|
||||||
self["filename"] = filename
|
p.add_argument("text", metavar="TEXT", help="the message to send (a string)")
|
||||||
synopsis = "FILENAME"
|
p.set_defaults(func=cmd_send_text.send_text)
|
||||||
|
|
||||||
class ReceiveFileOptions(usage.Options):
|
p = subparsers.add_parser("receive-text", description="Receive a text message",
|
||||||
optParameters = [
|
usage="wormhole receive-text [CODE]")
|
||||||
["output-file", "o", None, "File to create"],
|
p.add_argument("code", nargs="?", default=None, metavar="[CODE]",
|
||||||
]
|
help=dedent("""\
|
||||||
def parseArgs(self, code=None):
|
The magic-wormhole code, from the sender. If omitted, the
|
||||||
self["code"] = code
|
program will ask for it, using tab-completion."""),
|
||||||
synopsis = "[CODE]"
|
)
|
||||||
|
p.set_defaults(func=cmd_receive_text.receive_text)
|
||||||
|
|
||||||
class Options(usage.Options):
|
p = subparsers.add_parser("send-file", description="Send a file",
|
||||||
synopsis = "\nUsage: wormhole <command>"
|
usage="wormhole send-file FILENAME")
|
||||||
optParameters = [
|
p.add_argument("filename", metavar="FILENAME", help="The file to be sent")
|
||||||
["relay-url", None, public_relay.RENDEZVOUS_RELAY,
|
p.set_defaults(func=cmd_send_file.send_file)
|
||||||
"rendezvous relay to use (URL)"],
|
|
||||||
["transit-helper", None, public_relay.TRANSIT_RELAY,
|
|
||||||
"transit relay to use (tcp:HOST:PORT)"],
|
|
||||||
]
|
|
||||||
subCommands = [("send-text", None, SendTextOptions, "Send a text message"),
|
|
||||||
("send-file", None, SendFileOptions, "Send a file"),
|
|
||||||
("receive-text", None, ReceiveTextOptions, "Receive a text message"),
|
|
||||||
("receive-file", None, ReceiveFileOptions, "Receive a file"),
|
|
||||||
]
|
|
||||||
|
|
||||||
def getUsage(self, **kwargs):
|
p = subparsers.add_parser("receive-file", description="Receive a file",
|
||||||
t = usage.Options.getUsage(self, **kwargs)
|
usage="wormhole receive-file [-o FILENAME] [CODE]")
|
||||||
return t + "\nPlease run 'wormhole <command> --help' for more details on each command.\n"
|
p.add_argument("-o", "--output-file", default=None, metavar="FILENAME",
|
||||||
|
help=dedent("""\
|
||||||
|
The file to create, overriding the filename suggested by the
|
||||||
|
sender"""),
|
||||||
|
)
|
||||||
|
p.add_argument("code", nargs="?", default=None, metavar="[CODE]",
|
||||||
|
help=dedent("""\
|
||||||
|
The magic-wormhole code, from the sender. If omitted, the
|
||||||
|
program will ask for it, using tab-completion."""),
|
||||||
|
)
|
||||||
|
p.set_defaults(func=cmd_receive_file.receive_file)
|
||||||
|
|
||||||
def postOptions(self):
|
|
||||||
if not hasattr(self, 'subOptions'):
|
|
||||||
raise usage.UsageError("must specify a command")
|
|
||||||
|
|
||||||
def send_text(*args):
|
|
||||||
from . import cmd_send_text
|
|
||||||
return cmd_send_text.send_text(*args)
|
|
||||||
|
|
||||||
def receive_text(*args):
|
|
||||||
from . import cmd_receive_text
|
|
||||||
return cmd_receive_text.receive_text(*args)
|
|
||||||
|
|
||||||
def send_file(*args):
|
|
||||||
from . import cmd_send_file
|
|
||||||
return cmd_send_file.send_file(*args)
|
|
||||||
|
|
||||||
def receive_file(*args):
|
|
||||||
from . import cmd_receive_file
|
|
||||||
return cmd_receive_file.receive_file(*args)
|
|
||||||
|
|
||||||
DISPATCH = {"send-text": send_text,
|
|
||||||
"receive-text": receive_text,
|
|
||||||
"send-file": send_file,
|
|
||||||
"receive-file": receive_file,
|
|
||||||
}
|
|
||||||
|
|
||||||
def run(args, stdout, stderr, executable=None):
|
def run(args, stdout, stderr, executable=None):
|
||||||
"""This is invoked directly by the 'wormhole' entry-point script. It can
|
"""This is invoked directly by the 'wormhole' entry-point script. It can
|
||||||
also invoked by entry() below."""
|
also invoked by entry() below."""
|
||||||
config = Options()
|
|
||||||
|
args = parser.parse_args()
|
||||||
try:
|
try:
|
||||||
config.parseOptions(args)
|
#rc = command.func(args, stdout, stderr)
|
||||||
except usage.error, e:
|
rc = args.func(args)
|
||||||
c = config
|
|
||||||
while hasattr(c, 'subOptions'):
|
|
||||||
c = c.subOptions
|
|
||||||
print >>stderr, str(c)
|
|
||||||
print >>stderr, e.args[0]
|
|
||||||
return 1
|
|
||||||
command = config.subCommand
|
|
||||||
so = config.subOptions
|
|
||||||
so["executable"] = executable
|
|
||||||
try:
|
|
||||||
#rc = DISPATCH[command](so, stdout, stderr)
|
|
||||||
rc = DISPATCH[command](so)
|
|
||||||
return rc
|
return rc
|
||||||
except ImportError, e:
|
except ImportError, e:
|
||||||
print >>stderr, "--- ImportError ---"
|
print >>stderr, "--- ImportError ---"
|
||||||
|
@ -100,3 +76,7 @@ def entry():
|
||||||
"""This is used by a setuptools entry_point. When invoked this way,
|
"""This is used by a setuptools entry_point. When invoked this way,
|
||||||
setuptools has already put the installed package on sys.path ."""
|
setuptools has already put the installed package on sys.path ."""
|
||||||
return run(sys.argv[1:], sys.stdout, sys.stderr, executable=sys.argv[0])
|
return run(sys.argv[1:], sys.stdout, sys.stderr, executable=sys.argv[0])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = parser.parse_args()
|
||||||
|
print args
|
||||||
|
|
Loading…
Reference in New Issue
Block a user