예제 #1
0
def main():
    with Inform(notify_if_no_tty=True, version=version) as inform:
        try:
            # assure config and log directories exist
            to_path(CONFIG_DIR).mkdir(parents=True, exist_ok=True)
            to_path(DATA_DIR).mkdir(parents=True, exist_ok=True)
            inform.set_logfile(to_path(DATA_DIR, LOG_FILE))

            # read command line
            cmdline = docopt(synopsis, options_first=True, version=version)
            command = cmdline["<command>"]
            args = cmdline["<args>"]
            if cmdline["--quiet"]:
                inform.quiet = True

            # find and run command
            settings = Settings(cmdline)
            cmd, cmd_name = Command.find(command)
            cmd.execute(cmd_name, args, settings, cmdline)

        except KeyboardInterrupt:
            display("Terminated by user.")
        except Error as e:
            e.terminate()
        except OSError as e:
            fatal(os_error(e))
        done()
예제 #2
0
def main():
    try:
        # read config file
        read_config()

        # read command line
        cmdline = docopt(
            __doc__.format(commands=Command.summarize()),
            version='avendesora {} ({})'.format(__version__, __released__),
            options_first=True,
        )

        # start logging
        logfile = BufferedFile(get_setting('log_file'), True)
        Inform(logfile=logfile,
               hanging_indent=False,
               stream_policy='header',
               notify_if_no_tty=True)
        shlib.set_prefs(use_inform=True, log_cmd=True)

        # run the requested command
        Command.execute(cmdline['<command>'], cmdline['<args>'])
        done()
    except KeyboardInterrupt:
        output('\nTerminated by user.')
        terminate()
    except (PasswordError, Error) as e:
        e.terminate()
    except OSError as e:
        fatal(os_error(e))
    done()
예제 #3
0
def get_argv():
    argv = sys.argv[1:]
    if argv:
        # save the command line arguments for next time
        try:
            with open(saved_arguments_filename, 'w') as f:
                args = [a for a in argv if a not in ['-c', '--no-cache']]
                f.write('\n'.join(args))
        except OSError as e:
            warn(os_error(e))
    else:
        # command line arguments not give, reuse previous ones
        try:
            with open(saved_arguments_filename) as f:
                argv = f.read().split('\n')
            display('Using command:', ' '.join(argv))
        except OSError:
            done()
    return argv
예제 #4
0
파일: settings.py 프로젝트: kewlfft/emborg
    def read(self, name=None, path=None):
        """Recursively read configuration files.

        name (str):
            Name of desired configuration. Passed only when reading the top level
            settings file. Default is the default configuration as specified in the
            settings file, or if that is not specified then the first configuration
            given is used.
        path (str):
            Full path to settings file. Should not be given for the top level
            settings file (SETTINGS_FILE in CONFIG_DIR).
        """

        if path:
            settings = PythonFile(path).run()
            parent = path.parent
            includes = Collection(settings.get(INCLUDE_SETTING))
        else:
            # this is the generic settings file
            parent = self.config_dir
            if not parent.exists():
                # config dir does not exist, create and populate it
                narrate('creating config directory:', str(parent))
                parent.mkdir(mode=0o700, parents=True, exist_ok=True)
                for name, contents in [
                    (SETTINGS_FILE, INITIAL_SETTINGS_FILE_CONTENTS),
                    ('root', INITIAL_ROOT_CONFIG_FILE_CONTENTS),
                    ('home', INITIAL_HOME_CONFIG_FILE_CONTENTS),
                ]:
                    path = parent / name
                    path.write_text(contents)
                    path.chmod(0o600)
                output(
                    f'Configuration directory created: {parent!s}.',
                    'Includes example settings files. Edit them to suit your needs.',
                    'Search for and replace any fields delimited with << and >>.',
                    'Delete any configurations you do not need.',
                    'Generally you will use either home or root, but not both.',
                    sep='\n')
                done()

            path = PythonFile(parent, SETTINGS_FILE)
            settings_filename = path.path
            settings = path.run()

            config = get_config(name, settings, self.composite_config_allowed)
            settings['config_name'] = config
            self.config_name = config
            includes = Collection(settings.get(INCLUDE_SETTING))
            includes = [config] + list(includes.values())

        if settings.get('passphrase'):
            if getmod(path) & 0o077:
                warn("file permissions are too loose.", culprit=path)
                codicil(f"Recommend running: chmod 600 {path!s}")

        self.settings.update(settings)

        for include in includes:
            path = to_path(parent, include)
            self.read(path=path)

        # default src_dirs if not given
        if not self.settings.get('src_dirs'):
            self.settings['src_dirs'] = []

        # default archive if not given
        if 'archive' not in self.settings:
            if not 'prefix' in self.settings:
                self.settings[
                    'prefix'] = '{host_name}-{user_name}-{config_name}-'
            self.settings['archive'] = self.settings['prefix'] + '{{now}}'
