aboutsummaryrefslogtreecommitdiffstats
path: root/brutha/output.py
blob: 8ec8e110ffbbbc25958693d8ba5d2d4e0fc8cfde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# -*- coding: utf-8 -*-
from __future__ import division

import subprocess

from brutha.util import require_executable


def pbar(cur, total, color=True):
    "Progress bar"
    if color:
        BRIGHT = '\x1b[1m'
        NORMAL = '\x1b[22m'
    else:
        BRIGHT = ''
        NORMAL = ''
    if total == 0:
        pct = 100
    else:
        pct = int(100 * cur / total)

    bar = (int(pct/10) * '#') + (int(10-pct/10) * ' ')
    return "echo '%s[%s] (%s%%)%s'" % (BRIGHT, bar, pct, NORMAL)


# PRINTERS


def sh(p, commands, echo=False, jobs=None):
    p('#!%s' % require_executable('sh', ['bash', 'zsh', 'dash', 'sh']))
    p('set -eu')
    if echo:
        p('set -x')
    for i, subcommands in enumerate(commands):
        p("\n".join(subcommands))
        if echo:
            p('( set +x ; %s ) 2>/dev/null' % pbar(i+1, len(commands)))
        else:
            p(pbar(i+1, len(commands)))
        p()


def parallel(p, commands, echo=False, jobs=None):
    verbose = ' --verbose' if echo else ''
    jobs = ' --jobs %s' % jobs if jobs else ''
    p('#!%s --shebang --eta%s%s --' % (require_executable('parallel'), jobs, verbose))
    for i, subcommands in enumerate(commands):
        p(" && ".join(subcommands + [pbar(i+1, len(commands))]))


def make(p, commands, echo=False, jobs=None):
    prefix = '' if echo else '@'
    targets = ' '.join('d%s' % i for i in xrange(0, len(commands)))
    p('.PHONY: all %s' % targets)
    p('all: %s' % targets)
    p()
    for i, subcommands in enumerate(commands):
        p('d%s:' % i)
        for subcommand in subcommands:
            p('\t%s%s' % (prefix, subcommand))
        p('\t@%s' % pbar(i+1, len(commands)))


PRINTERS = {'sh': sh, 'parallel': parallel, 'make': make}


# EXECUTORS


def shebang(stream, jobs=None):
    """
    Extracts the shebang (#!) line and runs it, with the script provided as stdin.
    This is known to work at least with bash and GNU parallel.
    """
    stream.seek(0)
    line = stream.readline()
    assert line.startswith('#!')
    shebang = line[2:].split()
    p = subprocess.Popen(shebang, shell=False, stdin=subprocess.PIPE)
    p.communicate(stream.getvalue())
    return p.returncode


def emake(stream, jobs=None):
    if jobs:
        addon = ['-j', str(jobs)]
    else:
        addon = []
    p = subprocess.Popen([require_executable('make', ['gmake', 'make']), '-f', '-'] + addon,
                         shell=False, stdin=subprocess.PIPE)
    p.communicate(stream.getvalue())
    return p.returncode


EXECUTORS = {'sh': shebang, 'parallel': shebang, 'make': emake}