forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Internal] Refactoring how we integrate with dockerfile (pantsbuild#1…
…3027) Rather than having it as a direct dependency, package it into a PEX tool that we run out of process on demand. Closes pantsbuild#13026.
- Loading branch information
Showing
16 changed files
with
367 additions
and
165 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
ansicolors==1.1.8 | ||
dockerfile==3.2.0 | ||
fasteners==0.16 | ||
freezegun==1.1.0 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# This lockfile was autogenerated by Pants. To regenerate, run: | ||
# | ||
# build-support/bin/generate_all_lockfiles.sh | ||
# | ||
# --- BEGIN PANTS LOCKFILE METADATA: DO NOT EDIT OR REMOVE --- | ||
# { | ||
# "version": 2, | ||
# "valid_for_interpreter_constraints": [ | ||
# "CPython>=3.7" | ||
# ], | ||
# "generated_with_requirements": [ | ||
# "dockerfile==3.2.0" | ||
# ] | ||
# } | ||
# --- END PANTS LOCKFILE METADATA --- | ||
|
||
dockerfile==3.2.0; python_full_version >= "3.6.1" \ | ||
--hash=sha256:e6e00b82b82042fb4df569ae00bd2648ac6c8823f51c406da31ab01c728926c2 \ | ||
--hash=sha256:e6bd64408386b7ba2259d85820e0fe90de1b6b8269f560f18aba100c6aa40b7d \ | ||
--hash=sha256:e13fd3768216a788189e0667521e1435a273a4129119a8453085d897fc34aac8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from __future__ import annotations | ||
|
||
import pkgutil | ||
from dataclasses import dataclass | ||
from pathlib import PurePath | ||
|
||
from pants.backend.docker.target_types import DockerImageSources | ||
from pants.backend.python.goals.lockfile import PythonLockfileRequest, PythonToolLockfileSentinel | ||
from pants.backend.python.subsystems.python_tool_base import PythonToolRequirementsBase | ||
from pants.backend.python.target_types import EntryPoint | ||
from pants.backend.python.util_rules.pex import PexRequest, VenvPex, VenvPexProcess | ||
from pants.engine.fs import CreateDigest, Digest, FileContent | ||
from pants.engine.process import Process, ProcessResult | ||
from pants.engine.rules import Get, collect_rules, rule | ||
from pants.engine.target import HydratedSources, HydrateSourcesRequest | ||
from pants.engine.unions import UnionRule | ||
from pants.util.docutil import git_url | ||
|
||
_DOCKERFILE_SANDBOX_TOOL = "dockerfile_wrapper_script.py" | ||
|
||
|
||
class DockerfileParser(PythonToolRequirementsBase): | ||
options_scope = "dockerfile-parser" | ||
help = "Used to parse Dockerfile build specs to infer their dependencies." | ||
|
||
default_version = "dockerfile==3.2.0" | ||
|
||
register_interpreter_constraints = True | ||
default_interpreter_constraints = ["CPython>=3.7"] | ||
|
||
register_lockfile = True | ||
default_lockfile_resource = ("pants.backend.docker", "dockerfile_lockfile.txt") | ||
default_lockfile_path = "src/python/pants/backend/docker/dockerfile_lockfile.txt" | ||
default_lockfile_url = git_url(default_lockfile_path) | ||
|
||
|
||
class DockerfileParserLockfileSentinel(PythonToolLockfileSentinel): | ||
options_scope = DockerfileParser.options_scope | ||
|
||
|
||
@rule | ||
def setup_lockfile_request( | ||
_: DockerfileParserLockfileSentinel, dockerfile_parser: DockerfileParser | ||
) -> PythonLockfileRequest: | ||
return PythonLockfileRequest.from_tool(dockerfile_parser) | ||
|
||
|
||
@dataclass(frozen=True) | ||
class ParserSetup: | ||
pex: VenvPex | ||
|
||
|
||
@rule | ||
async def setup_parser(dockerfile_parser: DockerfileParser) -> ParserSetup: | ||
parser_script_content = pkgutil.get_data("pants.backend.docker", _DOCKERFILE_SANDBOX_TOOL) | ||
if not parser_script_content: | ||
raise ValueError( | ||
"Unable to find source to {_DOCKERFILE_SANDBOX_TOOL!r} in pants.backend.docker." | ||
) | ||
|
||
parser_content = FileContent( | ||
path="__pants_df_parser.py", | ||
content=parser_script_content, | ||
is_executable=True, | ||
) | ||
|
||
parser_digest = await Get(Digest, CreateDigest([parser_content])) | ||
|
||
parser_pex = await Get( | ||
VenvPex, | ||
PexRequest( | ||
output_filename="dockerfile_parser.pex", | ||
internal_only=True, | ||
requirements=dockerfile_parser.pex_requirements(), | ||
interpreter_constraints=dockerfile_parser.interpreter_constraints, | ||
main=EntryPoint(PurePath(parser_content.path).stem), | ||
sources=parser_digest, | ||
), | ||
) | ||
|
||
return ParserSetup(parser_pex) | ||
|
||
|
||
@dataclass(frozen=True) | ||
class DockerfileParseRequest: | ||
sources_digest: Digest | ||
paths: tuple[str, ...] | ||
|
||
|
||
@rule | ||
async def setup_process_for_parse_dockerfile( | ||
request: DockerfileParseRequest, parser: ParserSetup | ||
) -> Process: | ||
process = await Get( | ||
Process, | ||
VenvPexProcess( | ||
parser.pex, | ||
argv=request.paths, | ||
input_digest=request.sources_digest, | ||
description="Parse Dockerfile.", | ||
), | ||
) | ||
return process | ||
|
||
|
||
@dataclass(frozen=True) | ||
class DockerfileInfo: | ||
putative_target_addresses: tuple[str, ...] = () | ||
|
||
|
||
@rule | ||
async def parse_dockerfile(sources: DockerImageSources) -> DockerfileInfo: | ||
hydrated_sources = await Get(HydratedSources, HydrateSourcesRequest(sources)) | ||
result = await Get( | ||
ProcessResult, | ||
DockerfileParseRequest(hydrated_sources.snapshot.digest, hydrated_sources.snapshot.files), | ||
) | ||
|
||
putative_target_addresses = [line for line in result.stdout.decode("utf-8").split("\n") if line] | ||
|
||
return DockerfileInfo( | ||
putative_target_addresses=tuple(putative_target_addresses), | ||
) | ||
|
||
|
||
def rules(): | ||
return ( | ||
*collect_rules(), | ||
UnionRule(PythonToolLockfileSentinel, DockerfileParserLockfileSentinel), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
|
||
from textwrap import dedent | ||
|
||
import pytest | ||
|
||
from pants.backend.docker.dockerfile_parser import DockerfileInfo | ||
from pants.backend.docker.dockerfile_parser import rules as parser_rules | ||
from pants.backend.docker.target_types import DockerImage, DockerImageSources | ||
from pants.backend.python.target_types import PexBinary | ||
from pants.backend.python.util_rules.pex import rules as pex_rules | ||
from pants.engine.addresses import Address | ||
from pants.testutil.rule_runner import QueryRule, RuleRunner | ||
|
||
|
||
@pytest.fixture | ||
def rule_runner() -> RuleRunner: | ||
rule_runner = RuleRunner( | ||
rules=[ | ||
*parser_rules(), | ||
*pex_rules(), | ||
QueryRule(DockerfileInfo, (DockerImageSources,)), | ||
], | ||
target_types=[DockerImage, PexBinary], | ||
) | ||
rule_runner.set_options( | ||
[], | ||
env_inherit={"PATH", "PYENV_ROOT", "HOME"}, | ||
) | ||
return rule_runner | ||
|
||
|
||
def test_putative_target_addresses(rule_runner: RuleRunner) -> None: | ||
rule_runner.write_files( | ||
{ | ||
"test/BUILD": "docker_image()", | ||
"test/Dockerfile": dedent( | ||
"""\ | ||
FROM base | ||
COPY some.target/binary.pex some.target/tool.pex /bin | ||
COPY --from=scratch this.is/ignored.pex /opt | ||
COPY binary another/cli.pex tool /bin | ||
""" | ||
), | ||
} | ||
) | ||
tgt = rule_runner.get_target(Address("test")) | ||
info = rule_runner.request(DockerfileInfo, [tgt[DockerImageSources]]) | ||
assert info.putative_target_addresses == ( | ||
"some/target:binary", | ||
"some/target:tool", | ||
"another:cli", | ||
) |
Oops, something went wrong.