7 changed files with 900 additions and 19 deletions
-
2update/datavars.py
-
5update/package_tools.py
-
244update/profile.py
-
55update/update.py
-
110update/utils/cl_update_profile.py
-
457update/variables/update.py
-
46update/wsdl_update.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 "<Profile (%s) %s:%s from %s>" % (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 "<ProfileRepository %s url=%s>" % (self.directory, self.url) |
@ -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()' |
|||
}, |
|||
] |
|||
} |
|||
] |
Write
Preview
Loading…
Cancel
Save
Reference in new issue