| # Copyright 2018 Google LLC |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import functools |
| import json |
| import os |
| import platform |
| import tempfile |
| |
| from synthtool import metadata, shell |
| from synthtool.log import logger |
| |
| ARTMAN_VERSION = os.environ.get("SYNTHTOOL_ARTMAN_VERSION", "latest") |
| |
| |
| class Artman: |
| def __init__(self): |
| # Docker on mac by default cannot use the default temp file location |
| # # instead use the more standard *nix /tmp location\ |
| if platform.system() == "Darwin": |
| tempfile.tempdir = "/tmp" |
| self._ensure_dependencies_installed() |
| self._install_artman() |
| self._report_metadata() |
| |
| @functools.lru_cache() |
| def _docker_image_info(self): |
| result = shell.run( |
| ["docker", "inspect", f"googleapis/artman:{ARTMAN_VERSION}"], |
| hide_output=True, |
| ) |
| return json.loads(result.stdout)[0] |
| |
| @property |
| def version(self) -> str: |
| # The artman version is hidden in the container's environment variables. |
| # We could just docker run `artman --version`, but we already have the |
| # container info so why not? This is faster as it saves us an exec(). |
| env_vars = dict( |
| value.split("=", 1) for value in self._docker_image_info()["Config"]["Env"] |
| ) |
| |
| return env_vars.get("ARTMAN_VERSION", "unknown") |
| |
| @property |
| def docker_image(self) -> str: |
| return self._docker_image_info()["RepoDigests"][0] |
| |
| def run( |
| self, image, root_dir, config, *args, generator_dir=None, generator_args=None |
| ): |
| """Executes artman command in the artman container. |
| |
| Args: |
| image: |
| The Docker image for artman. |
| root_dir: |
| The input directory that will be mounted to artman docker |
| container as local googleapis directory. |
| config: |
| Path to artman configuration YAML file. |
| *args: |
| Arguments to artman that follow ``generate``. Defines which |
| artifacts to generate. |
| generator_dir (Optional[str]): |
| Path to local gapic-generator directory to use for generation. |
| By default, the latest version of gapic-generator will be used. |
| generator_args (Optional[List[str]]): |
| Additional arguments to pass to the gapic generator, such as |
| ``--dev_samples``. |
| Returns: |
| The output directory with artman-generated files. |
| """ |
| container_name = "artman-docker" |
| output_dir = root_dir / "artman-genfiles" |
| |
| additional_flags = [] |
| |
| if generator_args: |
| additional_flags.append( |
| "--generator-args='{}'".format(" ".join(generator_args)) |
| ) |
| |
| docker_cmd = ["docker", "run", "--name", container_name, "--rm", "-i"] |
| |
| # Environment variables |
| docker_cmd.extend( |
| [ |
| "-e", |
| f"HOST_USER_ID={os.getuid()}", |
| "-e", |
| f"HOST_GROUP_ID={os.getgid()}", |
| "-e", |
| "RUNNING_IN_ARTMAN_DOCKER=True", |
| ] |
| ) |
| |
| # Local directories to mount as volumes (and set working directory -w) |
| docker_cmd.extend( |
| [ |
| "-v", |
| f"{root_dir}:{root_dir}", |
| "-v", |
| f"{output_dir}:{output_dir}", |
| "-w", |
| root_dir, |
| ] |
| ) |
| |
| # Use local copy of GAPIC generator to generate, if path provided |
| if generator_dir: |
| docker_cmd.extend(["-v", f"{generator_dir}:/toolkit"]) |
| |
| # Run /bin/bash in the image and then provide the shell command to run |
| docker_cmd.extend([image, "/bin/bash", "-c"]) |
| |
| artman_command = " ".join( |
| map( |
| str, |
| ["artman", "--local", "--config", config] |
| + additional_flags |
| + ["generate"] |
| + list(args), |
| ) |
| ) |
| |
| cmd = docker_cmd + [artman_command] |
| |
| shell.run(cmd, cwd=root_dir) |
| |
| return output_dir |
| |
| def _ensure_dependencies_installed(self): |
| logger.debug("Ensuring dependencies.") |
| |
| dependencies = ["docker", "git"] |
| failed_dependencies = [] |
| for dependency in dependencies: |
| return_code = shell.run(["which", dependency], check=False).returncode |
| if return_code: |
| failed_dependencies.append(dependency) |
| |
| if failed_dependencies: |
| raise EnvironmentError( |
| f"Dependencies missing: {', '.join(failed_dependencies)}" |
| ) |
| |
| def _install_artman(self): |
| logger.debug("Pulling artman image.") |
| shell.run( |
| ["docker", "pull", f"googleapis/artman:{ARTMAN_VERSION}"], hide_output=False |
| ) |
| |
| def _report_metadata(self): |
| metadata.add_generator_source( |
| name="artman", version=self.version, docker_image=self.docker_image |
| ) |