1 |
commit: f9a040809c1ed0bf5fffea0602be20b55f5738d2 |
2 |
Author: Slava Bacherikov <slava <AT> bacher09 <DOT> org> |
3 |
AuthorDate: Fri Jul 6 13:36:29 2012 +0000 |
4 |
Commit: Slava Bacherikov <slava <AT> bacherikov <DOT> org <DOT> ua> |
5 |
CommitDate: Fri Jul 6 14:01:47 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/gentoo-packages.git;a=commit;h=f9a04080 |
7 |
|
8 |
Add license text object |
9 |
|
10 |
--- |
11 |
.../package_info/generic_metadata/license_text.py | 175 ++++++++++++++++++++ |
12 |
gpackages/libs/package_info/mixins.py | 14 ++- |
13 |
2 files changed, 188 insertions(+), 1 deletions(-) |
14 |
|
15 |
diff --git a/gpackages/libs/package_info/generic_metadata/license_text.py b/gpackages/libs/package_info/generic_metadata/license_text.py |
16 |
new file mode 100644 |
17 |
index 0000000..36e8336 |
18 |
--- /dev/null |
19 |
+++ b/gpackages/libs/package_info/generic_metadata/license_text.py |
20 |
@@ -0,0 +1,175 @@ |
21 |
+from ..generic import ToStrMixin, file_get_content |
22 |
+from itertools import ifilter, izip |
23 |
+from functools import wraps |
24 |
+import collections |
25 |
+import os |
26 |
+import os.path |
27 |
+ |
28 |
+def reverse_enumerate(lst): |
29 |
+ return izip(xrange(len(lst)-1, -1, -1), reversed(lst)) |
30 |
+ |
31 |
+def filter_predicate(file_name, file_path): |
32 |
+ full_file = os.path.join(file_path, file_name) |
33 |
+ return not file_name.startswith('.') and os.path.isfile(full_file) |
34 |
+ |
35 |
+class LicenseMixin(ToStrMixin): |
36 |
+ |
37 |
+ def get_license(self, license): |
38 |
+ try: |
39 |
+ return self[license] |
40 |
+ except (TypeError, KeyError): |
41 |
+ return None |
42 |
+ |
43 |
+class Licenses(LicenseMixin): |
44 |
+ __slots__ = ('is_valid', 'licenses_dict', 'licenses_path', 'tree_path') |
45 |
+ |
46 |
+ def __init__(self, tree_path): |
47 |
+ self.licenses_dict = {} |
48 |
+ self.is_valid = False |
49 |
+ self.tree_path = tree_path |
50 |
+ self.licenses_path = os.path.join(tree_path, 'licenses') |
51 |
+ if os.path.isdir(self.licenses_path): |
52 |
+ self.is_valid = True |
53 |
+ self._fetch_licenses_list() |
54 |
+ |
55 |
+ def _fetch_licenses_list(self): |
56 |
+ dir_list = os.listdir(self.licenses_path) |
57 |
+ f = lambda x: filter_predicate(x, self.licenses_path) |
58 |
+ licenses_list = ((s.lower(), s) for s in ifilter(f, dir_list)) |
59 |
+ self.licenses_dict = dict(licenses_list) |
60 |
+ |
61 |
+ def __len__(self): |
62 |
+ return len(self.licenses_dict) |
63 |
+ |
64 |
+ def __contains__(self, item): |
65 |
+ item = unicode(item) |
66 |
+ return item.lower() in self.licenses_dict |
67 |
+ |
68 |
+ def __iter__(self): |
69 |
+ return self.licenses_dict.itervalues() |
70 |
+ |
71 |
+ def __eq__(self, other): |
72 |
+ if isinstance(other, Licenses): |
73 |
+ return other.tree_path == self.tree_path |
74 |
+ |
75 |
+ def __ne__(self, other): |
76 |
+ return not self.__eq__(other) |
77 |
+ |
78 |
+ def __or__(self, other): |
79 |
+ return LicensesSet([self, other]) |
80 |
+ |
81 |
+ def hash(self): |
82 |
+ return hash(self.tree_path) |
83 |
+ |
84 |
+ def get_license_path(self, license): |
85 |
+ try: |
86 |
+ key = unicode(license).lower() |
87 |
+ except: |
88 |
+ raise TypeError |
89 |
+ return os.path.join(self.licenses_path, self.licenses_dict[key]) |
90 |
+ |
91 |
+ def __getitem__(self, key): |
92 |
+ return file_get_content(self.get_license_path(key)) |
93 |
+ |
94 |
+ def __unicode__(self): |
95 |
+ return unicode(self.tree_path) |
96 |
+ |
97 |
+def preinit_cache(func): |
98 |
+ @wraps(func) |
99 |
+ def wrapper(self, *args, **kwargs): |
100 |
+ if not self._cache_is_init: |
101 |
+ self._precache_objects() |
102 |
+ return func(self, *args, **kwargs) |
103 |
+ |
104 |
+ return wrapper |
105 |
+ |
106 |
+class LicensesSet(LicenseMixin): |
107 |
+ |
108 |
+ __slots__ = ('licenses_list', 'licenses_set', '_cache', '_cache_is_init') |
109 |
+ |
110 |
+ def __init__(self, val): |
111 |
+ self.licenses_list = [] |
112 |
+ self.licenses_set = set() |
113 |
+ self._cache = {} |
114 |
+ self._cache_is_init = False |
115 |
+ if isinstance(val, LicensesSet): |
116 |
+ obj = val.copy() |
117 |
+ self.licenses_list = obj.licenses_list |
118 |
+ self.licenses_set = obj.licenses_set |
119 |
+ self._cache = obj._cache |
120 |
+ self._cache_is_init = obj._cache_is_init |
121 |
+ else: |
122 |
+ if not isinstance(val, collections.Iterable): |
123 |
+ raise TypeError |
124 |
+ |
125 |
+ for item in val: |
126 |
+ if not isinstance(item, Licenses): |
127 |
+ raise TypeError |
128 |
+ self.add_licenses(item) |
129 |
+ |
130 |
+ def _precache_objects(self): |
131 |
+ cache = {} |
132 |
+ for num, licenses in reverse_enumerate(self.licenses_list): |
133 |
+ for key in licenses.licenses_dict.iterkeys(): |
134 |
+ cache[key] = num |
135 |
+ self._cache = cache |
136 |
+ self._cache_is_init = True |
137 |
+ |
138 |
+ def copy(self): |
139 |
+ return LicensesSet(self.licenses_list) |
140 |
+ |
141 |
+ def add_licenses(self, licenses): |
142 |
+ if not isinstance(licenses, Licenses): |
143 |
+ return None |
144 |
+ |
145 |
+ if (not licenses in self.licenses_set) and licenses.is_valid: |
146 |
+ self.licenses_list.append(licenses) |
147 |
+ self.licenses_set.add(licenses) |
148 |
+ self._cache_is_init = False |
149 |
+ |
150 |
+ def merge(self, licenses): |
151 |
+ if isinstance(licenses, Licenses): |
152 |
+ self.add_licenses(licenses) |
153 |
+ elif isinstance(licenses, LicensesSet): |
154 |
+ for licenses in licenses.licenses_list: |
155 |
+ self.add_licenses(licenses) |
156 |
+ else: |
157 |
+ raise TypeError |
158 |
+ |
159 |
+ def __or__(self, other): |
160 |
+ try: |
161 |
+ obj = self.copy() |
162 |
+ obj.merge(other) |
163 |
+ return obj |
164 |
+ except TypeError: |
165 |
+ return NotImplemented |
166 |
+ |
167 |
+ def __ior__(self, other): |
168 |
+ return self.merge(other) |
169 |
+ |
170 |
+ @preinit_cache |
171 |
+ def __contains__(self, item): |
172 |
+ item = unicode(item) |
173 |
+ return item.lower() in self._cache |
174 |
+ |
175 |
+ @preinit_cache |
176 |
+ def __len__(self): |
177 |
+ return len(self._cache) |
178 |
+ |
179 |
+ @preinit_cache |
180 |
+ def __getitem__(self, key): |
181 |
+ try: |
182 |
+ key = unicode(key).lower() |
183 |
+ except: |
184 |
+ raise TypeError |
185 |
+ return self.licenses_list[self._cache[key.lower()]][key] |
186 |
+ |
187 |
+ def __unicode__(self): |
188 |
+ res = "" |
189 |
+ for num ,licenses in enumerate(self.licenses_list): |
190 |
+ if num == 0: |
191 |
+ res += repr(licenses) |
192 |
+ else: |
193 |
+ res += ', %s' % repr(licenses) |
194 |
+ return '[%s]' % res |
195 |
+ |
196 |
|
197 |
diff --git a/gpackages/libs/package_info/mixins.py b/gpackages/libs/package_info/mixins.py |
198 |
index c18607e..a5cf9d1 100644 |
199 |
--- a/gpackages/libs/package_info/mixins.py |
200 |
+++ b/gpackages/libs/package_info/mixins.py |
201 |
@@ -13,6 +13,8 @@ from .generic_metadata.category_metadata import CategoryMetadata |
202 |
from .generic_metadata.package_metadata import PackageMetaData |
203 |
#License group metadata |
204 |
from .generic_metadata.license_groups import LicenseGroups |
205 |
+# License text |
206 |
+from .generic_metadata.license_text import Licenses, LicensesSet |
207 |
# News |
208 |
from .generic_metadata.news import News |
209 |
# Validators |
210 |
@@ -100,6 +102,10 @@ class PortageHerdsMixin(object): |
211 |
"Return new `LicenseGroups` object" |
212 |
return LicenseGroups() |
213 |
|
214 |
+ @cached_property |
215 |
+ def licenses(self): |
216 |
+ return LicensesSet([tree.licenses for tree in self.iter_trees()]) |
217 |
+ |
218 |
def _get_info_by_func(func, path1, path2): |
219 |
path = os.path.join(path1, path2) |
220 |
try: |
221 |
@@ -140,6 +146,12 @@ class PortTreeNewsMixin(object): |
222 |
class PortTreeIteratorMixin(AutoGeneratorMixin): |
223 |
main_iterator = 'iter_categories' |
224 |
generator_names = ('iter_packages', 'iter_ebuilds') |
225 |
+ |
226 |
+class PortTreeLicenseMixin(object): |
227 |
+ |
228 |
+ @cached_property |
229 |
+ def licenses(self): |
230 |
+ return Licenses(self.porttree_path) |
231 |
|
232 |
class CategoryBaseMixin(ToStrMixin): |
233 |
|
234 |
@@ -362,7 +374,7 @@ class PortageMixin(PortageGenericMixin, PortageIteratorMixin, AbstractPortage): |
235 |
pass |
236 |
|
237 |
class PortTreeMixin(PortTreeBaseMixin, PortTreeIteratorMixin, \ |
238 |
- PortTreeNewsMixin, AbstractPortTree): |
239 |
+ PortTreeNewsMixin, PortTreeLicenseMixin, AbstractPortTree): |
240 |
pass |
241 |
|
242 |
class CategoryMixin(CategoryBaseMixin, CategoryIteratorMixin, AbstractCategory): |