This commit is contained in:
2019-09-23 05:33:09 -04:00
parent 9815dcb06a
commit 210c16a420
20 changed files with 334 additions and 25 deletions
+7 -5
View File
@@ -27,13 +27,14 @@ class Bakefile:
if not os.path.exists(path):
raise NoBakefileFound()
self.cache = Cache(bf=self, debug=self.debug)
self.skip_cache = Cache(bf=self, namespace="skips", debug=self.debug)
self.env_cache = Cache(bf=self, namespace="env.allowed", debug=self.debug)
# Set environment variables for 'bake's that run underneath of us.
os.environ["BAKE_SKIP_DONE"] = "1"
os.environ["BAKE_SILENT"] = "1"
os.environ["PYTHONUNBUFFERED"] = "1"
os.environ["BAKEFILE_PATH"] = self.path
os.environ["BAKEFILE"] = self.path
self.chunks
self._tasks = None
@@ -141,6 +142,7 @@ class Bakefile:
root=os.getcwd(),
max_depth=4,
topdown=False,
**kwargs,
):
"""Returns the path of a Bakefile in parent directories."""
@@ -149,7 +151,7 @@ class Bakefile:
if i > max_depth:
break
elif filename in f:
return Class(path=os.path.join(c, filename))
return Class(path=os.path.join(c, filename), **kwargs)
i += 1
raise NoBakefileFound(f"No {filename} found!")
@@ -347,13 +349,13 @@ class TaskFilter(BaseAction):
return
key = sha256(key.encode("utf-8")).hexdigest()
old_hash = str(self.bf.cache[key])
old_hash = str(self.bf.skip_cache[key])
# Get the current filestate hashsum.
with open(key_path, "r") as f:
current_hash = sha256(f.read().encode("utf-8")).hexdigest()
self.bf.cache[key] = current_hash
self.bf.skip_cache[key] = current_hash
if old_hash == current_hash:
self.do_skip = True
+8 -5
View File
@@ -11,11 +11,12 @@ class Cache:
prefix = PREFIX
seperator = SEPERATOR
def __init__(self, *, bf, debug=False, enabled=True):
def __init__(self, *, bf, namespace="hashes", debug=False, enabled=True):
self.bf = bf
self.enabled = enabled
self.debug = debug
self.namespace = namespace
try:
# Assert git exists, and appears functioning.
@@ -46,7 +47,7 @@ class Cache:
return f"<Cache enabled={self.enabled}>"
def _key_for_hashes(self, key):
return self.seperator.join((self.prefix, "hashes", key))
return self.seperator.join((self.prefix, self.namespace, key))
def clear(self):
for key in self:
@@ -65,8 +66,9 @@ class Cache:
c = delegator.run(cmd)
for result in c.out.split("\n"):
if result.startswith(self.prefix):
print(result.split("=", -1)[0])
yield result.split("=", -1)[0]
yield result.split("=", -1)[0][
len(self.prefix + "." + self.namespace + ".") :
]
def __getitem__(self, k):
key = self._key_for_hashes(k)
@@ -92,7 +94,8 @@ class Cache:
return c.ok
def __delitem__(self, k):
cmd = f"git config --local --unset {k}"
key = self._key_for_hashes(k)
cmd = f"git config --local --unset {key}"
if self.debug:
click.echo(f" {click.style('$', fg='green')} {cmd}", err=True)
+24 -11
View File
@@ -82,7 +82,7 @@ def echo_json(obj):
"--bakefile",
"-b",
default="__BAKEFILE__",
envvar="BAKEFILE_PATH",
envvar="BAKEFILE",
nargs=1,
type=click.Path(),
help="The Bakefile to use.",
@@ -95,7 +95,13 @@ def echo_json(obj):
help="Lists available tasks (and their dependencies).",
)
@click.option(
"--clear-cache", default=False, is_flag=True, help="Clears the cache (e.g. @skip)."
"--clear-skips", default=False, is_flag=True, help="Clears the skip cache."
)
@click.option(
"--clear-envs",
default=False,
is_flag=True,
help="Clears the allowed environment variable cache.",
)
@click.option(
"--levels",
@@ -114,7 +120,6 @@ def echo_json(obj):
"--allow",
default=False,
nargs=1,
multiple=True,
hidden=False,
help="Whitelist an environment variable for use.",
)
@@ -189,7 +194,8 @@ def entrypoint(
allow,
_json,
no_deps,
clear_cache,
clear_skips,
clear_envs,
interactive,
yes,
help,
@@ -204,9 +210,6 @@ def entrypoint(
if _json or source:
silent = True
# Allow explicitlypassed environment variables.
SAFE_ENVIRONS.extend(allow)
# Enable list functionality, by default.
if task == "__LIST_ALL__":
_list = True
@@ -215,9 +218,9 @@ def entrypoint(
# Establish the Bakefile.
try:
bf = (
Bakefile.find(root=".", filename="Bakefile")
Bakefile.find(root=".", filename="Bakefile", debug=debug)
if bakefile == "__BAKEFILE__"
else Bakefile(path=bakefile)
else Bakefile(path=bakefile, debug=debug)
)
except NoBakefileFound:
@@ -225,12 +228,22 @@ def entrypoint(
do_help(1)
sys.exit(0)
if allow:
bf.env_cache[allow] = 1
# Clear the cache, if asked to do so.
if clear_envs:
bf.env_cache.clear()
# Allow explicitlypassed environment variables.
SAFE_ENVIRONS.extend([g.upper() for g in bf.env_cache])
if debug:
click.echo(f" + Bakefile: {bf.path}", err=True)
# Clear the cache, if asked to do so.
if clear_cache:
bf.cache.clear()
if clear_skips:
bf.skip_cache.clear()
# --source (internal API)
if source:
+1 -1
View File
@@ -9,7 +9,7 @@ SAFE_ENVIRONS = [
"USER",
"TERM",
"VIRTUAL_ENV",
"BAKEFILE_PATH",
"BAKEFILE",
"PYTHONUNBUFFERED",
"PYTHONDONTWRITEBYTECODE",
"BAKE_SILENT",
+2 -1
View File
@@ -1,6 +1,7 @@
import sys
import click
from click.utils import strip_ansi
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
@@ -13,4 +14,4 @@ def entrypoint(s, *, err):
s = s.rstrip()
click.echo(s)
click.echo(strip_ansi(s))
+8 -2
View File
@@ -12,18 +12,24 @@ colorama.init(strip=False)
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
@click.argument("s", type=click.STRING, default=False, required=False)
@click.option(
"--read-stderr", is_flag=True, type=click.BOOL, default=True, help="Read stderr."
"--read-stderr", is_flag=True, type=click.BOOL, default=False, help="Read stderr."
)
@click.option(
"--no-color", is_flag=True, type=click.BOOL, default=False, help="Read stderr."
)
@click.option("--char", nargs=1, type=click.STRING, default="+", help="Prefix char.")
@click.option(
"--color", nargs=1, type=click.STRING, default="yellow", help="Color to use."
)
def entrypoint(s, *, char, read_stderr, color):
def entrypoint(s, *, char, read_stderr, no_color, color):
pipe = sys.stdin if not read_stderr else sys.stderr
if s is False:
s = pipe.read()
if no_color:
color = "NOTACOLOR"
for line in s.strip().split("\n"):
try:
title = str(click.style(line, fg=color))
+8
View File
@@ -0,0 +1,8 @@
timeout() {
time=$1
command="/bin/sh -c \"$2\""
expect -c "set echo \"-noecho\"; set timeout $time; spawn -noecho $command; expect timeout { exit 0 } eof { exit 1 }"
}
export timeout
+4
View File
@@ -0,0 +1,4 @@
argv:
set -u
echo "${@}"
echo "${KEY}"
+15
View File
@@ -0,0 +1,15 @@
@test "arguments don't work (set -u)" {
run bake -b args.Bakefile argv
[ "${status}" -eq 1 ]
}
@test "arguments do work [argv]" {
run bake --silent -b args.Bakefile argv 1 2 KEY=VALUE 3
[[ "${lines[0]}" == *"1 2 3"* ]]
}
@test "arguments do work [environ]" {
run bake --silent -b args.Bakefile argv 1 2 KEY=VALUE 3
[[ "${lines[1]}" == *"VALUE"* ]]
}
+18
View File
@@ -0,0 +1,18 @@
//two:
one/two/three/four:
one/two/:
echo:
echo ${1}
echo/dep: dep
bake echo ${1} | red
dep:
echo 'Installing dep…'
exit 0
fail:
exit 1
deps/fail: fail
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bats
@test "bake --h" {
run bake -b basics.Bakefile --help
[ "${lines[0]}" = "Usage: [OPTIONS] [TASK] [ARGUMENTS]..." ]
}
@test "bake --help" {
run bake -b basics.Bakefile --help
[ "${lines[0]}" = "Usage: [OPTIONS] [TASK] [ARGUMENTS]..." ]
}
@test "bake --json" {
run bake -b basics.Bakefile --json
[ "${#lines[@]}" -eq 23 ]
}
@test "bake --json --levels 0" {
run bake -b basics.Bakefile --json --levels 0
[ "${#lines[@]}" -eq 3 ]
}
@test "bake --levels 0" {
run bake -b basics.Bakefile --levels 0
[ "${lines[0]}" = "" ]
}
@test "bake --levels 1" {
run bake -b basics.Bakefile --levels 1
[ "${#lines[@]}" -eq 4 ]
}
@test "bake --levels 2" {
run bake -b basics.Bakefile --levels 3
[ "${#lines[@]}" -eq 10 ]
}
@test "bake --levels 3" {
run bake -b basics.Bakefile --levels 3
[ "${#lines[@]}" -eq 10 ]
}
@test "bake --levels 4" {
run bake -b basics.Bakefile --levels 4
[ "${#lines[@]}" -eq 10 ]
}
@test "bake fails on 'exit 1'" {
run bake -b basics.Bakefile fail
[ "${status}" -eq 1 ]
}
@test "bake fails on subtask 'exit 1'" {
run bake -b basics.Bakefile deps/fail
[ "${status}" -eq 1 ]
}
@test "bake runs tasks" {
run bake -b basics.Bakefile echo
[ "${status}" -eq 0 ]
}
@test "bake runs sub-tasks" {
run bake -b basics.Bakefile echo/dep
[ "${status}" -eq 0 ]
}
@test "bake --no-deps" {
run bake -b basics.Bakefile deps/fail --no-deps
[ "${status}" -eq 0 ]
}
+4
View File
@@ -0,0 +1,4 @@
task: skipme
exit 0
skipme: @skip:key=cache.Bakefile
exit 0
+19
View File
@@ -0,0 +1,19 @@
@test "skips clear" {
bake -b cache.Bakefile --clear-skips
}
@test "cache runs" {
run bake -b cache.Bakefile task
[[ $output != *Skipping* ]]
}
@test "cache skips" {
run bake -b cache.Bakefile task
[[ $output == *Skipping* ]]
}
@test "skip skips" {
run bake -b cache.Bakefile --no-deps task
[[ $output != *Skipping* ]]
}
+5
View File
@@ -0,0 +1,5 @@
secure: @confirm
exit 0
secure/real: @confirm:secure
exit 1
+17
View File
@@ -0,0 +1,17 @@
source ./_common.sh
@test "confirm works" {
timeout 1 "bake -b confirm.Bakefile secure"
}
@test "confirm --yes works" {
bake -b confirm.Bakefile secure --yes
}
@test "confirm:secure works" {
timeout 1 "bake -b confirm.Bakefile secure/real"
}
@test "confirm:secure --yes don't work" {
timeout 1 "bake -b confirm.Bakefile secure/real --yes"
}
+2
View File
@@ -0,0 +1,2 @@
env:
env
+19
View File
@@ -0,0 +1,19 @@
export HELLO=WORLD
@test "env cache clear" {
bake -b env.Bakefile --clear-envs env
}
@test "removal of environment untrusted variables" {
run bake -b env.Bakefile env
[[ "${output}" != *HELLO=WORLD* ]]
}
@test "allowance of environment untrusted variables" {
run bake --allow HELLO
run bake -b env.Bakefile env
[[ "${output}" == *"WORLD"* ]]
}
+3
View File
@@ -0,0 +1,3 @@
python:
#!/usr/bin/env python
print('not bash')
+4
View File
@@ -0,0 +1,4 @@
@test "python" {
run bake --silent -b python.Bakefile python
[[ "${lines[0]}" == "not bash" ]]
}
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env bats
declare -a COLORS=('white', 'red', 'green', 'blue', 'cyan', 'purple', 'magenta')
@test "$(red red) --help" {
run red --help
[ "${lines[0]}" = "Usage: red [OPTIONS] [S]" ]
}
@test "$(red red) \${s}" {
run red test
[[ "${lines[0]}" == *"test"* ]]
}
@test "echo \${s} | $(red red)" {
output=$(echo test | red)
[[ "$output" == *"test"* ]]
}
@test "$(red red) --fg \${COLOR}" {
for COLOR in "${COLORS[@]}"; do
output=$(echo test | red --fg ${COLOR} )
[[ "$output" == *"test"* ]]
done
}
@test "$(red red) --fg \${COLOR} --bold" {
for COLOR in "${COLORS[@]}"; do
output=$(echo test | red --fg ${COLOR} --bold)
[[ "$output" == *"test"* ]]
done
}
@test "$(red red) --bg \${COLOR}" {
for COLOR in "${COLORS[@]}"; do
output=$(echo test | red --bg ${COLOR} )
[[ "$output" == *"test"* ]]
done
}
@test "$(red red) --bg \${COLOR} --bold" {
for COLOR in "${COLORS[@]}"; do
output=$(echo test | red --bg ${COLOR} --bold)
[[ "$output" == *"test"* ]]
done
}
@test "$(red notred --fg blue) \${s}" {
run notred test
[[ "${lines[0]}" == "test" ]]
}
@test "$(red red) \${s} | $(red notred --fg blue)" {
output=$(red test | notred)
[[ "$output" == *"test"* ]]
}
@test "which $(red red)" {
run which red
[ "${status}" -eq 0 ]
}
@test "which $(red notred --fg blue)" {
run which notred
[ "${status}" -eq 0 ]
}
@test "which $(red bake_indent --fg cyan)" {
run which bake_indent
[ "${status}" -eq 0 ]
}
@test "which $(red bake_step --fg cyan)" {
run which bake_step
[ "${status}" -eq 0 ]
}
@test "$(red bake_step --fg cyan) \${s}" {
run bake_step --no-color 'Step 1'
[[ "${lines[0]}" == " + Step 1: " ]]
}
@test "$(red bake_step --fg cyan) --help" {
run bake_step --help
[ "${lines[0]}" = "Usage: bake_step [OPTIONS] [S]" ]
}
@test "$(red bake_indent --fg cyan) --help" {
run bake_indent --help
[ "${lines[0]}" = "Usage: bake_indent [OPTIONS]" ]
}