mirror of
https://github.com/kennethreitz/bake.git
synced 2026-06-05 23:00:17 +00:00
Merge branch 'master' into patch-1
This commit is contained in:
@@ -58,11 +58,24 @@ ci: ci/setup
|
||||
ci/setup: @skip:key=Pipfile.lock
|
||||
pipenv install --dev --deploy --system
|
||||
|
||||
random/python:
|
||||
random/ip:
|
||||
#!/usr/bin/env python
|
||||
import requests
|
||||
print(requests)
|
||||
r = requests.get('https://httpbin.org/ip')
|
||||
print(r.json()['origin'].split(',')[0])
|
||||
|
||||
random/clis:
|
||||
bake:red 'Testing sub–commands.'
|
||||
bake:step 'sub-task'
|
||||
echo 'I should *not* be red.' | bake:red | bake:indent | bake:redless
|
||||
echo 'I *should* be red.' | bake:red --always | bake:indent
|
||||
echo "$(echo test $(bake:red test) test | bake:indent)"
|
||||
echo
|
||||
|
||||
random/kr:
|
||||
sparkescakesparkles="✨ 🍰 ✨" | pbcopy
|
||||
echo "$sparkescakesparkles" | pbcopy
|
||||
echo 'KR Copied!' | bake:red --fg cyan
|
||||
|
||||
lazy_brew() {
|
||||
set -e
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from .bakefile import Bakefile
|
||||
|
||||
+49
-57
@@ -11,7 +11,8 @@ import networkx
|
||||
|
||||
from . import utils
|
||||
from .bash import Bash
|
||||
from .constants import INDENT_STYLES
|
||||
from .cache import Cache
|
||||
from .constants import INDENT_STYLES, DEFAULT_BAKEFILE_NAME
|
||||
from .exceptions import FilterNotAvailable, NoBakefileFound, TaskNotInBashfile
|
||||
|
||||
|
||||
@@ -35,6 +36,10 @@ class Bakefile:
|
||||
self._tasks = None
|
||||
self._graph = None
|
||||
|
||||
@property
|
||||
def cache(self):
|
||||
return Cache(bf=self)
|
||||
|
||||
@property
|
||||
def graph(self):
|
||||
if self._graph:
|
||||
@@ -131,9 +136,14 @@ class Bakefile:
|
||||
|
||||
@classmethod
|
||||
def find(
|
||||
Class, *, filename="Bakefile", root=os.getcwd(), max_depth=4, topdown=False
|
||||
Class,
|
||||
*,
|
||||
filename=DEFAULT_BAKEFILE_NAME,
|
||||
root=os.getcwd(),
|
||||
max_depth=4,
|
||||
topdown=False,
|
||||
):
|
||||
"""Returns the path of a Pipfile in parent directories."""
|
||||
"""Returns the path of a Bakefile in parent directories."""
|
||||
|
||||
i = 0
|
||||
for c, d, f in utils.walk_up(root):
|
||||
@@ -199,7 +209,7 @@ class Bakefile:
|
||||
|
||||
tasks = {}
|
||||
for i, chunk in enumerate(self.chunks):
|
||||
script = TaskScript._from_chunk_index(bashfile=self, i=i)
|
||||
script = TaskScript._from_chunk_index(bf=self, i=i)
|
||||
tasks[script.name] = script
|
||||
|
||||
self._tasks = tasks
|
||||
@@ -225,21 +235,6 @@ class Bakefile:
|
||||
"""The source of the 'root level' of the Bashfile."""
|
||||
return "\n".join(list(self.iter_root_source_lines))
|
||||
|
||||
def iter_funcs_source(self):
|
||||
"""The standard library."""
|
||||
p = os.path.join(os.path.dirname(__file__), "scripts", "stdlib.sh")
|
||||
with open(p, "r") as f:
|
||||
for i, line in enumerate(f.readlines()):
|
||||
# Skip the shebang.
|
||||
if i != 1:
|
||||
yield line
|
||||
|
||||
@property
|
||||
def funcs_source(self):
|
||||
"""Functions (_task_name), inserted into the Bash runtime."""
|
||||
source = list(self.iter_funcs_source())
|
||||
return "\n".join(source)
|
||||
|
||||
|
||||
class BaseAction:
|
||||
do_skip = None
|
||||
@@ -253,9 +248,9 @@ class BaseAction:
|
||||
class TaskFilter(BaseAction):
|
||||
"""A filter, which can be applied to a task."""
|
||||
|
||||
def __init__(self, s, bashfile):
|
||||
def __init__(self, s, *, bf):
|
||||
self.source = s
|
||||
self.bashfile = bashfile
|
||||
self.bf = bf
|
||||
self.__uuid = uuid4().hex
|
||||
self.do_skip = None
|
||||
|
||||
@@ -273,7 +268,7 @@ class TaskFilter(BaseAction):
|
||||
|
||||
def __hash__(self):
|
||||
"""Important for (networkx) graph traversal."""
|
||||
return hash((self.bashfile, self.source, self.__uuid))
|
||||
return hash((self.bf, self.source, self.__uuid))
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@@ -341,39 +336,33 @@ class TaskFilter(BaseAction):
|
||||
|
||||
return ("confirmed", True)
|
||||
|
||||
def execute_skip_if(self, *, key, cache=None, **kwargs):
|
||||
def execute_skip_if(self, *, key, **kwargs):
|
||||
"""Determines if it is appropriate to skip the dependent TaskScript."""
|
||||
if cache is None:
|
||||
# I'm cheating here, and shoving stuff into the git folder (which I assume is there).
|
||||
# TODO: Improve this — look into $ git config --local (shell) use instead.
|
||||
cache = f".git/bake-hash-{sha256(key.encode('utf-8')).hexdigest()}"
|
||||
|
||||
# Ensure the provided file–key exists, and if it doesn't, abort mission.
|
||||
key_path = os.path.abspath(key)
|
||||
cache_path = os.path.abspath(cache)
|
||||
os.makedirs(os.path.dirname(cache_path), exist_ok=True)
|
||||
|
||||
if not os.path.exists(key_path):
|
||||
self.do_skip = False
|
||||
return ("skip", False)
|
||||
# return ("skip", False)
|
||||
return
|
||||
|
||||
if os.path.exists(cache_path):
|
||||
with open(cache_path, "r") as f:
|
||||
old_hash = f.read().strip()
|
||||
else:
|
||||
old_hash = "NOPE"
|
||||
key = sha256(key.encode("utf-8")).hexdigest()
|
||||
old_hash = str(self.bf.cache[key])
|
||||
|
||||
# Get the current filestate hashsum.
|
||||
with open(key_path, "r") as f:
|
||||
current_hash = sha256(f.read().encode("utf-8")).hexdigest()
|
||||
|
||||
with open(cache_path, "w") as f:
|
||||
f.write(current_hash)
|
||||
self.bf.cache[key] = current_hash
|
||||
|
||||
if old_hash == current_hash:
|
||||
self.do_skip = True
|
||||
return ("skip", True)
|
||||
# return ("skip", True)
|
||||
return
|
||||
|
||||
self.do_skip = False
|
||||
return ("skip", False)
|
||||
# return ("skip", False)
|
||||
return
|
||||
|
||||
def execute(self, yes=False, **kwargs):
|
||||
"""This should probably be two different classes…
|
||||
@@ -392,9 +381,9 @@ class FakeTaskScript(BaseAction):
|
||||
Ussually typos. They display red in the terminal. Neat.
|
||||
"""
|
||||
|
||||
def __init__(self, s, bashfile):
|
||||
def __init__(self, s, *, bf):
|
||||
self.source = s
|
||||
self.bashfile = bashfile
|
||||
self.bf = bf
|
||||
|
||||
def __str__(self):
|
||||
"""The color red, as mentioned above."""
|
||||
@@ -407,8 +396,8 @@ class TaskScript(BaseAction):
|
||||
You're pretty witty & intelligent — you can infer what this class is for, based on its name.
|
||||
"""
|
||||
|
||||
def __init__(self, bashfile, chunk_index=None):
|
||||
self.bashfile = bashfile
|
||||
def __init__(self, *, bf, chunk_index=None):
|
||||
self.bf = bf
|
||||
self._chunk_index = chunk_index
|
||||
|
||||
if self._chunk_index is None:
|
||||
@@ -421,7 +410,7 @@ class TaskScript(BaseAction):
|
||||
return f"{self.name}"
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.bashfile, self._chunk_index))
|
||||
return hash((self.bf, self._chunk_index))
|
||||
|
||||
def __eq__(self, other):
|
||||
if hasattr(other, "_chunk_index"):
|
||||
@@ -436,20 +425,20 @@ class TaskScript(BaseAction):
|
||||
task_strings = self.declaration_line.split(":", 1)[1].split()
|
||||
|
||||
task_name_index_tuples = [
|
||||
(self.bashfile.find_chunk(task_name=s), s) for s in task_strings
|
||||
(self.bf.find_chunk(task_name=s), s) for s in task_strings
|
||||
]
|
||||
|
||||
for i, task_string in task_name_index_tuples:
|
||||
|
||||
if task_string.startswith("@"):
|
||||
if include_filters:
|
||||
yield TaskFilter(task_string, bashfile=self.bashfile)
|
||||
yield TaskFilter(task_string, bf=self.bf)
|
||||
elif i is None:
|
||||
if include_fakes:
|
||||
yield FakeTaskScript(task_string, bashfile=self.bashfile)
|
||||
yield FakeTaskScript(task_string, bf=self.bf)
|
||||
else:
|
||||
# Otherwise, create the task.
|
||||
yield TaskScript(chunk_index=i, bashfile=self.bashfile)
|
||||
yield TaskScript(chunk_index=i, bf=self.bf)
|
||||
|
||||
actions = [t for t in gen_actions()]
|
||||
|
||||
@@ -457,9 +446,7 @@ class TaskScript(BaseAction):
|
||||
graph = {}
|
||||
actions = []
|
||||
|
||||
edge_view = networkx.edge_dfs(
|
||||
self.bashfile.graph, self, orientation="original"
|
||||
)
|
||||
edge_view = networkx.edge_dfs(self.bf.graph, self, orientation="original")
|
||||
|
||||
for parent, child, _ in edge_view:
|
||||
if parent not in graph:
|
||||
@@ -493,9 +480,9 @@ class TaskScript(BaseAction):
|
||||
return actions
|
||||
|
||||
@classmethod
|
||||
def _from_chunk_index(Class, bashfile, *, i):
|
||||
def _from_chunk_index(Class, bf, *, i):
|
||||
|
||||
return Class(bashfile=bashfile, chunk_index=i)
|
||||
return Class(bf=bf, chunk_index=i)
|
||||
|
||||
@staticmethod
|
||||
def _transform_line(line, *, indent_styles=INDENT_STYLES):
|
||||
@@ -545,7 +532,7 @@ class TaskScript(BaseAction):
|
||||
self, *, blocking=False, debug=False, interactive=False, silent=False, **kwargs
|
||||
):
|
||||
|
||||
args = " ".join([shlex_quote(a) for a in self.bashfile.args])
|
||||
args = " ".join([shlex_quote(a) for a in self.bf.args])
|
||||
args = args if args else "\b"
|
||||
sed_magic = (
|
||||
"2>&1 | sed >&2 's/^/ | /'" if not (silent or interactive) else "\b"
|
||||
@@ -563,7 +550,12 @@ class TaskScript(BaseAction):
|
||||
if debug:
|
||||
click.echo(f" {click.style('$', fg='green')} {script}", err=True)
|
||||
|
||||
bash = Bash(interactive=interactive)
|
||||
if silent:
|
||||
bash_interactive = True
|
||||
else:
|
||||
bash_interactive = interactive
|
||||
|
||||
bash = Bash(interactive=bash_interactive)
|
||||
return bash.command(script, quote=False)
|
||||
|
||||
@property
|
||||
@@ -572,7 +564,7 @@ class TaskScript(BaseAction):
|
||||
|
||||
@property
|
||||
def chunk(self):
|
||||
return self.bashfile.chunks[self._chunk_index]
|
||||
return self.bf.chunks[self._chunk_index]
|
||||
|
||||
def _iter_source(self):
|
||||
try:
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
import click
|
||||
import delegator
|
||||
|
||||
PREFIX = "bake"
|
||||
SEPERATOR = "."
|
||||
|
||||
__all__ = ['Cache']
|
||||
|
||||
|
||||
class Cache:
|
||||
prefix = PREFIX
|
||||
seperator = SEPERATOR
|
||||
|
||||
def __init__(self, *, bf, debug=False, enabled=True):
|
||||
|
||||
self.bf = bf
|
||||
self.enabled = enabled
|
||||
self.debug = debug
|
||||
|
||||
try:
|
||||
# Assert git exists, and appears functioning.
|
||||
c = delegator.run("git --version")
|
||||
assert c.ok
|
||||
if self.debug:
|
||||
click.echo(" + cache.git.ok: true", err=True)
|
||||
|
||||
# Record the top-level directory of the git repository.
|
||||
c = delegator.run("git rev-parse --show-toplevel")
|
||||
self.git_root = c.out.strip()
|
||||
if self.debug:
|
||||
click.echo(f" + cache.git.root: {self.git_root!r}", err=True)
|
||||
|
||||
# Assert Bakefile exists within it.
|
||||
assert self.bf.path.startswith(self.git_root)
|
||||
if self.debug:
|
||||
click.echo(f" + cache.git.contains_bakefile: true", err=True)
|
||||
|
||||
except AssertionError:
|
||||
# Cache is disabled.
|
||||
self.enabled = False
|
||||
|
||||
if debug:
|
||||
click.echo(f" + cache.enabled: true", err=True)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Cache enabled={self.enabled}>"
|
||||
|
||||
def _key_for_hashes(self, key):
|
||||
return self.seperator.join((self.prefix, "hashes", key))
|
||||
|
||||
def clear(self):
|
||||
for key in self:
|
||||
del self[key]
|
||||
|
||||
if self.debug:
|
||||
click.echo(" + cache.git.cleared: true", err=True)
|
||||
|
||||
def __iter__(self):
|
||||
# TODO: Print these.
|
||||
cmd = "git config --local --list"
|
||||
|
||||
if self.debug:
|
||||
click.echo(f" {click.style('$', fg='green')} {cmd}", err=True)
|
||||
|
||||
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]
|
||||
|
||||
def __getitem__(self, k):
|
||||
key = self._key_for_hashes(k)
|
||||
cmd = f"git config --local --get {key}"
|
||||
|
||||
if self.debug:
|
||||
click.echo(f" {click.style('$', fg='green')} {cmd}", err=True)
|
||||
|
||||
c = delegator.run()
|
||||
if c.ok:
|
||||
return c.out.strip()
|
||||
else:
|
||||
return None
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
key = self._key_for_hashes(k)
|
||||
cmd = f"git config --local {key} {v}"
|
||||
|
||||
if self.debug:
|
||||
click.echo(f" {click.style('$', fg='green')} {cmd}", err=True)
|
||||
|
||||
c = delegator.run(cmd)
|
||||
return c.ok
|
||||
|
||||
def __delitem__(self, k):
|
||||
cmd = f"git config --local --unset {k}"
|
||||
|
||||
if self.debug:
|
||||
click.echo(f" {click.style('$', fg='green')} {cmd}", err=True)
|
||||
|
||||
c = delegator.run(cmd)
|
||||
return c.ok
|
||||
+29
-39
@@ -75,7 +75,7 @@ def echo_json(obj):
|
||||
type=click.STRING,
|
||||
default="__LIST_ALL__",
|
||||
envvar="BAKE_TASK",
|
||||
# required=False,
|
||||
required=False,
|
||||
)
|
||||
@click.option(
|
||||
"--bakefile",
|
||||
@@ -93,13 +93,16 @@ def echo_json(obj):
|
||||
is_flag=True,
|
||||
help="Lists available tasks (and their dependencies).",
|
||||
)
|
||||
@click.option(
|
||||
"--clear", default=False, is_flag=True, help="Clears the cache (e.g. @skip)."
|
||||
)
|
||||
@click.option(
|
||||
"--levels",
|
||||
"-l",
|
||||
default=None,
|
||||
nargs=1,
|
||||
type=click.INT,
|
||||
help="List only a given number of '/' levels of tasks.",
|
||||
help="The number of '/' levels to list.",
|
||||
)
|
||||
@click.option(
|
||||
"--help", "-h", default=False, is_flag=True, help="Show this message and exit."
|
||||
@@ -185,6 +188,7 @@ def entrypoint(
|
||||
allow,
|
||||
_json,
|
||||
no_deps,
|
||||
clear,
|
||||
interactive,
|
||||
yes,
|
||||
help,
|
||||
@@ -209,10 +213,11 @@ def entrypoint(
|
||||
|
||||
# Establish the Bakefile.
|
||||
try:
|
||||
if bakefile == "__BAKEFILE__":
|
||||
bakefile = Bakefile.find(root=".", filename="Bakefile")
|
||||
else:
|
||||
bakefile = Bakefile(path=bakefile)
|
||||
bf = (
|
||||
Bakefile.find(root=".", filename="Bakefile")
|
||||
if bakefile == "__BAKEFILE__"
|
||||
else Bakefile(path=bakefile)
|
||||
)
|
||||
|
||||
except NoBakefileFound:
|
||||
click.echo(click.style("No Bakefile found!", fg="red"), err=True)
|
||||
@@ -220,42 +225,29 @@ def entrypoint(
|
||||
sys.exit(0)
|
||||
|
||||
if debug:
|
||||
click.echo(f" + Bakefile: {bakefile.path}", err=True)
|
||||
click.echo(f" + Bakefile: {bf.path}", err=True)
|
||||
|
||||
# Clear the cache, if asked to do so.
|
||||
if clear:
|
||||
bf.cache.clear()
|
||||
|
||||
# --source (internal API)
|
||||
if source:
|
||||
|
||||
def echo_generator(g):
|
||||
for g in g:
|
||||
click.echo(g)
|
||||
|
||||
if source == "__init__":
|
||||
source = random.choice(list(bakefile.tasks.keys()))
|
||||
task = bakefile.tasks[source]
|
||||
source = task.gen_source(
|
||||
sources=[task.bashfile.funcs_source, task.bashfile.root_source]
|
||||
)
|
||||
else:
|
||||
task = bakefile.tasks[source]
|
||||
source = task.gen_source(
|
||||
sources=[
|
||||
task.bashfile.funcs_source,
|
||||
task.bashfile.root_source,
|
||||
task.source,
|
||||
]
|
||||
)
|
||||
task = bf.tasks[source]
|
||||
source = task.gen_source(sources=[task.bf.root_source, task.source])
|
||||
|
||||
for source_line in source:
|
||||
click.echo(source_line)
|
||||
sys.exit(0)
|
||||
|
||||
if not insecure:
|
||||
for key in bakefile.environ:
|
||||
for key in bf.environ:
|
||||
if key not in SAFE_ENVIRONS:
|
||||
del bakefile.environ[key]
|
||||
del bf.environ[key]
|
||||
|
||||
if environ_json:
|
||||
bakefile.add_environ_json(environ_json)
|
||||
bf.add_environ_json(environ_json)
|
||||
|
||||
argv = []
|
||||
environ = []
|
||||
@@ -278,9 +270,9 @@ def entrypoint(
|
||||
f" + Setting environ: {click.style(key, fg='red')} {click.style('=', fg='white')} {value}.",
|
||||
err=True,
|
||||
)
|
||||
bakefile.add_environ(key, value)
|
||||
bf.add_environ(key, value)
|
||||
|
||||
bakefile.add_args(*argv)
|
||||
bf.add_args(*argv)
|
||||
|
||||
if _list:
|
||||
__list_json = {"tasks": {}}
|
||||
@@ -288,19 +280,17 @@ def entrypoint(
|
||||
# Enable level filtering.
|
||||
if levels is not None:
|
||||
task_list = []
|
||||
for _task in bakefile.tasks:
|
||||
for _task in bf.tasks:
|
||||
if len(_task.split("/")) <= levels:
|
||||
task_list.append(_task)
|
||||
else:
|
||||
task_list = bakefile.tasks
|
||||
task_list = bf.tasks
|
||||
|
||||
if sort:
|
||||
task_list = sorted(task_list)
|
||||
|
||||
for _task in task_list:
|
||||
depends_on = bakefile[_task].depends_on(
|
||||
include_filters=False, recursive=True
|
||||
)
|
||||
depends_on = bf[_task].depends_on(include_filters=False, recursive=True)
|
||||
|
||||
if no_deps:
|
||||
depends_on = ()
|
||||
@@ -323,7 +313,7 @@ def entrypoint(
|
||||
)
|
||||
|
||||
if not silent:
|
||||
tasks_unechoed = len(bakefile.tasks) - len(task_list)
|
||||
tasks_unechoed = len(bf.tasks) - len(task_list)
|
||||
|
||||
if tasks_unechoed:
|
||||
bake_command = str(click.style(f"bake --levels {levels + 1}", fg="red"))
|
||||
@@ -340,14 +330,14 @@ def entrypoint(
|
||||
|
||||
if task:
|
||||
try:
|
||||
task = bakefile[task]
|
||||
task = bf[task]
|
||||
except KeyError:
|
||||
click.echo(click.style(f"Task {task} does not exist!", fg="red"))
|
||||
sys.exit(1)
|
||||
|
||||
def execute_task(task, *, silent=False):
|
||||
try:
|
||||
edges = list(bakefile.graph.out_edges(task))[0]
|
||||
edges = list(bf.graph.out_edges(task))[0]
|
||||
except IndexError:
|
||||
edges = list()
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ SAFE_ENVIRONS = [
|
||||
"PYTHONDONTWRITEBYTECODE",
|
||||
"BAKE_SILENT",
|
||||
]
|
||||
DEFAULT_BAKEFILE_NAME = "Bakefile"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from . import red
|
||||
from . import indent
|
||||
from . import step
|
||||
@@ -0,0 +1,20 @@
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
|
||||
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
|
||||
@click.option(
|
||||
"--read-stderr", is_flag=True, type=click.BOOL, default=True, help="Read stderr."
|
||||
)
|
||||
@click.option("--char", nargs=1, type=click.STRING, default="|", help="Prefix char.")
|
||||
def entrypoint(*, char, read_stderr):
|
||||
|
||||
pipe = sys.stdin if not read_stderr else sys.stderr
|
||||
|
||||
for line in pipe:
|
||||
if line:
|
||||
print(f" {char} ", end="")
|
||||
print(line.rstrip())
|
||||
else:
|
||||
print(f" {char} ", end="")
|
||||
@@ -0,0 +1,43 @@
|
||||
import sys
|
||||
|
||||
import click
|
||||
import colorama
|
||||
|
||||
|
||||
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
|
||||
@click.argument("s", type=click.STRING, default=False, required=False)
|
||||
@click.option("--err", is_flag=True, type=click.BOOL, default=False, help="Use stderr.")
|
||||
@click.option(
|
||||
"--always",
|
||||
is_flag=True,
|
||||
type=click.BOOL,
|
||||
default=False,
|
||||
help="Always speak technicolor.",
|
||||
)
|
||||
@click.option(
|
||||
"--fg", nargs=1, type=click.STRING, default="red", help="Foreground color to use."
|
||||
)
|
||||
@click.option(
|
||||
"--bg",
|
||||
nargs=1,
|
||||
type=click.STRING,
|
||||
default=False,
|
||||
help="Background color to use (rare).",
|
||||
)
|
||||
@click.option("--bold", is_flag=True, type=click.BOOL, default=False, help="Be bold.")
|
||||
def entrypoint(s, *, fg, bg, bold, err, always):
|
||||
if always:
|
||||
# Don't strip colors.
|
||||
colorama.init(strip=False)
|
||||
|
||||
if s is False:
|
||||
s = sys.stdin.read()
|
||||
|
||||
s = s.rstrip()
|
||||
|
||||
try:
|
||||
s = click.style(s, fg=fg, bg=bg)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
print(s)
|
||||
@@ -0,0 +1,16 @@
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
|
||||
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
|
||||
@click.argument("s", type=click.STRING, default=False, required=False)
|
||||
@click.option("--err", is_flag=True, type=click.BOOL, default=False, help="Use stderr.")
|
||||
def entrypoint(s, *, err):
|
||||
|
||||
if s is False:
|
||||
s = sys.stdin.read()
|
||||
|
||||
s = s.rstrip()
|
||||
|
||||
click.echo(s)
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ----------
|
||||
# - Colors -
|
||||
# ----------
|
||||
|
||||
function bake_fg_color {
|
||||
BLACK="\033[0;30m"
|
||||
BLACK_BOLD="\033[1;30m"
|
||||
WHITE="\033[0;37m"
|
||||
WHITE_BOLD="\033[1;37m"
|
||||
RED="\033[0;31m"
|
||||
RED_BOLD="\033[1;31m"
|
||||
GREEN="\033[0;32m"
|
||||
GREEN_BOLD="\033[1;32m"
|
||||
YELLOW="\033[0;33m"
|
||||
YELLOW_BOLD="\033[1;33m"
|
||||
BLUE="\033[0;34m"
|
||||
BLUE_BOLD="\033[1;34m"
|
||||
PURPLE="\033[0;35m"
|
||||
PURPLE_BOLD="\033[1;35m"
|
||||
CYAN="\033[0;36m"
|
||||
CYAN_BOLD="\033[1;36m"
|
||||
NO_COLOR="\033[0m"
|
||||
|
||||
CHOSEN_COLOR="${1}"
|
||||
ARGV_INPUT="${2}"
|
||||
|
||||
COLOR="${!CHOSEN_COLOR}"
|
||||
|
||||
if [ -z "$ARGV_INPUT" ]; then
|
||||
read -r INPUT
|
||||
else
|
||||
INPUT="$ARGV_INPUT"
|
||||
fi
|
||||
echo -e "${COLOR}${INPUT}${NO_COLOR}"
|
||||
}
|
||||
|
||||
function bake_black {
|
||||
bake_fg_color 'BLACK' "$1"
|
||||
}
|
||||
|
||||
function bake_white {
|
||||
bake_fg_color 'WHITE' "$1"
|
||||
}
|
||||
|
||||
function bake_red {
|
||||
bake_fg_color 'RED' "$1"
|
||||
}
|
||||
|
||||
function bake_green {
|
||||
bake_fg_color 'GREEN' "$1"
|
||||
}
|
||||
|
||||
function bake_yellow {
|
||||
bake_fg_color 'YELLOW' "$1"
|
||||
}
|
||||
|
||||
function bake_blue {
|
||||
bake_fg_color 'BLUE' "$1"
|
||||
}
|
||||
|
||||
function bake_purple {
|
||||
bake_fg_color 'PURPLE' "$1"
|
||||
}
|
||||
|
||||
function bake_cyan {
|
||||
bake_fg_color 'CYAN' "$1"
|
||||
}
|
||||
|
||||
function red {
|
||||
bake_fg_color 'RED' "$1"
|
||||
}
|
||||
|
||||
# ----------
|
||||
# - Indent -
|
||||
# ----------
|
||||
|
||||
function bake_indent {
|
||||
PIPE_CHAR="$1"
|
||||
|
||||
if [ -z "$PIPE_CHAR" ]; then
|
||||
PIPE_CHAR="|"
|
||||
fi
|
||||
|
||||
read -r INPUT
|
||||
echo "$INPUT" | sed >&2 "s/^/ ${PIPE_CHAR} /"
|
||||
# echo 'hi'
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# + Executing random/entrypoints:
|
||||
|
||||
import sys
|
||||
|
||||
import colorama
|
||||
import click
|
||||
|
||||
# Don't strip colors.
|
||||
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."
|
||||
)
|
||||
@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):
|
||||
|
||||
pipe = sys.stdin if not read_stderr else sys.stderr
|
||||
if s is False:
|
||||
s = pipe.read()
|
||||
|
||||
for line in s.strip().split("\n"):
|
||||
try:
|
||||
title = str(click.style(line, fg=color))
|
||||
except TypeError:
|
||||
title = line
|
||||
|
||||
print(f" + {title}: ")
|
||||
+10
-4
@@ -1,10 +1,16 @@
|
||||
hello: hello/reuse hello/reuse/concurrent
|
||||
|
||||
echo "You just ran $(red 'hello') directly, then indirectly (via bake+bash; 6 times, concurrently!)"
|
||||
hello/basic:
|
||||
echo 'hello'
|
||||
|
||||
sleep 2
|
||||
echo "[$(red $(uuidgen))] hello!"
|
||||
hello/reuse:
|
||||
bake hello/basic
|
||||
|
||||
hello/reuse/concurrent:
|
||||
bake hello/reuse & bake hello/reuse
|
||||
set -ex && \
|
||||
bake hello/reuse &
|
||||
bake hello/reuse &
|
||||
bake hello/reuse &
|
||||
bake hello/reuse &
|
||||
bake hello/reuse &
|
||||
bake hello/reuse
|
||||
|
||||
@@ -18,10 +18,10 @@ URL = "https://github.com/kennethreitz/bake"
|
||||
EMAIL = "me@kennethreitz.org"
|
||||
AUTHOR = "Kenneth Reitz"
|
||||
REQUIRES_PYTHON = ">=3.6.0"
|
||||
VERSION = "0.9.0"
|
||||
VERSION = "0.10.0"
|
||||
|
||||
# What packages are required for this module to be executed?
|
||||
REQUIRED = ["click", "delegator.py", "pygments", "networkx"]
|
||||
REQUIRED = ["click", "delegator.py", "pygments", "networkx", "colorama"]
|
||||
|
||||
# What packages are optional?
|
||||
EXTRAS = {
|
||||
@@ -103,7 +103,15 @@ setup(
|
||||
packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
|
||||
# If your package is a single module, use this instead of 'packages':
|
||||
# py_modules=['mypackage'],
|
||||
entry_points={"console_scripts": ["bake=bake.cli:entrypoint"]},
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"bake=bake.cli:entrypoint",
|
||||
"bake:red=bake.scripts.red:entrypoint",
|
||||
"bake:redless=bake.scripts.redless:entrypoint",
|
||||
"bake:indent=bake.scripts.indent:entrypoint",
|
||||
"bake:step=bake.scripts.step:entrypoint",
|
||||
]
|
||||
},
|
||||
install_requires=REQUIRED,
|
||||
extras_require=EXTRAS,
|
||||
include_package_data=True,
|
||||
@@ -115,6 +123,7 @@ setup(
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user