NAME

Developer::Dashboard::DockerCompose - compose resolver and launcher

SYNOPSIS

my $docker = Developer::Dashboard::DockerCompose->new(
    config  => $config,
    paths   => $paths,
    plugins => $plugins,
);

DESCRIPTION

This module resolves layered docker compose inputs into a final transparent docker compose command line and can optionally execute it.

When a standard Compose file exists in the invocation directory, it is used as the local base and the command runs from that directory. Unscoped automatic runtime overlays are restricted to service names in that base file's services: map. Explicit service selectors remain opt-in, while the absence of a local Compose file preserves ecosystem-wide service discovery. YAML syntax and service-map errors are reported with their source path.

METHODS

new, resolve, list_services, run

Construct, resolve, list, and optionally execute compose operations. resolve returns both the project discovery root and the effective Compose working root so nested invocation directories retain their local project file.

enable_service_development, disable_service_development

Create or remove the selected-home-runtime develop.yml marker for one isolated service. A marker in any matching service folder across active runtime layers enables development.compose.yml overlays for the service. Removing the marker removes every develop.yml file for that service across those layers. New markers use ~/.developer-dashboard when it exists (or when neither runtime name exists), and ~/.d2 only when that is the existing home runtime name. An existing compose.yml remains the base and is loaded first. If development is enabled but its file is absent, resolution continues with the base file and does not report an error.

$docker->enable_service_development( service => 'web' );
$docker->disable_service_development( service => 'web' );

disable_service, enable_service

Write and remove the disabled.yml marker for one isolated service, below the selected home runtime config/docker root. Any matching service layer containing disabled.yml disables the service; enabling removes every such marker before reporting success. New markers use the same home runtime name selection as development markers.

The service name reaches these methods straight from the command line and is therefore untrusted. It is resolved below the toggle root and any name that escapes that root is refused - both methods die rather than fall back to the unchecked path. Resolution is lexical and never consults the filesystem, so the containment decision cannot change between the check and the write or unlink that follows it. Marker removal walks only existing service folders discovered by the layered service resolver, and marker names are restricted to the two internal toggle files.

The refusal protects two distinct sinks, and the second is the one usually underestimated: disable_service creates directories and writes a file, while enable_service removes one, so an uncontained name gave arbitrary deletion of any file with that fixed leaf name, not merely arbitrary creation.

One case is deliberately outside this containment: a parent directory that is itself a symlink pointing outside the root is lexically innocent and is not rejected here. Resolving it would require consulting the filesystem and would reopen the time-of-check-to-time-of-use window this approach closes.

PURPOSE

This module resolves and runs dashboard-managed Docker Compose stacks. It maps wrapper flags to compose files under layered runtime config/docker roots, infers service names, exports the effective docker config root, and builds the final docker compose command that the wrapper execs.

WHY IT EXISTS

It exists because dashboard-specific Compose resolution has more rules than a plain passthrough wrapper: isolated service folders, disabled markers, addon/mode selection, and layered runtime lookup all need one tested owner.

WHEN TO USE

Use this file when changing compose file discovery, wrapper-only flags, service inference, environment exports such as DDDC, or the dry-run versus exec behavior of the docker helper.

HOW TO USE

Feed the parsed wrapper arguments into this module and let it return or execute the effective docker compose command. Avoid rebuilding compose discovery logic in the CLI wrapper or in project-local scripts.

WHAT USES IT

It is used by the dashboard docker compose helper, by docker-focused tests, and by developers who keep Compose stacks under .developer-dashboard/config/docker/ instead of shell aliases.

EXAMPLES

Example 1:

perl -Ilib -MDeveloper::Dashboard::DockerCompose -e 1

Do a direct compile-and-load check against the module from a source checkout.

Example 2:

prove -lv t/10-extension-action-docker.t

Run the focused regression tests that most directly exercise this module's behavior.

Example 3:

dashboard docker list --disabled

Inspect the effective disabled-service view through the same resolver rules as compose discovery.

Example 4:

HARNESS_PERL_SWITCHES=-MDevel::Cover prove -lr t

Recheck the module under the repository coverage gate rather than relying on a load-only probe.

Example 4:

prove -lr t

Put any module-level change back through the entire repository suite before release.