1 |
commit: 57baa89e8bd8da906c8a001c92c7354635715b93 |
2 |
Author: Slava Bacherikov <slava <AT> bacher09 <DOT> org> |
3 |
AuthorDate: Wed Jun 6 20:39:37 2012 +0000 |
4 |
Commit: Slava Bacherikov <slava <AT> bacherikov <DOT> org <DOT> ua> |
5 |
CommitDate: Wed Jun 6 20:39:37 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/gentoo-packages.git;a=commit;h=57baa89e |
7 |
|
8 |
Add support multiple repo |
9 |
|
10 |
--- |
11 |
.../packages/management/commands/scanpackages.py | 3 +- |
12 |
gpackages/apps/packages/models.py | 14 +++-- |
13 |
gpackages/apps/packages/scan.py | 35 +++++++---- |
14 |
gpackages/libs/generic.py | 28 +++++++- |
15 |
gpackages/libs/porttree.py | 69 ++++++++++++++++--- |
16 |
5 files changed, 117 insertions(+), 32 deletions(-) |
17 |
|
18 |
diff --git a/gpackages/apps/packages/management/commands/scanpackages.py b/gpackages/apps/packages/management/commands/scanpackages.py |
19 |
index 27cc782..35a117b 100644 |
20 |
--- a/gpackages/apps/packages/management/commands/scanpackages.py |
21 |
+++ b/gpackages/apps/packages/management/commands/scanpackages.py |
22 |
@@ -12,5 +12,6 @@ class Command(BaseCommand): |
23 |
help = 'Will scan package tree and update info about it in database' |
24 |
def handle(self, *args, **options): |
25 |
st = datetime.datetime.now() |
26 |
- scan.scanpackages() |
27 |
+ #scan.scanpackages() |
28 |
+ scan.scan_all_repos() |
29 |
print (datetime.datetime.now() - st).total_seconds() |
30 |
|
31 |
diff --git a/gpackages/apps/packages/models.py b/gpackages/apps/packages/models.py |
32 |
index 90665bd..80e4103 100644 |
33 |
--- a/gpackages/apps/packages/models.py |
34 |
+++ b/gpackages/apps/packages/models.py |
35 |
@@ -23,10 +23,13 @@ class ArchesModel(models.Model): |
36 |
return self.name |
37 |
|
38 |
class RepositoryModel(models.Model): |
39 |
- name = models.CharField(max_length = 60) |
40 |
+ name = models.CharField(unique = True, max_length = 60) |
41 |
description = models.TextField(blank = True, null = True) |
42 |
# And other fields |
43 |
|
44 |
+ def __unicode__(self): |
45 |
+ return self.name |
46 |
+ |
47 |
class CategoryModel(models.Model): |
48 |
def __init__(self, *args, **kwargs): |
49 |
category_object = None |
50 |
@@ -125,9 +128,10 @@ class PackageModel(AbstractDateTimeModel): |
51 |
|
52 |
if 'package' in kwargs: |
53 |
package_object = kwargs['package'] |
54 |
+ del kwargs['package'] |
55 |
|
56 |
if isinstance(package_object, Package): |
57 |
- super(PackageModel, self).__init__() |
58 |
+ super(PackageModel, self).__init__(*args, **kwargs) |
59 |
self.init_by_package(package_object, category = kwargs.get('category')) |
60 |
else: |
61 |
super(PackageModel, self).__init__(*args, **kwargs) |
62 |
@@ -136,7 +140,7 @@ class PackageModel(AbstractDateTimeModel): |
63 |
|
64 |
name = models.CharField(max_length = 254) |
65 |
category = models.ForeignKey(CategoryModel) |
66 |
- changelog = models.TextField(blank = True) |
67 |
+ changelog = models.TextField(blank = True, null = True) |
68 |
changelog_hash = models.CharField(max_length = 128) |
69 |
manifest_hash = models.CharField(max_length = 128) |
70 |
metadata_hash = models.CharField(max_length = 128) |
71 |
@@ -148,6 +152,7 @@ class PackageModel(AbstractDateTimeModel): |
72 |
maintainers = models.ManyToManyField(MaintainerModel, blank = True) |
73 |
|
74 |
description = models.TextField(blank = True, null = True) |
75 |
+ repository = models.ForeignKey(RepositoryModel) |
76 |
# Different versions can have different licenses, or homepages. |
77 |
|
78 |
objects = managers.PackageManager() |
79 |
@@ -188,7 +193,7 @@ class PackageModel(AbstractDateTimeModel): |
80 |
self.description = package.description |
81 |
|
82 |
class Meta: |
83 |
- unique_together = ('name', 'category') |
84 |
+ unique_together = ('name', 'category', 'repository') |
85 |
|
86 |
class UseFlagModel(models.Model): |
87 |
name = models.CharField(unique = True, max_length = 60) |
88 |
@@ -221,7 +226,6 @@ class LicensModel(models.Model): |
89 |
|
90 |
class EbuildModel(AbstractDateTimeModel): |
91 |
package = models.ForeignKey(PackageModel) |
92 |
- #repository = models.ForeignKey(RepositoryModel) |
93 |
version = models.CharField(max_length = 26) |
94 |
revision = models.CharField(max_length = 12) |
95 |
use_flags = models.ManyToManyField(UseFlagModel) |
96 |
|
97 |
diff --git a/gpackages/apps/packages/scan.py b/gpackages/apps/packages/scan.py |
98 |
index f739c69..add62f1 100644 |
99 |
--- a/gpackages/apps/packages/scan.py |
100 |
+++ b/gpackages/apps/packages/scan.py |
101 |
@@ -1,16 +1,19 @@ |
102 |
from packages import models |
103 |
+from django.db import IntegrityError |
104 |
from collections import defaultdict |
105 |
+from generic import StrThatIgnoreCase |
106 |
import porttree |
107 |
import herds |
108 |
import use_info |
109 |
|
110 |
-porttree = porttree.PortTree() |
111 |
+portage = porttree.Portage() |
112 |
|
113 |
def _get_from_cache(cache, what): |
114 |
save_to = [] |
115 |
geted_items = set() |
116 |
for item in what: |
117 |
- if item in cache: |
118 |
+ if item.lower() in cache: |
119 |
+ item = StrThatIgnoreCase(item) |
120 |
geted_items.add(item) |
121 |
save_to.append(cache[item]) |
122 |
return save_to, geted_items |
123 |
@@ -26,8 +29,9 @@ def _update_cache_by_queryset(cache, queryset, field_name): |
124 |
if queryset is None: |
125 |
return None |
126 |
for item in queryset: |
127 |
- cache[getattr(item, field_name)] = item |
128 |
- geted_items.add(getattr(item, field_name)) |
129 |
+ val = StrThatIgnoreCase(getattr(item, field_name)) |
130 |
+ cache[val] = item |
131 |
+ geted_items.add(val) |
132 |
return geted_items |
133 |
|
134 |
def _get_from_database_and_update_cache(Model, field_name, request_items, cache): |
135 |
@@ -159,6 +163,7 @@ def update_globals_uses_descriptions(): |
136 |
|
137 |
|
138 |
def scan_uses_description(): |
139 |
+ # need changes for support many repos !!! |
140 |
uses_local = use_info.get_local_uses_info() |
141 |
existend_use_objects = models.UseFlagModel.objects.filter(name__in = uses_local.keys()) |
142 |
existend_use_local_descr = models.UseFlagDescriptionModel.objects.all() |
143 |
@@ -196,18 +201,21 @@ def scan_uses_description(): |
144 |
use_desc_obj.save(force_update = True) |
145 |
models.UseFlagDescriptionModel.objects.bulk_create(to_create) |
146 |
|
147 |
-def scanpackages(delete = True, force_update = False): |
148 |
- licenses_cache = {} |
149 |
+licenses_cache = {} |
150 |
+uses_cache = {} |
151 |
+arches_cache = {} |
152 |
+homepages_cache = {} |
153 |
+herds_cache = {} |
154 |
+maintainers_cache = {} |
155 |
+def scanpackages(porttree, porttree_obj, delete = True, force_update = False): |
156 |
def get_licenses_objects(ebuild): |
157 |
licenses = ebuild.licenses |
158 |
return _get_items(licenses, models.LicensModel, 'name', licenses_cache) |
159 |
|
160 |
- uses_cache = {} |
161 |
def get_uses_objects(ebuild): |
162 |
uses = [ use.name for use in ebuild.iter_uses() ] |
163 |
return _get_items(uses, models.UseFlagModel, 'name', uses_cache) |
164 |
|
165 |
- arches_cache = {} |
166 |
def get_keywords_objects(ebuild, ebuild_object): |
167 |
keywords_list = [] |
168 |
for keyword in ebuild.get_keywords(): |
169 |
@@ -226,13 +234,11 @@ def scanpackages(delete = True, force_update = False): |
170 |
models.Keyword.objects.bulk_create(keywords_list) |
171 |
|
172 |
|
173 |
- homepages_cache = {} |
174 |
def get_homepages_objects(ebuild): |
175 |
homepages = ebuild.homepages |
176 |
return _get_items(homepages, models.HomepageModel, 'url', homepages_cache) |
177 |
|
178 |
|
179 |
- herds_cache, maintainers_cache = scan_herds() |
180 |
def get_maintainers_objects(package): |
181 |
maintainers = package.metadata.maintainers() |
182 |
objects = [] |
183 |
@@ -319,8 +325,8 @@ def scanpackages(delete = True, force_update = False): |
184 |
category_object, category_created = models.CategoryModel.objects.get_or_create(category = category) |
185 |
existend_categorys.append(category_object.pk) |
186 |
for package in category.iter_packages(): |
187 |
- print package |
188 |
- package_object, package_created = models.PackageModel.objects.get_or_create(package = package, category = category_object) |
189 |
+ print('%s [%s]' % (package, porttree)) |
190 |
+ package_object, package_created = models.PackageModel.objects.get_or_create(package = package, category = category_object, repository = porttree_obj) |
191 |
existend_packages.append(package_object.pk) |
192 |
if not package_created: |
193 |
if package_object.check_or_need_update(package) or force_update: |
194 |
@@ -341,3 +347,8 @@ def scanpackages(delete = True, force_update = False): |
195 |
#models.CategoryModel.objects.exclude(pk__in = existend_categorys).delete() |
196 |
|
197 |
|
198 |
+def scan_all_repos(): |
199 |
+ herds_cache, maintainers_cache = scan_herds() |
200 |
+ for repo in portage.iter_trees(): |
201 |
+ repo_obj, repo_created = models.RepositoryModel.objects.get_or_create(name = repo.name) |
202 |
+ scanpackages(repo, repo_obj) |
203 |
|
204 |
diff --git a/gpackages/libs/generic.py b/gpackages/libs/generic.py |
205 |
index ed08d93..c3d8d2b 100644 |
206 |
--- a/gpackages/libs/generic.py |
207 |
+++ b/gpackages/libs/generic.py |
208 |
@@ -2,6 +2,21 @@ import os.path |
209 |
import hashlib |
210 |
from datetime import datetime |
211 |
|
212 |
+class StrThatIgnoreCase(unicode): |
213 |
+ |
214 |
+ def __init__(self, value): |
215 |
+ super(StrThatIgnoreCase, self).__init__(value) |
216 |
+ self._forcmp = value.lower() |
217 |
+ |
218 |
+ def __hash__(self): |
219 |
+ return hash(self._forcmp) |
220 |
+ |
221 |
+ def __eq__(self, other): |
222 |
+ return self._forcmp == unicode(other).lower() |
223 |
+ |
224 |
+ def __ne__(self, other): |
225 |
+ return self._forcmp != unicode(other).lower() |
226 |
+ |
227 |
class ToStrMixin(object): |
228 |
"""Abstract class for inheritence, allow add simple `__str__` and `__repr__` |
229 |
methods |
230 |
@@ -13,12 +28,19 @@ class ToStrMixin(object): |
231 |
return '<%s %s>' % (type(self).__name__, self.__str__()) |
232 |
|
233 |
|
234 |
+def file_get_content(file_path): |
235 |
+ if os.path.exists(file_path): |
236 |
+ with open(file_path, 'r') as f: |
237 |
+ content = f.read() |
238 |
+ return content |
239 |
+ else: |
240 |
+ return None |
241 |
+ |
242 |
def file_sha1(file_path): |
243 |
sha1 = 'NULL' |
244 |
if os.path.exists(file_path): |
245 |
- f = open(file_path, 'r') |
246 |
- sha1 = hashlib.sha1(f.read()).hexdigest() |
247 |
- f.close() |
248 |
+ with open(file_path, 'r') as f: |
249 |
+ sha1 = hashlib.sha1(f.read()).hexdigest() |
250 |
return sha1 |
251 |
|
252 |
def file_mtime(file_path): |
253 |
|
254 |
diff --git a/gpackages/libs/porttree.py b/gpackages/libs/porttree.py |
255 |
index 5a4da3a..5b1dba8 100644 |
256 |
--- a/gpackages/libs/porttree.py |
257 |
+++ b/gpackages/libs/porttree.py |
258 |
@@ -6,7 +6,8 @@ from portage.exception import PortageException, FileNotFound, InvalidAtom, \ |
259 |
|
260 |
from gentoolkit.package import Package as PackageInfo |
261 |
from gentoolkit.metadata import MetaData |
262 |
-from generic import ToStrMixin, file_sha1, file_mtime, cached_property |
263 |
+from generic import ToStrMixin, file_sha1, file_mtime, cached_property, \ |
264 |
+ file_get_content, StrThatIgnoreCase |
265 |
from use_info import get_uses_info, get_local_uses_info |
266 |
import os |
267 |
|
268 |
@@ -41,6 +42,21 @@ def _get_info_by_func(func, path1, path2): |
269 |
except IOError: |
270 |
return None |
271 |
|
272 |
+class FakeMetaData(ToStrMixin): |
273 |
+ |
274 |
+ def herds(self): |
275 |
+ return [] |
276 |
+ |
277 |
+ def maintainers(self): |
278 |
+ return [] |
279 |
+ |
280 |
+ def descriptions(self): |
281 |
+ return [] |
282 |
+ |
283 |
+ def __unicode__(self): |
284 |
+ return 'fake' |
285 |
+ |
286 |
+ |
287 |
class Use(ToStrMixin): |
288 |
"Represend Use flag as object" |
289 |
__slots__ = ('name',) |
290 |
@@ -51,7 +67,7 @@ class Use(ToStrMixin): |
291 |
""" |
292 |
if name.startswith('+') or name.startswith('-'): |
293 |
name = name[1:] |
294 |
- self.name = name |
295 |
+ self.name = StrThatIgnoreCase(name) |
296 |
|
297 |
def __unicode__(self): |
298 |
return self.name |
299 |
@@ -106,18 +122,28 @@ def _gen_all_use(func, iterator): |
300 |
return use_all_dict |
301 |
|
302 |
class Portage(object): |
303 |
+ |
304 |
+ def __init__(self): |
305 |
+ self.treemap = PORTDB.repositories.treemap |
306 |
+ self.tree_order = PORTDB.repositories.prepos_order |
307 |
+ |
308 |
+ def get_tree_by_name(self, tree_name): |
309 |
+ if tree_name in self.treemap: |
310 |
+ return PortTree(self.treemap[tree_name], tree_name) |
311 |
+ else: |
312 |
+ raise AttributeError |
313 |
|
314 |
def iter_trees(self): |
315 |
- tree_dict = PORTDB.repositories.treemap |
316 |
- for tree_name in PORTDB.repositories.prepos_order: |
317 |
+ tree_dict = self.treemap |
318 |
+ for tree_name in self.tree_order: |
319 |
yield PortTree(tree_dict[tree_name], tree_name) |
320 |
|
321 |
- def iter_packages(): |
322 |
+ def iter_packages(self): |
323 |
for tree in self.iter_trees(): |
324 |
for package in tree.iter_package(): |
325 |
yield package |
326 |
|
327 |
- def iter_ebuilds(): |
328 |
+ def iter_ebuilds(self): |
329 |
for tree in self.iter_trees(): |
330 |
for ebuild in tree.iter_ebuilds(): |
331 |
yield ebuild |
332 |
@@ -147,6 +173,7 @@ class PortTree(ToStrMixin): |
333 |
def __init__(self, tree_path = '/usr/portage', name = 'main'): |
334 |
"""Args: |
335 |
tree_path -- full path to portage tree as str |
336 |
+ name -- repo name as str |
337 |
""" |
338 |
self.porttree = tree_path |
339 |
self.name = name |
340 |
@@ -220,6 +247,10 @@ class Category(ToStrMixin): |
341 |
"Full path to category" |
342 |
return os.path.join(self.porttree.porttree_path, self.category) |
343 |
|
344 |
+ @property |
345 |
+ def porttree_path(self): |
346 |
+ return self.porttree.porttree |
347 |
+ |
348 |
|
349 |
class Package(ToStrMixin): |
350 |
"Represent package as object" |
351 |
@@ -235,7 +266,12 @@ class Package(ToStrMixin): |
352 |
ebuilds = PORTDB.cp_list(self.package, |
353 |
mytree = self.category.porttree.porttree) |
354 |
for ebuild in ebuilds: |
355 |
- yield Ebuild(self ,ebuild) |
356 |
+ try: |
357 |
+ PORTDB.aux_get(ebuild, [], mytree = self.category.porttree_path) |
358 |
+ except KeyError: |
359 |
+ pass |
360 |
+ else: |
361 |
+ yield Ebuild(self ,ebuild) |
362 |
|
363 |
def __unicode__(self): |
364 |
return '%s' % self.package |
365 |
@@ -246,7 +282,10 @@ class Package(ToStrMixin): |
366 |
|
367 |
@cached_property |
368 |
def metadata(self): |
369 |
- return MetaData( self.metadata_path) |
370 |
+ try: |
371 |
+ return MetaData( self.metadata_path) |
372 |
+ except IOError: |
373 |
+ return FakeMetaData() |
374 |
|
375 |
@property |
376 |
def cp(self): |
377 |
@@ -287,7 +326,7 @@ class Package(ToStrMixin): |
378 |
|
379 |
@cached_property |
380 |
def changelog(self): |
381 |
- return open(self.changelog_path,'r').read() |
382 |
+ return file_get_content(self.changelog_path) |
383 |
|
384 |
|
385 |
class Ebuild(ToStrMixin): |
386 |
@@ -371,7 +410,11 @@ class Ebuild(ToStrMixin): |
387 |
@cached_property |
388 |
def homepages(self): |
389 |
"List of homepages" |
390 |
- return self.homepage_val.split() |
391 |
+ ho_list = self.homepage_val.split() |
392 |
+ ret_list = [] |
393 |
+ for ho in ho_list: |
394 |
+ ret_list.append(StrThatIgnoreCase(ho)) |
395 |
+ return ret_list |
396 |
|
397 |
@cached_property |
398 |
def homepage(self): |
399 |
@@ -382,7 +425,11 @@ class Ebuild(ToStrMixin): |
400 |
@cached_property |
401 |
def licenses(self): |
402 |
"List of licenses used in ebuild" |
403 |
- return filter(_license_filter, self.license.split()) |
404 |
+ license_list = filter(_license_filter, self.license.split()) |
405 |
+ ret_list = [] |
406 |
+ for lic in license_list: |
407 |
+ ret_list.append(StrThatIgnoreCase(lic)) |
408 |
+ return ret_list |
409 |
|
410 |
sha1 = cached_property(_file_hash("ebuild_path"), name = 'sha1') |
411 |
mtime = cached_property(_file_mtime("ebuild_path"), name = 'mtime') |