From 99b1b0669d16d857e203201f536f8784da7cb325 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 3 Dec 2024 11:17:50 +0100 Subject: [PATCH 1/3] Development: use `--build-arg` to invalidate cache Create a hash of all the dependencies files and use it as a `--build-arg` to invalidate the cache when the hash changes. Related https://github.com/readthedocs/common/pull/241 --- dockerfiles/tasks.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/dockerfiles/tasks.py b/dockerfiles/tasks.py index e4b7048..ad480f5 100644 --- a/dockerfiles/tasks.py +++ b/dockerfiles/tasks.py @@ -1,5 +1,6 @@ import os import sys +import hashlib from invoke import task @@ -14,8 +15,32 @@ }) def build(c, cache=False): """Build docker image for servers.""" - cache_opt = '' if cache else '--no-cache' - c.run(f'{DOCKER_COMPOSE_COMMAND} build {cache_opt}', pty=True) + cache_opt = '--no-cache' + cache_hash = "" + build_arg = "" + if cache: + cache_opt = "" + files_to_cache = [ + # Community + "requirements/docker.txt", + + # Corporate + "../readthedocs.org/requirements/docker.txt", + "setup.cfg", + + # Both + "../ext-theme/setup.cfg", + "../readthedocs-ext/setup.cfg", + ] + + for f in files_to_cache: + if os.path.exists(f): + cache_hash += hashlib.md5(open(f, mode="rb").read()).hexdigest() + + if cache_hash: + build_arg = f"--build-arg PRUNE_PACKAGE_CACHE={cache_hash}" + + c.run(f'{DOCKER_COMPOSE_COMMAND} build {cache_opt} {build_arg}', echo=True, pty=True) @task(help={ 'command': 'Command to pass directly to "docker compose"', From ff89487e0dc8d2223d2ef9b91e1092bee596220e Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 4 Dec 2024 15:34:56 +0100 Subject: [PATCH 2/3] Update the cache hash instead of appending each of them --- dockerfiles/tasks.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dockerfiles/tasks.py b/dockerfiles/tasks.py index ad480f5..5dcaf0e 100644 --- a/dockerfiles/tasks.py +++ b/dockerfiles/tasks.py @@ -16,7 +16,6 @@ def build(c, cache=False): """Build docker image for servers.""" cache_opt = '--no-cache' - cache_hash = "" build_arg = "" if cache: cache_opt = "" @@ -33,12 +32,12 @@ def build(c, cache=False): "../readthedocs-ext/setup.cfg", ] + cache_hash = hashlib.md5() for f in files_to_cache: if os.path.exists(f): - cache_hash += hashlib.md5(open(f, mode="rb").read()).hexdigest() - - if cache_hash: - build_arg = f"--build-arg PRUNE_PACKAGE_CACHE={cache_hash}" + cache_hash.update(open(f, mode="rb").read()) + cache_hash = cache_hash.hexdigest() + build_arg = f"--build-arg PRUNE_PYTHON_PACKAGE_CACHE={cache_hash}" c.run(f'{DOCKER_COMPOSE_COMMAND} build {cache_opt} {build_arg}', echo=True, pty=True) From b8fc02084a4902d097ed0ad136c742232f002d89 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 4 Dec 2024 15:35:15 +0100 Subject: [PATCH 3/3] Accept `PRUNE_PYTHON_PACKAGE_CACHE` as an environment variable --- dockerfiles/docker-compose.yml | 2 ++ dockerfiles/tasks.py | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dockerfiles/docker-compose.yml b/dockerfiles/docker-compose.yml index 8695b12..3f2d6c2 100644 --- a/dockerfiles/docker-compose.yml +++ b/dockerfiles/docker-compose.yml @@ -11,6 +11,8 @@ services: build: context: ${PWD} dockerfile: ${PWD}/dockerfiles/Dockerfile + args: + PRUNE_PYTHON_PACKAGE_CACHE: ${PRUNE_PYTHON_PACKAGE_CACHE:-0} nginx: stop_grace_period: 1s diff --git a/dockerfiles/tasks.py b/dockerfiles/tasks.py index 5dcaf0e..e61f54c 100644 --- a/dockerfiles/tasks.py +++ b/dockerfiles/tasks.py @@ -15,10 +15,9 @@ }) def build(c, cache=False): """Build docker image for servers.""" - cache_opt = '--no-cache' - build_arg = "" - if cache: - cache_opt = "" + cache_opt = '--no-cache' if not cache else "" + cache_env_var = "" + if cache and not os.environ.get("PRUNE_PYTHON_PACKAGE_CACHE"): files_to_cache = [ # Community "requirements/docker.txt", @@ -37,9 +36,9 @@ def build(c, cache=False): if os.path.exists(f): cache_hash.update(open(f, mode="rb").read()) cache_hash = cache_hash.hexdigest() - build_arg = f"--build-arg PRUNE_PYTHON_PACKAGE_CACHE={cache_hash}" + cache_env_var = f"PRUNE_PYTHON_PACKAGE_CACHE={cache_hash}" - c.run(f'{DOCKER_COMPOSE_COMMAND} build {cache_opt} {build_arg}', echo=True, pty=True) + c.run(f'{cache_env_var} {DOCKER_COMPOSE_COMMAND} build {cache_opt}', echo=True, pty=True) @task(help={ 'command': 'Command to pass directly to "docker compose"',