Codebase list docker-compose / 3eee3e0
change builder API to return imageID this allows more flexibility running CLI builder, especially we don't have anymore to parse build output to get build status/imageID and can pass the console FDs to buildkit Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com> Nicolas De Loof authored 3 years ago Nicolas De loof committed 3 years ago
1 changed file(s) with 71 addition(s) and 51 deletion(s). Raw diff Collapse all Expand all
00 import enum
11 import itertools
2 import json
32 import logging
43 import os
54 import re
11241123 'Impossible to perform platform-targeted builds for API version < 1.35'
11251124 )
11261125
1127 builder = self.client if not cli else _CLIBuilder(progress)
1128 build_output = builder.build(
1126 builder = _ClientBuilder(self.client) if not cli else _CLIBuilder(progress)
1127 return builder.build(
1128 service=self,
11291129 path=path,
11301130 tag=self.image_name,
11311131 rm=rm,
11461146 gzip=gzip,
11471147 isolation=build_opts.get('isolation', self.options.get('isolation', None)),
11481148 platform=self.platform,
1149 )
1150
1151 try:
1152 all_events = list(stream_output(build_output, output_stream))
1153 except StreamOutputError as e:
1154 raise BuildError(self, str(e))
1155
1156 # Ensure the HTTP connection is not reused for another
1157 # streaming command, as the Docker daemon can sometimes
1158 # complain about it
1159 self.client.close()
1160
1161 image_id = None
1162
1163 for event in all_events:
1164 if 'stream' in event:
1165 match = re.search(r'Successfully built ([0-9a-f]+)', event.get('stream', ''))
1166 if match:
1167 image_id = match.group(1)
1168
1169 if image_id is None:
1170 raise BuildError(self, event if all_events else 'Unknown')
1171
1172 return image_id
1149 output_stream=output_stream)
11731150
11741151 def get_cache_from(self, build_opts):
11751152 cache_from = build_opts.get('cache_from', None)
18261803 return path
18271804
18281805
1829 class _CLIBuilder:
1830 def __init__(self, progress):
1831 self._progress = progress
1832
1833 def build(self, path, tag=None, quiet=False, fileobj=None,
1806 class _ClientBuilder:
1807 def __init__(self, client):
1808 self.client = client
1809
1810 def build(self, service, path, tag=None, quiet=False, fileobj=None,
18341811 nocache=False, rm=False, timeout=None,
18351812 custom_context=False, encoding=None, pull=False,
18361813 forcerm=False, dockerfile=None, container_limits=None,
18371814 decode=False, buildargs=None, gzip=False, shmsize=None,
18381815 labels=None, cache_from=None, target=None, network_mode=None,
18391816 squash=None, extra_hosts=None, platform=None, isolation=None,
1840 use_config_proxy=True):
1817 use_config_proxy=True, output_stream=sys.stdout):
1818 build_output = self.client.build(
1819 path=path,
1820 tag=tag,
1821 nocache=nocache,
1822 rm=rm,
1823 pull=pull,
1824 forcerm=forcerm,
1825 dockerfile=dockerfile,
1826 labels=labels,
1827 cache_from=cache_from,
1828 buildargs=buildargs,
1829 network_mode=network_mode,
1830 target=target,
1831 shmsize=shmsize,
1832 extra_hosts=extra_hosts,
1833 container_limits=container_limits,
1834 gzip=gzip,
1835 isolation=isolation,
1836 platform=platform)
1837
1838 try:
1839 all_events = list(stream_output(build_output, output_stream))
1840 except StreamOutputError as e:
1841 raise BuildError(service, str(e))
1842
1843 # Ensure the HTTP connection is not reused for another
1844 # streaming command, as the Docker daemon can sometimes
1845 # complain about it
1846 self.client.close()
1847
1848 image_id = None
1849
1850 for event in all_events:
1851 if 'stream' in event:
1852 match = re.search(r'Successfully built ([0-9a-f]+)', event.get('stream', ''))
1853 if match:
1854 image_id = match.group(1)
1855
1856 if image_id is None:
1857 raise BuildError(service, event if all_events else 'Unknown')
1858
1859 return image_id
1860
1861
1862 class _CLIBuilder:
1863 def __init__(self, progress):
1864 self._progress = progress
1865
1866 def build(self, service, path, tag=None, quiet=False, fileobj=None,
1867 nocache=False, rm=False, timeout=None,
1868 custom_context=False, encoding=None, pull=False,
1869 forcerm=False, dockerfile=None, container_limits=None,
1870 decode=False, buildargs=None, gzip=False, shmsize=None,
1871 labels=None, cache_from=None, target=None, network_mode=None,
1872 squash=None, extra_hosts=None, platform=None, isolation=None,
1873 use_config_proxy=True, output_stream=sys.stdout):
18411874 """
18421875 Args:
1876 service (str): Service to be built
18431877 path (str): Path to the directory containing the Dockerfile
18441878 buildargs (dict): A dictionary of build arguments
18451879 cache_from (:py:class:`list`): A list of images used for build
18881922 configuration file (``~/.docker/config.json`` by default)
18891923 contains a proxy configuration, the corresponding environment
18901924 variables will be set in the container being built.
1925 output_stream (writer): stream to use for build logs
18911926 Returns:
18921927 A generator for the build output.
18931928 """
19201955
19211956 args = command_builder.build([path])
19221957
1923 magic_word = "Successfully built "
1924 appear = False
1925 with subprocess.Popen(args, stdout=subprocess.PIPE,
1958 with subprocess.Popen(args, stdout=output_stream, stderr=sys.stderr,
19261959 universal_newlines=True) as p:
1927 while True:
1928 line = p.stdout.readline()
1929 if not line:
1930 break
1931 if line.startswith(magic_word):
1932 appear = True
1933 yield json.dumps({"stream": line})
1934
19351960 p.communicate()
19361961 if p.returncode != 0:
1937 raise StreamOutputError()
1962 raise BuildError(service, "Build failed")
19381963
19391964 with open(iidfile) as f:
19401965 line = f.readline()
19411966 image_id = line.split(":")[1].strip()
19421967 os.remove(iidfile)
19431968
1944 # In case of `DOCKER_BUILDKIT=1`
1945 # there is no success message already present in the output.
1946 # Since that's the way `Service::build` gets the `image_id`
1947 # it has to be added `manually`
1948 if not appear:
1949 yield json.dumps({"stream": "{}{}\n".format(magic_word, image_id)})
1969 return image_id
19501970
19511971
19521972 class _CommandBuilder: