Exemplo n.º 1
0
class ClientOptions(options.ConchOptions):

    synopsis = """Usage:   cftp [options] [user@]host
         cftp [options] [user@]host[:dir[/]]
         cftp [options] [user@]host[:file [localfile]]
"""
    longdesc = ("cftp is a client for logging into a remote machine and "
                "executing commands to send and receive file information")

    optParameters = [
                    ['buffersize', 'B', 32768, 'Size of the buffer to use for sending/receiving.'],
                    ['batchfile', 'b', None, 'File to read commands from, or \'-\' for stdin.'],
                    ['requests', 'R', 5, 'Number of requests to make before waiting for a reply.'],
                    ['subsystem', 's', 'sftp', 'Subsystem/server program to connect to.']]

    compData = usage.Completions(
        descriptions={
            "buffersize": "Size of send/receive buffer (default: 32768)"},
        extraActions=[usage.CompleteUserAtHost(),
                      usage.CompleteFiles(descr="local file")])

    def parseArgs(self, host, localPath=None):
        self['remotePath'] = ''
        if ':' in host:
            host, self['remotePath'] = host.split(':', 1)
            self['remotePath'].rstrip('/')
        self['host'] = host
        self['localPath'] = localPath
Exemplo n.º 2
0
class ClientOptions(options.ConchOptions):

    synopsis = """Usage:   cftp [options] [user@]host
         cftp [options] [user@]host[:dir[/]]
         cftp [options] [user@]host[:file [localfile]]
"""
    longdesc = (
        "cftp is a client for logging into a remote machine and "
        "executing commands to send and receive file information"
    )

    optParameters: List[List[Optional[Union[str, int]]]] = [
        ["buffersize", "B", 32768, "Size of the buffer to use for sending/receiving."],
        ["batchfile", "b", None, "File to read commands from, or '-' for stdin."],
        ["requests", "R", 5, "Number of requests to make before waiting for a reply."],
        ["subsystem", "s", "sftp", "Subsystem/server program to connect to."],
    ]

    compData = usage.Completions(
        descriptions={"buffersize": "Size of send/receive buffer (default: 32768)"},
        extraActions=[
            usage.CompleteUserAtHost(),
            usage.CompleteFiles(descr="local file"),
        ],
    )

    def parseArgs(self, host, localPath=None):
        self["remotePath"] = ""
        if ":" in host:
            host, self["remotePath"] = host.split(":", 1)
            self["remotePath"].rstrip("/")
        self["host"] = host
        self["localPath"] = localPath
Exemplo n.º 3
0
class Options(usage.Options):
    synopsis = "[loki options]"
    optParameters = [[
        "proxy", "p", None, "strports description of the port to "
        "start the proxy server on."
    ],
                     [
                         "ui", "u", None,
                         "strports description of the port to ",
                         "start the administrative ui server on."
                     ], ["tricks", "t", None, "path to YAML tricks file."]]

    compData = usage.Completions(
        optActions={"config": usage.CompleteFiles("*.yml")})

    def postOptions(self):
        if self['proxy'] is None:
            self['proxy'] = 'tcp:8080'

        if self['ui'] is None:
            self['ui'] = 'tcp:8181'

        if self['tricks'] is not None:
            (self['requestTricks'],
             self['responseTricks']) = load_tricks(file(self['tricks'], 'r'))
Exemplo n.º 4
0
class MyOptions(usage.Options):
    optFlags = [["unsigned", "u"]]
    optParameters = [
        ["tapfile", "t", "twistd.tap"],
        [
            "maintainer", "m", "",
            "The maintainer's name and email in a specific format: "
            "'John Doe <*****@*****.**>'"
        ], ["protocol", "p", ""], ["description", "e", ""],
        ["long_description", "l", ""], ["set-version", "V", "1.0"],
        ["debfile", "d", None],
        [
            "type", "y", "tap", "Type of configuration: 'tap', 'xml', "
            "'source' or 'python' for .tac files"
        ]
    ]

    compData = usage.Completions(
        optActions={
            "type": usage.CompleteList(["tap", "xml", "source", "python"]),
            "debfile": usage.CompleteFiles("*.deb")
        })

    def postOptions(self):
        if not self["maintainer"]:
            raise usage.UsageError("maintainer must be specified.")
Exemplo n.º 5
0
    def test_files(self):
        """
        CompleteFiles produces zsh shell-code that completes file names
        according to a glob.
        """
        c = usage.CompleteFiles()
        got = c._shellCode('some-option', usage._ZSH)
        self.assertEqual(got, ':some-option (*):_files -g "*"')

        c = usage.CompleteFiles('*.py')
        got = c._shellCode('some-option', usage._ZSH)
        self.assertEqual(got, ':some-option (*.py):_files -g "*.py"')

        c = usage.CompleteFiles('*.py', descr="some action", repeat=True)
        got = c._shellCode('some-option', usage._ZSH)
        self.assertEqual(got, '*:some action (*.py):_files -g "*.py"')
Exemplo n.º 6
0
class ServerOptions(app.ServerOptions):
    synopsis = "Usage: twistd [options]"

    optFlags = [
        ["nodaemon", "n", "don't daemonize, don't use default umask of 0077"],
        ["originalname", None, "Don't try to change the process name"],
        ["syslog", None, "Log to syslog, not to file"],
        [
            "euid",
            "",
            "Set only effective user-id rather than real user-id. "
            "(This option has no effect unless the server is running as "
            "root, in which case it means not to shed all privileges "
            "after binding ports, retaining the option to regain "
            "privileges in cases such as spawning processes. "
            "Use with caution.)",
        ],
    ]

    optParameters = [
        ["prefix", None, "twisted", "use the given prefix when syslogging"],
        ["pidfile", "", "twistd.pid", "Name of the pidfile"],
        ["chroot", None, None, "Chroot to a supplied directory before running"],
        ["uid", "u", None, "The uid to run as.", uidFromString],
        [
            "gid",
            "g",
            None,
            "The gid to run as.  If not specified, the default gid "
            "associated with the specified --uid is used.",
            gidFromString,
        ],
        ["umask", None, None, "The (octal) file creation mask to apply.", _umask],
    ]

    compData = usage.Completions(
        optActions={
            "pidfile": usage.CompleteFiles("*.pid"),
            "chroot": usage.CompleteDirs(descr="chroot directory"),
            "gid": usage.CompleteGroups(descr="gid to run as"),
            "uid": usage.CompleteUsernames(descr="uid to run as"),
            "prefix": usage.Completer(descr="syslog prefix"),
        },
    )

    def opt_version(self):
        """
        Print version information and exit.
        """
        print(
            "twistd (the Twisted daemon) {}".format(copyright.version), file=self.stdout
        )
        print(copyright.copyright, file=self.stdout)
        sys.exit()

    def postOptions(self):
        app.ServerOptions.postOptions(self)
        if self["pidfile"]:
            self["pidfile"] = os.path.abspath(self["pidfile"])
Exemplo n.º 7
0
class Options(usage.Options):
    synopsis = """%s [options] [path to test].py
    """ % (os.path.basename(sys.argv[0]), )

    longdesc = ("ooniprobe loads and executes a suite or a set of suites of"
                " network tests. These are loaded from modules, packages and"
                " files listed on the command line")

    optFlags = [["help", "h"], ["resume", "r"], ["no-collector", "n"]]

    optParameters = [
        ["reportfile", "o", None, "report file name"],
        [
            "testdeck", "i", None,
            "Specify as input a test deck: a yaml file containig the tests to run an their arguments"
        ],
        [
            "collector", "c", 'httpo://nkvphnp3p6agi5qq.onion',
            "Address of the collector of test results. default: httpo://nkvphnp3p6agi5qq.onion"
        ],
        ["logfile", "l", None, "log file name"],
        ["pcapfile", "O", None, "pcap file name"],
        ["parallelism", "p", "10", "input parallelism"],
    ]

    compData = usage.Completions(extraActions=[
        usage.CompleteFiles(
            "*.py",
            descr="file | module | package | TestCase | testMethod",
            repeat=True)
    ], )

    tracer = None

    def __init__(self):
        self['test'] = None
        usage.Options.__init__(self)

    def opt_asciilulz(self):
        from ooni.utils import logo
        print logo.getlogo()

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.  Useful
        when debugging freezes or locks in complex code.
        """
        sys.settrace(spewer)

    def parseArgs(self, *args):
        if self['testdeck']:
            return
        try:
            self['test_file'] = args[0]
            self['subargs'] = args[1:]
        except:
            raise usage.UsageError("No test filename specified!")
Exemplo n.º 8
0
class ServerOptions(app.ServerOptions):
    synopsis = "Usage: twistd [options]"

    optFlags = [
        ['nodaemon', 'n', "don't daemonize, don't use default umask of 0077"],
        ['originalname', None, "Don't try to change the process name"],
        ['syslog', None, "Log to syslog, not to file"],
        [
            'euid', '', "Set only effective user-id rather than real user-id. "
            "(This option has no effect unless the server is running as "
            "root, in which case it means not to shed all privileges "
            "after binding ports, retaining the option to regain "
            "privileges in cases such as spawning processes. "
            "Use with caution.)"
        ],
    ]

    optParameters = [
        ['prefix', None, 'twisted', "use the given prefix when syslogging"],
        ['pidfile', '', 'twistd.pid', "Name of the pidfile"],
        [
            'chroot', None, None,
            'Chroot to a supplied directory before running'
        ],
        ['uid', 'u', None, "The uid to run as.", uidFromString],
        ['gid', 'g', None, "The gid to run as.", gidFromString],
        [
            'umask', None, None, "The (octal) file creation mask to apply.",
            _umask
        ],
    ]

    compData = usage.Completions(optActions={
        "pidfile":
        usage.CompleteFiles("*.pid"),
        "chroot":
        usage.CompleteDirs(descr="chroot directory"),
        "gid":
        usage.CompleteGroups(descr="gid to run as"),
        "uid":
        usage.CompleteUsernames(descr="uid to run as"),
        "prefix":
        usage.Completer(descr="syslog prefix"),
    }, )

    def opt_version(self):
        """Print version information and exit.
        """
        print 'twistd (the Twisted daemon) %s' % copyright.version
        print copyright.copyright
        sys.exit()

    def postOptions(self):
        app.ServerOptions.postOptions(self)
        if self['pidfile']:
            self['pidfile'] = os.path.abspath(self['pidfile'])
Exemplo n.º 9
0
class Options(usage.Options, app.ReactorSelectionMixin):
    synopsis = """%s [options] [path to test].py
    """ % (os.path.basename(sys.argv[0]), )

    longdesc = ("ooniprobe loads and executes a suite or a set of suites of"
                " network tests. These are loaded from modules, packages and"
                " files listed on the command line")

    optFlags = [
        ["help", "h"],
        [
            'debug-stacktraces', 'B',
            'Report deferred creation and callback stack traces'
        ],
    ]

    optParameters = [
        ["reportfile", "o", None, "report file name"],
        [
            "collector", "c", None,
            "Address of the collector of test results. (example: http://127.0.0.1:8888)"
        ], ["logfile", "l", None, "log file name"],
        ["pcapfile", "p", None, "pcap file name"]
    ]

    compData = usage.Completions(extraActions=[
        usage.CompleteFiles(
            "*.py",
            descr="file | module | package | TestCase | testMethod",
            repeat=True)
    ], )

    tracer = None

    def __init__(self):
        self['test'] = None
        usage.Options.__init__(self)

    def opt_asciilulz(self):
        from ooni.utils import logo
        print logo.getlogo()

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.  Useful
        when debugging freezes or locks in complex code.
        """
        sys.settrace(spewer)

    def parseArgs(self, *args):
        try:
            self['test'] = args[0]
            self['subArgs'] = args[1:]
        except:
            raise usage.UsageError("No test filename specified!")
