mirror of
https://github.com/kennethreitz/bake.git
synced 2026-06-05 14:50:19 +00:00
things
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
# Bashfile: Like Make + Bash, Combined.
|
||||
# `bashf`: Kinda like Make & Bash, combined.
|
||||
|
||||
I love using `Makefile`s for one-off tasks in projects. The problem with doing this, is you can't use familiar bash–isms when doing so, as GNU Make doesn't use the familiar Bash sytnax. This project seeks to bridge these works.
|
||||
|
||||
## Installation
|
||||
|
||||
Install `bashf` via:
|
||||
|
||||
$ brew install kennethreitz/-/bashf --head
|
||||
|
||||
+33
-2
@@ -4,6 +4,9 @@ bash.py module
|
||||
import re
|
||||
import time
|
||||
import json as json_lib
|
||||
import os
|
||||
import stat
|
||||
from tempfile import mkstemp
|
||||
from shlex import quote as shlex_quote
|
||||
|
||||
import delegator
|
||||
@@ -100,9 +103,37 @@ class Bash:
|
||||
"""execute the bash process as a child of this process"""
|
||||
return BashProcess(parent=self, args=args, **kwargs)
|
||||
|
||||
def command(self, script: str, **kwargs) -> BashProcess:
|
||||
def command(self, script: str, debug=False, **kwargs) -> BashProcess:
|
||||
"""form up the command with shlex and execute"""
|
||||
return self._exec(f"-c {shlex_quote(script)}", **kwargs)
|
||||
|
||||
tf = mkstemp(suffix='.sh', prefix='bashf-')[1]
|
||||
|
||||
with open(tf, 'w') as f:
|
||||
f.write(script)
|
||||
|
||||
# Mark the temporary file as executable.
|
||||
st = os.stat(tf)
|
||||
os.chmod(tf, st.st_mode | stat.S_IEXEC)
|
||||
|
||||
stdlib_path = os.path.join(
|
||||
os.path.dirname(__file__), 'scripts', 'stdlib.sh'
|
||||
)
|
||||
# print(stdlib_path)
|
||||
|
||||
# cmd = f"bash -c {(script)}"
|
||||
script = shlex_quote(f"unbuffer {tf} 2>&1 | bashf-indent")
|
||||
cmd = f'bash --init-file {shlex_quote(stdlib_path)} -i -c {script} '
|
||||
|
||||
if debug:
|
||||
print(cmd)
|
||||
|
||||
return_code = os.system(cmd)
|
||||
|
||||
if not debug:
|
||||
# Cleanup temporary file.
|
||||
os.remove(tf)
|
||||
|
||||
return return_code
|
||||
|
||||
|
||||
def run(script=None, **kwargs):
|
||||
|
||||
@@ -48,9 +48,6 @@ class TaskScript:
|
||||
if t.name not in [task.name for task in tasks]:
|
||||
tasks.insert(i + 1, t)
|
||||
|
||||
# if reverse:
|
||||
# tasks = list(reversed(tasks))
|
||||
|
||||
return tasks
|
||||
|
||||
@classmethod
|
||||
|
||||
+35
-11
@@ -4,6 +4,10 @@ import crayons
|
||||
from .bashfile import Bashfile
|
||||
|
||||
|
||||
def indent(line):
|
||||
return f'{" " * 4}{line}'
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument(
|
||||
'task',
|
||||
@@ -31,6 +35,13 @@ from .bashfile import Bashfile
|
||||
multiple=True,
|
||||
help='task environment variable (can be passed multiple times).',
|
||||
)
|
||||
@click.option(
|
||||
'--fail',
|
||||
'-x',
|
||||
is_flag=True,
|
||||
type=click.BOOL,
|
||||
help='Fail immediately, if any task fails.',
|
||||
)
|
||||
@click.option(
|
||||
'--arg',
|
||||
'-a',
|
||||
@@ -39,6 +50,9 @@ from .bashfile import Bashfile
|
||||
multiple=True,
|
||||
help='task ARGV arguments (can be passed multiple times).',
|
||||
)
|
||||
@click.option(
|
||||
'--quiet', '-q', is_flag=True, type=click.BOOL, help='Reduce output.'
|
||||
)
|
||||
@click.option(
|
||||
'--environ-json',
|
||||
'-j',
|
||||
@@ -47,7 +61,17 @@ from .bashfile import Bashfile
|
||||
help='environment variables, in JSON format.',
|
||||
)
|
||||
def task(
|
||||
*, task, bashfile, arg, _list, environ, environ_json, shellcheck, debug
|
||||
*,
|
||||
task,
|
||||
bashfile,
|
||||
arg,
|
||||
_list,
|
||||
environ,
|
||||
fail,
|
||||
environ_json,
|
||||
shellcheck,
|
||||
debug,
|
||||
quiet,
|
||||
):
|
||||
"""bashf — Bashfile runner (the familiar Bash/Make hybrid)."""
|
||||
# Default to list behavior, when no task is provided.
|
||||
@@ -80,22 +104,22 @@ def task(
|
||||
try:
|
||||
task = bashfile[task]
|
||||
except KeyError:
|
||||
click.echo(f'Task {task!r} does not exist!')
|
||||
click.echo(crayons.red(f'Task {task!r} does not exist!'))
|
||||
sys.exit(1)
|
||||
|
||||
# print(task)
|
||||
for task in task.depends_on(recursive=True):
|
||||
cmd = task.execute()
|
||||
if not quiet:
|
||||
click.echo(crayons.yellow(f'Executing task {task.name!r}…'))
|
||||
return_code = task.execute()
|
||||
|
||||
for line in cmd.output:
|
||||
click.echo(line, nl=False, err=False)
|
||||
if fail:
|
||||
if not return_code == 0:
|
||||
click.echo(f'Task {task.name!r} failed!')
|
||||
sys.exit(return_code)
|
||||
|
||||
# if cmd.err:
|
||||
# click.echo(cmd.err, nl=False, err=True)
|
||||
|
||||
if not cmd.ok:
|
||||
click.echo(f'Task {task.name!r} failed!')
|
||||
sys.exit(cmd.return_code)
|
||||
click.echo('Done!')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def entrypoint():
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$(uname)" == Darwin ]; then
|
||||
bashf-sed() { command sed -l "$@"; }
|
||||
else
|
||||
bashf-sed() { command sed -u "$@"; }
|
||||
fi
|
||||
|
||||
# Syntax sugar.
|
||||
bashf-indent() {
|
||||
bashf-sed "s/^/ /"
|
||||
}
|
||||
Reference in New Issue
Block a user