mirror of
https://github.com/kennethreitz/bake.git
synced 2026-06-05 23:00:17 +00:00
shellcheck
This commit is contained in:
@@ -11,3 +11,6 @@ system-install: @confirm
|
||||
|
||||
pypi-upload: python-dev-deps
|
||||
pipenv run setup.py upload
|
||||
|
||||
test:
|
||||
echo $@
|
||||
|
||||
+31
-11
@@ -1,8 +1,12 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
from random import randint
|
||||
from shlex import quote as shlex_quote
|
||||
from tempfile import mkstemp
|
||||
|
||||
import delegator
|
||||
import click
|
||||
|
||||
from .bash import Bash
|
||||
@@ -140,11 +144,7 @@ class TaskScript(BaseAction):
|
||||
if line.startswith(indent_style):
|
||||
return line[len(indent_style) :]
|
||||
|
||||
def execute(self, *, blocking=False, debug=False, silent=False, **kwargs):
|
||||
from tempfile import mkstemp
|
||||
import stat
|
||||
from shlex import quote as shlex_quote
|
||||
|
||||
def temp_source(self):
|
||||
tf = mkstemp(suffix=".sh", prefix="bashf-")[1]
|
||||
|
||||
with open(tf, "w") as f:
|
||||
@@ -154,6 +154,12 @@ class TaskScript(BaseAction):
|
||||
st = os.stat(tf)
|
||||
os.chmod(tf, st.st_mode | stat.S_IEXEC)
|
||||
|
||||
return tf
|
||||
|
||||
def execute(self, *, blocking=False, debug=False, silent=False, **kwargs):
|
||||
|
||||
tf = self.temp_source()
|
||||
|
||||
stdlib_path = os.path.join(os.path.dirname(__file__), "scripts", "stdlib.sh")
|
||||
|
||||
args = [shlex_quote(a) for a in self.bashfile.args]
|
||||
@@ -163,11 +169,19 @@ class TaskScript(BaseAction):
|
||||
else:
|
||||
script = shlex_quote(f"{tf} {args} 2>&1 | bake-indent")
|
||||
cmd = f"bash --init-file {shlex_quote(stdlib_path)} -i -c {script}"
|
||||
|
||||
if debug:
|
||||
print(cmd)
|
||||
click.echo(f"$ {cmd}", err=True)
|
||||
|
||||
return os.system(cmd)
|
||||
|
||||
def shellcheck(self, *, silent=False, debug=False, **kwargs):
|
||||
tf = self.temp_source()
|
||||
cmd = f"shellcheck {shlex_quote(tf)} --external-sources --format=json"
|
||||
if debug:
|
||||
click.echo(f"$ {cmd}", err=True)
|
||||
return delegator.run(cmd)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.chunk[0].split(":")[0].strip()
|
||||
@@ -177,6 +191,14 @@ class TaskScript(BaseAction):
|
||||
return self.bashfile.chunks[self._chunk_index]
|
||||
|
||||
def _iter_source(self):
|
||||
try:
|
||||
has_shebang = self.chunk[2].startswith("#!")
|
||||
except IndexError:
|
||||
has_shebang = False
|
||||
|
||||
if not has_shebang:
|
||||
yield "#!/usr/bin/env bash"
|
||||
|
||||
for line in self.chunk[1:]:
|
||||
line = self._transform_line(line)
|
||||
if line:
|
||||
@@ -188,9 +210,7 @@ class TaskScript(BaseAction):
|
||||
|
||||
@property
|
||||
def source_lines(self):
|
||||
def gen():
|
||||
for line in self.bashfile.source_lines:
|
||||
pass
|
||||
return [s for s in self._iter_source()]
|
||||
|
||||
|
||||
class Bakefile:
|
||||
|
||||
+43
-9
@@ -11,7 +11,7 @@ import pygments.lexers
|
||||
import pygments.formatters
|
||||
|
||||
|
||||
SAFE_ENVIRONS = ["HOME", "PATH"]
|
||||
SAFE_ENVIRONS = ["HOME", "PATH", "LANG", "LOCALE", "TERM", "VIRTUAL_ENV"]
|
||||
|
||||
|
||||
def indent(line):
|
||||
@@ -171,7 +171,7 @@ def entrypoint(
|
||||
|
||||
bakefile.add_args(*argv)
|
||||
|
||||
if _list:
|
||||
if _list and not shellcheck:
|
||||
__list_json = {"tasks": {}}
|
||||
|
||||
for _task in bakefile.tasks:
|
||||
@@ -202,6 +202,45 @@ def entrypoint(
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
if shellcheck:
|
||||
__shellcheck_statuses = []
|
||||
for _task in bakefile.tasks:
|
||||
_task = bakefile[_task]
|
||||
c = _task.shellcheck(silent=silent, debug=debug)
|
||||
__shellcheck_statuses.append(c.return_code)
|
||||
if not c.ok:
|
||||
# click.echo(click.style("Shellcheck failed!", fg="red"), err=True)
|
||||
if _json:
|
||||
echo_json(json.loads(c.out))
|
||||
|
||||
for report in json.loads(c.out):
|
||||
level = report["level"]
|
||||
code = report["code"]
|
||||
message = report["message"]
|
||||
line = report["line"]
|
||||
column = (report["column"], report["endColumn"])
|
||||
colored_line_n = click.style(
|
||||
str(line).zfill(3), bg="black", fg="cyan", bold=True
|
||||
)
|
||||
colored_task = click.style(str(_task), fg="yellow", bold=True)
|
||||
actual_line = _task.source_lines[line - 1]
|
||||
|
||||
click.echo(f"In {colored_task} line {line}:", err=True)
|
||||
click.echo(f"{colored_line_n} {actual_line}", err=True)
|
||||
|
||||
length = column[1] - column[0]
|
||||
if not length:
|
||||
length = len(actual_line)
|
||||
|
||||
underline = (" " * 4) + (" " * column[0]) + "^" + "-" * (length - 1)
|
||||
underline += f"SC{code}: {message}"
|
||||
underline = click.style(level, fg="magenta") + click.style(
|
||||
underline[len(level) :], fg="red", bold=True
|
||||
)
|
||||
|
||||
click.echo(underline, err=True)
|
||||
|
||||
sys.exit(max(__shellcheck_statuses))
|
||||
if task:
|
||||
try:
|
||||
task = bakefile[task]
|
||||
@@ -209,7 +248,7 @@ def entrypoint(
|
||||
click.echo(click.style(f"Task {task} does not exist!", fg="red"))
|
||||
sys.exit(1)
|
||||
|
||||
def execute_task(task, *, next_task=None, silent=False):
|
||||
def execute_task(task, *, silent=False):
|
||||
if not silent:
|
||||
click.echo(
|
||||
click.style(" + ", fg="white")
|
||||
@@ -217,7 +256,7 @@ def entrypoint(
|
||||
+ click.style(":", fg="white"),
|
||||
err=True,
|
||||
)
|
||||
return_code = task.execute(yes=yes, next_task=next_task, silent=silent)
|
||||
return_code = task.execute(yes=yes, silent=silent)
|
||||
|
||||
if not _continue:
|
||||
if not return_code == 0:
|
||||
@@ -226,11 +265,6 @@ def entrypoint(
|
||||
|
||||
tasks = task.depends_on(recursive=True) + [task]
|
||||
for task in tasks:
|
||||
try:
|
||||
next_task = tasks[tasks.index(task) + 1]
|
||||
except IndexError:
|
||||
next_task = None
|
||||
|
||||
execute_task(task, next_task=next_task, silent=silent)
|
||||
|
||||
if not silent:
|
||||
|
||||
Reference in New Issue
Block a user