Пример #1
0
    def run(self):
        self.ActivePythonFile = self.path
        path = self.path
        narrate("reading:", path)
        try:
            self.code = self.read()
            # need to save the code for the new command
        except OSError as err:
            raise Error(os_error(err))

        try:
            compiled = compile(self.code, str(path), "exec")
        except SyntaxError as err:
            culprit = (err.filename, err.lineno)
            if err.text is None or err.offset is None:
                raise Error(full_stop(err.msg), culprit=culprit)
            else:
                raise Error(
                    err.msg + ":",
                    err.text.rstrip(),
                    (err.offset - 1) * " " + "^",
                    culprit=culprit,
                    sep="\n",
                )

        contents = {}
        try:
            exec(compiled, contents)
        except Exception as err:
            from .utilities import error_source

            raise Error(full_stop(err), culprit=error_source())
        self.ActivePythonFile = None
        # strip out keys that start with '__' and return them
        return {k: v for k, v in contents.items() if not k.startswith("__")}
Пример #2
0
    def get_account(name):
        canonical = canonicalize(name)
        try:
            return Account._accounts[canonical]
        except KeyError:
            # account not found, assemble message giving suggested account names
            names = Account._accounts.keys()
            candidates = get_close_matches(canonical, names, 9, 0.6)

            # do not want to give multiple options all of which are aliases for
            # the same accounts, so look for up to three unique accounts
            close_matches = []
            for candidate in candidates:
                account = Account._accounts[candidate]
                if account not in close_matches:
                    close_matches.append(account)
                if len(close_matches) >= 3:
                    break

            # add the aliases to be base account names if available
            offer = []
            for account in close_matches:
                aliases = getattr(account, 'aliases', None)
                if aliases:
                    offer.append('{} ({})'.format(account.get_name(),
                                                  ', '.join(aliases)))
                else:
                    offer.append(account.get_name())

            # generate the message handling 0, 1, 2 or 3 candidates gracefully
            msg = 'account not found'
            if offer:
                msg = '{}, did you mean:\n    {}?'.format(
                    msg, conjoin(offer, sep=',\n    ', conj=', or\n    '))
            raise PasswordError(full_stop(msg), culprit=name)
Пример #3
0
 def signal_start(self):
     url = f'{self.url}/{self.uuid}/start'
     log(f'signaling start of backups to {self.NAME}: {url}.')
     try:
         requests.post(url)
     except requests.exceptions.RequestException as e:
         raise Error('{self.NAME} connection error.', codicil=full_stop(e))
Пример #4
0
 def signal_start(self):
     url = self.START_URL.format(url=self.url, uuid=self.uuid)
     log(f'signaling start of backups to {self.NAME}: {url}.')
     try:
         requests.get(url)
     except requests.exceptions.RequestException as e:
         raise Error(f'{self.NAME} connection error.', codicil=full_stop(e))
Пример #5
0
 def fail(self, *msg, comment=''):
     msg = full_stop(' '.join(str(m) for m in msg))
     try:
         if self.notify:
             Run(['mail', '-s', f'{PROGRAM_NAME} on {hostname}: {msg}'] +
                 self.notify.split(),
                 stdin=dedent(f'''
                     {msg}
                     {comment}
                     config = {self.config_name}
                     source = {username}@{hostname}:{', '.join(str(d) for d in self.src_dirs)}
                     destination = {self.repository}
                 ''').lstrip(),
                 modes='soeW')
     except Error:
         pass
     try:
         if self.notifier:
             Run(self.notifier.format(
                 msg=msg,
                 hostname=hostname,
                 user_name=username,
                 prog_name=PROGRAM_NAME,
             ),
                 modes='soeW')
     except Error:
         pass
     except KeyError as e:
         warn('unknown key.', culprit=(self.settings_file, 'notifier', e))
     raise Error(msg)
Пример #6
0
def report(message, line, *args, colno=None, **kwargs):
    message = full_stop(message)
    culprits = get_culprit()
    if culprits:
        kwargs['source'] = culprits[0]
    if line:
        kwargs['culprit'] = get_culprit(line.lineno)
        if colno is not None:
            # build codicil that shows both the line and the preceding line
            if line.prev_line is not None:
                codicil = [
                    f'{line.prev_line.lineno:>4} «{line.prev_line.text}»'
                ]
            else:
                codicil = []
            codicil += [
                f'{line.lineno:>4} «{line.text}»',
                '      ' + (colno * ' ') + '▲',
            ]
            kwargs['codicil'] = '\n'.join(codicil)
            kwargs['colno'] = colno
        else:
            kwargs['codicil'] = f'{line.lineno:>4} «{line.text}»'
        kwargs['line'] = line.text
        kwargs['lineno'] = line.lineno
        if line.prev_line:
            kwargs['prev_line'] = line.prev_line.text
    else:
        kwargs['culprit'] = culprits  # pragma: no cover
    raise NestedTextError(template=message, *args, **kwargs)
