Exemple #1
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()
Exemple #2
0
def main():
    with Inform(error_status=2, flush=True, version=version) as inform:
        # read command line
        cmdline = docopt(expanded_synopsis, options_first=True, version=version)
        config = cmdline["--config"]
        command = cmdline["<command>"]
        args = cmdline["<args>"]
        if cmdline["--mute"]:
            inform.mute = True
        if cmdline["--quiet"]:
            inform.quiet = True
        emborg_opts = cull(
            [
                "verbose" if cmdline["--verbose"] else "",
                "narrate" if cmdline["--narrate"] else "",
                "dry-run" if cmdline["--dry-run"] else "",
                "no-log" if cmdline["--no-log"] else "",
            ]
        )
        if cmdline["--narrate"]:
            inform.narrate = True

        try:
            # find the command
            cmd, cmd_name = Command.find(command)

            # execute the command initialization
            exit_status = cmd.execute_early(cmd_name, args, None, emborg_opts)
            if exit_status is not None:
                terminate(exit_status)

            worst_exit_status = 0
            try:
                while True:
                    with Settings(config, cmd, emborg_opts) as settings:
                        try:
                            exit_status = cmd.execute(
                                cmd_name, args, settings, emborg_opts
                            )
                        except Error as e:
                            settings.fail(e, cmd=' '.join(sys.argv))
                            e.terminate()

                    if exit_status and exit_status > worst_exit_status:
                        worst_exit_status = exit_status
            except NoMoreConfigs:
                pass

            # execute the command termination
            exit_status = cmd.execute_late(cmd_name, args, None, emborg_opts)
            if exit_status and exit_status > worst_exit_status:
                worst_exit_status = exit_status

        except KeyboardInterrupt:
            display("Terminated by user.")
        except Error as e:
            e.terminate()
        except OSError as e:
            fatal(os_error(e))
        terminate(worst_exit_status)
Exemple #3
0
def main():
    with Inform() as inform:
        # read command line
        cmdline = docopt(
            __doc__.format(commands=Command.summarize()),
            options_first=True
        )
        config = cmdline['--config']
        command = cmdline['<command>']
        args = cmdline['<args>']
        options = cull([
            'verbose' if cmdline['--verbose'] else '',
            'narrate' if cmdline['--narrate'] else '',
            'trial-run' if cmdline['--trial-run'] else '',
        ])
        if cmdline['--narrate']:
            inform.narrate = True

        try:
            cmd, name = Command.find(command)

            with Settings(config, cmd.REQUIRES_EXCLUSIVITY) as settings:
                cmd.execute(name, args, settings, options)

        except KeyboardInterrupt:
            display('Terminated by user.')
        except Error as err:
            err.terminate()
        except OSError as err:
            fatal(os_error(err))
        terminate()
Exemple #4
0
def test_anglicize(capsys):
    Inform(colorscheme=None, prog_name=False)
    ppp()
    out, err = capsys.readouterr()
    assert out == dedent('''
        DEBUG: test_debug.py, 17, tests.test_debug.test_anglicize()
    ''').lstrip()
Exemple #5
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()
Exemple #6
0
def test_bartender(capsys):
    Inform(colorscheme=None, prog_name=False)
    b = 'b'
    ret = aaa(b)
    out, err = capsys.readouterr()
    assert out == dedent('''
        DEBUG: test_debug.py, 155, tests.test_debug.test_bartender(): 'b'
    ''').lstrip()
    assert ret == 'b'
Exemple #7
0
def test_grouch(capsys):
    Inform(colorscheme=None, prog_name=False)
    a = 0
    b = 'b'
    ppp('hey now!', a, b)
    out, err = capsys.readouterr()
    assert out == dedent('''
        DEBUG: test_debug.py, 27, tests.test_debug.test_grouch(): hey now! 0 b
    ''').lstrip()
Exemple #8
0
def test_prude(capsys):
    Inform(colorscheme=None, prog_name=False)
    Info(email='*****@*****.**')
    out, err = capsys.readouterr()
    assert out == dedent('''
        DEBUG: test_debug.py, 76, tests.test_debug.Info.__init__():
            email = '*****@*****.**'
            self = Info object containing {'email': '*****@*****.**'}
    ''').lstrip()
