Gentoo Archives: gentoo-commits

From: Slava Bacherikov <slava@××××××××××××××.ua>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/gentoo-packages:master commit in: gpackages/apps/packages/, gpackages/libs/package_info/package_backends/
Date: Thu, 05 Jul 2012 23:27:44
Message-Id: 1341510228.e6a1805fa32a963d1728c1e95797a13874662200.bacher09@gentoo
1 commit: e6a1805fa32a963d1728c1e95797a13874662200
2 Author: Slava Bacherikov <slava <AT> bacher09 <DOT> org>
3 AuthorDate: Thu Jul 5 17:43:48 2012 +0000
4 Commit: Slava Bacherikov <slava <AT> bacherikov <DOT> org <DOT> ua>
5 CommitDate: Thu Jul 5 17:43:48 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/gentoo-packages.git;a=commit;h=e6a1805f
7
8 Add stats calculating
9
10 ---
11 gpackages/apps/packages/models.py | 92 ++++++++++++++++++--
12 gpackages/apps/packages/stats.py | 31 +++++++
13 .../libs/package_info/package_backends/pkgcore.py | 6 ++
14 .../libs/package_info/package_backends/portage.py | 6 ++
15 4 files changed, 127 insertions(+), 8 deletions(-)
16
17 diff --git a/gpackages/apps/packages/models.py b/gpackages/apps/packages/models.py
18 index 51b839e..efb4638 100644
19 --- a/gpackages/apps/packages/models.py
20 +++ b/gpackages/apps/packages/models.py
21 @@ -6,6 +6,7 @@ from package_info.generic import get_from_kwargs_and_del
22 from package_info.repo_info import REPOS_TYPE
23 # relative
24 from .keywords import KeywordRepr
25 +from .stats import StatsMixin
26 #from utils import get_link
27 from package_info.validators import validate_url, validate_email, \
28 validate_name
29 @@ -90,12 +91,17 @@ class ArchesModel(models.Model):
30 def __unicode__(self):
31 return self.name
32
33 -class RepositoryModel(AbstractDateTimeModel):
34 +class RepositoryModel(StatsMixin, AbstractDateTimeModel):
35 QUALITY_CHOICES = ( (0, 'stable'),
36 (1, 'testing'),
37 (2, 'experimental'),
38 )
39
40 + stats_params = (
41 + ('packages_count', 'packagemodel'),
42 + ('ebuilds_count', 'packagemodel__ebuildmodel'),
43 + )
44 +
45 def __init__(self, *args, **kwargs):
46 repo = get_from_kwargs_and_del('repo', kwargs)
47 super(RepositoryModel, self).__init__(*args, **kwargs)
48 @@ -113,6 +119,12 @@ class RepositoryModel(AbstractDateTimeModel):
49 official = models.BooleanField(default = False)
50 quality = models.PositiveSmallIntegerField(choices = QUALITY_CHOICES)
51
52 + # Maybe in future auto generate this field by metaclass ?
53 + # For fast stats
54 + packages_count = models.PositiveIntegerField(default = 0)
55 + ebuilds_count = models.PositiveIntegerField(default = 0)
56 +
57 +
58 objects = managers.RepositoryManager()
59
60 def init_by_repo(self, repo):
61 @@ -194,7 +206,7 @@ class RepositorySourceModel(models.Model):
62 def __unicode__(self):
63 return self.url
64
65 -class CategoryModel(models.Model):
66 +class CategoryModel(StatsMixin, models.Model):
67 def __init__(self, *args, **kwargs):
68 super(CategoryModel, self).__init__(*args, **kwargs)
69
70 @@ -202,6 +214,13 @@ class CategoryModel(models.Model):
71 if isinstance(category, AbstractCategory):
72 self.update_by_category(category)
73
74 + stats_params = (
75 + ('virtual_packages_count', 'virtualpackagemodel'),
76 + ('packages_count', 'virtualpackagemodel__packagemodel'),
77 + ('repositories_count', 'virtualpackagemodel__packagemodel__repository'),
78 + ('ebuilds_count', 'virtualpackagemodel__packagemodel__ebuildmodel'),
79 + )
80 +
81 def update_by_category(self, category):
82 self.description = category.metadata.default_descr
83 self.metadata_hash = category.metadata_sha1
84 @@ -212,21 +231,47 @@ class CategoryModel(models.Model):
85 category = models.CharField(unique = True, max_length = 70, db_index = True)
86 description = models.TextField(blank = True, null = True)
87 metadata_hash = models.CharField(max_length = 128, null = True)
88 +
89 + # Maybe in future auto generate this field by metaclass ?
90 + # For fast stats
91 + virtual_packages_count = models.PositiveIntegerField(default = 0)
92 + packages_count = models.PositiveIntegerField(default = 0)
93 + repositories_count = models.PositiveIntegerField(default = 0)
94 + ebuilds_count = models.PositiveIntegerField(default = 0)
95
96 def __unicode__(self):
97 return unicode(self.category)
98
99 -class MaintainerModel(AbstractDateTimeModel):
100 +class MaintainerModel(StatsMixin, AbstractDateTimeModel):
101
102 def __init__(self, *args, **kwargs):
103 maintainer = get_from_kwargs_and_del('maintainer', kwargs)
104 super(MaintainerModel, self).__init__(*args, **kwargs)
105 if maintainer is not None:
106 self.init_by_maintainer(maintainer)
107 +
108 + stats_params = (
109 + ('packages_count', 'packagemodel'),
110 + ('herds_count', 'herdsmodel'),
111 + ('ebuilds_count', 'packagemodel__ebuildmodel'),
112 + ('repositories_count', 'packagemodel__ebuildmodel'),
113 + ('news_author_count', 'author_news_set'),
114 + ('news_translator_count', 'translator_news_set')
115 + )
116
117 name = models.CharField(max_length = 255, blank = True, null = True)
118 email = models.EmailField(unique = True, validators = [validate_email], db_index = True)
119
120 + # For fast stats
121 + # Maybe use django-composition ?
122 + # Maybe in future auto generate this field by metaclass ?
123 + herds_count = models.PositiveIntegerField(default = 0)
124 + packages_count = models.PositiveIntegerField(default = 0)
125 + ebuilds_count = models.PositiveIntegerField(default = 0)
126 + repositories_count = models.PositiveIntegerField(default = 0)
127 + news_author_count = models.PositiveIntegerField(default = 0)
128 + news_translator_count = models.PositiveIntegerField(default = 0)
129 +
130 objects = managers.MaintainerManager()
131
132 def init_by_maintainer(self, maintainer):
133 @@ -246,7 +291,7 @@ class MaintainerModel(AbstractDateTimeModel):
134 class Meta:
135 ordering = ('name',)
136
137 -class HerdsModel(AbstractDateTimeModel):
138 +class HerdsModel(StatsMixin, AbstractDateTimeModel):
139
140 def __init__(self, *args, **kwargs):
141 herd = get_from_kwargs_and_del('herd', kwargs)
142 @@ -254,11 +299,26 @@ class HerdsModel(AbstractDateTimeModel):
143 if herd is not None:
144 self.init_by_herd(herd)
145
146 + stats_params = (
147 + ('packages_count', 'packagemodel'),
148 + ('maintainers_count', 'maintainers'),
149 + ('ebuilds_count', 'packagemodel__ebuildmodel'),
150 + ('repositories_count', 'packagemodel__repository'),
151 + )
152 +
153 name = models.CharField(unique = True, max_length = 150, db_index = True)
154 email = models.EmailField(validators = [validate_email])
155 description = models.TextField(blank = True, null = True)
156 maintainers = models.ManyToManyField(MaintainerModel, blank = True)
157
158 + # For fast stats
159 + # Maybe use django-composition ?
160 + # Maybe in future auto generate this field by metaclass ?
161 + maintainers_count = models.PositiveIntegerField(default = 0)
162 + packages_count = models.PositiveIntegerField(default = 0)
163 + ebuilds_count = models.PositiveIntegerField(default = 0)
164 + repositories_count = models.PositiveIntegerField(default = 0)
165 +
166 objects = managers.HerdsManager()
167
168 def init_by_herd(self, herd):
169 @@ -304,7 +364,8 @@ class VirtualPackageModel(models.Model):
170 class Meta:
171 unique_together = ('name', 'category')
172
173 -class PackageModel(AbstractDateTimeModel):
174 +class PackageModel(StatsMixin, AbstractDateTimeModel):
175 +
176 def __init__(self, *args, **kwargs):
177 package_object, category = \
178 get_from_kwargs_and_del(('package','category' ), kwargs)
179 @@ -313,6 +374,9 @@ class PackageModel(AbstractDateTimeModel):
180 if isinstance(package_object, AbstarctPackage):
181 self.init_by_package(package_object, category = category)
182
183 + stats_params = (
184 + ('ebuilds_count', 'ebuildmodel'),
185 + )
186
187 virtual_package = models.ForeignKey(VirtualPackageModel, db_index = True)
188 changelog = models.TextField(blank = True, null = True)
189 @@ -329,6 +393,8 @@ class PackageModel(AbstractDateTimeModel):
190 description = models.TextField(blank = True, null = True)
191 repository = models.ForeignKey(RepositoryModel, db_index = True)
192 # Different versions can have different licenses, or homepages.
193 +
194 + ebuilds_count = models.PositiveIntegerField(default = 0)
195
196 objects = managers.PackageManager()
197
198 @@ -407,10 +473,16 @@ class PackageModel(AbstractDateTimeModel):
199 unique_together = ('virtual_package', 'repository')
200 ordering = ('-updated_datetime',)
201
202 -class UseFlagModel(models.Model):
203 +class UseFlagModel(StatsMixin, models.Model):
204 + stats_params = (
205 + ('ebuilds_count', 'ebuildmodel'),
206 + )
207 +
208 name = models.CharField(unique = True, max_length = 60, db_index = True)
209 description = models.TextField(blank = True)
210
211 + ebuilds_count = models.PositiveIntegerField(default = 0)
212 +
213 def __unicode__(self):
214 return self.name
215
216 @@ -431,9 +503,14 @@ class UseFlagDescriptionModel(models.Model):
217 class Meta:
218 unique_together = ('use_flag', 'package')
219
220 -class LicenseModel(models.Model):
221 +class LicenseModel(StatsMixin, models.Model):
222 + stats_params = (
223 + ('ebuilds_count', 'ebuildmodel'),
224 + )
225 +
226 name = models.CharField(unique = True, max_length = 60, db_index = True)
227 #description = TextField()
228 + ebuilds_count = models.PositiveIntegerField(default = 0)
229
230 def __unicode__(self):
231 return self.name
232 @@ -648,4 +725,3 @@ class Keyword(models.Model):
233 class Meta:
234 unique_together = ('ebuild', 'arch')
235
236 -
237
238 diff --git a/gpackages/apps/packages/stats.py b/gpackages/apps/packages/stats.py
239 new file mode 100644
240 index 0000000..9bf3efa
241 --- /dev/null
242 +++ b/gpackages/apps/packages/stats.py
243 @@ -0,0 +1,31 @@
244 +from django.db.models import Count
245 +from itertools import starmap
246 +
247 +gen_prefix = lambda x: x + '_prefix'
248 +
249 +def gen_query_dict(params):
250 + query_dict = {}
251 + for key, value in starmap(lambda x,y: (gen_prefix(x), y), params):
252 + query_dict[key] = Count(value, distinct = True)
253 +
254 + return query_dict
255 +
256 +def make_query_for_stats(model, params):
257 + query_dict = gen_query_dict(params)
258 + return model.objects.annotate(**query_dict)
259 +
260 +def update_stats(model, params):
261 + query = make_query_for_stats(model, params)
262 + for obj in query:
263 + for key, mykey in starmap(lambda x,y: (x, gen_prefix(x)), params):
264 + setattr(obj, key, getattr(obj, mykey))
265 +
266 + obj.save(force_update = True)
267 +
268 +class StatsMixin(object):
269 +
270 + stats_params = ((),)
271 +
272 + @classmethod
273 + def calc_stats(cls):
274 + update_stats(cls, cls.stats_params)
275
276 diff --git a/gpackages/libs/package_info/package_backends/pkgcore.py b/gpackages/libs/package_info/package_backends/pkgcore.py
277 index 9a17208..2ad6b69 100644
278 --- a/gpackages/libs/package_info/package_backends/pkgcore.py
279 +++ b/gpackages/libs/package_info/package_backends/pkgcore.py
280 @@ -57,6 +57,9 @@ class Portage(PortageMixin):
281
282 def __unicode__(self):
283 return u'pkgcore'
284 +
285 + def __len__(self):
286 + return len(self.repo_list)
287
288 class PortTree(PortTreeMixin):
289
290 @@ -86,6 +89,9 @@ class PortTree(PortTreeMixin):
291 def _versions(self):
292 return self._repo_obj.versions
293
294 + def __len__(self):
295 + return len(self.categories)
296 +
297 class Category(CategoryMixin):
298
299 __slots__ = ('_repo_obj', 'name')
300
301 diff --git a/gpackages/libs/package_info/package_backends/portage.py b/gpackages/libs/package_info/package_backends/portage.py
302 index 729e6e9..e3707d4 100644
303 --- a/gpackages/libs/package_info/package_backends/portage.py
304 +++ b/gpackages/libs/package_info/package_backends/portage.py
305 @@ -51,6 +51,9 @@ class Portage(PortageMixin):
306 def __unicode__(self):
307 return u'portage'
308
309 + def __len__(self):
310 + return len(self.tree_order)
311 +
312 class PortTree(PortTreeMixin):
313 "Represent portage tree as object"
314
315 @@ -72,6 +75,9 @@ class PortTree(PortTreeMixin):
316 "Full path to portage tree"
317 return self.porttree
318
319 + def __len__(self):
320 + return len(PORTDB.settings.categories)
321 +
322 class Category(CategoryMixin):
323 "Represent category of portage tree as object"