فهرست منبع

add --parallel option to build

Signed-off-by: Gil Raphaelli <[email protected]>
Gil Raphaelli 7 سال پیش
والد
کامیت
89f2bfe4f3

+ 2 - 0
compose/cli/main.py

@@ -260,6 +260,7 @@ class TopLevelCommand(object):
             --pull                  Always attempt to pull a newer version of the image.
             -m, --memory MEM        Sets memory limit for the build container.
             --build-arg key=val     Set build-time variables for services.
+            --parallel              Build images in parallel.
         """
         service_names = options['SERVICE']
         build_args = options.get('--build-arg', None)
@@ -280,6 +281,7 @@ class TopLevelCommand(object):
             memory=options.get('--memory'),
             build_args=build_args,
             gzip=options.get('--compress', False),
+            parallel_build=options.get('--parallel', False),
         )
 
     def bundle(self, options):

+ 25 - 2
compose/project.py

@@ -372,13 +372,36 @@ 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):
+              build_args=None, gzip=False, parallel_build=False):
+
+        services = []
         for service in self.get_services(service_names):
             if service.can_be_built():
-                service.build(no_cache, pull, force_rm, memory, build_args, gzip)
+                services.append(service)
             else:
                 log.info('%s uses an image, skipping' % service.name)
 
+        def build_service(service):
+            service.build(no_cache, pull, force_rm, memory, build_args, gzip)
+
+        if parallel_build:
+            _, errors = parallel.parallel_execute(
+                services,
+                build_service,
+                operator.attrgetter('name'),
+                'Building',
+                limit=5,
+            )
+            if len(errors):
+                combined_errors = '\n'.join([
+                    e.decode('utf-8') if isinstance(e, six.binary_type) else e for e in errors.values()
+                ])
+                raise ProjectError(combined_errors)
+
+        else:
+            for service in services:
+                build_service(service)
+
     def create(
         self,
         service_names=None,

+ 7 - 0
tests/acceptance/cli_test.py

@@ -773,6 +773,13 @@ class CLITestCase(DockerClientTestCase):
 
         assert 'does not exist, is not accessible, or is not a valid URL' in result.stderr
 
+    def test_build_parallel(self):
+        self.base_dir = 'tests/fixtures/build-multiple-composefile'
+        result = self.dispatch(['build', '--parallel'])
+        assert 'Successfully tagged build-multiple-composefile_a:latest' in result.stdout
+        assert 'Successfully tagged build-multiple-composefile_b:latest' in result.stdout
+        assert 'Successfully built' in result.stdout
+
     def test_create(self):
         self.dispatch(['create'])
         service = self.project.get_service('simple')

+ 4 - 0
tests/fixtures/build-multiple-composefile/a/Dockerfile

@@ -0,0 +1,4 @@
+
+FROM busybox:latest
+RUN  echo a
+CMD  top

+ 4 - 0
tests/fixtures/build-multiple-composefile/b/Dockerfile

@@ -0,0 +1,4 @@
+
+FROM busybox:latest
+RUN  echo b
+CMD  top

+ 8 - 0
tests/fixtures/build-multiple-composefile/docker-compose.yml

@@ -0,0 +1,8 @@
+
+version: "2"
+
+services:
+  a:
+    build: ./a
+  b:
+    build: ./b