From 2ed479ab9646973799ea867d59d50169b9ce86f8 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Dec 06 2016 23:33:51 +0000 Subject: patch to inherit parent ENVs --- diff --git a/dockerfile-parse-0.0.5-parent_env.patch b/dockerfile-parse-0.0.5-parent_env.patch new file mode 100644 index 0000000..37e48cc --- /dev/null +++ b/dockerfile-parse-0.0.5-parent_env.patch @@ -0,0 +1,128 @@ +diff --git a/dockerfile_parse/parser.py b/dockerfile_parse/parser.py +index 615d7a8..25b6536 100644 +--- a/dockerfile_parse/parser.py ++++ b/dockerfile_parse/parser.py +@@ -66,11 +66,12 @@ class Envs(dict): + + + class DockerfileParser(object): +- def __init__(self, path=None, cache_content=False, env_replace=True): ++ def __init__(self, path=None, cache_content=False, env_replace=True, parent_env=None): + """ + Initialize path to Dockerfile + :param path: path to (directory with) Dockerfile + :param cache_content: cache Dockerfile content inside DockerfileParser ++ :param parent_env: python dict of inherited env vars from parent image + """ + path = path or '.' + if path.endswith(DOCKERFILE_FILENAME): +@@ -91,6 +92,14 @@ class DockerfileParser(object): + + self.env_replace = env_replace + ++ if isinstance(parent_env, dict): ++ logger.debug("Setting inherited parent image ENV vars: %s", parent_env) ++ self.parent_env = parent_env ++ elif parent_env != None: ++ assert isinstance(parent_env, dict) ++ else: ++ self.parent_env = {} ++ + @property + def lines(self): + """ +@@ -106,7 +115,7 @@ class DockerfileParser(object): + self.cached_content = ''.join(lines) + return lines + except (IOError, OSError) as ex: +- logger.error("Couldn't retrieve lines from dockerfile: %s" % repr(ex)) ++ logger.error("Couldn't retrieve lines from dockerfile: %r", ex) + raise + + @lines.setter +@@ -122,7 +131,7 @@ class DockerfileParser(object): + with open(self.dockerfile_path, 'w') as dockerfile: + dockerfile.writelines([u2b(l) for l in lines]) + except (IOError, OSError) as ex: +- logger.error("Couldn't write lines to dockerfile: %s" % repr(ex)) ++ logger.error("Couldn't write lines to dockerfile: %r", ex) + raise + + @property +@@ -140,7 +149,7 @@ class DockerfileParser(object): + self.cached_content = content + return content + except (IOError, OSError) as ex: +- logger.error("Couldn't retrieve content of dockerfile: %s" % repr(ex)) ++ logger.error("Couldn't retrieve content of dockerfile: %r", ex) + raise + + @content.setter +@@ -156,7 +165,7 @@ class DockerfileParser(object): + with open(self.dockerfile_path, 'w') as dockerfile: + dockerfile.write(u2b(content)) + except (IOError, OSError) as ex: +- logger.error("Couldn't write content to dockerfile: %s" % repr(ex)) ++ logger.error("Couldn't write content to dockerfile: %r", ex) + raise + + @property +@@ -290,7 +299,7 @@ class DockerfileParser(object): + if name != 'LABEL' and name != 'ENV': + raise ValueError("Unsupported instruction '%s'", name) + instructions = {} +- envs = {} ++ envs = self.parent_env.copy() + for insndesc in self.structure: + this_insn = insndesc['instruction'] + if this_insn in (name, 'ENV'): +@@ -354,7 +363,7 @@ class DockerfileParser(object): + elif name == 'ENV': + existing = self.envs + +- logger.debug("setting %s instructions: %r" % (name, instructions)) ++ logger.debug("setting %s instructions: %r", name, instructions) + + to_delete = [k for k in existing if k not in instructions] + for key in to_delete: + +diff --git a/tests/test_parser.py b/tests/test_parser.py +index 8f63a04..e47fefe 100644 +--- a/tests/test_parser.py ++++ b/tests/test_parser.py +@@ -86,6 +86,35 @@ USER {0}""".format(NON_ASCII) + base_img = dfparser.baseimage + assert base_img.startswith('fedora') + ++ def test_get_parent_env(self, tmpdir): ++ tmpdir_path = str(tmpdir.realpath()) ++ p_env = {"bar": "baz"} ++ df1 = DockerfileParser(tmpdir_path, env_replace=True, parent_env=p_env) ++ df1.lines = [ ++ "FROM parent\n", ++ "ENV foo=\"$bar\"\n", ++ "LABEL label=\"$foo $bar\"\n" ++ ] ++ ++ # Even though we inherit an ENV, this .envs count should only be for the ++ # ENVs defined in *this* Dockerfile as we're parsing the Dockerfile and ++ # the parent_env is only to satisfy use of inhereted ENVs. ++ assert len(df1.envs) == 1 ++ assert df1.envs.get('foo') == 'baz' ++ assert len(df1.labels) == 1 ++ assert df1.labels.get('label') == 'baz baz' ++ ++ def test_get_parent_env_from_scratch(self, tmpdir): ++ tmpdir_path = str(tmpdir.realpath()) ++ p_env = {"bar": "baz"} ++ df1 = DockerfileParser(tmpdir_path, env_replace=True, parent_env=p_env) ++ df1.lines = [ ++ "FROM scratch\n", ++ ] ++ ++ assert not df1.envs ++ ++ + def test_get_instructions_from_df(self, dfparser, instruction): + dfparser.content = "" + lines = [] diff --git a/python-dockerfile-parse.spec b/python-dockerfile-parse.spec index 7b39452..02b2d73 100644 --- a/python-dockerfile-parse.spec +++ b/python-dockerfile-parse.spec @@ -15,13 +15,20 @@ Name: python-%{srcname} Version: 0.0.5 -Release: 6%{?dist} +Release: 7%{?dist} Summary: Python library for Dockerfile manipulation License: BSD URL: https://github.com/DBuildService/dockerfile-parse Source0: %{url}/archive/%{version}/%{srcname}-%{version}.tar.gz +# Patch to handle inheriting ENV vars from parent Dockerfiles +# +# Upstream PRs (merged into single patch here): +# https://github.com/DBuildService/dockerfile-parse/pull/21 +# https://github.com/DBuildService/dockerfile-parse/pull/22 +Patch0: dockerfile-parse-0.0.5-parent_env.patch + BuildArch: noarch %description @@ -61,7 +68,9 @@ Python 3 version. %endif %prep -%autosetup -n %{srcname}-%{version} +%setup -n %{srcname}-%{version} + +%patch0 -p1 %build %py2_build @@ -99,6 +108,9 @@ py.test-%{python3_version} -v tests %endif %changelog +* Tue Dec 06 2016 Adam Miller - 0.0.5-7 +- Patch to handle inheriting parent Dockerfile ENVs + * Wed Sep 07 2016 Igor Gnatenko - 0.0.5-6 - Modernize spec - Trivial fixes