diff --git a/update/datavars.py b/update/datavars.py index ce1f5b3..fb0f660 100644 --- a/update/datavars.py +++ b/update/datavars.py @@ -13,7 +13,6 @@ # 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. - __app__ = 'calculate-update' __version__ = '3.1.8' @@ -32,3 +31,4 @@ class DataVarsUpdate(DataVars): self.importVariables() self.importVariables('calculate.update.variables') self.defaultModule = "update" + diff --git a/update/package_tools.py b/update/package_tools.py index 90dde33..e299ed6 100644 --- a/update/package_tools.py +++ b/update/package_tools.py @@ -17,6 +17,7 @@ from collections import Mapping, defaultdict import re import sys +from calculate.lib.cl_template import iniParser from calculate.lib.utils.colortext.palette import TextState from calculate.lib.utils.tools import AddonError, SavableIterator import time @@ -177,6 +178,10 @@ class Git: def is_git(gitpath): return path.isdir(Git._gitDir(gitpath)) + def get_url(self, rpath, remote_name): + ini_parser = iniParser(path.join(Git._gitDir(rpath), "config")) + return ini_parser.getVar(u'remote "%s"'%remote_name, "url") + def cloneRepository(self, url, rpath, branch, cb_progress=None): """ Сделать локальную копию репозитория diff --git a/update/profile.py b/update/profile.py new file mode 100644 index 0000000..524be5d --- /dev/null +++ b/update/profile.py @@ -0,0 +1,244 @@ +#-*- coding: utf-8 -*- + +# Copyright 2014 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 shutil +import os +from calculate.lib.utils.files import listDirectory, readFile, readLinesFile, \ + makeDirectory, removeDir +from package_tools import Git +from update import UpdateError + +from calculate.lib.cl_lang import setLocalTranslate, _ +setLocalTranslate('cl_update3', sys.modules[__name__]) + +DEFAULT_BRANCH = "master" + + +class RepositoryStorage(object): + directory = '/tmp' + + def __init__(self, directory): + self.directory = directory + makeDirectory(directory) + + def __iter__(self): + git = Git() + for dn in listDirectory(self.directory, onlyDir=True, fullPath=True): + if git.is_git(dn): + yield ProfileRepository(path.basename(dn), self) + + def get_profiles(self, url, branch=DEFAULT_BRANCH): + return [] + +class ProfileStorage(RepositoryStorage): + def get_profiles(self, url, branch=DEFAULT_BRANCH): + rep = self.get_repository(url, branch) + if rep: + return rep.get_profiles() + return None + + def get_repository(self, url, branch=DEFAULT_BRANCH): + return None + +class LocalStorage(ProfileStorage): + """ + Локальное хранилище репозиториев, при запросе по урлу смотрит, доступные + репозитории если находит подходящий - возвращает его профили + """ + def get_repository(self, url, branch=DEFAULT_BRANCH): + for rep in self: + if rep.is_like(url, branch): + return rep + + +class CacheStorage(ProfileStorage): + """ + Хранилище репозиториев, при запросе по урлу смотрит, доступные + репозитории если находит подходящий - возвращает его профили, + если не находит - скачивает и возвращает профили + """ + def get_repository(self, url, branch=DEFAULT_BRANCH): + for rep in self: + if rep.is_like(url, branch): + return rep + else: + return ProfileRepository.clone(url, self, branch) + +class RepositoryStorageSet(RepositoryStorage): + """ + Набор хранилищ репозиториев + """ + def __init__(self): + self.storages = [LocalStorage('/var/lib/layman'), + CacheStorage('/var/calculate/tmp/update')] + + def get_profiles(self, url, branch=DEFAULT_BRANCH): + """ + Получить профили из указанного репозитория + """ + for storage in self.storages: + profiles = storage.get_profiles(url, branch) + if profiles is not None: + return profiles + return None + + def __iter__(self): + for storage in self.storages: + for rep in storage: + yield rep + + def get_repository(self, url, branch=DEFAULT_BRANCH): + """ + Получить репозиторий по параметрам + """ + for rep in self: + if rep.is_like(url, branch): + return rep + return None + + def is_local(self, url, branch=DEFAULT_BRANCH): + """ + Проверить является ли репозиторий с указанными параметрами + локальным + """ + rep = self.get_repository(url, branch) + if rep and isinstance(rep.storage, LocalStorage): + return True + return False + + def __repr__(self): + return "Repository set" + +class Profile(object): + """ + Профиль репозитория + """ + available_arch = ["amd64", "x86"] + + def __init__(self, repository, profile, arch): + self.repository = repository + self.profile = profile + self.arch = arch + + @property + def path(self): + return path.join(self.repository.directory,"profiles", self.profile) + + @classmethod + def from_string(cls, repository, s): + parts = filter(None, s.split()) + if len(parts) == 3 and parts[0] in cls.available_arch: + return Profile(repository, parts[1], parts[0]) + return None + + def __repr__(self): + return "" % (self.arch, + self.repository.repo_name, + self.profile, + self.repository.directory) + + +class ProfileRepository(object): + """ + Репозиторий либо скачивается, либо берется из кэша + """ + def __init__(self, name, storage): + self._storage = storage + self.name = name + + @property + def storage(self): + return self._storage + + @storage.setter + def storage(self, storage): + if storage.directory != self._storage.directory: + newpath = path.join(storage.directory, self.name) + if self.directory == newpath: + return + try: + if path.exists(newpath): + removeDir(newpath) + shutil.move(self.directory, newpath) + self._storage = storage + except OSError as e: + raise UpdateError(_("Failed to move profile: %s") % + str(e)) + + @classmethod + def clone(cls, url, storage, branch=DEFAULT_BRANCH): + name = path.basename(url) + if name.endswith(".git"): + name = name[:-4] + git = Git() + rpath = path.join(storage.directory, name) + if path.exists(rpath): + removeDir(rpath) + git.cloneRepository(url, rpath, branch) + pr = cls(name, storage) + repo_name = pr.repo_name + if name != repo_name: + rpath_new = path.join(storage.directory, repo_name) + if not path.exists(rpath_new): + os.rename(rpath, rpath_new) + pr = cls(repo_name, storage) + return pr + + @property + def repo_name(self): + return readFile(path.join(self.directory, + "profiles/repo_name")).strip() + + def is_like(self, url, branch=DEFAULT_BRANCH): + if self.url == url and (branch is None or self.branch == branch): + return True + return False + + @property + def directory(self): + """ + Получить локальную директорию на данные репозитория + """ + return path.join(self.storage.directory, self.name) + + @property + def url(self): + git = Git() + return git.get_url(self.directory, "origin") + + @property + def branch(self): + git = Git() + return git.getBranch(self.directory) + + def sync(self): + """ + Синхронизировать репозиторий + """ + git = Git() + git.pullRepository(self.directory) + + def get_profiles(self): + """ + Получить список профилей репозитория + """ + profiles_desc = path.join(self.directory, "profiles/profiles.desc") + return filter(None, (Profile.from_string(self, line) + for line in readLinesFile(profiles_desc))) + + def __repr__(self): + return "" % (self.directory, self.url) diff --git a/update/update.py b/update/update.py index bf34d5e..42031ff 100644 --- a/update/update.py +++ b/update/update.py @@ -22,6 +22,7 @@ import os import time from calculate.core.server.gen_pid import search_worked_process, ProcessStatus from calculate.lib.cl_template import SystemIni +from calculate.lib.datavars import DataVarsError from calculate.lib.utils.tools import AddonError from calculate.lib.utils.colortext.palette import TextState @@ -37,12 +38,12 @@ Colors = TextState.Colors from calculate.lib.utils.files import (getProgPath, STDOUT, removeDir, PercentProgress, process, getRunCommands, readFile) -from calculate.lib.cl_lang import (setLocalTranslate, getLazyLocalTranslate, - RegexpLocalization, _) import emerge_parser import logging from emerge_parser import EmergeParser, EmergeCommand, EmergeError, EmergeCache +from calculate.lib.cl_lang import (setLocalTranslate, getLazyLocalTranslate, + RegexpLocalization, _) setLocalTranslate('cl_update3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) @@ -165,6 +166,10 @@ class Update: if not self._syncRepository(repname, url, rpath, revision, branch, cb_progress=self.setProgress): return "skip" + layman = Layman(dv.Get('cl_update_layman_installed'), + dv.Get('cl_update_layman_make')) + if repname != "portage": + layman.add(repname, url, rpath) return True except GitError as e: if e.addon: @@ -655,3 +660,49 @@ class Update: return decor + def migrateCacheRepository(self, url, branch): + rep_set = self.clVars.Get('cl_update_profile_storage') + rep = rep_set.get_repository(url, branch) + if rep: + rep.storage = rep_set.storages[0] + self.clVars.Invalidate('cl_update_profile_storage') + return True + + + def reconfigureProfileVars(self): + """ + Синхронизировать репозитории + """ + dv = self.clVars + + profile_dv = dv.Get('cl_update_profile_datavars') + try: + for var_name in ('cl_update_rep_rev', + 'cl_update_rep_path', + 'cl_update_rep_url', + 'cl_update_rep_name', + 'cl_update_branch_name', + 'cl_profile_system', + 'cl_update_layman_storage', + 'cl_update_rep'): + dv.Set(var_name, profile_dv.Get(var_name), force=True) + except DataVarsError: + raise UpdateError(_("Wrong profile")) + return True + + def setProfile(self): + profile = self.clVars.Select('cl_profile_path', + where='cl_profile_shortname', + eq=self.clVars.Get('cl_update_profile_system'), limit=1) + if not profile: + raise UpdateError(_("Failed to determine profile %s") % + self.clVars.Get('cl_update_profile_system')) + profile_path = path.relpath(profile, '/etc/portage') + try: + for rm_fn in filter(path.exists, + ('/etc/make.profile', '/etc/portage/make.profile')): + os.unlink(rm_fn) + os.symlink(profile_path, '/etc/portage/make.profile') + except (OSError,IOError) as e: + raise UpdateError(_("Failed to set profile: %s")%str(e)) + return True diff --git a/update/utils/cl_update_profile.py b/update/utils/cl_update_profile.py new file mode 100644 index 0000000..045b92c --- /dev/null +++ b/update/utils/cl_update_profile.py @@ -0,0 +1,110 @@ +#-*- coding: utf-8 -*- + +# Copyright 2010-2013 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 calculate.core.server.func import Action, Tasks +from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate +from calculate.lib.utils.files import FilesError +from calculate.update.update import UpdateError +from calculate.update.package_tools import GitError + +setLocalTranslate('cl_update3', sys.modules[__name__]) +__ = getLazyLocalTranslate(_) + + +class ClUpdateProfileAction(Action): + """ + Действие обновление конфигурационных файлов + """ + # ошибки, которые отображаются без подробностей + native_error = (FilesError, UpdateError, GitError) + + successMessage = __("Update profile successed") + failedMessage = __("Update profile failed") + interruptMessage = __("Update profile manually interrupted") + + + # список задач для дейсвия + tasks = [ + {'name': 'check_run', + 'method': 'Update.checkRun(cl_update_wait_another_set)'}, + {'name': 'migrate_repository', + 'method': 'Update.migrateCacheRepository(' + 'cl_update_profile_rep,cl_update_profile_branch)', + 'message': __("Repository transfer"), + 'condition': lambda Get: not ( + Get('cl_update_profile_storage').is_local( + Get('cl_update_profile_rep'), + Get('cl_update_profile_branch'))) + }, + {'name': 'reconfigure_vars', + 'method': 'Update.reconfigureProfileVars()' + }, + {'name': 'reps_synchronization', + 'group': __("Repositories synchronization"), + 'tasks': [ + {'name': 'sync_reps', + 'foreach': 'cl_update_profile_sync_rep', + 'message': __("Syncing the {eachvar:capitalize} repository"), + 'method': 'Update.syncRepositories(eachvar)', + #'condition': lambda Get: Get('cl_update_profile_sync_rep') + }, + {'name': 'sync_reps:regen_cache', + 'foreach': 'cl_update_sync_overlay_rep', + 'message': __("Updating the {eachvar:capitalize} repository cache"), + 'essential': False, + 'method': 'Update.regenCache(eachvar)', + 'condition': ( + lambda Get: (Get('cl_update_outdate_set') == 'on' and + Get('cl_update_metadata_force') != 'skip' or + Get('cl_update_metadata_force') == 'force')) + }, + {'name': 'emerge_metadata', + 'message': __("Metadata transfer"), + 'method': 'Update.emergeMetadata()', + 'condition': ( + lambda Get: (Get('cl_update_outdate_set') == 'on' and + Get('cl_update_metadata_force') != 'skip' or + Get('cl_update_metadata_force') == 'force')) + }, + {'name': 'eix_update', + 'message': __("Updating the eix cache"), + 'method': 'Update.eixUpdate()', + 'condition': ( + lambda Get: (Get('cl_update_outdate_set') == 'on' and + Get('cl_update_eixupdate_force') != 'skip' or + Get('cl_update_eixupdate_force') == 'force')) + }, + # сообщение удачного завершения при обновлении репозиториев + {'name': 'success_syncrep', + 'message': __("Synchronization finished"), + 'depend': (Tasks.success() & Tasks.has_any("sync_reps", + "sync_other_reps", + "emerge_metadata", + "eix_update")), + } + ] + }, + {'name': 'reps_synchronization', + 'group': __("Setting up profile"), + 'tasks': [ + {'name': 'set_profile', + 'message': __("Switching to {cl_update_profile_system} profile"), + 'method': 'Update.setProfile()' + }, + ] + } + ] diff --git a/update/variables/update.py b/update/variables/update.py index 3173c23..6ce3896 100644 --- a/update/variables/update.py +++ b/update/variables/update.py @@ -19,14 +19,20 @@ import sys import re from os import path from calculate.lib.datavars import (Variable, VariableError, - ReadonlyVariable, ReadonlyTableVariable, TableVariable, FieldValue) + ReadonlyVariable, ReadonlyTableVariable, TableVariable, FieldValue, + SimpleDataVars, DataVarsError) from calculate.lib.utils.portage import searchProfile from calculate.lib.utils.files import readLinesFile, readFile, makeDirectory, \ listDirectory from calculate.lib.cl_lang import setLocalTranslate -from calculate.update.emerge_parser import EmergeCache +from calculate.lib.utils.text import simplify_profiles from calculate.update.package_tools import Git, GitError, Layman +from calculate.update.profile import RepositoryStorageSet, DEFAULT_BRANCH + +from calculate.lib.variables.linux import VariableOsLinuxName, \ + VariableOsLinuxSubname, VariableOsLinuxVer + setLocalTranslate('cl_update3',sys.modules[__name__]) @@ -113,19 +119,6 @@ class VariableClUpdateRepUrl(Variable): type = "list" value = [] -class VariableClUpdateSystemProfile(ReadonlyVariable): - """ - Профиль системы (симлинк /etc/make.profile') - """ - def get(self): - try: - make_profile = self.Get('cl_make_profile') - return path.normpath( - path.join(path.dirname(make_profile), - os.readlink(make_profile))) - except: - raise VariableError(_("Failed to determine the system profile")) - class VariableClUpdateLaymanStorage(ReadonlyVariable): """ Путь к репозиториям layman @@ -165,7 +158,7 @@ class VariableClUpdateRepRev(Variable): def get(self): if self.Get('cl_update_rep') == 'rev': - revPaths = searchProfile(self.Get('cl_update_system_profile'), + revPaths = searchProfile(self.Get('cl_profile_system'), "rev") if revPaths: revPath = revPaths[-1] @@ -432,3 +425,435 @@ class VariableClUpdateWaitAnotherSet(Variable): def init(self): self.label = _("Wait for another update to be complete") self.help = _("wait until the running update is finished") + +class VariableClUpdateProfileStorage(ReadonlyVariable): + type = "object" + + def get(self): + return RepositoryStorageSet() + +class VariableClUpdateRepHost(Variable): + type = "list" + value = ['calculate'] + +class VariableClUpdateRepHostUrl(Variable): + type = "list" + value = ['git://git.calculate.ru/calculate/%s.git'] + + +class VariableClUpdateProfileDatavars(ReadonlyVariable): + type = "object" + + def get(self): + profile = self.Get('cl_update_profile_system') + path_profile = self.Select('cl_profile_path', + where='cl_profile_shortname', + eq=profile, limit=1) + if path_profile: + return DataVarsUpdateProfile(path_profile) + return "" + +class VariableClUpdateProfileLinuxFullname(ReadonlyVariable): + """ + Имя системы в профиле + """ + def init(self): + self.label = _("Profile system name") + + def get(self): + dv = self.Get('cl_update_profile_datavars') + if dv: + try: + subname = dv.Get('os_linux_subname') + linuxname = dv.Get('os_linux_name') + if subname: + return "%s %s" % (linuxname, subname) + return linuxname + except DataVarsError: + raise VariableError("Wrong Calculate Linux profile") + return "" + +class VariableClUpdateProfileDependData(ReadonlyTableVariable): + """ + Зависимые репозитории + """ + source = ['cl_update_profile_depend_name', + 'cl_update_profile_depend_url'] + + def init(self): + self.label = _("Used repositories") + + @staticmethod + def url_like(url1, url2): + match1 = VariableClUpdateProfileRep.re_url.search(url1) + match2 = VariableClUpdateProfileRep.re_url.search(url2) + if match1 and match2: + return match1.group(2).lower() == match2.group(2).lower() + return False + + + def get(self, hr=False): + dv = self.Get('cl_update_profile_datavars') + url = self.Get('cl_update_profile_rep').lower() + if dv: + return reversed(zip(dv.Get('cl_update_rep_name'), + dv.Get('cl_update_rep_url'))) + return "" + + setValue = Variable.setValue + +class VariableClUpdateProfileDependName(FieldValue, ReadonlyVariable): + type = "list" + source_variable = "cl_update_profile_depend_data" + column = 0 + + def init(self): + self.label = _("Name") + +class VariableClUpdateProfileDependUrl(FieldValue, ReadonlyVariable): + type = "list" + source_variable = "cl_update_profile_depend_data" + column = 1 + + def init(self): + self.label = _("URL") + + +class VariableClUpdateProfileRepName(ReadonlyVariable): + type = "list" + + def get(self): + dv = self.Get('cl_update_profile_datavars') + if dv: + return dv.Get('cl_update_rep_name') + return [] + +class VariableClUpdateProfileSyncRep(ReadonlyVariable): + type = "list" + + def get(self): + return list(reversed(self.Get('cl_update_profile_rep_name'))) + +class VariableClUpdateProfileRepUrl(ReadonlyVariable): + type = "list" + + def get(self): + dv = self.Get('cl_update_profile_datavars') + if dv: + return dv.Get('cl_update_rep_url') + return [] + +class VariableClUpdateProfileLinuxVer(ReadonlyVariable): + """ + Имя системы в профиле + """ + def init(self): + self.label = _("Profile system version") + + def get(self): + dv = self.Get('cl_update_profile_datavars') + if dv: + return dv.Get('os_linux_ver') + return "" + +class VariableClUpdateProfileLinuxName(ReadonlyVariable): + """ + Имя системы в профиле + """ + def get(self): + dv = self.Get('cl_update_profile_datavars') + if dv: + dv.Get('os_linux_name') + return "" + +class VariableClUpdateProfileRep(Variable): + """ + Текущий репозиторий + """ + untrusted = True + check_after = "cl_update_profile_branch" + + opt = ["--url"] + + def init(self): + self.label = _("Profile repository") + self.help = _("set profile repository") + + re_url = re.compile( + r"^(?:(%s)://)?(\w[\w\./:-]+?\w)(\.git)?$" % "|".join( + ["http", "https", "git"])) + + re_shortname = re.compile('^(?:([\w\.-]+):)?([\w\.-]+)$') + + @classmethod + def normalize_url(cls, url): + match = cls.re_url.match(url) + if not match: + raise VariableError(_("Failed repository url")) + url = match.group(2) + url = "%s://%s" % (match.group(1) or "git", url) + url = "%s.git" % url + return url + + def url_by_shortname(self, value): + match = self.re_shortname.match(value) + if not match.group(1): + template = self.Get('cl_update_rep_host_url') + if template: + template = template[0] + else: + template = self.Select('cl_update_rep_host_url', + where='cl_update_rep_host', + eq=match.group(1), limit=1) + if not template: + raise VariableError(_("Failed to determine repository host")) + + try: + return template % match.group(2) + except TypeError: + raise VariableError(_("Failed to determine repository host")) + + def set(self, value): + if self.re_shortname.match(value): + value = self.url_by_shortname(value) + return self.normalize_url(value) + + def check(self, value): + if not value: + raise VariableError("Need to specify profile repository") + try: + branch = self.Get('cl_update_profile_branch') + self.Get('cl_update_profile_storage').get_profiles(value, branch) + except GitError as e: + raise VariableError(str(e)) + if not self.Get('cl_profile_shortname'): + raise VariableError(_("Repository %s has not profiles")%value) + + def get(self): + try: + profile = self.Get('cl_profile_system') + while profile != '/' and ".git" not in listDirectory(profile): + profile = path.dirname(profile) + if profile == '/': + return "" + git = Git() + return git.get_url(profile, "origin") or "" + except: + return "git://git.calculate.ru/calculate/distros.git" + +class VariableClUpdateProfileRepoName(ReadonlyVariable): + def init(self): + self.label = _("Repository name") + + def get(self): + rep_set = self.Get('cl_update_profile_storage') + url = self.Get('cl_update_profile_rep') + rep = rep_set.get_repository(url) + if rep: + return rep.repo_name + return "" + + +class VariableClUpdateProfileBranch(Variable): + """ + Текущий репозиторий + """ + untrusted = True + + type = "edit" + opt = ["--branch"] + + def init(self): + self.label = _("Repository branch") + self.help = _("set repository branch") + + def check(self, value): + pass + ## TODO: проверка ветки + #try: + # url = self.Get('cl_update_profile_rep') + # self.Get('cl_update_profile_storage').get_profiles(url, value) + #except GitError as e: +# raise VariableError(str(e)) + + def get(self): + rep_set = self.Get('cl_update_profile_storage') + url = self.Get('cl_update_profile_rep') + #print url, rep_set.is_local(url, branch=None) + if rep_set.is_local(url, branch=None): + rep = rep_set.get_repository(url, branch=None) + git = Git() + return git.getBranch(rep.directory) + return DEFAULT_BRANCH + + +class VariableClProfileSystem(ReadonlyVariable): + """ + Профиль системы (симлинк /etc/make.profile') + """ + def get(self): + try: + make_profile = self.Get('cl_make_profile') + return path.normpath( + path.join(path.dirname(make_profile), + os.readlink(make_profile))) + except: + raise VariableError(_("Failed to determine the system profile")) + + +class VariableClProfileData(ReadonlyTableVariable): + source = ["cl_profile_fullname", + "cl_profile_shortname", + "cl_profile_path", + "cl_profile_arch"] + + def get(self, hr=False): + url = self.Get('cl_update_profile_rep') + if not url: + return [[]] + try: + rep_set = self.Get('cl_update_profile_storage') + branch = self.Get('cl_update_profile_branch') + profiles = rep_set.get_profiles(url, branch) + rep = rep_set.get_repository(url, branch) + except GitError: + return [[]] + arch = self.Get('os_arch_machine_gentoo') + if profiles: + repo_name = profiles[0].repository.repo_name + arch_profiles = [x for x in profiles if x.arch == arch] + full_name = [x.profile for x in arch_profiles] + profile_path = [x.path for x in arch_profiles] + profile_arch = [x.arch for x in arch_profiles] + short_name = simplify_profiles(full_name) + full_name = ["%s:%s"%(repo_name,x) for x in full_name] + return zip(full_name, + short_name, + profile_path, + profile_arch) + return [[]] + + setValue = Variable.setValue + + +class VariableClProfileFullname(FieldValue, ReadonlyVariable): + """ + Полное название профиля + """ + type = "list" + source_variable = "cl_profile_data" + column = 0 + +class VariableClProfileShortname(FieldValue, ReadonlyVariable): + """ + Упрощенное название профиля + """ + type = "list" + source_variable = "cl_profile_data" + column = 1 + +class VariableClProfilePath(FieldValue, ReadonlyVariable): + """ + Путь от корня до профиля + """ + type = "list" + source_variable = "cl_profile_data" + column = 2 + +class VariableClProfileArch(FieldValue, ReadonlyVariable): + """ + Архитектура профиля + """ + type = "list" + source_variable = "cl_profile_data" + column = 3 + +class VariableClUpdateProfileSystem(Variable): + """ + Профиль системы (симлинк /etc/make.profile') + """ + type = "choice" + opt = ["cl_update_profile_system"] + untrusted = True + metavalue = "PROFILE" + + def init(self): + self.label = _("System profile") + self.help = _("set system profile") + + def check(self, profile): + if not profile: + raise VariableError(_("Profile must be specified")) + path_profile = self.Select('cl_profile_path', + where='cl_profile_shortname', + eq=profile, limit=1) + if path_profile: + dv = DataVarsUpdateProfile(path_profile) + try: + if (not dv.Get('cl_update_rep_name') or + not dv.Get('cl_update_rep_url')): + raise VariableError(_("Repository variables is not " + "configured in profile")) + if not dv.Get('os_linux_name'): + raise VariableError() + except (DataVarsError, VariableError) as e: + raise VariableError(_("Profile is not Calculate")) + else: + raise VariableError(_("Wrong Calculate profile")) + + def get(self): + try: + profile_system = self.Get('cl_profile_system') + profile = self.Select('cl_profile_shortname', + where='cl_profile_path', + eq=profile_system, limit=1) + if profile: + return profile + except VariableError: + pass + shortname = self.Get('cl_profile_shortname') + if len(shortname) == 1: + return shortname[0] + return "" + + def choice(self): + url = self.Get('cl_update_profile_rep') + if not url: + return [] + arch = self.Get('os_arch_machine_gentoo') + profiles = zip(*self.Select(['cl_profile_shortname', + 'cl_profile_fullname'], + where='cl_profile_arch', eq=arch)) + if profiles: + short_name, full_name = profiles + return zip(short_name, full_name) + return [] + +class DataVarsUpdateProfile(SimpleDataVars): + """ + Упрощенная модель переменных для получения данных с удаленного профиля + """ + source = ['cl_update_rep_name', + 'cl_update_rep_url', + 'cl_update_rep_path', + 'cl_update_rep_rev', + 'cl_update_branch_name'] + def __init__(self, profile): + SimpleDataVars.__init__(self, + VariableOsLinuxName(), + VariableOsLinuxSubname(), + VariableOsLinuxVer(), + VariableClUpdateRepData(section="update"), + VariableClUpdateRepPath(section="update"), + VariableClUpdateRepRev(section="update"), + VariableClUpdateBranchName(section="update"), + VariableClProfileSystem(section="update"), + VariableClUpdateLaymanStorage(section="update"), + VariableClUpdateRepName(section="update"), + VariableClUpdateRep(section="update"), + VariableClUpdateRepUrl(section="update")) + self.cache['cl_profile_system'] = profile + self.flIniFileFrom(profile) + + def __repr__(self): + return "Profile variables" diff --git a/update/wsdl_update.py b/update/wsdl_update.py index 9bd535e..9563c11 100644 --- a/update/wsdl_update.py +++ b/update/wsdl_update.py @@ -23,6 +23,7 @@ from calculate.install.install import InstallError from calculate.update.update import Update,UpdateError from calculate.update.package_tools import GitError from utils.cl_update import ClUpdateAction +from utils.cl_update_profile import ClUpdateProfileAction from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate setLocalTranslate('cl_update3',sys.modules[__name__]) __ = getLazyLocalTranslate(_) @@ -74,4 +75,49 @@ class Wsdl(WsdlBase): 'cl_templates_locate', 'cl_verbose_set', 'cl_dispatch_conf'), next_label=_("Update"))]}, + # + # Сменить профиль + # + { + # идентификатор метода + 'method_name': "update_profile", + # категория метода + 'category': __('Update'), + # заголовок метода + 'title': __("Update the Profile"), + # иконка для графической консоли + 'image': 'preferences-system', + # метод присутствует в графической консоли + 'gui': True, + # консольная команда + 'command': 'cl-update-profile', + # права для запуска метода + 'rights': ['change_profile'], + # объект содержащий модули для действия + 'logic': {'Update': Update}, + # описание действия + 'action': ClUpdateProfileAction, + # объект переменных + 'datavars': "update", + 'native_error': (VariableError, DataVarsError, + InstallError, UpdateError, GitError), + # значения по умолчанию для переменных этого метода + 'setvars': {'cl_action!': 'update_profile'}, + # описание груп (список лямбда функций) + 'groups': [ + lambda group: group(_("Repository"), + brief=('cl_update_profile_repo_name', + 'cl_update_profile_branch'), + hide=("cl_update_profile_rep",), + normal=('cl_update_profile_rep',), + expert=('cl_update_profile_branch',)), + lambda group: group(_("Profile"), + normal=('cl_update_profile_system',), + brief=('cl_update_profile_system', + 'cl_update_profile_linux_fullname', + 'cl_update_profile_linux_ver', + 'cl_update_profile_depend_data') + )], + 'brief': {'next': __("Perform"), + 'name': __("Set profile")}}, ]