瀏覽代碼

feat: add --progress flag

Signed-off-by: Nao YONASHIRO <[email protected]>
Nao YONASHIRO 6 年之前
父節點
當前提交
81e223d499
共有 3 個文件被更改,包括 104 次插入94 次删除
  1. 4 0
      compose/cli/main.py
  2. 3 2
      compose/project.py
  3. 97 92
      compose/service.py

+ 4 - 0
compose/cli/main.py

@@ -270,6 +270,9 @@ class TopLevelCommand(object):
             --no-cache              Do not use cache when building the image.
             --no-rm                 Do not remove intermediate containers after a successful build.
             --parallel              Build images in parallel.
+            --progress string       Set type of progress output (auto, plain, tty).
+                                    EXPERIMENTAL flag for native builder.
+                                    To enable, run with COMPOSE_NATIVE_BUILDER=1)
             --pull                  Always attempt to pull a newer version of the image.
             -q, --quiet             Don't print anything to STDOUT
         """
@@ -297,6 +300,7 @@ class TopLevelCommand(object):
             parallel_build=options.get('--parallel', False),
             silent=options.get('--quiet', False),
             cli=native_builder,
+            progress=options.get('--progress'),
         )
 
     def bundle(self, options):

+ 3 - 2
compose/project.py

@@ -355,7 +355,8 @@ class Project(object):
         return containers
 
     def build(self, service_names=None, no_cache=False, pull=False, force_rm=False, memory=None,
-              build_args=None, gzip=False, parallel_build=False, rm=True, silent=False, cli=False):
+              build_args=None, gzip=False, parallel_build=False, rm=True, silent=False, cli=False,
+              progress=None):
 
         services = []
         for service in self.get_services(service_names):
@@ -368,7 +369,7 @@ class Project(object):
             log.warning("Native build is an experimental feature and could change at any time")
 
         def build_service(service):
-            service.build(no_cache, pull, force_rm, memory, build_args, gzip, rm, silent, cli)
+            service.build(no_cache, pull, force_rm, memory, build_args, gzip, rm, silent, cli, progress)
         if parallel_build:
             _, errors = parallel.parallel_execute(
                 services,

+ 97 - 92
compose/service.py

@@ -1052,7 +1052,7 @@ class Service(object):
         return [build_spec(secret) for secret in self.secrets]
 
     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):
+              gzip=False, rm=True, silent=False, cli=False, progress=None):
         output_stream = open(os.devnull, 'w')
         if not silent:
             output_stream = sys.stdout
@@ -1073,8 +1073,8 @@ class Service(object):
                 'Impossible to perform platform-targeted builds for API version < 1.35'
             )
 
-        build_image = self.client.build if not cli else cli_build
-        build_output = build_image(
+        builder = self.client if not cli else _CLIBuilder(progress)
+        build_output = builder.build(
             path=path,
             tag=self.image_name,
             rm=rm,
@@ -1707,7 +1707,11 @@ def rewrite_build_path(path):
     return path
 
 
-def cli_build(path, tag=None, quiet=False, fileobj=None,
+class _CLIBuilder(object):
+    def __init__(self, progress):
+        self._progress = progress
+
+    def build(self, path, 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,
@@ -1715,94 +1719,95 @@ def cli_build(path, tag=None, quiet=False, fileobj=None,
               labels=None, cache_from=None, target=None, network_mode=None,
               squash=None, extra_hosts=None, platform=None, isolation=None,
               use_config_proxy=True):
-    """
-    Args:
-        path (str): Path to the directory containing the Dockerfile
-        buildargs (dict): A dictionary of build arguments
-        cache_from (:py:class:`list`): A list of images used for build
-            cache resolution
-        container_limits (dict): A dictionary of limits applied to each
-            container created by the build process. Valid keys:
-            - memory (int): set memory limit for build
-            - memswap (int): Total memory (memory + swap), -1 to disable
-                swap
-            - cpushares (int): CPU shares (relative weight)
-            - cpusetcpus (str): CPUs in which to allow execution, e.g.,
-                ``"0-3"``, ``"0,1"``
-        custom_context (bool): Optional if using ``fileobj``
-        decode (bool): If set to ``True``, the returned stream will be
-            decoded into dicts on the fly. Default ``False``
-        dockerfile (str): path within the build context to the Dockerfile
-        encoding (str): The encoding for a stream. Set to ``gzip`` for
-            compressing
-        extra_hosts (dict): Extra hosts to add to /etc/hosts in building
-            containers, as a mapping of hostname to IP address.
-        fileobj: A file object to use as the Dockerfile. (Or a file-like
-            object)
-        forcerm (bool): Always remove intermediate containers, even after
-            unsuccessful builds
-        isolation (str): Isolation technology used during build.
-            Default: `None`.
-        labels (dict): A dictionary of labels to set on the image
-        network_mode (str): networking mode for the run commands during
-            build
-        nocache (bool): Don't use the cache when set to ``True``
-        platform (str): Platform in the format ``os[/arch[/variant]]``
-        pull (bool): Downloads any updates to the FROM image in Dockerfiles
-        quiet (bool): Whether to return the status
-        rm (bool): Remove intermediate containers. The ``docker build``
-            command now defaults to ``--rm=true``, but we have kept the old
-            default of `False` to preserve backward compatibility
-        shmsize (int): Size of `/dev/shm` in bytes. The size must be
-            greater than 0. If omitted the system uses 64MB
-        squash (bool): Squash the resulting images layers into a
-            single layer.
-        tag (str): A tag to add to the final image
-        target (str): Name of the build-stage to build in a multi-stage
-            Dockerfile
-        timeout (int): HTTP timeout
-        use_config_proxy (bool): If ``True``, and if the docker client
-            configuration file (``~/.docker/config.json`` by default)
-            contains a proxy configuration, the corresponding environment
-            variables will be set in the container being built.
-    Returns:
-        A generator for the build output.
-    """
-    if dockerfile:
-        dockerfile = os.path.join(path, dockerfile)
-    iidfile = tempfile.mktemp()
-
-    command_builder = _CommandBuilder()
-    command_builder.add_params("--build-arg", buildargs)
-    command_builder.add_list("--cache-from", cache_from)
-    command_builder.add_arg("--file", dockerfile)
-    command_builder.add_flag("--force-rm", forcerm)
-    command_builder.add_arg("--memory", container_limits.get("memory"))
-    command_builder.add_flag("--no-cache", nocache)
-    command_builder.add_flag("--pull", pull)
-    command_builder.add_arg("--tag", tag)
-    command_builder.add_arg("--target", target)
-    command_builder.add_arg("--iidfile", iidfile)
-    args = command_builder.build([path])
-
-    magic_word = "Successfully built "
-    appear = False
-    with subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True) as p:
-        while True:
-            line = p.stdout.readline()
-            if not line:
-                break
-            if line.startswith(magic_word):
-                appear = True
-            yield json.dumps({"stream": line})
-
-    with open(iidfile) as f:
-        line = f.readline()
-        image_id = line.split(":")[1].strip()
-    os.remove(iidfile)
-
-    if not appear:
-        yield json.dumps({"stream": "{}{}\n".format(magic_word, image_id)})
+        """
+        Args:
+            path (str): Path to the directory containing the Dockerfile
+            buildargs (dict): A dictionary of build arguments
+            cache_from (:py:class:`list`): A list of images used for build
+                cache resolution
+            container_limits (dict): A dictionary of limits applied to each
+                container created by the build process. Valid keys:
+                - memory (int): set memory limit for build
+                - memswap (int): Total memory (memory + swap), -1 to disable
+                    swap
+                - cpushares (int): CPU shares (relative weight)
+                - cpusetcpus (str): CPUs in which to allow execution, e.g.,
+                    ``"0-3"``, ``"0,1"``
+            custom_context (bool): Optional if using ``fileobj``
+            decode (bool): If set to ``True``, the returned stream will be
+                decoded into dicts on the fly. Default ``False``
+            dockerfile (str): path within the build context to the Dockerfile
+            encoding (str): The encoding for a stream. Set to ``gzip`` for
+                compressing
+            extra_hosts (dict): Extra hosts to add to /etc/hosts in building
+                containers, as a mapping of hostname to IP address.
+            fileobj: A file object to use as the Dockerfile. (Or a file-like
+                object)
+            forcerm (bool): Always remove intermediate containers, even after
+                unsuccessful builds
+            isolation (str): Isolation technology used during build.
+                Default: `None`.
+            labels (dict): A dictionary of labels to set on the image
+            network_mode (str): networking mode for the run commands during
+                build
+            nocache (bool): Don't use the cache when set to ``True``
+            platform (str): Platform in the format ``os[/arch[/variant]]``
+            pull (bool): Downloads any updates to the FROM image in Dockerfiles
+            quiet (bool): Whether to return the status
+            rm (bool): Remove intermediate containers. The ``docker build``
+                command now defaults to ``--rm=true``, but we have kept the old
+                default of `False` to preserve backward compatibility
+            shmsize (int): Size of `/dev/shm` in bytes. The size must be
+                greater than 0. If omitted the system uses 64MB
+            squash (bool): Squash the resulting images layers into a
+                single layer.
+            tag (str): A tag to add to the final image
+            target (str): Name of the build-stage to build in a multi-stage
+                Dockerfile
+            timeout (int): HTTP timeout
+            use_config_proxy (bool): If ``True``, and if the docker client
+                configuration file (``~/.docker/config.json`` by default)
+                contains a proxy configuration, the corresponding environment
+                variables will be set in the container being built.
+        Returns:
+            A generator for the build output.
+        """
+        if dockerfile:
+            dockerfile = os.path.join(path, dockerfile)
+        iidfile = tempfile.mktemp()
+
+        command_builder = _CommandBuilder()
+        command_builder.add_params("--build-arg", buildargs)
+        command_builder.add_list("--cache-from", cache_from)
+        command_builder.add_arg("--file", dockerfile)
+        command_builder.add_flag("--force-rm", forcerm)
+        command_builder.add_arg("--memory", container_limits.get("memory"))
+        command_builder.add_flag("--no-cache", nocache)
+        command_builder.add_flag("--progress", self._progress)
+        command_builder.add_flag("--pull", pull)
+        command_builder.add_arg("--tag", tag)
+        command_builder.add_arg("--target", target)
+        command_builder.add_arg("--iidfile", iidfile)
+        args = command_builder.build([path])
+
+        magic_word = "Successfully built "
+        appear = False
+        with subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True) as p:
+            while True:
+                line = p.stdout.readline()
+                if not line:
+                    break
+                if line.startswith(magic_word):
+                    appear = True
+                yield json.dumps({"stream": line})
+
+        with open(iidfile) as f:
+            line = f.readline()
+            image_id = line.split(":")[1].strip()
+        os.remove(iidfile)
+
+        if not appear:
+            yield json.dumps({"stream": "{}{}\n".format(magic_word, image_id)})
 
 
 class _CommandBuilder(object):