예제 #5
0
    def read(self, name=None, path=None):
        """Recursively read configuration files.

        name (str):
            Name of desired configuration. Passed only when reading the top level
            settings file. Default is the default configuration as specified in the
            settings file, or if that is not specified then the first configuration
            given is used.
        path (str):
            Full path to settings file. Should not be given for the top level
            settings file (SETTINGS_FILE in CONFIG_DIR).
        """

        if path:
            settings = PythonFile(path).run()
            parent = path.parent
            includes = Collection(
                settings.get(INCLUDE_SETTING),
                split_lines,
                comment="#",
                strip=True,
                cull=True,
            )
        else:
            # this is the generic settings file
            parent = self.config_dir
            if not parent.exists():
                # config dir does not exist, create and populate it
                narrate("creating config directory:", str(parent))
                parent.mkdir(mode=0o700, parents=True, exist_ok=True)
                for name, contents in [
                    (SETTINGS_FILE, INITIAL_SETTINGS_FILE_CONTENTS),
                    ("root", INITIAL_ROOT_CONFIG_FILE_CONTENTS),
                    ("home", INITIAL_HOME_CONFIG_FILE_CONTENTS),
                ]:
                    path = parent / name
                    path.write_text(contents)
                    path.chmod(0o600)
                output(
                    f"Configuration directory created: {parent!s}.",
                    "Includes example settings files. Edit them to suit your needs.",
                    "Search for and replace any fields delimited with << and >>.",
                    "Delete any configurations you do not need.",
                    "Generally you will use either home or root, but not both.",
                    sep="\n",
                )
                done()

            path = PythonFile(parent, SETTINGS_FILE)
            self.settings_filename = path.path
            settings = path.run()

            config = get_config(name, settings, self.composite_config_response,
                                self.show_config_name)
            settings["config_name"] = config
            self.config_name = config
            includes = Collection(settings.get(INCLUDE_SETTING))
            includes = [config] + list(includes.values())

        if settings.get("passphrase"):
            if getmod(path) & 0o077:
                warn("file permissions are too loose.", culprit=path)
                codicil(f"Recommend running: chmod 600 {path!s}")

        self.settings.update(settings)

        # read include files, if any are specified
        for include in includes:
            path = to_path(parent, include)
            self.read(path=path)