Exemple #9
0
def main():
    with Inform(error_status=2, flush=True, version=version) as inform:
        # read command line
        cmdline = docopt(expanded_synopsis, options_first=True, version=version)
        config = cmdline['--config']
        command = cmdline['<command>']
        args = cmdline['<args>']
        if cmdline['--mute']:
            inform.mute = True
        if cmdline['--quiet']:
            inform.quiet = True
        options = cull([
            'verbose' if cmdline['--verbose'] else '',
            'narrate' if cmdline['--narrate'] else '',
            'trial-run' if cmdline['--trial-run'] else '',
            'no-log' if cmdline['--no-log'] else '',
        ])
        if cmdline['--narrate']:
            inform.narrate = True

        try:
            # find the command
            cmd, cmd_name = Command.find(command)

            # execute the command initialization
            exit_status = cmd.execute_early(cmd_name, args, None, options)
            if exit_status is not None:
                terminate(exit_status)

            worst_exit_status = 0
            try:
                while True:
                    with Settings(config, cmd, options) as settings:
                        try:
                            exit_status = cmd.execute(cmd_name, args, settings, options)
                        except Error as e:
                            settings.fail(e)
                            e.terminate()

                    if exit_status and exit_status > worst_exit_status:
                        worst_exit_status = exit_status
            except NoMoreConfigs:
                pass

            # execute the command termination
            exit_status = cmd.execute_late(cmd_name, args, None, options)
            if exit_status and exit_status > worst_exit_status:
                worst_exit_status = exit_status

        except KeyboardInterrupt:
            display('Terminated by user.')
        except Error as e:
            e.terminate()
        except OSError as e:
            fatal(os_error(e))
        terminate(worst_exit_status)
Exemple #10
0
 def test_prostrate(capsys):
     Inform(colorscheme=None, prog_name=False)
     sss()
     out, err = capsys.readouterr()
     out = out.strip().split('\n')
     assert out[
         0] == 'DEBUG: test_debug.py, 129, tests.test_debug.test_prostrate():'
     assert out[-2][
         -57:] == "inform/tests/test_debug.py', line 124, in test_prostrate,"
     assert out[-1] == '        sss()'
Exemple #11
0
def messenger(*args, **kwargs):
    stdout = StringIO()
    stderr = StringIO()
    logfile = StringIO()
    with Inform(
        *args, stdout=stdout, stderr=stderr, prog_name=False, logfile=logfile,
        **kwargs
    ) as msg:
        yield msg, stdout, stderr, logfile
    stdout.close()
    stderr.close()
    logfile.close()
Exemple #12
0
def test_run_ground():
    Inform(prog_name=False, logfile=False)
    set_prefs(use_inform=True)
    cmd = './test_prog 1'
    try:
        p = Run(cmd, 'sOEW')
        assert False, 'expected exception'
    except Error as e:
        assert str(e) == 'this is stderr.'
        assert e.cmd == './test_prog 1'
        assert e.stdout == 'this is stdout.'
        assert e.stderr == 'this is stderr.'
        assert e.status == 1
        assert e.msg == 'this is stderr.'
    set_prefs(use_inform=False)
Exemple #13
0
    def test_rubber(capsys):
        Inform(colorscheme=None, prog_name=False)
        a = aaa('a')
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 138, tests.test_debug.test_rubber(): 'a'
        ''').lstrip()
        assert a == 'a'

        b = aaa(b='b')
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 145, tests.test_debug.test_rubber(): b: 'b'
        ''').lstrip()
        assert b == 'b'
Exemple #14
0
def test_run_ground():
    with cd(wd):
        Inform(prog_name=False, logfile=False)
        set_prefs(use_inform=True)
        cmd = "./test_prog 1"
        try:
            Run(cmd, "sOEW")
            assert False, "expected exception"
        except Error as e:
            assert str(e) == "this is stderr."
            assert e.cmd == "./test_prog 1"
            assert e.stdout == "this is stdout."
            assert e.stderr == "this is stderr."
            assert e.status == 1
            assert e.msg == "this is stderr."
        set_prefs(use_inform=False)
