Gentoo Archives: gentoo-portage-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-portage-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-portage-dev] [PATCH 2/3] sets: Introduce @changed-deps to update packages which need dep changes
Date: Wed, 13 Aug 2014 17:20:22
Message-Id: 1407950435-2520-3-git-send-email-mgorny@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCHES] @changed-deps + missing slot check reposted for bernalex by "Michał Górny"
1 The @changed-deps set tries to compare RDEPEND and PDEPEND entries of
2 installed packages with ebuild counterparts, and pulls the ebuild
3 whenever the two are not in sync. This could be used, for example, to
4 clean up the system after disabling --dynamic-deps.
5 ---
6 cnf/sets/portage.conf | 5 +++
7 pym/portage/_sets/dbapi.py | 81 ++++++++++++++++++++++++++++++++++++++++++++--
8 2 files changed, 84 insertions(+), 2 deletions(-)
9
10 diff --git a/cnf/sets/portage.conf b/cnf/sets/portage.conf
11 index b73afb1..fd2c387 100644
12 --- a/cnf/sets/portage.conf
13 +++ b/cnf/sets/portage.conf
14 @@ -84,3 +84,8 @@ class = portage.sets.dbapi.UnavailableSet
15 # are not available.
16 [unavailable-binaries]
17 class = portage.sets.dbapi.UnavailableBinaries
18 +
19 +# Installed packages for which vdb *DEPEND entries are outdated compared
20 +# to the matching portdb entry.
21 +[changed-deps]
22 +class = portage.sets.dbapi.ChangedDepsSet
23 diff --git a/pym/portage/_sets/dbapi.py b/pym/portage/_sets/dbapi.py
24 index 817bcd7..299cb81 100644
25 --- a/pym/portage/_sets/dbapi.py
26 +++ b/pym/portage/_sets/dbapi.py
27 @@ -3,17 +3,19 @@
28
29 from __future__ import division
30
31 +import re
32 import time
33
34 from portage import os
35 from portage.versions import best, catsplit, vercmp
36 -from portage.dep import Atom
37 +from portage.dep import Atom, use_reduce
38 +from portage.exception import InvalidAtom
39 from portage.localization import _
40 from portage._sets.base import PackageSet
41 from portage._sets import SetConfigError, get_boolean
42 import portage
43
44 -__all__ = ["CategorySet", "DowngradeSet",
45 +__all__ = ["CategorySet", "ChangedDepsSet", "DowngradeSet",
46 "EverythingSet", "OwnerSet", "VariableSet"]
47
48 class EverythingSet(PackageSet):
49 @@ -458,3 +460,78 @@ class RebuiltBinaries(EverythingSet):
50 bindb=trees["bintree"].dbapi)
51
52 singleBuilder = classmethod(singleBuilder)
53 +
54 +class ChangedDepsSet(PackageSet):
55 +
56 + _operations = ["merge", "unmerge"]
57 +
58 + description = "Package set which contains all installed " + \
59 + "packages for which the vdb *DEPEND entries are outdated " + \
60 + "compared to corresponding portdb entries."
61 +
62 + def __init__(self, portdb=None, vardb=None):
63 + super(ChangedDepsSet, self).__init__()
64 + self._portdb = portdb
65 + self._vardb = vardb
66 +
67 + def load(self):
68 + depvars = ('RDEPEND', 'PDEPEND')
69 +
70 + # regexp used to match atoms using subslot operator :=
71 + subslot_repl_re = re.compile(r':[^[]*=')
72 +
73 + atoms = []
74 + for cpv in self._vardb.cpv_all():
75 + # no ebuild, no update :).
76 + if not self._portdb.cpv_exists(cpv):
77 + continue
78 +
79 + # USE flags used to build the ebuild and EAPI
80 + # (needed for Atom & use_reduce())
81 + use, eapi = self._vardb.aux_get(cpv, ('USE', 'EAPI'))
82 + usel = use.split()
83 +
84 + # function used to recursively process atoms in nested lists.
85 + def clean_subslots(depatom, usel=None):
86 + if isinstance(depatom, list):
87 + # process the nested list.
88 + return [clean_subslots(x, usel) for x in depatom]
89 + else:
90 + try:
91 + # this can be either an atom or some special operator.
92 + # in the latter case, we get InvalidAtom and pass it as-is.
93 + a = Atom(depatom)
94 + except InvalidAtom:
95 + return depatom
96 + else:
97 + # if we're processing portdb, we need to evaluate USE flag
98 + # dependency conditionals to make them match vdb. this
99 + # requires passing the list of USE flags, so we reuse it
100 + # as conditional for the operation as well.
101 + if usel is not None:
102 + a = a.evaluate_conditionals(usel)
103 +
104 + # replace slot operator := dependencies with plain :=
105 + # since we can't properly compare expanded slots
106 + # in vardb to abstract slots in portdb.
107 + return subslot_repl_re.sub(':=', a)
108 +
109 + # get all *DEPEND variables from vdb & portdb and compare them.
110 + # we need to do some cleaning up & expansion to make matching
111 + # meaningful since vdb dependencies are conditional-free.
112 + vdbvars = [clean_subslots(use_reduce(x, uselist=usel, eapi=eapi))
113 + for x in self._vardb.aux_get(cpv, depvars)]
114 + pdbvars = [clean_subslots(use_reduce(x, uselist=usel, eapi=eapi), usel)
115 + for x in self._portdb.aux_get(cpv, depvars)]
116 +
117 + # if dependencies don't match, trigger the rebuild.
118 + if vdbvars != pdbvars:
119 + atoms.append('=%s' % cpv)
120 +
121 + self._setAtoms(atoms)
122 +
123 + def singleBuilder(cls, options, settings, trees):
124 + return cls(portdb=trees["porttree"].dbapi,
125 + vardb=trees["vartree"].dbapi)
126 +
127 + singleBuilder = classmethod(singleBuilder)
128 --
129 2.0.4