Пример #7
0
 def fail(self, *msg, comment=''):
     msg = full_stop(' '.join(str(m) for m in msg))
     try:
         if self.notify:
             Run(['mail', f'-s "{PROGRAM_NAME}: {msg}"', self.notify],
                 stdin=dedent(f'''
                     {msg}
                     {comment}
                     config = {self.config_name}
                     source = {hostname}:{self.src_dir}
                     destination = {self.dest_server}:{self.dest_dir}
                 ''').lstrip(),
                 modes='soeW')
     except OSError as e:
         pass
     try:
         if self.notifier:
             Run(self.notifier.format(
                 msg=msg,
                 host_name=hostname,
                 user_name=username,
                 prog_name=PROGRAM_NAME,
             ),
                 modes='soeW')
     except OSError as e:
         pass
     except KeyError as e:
         warn('unknown key.', culprit=(self.settings_file, 'notifier', e))
     raise Error(msg)
Пример #8
0
 def reveal(cls, ciphertext, encoding=None):
     decrypted = cls.gpg.decrypt(dedent(ciphertext))
     if not decrypted.ok:
         msg = 'unable to decrypt argument to GPG()'
         try:
             msg = '%s: %s' % (msg, decrypted.stderr)
         except AttributeError:
             pass
         raise Error(full_stop(msg))
     plaintext = str(decrypted)
     return plaintext
Пример #9
0
 def reveal(cls, ciphertext, encoding=None):
     decrypted = cls.gpg.decrypt(dedent(ciphertext))
     if not decrypted.ok:
         msg = 'unable to decrypt argument to GPG()'
         try:
             msg = '%s: %s' % (msg, decrypted.stderr)
         except AttributeError:
             pass
         raise PasswordError(full_stop(msg))
     plaintext = str(decrypted)
     return plaintext
Пример #10
0
 def signal_end(self, exception):
     if exception:
         url = self.FAIL_URL.format(url=self.url, uuid=self.uuid)
         result = 'failure'
     else:
         url = self.SUCCESS_URL.format(url=self.url, uuid=self.uuid)
         result = 'success'
     log(f'signaling {result} of backups to {self.NAME}: {url}.')
     try:
         response = requests.get(url)
     except requests.exceptions.RequestException as e:
         raise Error('{self.NAME} connection error.', codicil=full_stop(e))
Пример #11
0
 def get_summary(self):
     summary = ["Network is", self.network.Name()]
     network_desc = self.network.description
     if network_desc:
         summary.append("({})".format(network_desc))
     if self.location:
         summary.append("located near {}".format(self.location))
     if ports.available_ports:
         summary.append("using port {}".format(
             conjoin([str(port) for port in ports.available_ports],
                     " or ")))
     if self.proxy:
         summary.append("proxying through {}".format(self.proxy))
     return full_stop(" ".join(summary))
Пример #12
0
    def run(cls, command, args, settings, options):
        # read command line
        cmdline = docopt(cls.USAGE, argv=[command] + args)
        name = cmdline["<name>"]

        # display summary
        display(full_stop(settings.get_summary()))
        display()

        # display host
        settings.read_hosts()
        try:
            display(settings.hosts.hosts_by_name[name])
        except KeyError:
            raise Error("not found.", culprit=name)
Пример #13
0
    def run(self):
        global ActivePythonFile
        ActivePythonFile = self.path
        path = self.path
        self.encrypted = path.suffix in ['.gpg', '.asc']
        narrate('reading.', culprit=path)
        try:
            self.code = self.read()
            # need to save the code for the new command
        except OSError as e:
            raise PasswordError(os_error(e))

        try:
            compiled = compile(self.code, str(path), 'exec')
        except SyntaxError as e:
            culprit = (e.filename, e.lineno)
            if e.text is None or e.offset is None:
                raise PasswordError(full_stop(e.msg), culprit=culprit)
            else:
                raise PasswordError(e.msg + ':',
                                    e.text.rstrip(),
                                    (e.offset - 1) * ' ' + '^',
                                    culprit=culprit,
                                    sep='\n')
                # File "/home/ken/.config/avendesora/config", line 18
                #   'c': 'google-chrome %s'
                #      ^

        contents = {}
        try:
            exec(compiled, contents)
        except Exception as e:
            from .utilities import error_source
            raise PasswordError(full_stop(e), culprit=error_source())
        ActivePythonFile = None
        return contents
