diff --git a/pym/builder/variables/images.py b/pym/builder/variables/images.py new file mode 100644 index 0000000..226b33b --- /dev/null +++ b/pym/builder/variables/images.py @@ -0,0 +1,1169 @@ +# -*- coding: utf-8 -*- + +# Copyright 2015 Calculate Ltd. http://www.calculate-linux.org +# +# Licensed 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 sys +from os import path +import os +import re +from calculate.install.variables.kernel import KernelConfig +from calculate.lib.utils.portage import getSquashList +from .action import Actions +from calculate.install import distr +from calculate.lib.utils.device import getUdevDeviceInfo, humanreadableSize +from calculate.lib.utils.files import isMount, process, typeFile, listDirectory, \ + pathJoin +from calculate.lib.utils.kernel import InitrdFile +from calculate.lib.utils.tools import max_default +from ..build_storage import BuildStorage, Build +from ..drive_spool import DriveSpool +from calculate.lib.datavars import Variable, VariableError, ReadonlyVariable, \ + TableVariable +from functools import wraps + +_ = lambda x:x + +from calculate.lib.cl_lang import setLocalTranslate +setLocalTranslate('cl_builder3',sys.modules[__name__]) + +def debug(func): + @wraps(func) + def _wrapped_func(*args, **kw): + ret = func(*args, **kw) + print "MYDEBUG",ret + return ret + return _wrapped_func + +def is_action(*available_action, **action_kwargs): + def decorator(func): + @wraps(func) + def _wrapped_func(self, *args, **kw): + if self.Get('cl_action') in available_action: + return func(self, *args, **kw) + else: + return action_kwargs.get('default_value', '') + return _wrapped_func + return decorator + +def as_list(func): + @wraps(func) + def _wrapped_func(self, *args, **kw): + return list(func(self, *args, **kw)) + return _wrapped_func + + +class VariableClBuilderStorage(ReadonlyVariable): + type = "object" + + def get(self): + return BuildStorage() + + +class VariableClBuilderAvailableDev(Variable): + """ + Список дисков, которые можно использовать для сборки + """ + type = "list" + + def get(self): + if self.Get('os_root_type') == "livecd": + return ["/run/initramfs/workspace/var/calculate/assemble"] + return [] + + +class VariableClBuilderDeviceSpool(ReadonlyVariable): + """ + Стэк дисков, которые можно использовать для сборки + """ + type = "object" + + def get(self): + ds = DriveSpool(self.Get('cl_builder_available_dev')) + return ds + + +class BaseBuildId(Variable): + """ + Базовый класс для переменной id + """ + opt = ["--id"] + metavalue = "ID" + + def init(self): + self.label = _("Build ID") + self.help = _("build ID") + +class VariableClBuilderVideoDriverPath(Variable): + """ + Имя файла, содержащего данные об установки драйверов во время загрузки + """ + def get(self): + builder_path = self.Get('cl_builder_path') + return path.join( + builder_path, + 'var/cache/calculate/video_drivers') + +class VariableClBuilderVideodrvSet(Variable): + """ + Нужно ли скачивать пакеты в дистрибутив для установки проприетарных + драйверов во время загрузки + """ + type = "bool" + opt = ["--video", "-V"] + value = "off" + + def init(self): + self.label = _("Include proprietary video drivers") + self.help = _("include proprietary video drivers") + +class VariableClBuilderSourceFilename(Variable): + """ + Названия файла исходного дистрибутива + """ + type = "file" + element = 'file' + opt = ["--source"] + metavalue = "SOURCE" + untrusted = True + + def init(self): + self.label = _("Source image") + self.help = _("source image") + + def check(self, isoimage): + """Set image file""" + if self.Get('cl_action') in Actions.NewAssemble and not isoimage: + raise VariableError(_("You need to select a source image")) + shortname = self.Get('os_builder_linux_shortname') + build = self.Get('os_builder_linux_build') + arch = self.Get('os_builder_arch_machine') + local_arch = self.Get('os_arch_machine') + if not build or not shortname or not arch: + raise VariableError(_("Wrong image file")) + if local_arch == "i686" and arch != local_arch: + raise VariableError( + _("Unable to assemble the system {what} from {local}").format( + what=arch, local=local_arch)) + + def humanReadable(self): + fullname = self.Get('os_builder_linux_name') + subname = self.Get('os_builder_linux_subname') + ver = self.Get('os_builder_linux_ver') + if subname: + subname = " %s" % subname + if ver: + ver = " %s"%ver + arch = self.Get('os_builder_arch_machine') + build = self.Get('os_builder_linux_build') + + return "{fullname}{ver} {arch} {build}".format( + fullname="%s%s" % (fullname, subname), + build=build, ver=ver, arch=arch) + + def get(self): + if self.Get('os_root_type') == 'livecd': + return '/run/initramfs/live' + return "" + + +class VariableClBuilderSource(ReadonlyVariable): + """ + Объект исходного дистрибутива для разворачивания сборки + """ + type = "object" + + def get(self): + """Get image file from distributive repository""" + try: + filename = self.Get('cl_builder_source_filename') + if filename: + return distr.Distributive.fromFile(filename) + except distr.DistributiveError: + pass + return "" + + def humanReadable(self): + filename = self.Get('cl_builder_source') + if filename: + return filename.getType() + return filename + + +class VariableClBuilderDiskDev(Variable): + """ + Диск или директория, куда будет развёрнут образ + """ + type = "choiceedit" + untrusted = True + opt = ["-d", "--disk"] + metavalue = "DEST" + + def init(self): + self.label = _("Build location") + self.help = _("partition or directory intended for build") + + def get(self): + ds = self.Get('cl_builder_device_spool') + return ds.get() or "" + + def choice(self): + devices = self.Select( + 'install.os_disk_dev', + where='install.os_disk_mount', eq='') + devices = [x for x in devices if not isMount(x)] + return devices + + def check(self, value): + if not value: + raise VariableError( + _("You need to select a destination for build")) + if value.startswith("/dev"): + cnDisk = getUdevDeviceInfo(name=value).get('DEVNAME', value) + if cnDisk not in self.Get('install.os_disk_dev'): + raise VariableError(_("Wrong device '%s'") % value) + if not value.startswith('/'): + raise VariableError( + _("Wrong directory '%s'") % value) + if isMount(value): + raise VariableError( + _("Destination '%s' is already in use") % value) + + +class DiskFreeHelper(ReadonlyVariable): + """ + Переменные содержащие свободное место на дисках + """ + type = "int" + + def get_free_for(self, dn): + try: + dfdn = dn + while True: + dfProcess = process("/bin/df", "--output=avail", dfdn) + data = dfProcess.readlines() + if len(data) > 1: + return int(data[1].strip()) * 1024 + if dfdn == '/': + return 0 + dfdn = path.dirname(dfdn) + except ValueError: + return 0 + return 0 + + def humanReadable(self): + value = self.Get() + if not value: + value = "0" + return humanreadableSize(int(value)) + + +class VariableClBuilderDiskSize(DiskFreeHelper): + """ + + """ + def init(self): + self.label = _("Free disk space") + + @is_action(Actions.Prepare) + def get(self): + device = self.Get('cl_builder_disk_dev') + if device: + if device.startswith('/dev/'): + return self.Select('install.os_disk_size', + where='install.os_disk_dev', + eq=device, limit=1) or "0" + else: + return str(self.get_free_for(device)) + return "0" + +class VariableClBuilderPrepareFreeSize(DiskFreeHelper): + """ + Свободное место используемое для подготовки образа + """ + def init(self): + self.label = _("Free disk space for ISO building") + + @is_action(Actions.Image) + def get(self): + dn = self.Get('cl_builder_iso_base_path') + return str(self.get_free_for(dn)) + +class VariableClBuilderImageFreeSize(DiskFreeHelper): + """ + Свободное место на диске, где создается iso образ + """ + def init(self): + self.label = _("Free disk space for ISO image") + + @is_action(Actions.Image) + def get(self): + dn = self.Get('cl_builder_image_filename') + return str(self.get_free_for(dn)) + + +class VariableClBuilderLayeredSet(Variable): + """ + Сборка будет выполняться в слое + """ + type = "bool" + opt = ["--layers"] + kernel_opt = "CONFIG_OVERLAY_FS" + + def init(self): + self.help = _("use layers for build") + self.label = _("Use layers for build") + + def check_kernel_option(self): + """ + Проверить возможность ядра использовать overlay fs + """ + return ( + self.kernel_opt in self.Get('install.os_install_kernel_config')) + + def get(self): + try: + self.check_on() + return "on" + except VariableError: + return "off" + + def check_on(self): + if not self.check_kernel_option(): + raise VariableError( + _("You need kernel with %s for use layers")%self.kernel_opt) + if self.Get('cl_builder_disk_dev').startswith('/dev'): + raise VariableError( + _("Layers are used for building in a directory only")) + if isinstance(self.Get('cl_builder_source'), + distr.ArchiveDistributive): + raise VariableError( + _("Layers are used for building from ISO image")) + + def check(self, value): + if value == "on": + self.check_on() + + +class VariableClBuilderPath(ReadonlyVariable): + """ + Путь, где будет собираться дистрбутив + """ + def get(self): + image = self.Get('cl_builder_target') + if image: + return image.getDirectory() + return "" + + +class VariableClBuilderTarget(Variable): + """ + Объект собираемого дистрибутива + """ + type = "object" + + def get_create(self): + builder_disk_dev = self.Get('cl_builder_disk_dev') + if not builder_disk_dev: + return "" + build_id = self.Get('cl_builder_id') + build_id_path = self.Get('cl_builder_id_path') + mount_dir = path.join(distr.DefaultMountPath.BaseMountPath, + build_id_path) + source = self.Get('cl_builder_source_filename') + if self.GetBool('cl_builder_layered_set'): + dist_obj = distr.LayeredDistributive(mount_dir, builder_disk_dev, + source) + return dist_obj + else: + if builder_disk_dev.startswith('/dev'): + dist_obj = distr.PartitionDistributive(builder_disk_dev, + mdirectory=mount_dir) + return dist_obj + else: + dist_obj = distr.DirectoryDistributive(builder_disk_dev, + mdirectory=mount_dir) + return dist_obj + + def get_worked(self): + build = self.Get('cl_builder_build') + if build: + dist_obj = build.distributive + return dist_obj + return "" + + def get(self): + action = self.Get('cl_action') + if action in Actions.NewAssemble: + return self.get_create() + elif action in Actions.WorkAssemble: + return self.get_worked() + elif action in Actions.BrokenAssemble: + return self.get_worked() + else: + return "" + + +class VariableClBuilderClearSet(Variable): + """ + Очистить дистрибутив при отключении сборки + """ + type = "bool" + value = "on" + opt = ["--clear"] + + def init(self): + self.label = _("Clear after unmount") + self.help = _("clear data after unmount") + + +class VariableClBuilderBuild(Variable): + """ + Объект сборки + """ + type = "object" + + def get_create(self): + distr = self.Get('cl_builder_target') + if not distr: + return "" + storage = self.Get('cl_builder_storage') + buildid = self.Get('cl_builder_id') + build = Build(buildid, distr, storage) + return build + + def get_worked(self): + storage = self.Get('cl_builder_storage') + buildid = self.Get('cl_builder_id') + build = storage.get_build(buildid) + if build and build.distributive: + build.distributive.reserve() + for child in build.distributive.childs: + child.reserve() + return build or "" + + def get(self): + action = self.Get('cl_action') + if action in Actions.NewAssemble: + return self.get_create() + if action in Actions.WorkAssemble: + return self.get_worked() + elif action in Actions.BrokenAssemble: + return self.get_worked() + return "" + + +class VariableClBuilderNewId(BaseBuildId): + """ + Id сборки при развертывании + """ + value = "" + untrusted = True + + def get(self): + return self.Get('cl_builder_profile_name') + + def check(self, value): + if not value and self.Get('cl_builder_source_filename'): + raise VariableError(_("Please specify the id")) + if value and not re.match("^[A-Za-z][A-Za-z0-9/:_-]+$", value): + raise VariableError(_("Wrong symbols in build ID")) + if value in self.Get('cl_builder_storage'): + raise VariableError(_("Assemble %s already exists")%value) + + +class VariableClBuilderPreparedId(BaseBuildId): + """ + Id развёрнутой сборки + """ + type = "choice" + untrusted = True + + @as_list + def available(self): + bs = self.Get('cl_builder_storage') + action = self.Get('cl_action') + for x in bs: + build = bs.get_build(x) + if (build and (action == Actions.Break or + build.status == Build.Status.Worked)): + yield x + + def get(self): + l = self.available() + if l and len(l) == 1: + return l[0] + return "" + + @as_list + def choice(self): + bs = self.Get('cl_builder_storage') + for x in bs: + build = bs.get_build(x) + if build: + if build.status == Build.Status.Broken: + yield (x, "%s (%s)" % (x, _("broken"))) + else: + yield (x, x) + + def check(self, value): + if not value: + raise VariableError(_("Please select the assemble id")) + l = self.available() + if not l: + raise VariableError(_("Assemble %s is not found") % value) + if (self.Get('cl_builder_build').status == Build.Status.Broken and + self.Get('cl_action') != Actions.Break): + raise VariableError( + _("Assemble %s is broken, try to restore build") % value) + + +class VariableClBuilderBrokenId(BaseBuildId): + """ + Id развёрнутой сборки + """ + type = "choice" + untrusted = True + + @as_list + def available(self): + bs = self.Get('cl_builder_storage') + for x in bs: + build = bs.get_build(x) + if build and build.status == Build.Status.Broken: + yield x + + @is_action(Actions.Restore) + def get(self): + l = self.available() + if l and len(l) == 1: + return l[0] + return "" + + @as_list + @is_action(Actions.Restore, default_value=[]) + def choice(self): + bs = self.Get('cl_builder_storage') + for x in bs: + build = bs.get_build(x) + if build.status == Build.Status.Broken: + yield (x, "%s (%s)" % (x, _("broken"))) + + def check(self, value): + if not value: + raise VariableError(_("Please select the assemble id")) + l = self.available() + if not l: + raise VariableError(_("Assemble %s is not found") % value) + +class VariableClBuilderIdPath(ReadonlyVariable): + """ + Преобразование сборки id в имя походящее для путей + """ + def get(self): + build_id = self.Get('cl_builder_id') + if build_id: + return re.sub("[/:]", "_", self.Get('cl_builder_id')) + return "" + +class VariableClBuilderId(ReadonlyVariable): + """ + Общий id сборки + """ + def get(self): + action = self.Get('cl_action') + if action in Actions.NewAssemble: + return self.Get('cl_builder_new_id') + elif action in Actions.WorkAssemble: + return self.Get('cl_builder_prepared_id') + elif action in Actions.BrokenAssemble: + return self.Get('cl_builder_broken_id') + + +class VariableOsBuilderMakeopts(Variable): + """ + Параметры MAKEOPTS + """ + def get(self): + return self.Get('install.os_install_makeopts') + + +class VariableClBuilderBuildpkgSet(Variable): + """ + Собирать бинарные пакеты в сборке + """ + type = "bool" + value = "off" + + +class VariableClBuilderBasePath(Variable): + """ + Базовый путь до сборок (директория, куда будут помещены готовые + iso образы, бинарные пакеты и т.д.) + """ + value = "/var/calculate/remote/assemble" + + +class VariableClBuilderParentPath(ReadonlyVariable): + """ + Путь в ".." до родительской системы + """ + def get(self): + builder_path = self.Get('cl_builder_path') + return ("../"*len(filter(None, + builder_path.split('/'))))[:-1] + +class VariableClBuilderStageSet(ReadonlyVariable): + """ + Разворачиваемый образ является stage (Gentoo системой) + """ + type = "bool" + + def get(self): + return ("on" + if self.Get('os_builder_linux_shortname') == "Gentoo" + else "off") + +class VariableClBuilderPkgdir(Variable): + """ + Путь собираемых бинарных архивов + """ + def fallback(self): + return path.join(self.Get('cl_builder_base_path'), + self.Get('cl_builder_id_path'), "packages") + + def get(self): + action = self.Get('cl_action') + if action in Actions.NewAssemble: + return self.fallback() + elif action in Actions.WorkAssemble: + build = self.Get('cl_builder_build') + return build.pkgdir or self.fallback() + else: + return "" + + +class VariableClBuilderAction(ReadonlyVariable): + """ + Дополнительное действие по созданию образа: iso, squash. + """ + value = "" + + +class VariableClBuilderImageFilename(Variable): + """ + Название iso образа + """ + opt = ["--iso"] + value = "" + metavalue = "IMAGE" + untrusted = True + + def init(self): + self.label = _("Image path") + self.help = _("set image path") + + def check(self, value): + if not value: + raise VariableError(_("You must specify image filename")) + + def _isoname(self): + shortname = self.Get('os_builder_linux_shortname').lower() + buildnumber = self.Get('os_builder_linux_build') + arch = self.Get('os_builder_arch_machine') + return "%s-%s-%s.iso" % (shortname, buildnumber, + arch) + + def get(self): + if self.Get('os_root_type') != 'livecd': + base_dn = self.Get('cl_builder_base_path') + build_id = self.Get('cl_builder_id') + build_id_path = self.Get('cl_builder_id_path') + if build_id: + imagename = self._isoname() + return path.join(base_dn, build_id_path, "linux", imagename) + else: + build_id = self.Get('cl_builder_id') + base_dn = '/run/initramfs/live/iso' + if build_id: + imagename = self._isoname() + return path.join(base_dn, imagename) + return "" + + +class VariableClBuilderIsoBasePath(Variable): + """ + Базовый путь, где будут подготавливаться данные, которые будут запакованы в iso + """ + livecd_value = '/run/initramfs/live/tmp' + default_value = "/var/calculate/tmp" + + def get(self): + if self.Get('os_root_type') == 'livecd': + return self.livecd_value + return self.default_value + + +class VariableClBuilderIsoPath(ReadonlyVariable): + """ + Путь, где будут подготавливаться данные, которые будут запакованы в iso + """ + def get(self): + base_dn = self.Get('cl_builder_iso_base_path') + build_id = self.Get('cl_builder_id') + build_id_path = self.Get('cl_builder_id_path') + if build_id: + dn = "iso-%s" % build_id_path + directory = path.join(base_dn, dn) + new_dn = directory + for i in range(0, 9999): + if not path.exists(new_dn): + return new_dn + else: + new_dn = "%s.%04d" % (directory, i) + return new_dn + return "" + + +class VariableClBuilderSquashPath(ReadonlyVariable): + """ + Путь от iso до содержимого squash + """ + @is_action(Actions.Image) + def get(self): + return path.relpath(self.Get('cl_builder_path'), + self.Get('cl_builder_iso_path')) + + +class VariableClBuilderImage(ReadonlyVariable): + """ + Создаваемый образ + """ + @is_action(Actions.Image) + def get(self): + image_name = self.Get('cl_builder_image_filename') + bdn = self.Get('cl_builder_iso_path') + exclude_list = self.Get('cl_builder_squash_exclude') + iso = distr.IsoDistributive(image_name, bdirectory=bdn, + vol_id=self.Get('cl_builder_iso_label'), + exclude=exclude_list, + compress=self.Get('cl_builder_compress')) + return iso + + +class VariableClBuilderLiveSet(Variable): + """ + Вызывать только live шаблоны при первой загрузке + """ + type = "bool" + value = "on" + + +class VariableClBuilderCdname(ReadonlyVariable): + """ + Type of iso (CD/DVD) + """ + @is_action(Actions.Image) + def get(self): + squashfile = pathJoin(self.Get('cl_builder_iso_path'), + self.Get('cl_builder_current_squash')) + kernelfile = pathJoin(self.Get('cl_builder_iso_path'), + self.Get('cl_builder_squash_path'), + 'boot', + self.Get('cl_builder_kernel')) + initrdfile = pathJoin(self.Get('cl_builder_iso_path'), + self.Get('cl_builder_squash_path'), + 'boot', + self.Get('cl_builder_initrd_install')) + if os.access(squashfile, os.R_OK) and os.access(kernelfile, os.R_OK) and \ + os.access(initrdfile, os.R_OK): + isosize = path.getsize(squashfile) + path.getsize(kernelfile) + \ + path.getsize(initrdfile) + 2 * 1024 * 1024 + if isosize > 700 * 1024 * 1024: + return "DVD" + else: + return "CD" + return "" + + +class VariableClBuilderIsoLabel(Variable): + """ + LABEL для iso + """ + @is_action(Actions.Image) + def get(self): + return "%s-%s" % (self.Get('os_builder_linux_shortname').upper(), + self.Get('os_builder_linux_build')) + + +class VariableClBuilderRootParam(Variable): + """ + параметр root= для livecd + """ + + @is_action(Actions.Image) + def get(self): + return "live:LABEL=%s" % self.Get('cl_builder_iso_label') + + +class VariableClBuilderCurrentSquash(ReadonlyVariable): + """ + Создаваемый livecd.squash + """ + value = "livecd.squashfs" + + +class VariableClBuilderKernelCmd(ReadonlyVariable): + """ + Параметры по умолчанию для calcboot + """ + value = "" + +class KernelInfo(ReadonlyVariable): + def get_current_kernel_src(self, prefix): + src_path = "usr/src" + current_linux_src = path.join(src_path, "linux") + symlink_kernel = path.join(prefix, current_linux_src) + if not path.exists(symlink_kernel) or not path.islink(symlink_kernel): + raise ValueError("Failed to determine current kernel version") + return path.join(src_path, os.readlink(symlink_kernel)) + +class VariableClBuilderKernelConfig(KernelInfo): + """ + Конфиг ядра + """ + def get(self): + prefix = self.Get('cl_builder_path') + if prefix: + kernel_src = self.get_current_kernel_src(prefix) + config_path = path.join(kernel_src, ".config") + return KernelConfig(path.join(prefix, config_path)) + return "" + +class VariableClBuilderKernelVer(KernelInfo): + """ + Текущая версия ядра + """ + def init(self): + self.label = _("Kernel version") + + def get(self): + prefix = self.Get('cl_builder_path') + if prefix: + current_src = self.get_current_kernel_src(prefix) + src = path.join(prefix,current_src) + return self.get_src_kernel_version(src) + + def get_config_version(self, configfile): + re_config = re.compile("Automatically generated file;.*\n" + ".*?Linux/\S+\s+(\S+)\s", re.M) + if path.exists(configfile): + with open(configfile) as f: + match = re_config.search(f.read(200)) + if match: + return match.group(1) + + def get_src_kernel_version(self, kernel_src): + """ + Get version of kernel from .config + """ + config_path = path.join(kernel_src, ".config") + makefile_path = path.join(kernel_src, "Makefile") + + # get version from config + version = self.get_config_version(config_path) + if version: + return version + + # get version from Makefile + re_makefile = re.compile("^VERSION = (\S+)\n" + "PATCHLEVEL = (\S+)\n" + "SUBLEVEL = (\S+)\n" + "EXTRAVERSION = (\S*)\n", re.M) + if path.exists(makefile_path): + with open(makefile_path) as f: + match = re_makefile.search(f.read(200)) + if match: + return "{0}.{1}.{2}{3}".format(*match.groups()) + return "" + + +class KernelData(ReadonlyVariable): + """ + Данные о текущем ядре + """ + kernel_object = "kernel" + file_description = "" + + def filter(self, x, version=None): + return x + + def list(self, prefix='/', bootdir='boot'): + boot_dir = path.join(prefix, bootdir) + return self.get_files_by_type(boot_dir, self.file_description) + + def get(self): + prefix = self.Get('cl_builder_path') + version = self.Get('cl_builder_kernel_ver') + obj_file = max_default( + self.filter(self.list(prefix), version=version), + key=path.getmtime, + default="") + if obj_file: + obj_file = path.basename(obj_file) + return obj_file + + def get_files_by_type(self, pathname, descr): + ftype = typeFile(magic=0x4).getMType + for x in listDirectory(pathname, fullPath=True): + if descr in ftype(x): + yield x + + +class VariableClBuilderInitrdInstall(KernelData): + """ + Текущий initrd + """ + file_description = "ASCII cpio archive" + + def init(self): + self.label = _("Init RAM fs") + + def filter(self, iterable, version=None): + for fn in iterable: + if InitrdFile(fn).get_kernel_version() == version: + yield fn + + +class VariableClBuilderKernel(KernelData): + """ + Текущее ядро + """ + file_description = "boot executable bzImage" + + def init(self): + self.label = _("Kernel file") + + def filter(self, iterable, version=None): + ftype = typeFile(magic=0x4).getMType + re_kver = re.compile("bzImage, version (\S+)\s") + for fn in iterable: + m = re_kver.search(ftype(fn)) + if m.group(1) == version: + yield fn + + +class VariableClBuilderTemplateLocation(Variable): + """ + Устанавливаются только дистрибутивные шаблоны + """ + type = "list" + + def get(self): + return [x for x in self.Get('main.cl_template_location') + if x not in ('remote', 'local')] + + +class VariableClBuilderOutdateSet(ReadonlyVariable): + """ + Флаг устанавливаемый в ходе обновления репозиториев, + сообщающий что хотя бы один из запланированных репозиториев + обновлен и следует обновляет различные метаданные + + Если обновляются прочие оверлеи - данные считаются что устарели + """ + type = "bool" + + def get(self): + if (self.Get('update.cl_update_other_set') == 'on' and + self.Get('cl_builder_other_rep_name')): + return "on" + return "off" + + +class VariableClBuilderBranchData(TableVariable): + """ + Выбор веток репозиториев до которых необходимо обновиться + """ + opt = ["--branch"] + metavalue = 'BRANCHES' + untrusted = True + source = ["cl_builder_branch_rep", + "cl_builder_branch_name"] + + def init(self): + self.help = _("set branches for repository (REPOSITORY:BRANCH)") + self.label = _("Repositories branches") + + def raiseReadonlyIndexError(self, fieldname="", variablename="", value=""): + """ + Неизвестный оврелей + """ + raise VariableError(_("Repository %s not found") % value) + + +class VariableClBuilderBranchRep(ReadonlyVariable): + """ + Список доступных репозиториев + """ + type = "list" + + def init(self): + self.label = _("Repositories") + + def get(self): + dv = self.Get('cl_builder_linux_datavars') + if dv: + return dv.Get('cl_update_rep_name') + return [] + + +class VariableClBuilderBranchName(Variable): + """ + Список доступных репозиторием + """ + type = "choiceedit-list" + + def init(self): + self.label = _("Branches") + + def choice(self): + return ["master", "develop", "update", "binhost"] + + def get(self): + dv = self.Get('cl_builder_linux_datavars') + if dv: + if "getbinpkg" in self.Get('cl_features'): + return ["binhost" for x in dv.Get('cl_update_rep_name')] + else: + branch = self.Get('cl_update_branch') + return [branch for x in dv.Get('cl_update_rep_name')] + return [] + +class VariableClBuilderCompress(Variable): + """ + Тип сжатия образа squash + """ + type = "choice" + opt = ["-c", "--compress"] + metavalue = "COMPRESS" + untrusted = True + + def init(self): + self.label = _("Compressor") + self.help = _("set the compressor") + + def choice(self): + config_param_prefix = "CONFIG_SQUASHFS_%s" + kernel_config = self.Get('cl_builder_kernel_config') + params = {"xz": "XZ", + "lzma": "XZ", + "lzo": "LZO", + "gzip": "ZLIB"} + + def generator(): + for compress in getSquashList(): + if compress in params: + if config_param_prefix % params[compress] in kernel_config: + yield compress + + else: + yield compress + + weight = {'xz':2, 'gzip':1} + + return list(sorted(generator(), + key=lambda x: (-weight.get(x, 0), x))) + + def get(self): + values = self.choice() + if values: + return values[0] + return "" + +class VariableClBuilderIsohybridSet(Variable): + """ + Преобразовать полученный iso образ в гибридный + """ + type = "bool" + opt = ["--isohybrid"] + value = "on" + + def init(self): + self.help = _("create the ISO image with isohybrid") + self.label = _("ISO hybrid feature") + +class VariableClBuilderKeepTreeSet(Variable): + """ + Не удалять ебилды из портежей о оверлеев + """ + type = "bool" + opt = ["--keep-tree"] + value = "off" + + def init(self): + self.help = _("keep portage tree in image") + self.label = _("Keep portage tree") + +class VariableClBuilderSquashExclude(ReadonlyVariable): + """ + Список файлов, которые не будут запакованы в livecd.squashfs + """ + type = "list" + + def get(self): + builder_path = self.Get('cl_builder_path') + keep_tree = self.GetBool('cl_builder_keep_tree_set') + excludes = ["", "metadata", "profiles/templates/deprecated"] + important = [".git", "distfiles", "packages", "eclass", "metadata", + "profiles", "layout.conf"] + + def generator(): + for rep_dn in self.Get('cl_builder_repository_location'): + for exclude_dn in excludes: + dn = pathJoin(builder_path, rep_dn, exclude_dn) + for exclude_name in (x for x in listDirectory(dn) + if x not in important): + yield path.join(rep_dn, exclude_dn, exclude_name)[1:] + + if not keep_tree and builder_path: + return list(generator()) + return [] + +class VariableClBuilderPrelinkSet(Variable): + """ + Выполнять ли prelink + """ + type = "bool" + opt = ["--prelink"] + + def init(self): + self.help = _("perform prelink") + self.label = _("Perform prelink") + + def get(self): + return "on" if self.GetBool('cl_builder_binary_set') else "off" + +class VariableClBuilderRebuildChangedSet(Variable): + """ + Выполнять ли prelink + """ + type = "bool" + opt = ["--rebuild-changed-packages"] + value = "on" + + def init(self): + self.help = _("rebuild changed packages") + self.label = _("Rebuild changed packages") + diff --git a/pym/builder/wsdl_builder.py b/pym/builder/wsdl_builder.py index e261b1a..f0456a3 100644 --- a/pym/builder/wsdl_builder.py +++ b/pym/builder/wsdl_builder.py @@ -77,12 +77,12 @@ class Wsdl(WsdlBase): normal=('cl_builder_source_filename', # Место сборки # (Build location) - 'cl_builder_disk_dev', - # Использовать слои для сборки - # Use layers for build - 'cl_builder_layered_set'), + 'cl_builder_disk_dev',), # Идентификатор сборки (Build ID) - expert=('cl_builder_new_id', + expert=(# Использовать слои для сборки + # Use layers for build + 'cl_builder_layered_set', + 'cl_builder_new_id', 'cl_templates_locate', 'cl_verbose_set', 'cl_dispatch_conf'),