Изменены критерии сортировки серверов обновления

1. по актуальности
2. у актуальных по скорости и свежести
3. у неактуальных по свежести и скорости
master3.4 3.4.5.3
ebeveyn bbcec6fbf0
işleme 72393cf50f

@ -43,11 +43,13 @@ _ = lambda x: x
setLocalTranslate('cl_update3', sys.modules[__name__])
class VariableAcUpdateSync(ReadonlyVariable):
"""
Action variable which has value "up" for package install and
install this package
"""
def get(self):
action = self.Get("cl_action")
if action in ("sync",):
@ -55,12 +57,14 @@ class VariableAcUpdateSync(ReadonlyVariable):
return self.Get('cl_update_world')
return ""
class VariableClUpdateWorldDefault(Variable):
"""
Ad-hoc
"""
value = "update"
class VariableClUpdateWorld(Variable):
type = "choice"
opt = ["--world"]
@ -95,6 +99,7 @@ class VariableClRebuildWorldSet(Variable):
self.help = _("Rebuild world")
self.label = _("Rebuild world")
class VariableClUpdateRevSet(Variable):
"""
List of action update world, rebuild world,
@ -104,14 +109,15 @@ class VariableClUpdateRevSet(Variable):
untrusted = True
value = "on"
check_after = ["cl_update_sync_rep",
"cl_update_metadata_force",
"cl_update_other_set",
"cl_update_eixupdate_force"]
"cl_update_metadata_force",
"cl_update_other_set",
"cl_update_eixupdate_force"]
def init(self):
self.help = _("make a revision update")
self.label = _("Make a revision update")
class VariableClUpdateRep(Variable):
"""
Обновлять репозитории до конкретной ревизии или до последней
@ -122,6 +128,7 @@ class VariableClUpdateRep(Variable):
def choice(self):
return ["last", "rev"]
class VariableClUpdateRepData(ReadonlyTableVariable):
"""
Информация о репозиториях
@ -131,6 +138,7 @@ class VariableClUpdateRepData(ReadonlyTableVariable):
'cl_update_rep_path',
'cl_update_rep_rev']
class VariableClUpdateRepName(Variable):
"""
Список имен используемых репозиториев
@ -138,6 +146,7 @@ class VariableClUpdateRepName(Variable):
type = "list"
value = []
class VariableClUpdateRepUrl(Variable):
"""
Список путей до репозиториев
@ -145,6 +154,7 @@ class VariableClUpdateRepUrl(Variable):
type = "list"
value = []
class VariableClUpdateLaymanConfig(ReadonlyVariable):
"""
Объект конфига layman
@ -157,6 +167,7 @@ class VariableClUpdateLaymanConfig(ReadonlyVariable):
cp.read(path.join(chroot, 'etc/layman/layman.cfg'))
return cp
class VariableClUpdateLaymanStorage(Variable):
"""
Путь к репозиториям layman
@ -169,6 +180,7 @@ class VariableClUpdateLaymanStorage(Variable):
res = cp.get('MAIN', self.param_name, fallback=self.fallback_value)
return pathJoin(self.Get('cl_chroot_path'), res)
class VariableClUpdateRepPath(ReadonlyVariable):
"""
Пути до репозиториев
@ -187,6 +199,7 @@ class VariableClUpdateRepPath(ReadonlyVariable):
yield path.join(chroot_path, self.mapPath[name])
else:
yield path.join(repPath, name)
return list(generatePaths(self.Get('cl_update_rep_name')))
@ -212,6 +225,7 @@ class VariableClUpdateRepRev(Variable):
yield cp.get("vcs", repname, fallback=branch)
else:
yield branchname
return list(generateBranch())
@ -221,6 +235,7 @@ class VariableClUpdateBranch(Variable):
"""
value = Git.Reference.Master
class VariableClUpdateBranchData(TableVariable):
"""
Выбор веток репозиториев до которых необходимо обновиться
@ -239,7 +254,8 @@ class VariableClUpdateBranchData(TableVariable):
"""
Неизвестный оврелей
"""
raise VariableError(_("Repository %s not found")%value)
raise VariableError(_("Repository %s not found") % value)
class VariableClUpdateBranchRep(ReadonlyVariable):
"""
@ -253,6 +269,7 @@ class VariableClUpdateBranchRep(ReadonlyVariable):
def get(self):
return self.Get('cl_update_rep_name')
class VariableClUpdateBinhostData(ReadonlyTableVariable):
"""
Таблица содержащая
@ -292,6 +309,10 @@ class VariableClUpdateBinhostData(ReadonlyTableVariable):
-int(time))
def get_timestamp(self, binhost):
"""
Возвращает таймстам полученный от сервера, время доступа,
актуальность (не более 5 суток)
"""
DAY = 60 * 60 * 24
timeout = self.GetInteger('cl_update_binhost_timeout')
timestamp_file = path.join(binhost,
@ -300,34 +321,57 @@ class VariableClUpdateBinhostData(ReadonlyTableVariable):
t = time.time()
data = urllib2.urlopen(timestamp_file,
timeout=timeout).read().strip()
if data.isdigit() and t - int(data) < 5 * DAY:
return data, int((time.time() - t)*1000)
if data.isdigit():
return (data, int((time.time() - t) * 1000),
t - int(data) < 5 * DAY)
except urllib2.URLError as e:
pass
except BaseException as e:
if isinstance(e, KeyboardInterrupt):
raise
pass
return "", -1
return "", -1, False
def get(self, hr=HumanReadable.No):
DAY = 60 * 60 * 24
binhost = self.Get('cl_update_binhost')
recheck = self.GetBool('cl_update_binhost_recheck_set')
cur_t = time.time()
def generate_by_timestamp():
for host in self.Get('cl_update_binhost_list'):
if host:
ts_content, duration = self.get_timestamp(host)
ts_content, duration, good = self.get_timestamp(host)
if ts_content:
yield host, ts_content, str(duration)
yield host, ts_content, str(duration), good
if not recheck and binhost:
ts, t = self.get_timestamp(binhost)
if ts:
ts, t, good = self.get_timestamp(binhost)
# условие актуальности текущего сервера
if ts and cur_t - int(ts) < 5 * DAY:
data = self.check_binhost(binhost)
if data:
return [[binhost, data, str(t)]]
for host, ts, t in sorted(generate_by_timestamp(),
key=lambda x: (-int(x[1]), int(x[2]))):
for host, ts, t, good in sorted(
generate_by_timestamp(),
# критерий сортировки между серверами
# актуальные сортируются по скорости
# неактульные по timestamp
# актуальность - 5 дней
reverse=True,
key=lambda x: (# приоритетны актуальные (не более 5 дней)
x[3],
# приоритет для неактуальных
# самое свежее
0 if x[3] else int(x[1]),
# приоритет для неактуальных
# самое быстрое
0 if x[3] else -int(x[2]),
# приоритет для актуальных
# самое быстрое
-int(x[2]) if x[3] else 0,
# самое свежее
int(x[1]) if x[3] else 0)):
data = self.check_binhost(host)
if data:
return [[host, data, str(t)]]
@ -356,7 +400,8 @@ class VariableClUpdateBinhostHost(FieldValue, ReadonlyVariable):
source_variable = "cl_update_binhost_data"
column = 0
class VariableClUpdateBinhostRevisions(FieldValue,ReadonlyVariable):
class VariableClUpdateBinhostRevisions(FieldValue, ReadonlyVariable):
"""
Список имен прочих репозиториев
"""
@ -364,7 +409,8 @@ class VariableClUpdateBinhostRevisions(FieldValue,ReadonlyVariable):
source_variable = "cl_update_binhost_data"
column = 1
class VariableClUpdateBinhostTime(FieldValue,ReadonlyVariable):
class VariableClUpdateBinhostTime(FieldValue, ReadonlyVariable):
"""
Список имен прочих репозиториев
"""
@ -418,7 +464,7 @@ class VariableClUpdateSyncRep(Variable):
def set(self, value):
orderList = self.rep_name
return sorted(value, key=lambda x:
(orderList.index(x) if x in orderList else -1), reverse=True)
(orderList.index(x) if x in orderList else -1), reverse=True)
def get(self):
return list(reversed(self.rep_name))
@ -426,6 +472,7 @@ class VariableClUpdateSyncRep(Variable):
def choice(self):
return self.rep_name
class VariableClUpdateSyncOverlayRep(ReadonlyVariable):
"""
Обновляемые репозитории (исключая portage)
@ -435,6 +482,7 @@ class VariableClUpdateSyncOverlayRep(ReadonlyVariable):
def get(self):
return filter(lambda x: x != "portage", self.Get('cl_update_sync_rep'))
class VariableClUpdateOutdateSet(ReadonlyVariable):
"""
Флаг устанавливаемый в ходе обновления репозиториев,
@ -447,10 +495,11 @@ class VariableClUpdateOutdateSet(ReadonlyVariable):
def get(self):
if (self.Get('cl_update_other_set') == 'on' and
self.Get('cl_update_other_rep_name')):
self.Get('cl_update_other_rep_name')):
return "on"
return "off"
class VariableClUpdateMetadataForce(Variable):
"""
Принудительное действие с метаданными
@ -460,7 +509,7 @@ class VariableClUpdateMetadataForce(Variable):
opt = ["--update-metadata"]
syntax = "--{choice}-update-metadata"
metavalue = "MODE"
#untrusted = True
# untrusted = True
def init(self):
self.help = ("'force' - " + _("force the update ebuilds metadata") +
@ -483,12 +532,13 @@ class VariableClUpdateEgencacheForce(Variable):
opt = ["--egencache"]
syntax = "--{choice}-egencache"
metavalue = "MODE"
#untrusted = True
# untrusted = True
def init(self):
self.help = ("'force' - " + _("force the update of the overlays cache") +
",\n'skip' - " + _("skip the update of the overlays cache") +
",\n'auto' - " + _("update the overlays cache if outdated"))
self.help = (
"'force' - " + _("force the update of the overlays cache") +
",\n'skip' - " + _("skip the update of the overlays cache") +
",\n'auto' - " + _("update the overlays cache if outdated"))
self.label = _("Update the overlays cache")
def choice(self):
@ -506,7 +556,7 @@ class VariableClUpdateEixupdateForce(Variable):
opt = ["--eix-update"]
syntax = "--{choice}-eix-update"
metavalue = "MODE"
#untrusted = True
# untrusted = True
def init(self):
self.help = ("'force' - " + _("force the eix cache update") +
@ -520,6 +570,7 @@ class VariableClUpdateEixupdateForce(Variable):
("skip", _("Skip")),
("auto", _("If needed"))]
class VariableClUpdateOtherSet(Variable):
"""
Обновить остальные оверлеи
@ -532,6 +583,7 @@ class VariableClUpdateOtherSet(Variable):
self.help = _("update other overlays")
self.label = _("Update other overlays")
class VariableClUpdateOtherRepData(ReadonlyTableVariable):
"""
Информация о прочих репозиториях
@ -558,7 +610,8 @@ class VariableClUpdateOtherRepData(ReadonlyTableVariable):
def get(self, hr=HumanReadable.No):
return list(self.generator())
class VariableClUpdateOtherRepName(FieldValue,ReadonlyVariable):
class VariableClUpdateOtherRepName(FieldValue, ReadonlyVariable):
"""
Список имен прочих репозиториев
"""
@ -566,7 +619,8 @@ class VariableClUpdateOtherRepName(FieldValue,ReadonlyVariable):
source_variable = "cl_update_other_rep_data"
column = 0
class VariableClUpdateOtherRepPath(FieldValue,ReadonlyVariable):
class VariableClUpdateOtherRepPath(FieldValue, ReadonlyVariable):
"""
Список путей до прочих репозиториев
"""
@ -574,6 +628,7 @@ class VariableClUpdateOtherRepPath(FieldValue,ReadonlyVariable):
source_variable = "cl_update_other_rep_data"
column = 1
class VariableClUpdateLaymanInstalled(VariableClUpdateLaymanStorage):
"""
Путь до файла layman installed.xml
@ -581,6 +636,7 @@ class VariableClUpdateLaymanInstalled(VariableClUpdateLaymanStorage):
param_name = "installed"
fallback_value = "var/lib/layman/installed.xml"
class VariableClUpdateLaymanMake(VariableClUpdateLaymanStorage):
"""
Путь до файла make.conf изменяемого layman`ом
@ -588,6 +644,7 @@ class VariableClUpdateLaymanMake(VariableClUpdateLaymanStorage):
param_name = "make_conf"
fallback_value = "var/lib/layman/make.conf"
class VariableClUpdateLaymanConf(VariableClUpdateLaymanStorage):
"""
Путь до конфигурационного файла репозиториев для layman
@ -595,6 +652,7 @@ class VariableClUpdateLaymanConf(VariableClUpdateLaymanStorage):
param_name = "repos_conf"
fallback_value = "etc/portage/repos.conf/layman.conf"
class VariableClUpdatePretendSet(Variable):
"""
Запустить предварительную проверку на обновления
@ -609,6 +667,7 @@ class VariableClUpdatePretendSet(Variable):
"simply display the list of packages that "
"will be installed")
class VariableClUpdateSyncOnlySet(Variable):
"""
Не выполнять установку/обновление пакетов при обновлении
@ -630,6 +689,7 @@ class VariableClUpdateSyncOnlySet(Variable):
self.Get('cl_update_eixupdate_force') != "force"):
raise VariableError(_("Select at least one sync repository"))
class VariableClUpdateWaitAnotherSet(Variable):
"""
Ждать завершения другого процесса обновления
@ -642,6 +702,7 @@ class VariableClUpdateWaitAnotherSet(Variable):
self.label = _("Wait for another update to be complete")
self.help = _("wait until the running update is finished")
class VariableClUpdateProfileStorage(ReadonlyVariable):
type = "object"
@ -650,10 +711,12 @@ class VariableClUpdateProfileStorage(ReadonlyVariable):
LocalStorage('/var/lib/layman'),
CacheStorage('/var/calculate/tmp/update'))
class VariableClUpdateRepHost(Variable):
type = "list"
value = ['calculate']
class VariableClUpdateRepHostUrl(Variable):
type = "list"
value = ['git://git.calculate.ru/calculate/%s.git']
@ -674,10 +737,12 @@ class VariableClUpdateProfileDatavars(ReadonlyVariable):
return DataVarsUpdateProfile(path_profile)
return ""
class VariableClUpdateProfileLinuxFullname(ReadonlyVariable):
"""
Имя системы в профиле
"""
def init(self):
self.label = _("Distribution name")
@ -692,11 +757,12 @@ class VariableClUpdateProfileLinuxFullname(ReadonlyVariable):
linuxver = dv.Get('os_linux_ver')
if subname:
return "%s %s %s" % (linuxname, linuxver, subname)
return "%s %s" %(linuxname,linuxver)
return "%s %s" % (linuxname, linuxver)
except DataVarsError as s:
raise VariableError("Wrong Calculate Linux profile")
return ""
class VariableClUpdateProfileDependData(ReadonlyTableVariable):
"""
Зависимые репозитории
@ -717,12 +783,11 @@ class VariableClUpdateProfileDependData(ReadonlyTableVariable):
return match1.group(2).lower() == match2.group(2).lower()
return False
def get(self, hr=HumanReadable.No):
dv = self.Get(self.datavars)
# TODO: неиспользуемая переменная возможно
# испольуется для инициализации
#url = self.Get('cl_update_profile_url').lower()
# url = self.Get('cl_update_profile_url').lower()
if dv:
return reversed(zip(dv.Get('cl_update_rep_name'),
dv.Get('cl_update_rep_url')))
@ -730,13 +795,14 @@ class VariableClUpdateProfileDependData(ReadonlyTableVariable):
setValue = Variable.setValue
class VariableClUpdateTemplatesLocate(Variable):
"""
Выбранные типы хранилищ шаблонов
"""
type = "choice-list"
element = "selecttable"
opt = ["-T","--templates"]
opt = ["-T", "--templates"]
metavalue = "TEMPLATES"
untrusted = True
check_after = ['cl_update_profile_system']
@ -754,7 +820,7 @@ class VariableClUpdateTemplatesLocate(Variable):
def init(self):
self.label = _("Templates location")
self.help = _("select the location for templates %s") \
%",".join(self.get())
% ",".join(self.get())
def get(self):
dv = self.Get(self.profile_datevars)
@ -768,6 +834,7 @@ class VariableClUpdateTemplatesLocate(Variable):
_("%s overlay templates" % x))
return map(lambda x: (x, descr(x)), self.get())
class VariableClUpdateProfileDependName(FieldValue, ReadonlyVariable):
type = "list"
source_variable = "cl_update_profile_depend_data"
@ -776,6 +843,7 @@ class VariableClUpdateProfileDependName(FieldValue, ReadonlyVariable):
def init(self):
self.label = _("Name")
class VariableClUpdateProfileDependUrl(FieldValue, ReadonlyVariable):
type = "list"
source_variable = "cl_update_profile_depend_data"
@ -794,12 +862,14 @@ class VariableClUpdateProfileRepName(ReadonlyVariable):
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"
@ -809,10 +879,12 @@ class VariableClUpdateProfileRepUrl(ReadonlyVariable):
return dv.Get('cl_update_rep_url')
return []
class VariableClUpdateProfileLinuxVer(ReadonlyVariable):
"""
Имя системы в профиле
"""
def init(self):
self.label = _("System profile version")
@ -822,16 +894,19 @@ class VariableClUpdateProfileLinuxVer(ReadonlyVariable):
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 VariableClUpdateProfileUrl(Variable):
"""
URL текущего репозитория
@ -852,7 +927,6 @@ class VariableClUpdateProfileUrl(Variable):
def current_root(self):
return '/'
def init(self):
self.label = _("Profile repository")
self.help = _("set the profile repository")
@ -905,7 +979,7 @@ class VariableClUpdateProfileUrl(Variable):
except GitError as e:
raise VariableError(str(e))
if not self.Get(self.profiles_shortname):
raise VariableError(_("Repository %s has no profiles")%value)
raise VariableError(_("Repository %s has no profiles") % value)
def get(self):
try:
@ -922,6 +996,7 @@ class VariableClUpdateProfileUrl(Variable):
pass
return self.default_url
class VariableClUpdateProfileRepoName(ReadonlyVariable):
def init(self):
self.label = _("Repository name")
@ -959,11 +1034,13 @@ class VariableClUpdateProfileBranch(Variable):
def check(self, value):
pass
## TODO: проверка ветки
#try:
# try:
# url = self.Get('cl_update_profile_url')
# self.Get('cl_update_profile_storage').get_profiles(url, value)
#except GitError as e:
# raise VariableError(str(e))
# except GitError as e:
# raise VariableError(str(e))
class VariableClProfileRepository(ReadonlyVariable):
@ -1017,6 +1094,7 @@ class VariableClProfileData(ReadonlyTableVariable):
setValue = Variable.setValue
class VariableClUpdateProfileRepository(ReadonlyVariable):
"""
Репозиторий из которого будет извлечён список профилей
@ -1041,10 +1119,12 @@ class VariableClUpdateProfileRepository(ReadonlyVariable):
except GitError:
return ""
class VariableClUpdateProfileRepositoryName(ReadonlyVariable):
"""
Название репозитория, из которого будут извлечены профили
"""
def get(self):
rep = self.Get('cl_update_profile_repository')
if rep:
@ -1069,6 +1149,7 @@ class VariableClUpdateProfileFullname(FieldValue, ReadonlyVariable):
source_variable = "cl_update_profile_data"
column = 0
class VariableClUpdateProfileShortname(FieldValue, ReadonlyVariable):
"""
Упрощенное название профиля
@ -1077,6 +1158,7 @@ class VariableClUpdateProfileShortname(FieldValue, ReadonlyVariable):
source_variable = "cl_update_profile_data"
column = 1
class VariableClUpdateProfilePath(FieldValue, ReadonlyVariable):
"""
Путь от корня до профиля
@ -1085,6 +1167,7 @@ class VariableClUpdateProfilePath(FieldValue, ReadonlyVariable):
source_variable = "cl_update_profile_data"
column = 2
class VariableClUpdateProfileArch(FieldValue, ReadonlyVariable):
"""
Архитектура профиля
@ -1093,6 +1176,7 @@ class VariableClUpdateProfileArch(FieldValue, ReadonlyVariable):
source_variable = "cl_update_profile_data"
column = 3
class VariableClUpdateProfileSystem(Variable):
"""
Профиль системы (симлинк /etc/make.profile')
@ -1141,7 +1225,7 @@ class VariableClUpdateProfileSystem(Variable):
raise VariableError(
_("Overlay %s is not specified "
"in cl_update_rep_name") % repo_name)
except (DataVarsError,VariableError) as e:
except (DataVarsError, VariableError) as e:
if str(e):
message = ". " + str(e)
else:
@ -1179,6 +1263,7 @@ class VariableClUpdateProfileSystem(Variable):
return zip(short_name, full_name)
return []
class DataVarsUpdateProfile(SimpleDataVars):
"""
Упрощенная модель переменных для получения данных с удаленного профиля
@ -1188,6 +1273,7 @@ class DataVarsUpdateProfile(SimpleDataVars):
'cl_update_rep_path',
'cl_update_rep_rev',
'cl_update_branch_name']
def __init__(self, profile, chroot_path='/', recheck=None):
SimpleDataVars.__init__(
self,
@ -1234,6 +1320,7 @@ class DataVarsUpdateProfile(SimpleDataVars):
def __repr__(self):
return "Profile variables"
class VariableClUpdateProfileSyncSet(Variable):
"""
Синхронизировать репозиторий перед сменой профиля
@ -1273,9 +1360,9 @@ class VariableClUpdateAutocheckInterval(Variable):
self.help = _("set interval for the updates checking")
def choice(self):
return [["6h",_("every six hours")],
["12h",_("every twelve hours")],
["1d",_("daily")]]
return [["6h", _("every six hours")],
["12h", _("every twelve hours")],
["1d", _("daily")]]
class VariableClUpdateAutocheckScheduleSet(Variable):
@ -1298,7 +1385,7 @@ class VariableClUpdateEmergelistSet(Variable):
"""
type = "bool"
value = "off"
opt = ["-e","--emergelist"]
opt = ["-e", "--emergelist"]
def init(self):
self.label = _("Emerge-like packages list")
@ -1309,18 +1396,20 @@ class VariableClUpdateKernelVersion(ReadonlyVariable):
"""
Текущая версия ядра
"""
def get(self):
return process('/bin/uname','-r').read().strip()
return process('/bin/uname', '-r').read().strip()
class VariableClUpdateKernelSrcPath(ReadonlyVariable):
"""
Каталог содержащий исходный код текущего ядра
"""
def get(self):
kernel_ver = self.Get('cl_update_kernel_version')
for template_path in ("/lib/modules/%s/build",
"/usr/src/linux-%s"):
"/usr/src/linux-%s"):
src_path = template_path % kernel_ver
if path.exists(src_path):
if path.islink(src_path):
@ -1335,6 +1424,7 @@ class VariableClUpdateKernelPkg(ReadonlyVariable):
"""
Пакет текущего ядра
"""
def get(self):
src_path = self.Get('cl_update_kernel_src_path')
if src_path:
@ -1409,6 +1499,7 @@ class VariableClUpdateOutdatedKernelSet(ReadonlyVariable):
ui = UpdateInfo(self.parent)
return "on" if ui.outdated_kernel else "off"
class VariableClUpdateBinhostList(Variable):
"""
Список хостов с бинарными обновлениями
@ -1416,12 +1507,14 @@ class VariableClUpdateBinhostList(Variable):
type = "list"
value = ["ftp://ftp.calculate-linux.ru/pub/calculate"]
class VariableClUpdateBinhost(Variable):
"""
Хост с бинарными обновлениями
"""
value = ""
class VariableClUpdateBinhostRevisionPath(Variable):
"""
Путь до revisions файлов
@ -1434,12 +1527,14 @@ class VariableClUpdateBinhostRevisionPath(Variable):
"grp/x/ini.env"
]
class VariableClUpdateBinhostTimestampPath(Variable):
"""
Путь до файла timestamp
"""
value = "timestamp"
class VariableClUpdateBinhostTimeout(Variable):
"""
Таймаут на проверку одного binhost
@ -1447,6 +1542,7 @@ class VariableClUpdateBinhostTimeout(Variable):
type = "int"
value = "5"
class VariableClUpdateCheckRepSet(Variable):
"""
Удлять лишние файлы из репозиториев (например созданные пользователем)
@ -1460,6 +1556,7 @@ class VariableClUpdateCheckRepSet(Variable):
self.label = _("Check the repositories integrity")
self.help = _("check and fix the repositories integrity")
class VariableClUpdateOnedepthSet(Variable):
"""
Удлять лишние файлы из репозиториев (например созданные пользователем)

Yükleniyor…
İptal
Kaydet