Exemple #15
0
def test_shear(capsys):
    Inform(colorscheme=None, prog_name=False)
    if sys.version_info >= (3, 6):
        a = 0
        b = 'b'
        c = [a, b]
        d = {a, b}
        e = {a: b}
        vvv(a, b, c, d, e)
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 116, tests.test_debug.test_shear():
                a = 0
                b = 'b'
                c = [0, 'b']
                d = {0, 'b'}
                e = {0: 'b'}
        ''').lstrip()

    def test_prostrate(capsys):
        Inform(colorscheme=None, prog_name=False)
        sss()
        out, err = capsys.readouterr()
        out = out.strip().split('\n')
        assert out[
            0] == 'DEBUG: test_debug.py, 129, tests.test_debug.test_prostrate():'
        assert out[-2][
            -57:] == "inform/tests/test_debug.py', line 124, in test_prostrate,"
        assert out[-1] == '        sss()'

    def test_rubber(capsys):
        Inform(colorscheme=None, prog_name=False)
        a = aaa('a')
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 138, tests.test_debug.test_rubber(): 'a'
        ''').lstrip()
        assert a == 'a'

        b = aaa(b='b')
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 145, tests.test_debug.test_rubber(): b: 'b'
        ''').lstrip()
        assert b == 'b'
Exemple #16
0
def test_composite(capsys):
    with Inform(prog_name=False):
        pw = PasswordGenerator()
        account = pw.get_account('mybank')
        accounts = account.get_composite('accounts')
        assert accounts == dict(checking='12345678',
                                savings='23456789',
                                creditcard='34567890')
        questions = account.get_composite('questions')
        assert questions == [
            'scallywag bedbug groupie', 'assay centrist fanatic',
            'shunt remnant burrow'
        ]
        pin = account.get_composite('pin')
        assert pin == '9982'
        name = account.get_composite('NAME')
        assert name == 'mybank'
        nada = account.get_composite('nada')
        assert nada == None
Exemple #17
0
def test_update(capsys):
    Inform(colorscheme=None, prog_name=False)
    if sys.version_info >= (3, 6):
        a = 0
        b = 'b'
        c = [a, b]
        d = {a, b}
        e = {a: b}
        vvv()
        out, err = capsys.readouterr()
        out = '\n'.join(l for l in out.split('\n') if 'capsys' not in l)
        assert out == dedent('''
            DEBUG: test_debug.py, 96, tests.test_debug.test_update():
                a = 0
                b = 'b'
                c = [0, 'b']
                d = {0, 'b'}
                e = {0: 'b'}
        ''').lstrip()
Exemple #18
0
def test_daiquiri(capsys):
    Inform(colorscheme=None, prog_name=False)
    if sys.version_info >= (3, 6):
        a = 0
        b = 'b'
        c = [a, b]
        d = {a, b}
        e = {a: b}
        ddd(s='hey now!', a=a, b=b, c=c, d=d, e=e)
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 61, tests.test_debug.test_daiquiri():
                a = 0
                b = 'b'
                c = [0, 'b']
                d = {0, 'b'}
                e = {0: 'b'}
                s = 'hey now!'
        ''').lstrip()
Exemple #19
0
def test_salver(capsys):
    Inform(colorscheme=None, prog_name=False)
    if sys.version_info >= (3, 6):
        a = 0
        b = 'b'
        c = [a, b]
        d = {a, b}
        e = {a: b}
        ddd('hey now!', a, b, c, d, e)
        out, err = capsys.readouterr()
        assert out == dedent('''
            DEBUG: test_debug.py, 41, tests.test_debug.test_salver():
                'hey now!'
                0
                'b'
                [0, 'b']
                {0, 'b'}
                {0: 'b'}
        ''').lstrip()