Exemplo n.º 10
0
class ConvertOptions(usage.Options):
    synopsis = "Usage: tapconvert [options]"
    optParameters = [
        ['in', 'i', None, "The filename of the tap to read from"],
        ['out', 'o', None, "A filename to write the tap to"],
        [
            'typein', 'f', 'guess',
            "The  format to use; this can be 'guess', 'python', "
            "'pickle', 'xml', or 'source'."
        ],
        [
            'typeout', 't', 'source',
            "The output format to use; this can be 'pickle', 'xml', or 'source'."
        ],
    ]

    optFlags = [[
        'decrypt', 'd', "The specified tap/aos/xml file is encrypted."
    ], ['encrypt', 'e', "Encrypt file before writing"]]

    compData = usage.Completions(
        optActions={
            "typein":
            usage.CompleteList(["guess", "python", "pickle", "xml", "source"]),
            "typeout":
            usage.CompleteList(["pickle", "xml", "source"]),
            "in":
            usage.CompleteFiles(descr="tap file to read from"),
            "out":
            usage.CompleteFiles(descr="tap file to write to"),
        })

    def postOptions(self):
        if self['in'] is None:
            raise usage.UsageError("%s\nYou must specify the input filename." %
                                   self)
        if self["typein"] == "guess":
            try:
                self["typein"] = sob.guessType(self["in"])
            except KeyError:
                raise usage.UsageError("Could not guess type for '%s'" %
                                       self["typein"])
Exemplo n.º 11
0
class Options(usage.Options):

    optParameters = [['rpc', 'r', '/etc/rpc', 'RPC procedure table file'],
                     [
                         'file', 'f', '/etc/inetd.conf',
                         'Service configuration file'
                     ]]

    optFlags = [['nointernal', 'i', "Don't run internal services"]]

    compData = usage.Completions(
        optActions={"file": usage.CompleteFiles('*.conf')})
Exemplo n.º 12
0
class Options(usage.Options):
    synopsis = "[-i <interface>] [-p <port>] [-l <file>]"
    optParameters = [["interface", "i", "127.0.0.1", "local interface to which we listen"],
                  ["port", "p", 1080, "Port on which to listen"],
                  ["log", "l", None, "file to log connection data to"]]

    compData = usage.Completions(
        optActions={"log": usage.CompleteFiles("*.log"),
                    "interface": usage.CompleteNetInterfaces()}
        )

    longdesc = "Makes a SOCKSv4 server."
Exemplo n.º 13
0
class Options(usage.Options):
    synopsis = """{} [options] source.py
    """.format(os.path.basename(sys.argv[0]), )

    optParameters = [
        ("stylesheet", "s", None, "URL of stylesheet to link to."),
    ]

    compData = usage.Completions(
        extraActions=[usage.CompleteFiles("*.py", descr="source python file")])

    def parseArgs(self, filename):
        self["filename"] = filename
Exemplo n.º 14
0
class Options(usage.Options):
    synopsis = """%s [options] source.py
    """ % (os.path.basename(sys.argv[0]), )

    optParameters = [
        ('stylesheet', 's', None, "URL of stylesheet to link to."),
    ]

    compData = usage.Completions(
        extraActions=[usage.CompleteFiles('*.py', descr='source python file')])

    def parseArgs(self, filename):
        self['filename'] = filename
Exemplo n.º 15
0
class MyOptions(usage.Options):
    optFlags = [['quiet', 'q']]
    optParameters = [
                     ["tapfile", "t", "twistd.tap"],
                     ["maintainer", "m", "tap2rpm"],
                     ["protocol", "p", None],
                     ["description", "e", None],
                     ["long_description", "l",
                         "Automatically created by tap2rpm"],
                     ["set-version", "V", "1.0"],
                     ["rpmfile", "r", None],
                     ["type", "y", "tap", "type of configuration: 'tap', 'xml, "
                      "'source' or 'python'"],
                    ]

    compData = usage.Completions(
        optActions={"type": usage.CompleteList(["tap", "xml", "source",
                                                "python"]),
                    "rpmfile": usage.CompleteFiles("*.rpm")}
        )

    def postOptions(self):
        """
        Calculate the default values for certain command-line options.
        """
        # Options whose defaults depend on other parameters.
        if self['protocol'] is None:
            base_tapfile = os.path.basename(self['tapfile'])
            self['protocol'] = os.path.splitext(base_tapfile)[0]
        if self['description'] is None:
            self['description'] = "A TCP server for %s" % (self['protocol'],)
        if self['rpmfile'] is None:
            self['rpmfile'] = 'twisted-%s' % (self['protocol'],)

        # Values that aren't options, but are calculated from options and are
        # handy to have around.
        self['twistd_option'] = type_dict[self['type']]
        self['release-name'] = '%s-%s' % (self['rpmfile'], self['set-version'])


    def opt_unsigned(self):
        """
        Generate an unsigned rather than a signed RPM. (DEPRECATED; unsigned
        is the default)
        """
        msg = deprecate.getDeprecationWarningString(
            self.opt_unsigned, versions.Version("Twisted", 12, 1, 0))
        warnings.warn(msg, category=DeprecationWarning, stacklevel=2)

    # Maintain the -u short flag
    opt_u = opt_unsigned
Exemplo n.º 16
0
class Options(usage.Options):

    longdesc = "lore converts documentation formats."

    optFlags = [
        ["plain", 'p', "Report filenames without progress bar"],
        ["null", 'n', "Do not report filenames"],
        ["number", 'N', "Add chapter/section numbers to section headings"],
    ]

    optParameters = [
        ["input", "i", 'lore'],
        [
            "inputext", "e", ".xhtml",
            "The extension that your Lore input files have"
        ],
        ["docsdir", "d", None],
        ["linkrel", "l", ''],
        ["output", "o", 'html'],
        [
            "index", "x", None,
            "The base filename you want to give your index file"
        ],
        ["book", "b", None, "The book file to generate a book from"],
        [
            "prefixurl", None, "",
            "The prefix to stick on to relative links; only useful when processing directories"
        ],
    ]

    compData = usage.Completions(
        extraActions=[usage.CompleteFiles(descr="files", repeat=True)])

    def __init__(self, *args, **kw):
        usage.Options.__init__(self, *args, **kw)
        self.config = {}

    def opt_config(self, s):
        if '=' in s:
            k, v = s.split('=', 1)
            self.config[k] = v
        else:
            self.config[s] = 1

    def parseArgs(self, *files):
        self['files'] = files
Exemplo n.º 17
0
class CheckConfigOptions(base.SubcommandOptions):
    subcommandFunction = "buildbot.scripts.checkconfig.checkconfig"
    optFlags = [
        ['quiet', 'q', "Don't display error messages or tracebacks"],
    ]

    # on tab completion, suggest files as first argument
    if hasattr(usage, 'Completions'):
        # only set completion suggestion if running with
        # twisted version (>=11.1.0) that supports it
        compData = usage.Completions(extraActions=[usage.CompleteFiles()])

    def getSynopsis(self):
        return "Usage:\t\tbuildbot checkconfig [configFile]\n" + \
            "\t\tIf not specified, the config file specified in " + \
            "'buildbot.tac' from the current directory will be used"

    def parseArgs(self, *args):
        if len(args) >= 1:
            self['configFile'] = args[0]
