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 = []