Exemple #20
0
def test_archive(capsys):
    from avendesora import Hidden, OTP, Question, RecognizeTitle, Script
    from inform import render
    with Inform(prog_name=False):
        pw = PasswordGenerator()
        account = pw.get_account('mybank')
        archive = account.archive()
        expected = dict(
            accounts=dict(checking=Hidden('MTIzNDU2Nzg='),
                          creditcard=Hidden('MzQ1Njc4OTA='),
                          savings=Hidden('MjM0NTY3ODk=')),
            aliases='mb'.split(),
            birthdate=Hidden('MTk4MS0xMC0wMQ==', is_secret=False),
            checking=Script('{accounts.checking}'),
            comment=dedent('''
                This is a multiline comment.
                It spans more than one line.
            '''),
            customer_service='1-866-229-6633',
            discovery=RecognizeTitle('easy peasy', script='lemon squeezy'),
            email='*****@*****.**',
            passcode=Hidden('b1UkJHcwVU1YZTc0'),
            pin=Hidden('OTk4Mg=='),
            questions=[
                Question('What city were you born in?',
                         answer=Hidden('c2NhbGx5d2FnIGJlZGJ1ZyBncm91cGll')),
                Question('What street did you grow up on?',
                         answer=Hidden('YXNzYXkgY2VudHJpc3QgZmFuYXRpYw==')),
                Question('What was your childhood nickname?',
                         answer=Hidden('c2h1bnQgcmVtbmFudCBidXJyb3c='))
            ],
            urls='https://mb.com',
            username='******',
            verbal=Hidden('Zml6emxlIGxlb3BhcmQ='))
        #with open('expected', 'w') as f:
        #    f.write(render(expected, sort=True))
        #with open('result', 'w') as f:
        #    f.write(render(archive, sort=True))
        assert render(archive, sort=True) == render(expected, sort=True)
Exemple #21
0
def test_summary(capsys):
    try:
        with Inform(prog_name=False):
            pw = PasswordGenerator()
            account = pw.get_account('mybank')
            stdout, stderr = capsys.readouterr()
            assert stdout == ''
            assert stderr == ''
            account.write_summary(sort=True)
            stdout, stderr = capsys.readouterr()
            assert stderr == ''
            assert stdout == dedent('''
                names: mybank, mb
                accounts:
                    checking: reveal with: avendesora value mybank accounts.checking
                    savings: reveal with: avendesora value mybank accounts.savings
                    creditcard: reveal with: avendesora value mybank accounts.creditcard
                birthdate: 1981-10-01
                checking: {accounts.checking}
                comment:
                    This is a multiline comment.
                    It spans more than one line.
                customer service: 1-866-229-6633
                email: [email protected]
                passcode: reveal with: avendesora value mybank passcode
                pin: reveal with: avendesora value mybank pin
                questions:
                    0: What city were you born in?, reveal with: avendesora value mybank questions.0
                    1: What street did you grow up on?, reveal with: avendesora value mybank questions.1
                    2: What was your childhood nickname?, reveal with: avendesora value mybank questions.2
                urls: https://mb.com
                username: pizzaman
                verbal: reveal with: avendesora value mybank verbal
            ''').lstrip()
    except PasswordError as err:
        assert str(err) == None
Exemple #22
0
def main():
    with Inform(error_status=2, flush=True, version=version) as inform:
        # read command line
        cmdline = docopt(expanded_synopsis, options_first=True, version=version)
        config = cmdline['--config']
        command = cmdline['<command>']
        args = cmdline['<args>']
        if cmdline['--mute']:
            inform.mute = True
        options = cull([
            'verbose' if cmdline['--verbose'] else '',
            'narrate' if cmdline['--narrate'] else '',
            'trial-run' if cmdline['--trial-run'] else '',
            'no-log' if cmdline['--no-log'] else '',
        ])
        if cmdline['--narrate']:
            inform.narrate = True

        try:
            cmd, cmd_name = Command.find(command)

            with Settings(config, cmd.REQUIRES_EXCLUSIVITY, options) as settings:
                try:
                    exit_status = cmd.execute(cmd_name, args, settings, options)
                except Error as e:
                    settings.fail(e)
                    e.terminate(True)

        except KeyboardInterrupt:
            display('Terminated by user.')
            exit_status = 0
        except Error as e:
            e.terminate()
        except OSError as e:
            fatal(os_error(e))
        terminate(exit_status)
