Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

269 linhas
8.8 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-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 sys
  16. import os
  17. from os import path
  18. import shutil
  19. from calculate.lib.utils.files import (listDirectory, readFile, readLinesFile,
  20. makeDirectory, removeDir)
  21. from calculate.lib.utils.git import Git
  22. from update import UpdateError
  23. from calculate.lib.cl_lang import setLocalTranslate, _
  24. setLocalTranslate('cl_update3', sys.modules[__name__])
  25. DEFAULT_BRANCH = Git.Reference.Master
  26. class RepositoryStorageInterface(object):
  27. def __iter__(self):
  28. raise StopIteration
  29. def get_profiles(self, url, branch=DEFAULT_BRANCH):
  30. return []
  31. def get_repository(self, url, branch=DEFAULT_BRANCH):
  32. return None
  33. class RepositoryStorage(RepositoryStorageInterface):
  34. directory = '/tmp'
  35. def __init__(self, git, directory):
  36. self.directory = directory
  37. self.git = git
  38. makeDirectory(directory)
  39. def __iter__(self):
  40. for dn in listDirectory(self.directory, onlyDir=True, fullPath=True):
  41. if self.git.is_git(dn):
  42. yield ProfileRepository(self.git, path.basename(dn), self)
  43. def get_profiles(self, url, branch=DEFAULT_BRANCH):
  44. return []
  45. def get_repository(self, url, branch=DEFAULT_BRANCH):
  46. return None
  47. class ProfileStorage(RepositoryStorage):
  48. def get_profiles(self, url, branch=DEFAULT_BRANCH):
  49. rep = self.get_repository(url, branch)
  50. if rep:
  51. return rep.get_profiles()
  52. return None
  53. def get_repository(self, url, branch=DEFAULT_BRANCH):
  54. return None
  55. class LocalStorage(ProfileStorage):
  56. """
  57. Локальное хранилище репозиториев, при запросе по урлу смотрит, доступные
  58. репозитории если находит подходящий - возвращает его профили
  59. """
  60. def get_repository(self, url, branch=DEFAULT_BRANCH):
  61. for rep in self:
  62. if rep.is_like(url, branch):
  63. return rep
  64. class CacheStorage(ProfileStorage):
  65. """
  66. Хранилище репозиториев, при запросе по урлу смотрит, доступные
  67. репозитории если находит подходящий - возвращает его профили,
  68. если не находит - скачивает и возвращает профили
  69. """
  70. def get_repository(self, url, branch=DEFAULT_BRANCH):
  71. for rep in self:
  72. if rep.is_like(url, branch):
  73. return rep
  74. else:
  75. return ProfileRepository.clone(self.git, url, self,
  76. branch or DEFAULT_BRANCH)
  77. class RepositoryStorageSet(RepositoryStorageInterface):
  78. """
  79. Набор хранилищ репозиториев
  80. """
  81. def __init__(self, *storages):
  82. self.storages = storages
  83. def get_profiles(self, url, branch=DEFAULT_BRANCH):
  84. """
  85. Получить профили из указанного репозитория
  86. """
  87. for storage in self.storages:
  88. profiles = storage.get_profiles(url, branch)
  89. if profiles is not None:
  90. return profiles
  91. return None
  92. def __iter__(self):
  93. for storage in self.storages:
  94. for rep in storage:
  95. yield rep
  96. def get_repository(self, url, branch=DEFAULT_BRANCH):
  97. """
  98. Получить репозиторий по параметрам
  99. """
  100. for rep in self:
  101. if rep.is_like(url, branch):
  102. return rep
  103. for storage in self.storages:
  104. rep = storage.get_repository(url, branch)
  105. if rep:
  106. return rep
  107. return None
  108. def is_local(self, url, branch=DEFAULT_BRANCH):
  109. """
  110. Проверить является ли репозиторий с указанными параметрами
  111. локальным
  112. """
  113. rep = self.get_repository(url, branch)
  114. if rep and isinstance(rep.storage, LocalStorage):
  115. return True
  116. return False
  117. def __repr__(self):
  118. return "Repository set"
  119. class Profile(object):
  120. """
  121. Профиль репозитория
  122. """
  123. available_arch = ["amd64", "x86"]
  124. def __init__(self, repository, profile, arch):
  125. self.repository = repository
  126. self.profile = profile
  127. self.arch = arch
  128. @property
  129. def path(self):
  130. return path.join(self.repository.directory,"profiles", self.profile)
  131. @classmethod
  132. def from_string(cls, repository, s):
  133. parts = filter(None, s.split())
  134. if len(parts) == 3 and parts[0] in cls.available_arch:
  135. return Profile(repository, parts[1], parts[0])
  136. return None
  137. def __repr__(self):
  138. return "<Profile (%s) %s:%s from %s>" % (self.arch,
  139. self.repository.repo_name,
  140. self.profile,
  141. self.repository.directory)
  142. class ProfileRepository(object):
  143. """
  144. Репозиторий либо скачивается, либо берется из кэша
  145. """
  146. def __init__(self, git, name, storage):
  147. self._storage = storage
  148. self.name = name
  149. self.git = git
  150. @property
  151. def storage(self):
  152. return self._storage
  153. @storage.setter
  154. def storage(self, storage):
  155. if storage.directory != self._storage.directory:
  156. newpath = path.join(storage.directory, self.name)
  157. if self.directory == newpath:
  158. return
  159. try:
  160. if path.exists(newpath):
  161. removeDir(newpath)
  162. shutil.move(self.directory, newpath)
  163. self._storage = storage
  164. except OSError as e:
  165. raise UpdateError(_("Failed to move the profile: %s") %
  166. str(e))
  167. @classmethod
  168. def clone(cls, git, url, storage, branch=DEFAULT_BRANCH):
  169. name = path.basename(url)
  170. if name.endswith(".git"):
  171. name = name[:-4]
  172. rpath = path.join(storage.directory, name)
  173. if path.exists(rpath):
  174. removeDir(rpath)
  175. if git.is_private_url(url):
  176. try:
  177. makeDirectory(rpath)
  178. os.chmod(rpath, 0700)
  179. except OSError:
  180. pass
  181. git.cloneRepository(url, rpath, branch)
  182. pr = cls(git, name, storage)
  183. repo_name = pr.repo_name
  184. if name != repo_name:
  185. rpath_new = path.join(storage.directory, repo_name)
  186. if path.exists(rpath_new):
  187. removeDir(rpath_new)
  188. shutil.move(rpath, rpath_new)
  189. pr = cls(git, repo_name, storage)
  190. return pr
  191. @property
  192. def repo_name(self):
  193. return readFile(path.join(self.directory,
  194. "profiles/repo_name")).strip()
  195. def is_like(self, url, branch=DEFAULT_BRANCH):
  196. if self.url == url and (branch is None or self.branch == branch):
  197. return True
  198. return False
  199. @property
  200. def directory(self):
  201. """
  202. Получить локальную директорию на данные репозитория
  203. """
  204. return path.join(self.storage.directory, self.name)
  205. @property
  206. def url(self):
  207. return self.git.get_url(self.directory, "origin")
  208. @property
  209. def branch(self):
  210. return self.git.getBranch(self.directory)
  211. def sync(self):
  212. """
  213. Синхронизировать репозиторий
  214. """
  215. if not self.git.pullRepository(self.directory, quiet_error=True):
  216. self.git.resetRepository(self.directory, to_origin=True)
  217. self.git.pullRepository(self.directory, quiet_error=True)
  218. def get_profiles(self):
  219. """
  220. Получить список профилей репозитория
  221. """
  222. profiles_desc = path.join(self.directory, "profiles/profiles.desc")
  223. return filter(None, (Profile.from_string(self, line)
  224. for line in readLinesFile(profiles_desc)))
  225. def __repr__(self):
  226. return "<ProfileRepository %s url=%s>" % (self.directory, self.url)