You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-update/update/update.py

262 lines
11 KiB

#-*- 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
from calculate.lib.utils.tools import AddonError
from calculate.lib.utils.colortext.palette import TextState
from calculate.lib.utils.colortext import get_color_print
from package_tools import Git, Layman, EmergeError, Emerge
Colors = TextState.Colors
from calculate.lib.utils.files import (getProgPath, STDOUT, removeDir,
PercentProgress, process, readFile)
from calculate.lib.utils.colortext import convert_console_to_xml
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
setLocalTranslate('cl_update3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class UpdateError(AddonError):
"""Update Error"""
class Update:
"""Основной объект для выполнения действий связанных с обновлением системы
"""
def _syncRepository(self, name, url, rpath, revision, branch,
cb_progress=None):
"""
Синхронизировать репозитори
"""
dv = self.clVars
git = Git()
needMeta = False
if not git.checkExistsRep(rpath):
if revision == "last":
git.cloneRepository(url, rpath, branch,
cb_progress=cb_progress)
else:
git.cloneRevRepository(url, rpath, branch, revision,
cb_progress=cb_progress)
needMeta = True
else:
# если нужно обновиться до конкретной ревизии
if revision != "last":
if revision == git.getCurrentCommit(rpath):
if git.getBranch(rpath) == branch:
return True
# получить изменения из удаленного репозитория
git.fetchRepository(rpath, cb_progress=cb_progress)
# если текущая ветка не соответствует нужной
repInfo = git.getStatusInfo(rpath)
if repInfo['branch'] != branch:
# меняем ветку
needMeta = True
git.checkoutBranch(rpath, branch)
if revision == "last":
if git.resetRepository(rpath, to_origin=True):
needMeta = True
else:
git.resetRepository(rpath, to_rev=revision)
needMeta = True
if needMeta:
dv.Set('cl_update_outdate_set', 'on', force=True)
layman = Layman(dv.Get('cl_update_layman_installed'),
dv.Get('cl_update_layman_make'))
if name != "portage":
layman.add(name, url, rpath)
return True
def syncRepositories(self, repname, clean_on_error=True):
"""
Синхронизировать репозитории
"""
dv = self.clVars
url, rpath, revision, branch = (
dv.Select(["cl_update_rep_url", "cl_update_rep_path",
"cl_update_rep_rev", "cl_update_branch_name"],
where="cl_update_rep_name", eq=repname, limit=1))
if not url or not rpath:
raise UpdateError(_("Repositories variables is not configured"))
self.addProgress()
if clean_on_error:
try:
self._syncRepository(repname, url, rpath, revision, branch,
cb_progress=self.setProgress)
return True
except GitError as e:
if e.addon:
self.printWARNING(str(e.addon))
self.printWARNING(str(e))
self.printWARNING(_("Re-fetch {name} repository"
).format(name=repname))
try:
removeDir(rpath)
except OSError as e:
raise UpdateError(_("Permission denied to change "
"{repname} repository").format(
repname=repname))
self._syncRepository(repname, url, rpath, revision, branch)
return True
def syncLaymanRepository(self, repname):
"""
Обновить репозиторий через layman
"""
layman = getProgPath('/usr/bin/layman')
if not layman:
raise UpdateError(_("Layman utility is not found"))
rpath = self.clVars.Select('cl_update_other_rep_path',
where='cl_update_other_rep_name', eq=repname,
limit=1)
laymanname = path.basename(rpath)
if Git.is_git(rpath):
self.addProgress()
p = PercentProgress(layman, "-s", laymanname, part=1, atty=True)
for perc in p.progress():
self.setProgress(perc)
else:
p = process(layman, "-s", repname, stderr=STDOUT)
if p.failed():
raise UpdateError(_("Failed to update repository {rname}"
).format(rname=repname), addon=p.read())
return True
def regenCache(self, repname):
"""
Обновить кэш метаданных репозитория
"""
egenCache = getProgPath('/usr/bin/egencache')
if not egenCache:
raise UpdateError(_("Portage utility is not found"))
cpu_num = self.clVars.Get('hr_cpu_num')
p = process(egenCache, "--repo=%s" % repname, "--update",
"--jobs=%s" % cpu_num, stderr=STDOUT)
if p.failed():
raise UpdateError(_("Failed to update cache of {rname} "
"repository").format(rname=repname),
addon=p.read())
return True
def emergeMetadata(self):
"""
Выполнить egencache и emerge --metadata
"""
emerge = getProgPath("/usr/bin/emerge")
if not emerge:
raise UpdateError(_("Emerge utility is not found"))
self.addProgress()
p = PercentProgress(emerge, "--metadata", part=1, atty=True)
for perc in p.progress():
self.setProgress(perc)
if p.failed():
raise UpdateError(_("Failed to update metadata"), addon=p.read())
return True
def eixUpdate(self):
"""
Выполенине eix-update для репозиторием
eix-update выполнятется только для тех репозиториев, которые
обновлялись, если cl_update_eixsync_force==auto, либо
все, если cl_update_eixupdate_force==force
"""
eixupdate = getProgPath("/usr/bin/eix-update")
if not eixupdate:
raise UpdateError(_("Eix utility is not found"))
self.addProgress()
excludeList = []
if self.clVars.Get('cl_update_eixupdate_force') == 'force':
countRep = len(self.clVars.Get('cl_update_rep_name'))
else:
for rep in self.clVars.Get('cl_update_rep_name'):
# подстановка имен
mapNames = {'portage': 'gentoo'}
if not rep in self.clVars.Get('cl_update_sync_rep'):
excludeList.extend(["-x", mapNames.get(rep, rep)])
countRep = len(self.clVars.Get('cl_update_sync_rep'))
if (self.clVars.Get('cl_update_other_set') == 'on' or
self.clVars.Get('cl_update_eixupdate_force') == 'force'):
countRep += len(self.clVars.Get('update.cl_update_other_rep_name'))
else:
for rep in self.clVars.Get('update.cl_update_other_rep_name'):
excludeList.extend(['-x', rep])
p = PercentProgress(eixupdate, "-F", *excludeList, part=countRep or 1,
atty=True)
for perc in p.progress():
self.setProgress(perc)
if p.failed():
raise UpdateError(_("Failed to update eix cache"), addon=p.read())
return True
def _printEmergePackage(self, pkg, binary=False, num=1, max_num=1):
self.endTask()
_print = get_color_print()
if max_num > 1:
one = _print.foreground(Colors.YELLOW).bold("{0}", num)
two = _print.foreground(Colors.YELLOW).bold("{0}", max_num)
part = " (%s of %s)" % (one, two)
else:
part = ""
if binary:
_print = _print.foreground(Colors.PURPLE)
else:
_print = _print.foreground(Colors.GREEN)
self.startTask("Emerging%s %s" % (part, _print(str(pkg))))
def _printInstallPackage(self, pkg):
self.endTask()
_print = get_color_print()
self.startTask(_("Installing %s")%
_print.foreground(Colors.YELLOW).bold(str(pkg)))
def emerge(self, param, *packages):
"""
Выполнить сборку пакета
"""
with Emerge(list(packages), extra_params=[param]) as emerge:
try:
update_list = emerge.get_update_list()
if not update_list:
self.printSUCCESS(_("Nothing to merge"))
return True
self.printPre(update_list)
except EmergeError as e:
if e.errno == EmergeError.CONFLICT:
self.printPre(emerge.update_block)
self.printPre(emerge.conflict_block)
elif e.errno == EmergeError.CUSTOM:
self.printPre(emerge.custom_error)
raise
if (self.askConfirm(
_("Would you like to merge these packages?")) == 'no'):
return False
emerge.handle_emerging(self._printEmergePackage)
emerge.handle_installing(self._printInstallPackage)
try:
return emerge.install()
except EmergeError:
self.printPre(
convert_console_to_xml(readFile(emerge.get_error_log())))
raise