Exemple #23
0
def main():
    version = f'{__version__} ({__released__})'
    cmdline = docopt(__doc__, version=version)
    quiet = cmdline['--quiet']
    problem = False
    with Inform(flush=True, quiet=quiet, version=version) as inform:

        # read the settings file
        settings_file = PythonFile(CONFIG_DIR, OVERDUE_FILE)
        settings_filename = settings_file.path
        settings = settings_file.run()

        # gather needed settings
        default_maintainer = settings.get('default_maintainer')
        default_max_age = settings.get('default_max_age', 28)
        dumper = settings.get('dumper', f'{getusername()}@{gethostname()}')
        repositories = settings.get('repositories')
        root = settings.get('root')

        # process repositories table
        backups = []
        if is_str(repositories):
            for line in repositories.split('\n'):
                line = line.split('#')[0].strip()  # discard comments
                if not line:
                    continue
                backups.append([c.strip() for c in line.split('|')])
        else:
            for each in repositories:
                backups.append([
                    each.get('host'),
                    each.get('path'),
                    each.get('maintainer'),
                    each.get('max_age')
                ])

        def send_mail(recipient, subject, message):
            if cmdline['--mail']:
                display(f'Reporting to {recipient}.\n')
                mail_cmd = ['mailx', '-r', dumper, '-s', subject, recipient]
                Run(mail_cmd, stdin=message, modes='soeW0')

        # check age of repositories
        now = arrow.now()
        display(f'current time = {now}')
        for host, path, maintainer, max_age in backups:
            maintainer = default_maintainer if not maintainer else maintainer
            max_age = int(max_age) if max_age else default_max_age
            try:
                path = to_path(root, path)
                if not path.is_dir():
                    raise Error('does not exist or is not a directory.',
                                culprit=path)
                paths = list(path.glob('index.*'))
                if not paths:
                    raise Error('no sentinel file found.', culprit=path)
                if len(paths) > 1:
                    raise Error('too many sentinel files.',
                                *paths,
                                sep='\n    ')
                path = paths[0]
                mtime = arrow.get(path.stat().st_mtime)
                delta = now - mtime
                age = 24 * delta.days + delta.seconds / 3600
                report = age > max_age
                display(
                    dedent(f"""
                    HOST: {host}
                        sentinel file: {path!s}
                        last modified: {mtime}
                        since last change: {age:0.1f} hours
                        maximum age: {max_age} hours
                        overdue: {report}
                """))

                if report:
                    problem = True
                    subject = f"backup of {host} is overdue"
                    msg = overdue_message.format(host=host, path=path, age=age)
                    send_mail(maintainer, subject, msg)
            except OSError as e:
                problem = True
                msg = os_error(e)
                error(msg)
                if maintaner:
                    send_mail(maintainer, f'{get_prog_name()} error',
                              error_message.format(msg))
            except Error as e:
                problem = True
                e.report()
                if maintaner:
                    send_mail(maintainer, f'{get_prog_name()} error',
                              error_message.format(str(e)))
        terminate(problem)
Exemple #24
0
#!/usr/bin/env python3
"""
Wetlab protocols that follow the Unix philosophy.
"""

__version__ = '0.27.0'

from .protocol import *
from .reaction import *
from .quantity import *
from .format import *
from .library import *
from .printer import *
from .config import *
from .errors import *

from pathlib import Path
from inform import Inform

Inform(stream_policy='header')


class Builtins:
    protocol_dir = Path(__file__).parent / 'builtins'
    priority = 0
