I am trying to build a wrapper around some docker-...
# plugins
a
I am trying to build a wrapper around some docker-compose functionality to make it easier for other to move into the new repo (previous repos used make files for running the commands). I have a file like this:
Copy code
"""Quick commands for running docker-compose environment."""
from typing import Iterable

from pants.base.build_root import BuildRoot
from pants.core.util_rules.system_binaries import BinaryPathRequest, BinaryPaths
from pants.engine.console import Console
from pants.engine.fs import Digest, PathGlobs, Paths
from pants.engine.goal import Goal, GoalSubsystem
from pants.engine.process import Process, ProcessResult
from pants.engine.rules import Get, Rule, collect_rules, goal_rule
from pants.option.option_types import BoolOption, StrOption


class DockerComposeSubsystem(GoalSubsystem):
    """Run docker compose commands."""

    name = "docker-compose"
    help = "Run docker-compose commands"

    command = StrOption(default="", help="Command to run")
    up = BoolOption(default=False, help="Spin up docker environment in background")
    up_fg = BoolOption(default=False, help="Spin up docker environment in foreground")
    down = BoolOption(default=False, help="Spin down docker environment")
    ps = BoolOption(default=False, help="List running processes")


class DockerComposeGoal(Goal):
    """Result of running commands."""

    subsystem_cls = DockerComposeSubsystem


@goal_rule
async def docker_compose(
    console: Console, buildroot: BuildRoot, subsystem: DockerComposeSubsystem
) -> DockerComposeGoal:
    docker_compose_paths = await Get(
        BinaryPaths,
        BinaryPathRequest(
            binary_name="docker-compose", search_path=["/usr/bin", "/bin", "/usr/local/bin"]
        ),
    )
    docker_compose_bin = docker_compose_paths.first_path
    if docker_compose_bin is None:
        raise OSError("Could not find 'docker-compose'.")
    paths = await Get(Paths, PathGlobs(["docker-compose/*.yml"]))
    command_additions = [
        paths.files[idx // 2] if idx % 2 == 1 else "-f" for idx in range(len(paths.files) * 2)
    ]
    digest = await Get(Digest, PathGlobs(["docker-compose/*.yml"]))
    if subsystem.up:
        await Get(
            ProcessResult,
            Process(
                argv=[docker_compose_bin] + command_additions + ["up", "-d"],
                description="Spin up docker-compose in background",
                input_digest=digest,
            ),
        )
    elif subsystem.down:
        await Get(
            ProcessResult,
            Process(
                argv=[docker_compose_bin] + command_additions + ["down"],
                description="Spin down docker-compose",
                input_digest=digest,
            ),
        )
    elif <http://subsystem.ps|subsystem.ps>:
        await Get(
            ProcessResult,
            Process(
                argv=[docker_compose_bin] + command_additions + ["ps"],
                description="List docker-compose running environment",
                input_digest=digest,
            ),
        )
    return DockerComposeGoal(exit_code=0)


def rules() -> Iterable[Rule]:
    return collect_rules()
However, when I try to run this, I get errors that the filesystem changed during the run. I am trying to understand how to prevent that
w
is there anything in
.pants.d/pants.log
? i expect that you have a type error in the
Process
constructor. that’s no longer fatal on
main
, but has been in past releases.
you can also try temporarily disabling your plugin, and checking it with
mypy
.
a
Briliant, caught that the docker_compose_bin needs to be docker_compose_bin.path. Onto the second thing. Looks like it docker-compose needs to have the docker command also available in the path. Is that down by merging a digest with that?
w
by default
Process
is very isolated and sandboxed
depending on your … goals … for this goal, you might not want to sandbox these processes
in which case you’d want to use
InteractiveProcess
, which runs in the foreground instead.
a
Okay, Will try that. Thanks
InteractiveProcess still fails with not being able to find docker. Is there a good way to add docker into the env or into input_digest so it can be discovered?
w
InteractiveProcess
uses the entire env by default, so it shouldn’t be necessary to expand it explicitly
…oh. hm. i might have lied there.