Exemple #1
0
    def build(self, client, pull=False, usecache=True):
        """
        Drives an individual build step. Build steps are separated by build_directory.
        If a build has zero one or less build_directories, it will be built in a single
        step.

        Args:
            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
        """
        print(colored('  Building step', 'blue'),
              colored(self.imagename, 'blue', attrs=['bold']),
              colored('defined in', 'blue'),
              colored(self.sourcefile, 'blue', attrs=['bold']))

        if self.build_first and not self.build_first.built:
            self.build_external_dockerfile(client, self.build_first)

        if self.bust_cache:
            usecache = False

        if not usecache:
            cprint('  Build cache disabled - this image will be rebuilt from scratch',
                   'yellow')

        dockerfile = u'\n'.join(self.dockerfile_lines)

        kwargs = dict(tag=self.buildname,
                      pull=pull,
                      nocache=not usecache,
                      decode=True, rm=True,
                      buildargs=self.buildargs)

        if usecache:
            utils.set_build_cachefrom(self.cache_from, kwargs, client)

        if self.build_dir is not None:
            tempdir = self.write_dockerfile(dockerfile)
            context_path = os.path.abspath(os.path.expanduser(self.build_dir))
            kwargs.update(fileobj=None,
                              dockerfile=os.path.join(DOCKER_TMPDIR, 'Dockerfile'))
            print(colored('  Build context:', 'blue'),
                  colored(os.path.relpath(context_path), 'blue', attrs=['bold']))

            if not self.custom_exclude:
                kwargs.update(path=context_path)
            else:
                print(colored('  Custom .dockerignore from:','blue'),
                      colored(os.path.relpath(self.ignoredefs_file),  'blue', attrs=['bold']))
                context = docker.utils.tar(self.build_dir,
                                           exclude=self.custom_exclude,
                                           dockerfile=os.path.join(DOCKER_TMPDIR, 'Dockerfile'),
                                           gzip=False)
                kwargs.update(fileobj=context,
                                  custom_context=True)

        else:
            if sys.version_info.major == 2:
                kwargs.update(fileobj=StringIO(dockerfile),
                                  path=None,
                                  dockerfile=None)
            else:
                kwargs.update(fileobj=BytesIO(dockerfile.encode('utf-8')),
                                  path=None,
                                  dockerfile=None)

            tempdir = None

        # start the build
        stream = client.api.build(**kwargs)
        try:
            utils.stream_docker_logs(stream, self.buildname)
        except (ValueError, docker.errors.APIError) as e:
            raise errors.BuildError(dockerfile, str(e), kwargs)

        # remove the temporary dockerfile
        if tempdir is not None:
            os.unlink(os.path.join(tempdir, 'Dockerfile'))
            os.rmdir(tempdir)
Exemple #2
0
    def build(self, client, pull=False, usecache=True):
        """
        Drives an individual build step. Build steps are separated by build_directory.
        If a build has zero one or less build_directories, it will be built in a single
        step.

        Args:
            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
        """
        print(
            colored("  Building step", "blue"),
            colored(self.imagename, "blue", attrs=["bold"]),
            colored("defined in", "blue"),
            colored(self.sourcefile, "blue", attrs=["bold"]),
        )

        if self.build_first and not self.build_first.built:
            self.build_external_dockerfile(client, self.build_first)

        if self.bust_cache:
            usecache = False

        if not usecache:
            cprint(
                "  Build cache disabled - this image will be rebuilt from scratch",
                "yellow",
            )

        dockerfile = "\n".join(self.dockerfile_lines)

        kwargs = dict(
            tag=self.buildname,
            pull=pull,
            nocache=not usecache,
            decode=True,
            rm=True,
            buildargs=self.buildargs,
            squash=self.squash,
        )

        if usecache:
            utils.set_build_cachefrom(self.cache_from, kwargs, client)

        if self.build_dir is not None:
            tempdir = self.write_dockerfile(dockerfile)
            context_path = os.path.abspath(os.path.expanduser(self.build_dir))
            kwargs.update(fileobj=None,
                          dockerfile=os.path.join(DOCKER_TMPDIR, "Dockerfile"))
            print(
                colored("  Build context:", "blue"),
                colored(os.path.relpath(context_path), "blue", attrs=["bold"]),
            )

            if not self.custom_exclude:
                kwargs.update(path=context_path)
            else:
                print(
                    colored("  Custom .dockerignore from:", "blue"),
                    colored(os.path.relpath(self.ignoredefs_file),
                            "blue",
                            attrs=["bold"]),
                )

                # AMV - this is a brittle call to an apparently "private' docker sdk method
                context = docker.utils.tar(
                    self.build_dir,
                    exclude=self.custom_exclude,
                    dockerfile=(os.path.join(DOCKER_TMPDIR,
                                             "Dockerfile"), dockerfile),
                    gzip=False,
                )
                kwargs.update(fileobj=context, custom_context=True)

        else:
            if sys.version_info.major == 2:
                fileobj = StringIO(dockerfile)
            else:
                fileobj = BytesIO(dockerfile.encode("utf-8"))

            kwargs.update(fileobj=fileobj, path=None, dockerfile=None)

            tempdir = None

        # start the build
        stream = client.api.build(**kwargs)
        try:
            utils.stream_docker_logs(stream, self.buildname)
        except docker.errors.APIError as e:
            if self.squash and not client.version().get("Experimental", False):
                raise errors.ExperimentalDaemonRequiredError(
                    "Docker error message:\n   " + str(e) +
                    "\n\nUsing `squash` and/or `secret_files` requires a docker"
                    " daemon with experimental features enabled. See\n"
                    "    https://github.com/docker/docker-ce/blob/master/components/cli/"
                    "experimental/README.md")
            else:
                raise errors.BuildError(dockerfile, str(e), kwargs)
        except ValueError as e:
            raise errors.BuildError(dockerfile, str(e), kwargs)

        if self.squash and not self.bust_cache:
            self._resolve_squash_cache(client)

        # remove the temporary dockerfile
        if tempdir is not None:
            os.unlink(os.path.join(tempdir, "Dockerfile"))
            os.rmdir(tempdir)