diff --git a/dev/archery/archery/docker/cli.py b/dev/archery/archery/docker/cli.py index bbdd2261db6..c7b42c094f6 100644 --- a/dev/archery/archery/docker/cli.py +++ b/dev/archery/archery/docker/cli.py @@ -16,6 +16,7 @@ # under the License. import os +import sys import click @@ -289,3 +290,27 @@ def docker_compose_images(obj): click.echo('Available images:') for image in compose.images(): click.echo(f' - {image}') + + +@docker.command('info') +@click.argument('service_name') +@click.option('--show', '-s', required=False, + help="Show only specific docker-compose key. Examples of keys:" + " command, environment, build, dockerfile") +@click.pass_obj +def docker_compose_info(obj, service_name, show): + """Show docker-compose definition info for service_name. + + SERVICE_NAME is the name of the docker service defined on + the docker-compose. Look at `archery docker images` output for names. + """ + compose = obj['compose'] + try: + service = compose.config.raw_config["services"][service_name] + except KeyError: + click.echo(f'Service name {service_name} could not be found', err=True) + sys.exit(1) + else: + click.echo(f'Service {service_name} docker-compose config:') + output = "\n".join(compose.info(service, show)) + click.echo(output) diff --git a/dev/archery/archery/docker/core.py b/dev/archery/archery/docker/core.py index da15f86935b..de5e6cf41c9 100644 --- a/dev/archery/archery/docker/core.py +++ b/dev/archery/archery/docker/core.py @@ -95,12 +95,12 @@ def _read_config(self, config_path, compose_bin): """ yaml = YAML() with config_path.open() as fp: - config = yaml.load(fp) + self.raw_config = yaml.load(fp) - services = config['services'].keys() - self.hierarchy = dict(flatten(config.get('x-hierarchy', {}))) - self.limit_presets = config.get('x-limit-presets', {}) - self.with_gpus = config.get('x-with-gpus', []) + services = self.raw_config['services'].keys() + self.hierarchy = dict(flatten(self.raw_config.get('x-hierarchy', {}))) + self.limit_presets = self.raw_config.get('x-limit-presets', {}) + self.with_gpus = self.raw_config.get('x-with-gpus', []) nodes = self.hierarchy.keys() errors = [] @@ -417,3 +417,22 @@ def _push(service): def images(self): return sorted(self.config.hierarchy.keys()) + + def info(self, key_name, filters=None, prefix=' '): + output = [] + for key, value in key_name.items(): + if hasattr(value, 'items'): + temp_filters = filters + if key == filters or filters is None: + output.append(f'{prefix} {key}') + # Keep showing this specific key + # as parent matched filter + temp_filters = None + output.extend(self.info(value, temp_filters, prefix + " ")) + else: + if key == filters or filters is None: + output.append( + f'{prefix} {key}: ' + + f'{value if value is not None else ""}' + ) + return output diff --git a/dev/archery/archery/docker/tests/test_docker.py b/dev/archery/archery/docker/tests/test_docker.py index 899a0449e1a..bc25738becf 100644 --- a/dev/archery/archery/docker/tests/test_docker.py +++ b/dev/archery/archery/docker/tests/test_docker.py @@ -114,6 +114,11 @@ arrow_compose_yml = """ version: '3.5' +x-sccache: &sccache + AWS_ACCESS_KEY_ID: + AWS_SECRET_ACCESS_KEY: + SCCACHE_BUCKET: + x-with-gpus: - ubuntu-cuda @@ -162,6 +167,8 @@ image: org/ubuntu-cpp-cmake32 ubuntu-c-glib: image: org/ubuntu-c-glib + environment: + <<: [*sccache] ubuntu-ruby: image: org/ubuntu-ruby ubuntu-cuda: @@ -529,3 +536,39 @@ def test_listing_images(arrow_compose_path): 'ubuntu-cuda', 'ubuntu-ruby', ] + + +def test_service_info(arrow_compose_path): + compose = DockerCompose(arrow_compose_path) + service = compose.config.raw_config["services"]["conda-cpp"] + assert compose.info(service) == [ + " image: org/conda-cpp", + " build", + " context: .", + " dockerfile: ci/docker/conda-cpp.dockerfile" + ] + + +def test_service_info_filters(arrow_compose_path): + compose = DockerCompose(arrow_compose_path) + service = compose.config.raw_config["services"]["conda-cpp"] + assert compose.info(service, filters="dockerfile") == [ + " dockerfile: ci/docker/conda-cpp.dockerfile" + ] + + +def test_service_info_non_existing_filters(arrow_compose_path): + compose = DockerCompose(arrow_compose_path) + service = compose.config.raw_config["services"]["conda-cpp"] + assert compose.info(service, filters="non-existing") == [] + + +def test_service_info_inherited_env(arrow_compose_path): + compose = DockerCompose(arrow_compose_path) + service = compose.config.raw_config["services"]["ubuntu-c-glib"] + assert compose.info(service, filters="environment") == [ + " environment", + " AWS_ACCESS_KEY_ID: ", + " AWS_SECRET_ACCESS_KEY: ", + " SCCACHE_BUCKET: " + ]