Skip to content

Commit 721878e

Browse files
committed
feat: implement parameters to allow use of an extra ignore file
In supplement to the support for the .dockerignore and .containerignore files, these two new parameters (extra-ignore-file and ingore-file-strategy) allow to modify how the ignore list is managed. This allows, for example in the case of BinderHub, the administrator to have a default set of files or folders that get ignored if the repository does not contain such any ignore file. The following strategies are available: - ours - theirs - merge The first forces the use of the file passed in parameters The second uses the file from the repository if it exists The last puts both together
1 parent 1bb3cba commit 721878e

30 files changed

+190
-16
lines changed

repo2docker/__main__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
import os
44
import sys
5+
from pathlib import Path
56

67
from . import __version__
78
from .app import Repo2Docker
@@ -282,6 +283,22 @@ def get_argparser():
282283
help=Repo2Docker.engine.help,
283284
)
284285

286+
argparser.add_argument(
287+
"--extra-ignore-file",
288+
dest="extra_ignore_file",
289+
type=Path,
290+
help=Repo2Docker.extra_ignore_file.help,
291+
)
292+
293+
argparser.add_argument(
294+
"--ignore-file-strategy",
295+
dest="ignore_file_strategy",
296+
type=str,
297+
choices=Repo2Docker.ignore_file_strategy.values,
298+
default=Repo2Docker.ignore_file_strategy.default_value,
299+
help=Repo2Docker.ignore_file_strategy.help,
300+
)
301+
285302
return argparser
286303

287304

@@ -464,6 +481,15 @@ def make_r2d(argv=None):
464481
if args.target_repo_dir:
465482
r2d.target_repo_dir = args.target_repo_dir
466483

484+
if args.extra_ignore_file is not None:
485+
if not args.extra_ignore_file.exists():
486+
print(f"The ignore file {args.extra_ignore_file} does not exist")
487+
sys.exit(1)
488+
r2d.extra_ignore_file = str(args.extra_ignore_file.resolve())
489+
490+
if args.ignore_file_strategy is not None:
491+
r2d.ignore_file_strategy = args.ignore_file_strategy
492+
467493
return r2d
468494

469495

repo2docker/app.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@
2121
import entrypoints
2222
import escapism
2323
from pythonjsonlogger import jsonlogger
24-
from traitlets import Any, Bool, Dict, Int, List, Unicode, default, observe
24+
from traitlets import Any, Bool, Dict, Enum, Int, List, Unicode, default, observe
2525
from traitlets.config import Application
2626

2727
from . import __version__, contentproviders
2828
from .buildpacks import (
2929
CondaBuildPack,
3030
DockerBuildPack,
31+
ExcludesStrategy,
3132
JuliaProjectTomlBuildPack,
3233
JuliaRequireBuildPack,
3334
LegacyBinderDockerBuildPack,
@@ -462,6 +463,32 @@ def _dry_run_changed(self, change):
462463
""",
463464
)
464465

466+
extra_ignore_file = Unicode(
467+
"",
468+
config=True,
469+
help="""
470+
Path to an additional .dockerignore or .containerignore file to be applied
471+
when building an image.
472+
473+
Depending on the strategy selected the content of the file will replace,
474+
be merged or be ignored.
475+
""",
476+
)
477+
478+
ignore_file_strategy = Enum(
479+
ExcludesStrategy.values(),
480+
config=True,
481+
default_value=ExcludesStrategy.theirs,
482+
help="""
483+
Strategy to use if an extra ignore file is passed:
484+
- merge means that the content of the extra ignore file will be merged
485+
with the ignore file contained in the repository (if any)
486+
- ours means that the extra ignore file content will be used in any case
487+
- theirs means that if there is an ignore file in the repository, the
488+
extra ignore file will not be used.
489+
""",
490+
)
491+
465492
def get_engine(self):
466493
"""Return an instance of the container engine.
467494
@@ -860,6 +887,8 @@ def build(self):
860887
self.cache_from,
861888
self.extra_build_kwargs,
862889
platform=self.platform,
890+
extra_ignore_file=self.extra_ignore_file,
891+
ignore_file_strategy=self.ignore_file_strategy,
863892
):
864893
if docker_client.string_output:
865894
self.log.info(l, extra=dict(phase=R2dState.BUILDING))

