""" Generate a Dockerfile from in.Dockerfile and a version JSON file, and write version info. If the argument --error-modified is passed, the script will not write any output and will exit with status code 1 if the output files were modified. """ import difflib import sys from pathlib import Path from textwrap import dedent try: from scripts.python_version import ALL_VERSIONS, MAIN_VERSION except ModuleNotFoundError: sys.path.insert(0, Path(__file__).parent.parent.absolute().as_posix()) from scripts.python_version import ALL_VERSIONS, MAIN_VERSION DOCKERFILE_TEMPLATE = Path("scripts/in.Dockerfile").read_text("utf-8") DOCKERFILE = Path("Dockerfile") ERROR_MODIFIED = "--error-modified" in sys.argv # Download and copy multiple python images into one layer python_build = "" previous_layer = "first" for version in ALL_VERSIONS: if version.is_main: # Main is handled separately later continue # Add the current version to the Dockerfile layer_name = version.version_name.replace(".", "-") # Dots aren't valid in layer names python_build += dedent( f""" FROM python:{version.image_tag} as base-{layer_name} COPY --from=base-{previous_layer} / / """ ) previous_layer = layer_name # Main version is installed twice, once at the very beginning to make sure # its files aren't overwritten, and once at the end which actually makes use of the version python_build = f"FROM python:{MAIN_VERSION.image_tag} as base-first\n" + python_build # Write new dockerfile # fmt: off # Black makes the following block much less readable dockerfile_out = ( "# THIS FILE IS AUTOGENERATED, DO NOT MODIFY! #\n" + DOCKERFILE_TEMPLATE .replace("{python_install_commands}", python_build) .replace("{final_base}", previous_layer).replace("{main_version_tag}", MAIN_VERSION.image_tag) ) # fmt: on if ERROR_MODIFIED: if (original := DOCKERFILE.read_text("utf-8")) != dockerfile_out: print("Dockerfile modified:") print("\n".join(difflib.unified_diff(dockerfile_out.splitlines(), original.splitlines()))) raise SystemExit(1) else: exit(0) else: DOCKERFILE.write_text(dockerfile_out, "utf-8") print("Finished!")