This commit is contained in:
2019-09-15 22:29:09 -04:00
parent 20680f93c1
commit 047028f9f0
7 changed files with 161 additions and 39 deletions
+12 -4
View File
@@ -22,12 +22,19 @@ class FilterNotAvailable(ValueError):
pass
class TaskFilter:
class BaseAction:
@property
def is_filter(self):
if not hasattr(self, "_chunk_index"):
return True
class TaskFilter(BaseAction):
def __init__(self, s):
self.source = s
def __str__(self):
return f"{self.source!r}"
return f"{self.source}"
@property
def name(self):
@@ -64,6 +71,7 @@ class TaskFilter:
user_value = click.prompt(f" What is {int1} times {int2}?")
if int(user_value) != int1 * int2:
click.echo("Aborted!", err=True)
sys.exit(1)
else:
@@ -74,7 +82,7 @@ class TaskFilter:
self.execute_confirm(yes=yes, **self.arguments)
class TaskScript:
class TaskScript(BaseAction):
def __init__(self, bashfile, chunk_index=None):
self.bashfile = bashfile
self._chunk_index = chunk_index
@@ -86,7 +94,7 @@ class TaskScript:
return f"<TaskScript name={self.name!r} depends_on={self.depends_on(recursive=True)!r}>"
def __str__(self):
return f"{self.name!r}"
return f"{self.name}"
@property
def declaration_line(self):
+72 -29
View File
@@ -1,9 +1,15 @@
import sys
import click
import crayons
import json
from .bakefile import Bakefile
from .config import config
from .clint import eng_join
import pygments
import pygments.lexers
import pygments.formatters
SAFE_ENVIRONS = ["HOME", "PATH"]
@@ -12,6 +18,17 @@ def indent(line):
return f'{" " * 4}{line}'
def echo_json(obj):
_json = json.dumps(obj, indent=2)
if sys.stdin.isatty():
_json = pygments.highlight(
_json, pygments.lexers.JsonLexer(), pygments.formatters.TerminalFormatter()
)
click.echo(_json, err=False)
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
@click.argument(
"task",
@@ -69,16 +86,23 @@ def indent(line):
# multiple=True,
# help="task ARGV argument (can be passed multiple times).",
)
@click.option("--no-color", is_flag=True, type=click.BOOL, help="Disable colors.")
@click.option("--silent", "-s", is_flag=True, type=click.BOOL, help="Reduce output.")
@click.option(
"--environ-json",
"-j",
"-e",
nargs=1,
type=click.STRING,
help="environment variables, in JSON format.",
)
def task(
@click.option(
"--json",
"-j",
"_json",
is_flag=True,
type=click.BOOL,
help="Output in JSON format (stdout).",
)
def entrypoint(
*,
task,
bakefile,
@@ -90,15 +114,15 @@ def task(
debug,
silent,
insecure,
no_color,
allow,
_json,
yes,
):
"""bake — the familiar Bash/Make hybrid."""
# Default to list behavior, when no task is provided.
if no_color:
crayons.DISABLE_COLOR = True
if _json:
silent = True
SAFE_ENVIRONS.extend(allow)
@@ -133,14 +157,14 @@ def task(
argv.append(argument)
if debug:
click.echo(f" + argv: {argv!r}")
click.echo(f" + environ: {environ!r}")
click.echo(f" + argv: {argv!r}", err=True)
click.echo(f" + environ: {environ!r}", err=True)
for env in environ:
key, value = env
if debug:
click.echo(
f" + Setting environ: {crayons.red(key)} {crayons.white('=')} {value}.",
f" + Setting environ: {click.style(key, fg='red')} {click.style('=', fg='white')} {value}.",
err=True,
)
bakefile.add_environ(key, value)
@@ -148,29 +172,56 @@ def task(
bakefile.add_args(*argv)
if _list:
for task in bakefile.tasks:
print(f" - {task}")
__list_json = {"tasks": {}}
for _task in bakefile.tasks:
depends_on = bakefile[_task].depends_on(recursive=True)
if depends_on:
deps = []
for dep in depends_on:
if dep.is_filter:
dep = click.style(str(dep), fg="yellow")
deps.append(str(dep))
deps = f"\n {click.style('+', fg='yellow', bold=True)} {eng_join(deps)}."
else:
deps = ""
colon = "" if not deps else ""
__list_json["tasks"].update(
{_task: {"depends_on": [str(d) for d in depends_on]}}
)
if not silent:
click.echo(
f" {click.style('-', fg='green', bold=True)} {click.style(_task, bold=True)}{colon}{deps}",
err=True,
)
if _json:
echo_json(__list_json)
sys.exit(0)
if task:
try:
task = bakefile[task]
except KeyError:
click.echo(crayons.red(f"Task {task} does not exist!"))
click.echo(click.style(f"Task {task} does not exist!", fg="red"))
sys.exit(1)
def execute_task(task, *, next_task=None, silent=False):
if not silent:
click.echo(
crayons.white(" + ")
+ crayons.yellow(f"Executing {task}")
+ crayons.white(":")
click.style(" + ", fg="white")
+ click.style(f"Executing {task}", fg="yellow")
+ click.style(":", fg="white"),
err=True,
)
return_code = task.execute(yes=yes, next_task=next_task, silent=silent)
if not _continue:
if not return_code == 0:
click.echo(f"Task {task} failed!")
click.echo(f"Task {task} failed!", err=True)
sys.exit(return_code)
tasks = task.depends_on(recursive=True) + [task]
@@ -184,21 +235,13 @@ def task(
if not silent:
click.echo(
crayons.white(" + ") + crayons.green("Done") + crayons.white(".")
click.style(" + ", fg="white")
+ click.style("Done", fg="green")
+ click.style(".", fg="white"),
err=True,
)
sys.exit(0)
def entrypoint():
try:
main()
except KeyboardInterrupt:
print("ool beans.")
def main():
task()
if __name__ == "__main__":
entrypoint()
+44
View File
@@ -0,0 +1,44 @@
COMMA = ","
CONJUNCTION = "and"
SPACE = " "
NEWLINES = ("\n", "\r", "\r\n")
MAX_WIDTHS = []
def tsplit(string, delimiters):
"""Behaves str.split but supports tuples of delimiters."""
delimiters = tuple(delimiters)
if len(delimiters) < 1:
return [string]
final_delimiter = delimiters[0]
for i in delimiters[1:]:
string = string.replace(i, final_delimiter)
return string.split(final_delimiter)
def eng_join(l, conj=CONJUNCTION, separator=COMMA):
"""Joins lists of words. Oxford comma and all."""
collector = []
left = len(l)
separator = separator + SPACE
conj = conj + SPACE
for _l in l[:]:
left += -1
collector.append(_l)
if left == 1:
if len(l) == 2:
collector.append(SPACE)
else:
collector.append(separator)
collector.append(conj)
elif left is not 0:
collector.append(separator)
return str().join(collector)
+2
View File
@@ -1,5 +1,7 @@
import os
os.environ["PYTHONUNBUFFERED"] = "1"
import pytest
import delegator
+5
View File
@@ -1,2 +1,7 @@
kinda-dangerous: @confirm
echo 'success1'
really-dangerous: @confirm:secure
echo 'success2'
mostly-harmless: kinda-dangerous
mostly-dangerous: really-dangerous
+25 -5
View File
@@ -1,10 +1,30 @@
def test_confirm(bake):
c = bake("kinda-dangerous", fixture="2", block=False)
# c.expect("?", "Y")
# c.block()
assert "kenneth" in c.out
c.expect(":", timeout=0.5)
c.send("N\n")
c.block()
assert "Aborted!" in c.out
def test_confirm_secure(bake):
c = bake("kinda-dangerous", fixture="2", block=False)
c.expect
c = bake("really-dangerous", fixture="2", block=False)
c.expect(":", timeout=0.5)
c.send("4222\n")
c.block()
assert "Aborted!" in c.out
def test_confirm_dep(bake):
c = bake("mostly-harmless", fixture="2", block=False)
c.expect(":", timeout=0.5)
c.send("N\n")
c.block()
assert "Aborted!" in c.out
def test_confirm_secure(bake):
c = bake("mostly-dangerous", fixture="2", block=False)
c.expect(":", timeout=0.5)
c.send("4222\n")
c.block()
assert "Aborted!" in c.out
+1 -1
View File
@@ -21,7 +21,7 @@ REQUIRES_PYTHON = ">=3.6.0"
VERSION = "0.1.0"
# What packages are required for this module to be executed?
REQUIRED = ["click", "delegator.py", "crayons", "appdirs"]
REQUIRED = ["click", "delegator.py", "pygments", "appdirs"]
# What packages are optional?
EXTRAS = {