Exemplo n.º 18
0
class Options(usage.Options):
    """
    To use it, create a file named `sample-inetd.conf` with:

    8123 stream tcp wait some_user /bin/cat -

    You can then run it as in the following example and port 8123 became an
    echo server.

    twistd -n inetd -f sample-inetd.conf
    """

    optParameters = [[
        'rpc', 'r', '/etc/rpc', 'DEPRECATED. RPC procedure table file'
    ], ['file', 'f', '/etc/inetd.conf', 'Service configuration file']]

    optFlags = [['nointernal', 'i', "Don't run internal services"]]

    compData = usage.Completions(
        optActions={"file": usage.CompleteFiles('*.conf')})
Exemplo n.º 19
0
class Options(usage.Options):
    """
    To use it, create a file named `sample-inetd.conf` with:

    8123 stream tcp wait some_user /bin/cat -

    You can then run it as in the following example and port 8123 became an
    echo server.

    twistd -n inetd -f sample-inetd.conf
    """

    optParameters = [
        ["rpc", "r", "/etc/rpc", "DEPRECATED. RPC procedure table file"],
        ["file", "f", "/etc/inetd.conf", "Service configuration file"],
    ]

    optFlags = [["nointernal", "i", "Don't run internal services"]]

    compData = usage.Completions(optActions={"file": usage.CompleteFiles("*.conf")})
Exemplo n.º 20
0
class MyOptions(usage.Options):
    optFlags = [["unsigned", "u"], ['quiet', 'q']]
    optParameters = [
        ["tapfile", "t", "twistd.tap"],
        ["maintainer", "m", "tap2rpm"],
        ["protocol", "p", None],
        ["description", "e", None],
        ["long_description", "l", "Automatically created by tap2rpm"],
        ["set-version", "V", "1.0"],
        ["rpmfile", "r", None],
        [
            "type", "y", "tap", "type of configuration: 'tap', 'xml, "
            "'source' or 'python'"
        ],
    ]

    compData = usage.Completions(
        optActions={
            "type": usage.CompleteList(["tap", "xml", "source", "python"]),
            "rpmfile": usage.CompleteFiles("*.rpm")
        })

    def postOptions(self):
        """
        Calculate the default values for certain command-line options.
        """
        # Options whose defaults depend on other parameters.
        if self['protocol'] is None:
            base_tapfile = os.path.basename(self['tapfile'])
            self['protocol'] = os.path.splitext(base_tapfile)[0]
        if self['description'] is None:
            self['description'] = "A TCP server for %s" % (self['protocol'], )
        if self['rpmfile'] is None:
            self['rpmfile'] = 'twisted-%s' % (self['protocol'], )

        # Values that aren't options, but are calculated from options and are
        # handy to have around.
        self['twistd_option'] = type_dict[self['type']]
        self['release-name'] = '%s-%s' % (self['rpmfile'], self['set-version'])
Exemplo n.º 21
0
class Options(usage.Options, app.ReactorSelectionMixin):
    synopsis = """%s [options] [[file|package|module|TestCase|testmethod]...]
    """ % (os.path.basename(sys.argv[0]), )

    longdesc = ("trial loads and executes a suite of unit tests, obtained "
                "from modules, packages and files listed on the command line.")

    optFlags = [
        ["help", "h"],
        [
            "rterrors", "e", "realtime errors, print out tracebacks as "
            "soon as they occur"
        ],
        [
            "debug", "b", "Run tests in the Python debugger. Will load "
            "'.pdbrc' from current directory if it exists."
        ],
        [
            "debug-stacktraces", "B", "Report Deferred creation and "
            "callback stack traces"
        ],
        [
            "nopm", None, "don't automatically jump into debugger for "
            "postmorteming of exceptions"
        ], ["dry-run", 'n', "do everything but run the tests"],
        [
            "force-gc", None, "Have Trial run gc.collect() before and "
            "after each test case."
        ], ["profile", None, "Run tests under the Python profiler"],
        ["unclean-warnings", None, "Turn dirty reactor errors into warnings"],
        ["until-failure", "u", "Repeat test until it fails"],
        ["no-recurse", "N", "Don't recurse into packages"],
        [
            'help-reporters', None,
            "Help on available output plugins (reporters)"
        ]
    ]

    optParameters = [
        ["logfile", "l", "test.log", "log file name"],
        [
            "random", "z", None,
            "Run tests in random order using the specified seed"
        ],
        [
            'temp-directory', None, '_trial_temp',
            'Path to use as working directory for tests.'
        ],
        [
            'reporter', None, 'verbose',
            'The reporter to use for this test run.  See --help-reporters for '
            'more info.'
        ]
    ]

    compData = usage.Completions(
        optActions={
            "tbformat": usage.CompleteList(["plain", "emacs", "cgitb"]),
            "reporter": _reporterAction,
            "logfile": usage.CompleteFiles(descr="log file name"),
            "random": usage.Completer(descr="random seed")
        },
        extraActions=[
            usage.CompleteFiles(
                "*.py",
                descr="file | module | package | TestCase | testMethod",
                repeat=True)
        ],
    )

    fallbackReporter = reporter.TreeReporter
    extra = None
    tracer = None

    def __init__(self):
        self['tests'] = set()
        usage.Options.__init__(self)

    def coverdir(self):
        """
        Return a L{FilePath} representing the directory into which coverage
        results should be written.
        """
        coverdir = 'coverage'
        result = FilePath(self['temp-directory']).child(coverdir)
        print "Setting coverage directory to %s." % (result.path, )
        return result

    def opt_coverage(self):
        """
        Generate coverage information in the I{coverage} file in the
        directory specified by the I{trial-temp} option.
        """
        import trace
        self.tracer = trace.Trace(count=1, trace=0)
        sys.settrace(self.tracer.globaltrace)

    def opt_testmodule(self, filename):
        """
        Filename to grep for test cases (-*- test-case-name)
        """
        # If the filename passed to this parameter looks like a test module
        # we just add that to the test suite.
        #
        # If not, we inspect it for an Emacs buffer local variable called
        # 'test-case-name'.  If that variable is declared, we try to add its
        # value to the test suite as a module.
        #
        # This parameter allows automated processes (like Buildbot) to pass
        # a list of files to Trial with the general expectation of "these files,
        # whatever they are, will get tested"
        if not os.path.isfile(filename):
            sys.stderr.write("File %r doesn't exist\n" % (filename, ))
            return
        filename = os.path.abspath(filename)
        if isTestFile(filename):
            self['tests'].add(filename)
        else:
            self['tests'].update(getTestModules(filename))

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.  Useful
        when debugging freezes or locks in complex code.
        """
        sys.settrace(spewer)

    def opt_help_reporters(self):
        synopsis = ("Trial's output can be customized using plugins called "
                    "Reporters. You can\nselect any of the following "
                    "reporters using --reporter=<foo>\n")
        print synopsis
        for p in plugin.getPlugins(itrial.IReporter):
            print '   ', p.longOpt, '\t', p.description
        print
        sys.exit(0)

    def opt_disablegc(self):
        """
        Disable the garbage collector
        """
        gc.disable()

    def opt_tbformat(self, opt):
        """
        Specify the format to display tracebacks with. Valid formats are
        'plain', 'emacs', and 'cgitb' which uses the nicely verbose stdlib
        cgitb.text function
        """
        try:
            self['tbformat'] = TBFORMAT_MAP[opt]
        except KeyError:
            raise usage.UsageError(
                "tbformat must be 'plain', 'emacs', or 'cgitb'.")

    def opt_extra(self, arg):
        """
        Add an extra argument.  (This is a hack necessary for interfacing with
        emacs's `gud'.)  NOTE: This option is deprecated as of Twisted 11.0
        """
        warnings.warn(deprecate.getDeprecationWarningString(
            Options.opt_extra, versions.Version('Twisted', 11, 0, 0)),
                      category=DeprecationWarning,
                      stacklevel=2)

        if self.extra is None:
            self.extra = []
        self.extra.append(arg)

    opt_x = opt_extra

    def opt_recursionlimit(self, arg):
        """
        see sys.setrecursionlimit()
        """
        try:
            sys.setrecursionlimit(int(arg))
        except (TypeError, ValueError):
            raise usage.UsageError(
                "argument to recursionlimit must be an integer")

    def opt_random(self, option):
        try:
            self['random'] = long(option)
        except ValueError:
            raise usage.UsageError(
                "Argument to --random must be a positive integer")
        else:
            if self['random'] < 0:
                raise usage.UsageError(
                    "Argument to --random must be a positive integer")
            elif self['random'] == 0:
                self['random'] = long(time.time() * 100)

    def opt_without_module(self, option):
        """
        Fake the lack of the specified modules, separated with commas.
        """
        for module in option.split(","):
            if module in sys.modules:
                warnings.warn("Module '%s' already imported, "
                              "disabling anyway." % (module, ),
                              category=RuntimeWarning)
            sys.modules[module] = None

    def parseArgs(self, *args):
        self['tests'].update(args)
        if self.extra is not None:
            self['tests'].update(self.extra)

    def _loadReporterByName(self, name):
        for p in plugin.getPlugins(itrial.IReporter):
            qual = "%s.%s" % (p.module, p.klass)
            if p.longOpt == name:
                return reflect.namedAny(qual)
        raise usage.UsageError("Only pass names of Reporter plugins to "
                               "--reporter. See --help-reporters for "
                               "more info.")

    def postOptions(self):
        # Only load reporters now, as opposed to any earlier, to avoid letting
        # application-defined plugins muck up reactor selecting by importing
        # t.i.reactor and causing the default to be installed.
        self['reporter'] = self._loadReporterByName(self['reporter'])

        if 'tbformat' not in self:
            self['tbformat'] = 'default'
        if self['nopm']:
            if not self['debug']:
                raise usage.UsageError("you must specify --debug when using "
                                       "--nopm ")
            failure.DO_POST_MORTEM = False
Exemplo n.º 22
0
class Options(usage.Options):
    """
    Define the options accepted by the I{twistd web} plugin.
    """
    synopsis = "[web options]"

    optParameters = [
        [
            "port", "p", None, "strports description of the port to "
            "start the server on."
        ],
        [
            "logfile", "l", None,
            "Path to web CLF (Combined Log Format) log file."
        ],
        ["https", None, None, "Port to listen on for Secure HTTP."],
        [
            "certificate", "c", "server.pem",
            "SSL certificate to use for HTTPS. "
        ],
        ["privkey", "k", "server.pem", "SSL certificate to use for HTTPS."],
    ]

    optFlags = [
        [
            "personal", "",
            "Instead of generating a webserver, generate a "
            "ResourcePublisher which listens on  the port given by "
            "--port, or ~/%s " % (distrib.UserDirectory.userSocketName, ) +
            "if --port is not specified."
        ],
        [
            "notracebacks", "n",
            "Do not display tracebacks in broken web pages. " +
            "Displaying tracebacks to users may be security risk!"
        ],
    ]

    compData = usage.Completions(
        optActions={
            "logfile": usage.CompleteFiles("*.log"),
            "certificate": usage.CompleteFiles("*.pem"),
            "privkey": usage.CompleteFiles("*.pem")
        })

    longdesc = """\
