root/releases/pkgcore-checks/0.3.4/pkgcore_checks/unported_mod_x.py @ ferringb%2540gmail.com-20070207174621-yb3eqrqc6jtmdgse

Revision ferringb%2540gmail.com-20070207174621-yb3eqrqc6jtmdgse, 11.2 KB (checked in by Brian Harring <ferringb@…>, 2 years ago)

kill off to_str, no longer used; use short_desc and long_desc properties instead

Line 
1# Copyright: 2006 Brian Harring <ferringb@gmail.com>
2# License: GPL2
3
4from pkgcore.util.compatibility import any
5from pkgcore.util.demandload import demandload
6from pkgcore_checks import base, addons
7from pkgcore.util.iterables import caching_iter
8from pkgcore.restrictions import boolean
9from pkgcore.ebuild.atom import atom
10from pkgcore.package import virtual
11from pkgcore_checks.util import get_cpvstr
12demandload(
13    globals(),
14    "urllib:urlopen "
15    "pkgcore.util.xml:escape "
16    "pkgcore.log:logger "
17    )
18
19
20class SuggestRemoval(base.Result):
21   
22    """pkg isn't ported, stablize the targets and it can likely go away"""
23   
24    __slots__ = ("category", "package", "version", "ported")
25
26    threshold = base.versioned_feed
27
28    def __init__(self, pkg, ported):
29        base.Result.__init__(self)
30        self._store_cpv(pkg)
31        self.ported = tuple(get_cpvstr(x) for x in ported)
32
33    @property
34    def short_desc(self):
35        return "version is unported, suggest removal for one of the ported " \
36            "versions: [ %s ]" % ', '.join(self.ported)
37   
38
39class BadRange(base.Result):
40   
41    """
42    look for virtual/x11 atoms that don't intersect =virtual/x11-6.9
43    """
44   
45    __slots__ = ("category", "package", "version", "attr", "atoms")
46
47    threshold = base.versioned_feed
48
49    def __init__(self, pkg, attr, atom_inst):
50        base.Result.__init__(self)
51        self._store_cpv(pkg)
52        self.attr = attr
53        self.atoms = tuple(str(x) for x in atom_inst)
54   
55    @property
56    def short_desc(self):
57        return "%s: virtual/x11 atoms must match version 6.9: %s" % (
58            self.attr, ', '.join(self.atoms))
59
60
61class NotPorted(base.Result):
62   
63    """standalone virtual/x11 atom, not ported."""
64   
65    __slots__ = ("category", "package", "version", "attr", "or_block")
66
67    threshold = base.versioned_feed
68
69    def __init__(self, pkg, attr, or_block):
70        base.Result.__init__(self)
71        self._store_cpv(pkg)
72        self.attr = attr
73        self.or_block = or_block
74   
75    @property
76    def short_desc(self):
77        return "%s: has standalone virtual/x11 in an OR block" % self.attr
78
79
80class VisibilityCausedNotPorted(base.Result):
81   
82    """
83    ported, but due to visibility (mask'ing/keywords), knocked back to
84    effectively not ported
85    """
86   
87    __slots__ = ("category", "package", "version", "attr", "keyword",
88        "profile", "failed")
89
90    threshold = base.versioned_feed
91
92    def __init__(self, pkg, keyword, profile, attr, failed):
93        base.Result.__init__(self)
94        self._store_cpv(pkg)
95        self.attr = attr
96        self.keyword = keyword
97        self.profile = profile
98        self.failed = tuple(str(x) for x in failed)
99   
100    @property
101    def short_desc(self):
102        return "attr(%s): keyword(%s): profile(%s): visibility induced " \
103            " unported, fix via [ %s ]" % (self.attr, self.keyword,
104            self.profile, ', '.join(self.failed))
105
106
107class ModularXPortingReport(base.Template):
108
109    """modular X porting report.
110    Scans for dependencies that require monolithic X, or via visibility
111    limiters from profiles, are forced to use monolithic X
112    """
113    feed_type = base.package_feed
114    required_addons = (
115        addons.ArchesAddon, addons.QueryCacheAddon, addons.EvaluateDepSetAddon)
116    known_results = (SuggestRemoval, BadRange, NotPorted,
117        VisibilityCausedNotPorted)
118
119    valid_modx_pkgs_url = \
120        "http://www.gentoo.org/proj/en/desktop/x/x11/modular-x-packages.txt"
121
122    @classmethod
123    def mangle_option_parser(cls, parser):
124        parser.add_option(
125            '--mod-x-packages',
126            help='location to cache %s' % (cls.valid_modx_pkgs_url,))
127
128    def __init__(self, options, arches, query_cache, depset_cache):
129        base.Template.__init__(self, options)
130        self.query_cache = query_cache.query_cache
131        self.depset_cache = depset_cache
132        self.arches = frozenset(x.lstrip("~") for x in options.arches)
133        # use 7.1 so it catches any >7.0
134        self.x7 = virtual.package(None, "virtual/x11-7.1")
135        self.x6 = virtual.package(None, "virtual/x11-6.9")
136        if self.options.mod_x_packages is not None:
137            try:
138                package_list = open(self.options.mod_x_packages, 'r')
139            except (IOError, OSError), e:
140                logger.warn(
141                    'modular X package file cannot be opened (%s), refetching',
142                    e)
143                package_list = list(urlopen(self.valid_modx_pkgs_url))
144                try:
145                    f = open(self.options.mod_x_packages, 'w')
146                    for line in package_list:
147                        f.write(line)
148                except (IOError, OSError), e:
149                    logger.warn(
150                        'modular X package file could not be written (%s)', e)
151        else:
152            package_list = urlopen(self.valid_modx_pkgs_url)
153        self.valid_modx_keys = frozenset(x for x in
154            (y.strip() for y in package_list) if
155                x and x != "virtual/x11")
156
157    def feed(self, pkgset, reporter):
158        # query_cache gets caching_iter partial repo searches shoved into it-
159        # reason is simple, it's likely that versions of this pkg probably
160        # use similar deps- so we're forcing those packages that were
161        # accessed for atom matching to remain in memory.
162        # end result is less going to disk
163        unported = []
164        for pkg in pkgset:
165            self.check_pkg(pkg, reporter, unported)
166
167        if unported:
168            for u in unported:
169                l = [pkg for pkg in pkgset if pkg not in unported]
170                if l:
171                    reporter.add_report(SuggestRemoval(u, l))
172
173    def check_pkg(self, pkg, reporter, unported):
174        failed = []
175
176        bool_or = boolean.OrRestriction
177        for attr, depset in (("depends", pkg.depends),
178            ("rdepends", pkg.rdepends), ("pdepends", pkg.post_rdepends)):
179            stack = [depset.evaluate_depset([], tristate_filter=[]
180                ).restrictions]
181            bad_range = set()
182            bad_blocks = set()
183            while stack:
184                for a in stack.pop(-1):
185                    if isinstance(a, atom):
186                        if a.key == "virtual/x11" and not a.blocks:
187                            if not a.match(self.x6):
188                                bad_range.add(a)
189                            bad_blocks.add((a,))
190                    elif isinstance(a, bool_or):
191                        for block in a.iter_dnf_solutions():
192                            i = iter(block)
193                            for x in i:
194                                if x.blocks:
195                                    continue
196                                if x.key == "virtual/x11":
197                                    break
198                            else:
199                                continue
200                            for x in i:
201                                if not x.blocks and \
202                                    x.key in self.valid_modx_keys:
203                                    break
204                            else:
205                                for or_block in a.cnf_solutions():
206                                    if not any(True for x in or_block if
207                                        x.key == "virtual/x11"
208                                        and not x.blocks):
209                                        continue
210
211                                    if any(True for x in or_block if
212                                        x.key in self.valid_modx_keys
213                                        and not x.blocks):
214                                        break
215                                else:
216                                    # standalone virtual/x11
217                                    bad_blocks.add(tuple(block))
218                                break
219                    else:
220                        stack.append(a.restrictions)
221            if bad_range:
222                reporter.add_report(BadRange(pkg, attr, sorted(bad_range)))
223            if bad_blocks:
224                for bad in sorted(bad_blocks):
225                    reporter.add_report(NotPorted(pkg, attr, bad))
226            if bad_range or bad_blocks:
227                failed.append(attr)
228                   
229        if failed:
230            unported.append(pkg)
231       
232        if len(failed) == 2:
233            # no point in trying it out, will fail anyways
234            return
235               
236        skip_depends = "depends" in failed
237        skip_rdepends = "rdepends" in failed
238        skip_pdepends = "pdepends" in failed
239        del failed
240
241        # ok heres the rules of the road.
242        # valid: || ( modx <virtual/x11-7 ), || ( modx virtual/x11 )
243        # not valid: >=virtual/x11-7 anywhere, virtual/x11 floating
244        # not valid: x11-base/xorg-x11 floating
245
246        if not skip_depends:
247            for edepset, profiles in \
248                self.depset_cache.collapse_evaluate_depset(pkg, "depends",
249                pkg.depends):
250                self.process_depset(pkg, "depends", edepset, profiles,
251                                    reporter)
252
253        if not skip_rdepends:
254            for edepset, profiles in \
255                self.depset_cache.collapse_evaluate_depset(pkg, "rdepends",
256                pkg.rdepends):
257                self.process_depset(pkg, "rdepends", edepset, profiles,
258                                    reporter)
259
260        if not skip_pdepends:
261            for edepset, profiles in self.depset_cache.collapse_evaluate_depset(
262                pkg, "post_rdepends", pkg.post_rdepends):
263                self.process_depset(pkg, "post_rdepends", edepset, profiles,
264                                    reporter)
265               
266    def process_depset(self, pkg, attr, depset, profiles, reporter):
267
268        csolutions = depset.cnf_solutions()
269        failed = set()
270        for profile in profiles:
271            failed.clear()
272            cache = profile.cache
273            insoluable = profile.insoluable
274            visible = profile.visible
275            for or_block in csolutions:
276                if not any(True for x in or_block if x.key == "virtual/x11"):
277                    continue
278           
279                # we know a virtual/x11 is in this options.
280                # better have a modx node in options, else it's bad.
281                modx_candidates = [x for x in or_block if
282                    x.key in self.valid_modx_keys]
283                for a in modx_candidates:
284                    if a.blocks:
285                        # weird.
286                        continue
287                    h = str(a)
288                    if h in insoluable:
289                        continue
290                    elif h in cache:
291                        break
292                    elif h not in self.query_cache:
293                        self.query_cache[h] = caching_iter(
294                            self.options.search_repo.itermatch(a))
295                    # if a provider is visible, good to go.
296                    if any(True for pkg in self.query_cache[h] if visible(pkg)):
297                        cache.add(h)
298                        break
299                    else:
300                        insoluable.add(h)
301                else:
302                    failed.update(modx_candidates)
303            if failed:
304                reporter.add_report(VisibilityCausedNotPorted(pkg,
305                    profile.key, profile.name, attr, sorted(failed)))
Note: See TracBrowser for help on using the browser.