Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support specifying a tar file as context #7283

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
136 changes: 98 additions & 38 deletions compose/service.py
Expand Up @@ -10,6 +10,7 @@
import tempfile
from collections import namedtuple
from collections import OrderedDict
from contextlib import contextmanager
from operator import attrgetter

import enum
Expand Down Expand Up @@ -1060,56 +1061,106 @@ def build_spec(secret):

return [build_spec(secret) for secret in self.secrets]

@contextmanager
def _prepare_build_args(
self,
no_cache=False,
pull=False,
force_rm=False,
memory=None,
build_args_override=None,
gzip=False,
rm=True,
):
fileobj = None

try:
build_opts = self.options.get('build', {})

path = rewrite_build_path(build_opts.get('context'))
if os.path.isfile(path):
fileobj = open(path, 'rb')
custom_context = True
path = None
else:
fileobj = None
custom_context = False

build_args = build_opts.get('args', {}).copy()
if build_args_override:
build_args.update(build_args_override)
for k, v in self._parse_proxy_config().items():
build_args.setdefault(k, v)

shmsize = build_opts.get('shm_size')
if shmsize is not None:
shmsize = parse_bytes(shmsize)

if memory is not None:
memory = parse_bytes(memory)
container_limits = {
'memory': memory,
}

isolation = self.options.get('isolation', None)
isolation = build_opts.get('isolation', isolation)

yield {
'path': path,
'fileobj': fileobj,
'custom_context': custom_context,
'tag': self.image_name,
'rm': rm,
'forcerm': force_rm,
'pull': pull,
'nocache': no_cache,
'dockerfile': build_opts.get('dockerfile', None),
'cache_from': self.get_cache_from(build_opts),
'labels': build_opts.get('labels', None),
'buildargs': build_args,
'network_mode': build_opts.get('network', None),
'target': build_opts.get('target', None),
'shmsize': shmsize,
'extra_hosts': build_opts.get('extra_hosts', None),
'container_limits': container_limits,
'gzip': gzip,
'isolation': isolation,
'platform': self.platform,
}

finally:
if fileobj is not None:
fileobj.close()

def build(self, no_cache=False, pull=False, force_rm=False, memory=None, build_args_override=None,
gzip=False, rm=True, silent=False, cli=False, progress=None):
output_stream = open(os.devnull, 'w')
if not silent:
output_stream = sys.stdout
log.info('Building %s' % self.name)

build_opts = self.options.get('build', {})

build_args = build_opts.get('args', {}).copy()
if build_args_override:
build_args.update(build_args_override)

for k, v in self._parse_proxy_config().items():
build_args.setdefault(k, v)

path = rewrite_build_path(build_opts.get('context'))
if self.platform and version_lt(self.client.api_version, '1.35'):
raise OperationFailedError(
'Impossible to perform platform-targeted builds for API version < 1.35'
)

builder = self.client if not cli else _CLIBuilder(progress)
build_output = builder.build(
path=path,
tag=self.image_name,
rm=rm,
forcerm=force_rm,

with self._prepare_build_args(
no_cache=no_cache,
pull=pull,
nocache=no_cache,
dockerfile=build_opts.get('dockerfile', None),
cache_from=self.get_cache_from(build_opts),
labels=build_opts.get('labels', None),
buildargs=build_args,
network_mode=build_opts.get('network', None),
target=build_opts.get('target', None),
shmsize=parse_bytes(build_opts.get('shm_size')) if build_opts.get('shm_size') else None,
extra_hosts=build_opts.get('extra_hosts', None),
container_limits={
'memory': parse_bytes(memory) if memory else None
},
force_rm=force_rm,
memory=memory,
build_args_override=build_args_override,
gzip=gzip,
isolation=build_opts.get('isolation', self.options.get('isolation', None)),
platform=self.platform,
)
rm=rm,
) as kwargs:
build_output = builder.build(**kwargs)

try:
all_events = list(stream_output(build_output, output_stream))
except StreamOutputError as e:
raise BuildError(self, six.text_type(e))
try:
all_events = list(stream_output(build_output, output_stream))
except StreamOutputError as e:
raise BuildError(self, six.text_type(e))

# Ensure the HTTP connection is not reused for another
# streaming command, as the Docker daemon can sometimes
Expand All @@ -1118,6 +1169,7 @@ def build(self, no_cache=False, pull=False, force_rm=False, memory=None, build_a

image_id = None

event = None
for event in all_events:
if 'stream' in event:
match = re.search(r'Successfully built ([0-9a-f]+)', event.get('stream', ''))
Expand Down Expand Up @@ -1722,7 +1774,7 @@ class _CLIBuilder(object):
def __init__(self, progress):
self._progress = progress

def build(self, path, tag=None, quiet=False, fileobj=None,
def build(self, path=None, tag=None, quiet=False, fileobj=None,
nocache=False, rm=False, timeout=None,
custom_context=False, encoding=None, pull=False,
forcerm=False, dockerfile=None, container_limits=None,
Expand Down Expand Up @@ -1783,7 +1835,7 @@ def build(self, path, tag=None, quiet=False, fileobj=None,
Returns:
A generator for the build output.
"""
if dockerfile:
if path and dockerfile:
dockerfile = os.path.join(path, dockerfile)
iidfile = tempfile.mktemp()

Expand All @@ -1799,11 +1851,19 @@ def build(self, path, tag=None, quiet=False, fileobj=None,
command_builder.add_arg("--tag", tag)
command_builder.add_arg("--target", target)
command_builder.add_arg("--iidfile", iidfile)
args = command_builder.build([path])
args = command_builder.build([path or '-'])

magic_word = "Successfully built "
appear = False
with subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True) as p:
with subprocess.Popen(
args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
universal_newlines=True,
) as p:
if fileobj:
p.stdin.write(fileobj.read().decode())
p.stdin.close()
while True:
line = p.stdout.readline()
if not line:
Expand Down