root/releases/pkgcore-checks/0.3.5/pkgcore_checks/repo_metadata.py @ ferringb%2540gmail.com-20070303123721-x6jq5tcuqfm9srrn

Revision ferringb%2540gmail.com-20070303123721-x6jq5tcuqfm9srrn, 8.2 KB (checked in by Brian Harring <ferringb@…>, 23 months ago)

drop digest specific awareness due to portage wiping digest-* for non m2-pure repos.

Line 
1# Copyright: 2006 Brian Harring <ferringb@gmail.com>
2# License: GPL2
3
4from pkgcore_checks import base, util, addons
5from pkgcore.ebuild.repository import SlavedTree
6from pkgcore.util.osutils import listdir_dirs
7from pkgcore.util.demandload import demandload
8from pkgcore.chksum.errors import MissingChksum
9import operator, itertools
10import os.path
11
12demandload(globals(), "pkgcore.util.xml:escape "
13    "pkgcore.util.osutils:listdir_files,pjoin "
14    "pkgcore.util.lists:iflatten_instance "
15    "pkgcore:fetch "
16    "pkgcore.ebuild:misc "
17)
18
19
20class UnusedLocalFlagsResult(base.Result):
21   
22    """
23    unused use.local.desc flag(s)
24    """
25   
26    __slots__ = ("category", "package", "flags")
27
28    threshold = base.package_feed
29
30    def __init__(self, pkg, flags):
31        base.Result.__init__(self)
32        # tricky, but it works; atoms have the same attrs
33        self._store_cp(pkg)
34        self.flags = tuple(sorted(flags))
35   
36    @property
37    def short_desc(self):
38        return "use.local.desc unused flag(s) %s" % ', '.join(self.flags)
39
40
41class UnusedLocalFlags(base.Template):
42
43    """
44    check for unused use.local.desc entries
45    """
46
47    feed_type = base.package_feed
48    required_addons = (addons.UseAddon,)
49    known_results = (UnusedLocalFlagsResult,) + addons.UseAddon.known_results
50
51    def __init__(self, options, use_handler):
52        base.Template.__init__(self, options)
53        self.iuse_handler = use_handler
54
55    def start(self):
56        self.collapsed = misc.non_incremental_collapsed_restrict_to_data(
57            self.iuse_handler.specific_iuse)
58
59    def feed(self, pkgs, reporter):
60        unused = set()
61        for pkg in pkgs:
62            unused.update(self.collapsed.iter_pull_data(pkg))
63        for pkg in pkgs:
64            unused.difference_update(pkg.iuse)
65        if unused:
66            reporter.add_report(UnusedLocalFlagsResult(pkg, unused))
67
68
69class UnusedGlobalFlagsResult(base.Result):
70   
71    """
72    unused use.desc flag(s)
73    """
74   
75    __slots__ = ("flags",)
76
77    threshold = base.repository_feed
78
79    def __init__(self, flags):
80        base.Result.__init__(self)
81        # tricky, but it works; atoms have the same attrs
82        self.flags = tuple(sorted(flags))
83   
84    @property
85    def short_desc(self):
86        return "use.desc unused flag(s): %s" % ', '.join(self.flags)
87
88
89class UnusedGlobalFlags(base.Template):
90    """
91    check for unused use.desc entries
92    """
93
94    feed_type = base.versioned_feed
95    scope = base.repository_scope
96    required_addons = (addons.UseAddon,)
97    known_results = (UnusedGlobalFlagsResult,) + addons.UseAddon.known_results
98
99    def __init__(self, options, iuse_handler):
100        base.Template.__init__(self, options)
101        self.flags = None
102        self.iuse_handler = iuse_handler
103
104    def start(self):
105        if not isinstance(self.options.target_repo,SlavedTree):
106            self.flags = set(self.iuse_handler.global_iuse)
107
108    def feed(self, pkg, reporter):
109        if self.flags:
110            self.flags.difference_update(pkg.iuse)
111
112    def finish(self, reporter):
113        if self.flags:
114            reporter.add_report(UnusedGlobalFlagsResult(self.flags))
115            self.flags.clear()
116
117
118class UnusedLicenseReport(base.Result):
119    """
120    unused license(s) detected
121    """
122   
123    __slots__ = ("licenses",)
124   
125    threshold = base.repository_feed
126   
127    def __init__(self, licenses):
128        base.Result.__init__(self)
129        self.licenses = tuple(sorted(licenses))
130
131    @property
132    def short_desc(self):
133        return "unused license(s): %s" % ', '.join(self.licenses)
134
135
136class UnusedLicense(base.Template):
137    """
138    unused license file(s) check
139    """
140
141    feed_type = base.versioned_feed
142    scope = base.repository_scope
143    required_addons = (addons.LicenseAddon,)
144    known_results = (UnusedLicenseReport,)
145
146    def __init__(self, options, licenses):
147        base.Template.__init__(self, options)
148        self.licenses = None
149
150    def start(self):
151        self.licenses = set()
152        if isinstance(self.options.target_repo,SlavedTree):
153            if 'licenses' in listdir_dirs(self.options.target_repo.location):
154                self.licenses.update(listdir_files(pjoin(self.options.target_repo.location,"licenses")))
155        else:
156            for license_dir in self.options.license_dirs:
157                self.licenses.update(listdir_files(license_dir))
158
159    def feed(self, pkg, reporter):
160        self.licenses.difference_update(iflatten_instance(pkg.license))
161
162    def finish(self, reporter):
163        if self.licenses:
164            reporter.add_report(UnusedLicenseReport(self.licenses))
165        self.licenses = None
166
167
168def reformat_chksums(iterable):
169    for chf, val1, val2 in iterable:
170        if chf == "size":
171            yield chf, val1, val2
172        else:
173            yield chf, "%x" % val1, "%x" % val2
174   
175
176class ConflictingChksums(base.Result):
177
178    """
179    checksum conflict detected between two files
180    """
181
182    __slots__ = ("category", "package", "version",
183        "filename", "chksums", "others")
184   
185    threshold = base.versioned_feed
186   
187    _sorter = staticmethod(operator.itemgetter(0))
188   
189    def __init__(self, pkg, filename, chksums, others):
190        base.Result.__init__(self)
191        self._store_cpv(pkg)
192        self.filename = filename
193        self.chksums = tuple(sorted(reformat_chksums(chksums),
194            key=self._sorter))
195        self.others = tuple(sorted(others))
196
197    @property
198    def short_desc(self):
199        return "conflicts with (%s) for file %s chksums %s" % (
200            ', '.join(self.others), self.filename, self.chksums)
201
202
203class OrphanedManifestDist(base.Result):
204    """
205    manifest2 has a checksum entry digest lacks
206    """
207   
208    __slots__ = ("category", "package", "files")
209
210    threshold = base.package_feed
211
212    def __init__(self, pkg, files):
213        base.Result.__init__(self)
214        self._store_cp(pkg)
215        self.files = tuple(sorted(files))
216   
217    @property
218    def short_desc(self):
219        return "manifest2 knows of files %r, but digest1 doesn't" % (self.files,)
220
221
222class MissingChksum(base.Result):
223    """
224    a file in the chksum data lacks required checksums
225    """
226    threshold = base.versioned_feed
227    __slots__ = ('category', 'package', 'version', 'filename', 'missing',
228        'existing')
229
230    def __init__(self, pkg, filename, missing, existing):
231        self._store_cpv(pkg)
232        self.filename, self.missing = filename, tuple(sorted(missing))
233        self.existing = tuple(sorted(existing))
234
235    @property
236    def short_desc(self):
237        return "file %s is missing required chksums: %s; has chksums: %s" % \
238            (self.filename, ', '.join(self.missing), ', '.join(self.existing))
239
240
241class DeprecatedManifest1(base.Result):
242    """
243    a package's checksum data still is manifest1, instead of manifest2
244    """
245   
246    threshold = base.package_feed
247    __slots__ = ("category", "package")
248   
249    def __init__(self, pkg):
250        self._store_cp(pkg)
251   
252    short_desc = "still is using manifest1 format, should be using manifest2"
253
254
255class Manifest2Transition(base.Template):
256
257    """
258    various checks for Manifest1/digest transition to Manifest2;
259    check for packages not converted, check for manifest2 packages lacking
260    required checksums
261    """
262
263    feed_type = base.package_feed
264    known_results = (MissingChksum, DeprecatedManifest1)
265    required_checksums = frozenset(("sha1", "sha256", "rmd160", "size"))
266
267    repo_grabber = operator.attrgetter("repo")
268
269    def feed(self, full_pkgset, reporter):
270        # sort it by repo.
271        for repo, pkgset in itertools.groupby(full_pkgset, self.repo_grabber):
272            pkgset = list(pkgset)
273            manifest = pkgset[0].manifest
274            if manifest.version == 1:
275                reporter.add_report(DeprecatedManifest1(pkgset[0]))
276                continue
277           
278            seen = set()
279            for pkg in pkgset:
280                for f_inst in (iflatten_instance(pkg.fetchables,
281                    fetch.fetchable)):
282                    if f_inst.filename in seen:
283                        continue
284                    missing = self.required_checksums.difference(f_inst.chksums)
285                    if missing:
286                        reporter.add_report(
287                            MissingChksum(pkg, f_inst.filename, missing,
288                                f_inst.chksums))
289                    seen.add(f_inst.filename)
Note: See TracBrowser for help on using the browser.