repo2docker/buildpacks/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .base import BaseImage, BuildPack
1+
from .base import BaseImage, BuildPack, ExcludesStrategy
22
from .conda import CondaBuildPack
33
from .docker import DockerBuildPack
44
from .julia import JuliaProjectTomlBuildPack, JuliaRequireBuildPack

repo2docker/buildpacks/base.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sys
88
import tarfile
99
import textwrap
10+
from enum import StrEnum, auto
1011
from functools import lru_cache
1112

1213
import escapism
@@ -205,6 +206,16 @@
205206
DEFAULT_NB_UID = 1000
206207

207208

209+
class ExcludesStrategy(StrEnum):
210+
theirs = auto()
211+
ours = auto()
212+
merge = auto()
213+
214+
@classmethod
215+
def values(cls):
216+
return [item.value for item in cls]
217+
218+
208219
class BuildPack:
209220
"""
210221
A composable BuildPack.
@@ -582,6 +593,8 @@ def build(
582593
cache_from,
583594
extra_build_kwargs,
584595
platform=None,
596+
extra_ignore_file=None,
597+
ignore_file_strategy=ExcludesStrategy.theirs,
585598
):
586599
tarf = io.BytesIO()
587600
tar = tarfile.open(fileobj=tarf, mode="w")
@@ -609,23 +622,34 @@ def _filter_tar(tarinfo):
609622
for fname in ("repo2docker-entrypoint", "python3-login"):
610623
tar.add(os.path.join(HERE, fname), fname, filter=_filter_tar)
611624

612-
exclude = []
625+
def _read_excludes(filepath):
626+
with open(filepath) as ignore_file:
627+
cleaned_lines = [
628+
line.strip() for line in ignore_file.read().splitlines()
629+
]
630+
return [line for line in cleaned_lines if line != "" and line[0] != "#"]
631+
632+
extra_excludes = []
633+
if extra_ignore_file:
634+
extra_excludes = _read_excludes(extra_ignore_file)
613635

636+
excludes = []
614637
for ignore_file_name in [".dockerignore", ".containerignore"]:
615638
if os.path.exists(ignore_file_name):
616-
with open(ignore_file_name) as ignore_file:
617-
cleaned_lines = [
618-
line.strip() for line in ignore_file.read().splitlines()
619-
]
620-
exclude.extend(
621-
[
622-
line
623-
for line in cleaned_lines
624-
if line != "" and line[0] != "#"
625-
]
626-
)
627-
628-
files_to_add = exclude_paths(".", exclude)
639+
excludes.extend(_read_excludes(ignore_file_name))
640+
641+
if extra_ignore_file is not None:
642+
if ignore_file_strategy == ExcludesStrategy.ours:
643+
excludes = extra_excludes
644+
elif ignore_file_strategy == ExcludesStrategy.merge:
645+
excludes.extend(extra_excludes)
646+
else:
647+
# ignore means that if an ignore file exist, its content is used
648+
# otherwise, the extra exclude
649+
if not excludes:
650+
excludes = extra_excludes
651+
652+
files_to_add = exclude_paths(".", excludes)
629653

630654
if files_to_add:
631655
for item in files_to_add:

tests/conda/ignore-file

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Docker compatible ignore file
2+
from-extra-ignore
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from-dockerignore
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dependencies:
2+
- python=3.11
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Must be ignored from .dockerignore file
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Must be ignored from extra ignore file
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# This file is respected by repo2docker's test suite, but not repo2docker
2+
# itself. It is used solely to help us test repo2docker's command line flags.
3+
#
4+
- --extra-ignore-file=ignore-file
5+
- --ignore-file-strategy=merge

0 commit comments

Comments
 (0)