This starts a webserver.  If you specify no arguments, it will be a
demo webserver that has the Test class from twisted.web.demo in it."""

    def __init__(self):
        usage.Options.__init__(self)
        self['indexes'] = []
        self['root'] = None

    def opt_index(self, indexName):
        """
        Add the name of a file used to check for directory indexes.
        [default: index, index.html]
        """
        self['indexes'].append(indexName)

    opt_i = opt_index

    def opt_user(self):
        """
        Makes a server with ~/public_html and ~/.twistd-web-pb support for
        users.
        """
        self['root'] = distrib.UserDirectory()

    opt_u = opt_user

    def opt_path(self, path):
        """
        <path> is either a specific file or a directory to be set as the root
        of the web server. Use this if you have a directory full of HTML, cgi,
        php3, epy, or rpy files or any other files that you want to be served
        up raw.
        """
        def php3(*args, **kwargs):
            # Help avoid actually importing twisted.web.twcgi.PHP3Script until
            # it is really needed. This avoids getting a deprecation warning if
            # you're not using deprecated functionality.
            from twisted.web.twcgi import PHP3Script
            return PHP3Script(*args, **kwargs)

        def php(*args, **kwargs):
            # Help avoid actually importing twisted.web.twcgi.PHPScript until it
            # is really needed. This avoids getting a deprecation warning if
            # you're not using deprecated functionality.
            from twisted.web.twcgi import PHPScript
            return PHPScript(*args, **kwargs)

        self['root'] = static.File(os.path.abspath(path))
        self['root'].processors = {
            '.cgi': twcgi.CGIScript,
            '.php3': php3,
            '.php': php,
            '.epy': script.PythonScript,
            '.rpy': script.ResourceScript,
        }

    def opt_processor(self, proc):
        """
        `ext=class' where `class' is added as a Processor for files ending
        with `ext'.
        """
        if not isinstance(self['root'], static.File):
            raise usage.UsageError(
                "You can only use --processor after --path.")
        ext, klass = proc.split('=', 1)
        self['root'].processors[ext] = reflect.namedClass(klass)

    def opt_class(self, className):
        """
        Create a Resource subclass with a zero-argument constructor.
        """
        classObj = reflect.namedClass(className)
        self['root'] = classObj()

    def opt_resource_script(self, name):
        """
        An .rpy file to be used as the root resource of the webserver.
        """
        self['root'] = script.ResourceScriptWrapper(name)

    def opt_wsgi(self, name):
        """
        The FQPN of a WSGI application object to serve as the root resource of
        the webserver.
        """
        pool = threadpool.ThreadPool()
        reactor.callWhenRunning(pool.start)
        reactor.addSystemEventTrigger('after', 'shutdown', pool.stop)
        try:
            application = reflect.namedAny(name)
        except (AttributeError, ValueError):
            raise usage.UsageError("No such WSGI application: %r" % (name, ))
        self['root'] = wsgi.WSGIResource(reactor, pool, application)

    def opt_mime_type(self, defaultType):
        """
        Specify the default mime-type for static files.
        """
        if not isinstance(self['root'], static.File):
            raise usage.UsageError(
                "You can only use --mime_type after --path.")
        self['root'].defaultType = defaultType

    opt_m = opt_mime_type

    def opt_allow_ignore_ext(self):
        """
        Specify whether or not a request for 'foo' should return 'foo.ext'
        """
        if not isinstance(self['root'], static.File):
            raise usage.UsageError("You can only use --allow_ignore_ext "
                                   "after --path.")
        self['root'].ignoreExt('*')

    def opt_ignore_ext(self, ext):
        """
        Specify an extension to ignore.  These will be processed in order.
        """
        if not isinstance(self['root'], static.File):
            raise usage.UsageError("You can only use --ignore_ext "
                                   "after --path.")
        self['root'].ignoreExt(ext)

    def postOptions(self):
        """
        Set up conditional defaults and check for dependencies.

        If SSL is not available but an HTTPS server was configured, raise a
        L{UsageError} indicating that this is not possible.

        If no server port was supplied, select a default appropriate for the
        other options supplied.
        """
        if self['https']:
            try:
                from twisted.internet.ssl import DefaultOpenSSLContextFactory
            except ImportError:
                raise usage.UsageError("SSL support not installed")
        if self['port'] is None:
            if self['personal']:
                path = os.path.expanduser(
                    os.path.join('~', distrib.UserDirectory.userSocketName))
                self['port'] = 'unix:' + path
            else:
                self['port'] = 'tcp:8080'
Exemplo n.º 23
0
class Options(usage.Options):
    """
    Define the options accepted by the I{twistd web} plugin.
    """

    synopsis = "[web options]"

    optParameters = [
        [
            "logfile", "l", None,
            "Path to web CLF (Combined Log Format) log file."
        ],
        [
            "certificate",
            "c",
            "server.pem",
            "(DEPRECATED: use --listen) "
            "SSL certificate to use for HTTPS. ",
        ],
        [
            "privkey",
            "k",
            "server.pem",
            "(DEPRECATED: use --listen) "
            "SSL certificate to use for HTTPS.",
        ],
    ]

    optFlags = [
        [
            "notracebacks",
            "n",
            ("(DEPRECATED: Tracebacks are disabled by default. "
             "See --enable-tracebacks to turn them on."),
        ],
        [
            "display-tracebacks",
            "",
            ("Show uncaught exceptions during rendering tracebacks to "
             "the client. WARNING: This may be a security risk and "
             "expose private data!"),
        ],
    ]

    optFlags.append([
        "personal",
        "",
        "Instead of generating a webserver, generate a "
        "ResourcePublisher which listens on  the port given by "
        "--listen, or ~/%s " % (distrib.UserDirectory.userSocketName, ) +
        "if --listen is not specified.",
    ])

    compData = usage.Completions(
        optActions={
            "logfile": usage.CompleteFiles("*.log"),
            "certificate": usage.CompleteFiles("*.pem"),
            "privkey": usage.CompleteFiles("*.pem"),
        })

    longdesc = """\
This starts a webserver.  If you specify no arguments, it will be a
demo webserver that has the Test class from twisted.web.demo in it."""

    def __init__(self):
        usage.Options.__init__(self)
        self["indexes"] = []
        self["root"] = None
        self["extraHeaders"] = []
        self["ports"] = []
        self["port"] = self["https"] = None

    def opt_port(self, port):
        """
        (DEPRECATED: use --listen)
        Strports description of port to start the server on
        """
        msg = deprecate.getDeprecationWarningString(
            self.opt_port, incremental.Version("Twisted", 18, 4, 0))
        warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
        self["port"] = port

    opt_p = opt_port

    def opt_https(self, port):
        """
        (DEPRECATED: use --listen)
        Port to listen on for Secure HTTP.
        """
        msg = deprecate.getDeprecationWarningString(
            self.opt_https, incremental.Version("Twisted", 18, 4, 0))
        warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
        self["https"] = port

    def opt_listen(self, port):
        """
        Add an strports description of port to start the server on.
        [default: tcp:8080]
        """
        self["ports"].append(port)

    def opt_index(self, indexName):
        """
        Add the name of a file used to check for directory indexes.
        [default: index, index.html]
        """
        self["indexes"].append(indexName)

    opt_i = opt_index

    def opt_user(self):
        """
        Makes a server with ~/public_html and ~/.twistd-web-pb support for
        users.
        """
        self["root"] = distrib.UserDirectory()

    opt_u = opt_user

    def opt_path(self, path):
        """
        <path> is either a specific file or a directory to be set as the root
        of the web server. Use this if you have a directory full of HTML, cgi,
        epy, or rpy files or any other files that you want to be served up raw.
        """
        self["root"] = static.File(os.path.abspath(path))
        self["root"].processors = {
            ".epy": script.PythonScript,
            ".rpy": script.ResourceScript,
        }
        self["root"].processors[".cgi"] = twcgi.CGIScript

    def opt_processor(self, proc):
        """
        `ext=class' where `class' is added as a Processor for files ending
        with `ext'.
        """
        if not isinstance(self["root"], static.File):
            raise usage.UsageError(
                "You can only use --processor after --path.")
        ext, klass = proc.split("=", 1)
        self["root"].processors[ext] = reflect.namedClass(klass)

    def opt_class(self, className):
        """
        Create a Resource subclass with a zero-argument constructor.
        """
        classObj = reflect.namedClass(className)
        self["root"] = classObj()

    def opt_resource_script(self, name):
        """
        An .rpy file to be used as the root resource of the webserver.
        """
        self["root"] = script.ResourceScriptWrapper(name)

    def opt_wsgi(self, name):
        """
        The FQPN of a WSGI application object to serve as the root resource of
        the webserver.
        """
        try:
            application = reflect.namedAny(name)
        except (AttributeError, ValueError):
            raise usage.UsageError(f"No such WSGI application: {name!r}")
        pool = threadpool.ThreadPool()
        reactor.callWhenRunning(pool.start)
        reactor.addSystemEventTrigger("after", "shutdown", pool.stop)
        self["root"] = wsgi.WSGIResource(reactor, pool, application)

    def opt_mime_type(self, defaultType):
        """
        Specify the default mime-type for static files.
        """
        if not isinstance(self["root"], static.File):
            raise usage.UsageError(
                "You can only use --mime_type after --path.")
        self["root"].defaultType = defaultType

    opt_m = opt_mime_type

    def opt_allow_ignore_ext(self):
        """
        Specify whether or not a request for 'foo' should return 'foo.ext'
        """
        if not isinstance(self["root"], static.File):
            raise usage.UsageError("You can only use --allow_ignore_ext "
                                   "after --path.")
        self["root"].ignoreExt("*")

    def opt_ignore_ext(self, ext):
        """
        Specify an extension to ignore.  These will be processed in order.
        """
        if not isinstance(self["root"], static.File):
            raise usage.UsageError("You can only use --ignore_ext "
                                   "after --path.")
        self["root"].ignoreExt(ext)

    def opt_add_header(self, header):
        """
        Specify an additional header to be included in all responses. Specified
        as "HeaderName: HeaderValue".
        """
        name, value = header.split(":", 1)
        self["extraHeaders"].append((name.strip(), value.strip()))

    def postOptions(self):
        """
        Set up conditional defaults and check for dependencies.

        If SSL is not available but an HTTPS server was configured, raise a
        L{UsageError} indicating that this is not possible.

        If no server port was supplied, select a default appropriate for the
        other options supplied.
        """
        if self["port"] is not None:
            self["ports"].append(self["port"])
        if self["https"] is not None:
            try:
                reflect.namedModule("OpenSSL.SSL")
            except ImportError:
                raise usage.UsageError("SSL support not installed")
            sslStrport = "ssl:port={}:privateKey={}:certKey={}".format(
                self["https"],
                self["privkey"],
                self["certificate"],
            )
            self["ports"].append(sslStrport)
        if len(self["ports"]) == 0:
            if self["personal"]:
                path = os.path.expanduser(
                    os.path.join("~", distrib.UserDirectory.userSocketName))
                self["ports"].append("unix:" + path)
            else:
                self["ports"].append("tcp:8080")
Exemplo n.º 24
0
class Options(usage.Options, strcred.AuthOptionMixin):
    synopsis = "[options]"

    optParameters = [
        [
            "pop3s", "S", 0,
            "Port to start the POP3-over-SSL server on (0 to disable). "
            "DEPRECATED: use "
            "'--pop3 ssl:port:privateKey=pkey.pem:certKey=cert.pem'"
        ],
        [
            "certificate", "c", None,
            "Certificate file to use for SSL connections. "
            "DEPRECATED: use "
            "'--pop3 ssl:port:privateKey=pkey.pem:certKey=cert.pem'"
        ],
        [
            "relay", "R", None,
            "Relay messages according to their envelope 'To', using "
            "the given path as a queue directory."
        ],
        [
            "hostname", "H", None,
            "The hostname by which to identify this server."
        ],
    ]

    optFlags = [
        ["esmtp", "E", "Use RFC 1425/1869 SMTP extensions"],
        [
            "disable-anonymous", None,
            "Disallow non-authenticated SMTP connections"
        ],
        ["no-pop3", None, "Disable the default POP3 server."],
        ["no-smtp", None, "Disable the default SMTP server."],
    ]

    _protoDefaults = {
        "pop3": 8110,
        "smtp": 8025,
    }

    compData = usage.Completions(
        optActions={
            "hostname": usage.CompleteHostnames(),
            "certificate": usage.CompleteFiles("*.pem")
        })

    longdesc = "This creates a mail.tap file that can be used by twistd."

    def __init__(self):
        usage.Options.__init__(self)
        self.service = mail.MailService()
        self.last_domain = None
        for service in self._protoDefaults:
            self[service] = []

    def addEndpoint(self, service, description, certificate=None):
        """
        Given a 'service' (pop3 or smtp), add an endpoint.
        """
        self[service].append(_toEndpoint(description, certificate=certificate))

    def opt_pop3(self, description):
        """
        Add a pop3 port listener on the specified endpoint.  You can listen on
        multiple ports by specifying multiple --pop3 options.  For backwards
        compatibility, a bare TCP port number can be specified, but this is
        deprecated. [SSL Example: ssl:8995:privateKey=mycert.pem] [default:
        tcp:8110]
        """
        self.addEndpoint('pop3', description)

    opt_p = opt_pop3

    def opt_smtp(self, description):
        """
        Add an smtp port listener on the specified endpoint.  You can listen on
        multiple ports by specifying multiple --smtp options For backwards
        compatibility, a bare TCP port number can be specified, but this is
        deprecated.  [SSL Example: ssl:8465:privateKey=mycert.pem] [default:
        tcp:8025]
        """
        self.addEndpoint('smtp', description)

    opt_s = opt_smtp

    def opt_passwordfile(self, filename):
        """
        Specify a file containing username:password login info for authenticated
        ESMTP connections. (DEPRECATED; see --help-auth instead)
        """
        ch = checkers.OnDiskUsernamePasswordDatabase(filename)
        self.service.smtpPortal.registerChecker(ch)
        msg = deprecate.getDeprecationWarningString(
            self.opt_passwordfile, versions.Version('twisted.mail', 11, 0, 0))
        warnings.warn(msg, category=DeprecationWarning, stacklevel=2)

    opt_P = opt_passwordfile

    def opt_default(self):
        """Make the most recently specified domain the default domain."""
        if self.last_domain:
            self.service.addDomain('', self.last_domain)
        else:
            raise usage.UsageError(
                "Specify a domain before specifying using --default")

    opt_D = opt_default

    def opt_maildirdbmdomain(self, domain):
        """generate an SMTP/POP3 virtual domain which saves to \"path\"
        """
        try:
            name, path = domain.split('=')
        except ValueError:
            raise usage.UsageError(
                "Argument to --maildirdbmdomain must be of the form 'name=path'"
            )

        self.last_domain = maildir.MaildirDirdbmDomain(self.service,
                                                       os.path.abspath(path))
        self.service.addDomain(name, self.last_domain)

    opt_d = opt_maildirdbmdomain

    def opt_user(self, user_pass):
        """add a user/password to the last specified domains
        """
        try:
            user, password = user_pass.split('=', 1)
        except ValueError:
            raise usage.UsageError(
                "Argument to --user must be of the form 'user=password'")
        if self.last_domain:
            self.last_domain.addUser(user, password)
        else:
            raise usage.UsageError("Specify a domain before specifying users")

    opt_u = opt_user

    def opt_bounce_to_postmaster(self):
        """undelivered mails are sent to the postmaster
        """
        self.last_domain.postmaster = 1

    opt_b = opt_bounce_to_postmaster

    def opt_aliases(self, filename):
        """Specify an aliases(5) file to use for this domain"""
        if self.last_domain is not None:
            if mail.IAliasableDomain.providedBy(self.last_domain):
                aliases = alias.loadAliasFile(self.service.domains, filename)
                self.last_domain.setAliasGroup(aliases)
                self.service.monitor.monitorFile(
                    filename,
                    AliasUpdater(self.service.domains, self.last_domain))
            else:
                raise usage.UsageError("%s does not support alias files" %
                                       (self.last_domain.__class__.__name__, ))
        else:
            raise usage.UsageError(
                "Specify a domain before specifying aliases")

    opt_A = opt_aliases

    def _getEndpoints(self, reactor, service):
        """
        Return a list of endpoints for the specified service, constructing
        defaults if necessary.

        @param reactor: If any endpoints are created, this is the reactor with
            which they are created.

        @param service: A key into self indicating the type of service to
            retrieve endpoints for.  This is either C{"pop3"} or C{"smtp"}.

        @return: A C{list} of C{IServerStreamEndpoint} providers corresponding
            to the command line parameters that were specified for C{service}.
            If none were and the protocol was not explicitly disabled with a
            I{--no-*} option, a default endpoint for the service is created
            using C{self._protoDefaults}.
        """
        if service == 'pop3' and self['pop3s'] and len(self[service]) == 1:
            # The single endpoint here is the POP3S service we added in
            # postOptions.  Include the default endpoint alongside it.
            return self[service] + [
                endpoints.TCP4ServerEndpoint(reactor,
                                             self._protoDefaults[service])
            ]
        elif self[service]:
            # For any non-POP3S case, if there are any services set up, just
            # return those.
            return self[service]
        elif self['no-' + service]:
            # If there are no services, but the service was explicitly disabled,
            # return nothing.
            return []
        else:
            # Otherwise, return the old default service.
            return [
                endpoints.TCP4ServerEndpoint(reactor,
                                             self._protoDefaults[service])
            ]

    def postOptions(self):
        from twisted.internet import reactor

        if self['pop3s']:
            if not self['certificate']:
                raise usage.UsageError("Cannot specify --pop3s without "
                                       "--certificate")
            elif not os.path.exists(self['certificate']):
                raise usage.UsageError("Certificate file %r does not exist." %
                                       self['certificate'])
            else:
                self.addEndpoint('pop3',
                                 self['pop3s'],
                                 certificate=self['certificate'])

        if self['esmtp'] and self['hostname'] is None:
            raise usage.UsageError("--esmtp requires --hostname")

        # If the --auth option was passed, this will be present -- otherwise,
        # it won't be, which is also a perfectly valid state.
        if 'credCheckers' in self:
            for ch in self['credCheckers']:
                self.service.smtpPortal.registerChecker(ch)

        if not self['disable-anonymous']:
            self.service.smtpPortal.registerChecker(
                checkers.AllowAnonymousAccess())

        anything = False
        for service in self._protoDefaults:
            self[service] = self._getEndpoints(reactor, service)
            if self[service]:
                anything = True

        if not anything:
            raise usage.UsageError("You cannot disable all protocols")
Exemplo n.º 25
0
class Options(usage.Options, strcred.AuthOptionMixin):
    """
    An options list parser for twistd mail.

    @type synopsis: L{bytes}
    @ivar synopsis: A description of options for use in the usage message.

    @type optParameters: L{list} of L{list} of (0) L{bytes}, (1) L{bytes},
        (2) L{object}, (3) L{bytes}, (4) L{None} or
        callable which takes L{bytes} and returns L{object}
    @ivar optParameters: Information about supported parameters.  See
        L{Options <twisted.python.usage.Options>} for details.

    @type optFlags: L{list} of L{list} of (0) L{bytes}, (1) L{bytes} or
        L{None}, (2) L{bytes}
    @ivar optFlags: Information about supported flags.  See
        L{Options <twisted.python.usage.Options>} for details.

    @type _protoDefaults: L{dict} mapping L{bytes} to L{int}
    @ivar _protoDefaults: A mapping of default service to port.

    @type compData: L{Completions <usage.Completions>}
    @ivar compData: Metadata for the shell tab completion system.

    @type longdesc: L{bytes}
    @ivar longdesc: A long description of the plugin for use in the usage
        message.

    @type service: L{MailService}
    @ivar service: The email service.

    @type last_domain: L{IDomain} provider or L{None}
    @ivar last_domain: The most recently specified domain.
    """
    synopsis = "[options]"

    optParameters = [
        [
            "pop3s", "S", 0,
            "Port to start the POP3-over-SSL server on (0 to disable). "
            "DEPRECATED: use "
            "'--pop3 ssl:port:privateKey=pkey.pem:certKey=cert.pem'"
        ],
        [
            "certificate", "c", None,
            "Certificate file to use for SSL connections. "
            "DEPRECATED: use "
            "'--pop3 ssl:port:privateKey=pkey.pem:certKey=cert.pem'"
        ],
        [
            "relay", "R", None,
            "Relay messages according to their envelope 'To', using "
            "the given path as a queue directory."
        ],
        [
            "hostname", "H", None,
            "The hostname by which to identify this server."
        ],
    ]

    optFlags = [
        ["esmtp", "E", "Use RFC 1425/1869 SMTP extensions"],
        [
            "disable-anonymous", None,
            "Disallow non-authenticated SMTP connections"
        ],
        ["no-pop3", None, "Disable the default POP3 server."],
        ["no-smtp", None, "Disable the default SMTP server."],
    ]

    _protoDefaults = {
        "pop3": 8110,
        "smtp": 8025,
    }

    compData = usage.Completions(
        optActions={
            "hostname": usage.CompleteHostnames(),
            "certificate": usage.CompleteFiles("*.pem")
        })

    longdesc = """
    An SMTP / POP3 email server plugin for twistd.

    Examples:

    1. SMTP and POP server

    twistd mail --maildirdbmdomain=example.com=/tmp/example.com
    --user=joe=password

    Starts an SMTP server that only accepts emails to [email protected] and saves
    them to /tmp/example.com.

    Also starts a POP mail server which will allow a client to log in using
    username: [email protected] and password: password and collect any email that
    has been saved in /tmp/example.com.

    2. SMTP relay

    twistd mail --relay=/tmp/mail_queue

    Starts an SMTP server that accepts emails to any email address and relays
    them to an appropriate remote SMTP server. Queued emails will be
    temporarily stored in /tmp/mail_queue.
    """

    def __init__(self):
        """
        Parse options and create a mail service.
        """
        usage.Options.__init__(self)
        self.service = mail.MailService()
        self.last_domain = None
        for service in self._protoDefaults:
            self[service] = []

    def addEndpoint(self, service, description, certificate=None):
        """
        Add an endpoint to a service.

        @type service: L{bytes}
        @param service: A service, either C{b'smtp'} or C{b'pop3'}.

        @type description: L{bytes}
        @param description: An endpoint description string or a TCP port
            number.

        @type certificate: L{bytes} or L{None}
        @param certificate: The name of a file containing an SSL certificate.
        """
        self[service].append(_toEndpoint(description, certificate=certificate))

    def opt_pop3(self, description):
        """
        Add a POP3 port listener on the specified endpoint.

        You can listen on multiple ports by specifying multiple --pop3 options.
        For backwards compatibility, a bare TCP port number can be specified,
        but this is deprecated.  [SSL Example: ssl:8995:privateKey=mycert.pem]
        [default: tcp:8110]
        """
        self.addEndpoint('pop3', description)

    opt_p = opt_pop3

    def opt_smtp(self, description):
        """
        Add an SMTP port listener on the specified endpoint.

        You can listen on multiple ports by specifying multiple --smtp options.
        For backwards compatibility, a bare TCP port number can be specified,
        but this is deprecated.  [SSL Example: ssl:8465:privateKey=mycert.pem]
        [default: tcp:8025]
        """
        self.addEndpoint('smtp', description)

    opt_s = opt_smtp

    def opt_default(self):
        """
        Make the most recently specified domain the default domain.
        """
        if self.last_domain:
            self.service.addDomain('', self.last_domain)
        else:
            raise usage.UsageError(
                "Specify a domain before specifying using --default")

    opt_D = opt_default

    def opt_maildirdbmdomain(self, domain):
        """
        Generate an SMTP/POP3 virtual domain.

        This option requires an argument of the form 'NAME=PATH' where NAME is
        the DNS domain name for which email will be accepted and where PATH is
        a the filesystem path to a Maildir folder.
        [Example: 'example.com=/tmp/example.com']
        """
        try:
            name, path = domain.split('=')
        except ValueError:
            raise usage.UsageError(
                "Argument to --maildirdbmdomain must be of the form 'name=path'"
            )

        self.last_domain = maildir.MaildirDirdbmDomain(self.service,
                                                       os.path.abspath(path))
        self.service.addDomain(name, self.last_domain)

    opt_d = opt_maildirdbmdomain

    def opt_user(self, user_pass):
        """
        Add a user and password to the last specified domain.
        """
        try:
            user, password = user_pass.split('=', 1)
        except ValueError:
            raise usage.UsageError(
                "Argument to --user must be of the form 'user=password'")
        if self.last_domain:
            self.last_domain.addUser(user, password)
        else:
            raise usage.UsageError("Specify a domain before specifying users")

    opt_u = opt_user

    def opt_bounce_to_postmaster(self):
        """
        Send undeliverable messages to the postmaster.
        """
        self.last_domain.postmaster = 1

    opt_b = opt_bounce_to_postmaster

    def opt_aliases(self, filename):
        """
        Specify an aliases(5) file to use for the last specified domain.
        """
        if self.last_domain is not None:
            if mail.IAliasableDomain.providedBy(self.last_domain):
                aliases = alias.loadAliasFile(self.service.domains, filename)
                self.last_domain.setAliasGroup(aliases)
                self.service.monitor.monitorFile(
                    filename,
                    AliasUpdater(self.service.domains, self.last_domain))
            else:
                raise usage.UsageError("%s does not support alias files" %
                                       (self.last_domain.__class__.__name__, ))
        else:
            raise usage.UsageError(
                "Specify a domain before specifying aliases")

    opt_A = opt_aliases

    def _getEndpoints(self, reactor, service):
        """
        Return a list of endpoints for the specified service, constructing
        defaults if necessary.

        If no endpoints were configured for the service and the protocol
        was not explicitly disabled with a I{--no-*} option, a default
        endpoint for the service is created.

        @type reactor: L{IReactorTCP <twisted.internet.interfaces.IReactorTCP>}
            provider
        @param reactor: If any endpoints are created, the reactor with
            which they are created.

        @type service: L{bytes}
        @param service: The type of service for which to retrieve endpoints,
            either C{b'pop3'} or C{b'smtp'}.

        @rtype: L{list} of L{IStreamServerEndpoint
            <twisted.internet.interfaces.IStreamServerEndpoint>} provider
        @return: The endpoints for the specified service as configured by the
            command line parameters.
        """
        if service == 'pop3' and self['pop3s'] and len(self[service]) == 1:
            # The single endpoint here is the POP3S service we added in
            # postOptions.  Include the default endpoint alongside it.
            return self[service] + [
                endpoints.TCP4ServerEndpoint(reactor,
                                             self._protoDefaults[service])
            ]
        elif self[service]:
            # For any non-POP3S case, if there are any services set up, just
            # return those.
            return self[service]
        elif self['no-' + service]:
            # If there are no services, but the service was explicitly disabled,
            # return nothing.
            return []
        else:
            # Otherwise, return the old default service.
            return [
                endpoints.TCP4ServerEndpoint(reactor,
                                             self._protoDefaults[service])
            ]

    def postOptions(self):
        """
        Check the validity of the specified set of options and
        configure authentication.

        @raise UsageError: When the set of options is invalid.
        """
        from twisted.internet import reactor

        if self['pop3s']:
            if not self['certificate']:
                raise usage.UsageError("Cannot specify --pop3s without "
                                       "--certificate")
            elif not os.path.exists(self['certificate']):
                raise usage.UsageError("Certificate file %r does not exist." %
                                       self['certificate'])
            else:
                self.addEndpoint('pop3',
                                 self['pop3s'],
                                 certificate=self['certificate'])

        if self['esmtp'] and self['hostname'] is None:
            raise usage.UsageError("--esmtp requires --hostname")

        # If the --auth option was passed, this will be present -- otherwise,
        # it won't be, which is also a perfectly valid state.
        if 'credCheckers' in self:
            for ch in self['credCheckers']:
                self.service.smtpPortal.registerChecker(ch)

        if not self['disable-anonymous']:
            self.service.smtpPortal.registerChecker(
                checkers.AllowAnonymousAccess())

        anything = False
        for service in self._protoDefaults:
            self[service] = self._getEndpoints(reactor, service)
            if self[service]:
                anything = True

        if not anything:
            raise usage.UsageError("You cannot disable all protocols")
Exemplo n.º 26
0
class Options(usage.Options):
    synopsis = """%s [options] [path to test].py
    """ % (os.path.basename(sys.argv[0]), )

    longdesc = ("ooniprobe loads and executes a suite or a set of suites of"
                " network tests. These are loaded from modules, packages and"
                " files listed on the command line")

    optFlags = [["help", "h"], ["resume", "r"], ["no-collector", "n"],
                ["no-geoip", "g"], ["list", "s"], ["printdeck", "p"],
                ["verbose", "v"]]

    optParameters = [
        ["reportfile", "o", None, "report file name"],
        [
            "testdeck", "i", None,
            "Specify as input a test deck: a yaml file containing the tests to run and their arguments"
        ],
        [
            "collector", "c", None,
            "Address of the collector of test results. This option should not be used, but you should always use a bouncer."
        ],
        [
            "bouncer", "b", 'httpo://nkvphnp3p6agi5qq.onion',
            "Address of the bouncer for test helpers. default: httpo://nkvphnp3p6agi5qq.onion"
        ], ["logfile", "l", None, "log file name"],
        ["pcapfile", "O", None, "pcap file name"],
        [
            "configfile", "f", None,
            "Specify a path to the ooniprobe configuration file"
        ],
        [
            "datadir", "d", None,
            "Specify a path to the ooniprobe data directory"
        ],
        [
            "annotations", "a", None,
            "Annotate the report with a key:value[, key:value] format."
        ]
    ]

    compData = usage.Completions(extraActions=[
        usage.CompleteFiles(
            "*.py",
            descr="file | module | package | TestCase | testMethod",
            repeat=True)
    ], )

    tracer = None

    def __init__(self):
        self['test'] = None
        usage.Options.__init__(self)

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.  Useful
        when debugging freezes or locks in complex code.
        """
        sys.settrace(spewer)

    def opt_version(self):
        """
        Display the ooniprobe version and exit.
        """
        print "ooniprobe version:", __version__
        sys.exit(0)

    def parseArgs(self, *args):
        if self['testdeck'] or self['list']:
            return
        try:
            self['test_file'] = args[0]
            self['subargs'] = args[1:]
        except:
            raise usage.UsageError("No test filename specified!")
Exemplo n.º 27
0
class Options(usage.Options):
    synopsis = """%s [options] [path to test].py
    """ % (os.path.basename(sys.argv[0]), )

    longdesc = ("ooniprobe loads and executes a suite or a set of suites of"
                " network tests. These are loaded from modules, packages and"
                " files listed on the command line.")

    optFlags = [["help", "h"],
                ["no-collector", "n", "Disable writing to collector"],
                ["no-yamloo", "N", "Disable writing to YAML file"],
                ["no-geoip", "g", "Disable geoip lookup on start"],
                [
                    "list", "s", "List the currently installed ooniprobe "
                    "nettests"
                ],
                [
                    "printdeck", "p", "Print the equivalent deck for the "
                    "provided command"
                ], ["verbose", "v", "Show more verbose information"]]

    optParameters = [
        ["reportfile", "o", None, "Specify the report file name to write to."],
        [
            "testdeck", "i", None, "Specify as input a test deck: a yaml file "
            "containing the tests to run and their "
            "arguments."
        ],
        [
            "collector", "c", None, "Specify the address of the collector for "
            "test results. In most cases a user will "
            "prefer to specify a bouncer over this."
        ],
        [
            "bouncer", "b", None, "Specify the bouncer used to "
            "obtain the address of the "
            "collector and test helpers."
        ], ["logfile", "l", None, "Write to this logs to this filename."],
        [
            "pcapfile", "O", None, "Write a PCAP of the ooniprobe session to "
            "this filename."
        ],
        [
            "configfile", "f", None, "Specify a path to the ooniprobe "
            "configuration file."
        ],
        [
            "datadir", "d", None, "Specify a path to the ooniprobe data "
            "directory."
        ],
        [
            "annotations", "a", None, "Annotate the report with a key:value[, "
            "key:value] format."
        ],
        [
            "preferred-backend", "P", None, "Set the preferred backend to use "
            "when submitting results and/or "
            "communicating with test helpers. "
            "Can be either onion, "
            "https or cloudfront"
        ],
        [
            "queue", "Q", None,
            "AMQP Queue URL amqp://user:pass@host:port/vhost/queue"
        ]
    ]

    compData = usage.Completions(extraActions=[
        usage.CompleteFiles(
            "*.py",
            descr="file | module | package | TestCase | testMethod",
            repeat=True)
    ], )

    tracer = None

    def __init__(self):
        usage.Options.__init__(self)

    def getUsage(self, width=None):
        return super(Options, self).getUsage(width) + """
To get started you may want to run:

$ oonideckgen

This will tell you how to run ooniprobe :)
"""

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.
        Useful when debugging freezes or locks in complex code.
        """
        from twisted.python.util import spewer
        sys.settrace(spewer)

    def opt_version(self):
        """
        Display the ooniprobe version and exit.
        """
        print "ooniprobe version:", __version__
        sys.exit(0)

    def parseArgs(self, *args):
        if self['testdeck'] or self['list']:
            return
        try:
            self['test_file'] = args[0]
            self['subargs'] = args[1:]
        except:
            raise usage.UsageError("No test filename specified!")
Exemplo n.º 28
0
class ServerOptions(usage.Options, ReactorSelectionMixin):

    longdesc = ("twistd reads a twisted.application.service.Application out "
                "of a file and runs it.")

    optFlags = [[
        'savestats', None,
        "save the Stats object rather than the text output of "
        "the profiler."
    ], ['no_save', 'o', "do not save state on shutdown"],
                ['encrypted', 'e', "The specified tap/aos file is encrypted."]]

    optParameters = [
        ['logfile', 'l', None, "log to a specified file, - for stdout"],
        [
            'logger', None, None,
            "A fully-qualified name to a log observer factory to use "
            "for the initial log observer.  Takes precedence over "
            "--logfile and --syslog (when available)."
        ],
        [
            'profile', 'p', None,
            "Run in profile mode, dumping results to specified file"
        ],
        [
            'profiler', None, "hotshot",
            "Name of the profiler to use (%s)." %
            ", ".join(AppProfiler.profilers)
        ], ['file', 'f', 'twistd.tap', "read the given .tap file"],
        [
            'python', 'y', None,
            "read an application from within a Python file "
            "(implies -o)"
        ],
        [
            'source', 's', None,
            "Read an application from a .tas file (AOT format)."
        ],
        ['rundir', 'd', '.', 'Change to a supplied directory before running']
    ]

    compData = usage.Completions(mutuallyExclusive=[("file", "python",
                                                     "source")],
                                 optActions={
                                     "file": usage.CompleteFiles("*.tap"),
                                     "python":
                                     usage.CompleteFiles("*.(tac|py)"),
                                     "source": usage.CompleteFiles("*.tas"),
                                     "rundir": usage.CompleteDirs()
                                 })

    _getPlugins = staticmethod(plugin.getPlugins)

    def __init__(self, *a, **kw):
        self['debug'] = False
        usage.Options.__init__(self, *a, **kw)

    def opt_debug(self):
        """
        Run the application in the Python Debugger (implies nodaemon),
        sending SIGUSR2 will drop into debugger
        """
        defer.setDebugging(True)
        failure.startDebugMode()
        self['debug'] = True

    opt_b = opt_debug

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.
        Useful when debugging freezes or locks in complex code."""
        sys.settrace(util.spewer)
        try:
            import threading
        except ImportError:
            return
        threading.settrace(util.spewer)

    def parseOptions(self, options=None):
        if options is None:
            options = sys.argv[1:] or ["--help"]
        usage.Options.parseOptions(self, options)

    def postOptions(self):
        if self.subCommand or self['python']:
            self['no_save'] = True
        if self['logger'] is not None:
            try:
                self['logger'] = namedAny(self['logger'])
            except Exception as e:
                raise usage.UsageError(
                    "Logger '%s' could not be imported: %s" %
                    (self['logger'], e))

    def subCommands(self):
        plugins = self._getPlugins(service.IServiceMaker)
        self.loadedPlugins = {}
        for plug in sorted(plugins, key=attrgetter('tapname')):
            self.loadedPlugins[plug.tapname] = plug
            yield (
                plug.tapname,
                None,
                # Avoid resolving the options attribute right away, in case
                # it's a property with a non-trivial getter (eg, one which
                # imports modules).
                lambda plug=plug: plug.options(),
                plug.description)

    subCommands = property(subCommands)
Exemplo n.º 29
0
class _BasicOptions(object):
    """
    Basic options shared between trial and its local workers.
    """
    synopsis = """%s [options] [[file|package|module|TestCase|testmethod]...]
    """ % (os.path.basename(sys.argv[0]), )

    longdesc = ("trial loads and executes a suite of unit tests, obtained "
                "from modules, packages and files listed on the command line.")

    optFlags = [
        ["help", "h"],
        ["no-recurse", "N", "Don't recurse into packages"],
        ['help-orders', None, "Help on available test running orders"],
        [
            'help-reporters', None,
            "Help on available output plugins (reporters)"
        ],
        [
            "rterrors", "e", "realtime errors, print out tracebacks as "
            "soon as they occur"
        ],
        ["unclean-warnings", None, "Turn dirty reactor errors into warnings"],
        [
            "force-gc", None, "Have Trial run gc.collect() before and "
            "after each test case."
        ],
        [
            "exitfirst", "x",
            "Exit after the first non-successful result (cannot be "
            "specified along with --jobs)."
        ],
    ]

    optParameters = [
        [
            "order", "o", None,
            "Specify what order to run test cases and methods. "
            "See --help-orders for more info.", _checkKnownRunOrder
        ],
        [
            "random", "z", None,
            "Run tests in random order using the specified seed"
        ],
        [
            'temp-directory', None, '_trial_temp',
            'Path to use as working directory for tests.'
        ],
        [
            'reporter', None, 'verbose',
            'The reporter to use for this test run.  See --help-reporters for '
            'more info.'
        ]
    ]

    compData = usage.Completions(
        optActions={
            "order": usage.CompleteList(_runOrders),
            "reporter": _reporterAction,
            "logfile": usage.CompleteFiles(descr="log file name"),
            "random": usage.Completer(descr="random seed")
        },
        extraActions=[
            usage.CompleteFiles(
                "*.py",
                descr="file | module | package | TestCase | testMethod",
                repeat=True)
        ],
    )

    fallbackReporter = reporter.TreeReporter
    tracer = None

    def __init__(self):
        self['tests'] = []
        usage.Options.__init__(self)

    def coverdir(self):
        """
        Return a L{FilePath} representing the directory into which coverage
        results should be written.
        """
        coverdir = 'coverage'
        result = FilePath(self['temp-directory']).child(coverdir)
        print("Setting coverage directory to %s." % (result.path, ))
        return result

    # TODO: Some of the opt_* methods on this class have docstrings and some do
    #       not. This is mostly because usage.Options's currently will replace
    #       any intended output in optFlags and optParameters with the
    #       docstring. See #6427. When that is fixed, all methods should be
    #       given docstrings (and it should be verified that those with
    #       docstrings already have content suitable for printing as usage
    #       information).

    def opt_coverage(self):
        """
        Generate coverage information in the coverage file in the
        directory specified by the temp-directory option.
        """
        import trace
        self.tracer = trace.Trace(count=1, trace=0)
        sys.settrace(self.tracer.globaltrace)
        self['coverage'] = True

    def opt_testmodule(self, filename):
        """
        Filename to grep for test cases (-*- test-case-name).
        """
        # If the filename passed to this parameter looks like a test module
        # we just add that to the test suite.
        #
        # If not, we inspect it for an Emacs buffer local variable called
        # 'test-case-name'.  If that variable is declared, we try to add its
        # value to the test suite as a module.
        #
        # This parameter allows automated processes (like Buildbot) to pass
        # a list of files to Trial with the general expectation of "these files,
        # whatever they are, will get tested"
        if not os.path.isfile(filename):
            sys.stderr.write("File %r doesn't exist\n" % (filename, ))
            return
        filename = os.path.abspath(filename)
        if isTestFile(filename):
            self['tests'].append(filename)
        else:
            self['tests'].extend(getTestModules(filename))

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.  Useful
        when debugging freezes or locks in complex code.
        """
        sys.settrace(spewer)

    def opt_help_orders(self):
        synopsis = ("Trial can attempt to run test cases and their methods in "
                    "a few different orders. You can select any of the "
                    "following options using --order=<foo>.\n")

        print(synopsis)
        for name, (description, _) in sorted(_runOrders.items()):
            print('   ', name, '\t', description)
        sys.exit(0)

    def opt_help_reporters(self):
        synopsis = ("Trial's output can be customized using plugins called "
                    "Reporters. You can\nselect any of the following "
                    "reporters using --reporter=<foo>\n")
        print(synopsis)
        for p in plugin.getPlugins(itrial.IReporter):
            print('   ', p.longOpt, '\t', p.description)
        sys.exit(0)

    def opt_disablegc(self):
        """
        Disable the garbage collector
        """
        self["disablegc"] = True
        gc.disable()

    def opt_tbformat(self, opt):
        """
        Specify the format to display tracebacks with. Valid formats are
        'plain', 'emacs', and 'cgitb' which uses the nicely verbose stdlib
        cgitb.text function
        """
        try:
            self['tbformat'] = TBFORMAT_MAP[opt]
        except KeyError:
            raise usage.UsageError(
                "tbformat must be 'plain', 'emacs', or 'cgitb'.")

    def opt_recursionlimit(self, arg):
        """
        see sys.setrecursionlimit()
        """
        try:
            sys.setrecursionlimit(int(arg))
        except (TypeError, ValueError):
            raise usage.UsageError(
                "argument to recursionlimit must be an integer")
        else:
            self["recursionlimit"] = int(arg)

    def opt_random(self, option):
        try:
            self['random'] = long(option)
        except ValueError:
            raise usage.UsageError(
                "Argument to --random must be a positive integer")
        else:
            if self['random'] < 0:
                raise usage.UsageError(
                    "Argument to --random must be a positive integer")
            elif self['random'] == 0:
                self['random'] = long(time.time() * 100)

    def opt_without_module(self, option):
        """
        Fake the lack of the specified modules, separated with commas.
        """
        self["without-module"] = option
        for module in option.split(","):
            if module in sys.modules:
                warnings.warn("Module '%s' already imported, "
                              "disabling anyway." % (module, ),
                              category=RuntimeWarning)
            sys.modules[module] = None

    def parseArgs(self, *args):
        self['tests'].extend(args)

    def _loadReporterByName(self, name):
        for p in plugin.getPlugins(itrial.IReporter):
            qual = "%s.%s" % (p.module, p.klass)
            if p.longOpt == name:
                return reflect.namedAny(qual)
        raise usage.UsageError("Only pass names of Reporter plugins to "
                               "--reporter. See --help-reporters for "
                               "more info.")

    def postOptions(self):
        # Only load reporters now, as opposed to any earlier, to avoid letting
        # application-defined plugins muck up reactor selecting by importing
        # t.i.reactor and causing the default to be installed.
        self['reporter'] = self._loadReporterByName(self['reporter'])
        if 'tbformat' not in self:
            self['tbformat'] = 'default'
        if self['order'] is not None and self['random'] is not None:
            raise usage.UsageError(
                "You can't specify --random when using --order")
Exemplo n.º 30
0
class Options(usage.Options):
    synopsis = """%s [options] [path to test].py
    """ % (os.path.basename(sys.argv[0]),)

    longdesc = ("ooniprobe loads and executes a suite or a set of suites of"
                " network tests. These are loaded from modules, packages and"
                " files listed on the command line.")

    optFlags = [["help", "h"],
                ["no-collector", "n", "Disable writing to collector"],
                ["no-njson", "N", "Disable writing to disk"],
                ["no-geoip", "g", "Don't include geoip related information inside of the report."
                                  "Note: Even with this option your IP address can be disclosed in the report."],
                ["list", "s", "List the currently installed ooniprobe "
                              "nettests"],
                ["verbose", "v", "Show more verbose information"],
                ["web-ui", "w", "Start the web UI"],
                ["initialize", "z", "Initialize ooniprobe to begin running "
                                    "it"],
                ["info", None, "Print system wide info and exit"]
                ]

    optParameters = [
        ["reportfile", "o", None, "Specify the report file name to write "
                                  "to."],
        ["testdeck", "i", None, "Specify as input a test deck: a yaml file "
                                 "containing the tests to run and their "
                                "arguments."],
        ["collector", "c", None, "Specify the address of the collector for "
                                 "test results. In most cases a user will "
                                 "prefer to specify a bouncer over this."],
        ["bouncer", "b", None, "Specify the bouncer used to "
                               "obtain the address of the "
                               "collector and test helpers."],
        ["logfile", "l", None, "Write to this logs to this filename."],
        ["pcapfile", "O", None, "Write a PCAP of the ooniprobe session to "
                                "this filename."],
        ["configfile", "f", None, "Specify a path to the ooniprobe "
                                  "configuration file."],
        ["datadir", "d", None, "Specify a path to the ooniprobe data "
                               "directory."],
        ["annotations", "a", None, "Annotate the report with a key:value[, "
                                   "key:value] format."],
        ["preferred-backend", "P", None, "Set the preferred backend to use "
                                         "when submitting results and/or "
                                         "communicating with test helpers. "
                                         "Can be either onion, "
                                         "https or cloudfront"],
        ["queue", "Q", None, "AMQP Queue URL "
                             "amqp://*****:*****@host:port/vhost/queue"]
    ]

    compData = usage.Completions(
        extraActions=[usage.CompleteFiles(
            "*.py", descr="file | module | package | TestCase | testMethod",
            repeat=True)],)

    tracer = None

    def __init__(self):
        usage.Options.__init__(self)

    def opt_spew(self):
        """
        Print an insanely verbose log of everything that happens.
        Useful when debugging freezes or locks in complex code.
        """
        from twisted.python.util import spewer
        sys.settrace(spewer)

    def opt_version(self):
        """
        Display the ooniprobe version and exit.
        """
        print "ooniprobe version:", __version__
        sys.exit(0)

    def parseArgs(self, *args):
        flag_opts = ['testdeck', 'list', 'web-ui', 'info']
        if any([self[opt] for opt in flag_opts]):
            return
        try:
            self['test_file'] = args[0]
            self['subargs'] = args[1:]
        except:
            raise usage.UsageError("No test filename specified!")