예제 #6
0
def plot_signals():
    try:
        # process command line {{{2
        cmdline = docopt(__doc__, argv=get_argv())
        psf_file = get_psf_filename(cmdline['--psf-file'])
        args = cmdline['<signal>']
        title = cmdline['--title']
        svg_file = cmdline['--svg']
        dB = cmdline['--db']
        mag = cmdline['--mag']
        phase = cmdline['--ph']
        use_cache = not cmdline['--no-cache']
        linestyle = '' if cmdline['--just-points'] else '-'
        marker = '.' if cmdline['--mark-points'] or cmdline['--just-points'] else ''

        # Open PSF file {{{2
        psf = PSF(psf_file, sep=':', use_cache=use_cache)
        sweep = psf.get_sweep()
        to_plot = expand_args(psf.signals.keys(), args)

        # x_name = sweep.name
        if not sweep:
            with Quantity.prefs(map_sf = Quantity.map_sf_to_greek, prec = print_prec):
                to_print = []
                width = 0
                for arg in to_plot:
                    pair = arg.split('-')
                    if len(pair) == 2:
                        psig = psf.get_signal(pair[0])
                        nsig = psf.get_signal(pair[1])
                        if psig.units != nsig.units:
                            warn(
                                f'incompatible units ({psig.units} != {nsig.units}',
                                culprit=arg
                            )
                        units = psig.units
                        access = psig.access
                        y_data = Quantity(psig.ordinate - nsig.ordinate, units)
                        name = f'{access}({psig.name},{nsig.name})'
                    else:
                        sig = psf.get_signal(arg)
                        access = sig.access
                        name = f'{access}({sig.name})'
                        y_data = sig.ordinate
                    to_print.append((name, y_data))
                    width = max(width, len(name))
                for name, y_data in to_print:
                    display(f'{name:>{width+4}} = {y_data}')
                return

        x_units = sweep.units
        x_data = sweep.abscissa
        x_formatter = FuncFormatter(
            lambda v, p: Quantity(v, x_units).render()
        )

        # Process arguments {{{2
        waves = []
        y_units = set()
        for arg in to_plot:
            pair = arg.split('-')
            if len(pair) == 2:
                psig = psf.get_signal(pair[0])
                nsig = psf.get_signal(pair[1])
                name = arg
                if psig.units != nsig.units:
                    warn(
                        f'incompatible units ({psig.units} != {nsig.units}',
                        culprit=arg
                    )
                units = psig.units
                y_data = psig.ordinate - nsig.ordinate
            else:
                sig = psf.get_signal(arg)
                name = arg
                units = sig.units
                y_data = sig.ordinate
            if units == 'Unitless':
                units = ''
            if dB:
                y_data = 20*np.log10(np.absolute(y_data))
                units = 'dB' + units
            elif mag:
                y_data = np.absolute(y_data)
            elif phase:
                y_data = np.angle(y_data, deg=True)
                units = '°'
            elif np.iscomplexobj(y_data):
                y_data = np.absolute(y_data)
            waves.append((name, y_data, units))
            y_units.add(units)
        if not y_units:
            raise Error(f'{plural(args):no match/es}.', culprit=args)

        y_formatters = {
            u: FuncFormatter(
                lambda v, p, u=u: str(Quantity(v, psf.units_to_unicode(u)))
            )
            for u in y_units
        }

        xy_formatters = {}
        x_kind = signal_kinds.get(x_units, x_units)
        for u in y_units:
            y_kind = signal_kinds.get(x_units, u)
            xy_label = f"{x_kind} = {{x}},  {y_kind} = {{y}}"
            units = psf.units_to_unicode(u)
            xy_formatters[u] = lambda x, y: xy_label.format(
                x = Quantity(x, x_units).render(prec=cursor_prec),
                y = Quantity(y, units).render(prec=cursor_prec)
            )

        # Generate the plot {{{2
        if svg_file:
            matplotlib.use('SVG')
        figure, axes = plt.subplots(len(y_units), 1, sharex=True, squeeze=False)
        for i, units in enumerate(y_units):
            for sig_name, y_data, sig_units in waves:
                if sig_units == units:
                    axes[i, 0].plot(
                        x_data, y_data,
                        label = sig_name,
                        marker = marker,
                        linestyle = linestyle,
                        linewidth = 2,
                    )
            axes[i, 0].legend(frameon=False, loc='best')
            axes[i, 0].set_xscale('log' if psf.log_x(sweep) else 'linear')
            axes[i, 0].set_yscale('log' if psf.log_y(sweep) and not dB else 'linear')
            axes[i, 0].xaxis.set_major_formatter(x_formatter)
            axes[i, 0].yaxis.set_major_formatter(y_formatters[units])
            axes[i, 0].format_coord = xy_formatters[units]
        if title:
            plt.suptitle(title)
        if svg_file:
            plt.savefig(svg_file)
        else:
            plt.show()
    except Error as e:
        e.terminate()
    except KeyboardInterrupt:
        done()
