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.

1576 lines
47 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2013-2016 Mir Calculate. http://www.calculate-linux.org
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import os
  16. import sys
  17. import re
  18. from os import path
  19. from calculate.lib.cl_template import SystemIni
  20. from calculate.lib.cl_log import log
  21. from calculate.lib.datavars import (Variable, VariableError,
  22. ReadonlyVariable, ReadonlyTableVariable,
  23. TableVariable, FieldValue,
  24. HumanReadable,
  25. SimpleDataVars, DataVarsError)
  26. from calculate.lib.utils.binhosts import Binhosts
  27. from calculate.lib.utils.files import readFile, listDirectory, process, pathJoin
  28. from calculate.lib.configparser import ConfigParser
  29. from calculate.lib.cl_lang import setLocalTranslate
  30. from calculate.lib.utils.text import simplify_profiles
  31. from calculate.lib.utils.git import Git, GitError
  32. from calculate.lib.utils.portage import Layman
  33. from ..profile import (RepositoryStorageSet, DEFAULT_BRANCH,
  34. LocalStorage, ProfileRepository, CacheStorage)
  35. from calculate.lib.variables import linux as lib_linux
  36. from calculate.lib.variables import env
  37. from calculate.update.update_info import UpdateInfo
  38. from itertools import chain
  39. import time
  40. _ = lambda x: x
  41. setLocalTranslate('cl_update3', sys.modules[__name__])
  42. class VariableAcUpdateSync(ReadonlyVariable):
  43. """
  44. Action variable which has value "up" for package install and
  45. install this package
  46. """
  47. def get(self):
  48. action = self.Get("cl_action")
  49. if action in ("sync",):
  50. if self.Get('cl_update_world'):
  51. return self.Get('cl_update_world')
  52. return ""
  53. class VariableClUpdateWorldDefault(Variable):
  54. """
  55. Ad-hoc
  56. """
  57. value = "update"
  58. class VariableClUpdateWorld(Variable):
  59. type = "choice"
  60. opt = ["--world"]
  61. syntax = "--{choice}-world"
  62. metavalue = "MODE"
  63. def init(self):
  64. self.help = ("'rebuild' - " + _("rebuild the system packages list") +
  65. ",\n'merge' - " + _("append the profile packages list") +
  66. ",\n'update' - " + _("update the system packages list"))
  67. self.label = _("System packages list")
  68. def get(self):
  69. return self.Get('cl_update_world_default')
  70. def choice(self):
  71. return [("rebuild", _("Rebuild")),
  72. ("merge", _("Merge")),
  73. ("update", _("Update"))]
  74. class VariableClRebuildWorldSet(Variable):
  75. """
  76. List of action update world, rebuild world,
  77. """
  78. type = "bool"
  79. opt = ["--rebuild-world"]
  80. untrusted = True
  81. value = "off"
  82. def init(self):
  83. self.help = _("Rebuild world")
  84. self.label = _("Rebuild world")
  85. class VariableClUpdateRevSet(Variable):
  86. """
  87. List of action update world, rebuild world,
  88. """
  89. type = "bool"
  90. opt = ["--update-rev"]
  91. untrusted = True
  92. value = "on"
  93. check_after = ["cl_update_sync_rep",
  94. "cl_update_metadata_force",
  95. "cl_update_other_set",
  96. "cl_update_eixupdate_force"]
  97. def init(self):
  98. self.help = _("make a revision update")
  99. self.label = _("Make a revision update")
  100. class VariableClUpdateRep(Variable):
  101. """
  102. Обновлять репозитории до конкретной ревизии или до последней
  103. """
  104. type = "choice"
  105. value = "rev"
  106. def choice(self):
  107. return ["last", "rev"]
  108. class VariableClUpdateRepData(ReadonlyTableVariable):
  109. """
  110. Информация о репозиториях
  111. """
  112. source = ['cl_update_rep_name',
  113. 'cl_update_rep_url',
  114. 'cl_update_rep_path',
  115. 'cl_update_rep_rev']
  116. class VariableClUpdateRepName(Variable):
  117. """
  118. Список имен используемых репозиториев
  119. """
  120. type = "list"
  121. value = []
  122. class VariableClUpdateRepUrl(Variable):
  123. """
  124. Список путей до репозиториев
  125. """
  126. type = "list"
  127. value = []
  128. class VariableClUpdateLaymanConfig(ReadonlyVariable):
  129. """
  130. Объект конфига layman
  131. """
  132. type = "object"
  133. def get(self):
  134. chroot = self.Get('cl_chroot_path')
  135. cp = ConfigParser()
  136. cp.read(path.join(chroot, 'etc/layman/layman.cfg'))
  137. return cp
  138. class VariableClUpdateLaymanStorage(Variable):
  139. """
  140. Путь к репозиториям layman
  141. """
  142. param_name = "storage"
  143. fallback_value = "var/lib/layman"
  144. def get(self):
  145. cp = self.Get('cl_update_layman_config')
  146. res = cp.get('MAIN', self.param_name, fallback=self.fallback_value)
  147. return pathJoin(self.Get('cl_chroot_path'), res)
  148. class VariableClUpdateRepPath(ReadonlyVariable):
  149. """
  150. Пути до репозиториев
  151. """
  152. type = "list"
  153. mapPath = {'portage': 'usr/portage',
  154. 'gentoo': '/usr/portage'}
  155. def get(self):
  156. repPath = self.Get('cl_update_layman_storage')
  157. chroot_path = self.Get('cl_chroot_path')
  158. def generatePaths(names):
  159. for name in names:
  160. if name in self.mapPath:
  161. yield path.join(chroot_path, self.mapPath[name])
  162. else:
  163. yield path.join(repPath, name)
  164. return list(generatePaths(self.Get('cl_update_rep_name')))
  165. class VariableClUpdateRepRev(Variable):
  166. """
  167. Ревизии до которых необходимо обновить репозитории
  168. """
  169. type = "list"
  170. def get(self):
  171. cp = ConfigParser()
  172. revisions = self.Get('update.cl_update_binhost_revisions')
  173. if revisions:
  174. cp.read_string(unicode(revisions[0]))
  175. branch = self.Get('cl_update_branch')
  176. def generateBranch():
  177. for repname, branchname in zip(
  178. self.Get('cl_update_rep_name'),
  179. self.Get('cl_update_branch_name')):
  180. if branchname == Git.Reference.Tag:
  181. yield cp.get("vcs", repname, fallback=branch)
  182. else:
  183. yield branchname
  184. return list(generateBranch())
  185. class VariableClUpdateBranch(Variable):
  186. """
  187. Ветка на которую будет обновляться репозиторий если -getbinpkg
  188. """
  189. value = Git.Reference.Master
  190. class VariableClUpdateBranchData(TableVariable):
  191. """
  192. Выбор веток репозиториев до которых необходимо обновиться
  193. """
  194. opt = ["--branch"]
  195. metavalue = 'REFS'
  196. untrusted = True
  197. source = ["cl_update_branch_rep",
  198. "cl_update_branch_name"]
  199. def init(self):
  200. self.help = _("set references for repository (REPOSITORY:REF)")
  201. self.label = _("Repositories references")
  202. def raiseReadonlyIndexError(self, fieldname="", variablename="", value=""):
  203. """
  204. Неизвестный оврелей
  205. """
  206. raise VariableError(_("Repository %s not found") % value)
  207. class VariableClUpdateBranchRep(ReadonlyVariable):
  208. """
  209. Список доступных репозиторием
  210. """
  211. type = "list"
  212. def init(self):
  213. self.label = _("Repository")
  214. def get(self):
  215. return self.Get('cl_update_rep_name')
  216. class VariableClUpdateBinhostData(ReadonlyTableVariable):
  217. """
  218. Таблица содержащая
  219. binhost/содержимое файла ревизий/время доступа
  220. """
  221. source = ["cl_update_binhost_host",
  222. "cl_update_binhost_revisions",
  223. "cl_update_binhost_timestamp",
  224. "cl_update_binhost_time"]
  225. def get_logger(self, stub=False):
  226. class StubLogger(object):
  227. def info(self, message):
  228. pass
  229. if not stub and (not self.Get('cl_ebuild_phase')):
  230. # проверка на chroot_path
  231. return log("binhost-scan.log",
  232. filename=pathJoin(
  233. self.Get('cl_chroot_path'),
  234. "/var/log/calculate/binhost-scan.log"),
  235. formatter="%(message)s")
  236. else:
  237. return StubLogger()
  238. def get(self, hr=HumanReadable.No):
  239. last_ts = self.Get('cl_update_last_timestamp')
  240. binhosts_data = Binhosts(
  241. self.GetInteger('cl_update_binhost_timeout'),
  242. self.Get('cl_update_binhost_revision_path'),
  243. self.Get('cl_update_binhost_timestamp_path'),
  244. last_ts,
  245. self.Get('cl_update_binhost_list')
  246. )
  247. binhost = self.Get('cl_update_binhost')
  248. recheck = self.GetBool('cl_update_binhost_recheck_set')
  249. if not recheck and binhost:
  250. ts, t, good, downgrade = binhosts_data.get_timestamp(binhost)
  251. # условие актуальности текущего сервера
  252. if ts and good and not downgrade:
  253. data = binhosts_data.check_binhost(binhost)
  254. if data:
  255. return [[binhost, data, ts, str(t)]]
  256. logger = self.get_logger(stub=binhosts_data.is_cache())
  257. ret_val = None
  258. # TODO: важно еще сверу коммент
  259. # отладочная строка
  260. # необходимо разобраться почему calculate-builder вызывает
  261. # заполнение несколько раз!!!!!!!!!!!!
  262. logger.info("Started scan on: {date}, current timestamp: {ts}".format(
  263. date=time.ctime(), ts=last_ts))
  264. for host, ts, t, good, downgrade in binhosts_data.get_sorted():
  265. if ret_val is None:
  266. data = binhosts_data.check_binhost(host)
  267. else:
  268. data = ""
  269. if not good:
  270. reason = "OUTDATED"
  271. elif downgrade:
  272. reason = "SKIP"
  273. elif not data and ret_val is None:
  274. reason = "UPDATING"
  275. else:
  276. reason = ""
  277. logger.info("{host:<60} {speed:<7} {timestamp:<10} {reason}".format(
  278. host=host, speed=float(t) / 1000.0, timestamp=ts,
  279. reason=reason))
  280. if ret_val is None and data and not downgrade:
  281. ret_val = [[host, data, ts, str(t)]]
  282. return ret_val or [[]]
  283. class VariableClUpdateBinhostRecheckSet(Variable):
  284. """
  285. Принудительно обновить binhost
  286. """
  287. type = "bool"
  288. value = "off"
  289. opt = ["--scan"]
  290. def init(self):
  291. self.help = _("search for the most appropriate update server")
  292. self.label = _("Search for the most appropriate update server")
  293. class VariableClUpdateBinhostHost(FieldValue, ReadonlyVariable):
  294. """
  295. Список имен прочих репозиториев
  296. """
  297. type = "list"
  298. source_variable = "cl_update_binhost_data"
  299. column = 0
  300. class VariableClUpdateBinhostRevisions(FieldValue, ReadonlyVariable):
  301. """
  302. Список имен прочих репозиториев
  303. """
  304. type = "list"
  305. source_variable = "cl_update_binhost_data"
  306. column = 1
  307. class VariableClUpdateBinhostTimestamp(FieldValue, ReadonlyVariable):
  308. """
  309. Список имен прочих репозиториев
  310. """
  311. type = "list"
  312. source_variable = "cl_update_binhost_data"
  313. column = 2
  314. class VariableClUpdateLastTimestamp(ReadonlyVariable):
  315. """
  316. Текущий timestamp
  317. """
  318. def get(self):
  319. ini = SystemIni(self.parent)
  320. return ini.getVar('update', 'last_update') or "0"
  321. class VariableClUpdateBinhostTime(FieldValue, ReadonlyVariable):
  322. """
  323. Список имен прочих репозиториев
  324. """
  325. type = "list"
  326. source_variable = "cl_update_binhost_data"
  327. column = 3
  328. class VariableClUpdateBranchName(Variable):
  329. """
  330. Список доступных репозиторием
  331. """
  332. type = "choiceedit-list"
  333. def init(self):
  334. self.label = _("Reference")
  335. def choice(self):
  336. return [
  337. Git.Reference.Tag,
  338. Git.Reference.Master,
  339. Git.Reference.Develop,
  340. Git.Reference.Update]
  341. def get(self):
  342. if "getbinpkg" in self.Get('cl_features'):
  343. return [Git.Reference.Tag for x in self.Get('cl_update_rep_name')]
  344. else:
  345. branch = self.Get('cl_update_branch')
  346. return [branch for x in self.Get('cl_update_rep_name')]
  347. class VariableClUpdateSyncRep(Variable):
  348. """
  349. Обновляемый репозиторий
  350. """
  351. type = "choice-list"
  352. element = "selecttable"
  353. opt = ["-r", "--repositories"]
  354. metavalue = "REPOSITORIES"
  355. untrusted = True
  356. @property
  357. def rep_name(self):
  358. return self.Get('update.cl_update_rep_name')
  359. def init(self):
  360. self.help = _("synchronized repositories (all by default)")
  361. self.label = _("Synchronized repositories")
  362. def set(self, value):
  363. orderList = self.rep_name
  364. return sorted(value, key=lambda x:
  365. (orderList.index(x) if x in orderList else -1), reverse=True)
  366. def get(self):
  367. return list(reversed(self.rep_name))
  368. def choice(self):
  369. return self.rep_name
  370. class VariableClUpdateSyncOverlayRep(ReadonlyVariable):
  371. """
  372. Обновляемые репозитории (исключая portage)
  373. """
  374. type = "list"
  375. def get(self):
  376. return filter(lambda x: x != "portage", self.Get('cl_update_sync_rep'))
  377. class VariableClUpdateOutdateSet(ReadonlyVariable):
  378. """
  379. Флаг устанавливаемый в ходе обновления репозиториев,
  380. сообщающий что хотя бы один из запланированных репозиториев
  381. обновлен и следует обновляет различные метаданные
  382. Если обновляются прочие оверлеи - данные считаются что устарели
  383. """
  384. type = "bool"
  385. def get(self):
  386. if (self.Get('cl_update_other_set') == 'on' and
  387. self.Get('cl_update_other_rep_name')):
  388. return "on"
  389. return "off"
  390. class VariableClUpdateMetadataForce(Variable):
  391. """
  392. Принудительное действие с метаданными
  393. """
  394. type = "choice"
  395. value = "auto"
  396. opt = ["--update-metadata"]
  397. syntax = "--{choice}-update-metadata"
  398. metavalue = "MODE"
  399. # untrusted = True
  400. def init(self):
  401. self.help = ("'force' - " + _("force the update ebuilds metadata") +
  402. ",\n'skip' - " + _("skip the ebuild metadata update") +
  403. ",\n'auto' - " + _("update metadata if it is outdated"))
  404. self.label = _("Update metadata")
  405. def choice(self):
  406. return [("force", _("Force")),
  407. ("skip", _("Skip")),
  408. ("auto", _("If needed"))]
  409. class VariableClUpdateEgencacheForce(Variable):
  410. """
  411. Принудительное выполнение egencache
  412. """
  413. type = "choice"
  414. value = "auto"
  415. opt = ["--egencache"]
  416. syntax = "--{choice}-egencache"
  417. metavalue = "MODE"
  418. # untrusted = True
  419. def init(self):
  420. self.help = (
  421. "'force' - " + _("force the update of the overlays cache") +
  422. ",\n'skip' - " + _("skip the update of the overlays cache") +
  423. ",\n'auto' - " + _("update the overlays cache if outdated"))
  424. self.label = _("Update the overlays cache")
  425. def choice(self):
  426. return [("force", _("Force")),
  427. ("skip", _("Skip")),
  428. ("auto", _("If needed"))]
  429. class VariableClUpdateEixupdateForce(Variable):
  430. """
  431. Принудительное действие с eix-update
  432. """
  433. type = "choice"
  434. value = "auto"
  435. opt = ["--eix-update"]
  436. syntax = "--{choice}-eix-update"
  437. metavalue = "MODE"
  438. # untrusted = True
  439. def init(self):
  440. self.help = ("'force' - " + _("force the eix cache update") +
  441. ",\n'skip' - " + _("skip the eix cache update") +
  442. ",\n'auto' - " + _("update the eix cache if it "
  443. "is outdated"))
  444. self.label = _("Update the eix cache")
  445. def choice(self):
  446. return [("force", _("Force")),
  447. ("skip", _("Skip")),
  448. ("auto", _("If needed"))]
  449. class VariableClUpdateOtherSet(Variable):
  450. """
  451. Обновить остальные оверлеи
  452. """
  453. type = "bool"
  454. value = "off"
  455. opt = ["-o", "--update-other"]
  456. def init(self):
  457. self.help = _("update other overlays")
  458. self.label = _("Update other overlays")
  459. class VariableClUpdateOtherRepData(ReadonlyTableVariable):
  460. """
  461. Информация о прочих репозиториях
  462. """
  463. source = ['cl_update_other_rep_name',
  464. 'cl_update_other_rep_path']
  465. portdir_overlay = "main.cl_portdir_overlay"
  466. def generator(self):
  467. repNames = self.Get('update.cl_update_rep_name')
  468. chroot_path = self.Get('cl_chroot_path')
  469. layman = Layman(self.Get('update.cl_update_layman_installed'),
  470. self.Get('update.cl_update_layman_make'),
  471. self.Get('update.cl_update_layman_conf'),
  472. prefix=chroot_path)
  473. layman_overlays = layman.get_installed()
  474. for rpath in self.Get(self.portdir_overlay):
  475. repo_file = path.join(rpath, "profiles/repo_name")
  476. rname = readFile(repo_file).strip() or path.basename(rpath)
  477. if rname in layman_overlays and rname not in repNames:
  478. yield (rname, rpath)
  479. def get(self, hr=HumanReadable.No):
  480. return list(self.generator())
  481. class VariableClUpdateOtherRepName(FieldValue, ReadonlyVariable):
  482. """
  483. Список имен прочих репозиториев
  484. """
  485. type = "list"
  486. source_variable = "cl_update_other_rep_data"
  487. column = 0
  488. class VariableClUpdateOtherRepPath(FieldValue, ReadonlyVariable):
  489. """
  490. Список путей до прочих репозиториев
  491. """
  492. type = "list"
  493. source_variable = "cl_update_other_rep_data"
  494. column = 1
  495. class VariableClUpdateLaymanInstalled(VariableClUpdateLaymanStorage):
  496. """
  497. Путь до файла layman installed.xml
  498. """
  499. param_name = "installed"
  500. fallback_value = "var/lib/layman/installed.xml"
  501. class VariableClUpdateLaymanMake(VariableClUpdateLaymanStorage):
  502. """
  503. Путь до файла make.conf изменяемого layman`ом
  504. """
  505. param_name = "make_conf"
  506. fallback_value = "var/lib/layman/make.conf"
  507. class VariableClUpdateLaymanConf(VariableClUpdateLaymanStorage):
  508. """
  509. Путь до конфигурационного файла репозиториев для layman
  510. """
  511. param_name = "repos_conf"
  512. fallback_value = "etc/portage/repos.conf/layman.conf"
  513. class VariableClUpdatePretendSet(Variable):
  514. """
  515. Запустить предварительную проверку на обновления
  516. """
  517. type = "bool"
  518. value = "off"
  519. opt = ["-p", "--pretend"]
  520. def init(self):
  521. self.label = _("Pretend a package update")
  522. self.help = _("instead of actually performing the update, "
  523. "simply display the list of packages that "
  524. "will be installed")
  525. class VariableClUpdateSyncOnlySet(Variable):
  526. """
  527. Не выполнять установку/обновление пакетов при обновлении
  528. """
  529. type = "bool"
  530. value = "off"
  531. opt = ["-s", "--sync-only"]
  532. def init(self):
  533. self.label = _("Only synchronize repositories")
  534. self.help = _("do not update packages")
  535. def check(self, value):
  536. if (value == "on" and self.Get('cl_rebuild_world_set') != 'on' and
  537. not self.Get('cl_update_sync_rep') and
  538. self.Get('cl_update_other_set') == 'off' and
  539. self.Get('cl_update_rev_set') == 'off' and
  540. self.Get('cl_update_metadata_force') != "force" and
  541. self.Get('cl_update_eixupdate_force') != "force"):
  542. raise VariableError(_("Select at least one sync repository"))
  543. class VariableClUpdateWaitAnotherSet(Variable):
  544. """
  545. Ждать завершения другого процесса обновления
  546. """
  547. type = "bool"
  548. value = "on"
  549. opt = ["--wait-another-update"]
  550. def init(self):
  551. self.label = _("Wait for another update to be complete")
  552. self.help = _("wait until the running update is finished")
  553. class VariableClUpdateProfileStorage(ReadonlyVariable):
  554. type = "object"
  555. def get(self):
  556. return RepositoryStorageSet(
  557. LocalStorage('/var/lib/layman'),
  558. CacheStorage('/var/calculate/tmp/update'))
  559. class VariableClUpdateRepHost(Variable):
  560. type = "list"
  561. value = ['calculate']
  562. class VariableClUpdateRepHostUrl(Variable):
  563. type = "list"
  564. value = ['git://git.calculate.ru/calculate/%s.git']
  565. class VariableClUpdateProfileDatavars(ReadonlyVariable):
  566. type = "object"
  567. profile = "cl_update_profile_system"
  568. profiles_path = "cl_update_profile_path"
  569. profiles_shortname = "cl_update_profile_shortname"
  570. def get(self):
  571. profile = self.Get(self.profile)
  572. path_profile = self.Select(self.profiles_path,
  573. where=self.profiles_shortname,
  574. eq=profile, limit=1)
  575. if path_profile:
  576. return DataVarsUpdateProfile(path_profile)
  577. return ""
  578. class VariableClUpdateProfileLinuxFullname(ReadonlyVariable):
  579. """
  580. Имя системы в профиле
  581. """
  582. def init(self):
  583. self.label = _("Distribution name")
  584. datavars = "cl_update_profile_datavars"
  585. def get(self):
  586. dv = self.Get(self.datavars)
  587. if dv:
  588. try:
  589. subname = dv.Get('os_linux_subname')
  590. linuxname = dv.Get('os_linux_name')
  591. linuxver = dv.Get('os_linux_ver')
  592. if subname:
  593. return "%s %s %s" % (linuxname, linuxver, subname)
  594. return "%s %s" % (linuxname, linuxver)
  595. except DataVarsError as s:
  596. raise VariableError("Wrong Calculate Linux profile")
  597. return ""
  598. class VariableClUpdateProfileDependData(ReadonlyTableVariable):
  599. """
  600. Зависимые репозитории
  601. """
  602. source = ['cl_update_profile_depend_name',
  603. 'cl_update_profile_depend_url']
  604. datavars = "cl_update_profile_datavars"
  605. def init(self):
  606. self.label = _("Used repositories")
  607. @staticmethod
  608. def url_like(url1, url2):
  609. match1 = VariableClUpdateProfileUrl.re_url.search(url1)
  610. match2 = VariableClUpdateProfileUrl.re_url.search(url2)
  611. if match1 and match2:
  612. return match1.group(2).lower() == match2.group(2).lower()
  613. return False
  614. def get(self, hr=HumanReadable.No):
  615. dv = self.Get(self.datavars)
  616. # TODO: неиспользуемая переменная возможно
  617. # испольуется для инициализации
  618. # url = self.Get('cl_update_profile_url').lower()
  619. if dv:
  620. return reversed(zip(dv.Get('cl_update_rep_name'),
  621. dv.Get('cl_update_rep_url')))
  622. return ""
  623. setValue = Variable.setValue
  624. class VariableClUpdateTemplatesLocate(Variable):
  625. """
  626. Выбранные типы хранилищ шаблонов
  627. """
  628. type = "choice-list"
  629. element = "selecttable"
  630. opt = ["-T", "--templates"]
  631. metavalue = "TEMPLATES"
  632. untrusted = True
  633. check_after = ['cl_update_profile_system']
  634. profile_datevars = "update.cl_update_profile_datavars"
  635. descriptionMap = {'overlay': _('Overlay templates'),
  636. 'local': _('Local templates'),
  637. 'calculate': _("Calculate overlay templates"),
  638. 'distros': _('Distribution templates'),
  639. 'distro': _('Distribution templates'),
  640. 'remote': _('Remote templates'),
  641. 'clt': _('clt templates')}
  642. def init(self):
  643. self.label = _("Templates location")
  644. self.help = _("select the location for templates %s") \
  645. % ",".join(self.get())
  646. def get(self):
  647. dv = self.Get(self.profile_datevars)
  648. if dv:
  649. return dv.Get('cl_template_location') + ['clt']
  650. else:
  651. return self.Get('cl_templates_locate')
  652. def choice(self):
  653. descr = lambda x: self.descriptionMap.get(x,
  654. _("%s overlay templates" % x))
  655. return map(lambda x: (x, descr(x)), self.get())
  656. class VariableClUpdateProfileDependName(FieldValue, ReadonlyVariable):
  657. type = "list"
  658. source_variable = "cl_update_profile_depend_data"
  659. column = 0
  660. def init(self):
  661. self.label = _("Name")
  662. class VariableClUpdateProfileDependUrl(FieldValue, ReadonlyVariable):
  663. type = "list"
  664. source_variable = "cl_update_profile_depend_data"
  665. column = 1
  666. def init(self):
  667. self.label = _("URL")
  668. class VariableClUpdateProfileRepName(ReadonlyVariable):
  669. type = "list"
  670. def get(self):
  671. dv = self.Get('cl_update_profile_datavars')
  672. if dv:
  673. return dv.Get('cl_update_rep_name')
  674. return []
  675. class VariableClUpdateProfileSyncRep(ReadonlyVariable):
  676. type = "list"
  677. def get(self):
  678. return list(reversed(self.Get('cl_update_profile_rep_name')))
  679. class VariableClUpdateProfileRepUrl(ReadonlyVariable):
  680. type = "list"
  681. def get(self):
  682. dv = self.Get('cl_update_profile_datavars')
  683. if dv:
  684. return dv.Get('cl_update_rep_url')
  685. return []
  686. class VariableClUpdateProfileLinuxVer(ReadonlyVariable):
  687. """
  688. Имя системы в профиле
  689. """
  690. def init(self):
  691. self.label = _("System profile version")
  692. def get(self):
  693. dv = self.Get('cl_update_profile_datavars')
  694. if dv:
  695. return dv.Get('os_linux_ver')
  696. return ""
  697. class VariableClUpdateProfileLinuxName(ReadonlyVariable):
  698. """
  699. Имя системы в профиле
  700. """
  701. def get(self):
  702. dv = self.Get('cl_update_profile_datavars')
  703. if dv:
  704. dv.Get('os_linux_name')
  705. return ""
  706. class VariableClUpdateProfileUrl(Variable):
  707. """
  708. URL текущего репозитория
  709. """
  710. untrusted = True
  711. check_after = ["cl_update_profile_branch"]
  712. opt = ["--url"]
  713. metavalue = "URL"
  714. profile = "cl_profile_system"
  715. branch = "cl_update_profile_branch"
  716. storage = "cl_update_profile_storage"
  717. default_url = "git://git.calculate.ru/calculate/distros.git"
  718. profiles_shortname = 'cl_update_profile_shortname'
  719. @property
  720. def current_root(self):
  721. return '/'
  722. def init(self):
  723. self.label = _("Profile repository")
  724. self.help = _("set the profile repository")
  725. re_url = re.compile(
  726. r"^(?:(%s)://)?(\w[\w\./:-]+?\w)(\.git)?$" % "|".join(
  727. ["http", "https", "git"]))
  728. re_shortname = re.compile('^(?:([\w\.-]+):)?([\w\.-]+)$')
  729. @classmethod
  730. def normalize_url(cls, url):
  731. match = cls.re_url.match(url)
  732. if not match:
  733. raise VariableError(_("Wrong repository URL"))
  734. url = match.group(2)
  735. url = "%s://%s" % (match.group(1) or "git", url)
  736. url = "%s.git" % url
  737. return url
  738. def url_by_shortname(self, value):
  739. match = self.re_shortname.match(value)
  740. if not match.group(1):
  741. template = self.Get('update.cl_update_rep_host_url')
  742. if template:
  743. template = template[0]
  744. else:
  745. template = self.Select('update.cl_update_rep_host_url',
  746. where='update.cl_update_rep_host',
  747. eq=match.group(1), limit=1)
  748. if not template:
  749. raise VariableError(_("Failed to determine the repository host"))
  750. try:
  751. return template % match.group(2)
  752. except TypeError:
  753. raise VariableError(_("Failed to determine the repository host"))
  754. def set(self, value):
  755. if self.re_shortname.match(value):
  756. value = self.url_by_shortname(value)
  757. return self.normalize_url(value)
  758. def check(self, value):
  759. if not value:
  760. raise VariableError("Need to specify profile repository")
  761. try:
  762. branch = self.Get(self.branch)
  763. self.Get(self.storage).get_profiles(value, branch)
  764. except GitError as e:
  765. raise VariableError(str(e))
  766. if not self.Get(self.profiles_shortname):
  767. raise VariableError(_("Repository %s has no profiles") % value)
  768. def get(self):
  769. try:
  770. profile = self.Get(self.profile)
  771. if profile:
  772. while (profile != self.current_root and
  773. ".git" not in listDirectory(profile)):
  774. profile = path.dirname(profile)
  775. if profile == self.current_root:
  776. return ""
  777. git = Git()
  778. return git.get_url(profile, "origin") or ""
  779. except Exception:
  780. pass
  781. return self.default_url
  782. class VariableClUpdateProfileRepoName(ReadonlyVariable):
  783. def init(self):
  784. self.label = _("Repository name")
  785. storage = "cl_update_profile_storage"
  786. url = "cl_update_profile_url"
  787. def get(self):
  788. rep_set = self.Get(self.storage)
  789. url = self.Get(self.url)
  790. rep = rep_set.get_repository(url, branch=None)
  791. if rep:
  792. return rep.repo_name
  793. return ""
  794. class VariableClUpdateProfileBranch(Variable):
  795. """
  796. Текущий репозиторий
  797. """
  798. untrusted = True
  799. type = "edit"
  800. opt = ["--branch"]
  801. metavalue = "BRANCH"
  802. storage = "cl_update_profile_storage"
  803. url = "cl_update_profile_url"
  804. value = DEFAULT_BRANCH
  805. def init(self):
  806. self.label = _("Repository branch")
  807. self.help = _("set the repository branch")
  808. def check(self, value):
  809. pass
  810. ## TODO: проверка ветки
  811. # try:
  812. # url = self.Get('cl_update_profile_url')
  813. # self.Get('cl_update_profile_storage').get_profiles(url, value)
  814. # except GitError as e:
  815. # raise VariableError(str(e))
  816. class VariableClProfileRepository(ReadonlyVariable):
  817. """
  818. Репозиторий из которого будут получены профили
  819. """
  820. type = "object"
  821. def get(self):
  822. try:
  823. profile_dn = self.Get('cl_profile_system')
  824. while profile_dn != '/' and ".git" not in listDirectory(profile_dn):
  825. profile_dn = path.dirname(profile_dn)
  826. if profile_dn == '/':
  827. return ""
  828. ls = LocalStorage(path.dirname(profile_dn))
  829. return ProfileRepository(path.basename(profile_dn), ls)
  830. except Exception:
  831. return ""
  832. class VariableClProfileData(ReadonlyTableVariable):
  833. """
  834. Таблица данных о текущих профилях системы
  835. """
  836. source = []
  837. repository = "cl_profile_repository"
  838. def profile_filter(self, profiles):
  839. arch = self.Get('os_arch_machine_gentoo')
  840. return [x for x in profiles if x.arch == arch]
  841. def get(self, hr=HumanReadable.No):
  842. rep = self.Get(self.repository)
  843. if not rep:
  844. return [[]]
  845. profiles = rep.get_profiles()
  846. if not profiles:
  847. return [[]]
  848. repo_name = profiles[0].repository.repo_name
  849. filtered_profiles = self.profile_filter(profiles)
  850. full_name = [x.profile for x in filtered_profiles]
  851. profile_path = [x.path for x in filtered_profiles]
  852. profile_arch = [x.arch for x in filtered_profiles]
  853. short_name = simplify_profiles(full_name)
  854. full_name = ["%s:%s" % (repo_name, x) for x in full_name]
  855. return zip(full_name,
  856. short_name,
  857. profile_path,
  858. profile_arch)
  859. setValue = Variable.setValue
  860. class VariableClUpdateProfileRepository(ReadonlyVariable):
  861. """
  862. Репозиторий из которого будет извлечён список профилей
  863. """
  864. type = "object"
  865. url = "cl_update_profile_url"
  866. storage = "cl_update_profile_storage"
  867. branch = "cl_update_profile_branch"
  868. sync_set = "update.cl_update_profile_sync_set"
  869. def get(self):
  870. url = self.Get(self.url)
  871. if not url:
  872. return ""
  873. try:
  874. rep_set = self.Get(self.storage)
  875. branch = self.Get(self.branch)
  876. rep = rep_set.get_repository(url, branch)
  877. if rep and self.Get(self.sync_set) == 'on':
  878. rep.sync()
  879. return rep_set.get_repository(url, branch) or ""
  880. except GitError:
  881. return ""
  882. class VariableClUpdateProfileRepositoryName(ReadonlyVariable):
  883. """
  884. Название репозитория, из которого будут извлечены профили
  885. """
  886. def get(self):
  887. rep = self.Get('cl_update_profile_repository')
  888. if rep:
  889. return rep.repo_name
  890. return ""
  891. class VariableClUpdateProfileData(VariableClProfileData):
  892. source = ["cl_update_profile_fullname",
  893. "cl_update_profile_shortname",
  894. "cl_update_profile_path",
  895. "cl_update_profile_arch"]
  896. repository = "cl_update_profile_repository"
  897. class VariableClUpdateProfileFullname(FieldValue, ReadonlyVariable):
  898. """
  899. Полное название профиля
  900. """
  901. type = "list"
  902. source_variable = "cl_update_profile_data"
  903. column = 0
  904. class VariableClUpdateProfileShortname(FieldValue, ReadonlyVariable):
  905. """
  906. Упрощенное название профиля
  907. """
  908. type = "list"
  909. source_variable = "cl_update_profile_data"
  910. column = 1
  911. class VariableClUpdateProfilePath(FieldValue, ReadonlyVariable):
  912. """
  913. Путь от корня до профиля
  914. """
  915. type = "list"
  916. source_variable = "cl_update_profile_data"
  917. column = 2
  918. class VariableClUpdateProfileArch(FieldValue, ReadonlyVariable):
  919. """
  920. Архитектура профиля
  921. """
  922. type = "list"
  923. source_variable = "cl_update_profile_data"
  924. column = 3
  925. class VariableClUpdateProfileSystem(Variable):
  926. """
  927. Профиль системы (симлинк /etc/make.profile')
  928. """
  929. type = "choice"
  930. opt = ["cl_update_profile_system"]
  931. untrusted = True
  932. metavalue = "PROFILE"
  933. profiles_path = "cl_update_profile_path"
  934. profiles_shortname = "cl_update_profile_shortname"
  935. profiles_fullname = "cl_update_profile_fullname"
  936. profiles_arch = "cl_update_profile_arch"
  937. profile = "cl_profile_system"
  938. url = "cl_update_profile_url"
  939. gentoo_arch = 'os_arch_machine_gentoo'
  940. def init(self):
  941. self.label = _("System profile")
  942. self.help = _("set the system profile")
  943. def check(self, profile):
  944. if not profile:
  945. raise VariableError(_("You must specify the profile"))
  946. path_profile = self.Select(self.profiles_path,
  947. where=self.profiles_shortname,
  948. eq=profile, limit=1)
  949. profile_fullname = self.Select(self.profiles_fullname,
  950. where=self.profiles_shortname,
  951. eq=profile, limit=1)
  952. if path_profile:
  953. dv = DataVarsUpdateProfile(path_profile)
  954. if ":" in profile_fullname:
  955. repo_name = profile_fullname.partition(":")[0]
  956. else:
  957. repo_name = ""
  958. try:
  959. if (not dv.Get('cl_update_rep_name') or
  960. not dv.Get('cl_update_rep_url')):
  961. raise VariableError(
  962. _("Repository variables "
  963. "were not configured for the profile"))
  964. if not dv.Get('os_linux_name'):
  965. raise VariableError("")
  966. if repo_name not in list(dv.Get('cl_update_rep_name')):
  967. raise VariableError(
  968. _("Overlay %s is not specified "
  969. "in cl_update_rep_name") % repo_name)
  970. except (DataVarsError, VariableError) as e:
  971. if str(e):
  972. message = ". " + str(e)
  973. else:
  974. message = ""
  975. raise VariableError(_("The selected profile is not Calculate")
  976. + message)
  977. else:
  978. raise VariableError(_("Wrong Calculate profile"))
  979. def get(self):
  980. try:
  981. profile_system = self.Get(self.profile)
  982. profile = self.Select(self.profiles_shortname,
  983. where=self.profiles_path,
  984. eq=profile_system, limit=1)
  985. if profile:
  986. return profile
  987. except VariableError:
  988. pass
  989. shortname = self.Get(self.profiles_shortname)
  990. if len(shortname) == 1:
  991. return shortname[0]
  992. return ""
  993. def choice(self):
  994. url = self.Get(self.url)
  995. if not url:
  996. return []
  997. arch = self.Get(self.gentoo_arch)
  998. profiles = zip(*self.Select([self.profiles_shortname,
  999. self.profiles_fullname],
  1000. where=self.profiles_arch, eq=arch))
  1001. if profiles:
  1002. short_name, full_name = profiles
  1003. return zip(short_name, full_name)
  1004. return []
  1005. class DataVarsUpdateProfile(SimpleDataVars):
  1006. """
  1007. Упрощенная модель переменных для получения данных с удаленного профиля
  1008. """
  1009. source = ['cl_update_rep_name',
  1010. 'cl_update_rep_url',
  1011. 'cl_update_rep_path',
  1012. 'cl_update_rep_rev',
  1013. 'cl_update_branch_name']
  1014. def __init__(self, profile, chroot_path='/', recheck=None):
  1015. SimpleDataVars.__init__(
  1016. self,
  1017. lib_linux.VariableOsLinuxName(),
  1018. lib_linux.VariableOsLinuxShortname(),
  1019. lib_linux.VariableOsLinuxSubname(),
  1020. lib_linux.VariableOsLinuxVer(),
  1021. lib_linux.VariableClProfileSystem(),
  1022. env.VariableClRepositoryData(),
  1023. env.VariableClRepositoryName(),
  1024. env.VariableClRepositoryLocation(),
  1025. env.VariableClChrootPath(),
  1026. env.VariableClTemplateLocation(),
  1027. env.VariableClTemplatePath(),
  1028. env.VariableClEmergeConfig(systemRoot=chroot_path),
  1029. env.VariableClFeatures(),
  1030. env.VariableClEbuildPhase(),
  1031. VariableClUpdateRepData(section="update"),
  1032. VariableClUpdateRepPath(section="update"),
  1033. VariableClUpdateRepRev(section="update"),
  1034. VariableClUpdateBranch(section="update"),
  1035. VariableClUpdateBranchName(section="update"),
  1036. VariableClUpdateLaymanConfig(section="update"),
  1037. VariableClUpdateLaymanStorage(section="update"),
  1038. VariableClUpdateRepName(section="update"),
  1039. VariableClUpdateRep(section="update"),
  1040. VariableClUpdateRepUrl(section="update"),
  1041. VariableClUpdateBinhost(section="update"),
  1042. VariableClUpdateBinhostData(section="update"),
  1043. VariableClUpdateBinhostHost(section="update"),
  1044. VariableClUpdateBinhostRecheckSet(section="update"),
  1045. VariableClUpdateBinhostRevisions(section="update"),
  1046. VariableClUpdateBinhostTime(section="update"),
  1047. VariableClUpdateBinhostTimestamp(section="update"),
  1048. VariableClUpdateLastTimestamp(section="update"),
  1049. VariableClUpdateBinhostTimeout(section="update"),
  1050. VariableClUpdateBinhostTimestampPath(section="update"),
  1051. VariableClUpdateBinhostList(section="update"),
  1052. VariableClUpdateBinhostRevisionPath(section="update"),
  1053. )
  1054. self['cl_profile_system'] = profile
  1055. self['cl_chroot_path'] = chroot_path
  1056. if recheck is not None:
  1057. self['cl_update_binhost_recheck_set'] = recheck
  1058. self.flIniFileFrom(profile)
  1059. def __repr__(self):
  1060. return "Profile variables"
  1061. class VariableClUpdateProfileSyncSet(Variable):
  1062. """
  1063. Синхронизировать репозиторий перед сменой профиля
  1064. """
  1065. type = "bool"
  1066. value = "off"
  1067. opt = ["-u", "--update-cache"]
  1068. def init(self):
  1069. self.label = _("Update the cache")
  1070. self.help = _("Update the cache")
  1071. class VariableClUpdateAutocheckSet(Variable):
  1072. """
  1073. Выполнять/невыполнять автопроверку обновлений
  1074. """
  1075. type = "bool"
  1076. value = "on"
  1077. opt = ["-a", "--autocheck"]
  1078. def init(self):
  1079. self.label = _("Automatically check updates")
  1080. self.help = _("automatically check updates")
  1081. class VariableClUpdateAutocheckInterval(Variable):
  1082. """
  1083. Интервал выполнения проверки
  1084. """
  1085. type = "choiceedit"
  1086. opt = ["-I", "--autocheck-interval"]
  1087. metavalue = "INTERVAL"
  1088. def init(self):
  1089. self.label = _("Interval for the updates checking")
  1090. self.help = _("set interval for the updates checking")
  1091. def choice(self):
  1092. return [["6h", _("every six hours")],
  1093. ["12h", _("every twelve hours")],
  1094. ["1d", _("daily")]]
  1095. class VariableClUpdateAutocheckScheduleSet(Variable):
  1096. """
  1097. Запустить проверку только если со времени последнего запуска прошло
  1098. необходимое время
  1099. """
  1100. type = "bool"
  1101. value = "off"
  1102. opt = ["--schedule"]
  1103. def init(self):
  1104. self.label = _("Consider the autocheck schedule")
  1105. self.help = _("consider the autocheck schedule")
  1106. class VariableClUpdateEmergelistSet(Variable):
  1107. """
  1108. Вывести список пакетов в формате emerge
  1109. """
  1110. type = "bool"
  1111. value = "off"
  1112. opt = ["-e", "--emergelist"]
  1113. def init(self):
  1114. self.label = _("Emerge-like packages list")
  1115. self.help = _("display the packages list in emerge format")
  1116. class VariableClUpdateKernelVersion(ReadonlyVariable):
  1117. """
  1118. Текущая версия ядра
  1119. """
  1120. def get(self):
  1121. return process('/bin/uname', '-r').read().strip()
  1122. class VariableClUpdateKernelSrcPath(ReadonlyVariable):
  1123. """
  1124. Каталог содержащий исходный код текущего ядра
  1125. """
  1126. def get(self):
  1127. kernel_ver = self.Get('cl_update_kernel_version')
  1128. for template_path in ("/lib/modules/%s/build",
  1129. "/usr/src/linux-%s"):
  1130. src_path = template_path % kernel_ver
  1131. if path.exists(src_path):
  1132. if path.islink(src_path):
  1133. return os.readlink(src_path)
  1134. else:
  1135. return src_path
  1136. else:
  1137. return ""
  1138. class VariableClUpdateKernelPkg(ReadonlyVariable):
  1139. """
  1140. Пакет текущего ядра
  1141. """
  1142. def get(self):
  1143. src_path = self.Get('cl_update_kernel_src_path')
  1144. if src_path:
  1145. qfile = process('/usr/bin/qfile', '-vC', src_path)
  1146. if qfile.success():
  1147. return qfile.read().partition(" ")[0]
  1148. return ""
  1149. class VariableClUpdateLinesLimit(Variable):
  1150. """
  1151. Количество выводимых строк при ошибке
  1152. """
  1153. type = "int"
  1154. value = "30"
  1155. class VariableClUpdateSkipSetupSet(Variable):
  1156. """
  1157. Пропустить выполнение cl-setup-system в cl-update-profile
  1158. """
  1159. type = "bool"
  1160. value = "off"
  1161. opt = ["--skip-setup-system"]
  1162. def init(self):
  1163. self.label = _("Skip the system setup")
  1164. self.help = _("skip the system setup")
  1165. class VariableClUpdateCleanpkgSet(Variable):
  1166. """
  1167. Пропустить выполнение cl-setup-system в cl-update-profile
  1168. """
  1169. type = "bool"
  1170. value = "off"
  1171. opt = ["--clean-pkg"]
  1172. def init(self):
  1173. self.label = _("Clean obsolete programs archives")
  1174. self.help = _("clean obsolete programs archives")
  1175. class VariableClUpdateOutdatedKernelPath(Variable):
  1176. """
  1177. Файл-флаг наличия устаревшего, неудаленного ядра
  1178. """
  1179. value = "/var/lib/calculate/calculate-update/outdated_kernel"
  1180. class VariableClUpdateSkipRbSet(Variable):
  1181. """
  1182. Пропусить revdep-rebuild
  1183. """
  1184. type = "bool"
  1185. value = "off"
  1186. opt = ["-R", "--skip-revdep-rebuild"]
  1187. def init(self):
  1188. self.label = _("Skip reverse dependencies check")
  1189. self.help = _("skip reverse dependencies check")
  1190. class VariableClUpdateOutdatedKernelSet(ReadonlyVariable):
  1191. """
  1192. Есть наличие устаревшего ядра
  1193. """
  1194. type = "bool"
  1195. def get(self):
  1196. ui = UpdateInfo(self.parent)
  1197. return "on" if ui.outdated_kernel else "off"
  1198. class VariableClUpdateBinhostList(Variable):
  1199. """
  1200. Список хостов с бинарными обновлениями
  1201. """
  1202. type = "list"
  1203. value = ["ftp://ftp.calculate-linux.ru/pub/calculate"]
  1204. class VariableClUpdateBinhost(Variable):
  1205. """
  1206. Хост с бинарными обновлениями
  1207. """
  1208. value = ""
  1209. class VariableClUpdateBinhostRevisionPath(Variable):
  1210. """
  1211. Путь до revisions файлов
  1212. """
  1213. type = "list"
  1214. value = [
  1215. "grp/default/ini.env",
  1216. "grp/kde/ini.env",
  1217. "grp/server/ini.env",
  1218. "grp/x/ini.env"
  1219. ]
  1220. class VariableClUpdateBinhostTimestampPath(Variable):
  1221. """
  1222. Путь до файла timestamp
  1223. """
  1224. value = "timestamp"
  1225. class VariableClUpdateBinhostTimeout(Variable):
  1226. """
  1227. Таймаут на проверку одного binhost
  1228. """
  1229. type = "int"
  1230. value = "5"
  1231. class VariableClUpdateCheckRepSet(Variable):
  1232. """
  1233. Удлять лишние файлы из репозиториев (например созданные пользователем)
  1234. """
  1235. type = "bool"
  1236. value = "off"
  1237. opt = ["--check-repos", "-C"]
  1238. def init(self):
  1239. self.label = _("Check the repositories integrity")
  1240. self.help = _("check and fix the repositories integrity")
  1241. class VariableClUpdateOnedepthSet(Variable):
  1242. """
  1243. Удлять лишние файлы из репозиториев (например созданные пользователем)
  1244. """
  1245. type = "bool"
  1246. value = "off"
  1247. opt = ["--one-depth", "-1"]
  1248. def init(self):
  1249. self.label = _("Clear the history of repositories")
  1250. self.help = _("clear the history of repositories")
  1251. class VariableClUpdateEixRepositories(ReadonlyVariable):
  1252. """
  1253. Отображаемый список обновляемых репозиториев eix
  1254. """
  1255. def get(self):
  1256. return ", ".join(
  1257. x for x in chain(
  1258. reversed(self.Get('update.cl_update_rep_name')),
  1259. self.Get('update.cl_update_other_rep_name')))