Merge pull request #681 from Xarthisius/abspath_in_scripts

[MRG] Allow absolute paths in build_script_files. Fixes #673
pull/782/head
Min RK 2019-09-07 12:33:14 +02:00 zatwierdzone przez GitHub
commit 4f428c3055
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
2 zmienionych plików z 88 dodań i 5 usunięć

Wyświetl plik

@ -5,8 +5,10 @@ import io
import os import os
import re import re
import logging import logging
import docker import string
import sys import sys
import hashlib
import escapism
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from traitlets import Dict from traitlets import Dict
@ -534,6 +536,17 @@ class BuildPack:
"RUN {}".format(textwrap.dedent(script.strip("\n"))) "RUN {}".format(textwrap.dedent(script.strip("\n")))
) )
# Based on a physical location of a build script on the host,
# create a mapping between:
# 1. Location of a build script in a Docker build context
# ('assemble_files/<escaped-file-path-truncated>-<6-chars-of-its-hash>')
# 2. Location of the aforemention script in the Docker image
# Base template basically does: COPY <1.> <2.>
build_script_files = {
self.generate_build_context_filename(k)[0]: v
for k, v in self.get_build_script_files().items()
}
return t.render( return t.render(
packages=sorted(self.get_packages()), packages=sorted(self.get_packages()),
path=self.get_path(), path=self.get_path(),
@ -544,13 +557,42 @@ class BuildPack:
preassemble_script_files=self.get_preassemble_script_files(), preassemble_script_files=self.get_preassemble_script_files(),
preassemble_script_directives=preassemble_script_directives, preassemble_script_directives=preassemble_script_directives,
assemble_script_directives=assemble_script_directives, assemble_script_directives=assemble_script_directives,
build_script_files=self.get_build_script_files(), build_script_files=build_script_files,
base_packages=sorted(self.get_base_packages()), base_packages=sorted(self.get_base_packages()),
post_build_scripts=self.get_post_build_scripts(), post_build_scripts=self.get_post_build_scripts(),
start_script=self.get_start_script(), start_script=self.get_start_script(),
appendix=self.appendix, appendix=self.appendix,
) )
@staticmethod
def generate_build_context_filename(src_path, hash_length=6):
"""
Generate a filename for a file injected into the Docker build context.
In case the src_path is relative, it's assumed it's relative to directory of
this __file__. Returns the resulting filename and an absolute path to the source
file on host.
"""
if not os.path.isabs(src_path):
src_parts = src_path.split("/")
src_path = os.path.join(os.path.dirname(__file__), *src_parts)
src_path_hash = hashlib.sha256(src_path.encode("utf-8")).hexdigest()
safe_chars = set(string.ascii_letters + string.digits)
def escape(s):
return escapism.escape(s, safe=safe_chars, escape_char="-")
src_path_slug = escape(src_path)
filename = "build_script_files/{name}-{hash}"
return (
filename.format(
name=src_path_slug[: 255 - hash_length - 20],
hash=src_path_hash[:hash_length],
).lower(),
src_path,
)
def build( def build(
self, self,
client, client,
@ -580,9 +622,8 @@ class BuildPack:
return tar return tar
for src in sorted(self.get_build_script_files()): for src in sorted(self.get_build_script_files()):
src_parts = src.split("/") dest_path, src_path = self.generate_build_context_filename(src)
src_path = os.path.join(os.path.dirname(__file__), *src_parts) tar.add(src_path, dest_path, filter=_filter_tar)
tar.add(src_path, src, filter=_filter_tar)
tar.add(ENTRYPOINT_FILE, "repo2docker-entrypoint", filter=_filter_tar) tar.add(ENTRYPOINT_FILE, "repo2docker-entrypoint", filter=_filter_tar)

Wyświetl plik

@ -0,0 +1,42 @@
"""Test if assemble scripts from outside of r2d repo are accepted."""
import time
from repo2docker.app import Repo2Docker
from repo2docker.buildpacks import PythonBuildPack
def test_Repo2Docker_external_build_scripts(tmpdir):
tempfile = tmpdir.join("absolute-script")
tempfile.write("Hello World of Absolute Paths!")
class MockBuildPack(PythonBuildPack):
def detect(self):
return True
def get_build_script_files(self):
files = {str(tempfile): "/tmp/my_extra_script"}
files.update(super().get_build_script_files())
return files
app = Repo2Docker(repo=str(tmpdir))
app.buildpacks = [MockBuildPack]
app.initialize()
app.build()
container = app.start_container()
# give the container a chance to start
tic = 180
while container.status != "running" or tic < 0:
time.sleep(1)
tic -= 1
assert container.status == "running"
try:
status, output = container.exec_run(["sh", "-c", "cat /tmp/my_extra_script"])
assert status == 0
assert output.decode("utf-8") == "Hello World of Absolute Paths!"
finally:
container.stop(timeout=1)
container.reload()
assert container.status == "exited", container.status
container.remove()