Пример #14
0
    def run(cls, command, args, settings, options):
        # read command line
        docopt(cls.USAGE, argv=[command] + args)

        # display summary
        display(full_stop(settings.get_summary()))

        # initialize the network
        settings.initialize_network()
        # initializing the network must be done before reading the hosts
        # file as it may try to do network operations

        # create SSH config file components
        # header
        name = settings.network.Name()
        desc = settings.network.description
        if desc:
            network = f"{name} network -- {desc}"
        else:
            network = f"{name} network"
        now = arrow.now()
        time = now.format(DATE_FORMAT)
        header = SSH_HEADER.format(network=network,
                                   time=time,
                                   config_dir=settings.config_dir)

        # overrides
        overrides = settings.ssh_overrides
        if overrides:
            overrides = SSH_OVERRIDES.format(overrides=overrides)

        # hosts
        settings.read_hosts()
        hosts = SSH_HOSTS.format(hosts=settings.hosts.output())

        # defaults
        defaults = settings.ssh_defaults
        if defaults:
            defaults = SSH_DEFAULTS.format(defaults=defaults)

        # combine everything and write as SSH config file
        contents = "\n\n\n".join(
            section.strip()
            for section in [header, overrides, hosts, defaults] if section)
        settings.write_ssh_config(contents)
Пример #15
0
    def signal_end(self, exception):
        if exception:
            result = 'failure'
            status = exception.status
            payload = exception.stderr
        else:
            result = 'success'
            status = 0
            payload = ''

        url = f'{self.url}/{self.uuid}/{status}'
        log(f'signaling {result} of backups to {self.NAME}: {url}.')
        try:
            if payload:
                response = requests.post(url, data=payload.encode('utf-8'))
            else:
                response = requests.post(url)
        except requests.exceptions.RequestException as e:
            raise Error('{self.NAME} connection error.', codicil=full_stop(e))
Пример #16
0
 def read(self):
     path = self.path
     # file is only assumed to be encrypted if path has gpg extension
     if path.suffix.lower() in GPG_EXTENSIONS:
         try:
             with path.open('rb') as f:
                 decrypted = self.gpg.decrypt_file(f)
                 if not decrypted.ok:
                     msg = ' '.join(
                         cull([
                             'unable to decrypt.',
                             getattr(decrypted, 'stderr', None)
                         ]))
                     raise PasswordError(msg, culprit=path, sep='\n')
         except ValueError as e:
             raise PasswordError(full_stop(e), culprit=path)
         except OSError as e:
             raise PasswordError(os_error(e))
         return decrypted.data.decode(get_setting('encoding'))
     else:
         return path.read_text(encoding=get_setting('encoding'))
Пример #17
0
    def save(self, contents, gpg_ids=None):
        path = self.path
        if not gpg_ids:
            gpg_ids = get_setting('gpg_ids', [])
        if is_str(gpg_ids):
            gpg_ids = gpg_ids.split()
        if not gpg_ids:
            # raise PasswordError('must specify GPG ID.')
            log('no gpg id available, using symmetric encryption.')

        use_gpg, use_armor = self._choices()
        if use_gpg:
            try:
                encoded = contents.encode(get_setting('encoding'))
                if gpg_ids:
                    encrypted = self.gpg.encrypt(encoded,
                                                 gpg_ids,
                                                 armor=use_armor)
                else:
                    encrypted = self.gpg.encrypt(encoded,
                                                 None,
                                                 symmetric='AES256',
                                                 armor=use_armor)
                if not encrypted.ok:
                    msg = ' '.join(
                        cull([
                            'unable to encrypt.',
                            getattr(encrypted, 'stderr', None)
                        ]))
                    raise PasswordError(msg, culprit=path, sep='\n')
                else:
                    path.write_bytes(encrypted.data)
            except ValueError as e:
                raise PasswordError(full_stop(e), culprit=path)
        else:
            path.write_text(contents, encoding=get_setting('encoding'))
        self.chmod()
Пример #18
0
def title(text):
    return full_stop(text.capitalize())
Пример #19
0
import nestedtext as nt
from voluptuous import Schema, Coerce, Invalid
from inform import fatal, full_stop
from pprint import pprint

schema = Schema({
    'debug': Coerce(bool),
    'secret_key': str,
    'allowed_hosts': [str],
    'database': {
        'engine': str,
        'host': str,
        'port': Coerce(int),
        'user': str,
    },
    'webmaster_email': str,
})
try:
    keymap = {}
    raw = nt.load('deploy.nt', keymap=keymap)
    config = schema(raw)
except nt.NestedTextError as e:
    e.terminate()
except Invalid as e:
    kind = 'key' if 'key' in e.msg else 'value'
    loc = keymap[tuple(e.path)]
    fatal(full_stop(e.msg), culprit=e.path, codicil=loc.as_line(kind))

pprint(config)