Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions lading/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import collections.abc as cabc
import importlib
import logging
import os
import re
Expand All @@ -14,8 +15,10 @@
from cyclopts import App, Parameter

from . import commands, config
from .runtime import CommandRunner, subprocess_runner
from .utils import normalise_workspace_root
from .workspace import WorkspaceGraph, WorkspaceModelError, load_workspace
from .workspace import metadata as metadata_module

WORKSPACE_ROOT_ENV_VAR = "LADING_WORKSPACE_ROOT"
WORKSPACE_ROOT_REQUIRED_MESSAGE = "--workspace-root requires a value"
Expand Down Expand Up @@ -66,6 +69,8 @@
_DEFAULT_LOG_LEVEL = logging.INFO
_LOG_FORMAT = "%(levelname)s: %(message)s"
_LADING_HANDLER_NAME = "lading-cli-handler"
_CMD_MOX_STUB_ENV = "LADING_USE_CMD_MOX_STUB"
_CMD_MOX_TRUTHY_VALUES = frozenset({"1", "true", "yes", "on"})
_LOG_LEVEL_ALIASES: dict[str, int] = {
"CRITICAL": logging.CRITICAL,
"FATAL": logging.CRITICAL,
Expand All @@ -79,6 +84,15 @@
app = App(help="Manage Rust workspaces with the lading toolkit.")


def _select_runner() -> CommandRunner:
"""Return the command runner selected for this CLI invocation."""
stub_value = os.environ.get(_CMD_MOX_STUB_ENV, "")
if stub_value.lower() in _CMD_MOX_TRUTHY_VALUES:
module = importlib.import_module("lading.testing.cmd_mox_runner")
return typ.cast("CommandRunner", module.cmd_mox_runner)
return subprocess_runner


def _validate_workspace_value(value: str) -> str:
"""Ensure ``value`` is usable as a workspace path."""
if not value or value.startswith("-"):
Expand Down Expand Up @@ -246,20 +260,27 @@ def main(argv: cabc.Sequence[str] | None = None) -> int:
def _run_with_context(
workspace_root: Path,
runner: cabc.Callable[
[Path, config.LadingConfig | None, WorkspaceGraph | None],
[Path, config.LadingConfig | None, WorkspaceGraph | None, CommandRunner],
str,
],
*,
command_runner: CommandRunner | None = None,
) -> str:
"""Execute ``runner`` with configuration and workspace data."""
active_runner = command_runner or _select_runner()
try:
configuration = config.current_configuration()
except config.ConfigurationNotLoadedError:
configuration = config.load_configuration(workspace_root)
with (
config.use_configuration(configuration),
metadata_module.use_command_runner(active_runner),
):
workspace_model = load_workspace(workspace_root)
return runner(workspace_root, configuration, workspace_model, active_runner)
with metadata_module.use_command_runner(active_runner):
workspace_model = load_workspace(workspace_root)
with config.use_configuration(configuration):
return runner(workspace_root, configuration, workspace_model)
workspace_model = load_workspace(workspace_root)
return runner(workspace_root, configuration, workspace_model)
return runner(workspace_root, configuration, workspace_model, active_runner)


_VERSION_PATTERN = re.compile(
Expand Down Expand Up @@ -290,7 +311,7 @@ def bump(
resolved = normalise_workspace_root(workspace_root)
return _run_with_context(
resolved,
lambda root, configuration, workspace: commands.bump.run(
lambda root, configuration, workspace, command_runner: commands.bump.run(
root,
version,
options=commands.bump.BumpOptions(
Expand Down Expand Up @@ -319,14 +340,15 @@ def publish(
resolved = normalise_workspace_root(workspace_root)
return _run_with_context(
resolved,
lambda root, configuration, workspace: commands.publish.run(
lambda root, configuration, workspace, command_runner: commands.publish.run(
root,
configuration,
workspace,
options=commands.publish.PublishOptions(
allow_dirty=not forbid_dirty,
live=live,
allow_unpublished_workspace_deps=allow_unpublished_workspace_deps,
command_runner=command_runner,
),
),
)
Expand Down
48 changes: 19 additions & 29 deletions lading/commands/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,9 @@
from pathlib import Path

from lading import config as config_module
from lading.commands import publish_preflight as _publish_preflight
from lading.commands.publish_errors import PublishError, PublishPreflightError
from lading.commands.publish_execution import (
_CommandRunner,
_invoke,
normalise_cmd_mox_command,
should_use_cmd_mox_stub,
split_command,
)
from lading.commands.publish_index_check import (
_CargoInvocation,
Expand All @@ -81,38 +76,33 @@
)
from lading.commands.publish_plan import (
PublishPlan,
append_section,
format_plan,
plan_publication,
)
from lading.commands.publish_plan import (
PublishPlanError as _PublishPlanError,
)
from lading.commands.publish_preflight import (
_apply_compiletest_externs,
_build_preflight_environment,
_CargoPreflightOptions,
_compose_preflight_arguments,
_run_aux_build_commands,
_run_cargo_preflight,
_verify_clean_working_tree,
)
from lading.utils.path import normalise_workspace_root
from lading.workspace import metadata as _metadata_module

StripPatchesSetting = config_module.StripPatchesSetting
metadata_module = _metadata_module
PublishPlanError = _PublishPlanError
_normalise_cmd_mox_command = normalise_cmd_mox_command
_should_use_cmd_mox_stub = should_use_cmd_mox_stub
_split_command = split_command
_append_section = append_section
_format_plan = format_plan
_CargoPreflightOptions = _publish_preflight._CargoPreflightOptions
_apply_compiletest_externs = _publish_preflight._apply_compiletest_externs
_build_preflight_environment = _publish_preflight._build_preflight_environment
_build_test_arguments = _publish_preflight._build_test_arguments
_compose_preflight_arguments = _publish_preflight._compose_preflight_arguments
_normalise_test_excludes = _publish_preflight._normalise_test_excludes
_run_aux_build_commands = _publish_preflight._run_aux_build_commands
_run_cargo_preflight = _publish_preflight._run_cargo_preflight
_verify_clean_working_tree = _publish_preflight._verify_clean_working_tree

LOGGER = logging.getLogger(__name__)

if typ.TYPE_CHECKING:
from lading.config import LadingConfig
from lading.runtime import CommandRunner
from lading.workspace import WorkspaceCrate, WorkspaceGraph


Expand Down Expand Up @@ -179,7 +169,7 @@ class PublishOptions:
cleanup: bool = False
configuration: LadingConfig | None = None
workspace: WorkspaceGraph | None = None
command_runner: _CommandRunner | None = None
command_runner: CommandRunner | None = None
allow_unpublished_workspace_deps: bool = False


Expand Down Expand Up @@ -384,7 +374,7 @@ def _package_publishable_crates(
preparation: PublishPreparation,
*,
options: _PublishExecutionOptions,
runner: _CommandRunner,
runner: CommandRunner,
) -> None:
"""Package each publishable crate in order using the staged workspace."""
state = _PublicationPipelineState(plan, preparation, options)
Expand All @@ -400,7 +390,7 @@ def _package_crate(
crate: WorkspaceCrate,
state: _PublicationPipelineState,
*,
runner: _CommandRunner,
runner: CommandRunner,
) -> None:
"""Package one publishable crate using the staged workspace."""
plan = state.plan
Expand Down Expand Up @@ -463,7 +453,7 @@ def _publish_crates(
plan: PublishPlan,
preparation: PublishPreparation,
*,
runner: _CommandRunner,
runner: CommandRunner,
options: _PublishExecutionOptions,
) -> None:
"""Publish each crate in order, respecting dry-run vs live mode."""
Expand All @@ -480,7 +470,7 @@ def _publish_crate(
crate: WorkspaceCrate,
state: _PublicationPipelineState,
*,
runner: _CommandRunner,
runner: CommandRunner,
) -> None:
"""Publish one crate from the staged workspace."""
plan = state.plan
Expand Down Expand Up @@ -556,7 +546,7 @@ def _execute_live_publication_pipeline(
preparation: PublishPreparation,
*,
options: _PublishExecutionOptions,
runner: _CommandRunner,
runner: CommandRunner,
) -> None:
"""Package and publish each crate before moving to the next crate."""
state = _PublicationPipelineState(plan, preparation, options)
Expand Down Expand Up @@ -647,7 +637,7 @@ def _dispatch_publication(
preparation: PublishPreparation,
*,
options: _PublishExecutionOptions,
runner: _CommandRunner,
runner: CommandRunner,
) -> None:
"""Route to the live or dry-run publication pipeline."""
if options.live:
Expand Down Expand Up @@ -721,7 +711,7 @@ def run(
options=execution_options,
runner=command_runner,
)
plan_message = _format_plan(
plan_message = format_plan(
plan, strip_patches=active_configuration.publish.strip_patches
)
summary_lines = _format_preparation_summary(preparation)
Expand All @@ -734,7 +724,7 @@ def _run_preflight_checks(
*,
allow_dirty: bool,
configuration: LadingConfig | None = None,
runner: _CommandRunner | None = None,
runner: CommandRunner | None = None,
) -> None:
"""Execute publish pre-flight checks for ``workspace_root``."""
command_runner = runner or _invoke
Expand Down
Loading
Loading