Exemple #25
0
def main():
    version = f"{__version__} ({__released__})"
    cmdline = docopt(__doc__, version=version)
    quiet = cmdline["--quiet"]
    problem = False
    use_color = Color.isTTY() and not cmdline["--no-color"]
    passes = Color("green", enable=use_color)
    fails = Color("red", enable=use_color)
    if cmdline["--verbose"]:
        overdue_message = verbose_overdue_message
    else:
        overdue_message = terse_overdue_message

    # prepare to create logfile
    log = to_path(DATA_DIR, OVERDUE_LOG_FILE) if OVERDUE_LOG_FILE else False
    if log:
        data_dir = to_path(DATA_DIR)
        if not data_dir.exists():
            try:
                # data dir does not exist, create it
                data_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
            except OSError as e:
                warn(os_error(e))
                log = False

    with Inform(flush=True, quiet=quiet, logfile=log, version=version):

        # read the settings file
        try:
            settings_file = PythonFile(CONFIG_DIR, OVERDUE_FILE)
            settings = settings_file.run()
        except Error as e:
            e.terminate()

        # gather needed settings
        default_maintainer = settings.get("default_maintainer")
        default_max_age = settings.get("default_max_age", 28)
        dumper = settings.get("dumper", f"{username}@{hostname}")
        repositories = settings.get("repositories")
        root = settings.get("root")

        # process repositories table
        backups = []
        if is_str(repositories):
            for line in repositories.split("\n"):
                line = line.split("#")[0].strip()  # discard comments
                if not line:
                    continue
                backups.append([c.strip() for c in line.split("|")])
        else:
            for each in repositories:
                backups.append([
                    each.get("host"),
                    each.get("path"),
                    each.get("maintainer"),
                    each.get("max_age"),
                ])

        def send_mail(recipient, subject, message):
            if cmdline["--mail"]:
                if cmdline['--verbose']:
                    display(f"Reporting to {recipient}.\n")
                mail_cmd = ["mailx", "-r", dumper, "-s", subject, recipient]
                Run(mail_cmd, stdin=message, modes="soeW0")

        # check age of repositories
        for host, path, maintainer, max_age in backups:
            maintainer = default_maintainer if not maintainer else maintainer
            max_age = float(max_age) if max_age else default_max_age
            try:
                path = to_path(root, path)
                if path.is_dir():
                    paths = list(path.glob("index.*"))
                    if not paths:
                        raise Error("no sentinel file found.", culprit=path)
                    if len(paths) > 1:
                        raise Error("too many sentinel files.",
                                    *paths,
                                    sep="\n    ")
                    path = paths[0]
                mtime = arrow.get(path.stat().st_mtime)
                delta = now - mtime
                age = 24 * delta.days + delta.seconds / 3600
                report = age > max_age
                overdue = ' -- overdue' if report else ''
                color = fails if report else passes
                if report or not cmdline["--no-passes"]:
                    display(color(fmt(overdue_message)))

                if report:
                    problem = True
                    subject = f"backup of {host} is overdue"
                    msg = fmt(mail_overdue_message)
                    send_mail(maintainer, subject, msg)
            except OSError as e:
                problem = True
                msg = os_error(e)
                error(msg)
                if maintainer:
                    send_mail(
                        maintainer,
                        f"{get_prog_name()} error",
                        error_message.format(msg),
                    )
            except Error as e:
                problem = True
                e.report()
                if maintainer:
                    send_mail(
                        maintainer,
                        f"{get_prog_name()} error",
                        error_message.format(str(e)),
                    )
        terminate(problem)
Exemple #26
0
def main():
    with Inform(
            error_status=2,
            flush=True,
            logfile=LoggingCache(),
            prog_name='emborg',
            version=version,
    ) as inform:

        # read command line
        cmdline = docopt(expanded_synopsis,
                         options_first=True,
                         version=version)
        config = cmdline["--config"]
        command = cmdline["<command>"]
        args = cmdline["<args>"]
        if cmdline["--mute"]:
            inform.mute = True
        if cmdline["--quiet"]:
            inform.quiet = True
        if cmdline["--relocated"]:
            os.environ['BORG_RELOCATED_REPO_ACCESS_IS_OK'] = 'YES'
        emborg_opts = cull([
            "verbose" if cmdline["--verbose"] else "",
            "narrate" if cmdline["--narrate"] else "",
            "dry-run" if cmdline["--dry-run"] else "",
            "no-log" if cmdline["--no-log"] else "",
        ])
        if cmdline["--narrate"]:
            inform.narrate = True

        Hooks.provision_hooks()
        worst_exit_status = 0

        try:
            # find the command
            cmd, cmd_name = Command.find(command)

            # execute the command initialization
            exit_status = cmd.execute_early(cmd_name, args, None, emborg_opts)
            if exit_status is not None:
                terminate(exit_status)

            queue = ConfigQueue(cmd)
            while queue:
                with Settings(config, emborg_opts, queue) as settings:
                    try:
                        exit_status = cmd.execute(cmd_name, args, settings,
                                                  emborg_opts)
                    except Error as e:
                        exit_status = 2
                        settings.fail(e, cmd=' '.join(sys.argv))
                        e.terminate()

                if exit_status and exit_status > worst_exit_status:
                    worst_exit_status = exit_status

            # execute the command termination
            exit_status = cmd.execute_late(cmd_name, args, None, emborg_opts)
            if exit_status and exit_status > worst_exit_status:
                worst_exit_status = exit_status

        except KeyboardInterrupt:
            display("Terminated by user.")
        except Error as e:
            e.report()
            exit_status = 2
        except OSError as e:
            exit_status = 2
            error(os_error(e))
        if exit_status and exit_status > worst_exit_status:
            worst_exit_status = exit_status
        terminate(worst_exit_status)
