bakefile 0.0.9__py3-none-any.whl → 0.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bake/cli/bake/main.py +51 -9
- bake/cli/bake/reinvocation.py +6 -3
- bake/cli/bakefile/main.py +38 -4
- bake/cli/common/app.py +35 -33
- bake/cli/common/context.py +4 -0
- bake/cli/common/obj.py +4 -3
- bake/cli/common/params.py +10 -2
- bake/manage/find_python.py +26 -9
- bake/manage/lint.py +10 -7
- bake/ui/console.py +73 -9
- bake/ui/run/run.py +45 -13
- bake/ui/run/splitter.py +42 -31
- bake/ui/run/uv.py +2 -10
- bake/utils/__init__.py +8 -2
- bake/utils/settings.py +25 -0
- {bakefile-0.0.9.dist-info → bakefile-0.0.11.dist-info}/METADATA +3 -1
- {bakefile-0.0.9.dist-info → bakefile-0.0.11.dist-info}/RECORD +28 -24
- {bakefile-0.0.9.dist-info → bakefile-0.0.11.dist-info}/WHEEL +1 -1
- bakelib/__init__.py +2 -0
- bakelib/refreshable_cache/__init__.py +17 -0
- bakelib/refreshable_cache/cache.py +250 -0
- bakelib/refreshable_cache/exceptions.py +2 -0
- bakelib/space/base.py +29 -20
- bakelib/space/lib.py +161 -0
- bakelib/space/python.py +17 -0
- bakelib/space/python_lib.py +77 -0
- bakelib/space/utils.py +10 -0
- bake/cli/common/callback.py +0 -13
- bake/utils/env.py +0 -10
- {bakefile-0.0.9.dist-info → bakefile-0.0.11.dist-info}/entry_points.txt +0 -0
bake/cli/bake/main.py
CHANGED
|
@@ -1,17 +1,53 @@
|
|
|
1
1
|
import sys
|
|
2
|
+
from collections.abc import Callable
|
|
2
3
|
from contextlib import contextmanager
|
|
4
|
+
from pathlib import Path
|
|
3
5
|
|
|
4
6
|
import typer
|
|
5
7
|
|
|
6
8
|
from bake.cli.bake.reinvocation import _reinvoke_with_detected_python
|
|
7
9
|
from bake.cli.common.app import (
|
|
8
10
|
add_completion,
|
|
9
|
-
|
|
11
|
+
call_app_with_chdir,
|
|
10
12
|
rich_markup_mode,
|
|
13
|
+
show_help_if_no_command,
|
|
14
|
+
)
|
|
15
|
+
from bake.cli.common.context import Context
|
|
16
|
+
from bake.cli.common.obj import BakefileObject, get_bakefile_object, is_bakebook_optional
|
|
17
|
+
from bake.cli.common.params import (
|
|
18
|
+
bakebook_name_option,
|
|
19
|
+
chdir_option,
|
|
20
|
+
dry_run_option,
|
|
21
|
+
file_name_option,
|
|
22
|
+
is_chain_commands_option,
|
|
23
|
+
verbosity_option,
|
|
24
|
+
version_option,
|
|
11
25
|
)
|
|
12
|
-
from bake.cli.common.obj import get_bakefile_object, is_bakebook_optional
|
|
13
26
|
from bake.ui import console
|
|
14
|
-
from bake.utils import
|
|
27
|
+
from bake.utils.constants import (
|
|
28
|
+
DEFAULT_BAKEBOOK_NAME,
|
|
29
|
+
DEFAULT_CHDIR,
|
|
30
|
+
DEFAULT_FILE_NAME,
|
|
31
|
+
DEFAULT_IS_CHAIN_COMMAND,
|
|
32
|
+
)
|
|
33
|
+
from bake.utils.settings import bake_settings
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def bake_app_callback_with_obj(obj: BakefileObject) -> Callable[..., None]:
|
|
37
|
+
def bake_app_callback(
|
|
38
|
+
ctx: Context,
|
|
39
|
+
_chdir: chdir_option = DEFAULT_CHDIR,
|
|
40
|
+
_file_name: file_name_option = DEFAULT_FILE_NAME,
|
|
41
|
+
_bakebook_name: bakebook_name_option = DEFAULT_BAKEBOOK_NAME,
|
|
42
|
+
_version: version_option = False,
|
|
43
|
+
_is_chain_commands: is_chain_commands_option = DEFAULT_IS_CHAIN_COMMAND,
|
|
44
|
+
_verbosity: verbosity_option = 0,
|
|
45
|
+
_dry_run: dry_run_option = False,
|
|
46
|
+
):
|
|
47
|
+
ctx.obj = obj
|
|
48
|
+
show_help_if_no_command(ctx)
|
|
49
|
+
|
|
50
|
+
return bake_app_callback
|
|
15
51
|
|
|
16
52
|
|
|
17
53
|
@contextmanager
|
|
@@ -24,13 +60,15 @@ def set_argv(argv: list[str]):
|
|
|
24
60
|
sys.argv = original
|
|
25
61
|
|
|
26
62
|
|
|
27
|
-
def _run_chain_commands(
|
|
63
|
+
def _run_chain_commands(
|
|
64
|
+
remaining_args: list[str], prog_name: str, bake_app: typer.Typer, bakefile_path: Path | None
|
|
65
|
+
) -> int:
|
|
28
66
|
exit_code = 0
|
|
29
67
|
for cmd in remaining_args:
|
|
30
68
|
try:
|
|
31
69
|
with set_argv([prog_name, cmd]):
|
|
32
70
|
console.cmd(" ".join(sys.argv))
|
|
33
|
-
bake_app
|
|
71
|
+
call_app_with_chdir(app=bake_app, bakefile_path=bakefile_path, prog_name=prog_name)
|
|
34
72
|
except SystemExit as e:
|
|
35
73
|
if e.code is not None and e.code != 0:
|
|
36
74
|
exit_code = e.code if isinstance(e.code, int) else 1
|
|
@@ -52,14 +90,15 @@ def main():
|
|
|
52
90
|
allow_missing=is_bakebook_optional(remaining_args=bakefile_obj.remaining_args)
|
|
53
91
|
)
|
|
54
92
|
|
|
55
|
-
bakefile_obj.warn_if_no_bakebook(color_echo=
|
|
93
|
+
bakefile_obj.warn_if_no_bakebook(color_echo=bake_settings.should_use_colors())
|
|
56
94
|
|
|
57
95
|
bake_app = typer.Typer(
|
|
58
96
|
add_completion=add_completion,
|
|
59
97
|
rich_markup_mode=rich_markup_mode,
|
|
60
98
|
)
|
|
61
99
|
|
|
62
|
-
|
|
100
|
+
callback = bake_app_callback_with_obj(obj=bakefile_obj)
|
|
101
|
+
bake_app.callback(invoke_without_command=True)(callback)
|
|
63
102
|
|
|
64
103
|
prog_name = "bake"
|
|
65
104
|
|
|
@@ -68,7 +107,10 @@ def main():
|
|
|
68
107
|
|
|
69
108
|
if bakefile_obj.is_chain_commands and bakefile_obj.remaining_args:
|
|
70
109
|
exit_code = _run_chain_commands(
|
|
71
|
-
remaining_args=bakefile_obj.remaining_args,
|
|
110
|
+
remaining_args=bakefile_obj.remaining_args,
|
|
111
|
+
prog_name=prog_name,
|
|
112
|
+
bake_app=bake_app,
|
|
113
|
+
bakefile_path=bakefile_obj.bakefile_path,
|
|
72
114
|
)
|
|
73
115
|
raise SystemExit(exit_code)
|
|
74
|
-
bake_app
|
|
116
|
+
call_app_with_chdir(app=bake_app, bakefile_path=bakefile_obj.bakefile_path, prog_name=prog_name)
|
bake/cli/bake/reinvocation.py
CHANGED
|
@@ -4,7 +4,7 @@ import subprocess
|
|
|
4
4
|
import sys
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
-
from bake.utils.
|
|
7
|
+
from bake.utils.settings import ENV__BAKE_REINVOKED, bake_settings
|
|
8
8
|
|
|
9
9
|
logger = logging.getLogger(__name__)
|
|
10
10
|
|
|
@@ -21,8 +21,11 @@ def _reinvoke_with_detected_python(bakefile_path: Path | None) -> None:
|
|
|
21
21
|
Returns:
|
|
22
22
|
None. Either calls os.execve() (replaces process) or returns normally.
|
|
23
23
|
"""
|
|
24
|
+
# Access via module path so tests can reassign
|
|
25
|
+
# from bake.utils import settings
|
|
26
|
+
|
|
24
27
|
# 1. Check marker to prevent infinite loops
|
|
25
|
-
if
|
|
28
|
+
if bake_settings.bake_reinvoked:
|
|
26
29
|
logger.debug(
|
|
27
30
|
"Re-invocation marker set, skipping Python check",
|
|
28
31
|
extra={"sys.executable": sys.executable},
|
|
@@ -52,7 +55,7 @@ def _reinvoke_with_detected_python(bakefile_path: Path | None) -> None:
|
|
|
52
55
|
extra={"target_python": str(target_python)},
|
|
53
56
|
)
|
|
54
57
|
env = os.environ.copy()
|
|
55
|
-
env[
|
|
58
|
+
env[ENV__BAKE_REINVOKED] = "1"
|
|
56
59
|
|
|
57
60
|
sys.stdout.flush()
|
|
58
61
|
sys.stderr.flush()
|
bake/cli/bakefile/main.py
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
1
3
|
from bake.cli.common.app import (
|
|
2
4
|
BakefileApp,
|
|
3
5
|
add_completion,
|
|
4
|
-
|
|
6
|
+
call_app_with_chdir,
|
|
5
7
|
rich_markup_mode,
|
|
8
|
+
show_help_if_no_command,
|
|
9
|
+
)
|
|
10
|
+
from bake.cli.common.context import Context
|
|
11
|
+
from bake.cli.common.obj import BakefileObject, get_bakefile_object
|
|
12
|
+
from bake.cli.common.params import (
|
|
13
|
+
bakebook_name_option,
|
|
14
|
+
chdir_option,
|
|
15
|
+
dry_run_option,
|
|
16
|
+
file_name_option,
|
|
17
|
+
verbosity_option,
|
|
18
|
+
version_option,
|
|
19
|
+
)
|
|
20
|
+
from bake.utils.constants import (
|
|
21
|
+
DEFAULT_BAKEBOOK_NAME,
|
|
22
|
+
DEFAULT_CHDIR,
|
|
23
|
+
DEFAULT_FILE_NAME,
|
|
6
24
|
)
|
|
7
|
-
from bake.cli.common.obj import get_bakefile_object
|
|
8
25
|
|
|
9
26
|
from . import uv
|
|
10
27
|
from .add_inline import add_inline
|
|
@@ -14,6 +31,22 @@ from .init import init
|
|
|
14
31
|
from .lint import lint
|
|
15
32
|
|
|
16
33
|
|
|
34
|
+
def bakefile_app_callback_with_obj(obj: BakefileObject) -> Callable[..., None]:
|
|
35
|
+
def bakefile_app_callback(
|
|
36
|
+
ctx: Context,
|
|
37
|
+
_chdir: chdir_option = DEFAULT_CHDIR,
|
|
38
|
+
_file_name: file_name_option = DEFAULT_FILE_NAME,
|
|
39
|
+
_bakebook_name: bakebook_name_option = DEFAULT_BAKEBOOK_NAME,
|
|
40
|
+
_version: version_option = False,
|
|
41
|
+
_verbosity: verbosity_option = 0,
|
|
42
|
+
_dry_run: dry_run_option = False,
|
|
43
|
+
):
|
|
44
|
+
ctx.obj = obj
|
|
45
|
+
show_help_if_no_command(ctx)
|
|
46
|
+
|
|
47
|
+
return bakefile_app_callback
|
|
48
|
+
|
|
49
|
+
|
|
17
50
|
def main():
|
|
18
51
|
bakefile_obj = get_bakefile_object(rich_markup_mode=rich_markup_mode)
|
|
19
52
|
bakefile_obj.setup_logging()
|
|
@@ -29,7 +62,8 @@ def main():
|
|
|
29
62
|
"ignore_unknown_options": True,
|
|
30
63
|
}
|
|
31
64
|
|
|
32
|
-
|
|
65
|
+
callback = bakefile_app_callback_with_obj(obj=bakefile_obj)
|
|
66
|
+
bakefile_app.callback(invoke_without_command=True)(callback)
|
|
33
67
|
bakefile_app.command()(init)
|
|
34
68
|
bakefile_app.command()(add_inline)
|
|
35
69
|
bakefile_app.command()(find_python)
|
|
@@ -40,4 +74,4 @@ def main():
|
|
|
40
74
|
bakefile_app.command(context_settings=uv_commands_context_settings)(uv.add)
|
|
41
75
|
bakefile_app.command(context_settings=uv_commands_context_settings)(uv.pip)
|
|
42
76
|
bakefile_app.bakefile_object = bakefile_obj
|
|
43
|
-
bakefile_app
|
|
77
|
+
call_app_with_chdir(app=bakefile_app, bakefile_path=bakefile_obj.bakefile_path)
|
bake/cli/common/app.py
CHANGED
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from collections.abc import Generator
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
2
7
|
|
|
3
8
|
import typer
|
|
4
9
|
from typer.core import MarkupMode
|
|
5
10
|
|
|
6
11
|
from bake.cli.common.context import Context
|
|
7
|
-
from bake.cli.common.params import (
|
|
8
|
-
bakebook_name_option,
|
|
9
|
-
chdir_option,
|
|
10
|
-
dry_run_option,
|
|
11
|
-
file_name_option,
|
|
12
|
-
is_chain_commands_option,
|
|
13
|
-
verbosity_option,
|
|
14
|
-
version_option,
|
|
15
|
-
)
|
|
16
12
|
from bake.ui import console
|
|
17
|
-
from bake.utils.constants import (
|
|
18
|
-
DEFAULT_BAKEBOOK_NAME,
|
|
19
|
-
DEFAULT_CHDIR,
|
|
20
|
-
DEFAULT_FILE_NAME,
|
|
21
|
-
DEFAULT_IS_CHAIN_COMMAND,
|
|
22
|
-
)
|
|
23
13
|
|
|
24
14
|
from .obj import BakefileObject
|
|
25
15
|
|
|
@@ -31,24 +21,36 @@ class BakefileApp(typer.Typer):
|
|
|
31
21
|
bakefile_object: BakefileObject
|
|
32
22
|
|
|
33
23
|
|
|
24
|
+
if sys.version_info >= (3, 11):
|
|
25
|
+
from contextlib import chdir
|
|
26
|
+
else:
|
|
27
|
+
|
|
28
|
+
@contextmanager
|
|
29
|
+
def chdir(path: Path) -> Generator[None, None, None]:
|
|
30
|
+
"""Change directory context manager for Python < 3.11 compatibility."""
|
|
31
|
+
original = Path.cwd()
|
|
32
|
+
try:
|
|
33
|
+
os.chdir(path)
|
|
34
|
+
yield
|
|
35
|
+
finally:
|
|
36
|
+
os.chdir(original)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def call_app_with_chdir(
|
|
40
|
+
app: typer.Typer,
|
|
41
|
+
bakefile_path: Path | None,
|
|
42
|
+
*args: Any,
|
|
43
|
+
**kwargs: Any,
|
|
44
|
+
) -> None:
|
|
45
|
+
if bakefile_path is not None:
|
|
46
|
+
dir_path = bakefile_path.parent
|
|
47
|
+
with chdir(dir_path):
|
|
48
|
+
app(*args, **kwargs)
|
|
49
|
+
else:
|
|
50
|
+
app(*args, **kwargs)
|
|
51
|
+
|
|
52
|
+
|
|
34
53
|
def show_help_if_no_command(ctx: Context) -> None:
|
|
35
54
|
if ctx.invoked_subcommand is None:
|
|
36
55
|
console.echo(ctx.get_help())
|
|
37
56
|
raise typer.Exit(1)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def bake_app_callback_with_obj(obj: BakefileObject) -> Callable:
|
|
41
|
-
def bake_app_callback(
|
|
42
|
-
ctx: Context,
|
|
43
|
-
_chdir: chdir_option = DEFAULT_CHDIR,
|
|
44
|
-
_file_name: file_name_option = DEFAULT_FILE_NAME,
|
|
45
|
-
_bakebook_name: bakebook_name_option = DEFAULT_BAKEBOOK_NAME,
|
|
46
|
-
_version: version_option = False,
|
|
47
|
-
_is_chain_commands: is_chain_commands_option = DEFAULT_IS_CHAIN_COMMAND,
|
|
48
|
-
_verbosity: verbosity_option = 0,
|
|
49
|
-
_dry_run: dry_run_option = False,
|
|
50
|
-
):
|
|
51
|
-
ctx.obj = obj
|
|
52
|
-
show_help_if_no_command(ctx)
|
|
53
|
-
|
|
54
|
-
return bake_app_callback
|
bake/cli/common/context.py
CHANGED
|
@@ -57,6 +57,7 @@ class Context(typer.Context):
|
|
|
57
57
|
stream: bool = True,
|
|
58
58
|
shell: bool | None = None,
|
|
59
59
|
echo: bool = True,
|
|
60
|
+
echo_cmd: str | None = None,
|
|
60
61
|
dry_run: bool | None = None,
|
|
61
62
|
keep_temp_file: bool = False,
|
|
62
63
|
env: dict[str, str] | None = None,
|
|
@@ -74,6 +75,7 @@ class Context(typer.Context):
|
|
|
74
75
|
stream: bool = True,
|
|
75
76
|
shell: bool | None = None,
|
|
76
77
|
echo: bool = True,
|
|
78
|
+
echo_cmd: str | None = None,
|
|
77
79
|
dry_run: bool | None = None,
|
|
78
80
|
keep_temp_file: bool = False,
|
|
79
81
|
env: dict[str, str] | None = None,
|
|
@@ -90,6 +92,7 @@ class Context(typer.Context):
|
|
|
90
92
|
stream: bool = True,
|
|
91
93
|
shell: bool | None = None,
|
|
92
94
|
echo: bool = True,
|
|
95
|
+
echo_cmd: str | None = None,
|
|
93
96
|
dry_run: bool | None = None,
|
|
94
97
|
keep_temp_file: bool = False,
|
|
95
98
|
env: dict[str, str] | None = None,
|
|
@@ -104,6 +107,7 @@ class Context(typer.Context):
|
|
|
104
107
|
stream=stream,
|
|
105
108
|
shell=shell,
|
|
106
109
|
echo=echo,
|
|
110
|
+
echo_cmd=echo_cmd,
|
|
107
111
|
dry_run=self.obj.dry_run if dry_run is None else dry_run,
|
|
108
112
|
keep_temp_file=keep_temp_file,
|
|
109
113
|
env=env,
|
bake/cli/common/obj.py
CHANGED
|
@@ -27,7 +27,6 @@ from bake.utils.constants import (
|
|
|
27
27
|
)
|
|
28
28
|
from bake.utils.exceptions import BakebookError, BakefileNotFoundError
|
|
29
29
|
|
|
30
|
-
from .callback import validate_file_name
|
|
31
30
|
from .exception_handler import typer_exception_handler
|
|
32
31
|
from .params import (
|
|
33
32
|
bakebook_name_option,
|
|
@@ -36,6 +35,7 @@ from .params import (
|
|
|
36
35
|
file_name_option,
|
|
37
36
|
is_chain_commands_option,
|
|
38
37
|
remaining_args_argument,
|
|
38
|
+
validate_file_name,
|
|
39
39
|
verbosity_option,
|
|
40
40
|
)
|
|
41
41
|
|
|
@@ -112,8 +112,9 @@ class BakefileObject:
|
|
|
112
112
|
console.echo(f"Searched in: {self.chdir.resolve()}\n")
|
|
113
113
|
|
|
114
114
|
def setup_logging(self):
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
# Verbosity: 0=silent, 1=INFO, 2=DEBUG (CRITICAL+1 silences all logs)
|
|
116
|
+
level_map: dict[int, int] = {0: logging.CRITICAL + 1, 1: logging.INFO, 2: logging.DEBUG}
|
|
117
|
+
log_level = level_map.get(self.verbosity, logging.CRITICAL + 1)
|
|
117
118
|
setup_logging(level_per_module={"": log_level}, is_pretty_log=True)
|
|
118
119
|
|
|
119
120
|
|
bake/cli/common/params.py
CHANGED
|
@@ -3,10 +3,18 @@ from typing import Annotated
|
|
|
3
3
|
|
|
4
4
|
import typer
|
|
5
5
|
|
|
6
|
-
from bake.cli.common.callback import validate_file_name_callback
|
|
7
6
|
from bake.cli.utils.version import version_callback
|
|
8
7
|
|
|
9
8
|
|
|
9
|
+
def validate_file_name(value: str) -> str:
|
|
10
|
+
"""Validate file name for --file-name option."""
|
|
11
|
+
if "/" in value or "\\" in value:
|
|
12
|
+
raise typer.BadParameter(f"File name must not contain path separators: {value}")
|
|
13
|
+
if not value.endswith(".py"):
|
|
14
|
+
raise typer.BadParameter(f"File name must end with .py: {value}")
|
|
15
|
+
return value
|
|
16
|
+
|
|
17
|
+
|
|
10
18
|
def verbosity_callback(_ctx: typer.Context, _param: typer.CallbackParam, value: int) -> int:
|
|
11
19
|
"""Validate verbosity level (max 2)."""
|
|
12
20
|
if value > 2:
|
|
@@ -31,7 +39,7 @@ file_name_option = Annotated[
|
|
|
31
39
|
"--file-name",
|
|
32
40
|
"-f",
|
|
33
41
|
help="Path to bakefile.py",
|
|
34
|
-
callback=
|
|
42
|
+
callback=validate_file_name,
|
|
35
43
|
),
|
|
36
44
|
]
|
|
37
45
|
bakebook_name_option = Annotated[
|
bake/manage/find_python.py
CHANGED
|
@@ -9,6 +9,8 @@ from bake.utils.exceptions import PythonNotFoundError
|
|
|
9
9
|
|
|
10
10
|
logger = logging.getLogger(__name__)
|
|
11
11
|
|
|
12
|
+
_NO_PROJECT_PYTHON_MSG = "No project Python found"
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
def is_standalone_bakefile(bakefile_path: Path) -> bool:
|
|
14
16
|
inline_metadata = read_inline(bakefile_path)
|
|
@@ -101,18 +103,33 @@ def _find_project_python(bakefile_path: Path) -> Path | None:
|
|
|
101
103
|
# Check if stderr contains "Found `...` at `...` (...)"
|
|
102
104
|
# where source is "active virtual environment" or "virtual environment"
|
|
103
105
|
stderr = result.stderr.strip()
|
|
104
|
-
pattern = r"Found `[^`]+` at `[^`]
|
|
106
|
+
pattern = r"Found `[^`]+` at `([^`]+)` \(([^)]+)\)"
|
|
105
107
|
match = re.search(pattern, stderr)
|
|
106
108
|
|
|
107
|
-
if result.returncode == 0 and match:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
python_path = Path(result.stdout.strip())
|
|
111
|
-
logger.debug(f"Found project Python at {python_path} (source: {source})")
|
|
112
|
-
return python_path
|
|
109
|
+
if not (result.returncode == 0 and match):
|
|
110
|
+
logger.debug(_NO_PROJECT_PYTHON_MSG)
|
|
111
|
+
return None
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
source = match.group(2)
|
|
114
|
+
if source not in {"active virtual environment", "virtual environment"}:
|
|
115
|
+
logger.debug(_NO_PROJECT_PYTHON_MSG)
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
python_path_from_log = Path(match.group(1))
|
|
119
|
+
python_path_from_stdout = Path(result.stdout.strip())
|
|
120
|
+
if python_path_from_log != python_path_from_stdout:
|
|
121
|
+
logger.debug(
|
|
122
|
+
"Python path mismatch between log and stdout",
|
|
123
|
+
extra={
|
|
124
|
+
"python_path_from_log": python_path_from_log,
|
|
125
|
+
"python_path_from_stdout": python_path_from_stdout,
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
logger.debug(_NO_PROJECT_PYTHON_MSG)
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
logger.debug(f"Found project Python at {python_path_from_stdout} (source: {source})")
|
|
132
|
+
return python_path_from_stdout
|
|
116
133
|
|
|
117
134
|
|
|
118
135
|
def _create_bakefile_venv(bakefile_path: Path) -> Path | None:
|
bake/manage/lint.py
CHANGED
|
@@ -5,7 +5,6 @@ from pathlib import Path
|
|
|
5
5
|
from ruff.__main__ import find_ruff_bin
|
|
6
6
|
from ty.__main__ import find_ty_bin
|
|
7
7
|
|
|
8
|
-
from bake.ui import console
|
|
9
8
|
from bake.ui.run import run
|
|
10
9
|
|
|
11
10
|
logger = logging.getLogger(__name__)
|
|
@@ -19,19 +18,19 @@ def run_ruff(
|
|
|
19
18
|
only_bakefile: bool = False,
|
|
20
19
|
check: bool = True,
|
|
21
20
|
dry_run: bool = False,
|
|
21
|
+
echo: bool = True,
|
|
22
22
|
) -> subprocess.CompletedProcess[str]:
|
|
23
23
|
ruff_bin = find_ruff_bin()
|
|
24
24
|
target = bakefile_path.name if only_bakefile else "."
|
|
25
25
|
cmd = [subcommand, *args, target]
|
|
26
|
-
display_cmd = "ruff " + " ".join(cmd)
|
|
27
|
-
console.cmd(display_cmd)
|
|
28
26
|
return run(
|
|
29
27
|
[str(ruff_bin), *cmd],
|
|
30
28
|
cwd=bakefile_path.parent,
|
|
31
29
|
capture_output=True,
|
|
32
30
|
stream=True,
|
|
33
31
|
check=check,
|
|
34
|
-
echo=
|
|
32
|
+
echo=echo,
|
|
33
|
+
echo_cmd="ruff " + " ".join(cmd) if echo else None,
|
|
35
34
|
dry_run=dry_run,
|
|
36
35
|
)
|
|
37
36
|
|
|
@@ -42,6 +41,7 @@ def run_ruff_format(
|
|
|
42
41
|
only_bakefile: bool = False,
|
|
43
42
|
check: bool = True,
|
|
44
43
|
dry_run: bool = False,
|
|
44
|
+
echo: bool = True,
|
|
45
45
|
) -> subprocess.CompletedProcess[str]:
|
|
46
46
|
return run_ruff(
|
|
47
47
|
bakefile_path=bakefile_path,
|
|
@@ -50,6 +50,7 @@ def run_ruff_format(
|
|
|
50
50
|
only_bakefile=only_bakefile,
|
|
51
51
|
check=check,
|
|
52
52
|
dry_run=dry_run,
|
|
53
|
+
echo=echo,
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
|
|
@@ -59,6 +60,7 @@ def run_ruff_check(
|
|
|
59
60
|
only_bakefile: bool = False,
|
|
60
61
|
check: bool = True,
|
|
61
62
|
dry_run: bool = False,
|
|
63
|
+
echo: bool = True,
|
|
62
64
|
) -> subprocess.CompletedProcess[str]:
|
|
63
65
|
return run_ruff(
|
|
64
66
|
bakefile_path=bakefile_path,
|
|
@@ -72,6 +74,7 @@ def run_ruff_check(
|
|
|
72
74
|
only_bakefile=only_bakefile,
|
|
73
75
|
check=check,
|
|
74
76
|
dry_run=dry_run,
|
|
77
|
+
echo=echo,
|
|
75
78
|
)
|
|
76
79
|
|
|
77
80
|
|
|
@@ -82,20 +85,20 @@ def run_ty_check(
|
|
|
82
85
|
only_bakefile: bool = False,
|
|
83
86
|
check: bool = True,
|
|
84
87
|
dry_run: bool = False,
|
|
88
|
+
echo: bool = True,
|
|
85
89
|
) -> subprocess.CompletedProcess[str]:
|
|
86
90
|
ty_bin = find_ty_bin()
|
|
87
91
|
cmd = ["check", "--error-on-warning", "--python", str(python_path)]
|
|
88
92
|
if only_bakefile:
|
|
89
93
|
cmd.append(bakefile_path.name)
|
|
90
94
|
|
|
91
|
-
display_cmd = "ty " + " ".join(cmd)
|
|
92
|
-
console.cmd(display_cmd)
|
|
93
95
|
return run(
|
|
94
96
|
[str(ty_bin), *cmd],
|
|
95
97
|
cwd=bakefile_path.parent,
|
|
96
98
|
capture_output=True,
|
|
97
99
|
stream=True,
|
|
98
100
|
check=check,
|
|
99
|
-
echo=
|
|
101
|
+
echo=echo,
|
|
102
|
+
echo_cmd="ty " + " ".join(cmd) if echo else None,
|
|
100
103
|
dry_run=dry_run,
|
|
101
104
|
)
|
bake/ui/console.py
CHANGED
|
@@ -1,26 +1,72 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
import textwrap
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
4
5
|
from beautysh import BashFormatter
|
|
5
6
|
from rich.console import Console
|
|
6
7
|
|
|
8
|
+
from bake.utils.settings import bake_settings
|
|
9
|
+
|
|
7
10
|
out = Console(stderr=False)
|
|
8
11
|
err = Console(stderr=True)
|
|
9
12
|
|
|
10
13
|
BOLD_GREEN = "bold green"
|
|
14
|
+
UNICODE_ENCODINGS = {"utf-8", "utf-16", "utf-32", "utf-16-le", "utf-16-be"}
|
|
11
15
|
|
|
12
16
|
|
|
13
|
-
def
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
def _supports_unicode() -> bool:
|
|
18
|
+
return sys.stdout.encoding.lower() in UNICODE_ENCODINGS
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _format_prefix(
|
|
22
|
+
console_obj: Console,
|
|
23
|
+
emoji: str | None,
|
|
24
|
+
label: str,
|
|
25
|
+
style: str,
|
|
26
|
+
message: str,
|
|
27
|
+
) -> str:
|
|
16
28
|
formatted_label = f"[{label}]" if console_obj.no_color or out.color_system is None else label
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
# Strip emoji/unicode in non-UTF contexts (e.g., Windows CI) to avoid encoding issues
|
|
31
|
+
emoji_str = ""
|
|
32
|
+
if emoji and _supports_unicode():
|
|
33
|
+
emoji_str = emoji + " "
|
|
34
|
+
|
|
35
|
+
return f"[{style}]{emoji_str}{formatted_label}[/{style}] {message}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def prefix_out(
|
|
39
|
+
message: str,
|
|
40
|
+
emoji: str | None = None,
|
|
41
|
+
label: str = "INFO",
|
|
42
|
+
style: str = "bold blue",
|
|
43
|
+
**kwargs,
|
|
44
|
+
) -> None:
|
|
45
|
+
out.print(_format_prefix(out, emoji=emoji, label=label, style=style, message=message), **kwargs)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def prefix_err(
|
|
49
|
+
message: str,
|
|
50
|
+
emoji: str | None = None,
|
|
51
|
+
label: str = "INFO",
|
|
52
|
+
style: str = "bold blue",
|
|
53
|
+
**kwargs,
|
|
54
|
+
) -> None:
|
|
55
|
+
err.print(_format_prefix(err, emoji=emoji, label=label, style=style, message=message), **kwargs)
|
|
20
56
|
|
|
21
57
|
|
|
22
58
|
def success(message: str, **kwargs) -> None:
|
|
23
|
-
|
|
59
|
+
prefix_out(
|
|
60
|
+
emoji=":white_check_mark:",
|
|
61
|
+
label="SUCCESS",
|
|
62
|
+
style=BOLD_GREEN,
|
|
63
|
+
message=message,
|
|
64
|
+
**kwargs,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def start(message: str, **kwargs) -> None:
|
|
69
|
+
prefix_out(emoji=None, label="START", style="cyan", message=f"{message}...", **kwargs)
|
|
24
70
|
|
|
25
71
|
|
|
26
72
|
def echo(message: Any, **kwargs) -> None:
|
|
@@ -28,7 +74,8 @@ def echo(message: Any, **kwargs) -> None:
|
|
|
28
74
|
|
|
29
75
|
|
|
30
76
|
def cmd(cmd_str: str, **kwargs) -> None:
|
|
31
|
-
|
|
77
|
+
arrow = "❯" if _supports_unicode() else ">" # noqa: RUF001
|
|
78
|
+
err.print(f"[{BOLD_GREEN}]{arrow}[/{BOLD_GREEN}] [default]{cmd_str}[/default]", **kwargs)
|
|
32
79
|
|
|
33
80
|
|
|
34
81
|
def script_block(title: str, script: str, **kwargs) -> None:
|
|
@@ -51,8 +98,25 @@ def script_block(title: str, script: str, **kwargs) -> None:
|
|
|
51
98
|
|
|
52
99
|
|
|
53
100
|
def warning(message: str, **kwargs) -> None:
|
|
54
|
-
|
|
101
|
+
if bake_settings.github_actions:
|
|
102
|
+
err.print(f"::warning::{message}", **kwargs)
|
|
103
|
+
else:
|
|
104
|
+
prefix_err(
|
|
105
|
+
emoji=":warning-emoji: ",
|
|
106
|
+
label="WARNING",
|
|
107
|
+
style="bold yellow",
|
|
108
|
+
message=message,
|
|
109
|
+
**kwargs,
|
|
110
|
+
)
|
|
55
111
|
|
|
56
112
|
|
|
57
113
|
def error(message: str, **kwargs) -> None:
|
|
58
|
-
|
|
114
|
+
if bake_settings.github_actions:
|
|
115
|
+
err.print(f"::error::{message}", **kwargs)
|
|
116
|
+
else:
|
|
117
|
+
prefix_err(emoji=":x:", label="ERROR", style="bold red", message=message, **kwargs)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def github_action_add_mask(value: str, **kwargs) -> None:
|
|
121
|
+
if bake_settings.github_actions:
|
|
122
|
+
out.print(f"::add-mask::{value}", **kwargs)
|