blob: 83685b32784839a6f016e71e1703112067424cf8 [file] [edit]
# 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
)