Exemple #27
0
def main():
    version = f'{__version__} ({__released__})'
    cmdline = docopt(__doc__, version=version)
    quiet = cmdline['--quiet']
    problem = False
    use_color = Color.isTTY() and not cmdline['--no-color']
    passes = Color('green', enable=use_color)
    fails = Color('red', enable=use_color)

    # prepare to create logfile
    log = to_path(DATA_DIR, OVERDUE_LOG_FILE) if OVERDUE_LOG_FILE else False
    if log:
        data_dir = to_path(DATA_DIR)
        if not data_dir.exists():
            try:
                # data dir does not exist, create it
                data_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
            except OSError as e:
                warn(os_error(e))
                log = False

    with Inform(flush=True, quiet=quiet, logfile=log, version=version):

        # read the settings file
        try:
            settings_file = PythonFile(CONFIG_DIR, OVERDUE_FILE)
            settings = settings_file.run()
        except Error as e:
            e.terminate()

        # gather needed settings
        default_maintainer = settings.get('default_maintainer')
        default_max_age = settings.get('default_max_age', 28)
        dumper = settings.get('dumper', f'{username}@{hostname}')
        repositories = settings.get('repositories')
        root = settings.get('root')

        # process repositories table
        backups = []
        if is_str(repositories):
            for line in repositories.split('\n'):
                line = line.split('#')[0].strip()  # discard comments
                if not line:
                    continue
                backups.append([c.strip() for c in line.split('|')])
        else:
            for each in repositories:
                backups.append([
                    each.get('host'),
                    each.get('path'),
                    each.get('maintainer'),
                    each.get('max_age')
                ])

        def send_mail(recipient, subject, message):
            if cmdline['--mail']:
                display(f'Reporting to {recipient}.\n')
                mail_cmd = ['mailx', '-r', dumper, '-s', subject, recipient]
                Run(mail_cmd, stdin=message, modes='soeW0')

        # check age of repositories
        for host, path, maintainer, max_age in backups:
            maintainer = default_maintainer if not maintainer else maintainer
            max_age = float(max_age) if max_age else default_max_age
            try:
                path = to_path(root, path)
                if path.is_dir():
                    paths = list(path.glob('index.*'))
                    if not paths:
                        raise Error('no sentinel file found.', culprit=path)
                    if len(paths) > 1:
                        raise Error('too many sentinel files.',
                                    *paths,
                                    sep='\n    ')
                    path = paths[0]
                mtime = arrow.get(path.stat().st_mtime)
                delta = now - mtime
                age = 24 * delta.days + delta.seconds / 3600
                report = age > max_age
                color = fails if report else passes
                if report or not cmdline['--no-passes']:
                    display(
                        color(
                            dedent(f"""
                        HOST: {host}
                            sentinel file: {path!s}
                            last modified: {mtime}
                            since last change: {age:0.1f} hours
                            maximum age: {max_age} hours
                            overdue: {report}
                    """).lstrip()))

                if report:
                    problem = True
                    subject = f"backup of {host} is overdue"
                    msg = overdue_message.format(host=host, path=path, age=age)
                    send_mail(maintainer, subject, msg)
            except OSError as e:
                problem = True
                msg = os_error(e)
                error(msg)
                if maintainer:
                    send_mail(maintainer, f'{get_prog_name()} error',
                              error_message.format(msg))
            except Error as e:
                problem = True
                e.report()
                if maintainer:
                    send_mail(maintainer, f'{get_prog_name()} error',
                              error_message.format(str(e)))
        terminate(problem)