def fmt_field(name, value='', key=None, level=0): hl = False # resolve values if isinstance(value, Script): hl = True value = value.script elif cls.is_secret(name, key): reveal = "reveal with: {}".format( HighlightColor( join('avendesora', 'value', cls.get_name(), cls.combine_field(name, key)))) value = ', '.join(cull([value.get_description(), reveal])) elif isinstance(value, (GeneratedSecret, ObscuredSecret)): v = cls.get_scalar(name, key) value = ', '.join(cull([value.get_description(), str(v)])) else: value = str(value) # format values if '\n' in value: value = indent(dedent(value), get_setting('indent')).strip('\n') sep = '\n' elif value: sep = ' ' else: sep = '' if hl: value = HighlightColor(value) name = str(name).replace('_', ' ') leader = level * get_setting('indent') return indent( LabelColor((name if key is None else str(key)) + ':') + sep + value, leader)
def run_borg_raw(self, args): # prepare the command os.environ.update(self.publish_passcode()) os.environ["BORG_DISPLAY_PASSPHRASE"] = "no" executable = self.value("borg_executable", BORG) remote_path = self.value("remote_path") remote_path = ["--remote-path", remote_path] if remote_path else [] repository = str(self.repository) command = ([executable] + remote_path + [a.replace('@repo', repository) for a in args]) # run the command narrate("running:\n{}".format( indent(render_command(command, borg_options_arg_count)))) with cd(self.working_dir): narrate("running in:", cwd()) starts_at = arrow.now() log("starts at: {!s}".format(starts_at)) borg = Run(command, modes="soeW", env=os.environ, log=False) ends_at = arrow.now() log("ends at: {!s}".format(ends_at)) log("elapsed = {!s}".format(ends_at - starts_at)) if borg.stdout: narrate("Borg stdout:") narrate(indent(borg.stdout)) if borg.stderr: narrate("Borg stderr:") narrate(indent(borg.stderr)) if borg.status: narrate("Borg exit status:", borg.status) return borg
def conceal(cls, plaintext, decorate=False, encoding=None, symmetric=False, gpg_ids=None): encoding = encoding if encoding else get_setting('encoding') plaintext = str(plaintext).encode(encoding) if not gpg_ids: gpg_ids = get_setting('gpg_ids', []) if is_str(gpg_ids): gpg_ids = gpg_ids.split() encrypted = cls.gpg.encrypt(plaintext, gpg_ids, armor=True, symmetric=bool(symmetric)) if not encrypted.ok: msg = ' '.join( cull( ['unable to encrypt.', getattr(encrypted, 'stderr', None)])) raise PasswordError(msg) ciphertext = str(encrypted) if decorate: return 'GPG("""\n%s""")' % indent(ciphertext) else: return ciphertext
def to_python(obj, _level=0): """Recursively convert object to string with reasonable formatting""" def leader(relative_level=0): return (_level + relative_level) * ' ' code = [] if type(obj) == dict: code += ['{'] for key in sorted(obj.keys()): value = obj[key] code += [ '%s%r: %s,' % (leader(1), key, to_python(value, _level + 1)) ] code += ['%s}' % (leader(0))] elif type(obj) == list: code += ['['] for each in obj: code += ['%s%s,' % (leader(1), to_python(each, _level + 1))] code += ['%s]' % (leader(0))] elif type(obj) == tuple: code += ['('] for each in obj: code += ['%s%s,' % (leader(1), to_python(each, _level + 1))] code += ['%s)' % (leader(0))] elif type(obj) == set: code += ['set(['] for each in sorted(obj): code += ['%s%s,' % (leader(1), to_python(each, _level + 1))] code += ['%s])' % (leader(0))] elif is_str(obj) and '\n' in obj: code += ['"""' + indent(dedent(obj), leader(1)) + leader(0) + '"""'] else: code += [repr(obj)] return '\n'.join(code)
def run_borg(self, cmd, args='', borg_opts=None, emborg_opts=()): # prepare the command os.environ.update(self.publish_passcode()) os.environ['BORG_DISPLAY_PASSPHRASE'] = 'no' if self.ssh_command: os.environ['BORG_RSH'] = self.ssh_command executable = self.value('borg_executable', BORG) if borg_opts is None: borg_opts = self.borg_options(cmd, emborg_opts) command = ([executable] + cmd.split() + borg_opts + (args.split() if is_str(args) else args)) environ = { k: v for k, v in os.environ.items() if k.startswith('BORG_') } if 'BORG_PASSPHRASE' in environ: environ['BORG_PASSPHRASE'] = '<redacted>' narrate('setting environment variables:', render(environ)) # check if ssh agent is present if self.needs_ssh_agent: for ssh_var in 'SSH_AGENT_PID SSH_AUTH_SOCK'.split(): if ssh_var not in os.environ: warn( 'environment variable not found, is ssh-agent running?', culprit=ssh_var) # run the command narrate('running:\n{}'.format( indent(render_command(command, borg_options_arg_count)))) narrating = 'verbose' in emborg_opts or 'narrate' in emborg_opts modes = 'soeW' if narrating else 'sOEW' return Run(command, modes=modes, stdin='', env=os.environ, log=False)
def format(text): try: if '\n' in text: return '\n' + indent(text, ' ') else: return text except: return text
def run_duplicity(cmd, settings, narrating): os.environ.update(publish_passcode(settings)) for ssh_var in 'SSH_AGENT_PID SSH_AUTH_SOCK'.split(): if ssh_var not in os.environ: warn('environment variable not found, is ssh-agent running?', culprit=ssh_var) narrate('running:\n{}'.format(indent(render_command(cmd)))) modes = 'soeW' if narrating else 'sOEW' Run(cmd, modes=modes, env=os.environ)
def run_borg_raw(self, args): # run the run_before_borg commands self.run_user_commands('run_before_borg') # prepare the command self.publish_passcode() os.environ["BORG_DISPLAY_PASSPHRASE"] = "no" executable = self.value("borg_executable", BORG) remote_path = self.value("remote_path") remote_path = ["--remote-path", remote_path] if remote_path else [] repository = str(self.repository) command = ([executable] + remote_path + [a.replace('@repo', repository) for a in args]) # run the command narrate("running:\n{}".format( indent(render_command(command, borg_options_arg_count)))) with cd(self.working_dir): narrate("running in:", cwd()) starts_at = arrow.now() log("starts at: {!s}".format(starts_at)) try: borg = Run(command, modes="soeW1", env=os.environ, log=False) except Error as e: self.report_borg_error(e, executable) ends_at = arrow.now() log("ends at: {!s}".format(ends_at)) log("elapsed = {!s}".format(ends_at - starts_at)) if borg.status == 1: warn('Warning emitted by Borg, see logfile for details.') if borg.stdout: narrate("Borg stdout:") narrate(indent(borg.stdout)) if borg.stderr: narrate("Borg stderr:") narrate(indent(borg.stderr)) if borg.status: narrate("Borg exit status:", borg.status) return borg
def run_borg_raw(self, args): # prepare the command os.environ.update(self.publish_passcode()) os.environ['BORG_DISPLAY_PASSPHRASE'] = 'no' executable = self.value('borg_executable', BORG) repository = str(self.repository) command = ([executable] + [(repository if a == '@repo' else a) for a in args]) # run the command narrate('running:\n{}'.format( indent(render_command(command, borg_options_arg_count)))) return Run(command, modes='soeW', env=os.environ, log=False)
def display_field(self, account, field): # get string to display value, is_secret, name, desc = tuple(account.get_value(field)) label = '%s (%s)' % (name, desc) if desc else name value = dedent(str(value)).strip() label_color = get_setting('_label_color') # indent multiline outputs sep = ' ' if '\n' in value: if is_secret: warn('secret contains newlines, will not be fully concealed.') value = indent(value, get_setting('indent')).strip('\n') sep = '\n' if label: if label[0] == '_': # hidden field label = '!' + label[1:] text = label_color(label.replace('_', ' ') + ':') + sep + value else: text = value label = field log('Writing to TTY:', label) if is_secret: if Color.isTTY(): # Write only if output is a TTY. This is a security feature. # The ideas is that when the TTY writer is called it is because # the user is expecting the output to go to the tty. This # eliminates the chance that the output can be intercepted and # recorded by replacing Avendesora with an alias or shell # script. If the user really want the output to go to something # other than the TTY, the user should use the --stdout option. try: cursor.write(text) cursor.conceal() sleep(get_setting('display_time')) except KeyboardInterrupt: pass cursor.reveal() cursor.clear() else: error('output is not a TTY.') codicil( 'Use --stdout option if you want to send secret', 'to a file or a pipe.' ) else: output(text)
def command_briefs(self): """ Return a nicely formatted list of all the subcommands installed on this system, to incorporate into the usage text. """ from stepwise import tabulate from inform import indent rows = [ [f'{name}:', getattr(app, 'brief', 'No summary.')] for name, app in self.commands.items() ] table = tabulate(rows, truncate='-x', max_width=-4) return indent(table, leader=' ', first=-1)
def fail(self, *msg, cmd='<unknown>'): msg = join(*msg) try: msg = msg.decode('ascii', errors='replace') except AttributeError: pass try: if self.notify and not Color.isTTY(): Run( [ "mail", "-s", f"{PROGRAM_NAME} failed on {username}@{hostname}" ] + self.notify.split(), stdin=dedent(f"""\ {PROGRAM_NAME} fails. command: {cmd} config: {self.config_name} source: {username}@{fullhostname}:{', '.join(str(d) for d in self.src_dirs)} destination: {self.repository!s} error message: """) + indent(msg) + "\n", modes="soeW", encoding="ascii", ) except Error: pass try: notifier = self.settings.get("notifier") # don't use self.value as we don't want arguments expanded yet if notifier and not Color.isTTY(): Run(self.notifier.format( cmd=cmd, msg=msg, hostname=hostname, user_name=username, prog_name=PROGRAM_NAME, ), modes="SoeW" # need to use the shell as user will generally quote msg ) except Error: pass except KeyError as e: warn("unknown key.", culprit=(self.settings_file, "notifier", e))
def render(self, fmts=('{f} ({d}): {v}', '{f}: {v}')): """Return value formatted as a string. Args: fmts (collection of strings): *fmts* contains a sequence of format strings that are tried in sequence. The first one for which all keys are known is used. The possible keys are: | n -- name (identifier for the first level of a field) | k -- key (identifier for the second level of a field) | f -- field (name.key) | d -- description | v -- value If none work, the value alone is returned. Returns: The value rendered as a string. """ value = str(self.value) if '\n' in value: value = '\n' + indent(dedent(value), get_setting('indent')).strip('\n') if is_str(fmts): fmts = fmts, # build list of arguments, deleting any that is not set args = { k: v for k, v in [('f', self.field), ('k', self.key), ( 'n', self.name), ('d', self.desc), ('v', value)] if v } # format the arguments, use first format sting that works for fmt in fmts: try: return fmt.format(**args) except KeyError: pass # nothing worked, just return the value return value
def conceal(cls, plaintext, decorate=False, encoding=None, symmetric=False): encoding = encoding if encoding else get_setting('encoding') plaintext = str(plaintext).encode(encoding) gpg_ids = get_setting('gpg_ids', []) if is_str(gpg_ids): gpg_ids = gpg_ids.split() encrypted = cls.gpg.encrypt( plaintext, gpg_ids, armor=True, symmetric=bool(symmetric) ) if not encrypted.ok: msg = ' '.join(cull([ 'unable to encrypt.', getattr(encrypted, 'stderr', None) ])) raise Error(msg) ciphertext = str(encrypted) if decorate: return 'GPG("""\n%s""")' % indent(ciphertext) else: return ciphertext
def run_borg_raw(self, args): # prepare the command os.environ.update(self.publish_passcode()) os.environ['BORG_DISPLAY_PASSPHRASE'] = 'no' executable = self.value('borg_executable', BORG) remote_path = self.value('remote_path') remote_path = ['--remote-path', remote_path] if remote_path else [] repository = str(self.repository) command = ([executable] + remote_path + [(repository if a == '@repo' else a) for a in args]) # run the command narrate('running:\n{}'.format( indent(render_command(command, borg_options_arg_count)))) starts_at = arrow.now() narrate('starts at: {!s}'.format(starts_at)) borg = Run(command, modes='soeW', env=os.environ, log=False) ends_at = arrow.now() narrate('ends at: {!s}'.format(ends_at)) narrate('elapsed = {!s}'.format(ends_at - starts_at)) return borg
def run_borg( self, cmd, args=(), borg_opts=None, emborg_opts=(), strip_prefix=False, show_borg_output=False, use_working_dir=False, ): # prepare the command os.environ.update(self.publish_passcode()) os.environ["BORG_DISPLAY_PASSPHRASE"] = "no" if self.ssh_command: os.environ["BORG_RSH"] = self.ssh_command executable = self.value("borg_executable", BORG) borg_opts = self.borg_options(cmd, borg_opts, emborg_opts, strip_prefix) command = [executable] + cmd.split() + borg_opts + args environ = { k: v for k, v in os.environ.items() if k.startswith("BORG_") } if "BORG_PASSPHRASE" in environ: environ["BORG_PASSPHRASE"] = "<redacted>" narrate("Borg-related environment variables:", render(environ)) # check if ssh agent is present if self.needs_ssh_agent: if "SSH_AUTH_SOCK" not in os.environ: warn( "SSH_AUTH_SOCK environment variable not found.", "Is ssh-agent running?", ) # run the command narrate("running:\n{}".format( indent(render_command(command, borg_options_arg_count)))) with cd(self.working_dir if use_working_dir else "."): narrate("running in:", cwd()) starts_at = arrow.now() log("starts at: {!s}".format(starts_at)) narrating = (show_borg_output or "--verbose" in borg_opts or "verbose" in emborg_opts or "narrate" in emborg_opts) and "--json" not in command if narrating: modes = "soeW" display("\nRunning Borg {} command ...".format(cmd)) else: modes = "sOEW" try: borg = Run(command, modes=modes, stdin="", env=os.environ, log=False) except Error as e: e.reraise(culprit=f"borg {cmd}") ends_at = arrow.now() log("ends at: {!s}".format(ends_at)) log("elapsed = {!s}".format(ends_at - starts_at)) if borg.stdout: narrate("Borg stdout:") narrate(indent(borg.stdout)) if borg.stderr: narrate("Borg stderr:") narrate(indent(borg.stderr)) if borg.status: narrate("Borg exit status:", borg.status) return borg
def run_borg( self, cmd, args=(), borg_opts=None, emborg_opts=(), strip_prefix=False, show_borg_output=False, use_working_dir=False, ): # run the run_before_borg commands self.run_user_commands('run_before_borg') # prepare the command self.publish_passcode() if "BORG_PASSPHRASE" in os.environ: os.environ["BORG_DISPLAY_PASSPHRASE"] = "no" if self.ssh_command: os.environ["BORG_RSH"] = self.ssh_command environ = { k: v for k, v in os.environ.items() if k.startswith("BORG_") } if "BORG_PASSPHRASE" in environ: environ["BORG_PASSPHRASE"] = "<redacted>" executable = self.value("borg_executable", BORG) borg_opts = self.borg_options(cmd, borg_opts, emborg_opts, strip_prefix) command = [executable] + cmd.split() + borg_opts + args narrate("Borg-related environment variables:", render(environ)) # check if ssh agent is present if self.needs_ssh_agent: if "SSH_AUTH_SOCK" not in os.environ: warn( "SSH_AUTH_SOCK environment variable not found.", "Is ssh-agent running?", ) # run the command narrate("running:\n{}".format( indent(render_command(command, borg_options_arg_count)))) with cd(self.working_dir if use_working_dir else "."): narrate("running in:", cwd()) if "--json" in command or "--json-lines" in command: narrating = False else: narrating = (show_borg_output or "--verbose" in borg_opts or "--progress" in borg_opts or "verbose" in emborg_opts or "narrate" in emborg_opts) if narrating: modes = "soeW1" display("\nRunning Borg {} command ...".format(cmd)) else: modes = "sOEW1" starts_at = arrow.now() log("starts at: {!s}".format(starts_at)) try: borg = Run(command, modes=modes, stdin="", env=os.environ, log=False) except Error as e: self.report_borg_error(e, cmd) finally: # remove passcode env variables created by emborg if self.borg_passcode_env_var_set_by_emborg: narrate( f"Unsetting {self.borg_passcode_env_var_set_by_emborg}." ) del os.environ[self.borg_passcode_env_var_set_by_emborg] ends_at = arrow.now() log("ends at: {!s}".format(ends_at)) log("elapsed = {!s}".format(ends_at - starts_at)) if borg.status: narrate("Borg exit status:", borg.status) if borg.status == 1 and borg.stderr: warnings = borg.stderr.partition(72 * '-')[0] warn('Warning emitted by Borg:', codicil=warnings) if borg.stdout: narrate("Borg stdout:") narrate(indent(borg.stdout)) if borg.stderr: narrate("Borg stderr:") narrate(indent(borg.stderr)) return borg
def get_expected(self): if "\n" in self.expected: expected = "\n" + indent(self.expected, stops=2) else: expected = self.expected return dict(exit_status=self.expected_exit_status, output=expected)
def get_result(self): if "\n" in self.result: result = "\n" + indent(self.result, stops=2) else: result = self.result return dict(exit_status=self.exit_status, output=result)