diff --git a/dockermake/builds.py b/dockermake/builds.py index 413155a..7774c80 100644 --- a/dockermake/builds.py +++ b/dockermake/builds.py @@ -68,7 +68,7 @@ def build(self, client, Drives the build of the final image - get the list of steps and execute them. Args: - client (docker.APIClient): docker client object that will build the image + client (docker.Client): docker client object that will build the image nobuild (bool): just create dockerfiles, don't actually build the image keepbuildtags (bool): keep tags on intermediate images usecache (bool): use docker cache, or rebuild everything from scratch? @@ -142,13 +142,13 @@ def update_source_images(self, client, usecache, pull): def finalizenames(self, client, finalimage, keepbuildtags): """ Tag the built image with its final name and untag intermediate containers """ - client.tag(finalimage, *self.targetname.split(':')) + client.api.tag(finalimage, *self.targetname.split(':')) cprint('Tagged final image as "%s"' % self.targetname, 'green') if not keepbuildtags: print('Untagging intermediate containers:', end='') for step in self.steps: - client.remove_image(step.buildname, force=True) + client.api.remove_image(step.buildname, force=True) print(step.buildname, end=',') print() diff --git a/dockermake/staging.py b/dockermake/staging.py index 6d1f7b4..0d1a97c 100644 --- a/dockermake/staging.py +++ b/dockermake/staging.py @@ -105,9 +105,7 @@ def stage(self, startimage, newimage): buildargs = dict(path=cachedir, tag=newimage, decode=True) - - if self.cache_from: - buildargs['cache_from'] = self.cache_from + utils.set_build_cachefrom(self.cache_from, buildargs, client) # Build and show logs stream = client.api.build(**buildargs) diff --git a/dockermake/step.py b/dockermake/step.py index 2507205..ca385df 100644 --- a/dockermake/step.py +++ b/dockermake/step.py @@ -78,7 +78,7 @@ def build(self, client, pull=False, usecache=True): step. Args: - client (docker.APIClient): docker client object that will build the image + client (docker.Client): docker client object that will build the image pull (bool): whether to pull dependent layers from remote repositories usecache (bool): whether to use cached layers or rebuild from scratch """ @@ -94,7 +94,8 @@ def build(self, client, pull=False, usecache=True): usecache = False if not usecache: - print(' INFO: Docker caching disabled - forcing rebuild') + cprint(' Build cache disabled - this image will be rebuilt from scratch', + 'yellow') dockerfile = u'\n'.join(self.dockerfile_lines) @@ -103,8 +104,8 @@ def build(self, client, pull=False, usecache=True): nocache=not usecache, decode=True, rm=True) - if usecache and self.cache_from: - build_args['cache_from'] = self.cache_from + if usecache: + utils.set_build_cachefrom(self.cache_from, build_args, client) if self.build_dir is not None: tempdir = self.write_dockerfile(dockerfile) @@ -139,7 +140,7 @@ def build(self, client, pull=False, usecache=True): tempdir = None # start the build - stream = client.build(**build_args) + stream = client.api.build(**build_args) try: utils.stream_docker_logs(stream, self.buildname) except (ValueError, docker.errors.APIError) as e: @@ -150,6 +151,7 @@ def build(self, client, pull=False, usecache=True): os.unlink(os.path.join(tempdir, 'Dockerfile')) os.rmdir(tempdir) + def write_dockerfile(self, dockerfile): tempdir = os.path.abspath(os.path.join(self.build_dir, DOCKER_TMPDIR)) temp_df = os.path.join(tempdir, 'Dockerfile') @@ -165,11 +167,11 @@ def build_external_dockerfile(client, image): cprint(" Building base image from %s" % image, 'blue') assert not image.built - stream = client.build(path=os.path.dirname(image.path), - dockerfile=os.path.basename(image.path), - tag=image.tag, - decode=True, - rm=True) + stream = client.api.build(path=os.path.dirname(image.path), + dockerfile=os.path.basename(image.path), + tag=image.tag, + decode=True, + rm=True) try: utils.stream_docker_logs(stream, image) diff --git a/dockermake/utils.py b/dockermake/utils.py index 7a4a7c7..a187262 100644 --- a/dockermake/utils.py +++ b/dockermake/utils.py @@ -18,7 +18,8 @@ import textwrap import yaml -import docker +import docker.errors +from termcolor import cprint from . import errors @@ -95,7 +96,7 @@ def build_targets(args, defs, targets): if args.no_build: client = None else: - client = get_client_api() + client = get_client() if args.push_to_registry and args.registry_user: if not args.repository: @@ -147,7 +148,7 @@ def push(client, name): print(warn) else: print(' Pushing %s to %s:' % (name, name.split('/')[0])) - stream = _linestream(client.push(name, stream=True)) + stream = _linestream(client.api.push(name, stream=True)) line = stream_docker_logs(stream, 'PUSH %s' % name) if 'error' in line: @@ -216,6 +217,7 @@ def get_console_width(): SHOWSIZE = set(('Pushing', 'Pulling', 'Pulled', 'Downloaded', 'Downloading')) + def _show_xfer_state(pullstats, item): imgid = item['id'] stat = item['status'] @@ -231,3 +233,20 @@ def _show_xfer_state(pullstats, item): return toprint else: return None + + +def set_build_cachefrom(cache_from, buildargs, client): + if cache_from: # use cachefrom only if at least one of the images exists + for image in cache_from: + try: + client.images.get(image) + except docker.errors.ImageNotFound: + pass + else: + cprint(" Build cache sources: %s" % cache_from, + 'blue') + buildargs['cache_from'] = cache_from + return + else: + cprint(" No build cache sources present; ignoring --cache-repo and --cache-tag", + 'blue') diff --git a/test/test_features.py b/test/test_features.py index 734db4f..cd93b19 100644 --- a/test/test_features.py +++ b/test/test_features.py @@ -76,8 +76,9 @@ def test_no_cache(twin_simple_targets): image1, image2 = twin_simple_targets assert image1.id != image2.id - -def test_explicit_cache_from(twin_simple_targets, docker_client): +clean8 = creates_images('img1repo/simple-target:img1tag', + 'img2repo/simple-target:img2tag') +def test_explicit_cache_from(twin_simple_targets, docker_client, clean8): image1, image2 = twin_simple_targets image1.tag('img1repo/simple-target', tag='img1tag') image2.tag('img2repo/simple-target', tag='img2tag') @@ -88,6 +89,15 @@ def test_explicit_cache_from(twin_simple_targets, docker_client): assert final_image.id == image1.id +def test_cache_fallback(twin_simple_targets, docker_client): + image1, image2 = twin_simple_targets + + run_docker_make('-f data/simple.yml simple-target' + ' --cache-repo fakerepo --cache-tag faketag') + final_image = docker_client.images.get('simple-target') + assert final_image.id == image2.id + + def _check_files(img, **present): for f, record in _FILES.items(): if not present.get(f, True):