|
|
@ -19,74 +19,29 @@ import re |
|
|
|
import sys |
|
|
|
import time |
|
|
|
from os import path |
|
|
|
from subprocess import Popen |
|
|
|
from calculate.lib.utils.files import (process,getProgPath,STDOUT,removeDir, |
|
|
|
processProgress) |
|
|
|
processProgress,PercentProgress,process) |
|
|
|
|
|
|
|
class UpdateError(Exception): |
|
|
|
"""Update Error""" |
|
|
|
|
|
|
|
class GitError(Exception): |
|
|
|
"""Git Error""" |
|
|
|
class AddonError(Exception): |
|
|
|
""" |
|
|
|
Исключение с добавочным сообщением |
|
|
|
""" |
|
|
|
def __init__(self, msg, addon=None): |
|
|
|
self.message = msg |
|
|
|
self.addon = addon |
|
|
|
Exception.__init__(self,msg) |
|
|
|
|
|
|
|
class UpdateError(AddonError): |
|
|
|
"""Update Error""" |
|
|
|
|
|
|
|
class GitError(AddonError): |
|
|
|
"""Git Error""" |
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate |
|
|
|
setLocalTranslate('cl_update3',sys.modules[__name__]) |
|
|
|
__ = getLazyLocalTranslate(_) |
|
|
|
|
|
|
|
class PercentProgress(processProgress): |
|
|
|
""" |
|
|
|
Объект выдает прогресс, ища в выводе \d+% |
|
|
|
|
|
|
|
Args: |
|
|
|
part: количество прогрессов в программе |
|
|
|
delimeter: разделители строк по умолчанию \n и \r |
|
|
|
cachefilter: фильтр вывода программы (регулярная строка) |
|
|
|
startpart: используется для вывода процентов прогрессбар |
|
|
|
с определенного места (0 по умолчанию) |
|
|
|
end: конечный прогрессбар (по умолчанию) |
|
|
|
""" |
|
|
|
def init(self,*args,**kwargs): |
|
|
|
self.rePerc = re.compile("(\d+)%",re.S) |
|
|
|
self.part = kwargs.get("part",1) |
|
|
|
self.add_offset = 100 / self.part |
|
|
|
self.offset = 0 + kwargs.get("startpart",0)*self.add_offset |
|
|
|
self.is_end = kwargs.get("end",True) |
|
|
|
self.stderr = STDOUT |
|
|
|
self.delimeter = re.compile("[%s]"%kwargs.get("delimeter","\n\r")) |
|
|
|
self.cachedata = re.compile(kwargs.get("cachefilter", |
|
|
|
"((?:error|warning|fatal):.*)")) |
|
|
|
|
|
|
|
def processInit(self): |
|
|
|
self.percent = 0 |
|
|
|
self.showval = 0 |
|
|
|
if not self.offset: |
|
|
|
return 0 |
|
|
|
|
|
|
|
def processEnd(self): |
|
|
|
if self.is_end: |
|
|
|
self.percent = 100 |
|
|
|
return 100 |
|
|
|
|
|
|
|
def processString(self,strdata): |
|
|
|
match = self.rePerc.search(strdata) |
|
|
|
resSearch = self.cachedata.search(strdata) |
|
|
|
if resSearch: |
|
|
|
self.cacheresult.append(resSearch.group(1)) |
|
|
|
if match: |
|
|
|
percent = int(match.group(1)) |
|
|
|
if percent < self.percent: |
|
|
|
self.offset = self.offset + self.add_offset |
|
|
|
percent = percent / self.part |
|
|
|
if percent != self.percent: |
|
|
|
self.percent = percent |
|
|
|
showval = min(99,self.percent + self.offset) |
|
|
|
if showval != self.showval: |
|
|
|
self.showval = showval |
|
|
|
return self.showval |
|
|
|
|
|
|
|
class Git: |
|
|
|
""" |
|
|
|
Объект для управление git репозиторием |
|
|
@ -163,7 +118,10 @@ class Git: |
|
|
|
Return: |
|
|
|
Возвращает True если клонирование произведено с установкой на |
|
|
|
указанную ревизию. False если клонирование произведено с |
|
|
|
установкой на последнюю ревизию. В остальных случаях GitError |
|
|
|
установкой на последнюю ревизию. |
|
|
|
Raises: |
|
|
|
GitError: Выполнение ключевых команд выполнено с ошибками (не |
|
|
|
удалось скачать и получить данные из удаленного репозитория) |
|
|
|
""" |
|
|
|
git_dir = self.__gitDir(rpath) |
|
|
|
error = [] |
|
|
@ -357,10 +315,19 @@ class Git: |
|
|
|
to_origin: откатить все изменения до удаленного репозитория |
|
|
|
to_rev: откатить все изменения до определенной ревизии |
|
|
|
info: использовать уже полученную информация об изменения в репозитории |
|
|
|
Return: |
|
|
|
True - успешное выполнение |
|
|
|
False - нет необходимости выполнять reset |
|
|
|
Raises: |
|
|
|
GitError: выполнение комманд reset и clean прошло с ошибкой |
|
|
|
""" |
|
|
|
git_dir = self.__gitDir(rpath) |
|
|
|
if to_origin and not info: |
|
|
|
if not info: |
|
|
|
info = self._getStatusInfo(rpath) |
|
|
|
if (all(not info[x] for x in ("files","ahead","behind") if x in info) |
|
|
|
and (not info["origin"] or |
|
|
|
"origin/%s"%info["branch"] == info["origin"])): |
|
|
|
return False |
|
|
|
commit = (info['origin'] if to_origin else to_rev) or "HEAD" |
|
|
|
git_reset = process(self._git,"--git-dir",git_dir,"--work-tree",rpath, |
|
|
|
"reset","--hard", commit, stderr=STDOUT) |
|
|
@ -369,6 +336,7 @@ class Git: |
|
|
|
if git_reset.failed() or git_clean.failed(): |
|
|
|
raise GitError(_("Failed to clean {rpath} repository").format( |
|
|
|
rpath=rpath)) |
|
|
|
return True |
|
|
|
|
|
|
|
def _getBranch(self,rpath): |
|
|
|
""" |
|
|
@ -406,7 +374,9 @@ class Update: |
|
|
|
""" |
|
|
|
Синхронизировать репозиторий |
|
|
|
""" |
|
|
|
dv = self.clVars |
|
|
|
git = Git() |
|
|
|
needMeta = False |
|
|
|
if not git._checkExistsRep(rpath): |
|
|
|
if revision == "last": |
|
|
|
git._cloneRepository(url, rpath, branch, |
|
|
@ -414,6 +384,7 @@ class Update: |
|
|
|
else: |
|
|
|
git._cloneRevRepository(url, rpath, branch, revision, |
|
|
|
cb_progress=cb_progress) |
|
|
|
needMeta = True |
|
|
|
else: |
|
|
|
# если нужно обновиться до конкретной ревизии |
|
|
|
if revision != "last": |
|
|
@ -426,11 +397,16 @@ class Update: |
|
|
|
repInfo = git._getStatusInfo(rpath) |
|
|
|
if repInfo['branch'] != branch: |
|
|
|
# меняем ветку |
|
|
|
needMeta = True |
|
|
|
git._checkoutBranch(rpath,branch) |
|
|
|
if revision == "last": |
|
|
|
git._resetRepository(rpath, to_origin=True) |
|
|
|
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) |
|
|
|
return True |
|
|
|
|
|
|
|
def syncRepositories(self,repname,clean_on_error=True): |
|
|
@ -442,6 +418,8 @@ class Update: |
|
|
|
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: |
|
|
@ -453,7 +431,94 @@ class Update: |
|
|
|
self.printWARNING(str(e.addon)) |
|
|
|
self.printWARNING(str(e)) |
|
|
|
self.printWARNING(_("Re-fetch {name} repository" |
|
|
|
).format(name=name)) |
|
|
|
).format(name=repname)) |
|
|
|
removeDir(rpath) |
|
|
|
self._syncRepository(name,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 path.exists(path.join(rpath,'.git')): |
|
|
|
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 |