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("__")}
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)
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))
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))
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)
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)
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)
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
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
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))
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))
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)
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
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)
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))
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'))
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()
def title(text): return full_stop(text.capitalize())
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)