예제 #7
0
def main():
    try:
        # Read command line {{{1
        cmdline = docopt(__doc__)
        keys = cmdline["--keys"].split(",") if cmdline["--keys"] else []
        update = cmdline["--update"].split(",") if cmdline["--update"] else []
        skip = cmdline["--skip"].split(",") if cmdline["--skip"] else []
        Inform(
            narrate=cmdline["--narrate"] or cmdline["--verbose"],
            verbose=cmdline["--verbose"],
            logfile=".sshdeploy.log",
            prog_name=False,
            flush=True,
            version=__version__,
        )
        if keys and not cmdline["--trial-run"]:
            fatal(
                "Using the --keys option results in incomplete authorized_keys files.",
                "It may only be used for testing purposes.",
                "As such, --trial-run must also be specified when using --keys.",
                sep="\n",
            )

        # Generated detailed help {{{1
        if cmdline["manual"]:
            from pkg_resources import resource_string

            try:
                Run(cmd=["less"], modes="soeW0", stdin=resource_string("src", "manual.rst").decode("utf8"))
            except OSError as err:
                error(os_error(err))
            terminate()

        # Read config file {{{1
        try:
            config_file = cmdline.get("--config-file")
            config_file = config_file if config_file else "sshdeploy.conf"
            contents = to_path(config_file).read_text()
        except OSError as err:
            fatal(os_error(err))
        code = compile(contents, config_file, "exec")
        config = {}
        try:
            exec(code, config)
        except Exception as err:
            fatal(err)

        # Move into keydir {{{1
        keydir = cmdline["--keydir"]
        keydir = to_path(keydir if keydir else "keys-" + date)
        if cmdline["generate"]:
            comment("creating key directory:", keydir)
            rm(keydir)
            mkdir(keydir)
            cd(keydir)
        elif cmdline["distribute"]:
            cd(keydir)

        # determine default values for key options
        defaults = {}
        for name, default in [
            ("keygen-options", DefaultKeygenOpts),
            ("abraxas-account", DefaultAbraxasAccount),
            ("remote-include-filename", DefaultRemoteIncludeFilename),
        ]:
            defaults[name] = config.get(name, default)

        # Generate keys {{{1
        if cmdline["generate"]:
            for keyname in sorted(config["keys"].keys()):
                data = config["keys"][keyname]
                if keys and keyname not in keys:
                    # user did not request this key
                    continue

                # get default values for missing key options
                for option in defaults:
                    data[option] = data.get(option, defaults[option])

                # generate the key
                key = Key(keyname, data, update, skip, cmdline["--trial-run"])
                key.generate()

        # Publish keys {{{1
        elif cmdline["distribute"]:
            for keyname in sorted(config["keys"].keys()):
                data = config["keys"][keyname]
                if keys and keyname not in keys:
                    continue  # user did not request this key

                # get default values for missing key options
                for option in defaults:
                    data[option] = data.get(option, defaults[option])

                # publish the key pair to clients
                key = Key(keyname, data, update, skip, cmdline["--trial-run"])
                key.publish_private_key()
                key.gather_public_keys()

            # publish authorized_keys files to servers {{{1
            if cmdline["distribute"]:
                for each in sorted(AuthKeys.known):
                    authkey = AuthKeys.known[each]
                    authkey.publish()
                    authkey.verify()

        # Process hosts {{{1
        elif cmdline["test"] or cmdline["clean"] or cmdline["hosts"]:
            hosts = set()
            for keyname, data in config["keys"].items():
                if keys and keyname not in keys:
                    continue  # user did not request this key

                # add servers to list of hosts
                for server, options in data["servers"].items():
                    if update and server not in update or server in skip:
                        continue
                    if "bypass" not in options:
                        hosts.add(server)

                # add clients to list of hosts
                for client in data["clients"].keys():
                    if update and client not in update or client in skip:
                        continue
                    hosts.add(client)

            # process the hosts
            if cmdline["test"]:
                # test host
                for host in sorted(hosts):
                    test_access(host)
            elif cmdline["clean"]:
                # clean host
                for host in sorted(hosts):
                    clean(host)
            else:
                # list hosts
                for host in sorted(hosts):
                    display(host)

    except OSError as err:
        error(os_error(err))
    except KeyboardInterrupt:
        display("Killed by user")
    done()
예제 #8
0
    def read_config(self, name=None, path=None, queue=None):
        """Recursively read configuration files.

        name (str):
            Name of desired configuration. Passed only when reading the top level
            settings file. Default is the default configuration as specified in the
            settings file, or if that is not specified then the first configuration
            given is used.
        path (str):
            Full path to settings file. Should not be given for the top level
            settings file (SETTINGS_FILE in CONFIG_DIR).
        """

        if path:
            # we are reading an include file
            settings = PythonFile(path).run()
            parent = path.parent
            includes = Collection(
                settings.get(INCLUDE_SETTING),
                split_lines,
                comment="#",
                strip=True,
                cull=True,
            )
        else:
            # this is the base-level settings file
            parent = self.config_dir
            if not parent.exists():
                # config dir does not exist, create and populate it
                narrate("creating config directory:", str(parent))
                parent.mkdir(mode=0o700, parents=True, exist_ok=True)
                for fname, contents in [
                    (SETTINGS_FILE, INITIAL_SETTINGS_FILE_CONTENTS),
                    ("root", INITIAL_ROOT_CONFIG_FILE_CONTENTS),
                    ("home", INITIAL_HOME_CONFIG_FILE_CONTENTS),
                ]:
                    path = parent / fname
                    path.write_text(contents)
                    path.chmod(0o600)
                output(
                    f"Configuration directory created: {parent!s}.",
                    "Includes example settings files. Edit them to suit your needs.",
                    "Search for and replace any fields delimited with ⟪ and ⟫.",
                    "Delete any configurations you do not need.",
                    "Generally you will use either home or root, but not both.",
                    sep="\n",
                )
                done()

            # read the shared settings file
            path = PythonFile(parent, SETTINGS_FILE)
            self.settings_filename = path.path
            settings = path.run()

            # initialize the config queue
            if not queue:
                # this is a request through the API
                queue = ConfigQueue()
            if queue.uninitialized:
                queue.initialize(name, settings)
            config = queue.get_active_config()
            self.configs = queue.configs
            self.log_command = queue.log_command

            # save config name
            settings["config_name"] = config
            self.config_name = config
            if not config:
                # this happens on composite configs for commands that do not
                # need access to a specific config, such as help and configs
                self.settings.update(settings)
                return

            # get includes
            includes = Collection(settings.get(INCLUDE_SETTING))
            includes = [config] + list(includes.values())

        if settings.get("passphrase"):
            if getmod(path) & 0o077:
                warn("file permissions are too loose.", culprit=path)
                codicil(f"Recommend running: chmod 600 {path!s}")

        self.settings.update(settings)

        # read include files, if any are specified
        for include in includes:
            path = to_path(parent, include)
            self.read_config(path=path)
