From 62b71a1bef216ab1bbb4db627481e5824400f41b Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 19:36:02 -0400 Subject: [PATCH 01/11] v0.9.1 --- bake/bakefile.py | 7 ++++++- setup.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bake/bakefile.py b/bake/bakefile.py index 325c3a7..f709e16 100644 --- a/bake/bakefile.py +++ b/bake/bakefile.py @@ -561,7 +561,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 diff --git a/setup.py b/setup.py index 0130ee6..2fadac4 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ URL = "https://github.com/kennethreitz/bake" EMAIL = "me@kennethreitz.org" AUTHOR = "Kenneth Reitz" REQUIRES_PYTHON = ">=3.6.0" -VERSION = "0.9.0" +VERSION = "0.9.1" # What packages are required for this module to be executed? REQUIRED = ["click", "delegator.py", "pygments", "networkx"] From 3c6330a8c0a94665a499650c2f5b8dcec1f5668c Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 20:01:27 -0400 Subject: [PATCH 02/11] number of levels --- bake/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bake/cli.py b/bake/cli.py index 1a2f605..0bca866 100644 --- a/bake/cli.py +++ b/bake/cli.py @@ -99,7 +99,7 @@ def echo_json(obj): 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." From 8d00779c3956ea858e3ca9476c276ccacf9fdeef Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 20:02:23 -0400 Subject: [PATCH 03/11] skip cache --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2fadac4..39717ab 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ URL = "https://github.com/kennethreitz/bake" EMAIL = "me@kennethreitz.org" AUTHOR = "Kenneth Reitz" REQUIRES_PYTHON = ">=3.6.0" -VERSION = "0.9.1" +VERSION = "0.10.0" # What packages are required for this module to be executed? REQUIRED = ["click", "delegator.py", "pygments", "networkx"] From 5168dd6d16286ee2c11761e90aadb6480c41838a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 20:03:10 -0400 Subject: [PATCH 04/11] clear --- bake/cli.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bake/cli.py b/bake/cli.py index 0bca866..7f325fc 100644 --- a/bake/cli.py +++ b/bake/cli.py @@ -93,6 +93,9 @@ 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", @@ -185,6 +188,7 @@ def entrypoint( allow, _json, no_deps, + clear, interactive, yes, help, From 86868f33d4fafeea1628602f8ed61b4803fe0e18 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 21:07:33 -0400 Subject: [PATCH 05/11] =?UTF-8?q?epic=20git=E2=80=93based=20cache=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bake/__init__.py | 1 + bake/bakefile.py | 84 +++++++++++++++++++------------------- bake/cache.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++ bake/cli.py | 49 +++++++++++----------- bake/constants.py | 1 + 5 files changed, 170 insertions(+), 66 deletions(-) create mode 100644 bake/cache.py diff --git a/bake/__init__.py b/bake/__init__.py index e69de29..3b83a00 100644 --- a/bake/__init__.py +++ b/bake/__init__.py @@ -0,0 +1 @@ +from .bakefile import Bakefile diff --git a/bake/bakefile.py b/bake/bakefile.py index f709e16..e8c1c63 100644 --- a/bake/bakefile.py +++ b/bake/bakefile.py @@ -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="Bashfile", 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): @@ -197,7 +207,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 @@ -251,9 +261,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 @@ -271,7 +281,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): @@ -339,39 +349,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… @@ -390,9 +394,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.""" @@ -405,8 +409,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: @@ -419,7 +423,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"): @@ -434,20 +438,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()] @@ -455,9 +459,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: @@ -491,9 +493,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): @@ -543,7 +545,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" @@ -575,7 +577,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: diff --git a/bake/cache.py b/bake/cache.py new file mode 100644 index 0000000..1f2f1e3 --- /dev/null +++ b/bake/cache.py @@ -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"" + + 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 diff --git a/bake/cli.py b/bake/cli.py index 7f325fc..8695bd7 100644 --- a/bake/cli.py +++ b/bake/cli.py @@ -75,7 +75,7 @@ def echo_json(obj): type=click.STRING, default="__LIST_ALL__", envvar="BAKE_TASK", - # required=False, + required=False, ) @click.option( "--bakefile", @@ -213,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) @@ -224,7 +225,7 @@ def entrypoint( sys.exit(0) if debug: - click.echo(f" + Bakefile: {bakefile.path}", err=True) + click.echo(f" + Bakefile: {bf.path}", err=True) # --source (internal API) if source: @@ -234,17 +235,17 @@ def entrypoint( click.echo(g) if source == "__init__": - source = random.choice(list(bakefile.tasks.keys())) - task = bakefile.tasks[source] + source = random.choice(list(bf.tasks.keys())) + task = bf.tasks[source] source = task.gen_source( - sources=[task.bashfile.funcs_source, task.bashfile.root_source] + sources=[task.bf.funcs_source, task.bf.root_source] ) else: - task = bakefile.tasks[source] + task = bf.tasks[source] source = task.gen_source( sources=[ - task.bashfile.funcs_source, - task.bashfile.root_source, + task.bf.funcs_source, + task.bf.root_source, task.source, ] ) @@ -254,12 +255,12 @@ def entrypoint( 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 = [] @@ -282,9 +283,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": {}} @@ -292,19 +293,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 = () @@ -327,7 +326,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")) @@ -344,14 +343,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() diff --git a/bake/constants.py b/bake/constants.py index 90c7f93..75a5685 100644 --- a/bake/constants.py +++ b/bake/constants.py @@ -14,3 +14,4 @@ SAFE_ENVIRONS = [ "PYTHONDONTWRITEBYTECODE", "BAKE_SILENT", ] +DEFAULT_BAKEFILE_NAME = "Bakefile" From 3f6c51600175841a5db9d5bfaa2263d6151eb6de Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 21:07:57 -0400 Subject: [PATCH 06/11] cleanup --- bake/cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bake/cache.py b/bake/cache.py index 1f2f1e3..c40eecf 100644 --- a/bake/cache.py +++ b/bake/cache.py @@ -4,7 +4,7 @@ import delegator PREFIX = "bake" SEPERATOR = "." -__all__ = ["cache"] +__all__ = ['Cache'] class Cache: From b1e3b7cdef5163f78c10b1790c8cc34db17b377e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 21:12:49 -0400 Subject: [PATCH 07/11] cleanup --- bake/cli.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/bake/cli.py b/bake/cli.py index 8695bd7..09291e1 100644 --- a/bake/cli.py +++ b/bake/cli.py @@ -227,28 +227,17 @@ def entrypoint( if debug: 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(bf.tasks.keys())) - task = bf.tasks[source] - source = task.gen_source( - sources=[task.bf.funcs_source, task.bf.root_source] - ) - else: - task = bf.tasks[source] - source = task.gen_source( - sources=[ - task.bf.funcs_source, - task.bf.root_source, - task.source, - ] - ) + task = bf.tasks[source] + source = task.gen_source( + sources=[task.bf.funcs_source, task.bf.root_source, task.source] + ) for source_line in source: click.echo(source_line) From ede57753ef7c8d227f341995ee5a8cfe54089536 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 21:35:05 -0400 Subject: [PATCH 08/11] improved examples --- examples/reuse/Bakefile | 14 ++++++++++---- t.py | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 t.py diff --git a/examples/reuse/Bakefile b/examples/reuse/Bakefile index 476cbf1..306be69 100644 --- a/examples/reuse/Bakefile +++ b/examples/reuse/Bakefile @@ -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 diff --git a/t.py b/t.py new file mode 100644 index 0000000..43c515a --- /dev/null +++ b/t.py @@ -0,0 +1,6 @@ +from bake import Bakefile + +bakefile = Bakefile.find() +bakefile.cache.clear() +# bakefile.cache["test"] = 1 +# print(bakefile.cache["test"]) From 08d5f9347533950017259ad771fead9c4836fe59 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 22:10:51 -0400 Subject: [PATCH 09/11] indent & red --- bake/bakefile.py | 15 --------------- bake/cli.py | 4 +--- bake/scripts/__init__.py | 1 + bake/scripts/indent.py | 20 ++++++++++++++++++++ bake/scripts/red.py | 27 +++++++++++++++++++++++++++ setup.py | 10 ++++++++-- 6 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 bake/scripts/__init__.py create mode 100644 bake/scripts/indent.py create mode 100644 bake/scripts/red.py diff --git a/bake/bakefile.py b/bake/bakefile.py index e8c1c63..8d09451 100644 --- a/bake/bakefile.py +++ b/bake/bakefile.py @@ -233,21 +233,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 diff --git a/bake/cli.py b/bake/cli.py index 09291e1..f6784b0 100644 --- a/bake/cli.py +++ b/bake/cli.py @@ -235,9 +235,7 @@ def entrypoint( if source: task = bf.tasks[source] - source = task.gen_source( - sources=[task.bf.funcs_source, task.bf.root_source, task.source] - ) + source = task.gen_source(sources=[task.bf.root_source, task.source]) for source_line in source: click.echo(source_line) diff --git a/bake/scripts/__init__.py b/bake/scripts/__init__.py new file mode 100644 index 0000000..c543ad7 --- /dev/null +++ b/bake/scripts/__init__.py @@ -0,0 +1 @@ +from . import red diff --git a/bake/scripts/indent.py b/bake/scripts/indent.py new file mode 100644 index 0000000..44a9a48 --- /dev/null +++ b/bake/scripts/indent.py @@ -0,0 +1,20 @@ +import sys + +import click + + +@click.command(context_settings=dict(help_option_names=["-h", "--help"])) +@click.option( + "--only-stdout", is_flag=True, type=click.BOOL, default=False, help="Use stdout." +) +@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 indent(*, char, read_stderr, only_stdout): + + pipe = sys.stdin if not read_stderr else sys.stderr + + for line in pipe: + click.echo(f" {char} ", err=(not only_stdout), nl=False) + click.echo(line, nl=False) diff --git a/bake/scripts/red.py b/bake/scripts/red.py new file mode 100644 index 0000000..54d9d47 --- /dev/null +++ b/bake/scripts/red.py @@ -0,0 +1,27 @@ +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.") +@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 red(s, *, fg, bg, bold, err): + if s is False: + s = sys.stdin.read() + + try: + click.echo(click.style(s, fg=fg, bg=bg), err=err, nl=False) + except TypeError: + click.echo(click.style(s), err=err, nl=False) diff --git a/setup.py b/setup.py index 39717ab..6cbadc2 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ REQUIRES_PYTHON = ">=3.6.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,13 @@ 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:red", + "bake:indent=bake.scripts.indent:indent", + ] + }, install_requires=REQUIRED, extras_require=EXTRAS, include_package_data=True, From aba0ec155e6938f16e705f97a1c2b15d57f655dd Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 22:10:58 -0400 Subject: [PATCH 10/11] no more stdlib --- bake/scripts/stdlib.sh | 89 ------------------------------------------ 1 file changed, 89 deletions(-) delete mode 100644 bake/scripts/stdlib.sh diff --git a/bake/scripts/stdlib.sh b/bake/scripts/stdlib.sh deleted file mode 100644 index 8b3d3c6..0000000 --- a/bake/scripts/stdlib.sh +++ /dev/null @@ -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' -} From b70a69b42282c2f04c3b213b8281d37de03e5e5c Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 22 Sep 2019 23:00:25 -0400 Subject: [PATCH 11/11] bakefile --- Bakefile | 17 +++++++++++++++-- bake/scripts/__init__.py | 2 ++ bake/scripts/indent.py | 12 ++++++------ bake/scripts/red.py | 22 +++++++++++++++++++--- bake/scripts/redless.py | 16 ++++++++++++++++ bake/scripts/step.py | 33 +++++++++++++++++++++++++++++++++ setup.py | 7 +++++-- 7 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 bake/scripts/redless.py create mode 100644 bake/scripts/step.py diff --git a/Bakefile b/Bakefile index ebc41da..efac824 100644 --- a/Bakefile +++ b/Bakefile @@ -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 diff --git a/bake/scripts/__init__.py b/bake/scripts/__init__.py index c543ad7..4ba9f04 100644 --- a/bake/scripts/__init__.py +++ b/bake/scripts/__init__.py @@ -1 +1,3 @@ from . import red +from . import indent +from . import step diff --git a/bake/scripts/indent.py b/bake/scripts/indent.py index 44a9a48..fe63f66 100644 --- a/bake/scripts/indent.py +++ b/bake/scripts/indent.py @@ -4,17 +4,17 @@ import click @click.command(context_settings=dict(help_option_names=["-h", "--help"])) -@click.option( - "--only-stdout", is_flag=True, type=click.BOOL, default=False, help="Use stdout." -) @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 indent(*, char, read_stderr, only_stdout): +def entrypoint(*, char, read_stderr): pipe = sys.stdin if not read_stderr else sys.stderr for line in pipe: - click.echo(f" {char} ", err=(not only_stdout), nl=False) - click.echo(line, nl=False) + if line: + print(f" {char} ", end="") + print(line.rstrip()) + else: + print(f" {char} ", end="") diff --git a/bake/scripts/red.py b/bake/scripts/red.py index 54d9d47..ecce34b 100644 --- a/bake/scripts/red.py +++ b/bake/scripts/red.py @@ -1,11 +1,19 @@ 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." ) @@ -17,11 +25,19 @@ import click help="Background color to use (rare).", ) @click.option("--bold", is_flag=True, type=click.BOOL, default=False, help="Be bold.") -def red(s, *, fg, bg, bold, err): +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: - click.echo(click.style(s, fg=fg, bg=bg), err=err, nl=False) + s = click.style(s, fg=fg, bg=bg) except TypeError: - click.echo(click.style(s), err=err, nl=False) + pass + + print(s) diff --git a/bake/scripts/redless.py b/bake/scripts/redless.py new file mode 100644 index 0000000..582438f --- /dev/null +++ b/bake/scripts/redless.py @@ -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) diff --git a/bake/scripts/step.py b/bake/scripts/step.py new file mode 100644 index 0000000..9c61f04 --- /dev/null +++ b/bake/scripts/step.py @@ -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}: ") diff --git a/setup.py b/setup.py index 6cbadc2..7de01af 100644 --- a/setup.py +++ b/setup.py @@ -106,8 +106,10 @@ setup( entry_points={ "console_scripts": [ "bake=bake.cli:entrypoint", - "bake:red=bake.scripts.red:red", - "bake:indent=bake.scripts.indent:indent", + "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, @@ -121,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", ],