|
|
|
@ -14,515 +14,109 @@
|
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
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,PercentProgress,process,readFile)
|
|
|
|
|
|
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
|
|
|
|
|
setLocalTranslate('cl_update3',sys.modules[__name__])
|
|
|
|
|
__ = getLazyLocalTranslate(_)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
class AddonError(Exception):
|
|
|
|
|
"""
|
|
|
|
|
Исключение с добавочным сообщением
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, msg, addon=None):
|
|
|
|
|
self.message = msg
|
|
|
|
|
self.addon = addon
|
|
|
|
|
Exception.__init__(self,msg)
|
|
|
|
|
setLocalTranslate('cl_update3', sys.modules[__name__])
|
|
|
|
|
__ = getLazyLocalTranslate(_)
|
|
|
|
|
|
|
|
|
|
class UpdateError(AddonError):
|
|
|
|
|
"""Update Error"""
|
|
|
|
|
|
|
|
|
|
class GitError(AddonError):
|
|
|
|
|
"""Git Error"""
|
|
|
|
|
|
|
|
|
|
class Layman:
|
|
|
|
|
"""
|
|
|
|
|
Объект для управления репозиториями Layman
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
installed: путь до installed.xml
|
|
|
|
|
makeconf: путь до makeconf
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self,installed,makeconf):
|
|
|
|
|
self.installed = installed
|
|
|
|
|
self.makeconf = makeconf
|
|
|
|
|
|
|
|
|
|
def _add_to_installed(self,rname,rurl):
|
|
|
|
|
"""
|
|
|
|
|
Добавить репозиторий в installed.xml
|
|
|
|
|
"""
|
|
|
|
|
if path.exists(self.installed) and readFile(self.installed).strip():
|
|
|
|
|
tree = ET.parse(self.installed)
|
|
|
|
|
root = tree.getroot()
|
|
|
|
|
# если репозиторий уже присутсвует в installed.xml
|
|
|
|
|
if root.find("repo[name='%s']"%rname) is not None:
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
root = ET.Element("repositories",version="1.0")
|
|
|
|
|
tree = ET.ElementTree(root)
|
|
|
|
|
|
|
|
|
|
newrepo = ET.SubElement(root,"repo",priority="50",
|
|
|
|
|
quality="experimental",
|
|
|
|
|
status="unofficial")
|
|
|
|
|
name = ET.SubElement(newrepo,"name")
|
|
|
|
|
name.text = rname
|
|
|
|
|
source = ET.SubElement(newrepo,"source",type="git")
|
|
|
|
|
source.text = rurl
|
|
|
|
|
try:
|
|
|
|
|
from layman.utils import indent
|
|
|
|
|
indent(root)
|
|
|
|
|
except ImportError as e:
|
|
|
|
|
pass
|
|
|
|
|
with open(self.installed,'w') as f:
|
|
|
|
|
f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
|
|
|
|
tree.write(f, encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
def _add_to_makeconf(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Добавить репозиторий в layman/make.conf
|
|
|
|
|
"""
|
|
|
|
|
def fixContent(match):
|
|
|
|
|
repos = match.group(1).strip().split('\n')
|
|
|
|
|
if not rpath in repos:
|
|
|
|
|
repos.insert(0,rpath)
|
|
|
|
|
return 'PORTDIR_OVERLAY="\n%s"'%"\n".join(repos);
|
|
|
|
|
if path.exists(self.makeconf):
|
|
|
|
|
content = readFile(self.makeconf)
|
|
|
|
|
if "PORTDIR_OVERLAY" in content:
|
|
|
|
|
new_content = re.sub("\APORTDIR_OVERLAY=\"([^\"]+)\"",
|
|
|
|
|
fixContent, content,re.DOTALL)
|
|
|
|
|
if new_content == content:
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
content = new_content
|
|
|
|
|
else:
|
|
|
|
|
content = 'PORTDIR_OVERLAY="\n%s"\n'%rpath + content
|
|
|
|
|
else:
|
|
|
|
|
content = 'PORTDIR_OVERLAY="\n%s"\n'%rpath
|
|
|
|
|
with open(self.makeconf,'w') as f:
|
|
|
|
|
f.write(content)
|
|
|
|
|
|
|
|
|
|
def add(self,rname,rurl,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Добавить репозиторий в installed.xml и layman/make.conf
|
|
|
|
|
"""
|
|
|
|
|
self._add_to_installed(rname,rurl)
|
|
|
|
|
self._add_to_makeconf(rpath)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
class Git:
|
|
|
|
|
"""
|
|
|
|
|
Объект для управление git репозиторием
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self._git = self.__getGit()
|
|
|
|
|
|
|
|
|
|
def _checkExistsRep(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Проверить путь на наличие репозитория
|
|
|
|
|
"""
|
|
|
|
|
if path.exists(rpath):
|
|
|
|
|
if not path.isdir(rpath):
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Repository {path} is not directory").format(
|
|
|
|
|
path=rpath))
|
|
|
|
|
if not path.isdir(self.__gitDir(rpath)):
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Repository {path} is not git").format(
|
|
|
|
|
path=rpath))
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def __getGit(self):
|
|
|
|
|
"""
|
|
|
|
|
Получить утилиту git
|
|
|
|
|
"""
|
|
|
|
|
git = getProgPath("/usr/bin/git")
|
|
|
|
|
if not git:
|
|
|
|
|
raise GitError(_("Git utility is not found"))
|
|
|
|
|
return git
|
|
|
|
|
|
|
|
|
|
def __gitDir(self,rpath):
|
|
|
|
|
return path.join(rpath,".git")
|
|
|
|
|
|
|
|
|
|
def _cloneRepository(self, url, rpath, branch, cb_progress=None):
|
|
|
|
|
"""
|
|
|
|
|
Сделать локальную копию репозитория
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
url: откуда качать репозиторий
|
|
|
|
|
rpath: куда сохранять репозиторий
|
|
|
|
|
branch: ветка на которую необходимо переключиться
|
|
|
|
|
"""
|
|
|
|
|
if cb_progress:
|
|
|
|
|
gitClone = PercentProgress(self._git,"clone","-q",
|
|
|
|
|
"--no-single-branch","--progress","--verbose",
|
|
|
|
|
"--depth=1","-b",branch,url,rpath,part=4,stderr=STDOUT)
|
|
|
|
|
for perc in gitClone.progress():
|
|
|
|
|
cb_progress(perc)
|
|
|
|
|
else:
|
|
|
|
|
gitClone = process(self._git,"clone","-q","--no-single-branch",
|
|
|
|
|
"--depth=1","-b",branch,url,rpath,stderr=STDOUT)
|
|
|
|
|
if gitClone.failed():
|
|
|
|
|
error = gitClone.read()
|
|
|
|
|
if "Remote branch %s not found"%branch in error:
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Branch {branch} not found in {url} repository").format(
|
|
|
|
|
branch=branch,url=url))
|
|
|
|
|
raise GitError(_("Failed to clone {url} repository").format(
|
|
|
|
|
url=url),error)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _cloneRevRepository(self, url, rpath, branch,revision,cb_progress=None):
|
|
|
|
|
"""
|
|
|
|
|
Сделать локальную копию репозитория с указанной ревизией
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
url: откуда качать репозиторий
|
|
|
|
|
rpath: куда сохранять репозиторий
|
|
|
|
|
branch: ветка на которую необходимо переключиться
|
|
|
|
|
revision: если указана - сделать ревизию текущей
|
|
|
|
|
|
|
|
|
|
Return:
|
|
|
|
|
Возвращает True если клонирование произведено с установкой на
|
|
|
|
|
указанную ревизию. False если клонирование произведено с
|
|
|
|
|
установкой на последнюю ревизию.
|
|
|
|
|
Raises:
|
|
|
|
|
GitError: Выполнение ключевых команд выполнено с ошибками (не
|
|
|
|
|
удалось скачать и получить данные из удаленного репозитория)
|
|
|
|
|
"""
|
|
|
|
|
git_dir = self.__gitDir(rpath)
|
|
|
|
|
error = []
|
|
|
|
|
|
|
|
|
|
def command(cmd,startpart=0):
|
|
|
|
|
"""
|
|
|
|
|
Выполнить одну из команд необходимой для клонирования репозитория
|
|
|
|
|
"""
|
|
|
|
|
commands = {# инициализация пустого репозитория
|
|
|
|
|
'init': ["init",rpath],
|
|
|
|
|
# подключить указанный удаленный как origin
|
|
|
|
|
'add_remote':["remote","add","origin",url],
|
|
|
|
|
# скачать последние коммиты веток
|
|
|
|
|
'fetchshallow': ["fetch","--depth=1"],
|
|
|
|
|
# проверить есть указанный коммит
|
|
|
|
|
'has_revision': ["log","-n1",revision],
|
|
|
|
|
# проверить есть указанный коммит
|
|
|
|
|
'has_branch': ["log","-n1","remotes/origin/%s"%branch],
|
|
|
|
|
# получить ревизию из revs тэгов
|
|
|
|
|
'get_rev_tag': ["fetch","--depth=1","origin",
|
|
|
|
|
"+refs/revs/%s:refs/remotes/origin/%s"%
|
|
|
|
|
(revision,branch)],
|
|
|
|
|
# переключиться на указанную ревизию указанной веткой
|
|
|
|
|
'checkout_revision': ["checkout","-b",branch,revision],
|
|
|
|
|
# переключить на указанную ветку
|
|
|
|
|
'checkout': ["checkout",branch],
|
|
|
|
|
# установить upstream для локальной ветки
|
|
|
|
|
'set_track': ["branch",branch,'-u',"origin/%s"%branch]
|
|
|
|
|
}
|
|
|
|
|
if cmd == "init":
|
|
|
|
|
wholeCommand = [self._git]+commands[cmd]
|
|
|
|
|
else:
|
|
|
|
|
wholeCommand = [self._git,"--git-dir",git_dir,
|
|
|
|
|
"--work-tree",rpath]+commands[cmd]
|
|
|
|
|
if cb_progress and commands[cmd][0] in ("fetch","checkout"):
|
|
|
|
|
progressParam = {'fetch': {'part':4,'end':False},
|
|
|
|
|
'checkout':{'part':4,'startpart':3}}
|
|
|
|
|
gitClone = PercentProgress(*wholeCommand+["--progress","--verbose"],
|
|
|
|
|
stderr=STDOUT,**progressParam)
|
|
|
|
|
for perc in gitClone.progress():
|
|
|
|
|
cb_progress(perc)
|
|
|
|
|
else:
|
|
|
|
|
gitCmd = process(*wholeCommand,stderr=STDOUT)
|
|
|
|
|
if gitCmd.failed():
|
|
|
|
|
error.append(gitCmd.read())
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# получить последние коммиты из удаленного репозитория
|
|
|
|
|
if command("init") and command("add_remote"):
|
|
|
|
|
if command("get_rev_tag") or command("fetchshallow"):
|
|
|
|
|
if not command("has_branch"):
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Branch {branch} not found in {url} repository"
|
|
|
|
|
).format(branch=branch,url=url))
|
|
|
|
|
# если среди коммитов есть указанный коммит
|
|
|
|
|
if command("has_revision"):
|
|
|
|
|
# переключаемся на нужный коммита, устанавливаем связь
|
|
|
|
|
if command("checkout_revision") and command("set_track"):
|
|
|
|
|
return True
|
|
|
|
|
elif command("checkout"):
|
|
|
|
|
return False
|
|
|
|
|
raise GitError(_("Failed to clone {url} repository").format(
|
|
|
|
|
url=url),error[-1])
|
|
|
|
|
|
|
|
|
|
def _pullRepository(self,rpath,quiet_error=False,cb_progress=None):
|
|
|
|
|
"""
|
|
|
|
|
Обновить репозиторий до последней версии
|
|
|
|
|
"""
|
|
|
|
|
gitPull = process(self._git,"--git-dir",self.__gitDir(rpath),
|
|
|
|
|
"pull","--ff-only",stderr=STDOUT)
|
|
|
|
|
if gitPull.failed():
|
|
|
|
|
if not quiet_error:
|
|
|
|
|
error = gitPull.read()
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Failed to update repository in {rpath}").format(
|
|
|
|
|
rpath=rpath),error)
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _fetchRepository(self, rpath, cb_progress=None):
|
|
|
|
|
"""
|
|
|
|
|
Получить изменения из удаленно репозитория
|
|
|
|
|
"""
|
|
|
|
|
if cb_progress:
|
|
|
|
|
gitFetch = PercentProgress(self._git,"--git-dir",self.__gitDir(rpath),
|
|
|
|
|
"fetch","--progress","--verbose",part=3,stderr=STDOUT)
|
|
|
|
|
for perc in gitFetch.progress():
|
|
|
|
|
cb_progress(perc)
|
|
|
|
|
else:
|
|
|
|
|
gitFetch = process(self._git,"--git-dir",self.__gitDir(rpath),
|
|
|
|
|
"fetch",stderr=STDOUT)
|
|
|
|
|
if gitFetch.failed():
|
|
|
|
|
error = gitFetch.read()
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Failed to update repository in {rpath}").format(
|
|
|
|
|
rpath=rpath),error)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _checkChanges(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Проверить наличие изменений пользователем файлов в репозитории
|
|
|
|
|
"""
|
|
|
|
|
git_dir = self.__gitDir(rpath)
|
|
|
|
|
git_status = process(self._git,"--git-dir",git_dir,"--work-tree",rpath,
|
|
|
|
|
"status","--porcelain",stderr=STDOUT)
|
|
|
|
|
if git_status.success():
|
|
|
|
|
for i in git_status:
|
|
|
|
|
if i.strip():
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Wrong repository in {rpath} directory").format(
|
|
|
|
|
rpath=rpath))
|
|
|
|
|
|
|
|
|
|
def _parseStatusInfo(self,data):
|
|
|
|
|
"""
|
|
|
|
|
Разобрать информацию полученную через git status -b --porcelain
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Словарь
|
|
|
|
|
# есть ли измененные файлы пользователем
|
|
|
|
|
{'files':True/False,
|
|
|
|
|
# есть коммиты после текущего
|
|
|
|
|
'ahead':True/False,
|
|
|
|
|
# есть коммиты перед текущим (означает, что обновление
|
|
|
|
|
# с основной веткой не осуществляется через fast-forward
|
|
|
|
|
'behind':True/False,
|
|
|
|
|
# текущая ветка
|
|
|
|
|
'branch':'',
|
|
|
|
|
# оригинальная ветка
|
|
|
|
|
'origin':'origin/master'}
|
|
|
|
|
"""
|
|
|
|
|
reStatus = re.compile("^## (\w+)(?:\.\.\.(\S+)\s+\[(ahead \d+)?"
|
|
|
|
|
"(?:, )?(behind \d+)?\])?\n?(.*|$)",re.S)
|
|
|
|
|
match = reStatus.search(data)
|
|
|
|
|
if not match:
|
|
|
|
|
return {}
|
|
|
|
|
return {'files':True if match.group(5) else False,
|
|
|
|
|
'ahead':True if match.group(3) else False,
|
|
|
|
|
'behind':True if match.group(4) else False,
|
|
|
|
|
'origin':match.group(2) or "",
|
|
|
|
|
'branch':match.group(1)}
|
|
|
|
|
|
|
|
|
|
def _getCurrentCommit(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Получить текущий коммит в репозитории
|
|
|
|
|
"""
|
|
|
|
|
git_dir = self.__gitDir(rpath)
|
|
|
|
|
git_show = process(self._git,"--git-dir",git_dir,"show","--format=format:%H",
|
|
|
|
|
"--quiet",stderr=STDOUT)
|
|
|
|
|
if git_show.success():
|
|
|
|
|
return git_show.read().strip()
|
|
|
|
|
else:
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Failed to get status of repository in "
|
|
|
|
|
"{rpath} directory").format(
|
|
|
|
|
rpath=rpath))
|
|
|
|
|
|
|
|
|
|
def _getStatusInfo(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Получить информацию об изменениях в репозитории
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Словарь выдаваемый функцией _parseStatusInfo
|
|
|
|
|
"""
|
|
|
|
|
git_dir = self.__gitDir(rpath)
|
|
|
|
|
git_status = process(self._git,"--git-dir",git_dir,"--work-tree",rpath,
|
|
|
|
|
"status","-b","--porcelain",stderr=STDOUT)
|
|
|
|
|
if git_status.success():
|
|
|
|
|
retDict = self._parseStatusInfo(git_status.read())
|
|
|
|
|
if not retDict:
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Failed to get status of repository in "
|
|
|
|
|
"{rpath} directory").format(
|
|
|
|
|
rpath=rpath))
|
|
|
|
|
return retDict
|
|
|
|
|
else:
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Wrong repository in {rpath} directory").format(
|
|
|
|
|
rpath=rpath))
|
|
|
|
|
|
|
|
|
|
def _resetRepository(self, rpath, to_origin=False, to_rev=None, info=None):
|
|
|
|
|
"""
|
|
|
|
|
Удалить неиндексированные изменения в репозитории
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
to_origin: откатить все изменения до удаленного репозитория
|
|
|
|
|
to_rev: откатить все изменения до определенной ревизии
|
|
|
|
|
info: использовать уже полученную информация об изменения в репозитории
|
|
|
|
|
Return:
|
|
|
|
|
True - успешное выполнение
|
|
|
|
|
False - нет необходимости выполнять reset
|
|
|
|
|
Raises:
|
|
|
|
|
GitError: выполнение комманд reset и clean прошло с ошибкой
|
|
|
|
|
"""
|
|
|
|
|
git_dir = self.__gitDir(rpath)
|
|
|
|
|
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)
|
|
|
|
|
git_clean = process(self._git,"--git-dir",git_dir,"--work-tree",rpath,
|
|
|
|
|
"clean","-fd",stderr=STDOUT)
|
|
|
|
|
if git_reset.failed() or git_clean.failed():
|
|
|
|
|
raise GitError(_("Failed to clean {rpath} repository").format(
|
|
|
|
|
rpath=rpath))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _getBranch(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Получить текущую ветку
|
|
|
|
|
"""
|
|
|
|
|
return self._getStatusInfo(rpath)['branch']
|
|
|
|
|
|
|
|
|
|
def _checkoutBranch(self,rpath,branch):
|
|
|
|
|
"""
|
|
|
|
|
Сменить ветку
|
|
|
|
|
"""
|
|
|
|
|
git_dir = self.__gitDir(rpath)
|
|
|
|
|
git_checkout = process(self._git,"--git-dir",git_dir,
|
|
|
|
|
"--work-tree", rpath,
|
|
|
|
|
"checkout","-f",branch, stderr=STDOUT)
|
|
|
|
|
if git_checkout.failed():
|
|
|
|
|
error = git_checkout.read()
|
|
|
|
|
if "pathspec '%s' did not match"%branch in error:
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Branch {branch} not found in {rpath} repository").format(
|
|
|
|
|
branch=branch,rpath=rpath))
|
|
|
|
|
raise GitError(
|
|
|
|
|
_("Failed to change branch to {branch} in "
|
|
|
|
|
"{rpath} repository").format(branch=branch,
|
|
|
|
|
rpath=rpath),error)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
class Update:
|
|
|
|
|
"""Основной объект для выполнения действий связанных с обновлением системы
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def _syncRepository(self,name,url,rpath,revision,branch,
|
|
|
|
|
def _syncRepository(self, name, url, rpath, revision, branch,
|
|
|
|
|
cb_progress=None):
|
|
|
|
|
"""
|
|
|
|
|
Синхронизировать репозиторий
|
|
|
|
|
Синхронизировать репозитори
|
|
|
|
|
"""
|
|
|
|
|
dv = self.clVars
|
|
|
|
|
git = Git()
|
|
|
|
|
needMeta = False
|
|
|
|
|
if not git._checkExistsRep(rpath):
|
|
|
|
|
if not git.checkExistsRep(rpath):
|
|
|
|
|
if revision == "last":
|
|
|
|
|
git._cloneRepository(url, rpath, branch,
|
|
|
|
|
cb_progress=cb_progress)
|
|
|
|
|
git.cloneRepository(url, rpath, branch,
|
|
|
|
|
cb_progress=cb_progress)
|
|
|
|
|
else:
|
|
|
|
|
git._cloneRevRepository(url, rpath, branch, revision,
|
|
|
|
|
cb_progress=cb_progress)
|
|
|
|
|
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:
|
|
|
|
|
if revision == git.getCurrentCommit(rpath):
|
|
|
|
|
if git.getBranch(rpath) == branch:
|
|
|
|
|
return True
|
|
|
|
|
# получить изменения из удаленного репозитория
|
|
|
|
|
git._fetchRepository(rpath,cb_progress=cb_progress)
|
|
|
|
|
git.fetchRepository(rpath, cb_progress=cb_progress)
|
|
|
|
|
# если текущая ветка не соответствует нужной
|
|
|
|
|
repInfo = git._getStatusInfo(rpath)
|
|
|
|
|
repInfo = git.getStatusInfo(rpath)
|
|
|
|
|
if repInfo['branch'] != branch:
|
|
|
|
|
# меняем ветку
|
|
|
|
|
needMeta = True
|
|
|
|
|
git._checkoutBranch(rpath,branch)
|
|
|
|
|
git.checkoutBranch(rpath, branch)
|
|
|
|
|
if revision == "last":
|
|
|
|
|
if git._resetRepository(rpath, to_origin=True):
|
|
|
|
|
if git.resetRepository(rpath, to_origin=True):
|
|
|
|
|
needMeta = True
|
|
|
|
|
else:
|
|
|
|
|
git._resetRepository(rpath, to_rev=revision)
|
|
|
|
|
git.resetRepository(rpath, to_rev=revision)
|
|
|
|
|
needMeta = True
|
|
|
|
|
if needMeta:
|
|
|
|
|
dv.Set('cl_update_outdate_set','on',force=True)
|
|
|
|
|
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)
|
|
|
|
|
layman.add(name, url, rpath)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def syncRepositories(self,repname,clean_on_error=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))
|
|
|
|
|
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)
|
|
|
|
|
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))
|
|
|
|
|
).format(name=repname))
|
|
|
|
|
try:
|
|
|
|
|
removeDir(rpath)
|
|
|
|
|
except OSError as e:
|
|
|
|
|
raise UpdateError(_("Permission denied to change "
|
|
|
|
|
"{repname} repository").format(repname=repname))
|
|
|
|
|
self._syncRepository(name,url,rpath,revision,branch)
|
|
|
|
|
"{repname} repository").format(
|
|
|
|
|
repname=repname))
|
|
|
|
|
self._syncRepository(repname, url, rpath, revision, branch)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def syncLaymanRepository(self,repname):
|
|
|
|
|
def syncLaymanRepository(self, repname):
|
|
|
|
|
"""
|
|
|
|
|
Обновить репозиторий через layman
|
|
|
|
|
"""
|
|
|
|
@ -530,21 +124,22 @@ class Update:
|
|
|
|
|
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)
|
|
|
|
|
where='cl_update_other_rep_name', eq=repname,
|
|
|
|
|
limit=1)
|
|
|
|
|
laymanname = path.basename(rpath)
|
|
|
|
|
if path.exists(path.join(rpath,'.git')):
|
|
|
|
|
if Git.is_git(rpath):
|
|
|
|
|
self.addProgress()
|
|
|
|
|
p = PercentProgress(layman,"-s",laymanname,part=1,atty=True)
|
|
|
|
|
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)
|
|
|
|
|
p = process(layman, "-s", repname, stderr=STDOUT)
|
|
|
|
|
if p.failed():
|
|
|
|
|
raise UpdateError(_("Failed to update repository {rname}"
|
|
|
|
|
).format(rname=repname),addon=p.read())
|
|
|
|
|
).format(rname=repname), addon=p.read())
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def regenCache(self,repname):
|
|
|
|
|
def regenCache(self, repname):
|
|
|
|
|
"""
|
|
|
|
|
Обновить кэш метаданных репозитория
|
|
|
|
|
"""
|
|
|
|
@ -552,11 +147,12 @@ class Update:
|
|
|
|
|
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)
|
|
|
|
|
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())
|
|
|
|
|
raise UpdateError(_("Failed to update cache of {rname} "
|
|
|
|
|
"repository").format(rname=repname),
|
|
|
|
|
addon=p.read())
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def emergeMetadata(self):
|
|
|
|
@ -567,11 +163,11 @@ class Update:
|
|
|
|
|
if not emerge:
|
|
|
|
|
raise UpdateError(_("Emerge utility is not found"))
|
|
|
|
|
self.addProgress()
|
|
|
|
|
p = PercentProgress(emerge,"--metadata",part=1,atty=True)
|
|
|
|
|
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())
|
|
|
|
|
raise UpdateError(_("Failed to update metadata"), addon=p.read())
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def eixUpdate(self):
|
|
|
|
@ -592,19 +188,74 @@ class Update:
|
|
|
|
|
else:
|
|
|
|
|
for rep in self.clVars.Get('cl_update_rep_name'):
|
|
|
|
|
# подстановка имен
|
|
|
|
|
mapNames = {'portage':'gentoo'}
|
|
|
|
|
mapNames = {'portage': 'gentoo'}
|
|
|
|
|
if not rep in self.clVars.Get('cl_update_sync_rep'):
|
|
|
|
|
excludeList.extend(["-x",mapNames.get(rep,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'):
|
|
|
|
|
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)
|
|
|
|
|
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())
|
|
|
|
|
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
|
|
|
|
|