예제 #9
0
def test_pardon():
    with messenger() as (msg, stdout, stderr, logfile):
        try:
            terminate()
            assert False
        except SystemExit as e:
            assert e.args == (0,)

        try:
            raise Error('hey now!', culprit='nutz', extra='foo', codicil='putz')
            assert False
        except Error as err:
            assert err.get_message() == 'hey now!'
            assert err.get_culprit() == ('nutz',)
            assert err.get_codicil() == ('putz',)
            assert join_culprit(err.get_culprit()) == 'nutz'
            assert err.extra == 'foo'
            assert str(err) == 'nutz: hey now!'
            assert errors_accrued() == 0  # errors don't accrue until reported

        try:
            raise Error(
                'hey now!',
                culprit=('nutz',  'crunch'),
                extra='foo',
                codicil=('putz',  'toodle'),
            )
            assert False
        except Error as err:
            assert err.get_message() == 'hey now!'
            assert err.get_culprit() == ('nutz', 'crunch')
            assert err.get_codicil() == ('putz', 'toodle')
            assert join_culprit(err.get_culprit()) == 'nutz, crunch'
            assert err.extra == 'foo'
            assert str(err) == 'nutz, crunch: hey now!'
            assert err.get_message() == 'hey now!'
            assert err.get_message('{extra}, {}') == 'foo, hey now!'
            assert err.render() == 'nutz, crunch: hey now!'
            assert err.render('{extra}, {}') == 'nutz, crunch: foo, hey now!'
            assert errors_accrued() == 0  # errors don't accrue until reported
            try:
                err.terminate()
                assert False
            except SystemExit as e:
                assert e.args == (1,)

            try:
                done()
                assert False
            except SystemExit as e:
                assert e.args == (0,)

            try:
                rv = done(exit=False)
                assert rv == 0
            except SystemExit as e:
                assert False

            try:
                terminate()
                assert False
            except SystemExit as e:
                assert e.args == (1,)

            try:
                rv = terminate(exit=False)
                assert rv == 1
            except SystemExit as e:
                assert False

            try:
                rv = terminate(True, exit=False)
                assert rv == 1
            except SystemExit as e:
                assert False

            try:
                rv = terminate('fuxit', exit=False)
                assert rv == 1
            except SystemExit as e:
                assert False

            try:
                rv = terminate(6, exit=False)
                assert rv == 6
            except SystemExit as e:
                assert False

            try:
                terminate_if_errors()
                assert False
            except SystemExit as e:
                assert e.args == (1,)
                assert True

            try:
                rv = terminate_if_errors(exit=False)
                assert rv == 1
            except SystemExit as e:
                assert False

        try:
            raise Error('hey now', culprit=('nutz', 347))
            assert False
        except Error as err:
            assert err.get_message() == 'hey now'
            assert err.get_culprit() == ('nutz', 347)
            assert join_culprit(err.get_culprit()) == 'nutz, 347'
            assert join_culprit(err.get_culprit(66)) == '66, nutz, 347'
            assert join_culprit(err.get_culprit(('a', 'b'))) == 'a, b, nutz, 347'
            assert str(err) == 'nutz, 347: hey now'