blob: e42b63b79460eb0e658d627f9a43627d0c4f8439 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import os
from liminal.build.image_builder import ImageBuilder
class PythonImageVersions:
"""
Handles the python versions for python images.
"""
@property
def default_version(self):
return '3.7'
@property
def supported_versions(self):
return '3.6', '3.7', '3.8', '3.9'
def get_image_name(self, python_version):
"""
:param python_version: The python version that would be installed in
the docker image. For example '3.8', '3.8.1' etc.
:type python_version: str
:return: The name of the base (slim) python image
:rtype: str
"""
if not python_version:
python_version = self.default_version
else:
python_version = str(python_version)
if python_version[:3] not in self.supported_versions:
raise ValueError(f'liminal supports the following python versions: '
f'{self.supported_versions} but {python_version} '
f'were passed')
return f'python:{python_version}-slim'
class BasePythonImageBuilder(ImageBuilder):
"""
Base class for building python images.
"""
__PIP_CONF = 'pip_conf'
__PYTHON_VERSION = 'python_version'
def __init__(self, config, base_path, relative_source_path, tag,
base_image=PythonImageVersions()):
super().__init__(config, base_path, relative_source_path, tag)
self._base_image = base_image
@staticmethod
def _dockerfile_path():
raise NotImplementedError()
def _write_additional_files(self, temp_dir):
requirements_file_path = os.path.join(temp_dir, 'requirements.txt')
if not os.path.exists(requirements_file_path):
with open(requirements_file_path, 'w'):
pass
super()._write_additional_files(temp_dir)
def _additional_files_from_filename_content_pairs(self):
with open(self._dockerfile_path()) as original:
data = original.read()
data = self.__mount_pip_conf(data)
data = self.__add_python_base_version(data)
return [('Dockerfile', data)]
def __mount_pip_conf(self, data):
new_data = data
if self.__PIP_CONF in self.config:
new_data = '# syntax = docker/dockerfile:1.0-experimental\n' + data
new_data = new_data.replace('{{mount}}',
'--mount=type=secret,id=pip_config,dst=/etc/pip.conf \\\n')
else:
new_data = new_data.replace('{{mount}} ', '')
return new_data
def __add_python_base_version(self, data):
python_version = self.config.get(self.__PYTHON_VERSION)
base_image = self._base_image.get_image_name(python_version)
return data.replace('{{python}}', base_image)
def _build_flags(self):
if self.__PIP_CONF in self.config:
return f'--secret id=pip_config,src={self.config[self.__PIP_CONF]}'
else:
return ''
def _use_buildkit(self):
if self.__PIP_CONF in self.config:
return True