1 |
Author: zmedico |
2 |
Date: 2009-04-30 07:19:02 +0000 (Thu, 30 Apr 2009) |
3 |
New Revision: 13519 |
4 |
|
5 |
Modified: |
6 |
main/branches/2.1.6/man/emerge.1 |
7 |
main/branches/2.1.6/pym/_emerge/__init__.py |
8 |
main/branches/2.1.6/pym/_emerge/help.py |
9 |
main/branches/2.1.6/pym/portage/dep.py |
10 |
Log: |
11 |
Add a new --deselect action which removes atoms from the world file. This |
12 |
action is implied by uninstall actions, including --depclean, --prune and |
13 |
--unmerge. Use --deselect=n in order to prevent uninstall actions from |
14 |
removing atoms from the world file. This solves bug #259994 and bug #265206. |
15 |
(trunk r13363) |
16 |
|
17 |
Modified: main/branches/2.1.6/man/emerge.1 |
18 |
=================================================================== |
19 |
--- main/branches/2.1.6/man/emerge.1 2009-04-30 07:18:51 UTC (rev 13518) |
20 |
+++ main/branches/2.1.6/man/emerge.1 2009-04-30 07:19:02 UTC (rev 13519) |
21 |
@@ -130,6 +130,13 @@ |
22 |
\fB\-\-depclean\fR together with \fB\-\-verbose\fR to show reverse |
23 |
dependencies. |
24 |
.TP |
25 |
+.BR "\-\-deselect[=n]" |
26 |
+Remove atoms from the world file. This action is implied |
27 |
+by uninstall actions, including \fB-\-depclean\fR, |
28 |
+\fB-\-prune\fR and \fB-\-unmerge\fR. Use \fB-\-deselect=n\fR |
29 |
+in order to prevent uninstall actions from removing |
30 |
+atoms from the world file. |
31 |
+.TP |
32 |
.BR "\-\-help " (\fB\-h\fR) |
33 |
Displays help information for emerge. Adding one of the additional |
34 |
arguments listed above will give you more specific help information |
35 |
|
36 |
Modified: main/branches/2.1.6/pym/_emerge/__init__.py |
37 |
=================================================================== |
38 |
--- main/branches/2.1.6/pym/_emerge/__init__.py 2009-04-30 07:18:51 UTC (rev 13518) |
39 |
+++ main/branches/2.1.6/pym/_emerge/__init__.py 2009-04-30 07:19:02 UTC (rev 13519) |
40 |
@@ -11837,6 +11837,8 @@ |
41 |
clean_world=1, clean_delay=1, ordered=0, raise_on_error=0, |
42 |
scheduler=None, writemsg_level=portage.util.writemsg_level): |
43 |
|
44 |
+ if clean_world: |
45 |
+ clean_world = myopts.get('--deselect') != 'n' |
46 |
quiet = "--quiet" in myopts |
47 |
settings = root_config.settings |
48 |
sets = root_config.sets |
49 |
@@ -13873,12 +13875,50 @@ |
50 |
unmerge(trees[settings["ROOT"]]['root_config'], opts, action, |
51 |
valid_atoms, ldpath_mtimes, ordered=ordered) |
52 |
rval = os.EX_OK |
53 |
+ elif action == 'deselect': |
54 |
+ rval = action_deselect(settings, trees, opts, valid_atoms) |
55 |
else: |
56 |
rval = action_depclean(settings, trees, ldpath_mtimes, |
57 |
opts, action, valid_atoms, spinner) |
58 |
|
59 |
return rval |
60 |
|
61 |
+def action_deselect(settings, trees, opts, atoms): |
62 |
+ world_set = trees[settings['ROOT']]['root_config'].sets['world'] |
63 |
+ if not hasattr(world_set, 'update'): |
64 |
+ writemsg_level("World set does not appear to be mutable.\n", |
65 |
+ level=logging.ERROR, noiselevel=-1) |
66 |
+ return 1 |
67 |
+ locked = False |
68 |
+ if not hasattr(world_set, 'lock'): |
69 |
+ world_set.lock() |
70 |
+ locked = True |
71 |
+ try: |
72 |
+ discard_atoms = set() |
73 |
+ world_set.load() |
74 |
+ from portage.dep import Atom |
75 |
+ for atom in world_set: |
76 |
+ if not isinstance(atom, Atom): |
77 |
+ # nested set |
78 |
+ continue |
79 |
+ for arg_atom in atoms: |
80 |
+ if arg_atom.intersects(atom): |
81 |
+ discard_atoms.add(atom) |
82 |
+ break |
83 |
+ if discard_atoms: |
84 |
+ for atom in sorted(discard_atoms): |
85 |
+ print ">>> Removing %s from \"world\" favorites file..." % \ |
86 |
+ colorize("INFORM", str(atom)) |
87 |
+ remaining = set(world_set) |
88 |
+ remaining.difference_update(discard_atoms) |
89 |
+ world_set.replace(remaining) |
90 |
+ else: |
91 |
+ print ">>> No matching atoms found in \"world\" favorites file..." |
92 |
+ finally: |
93 |
+ if locked: |
94 |
+ world_set.unlock() |
95 |
+ return os.EX_OK |
96 |
+ |
97 |
def action_depclean(settings, trees, ldpath_mtimes, |
98 |
myopts, action, myfiles, spinner): |
99 |
# Kill packages that aren't explicitly merged or are required as a |
100 |
@@ -13921,6 +13961,7 @@ |
101 |
root_config = trees[myroot]["root_config"] |
102 |
getSetAtoms = root_config.setconfig.getSetAtoms |
103 |
vardb = trees[myroot]["vartree"].dbapi |
104 |
+ deselect = myopts.get('--deselect') != 'n' |
105 |
|
106 |
required_set_names = ("system", "world") |
107 |
required_sets = {} |
108 |
@@ -13978,11 +14019,13 @@ |
109 |
if action == "depclean": |
110 |
|
111 |
if args_set: |
112 |
+ |
113 |
+ if deselect: |
114 |
+ world_temp_set.clear() |
115 |
+ |
116 |
# Pull in everything that's installed but not matched |
117 |
# by an argument atom since we don't want to clean any |
118 |
# package if something depends on it. |
119 |
- |
120 |
- world_temp_set.clear() |
121 |
for pkg in vardb: |
122 |
spinner.update() |
123 |
|
124 |
@@ -13999,9 +14042,11 @@ |
125 |
|
126 |
elif action == "prune": |
127 |
|
128 |
+ if deselect: |
129 |
+ world_temp_set.clear() |
130 |
+ |
131 |
# Pull in everything that's installed since we don't |
132 |
# to prune a package if something depends on it. |
133 |
- world_temp_set.clear() |
134 |
world_temp_set.update(vardb.cp_all()) |
135 |
|
136 |
if not args_set: |
137 |
@@ -14820,16 +14865,19 @@ |
138 |
|
139 |
new_args = [] |
140 |
jobs_opts = ("-j", "--jobs") |
141 |
- root_deps_opt = '--root-deps' |
142 |
- root_deps_choices = ('True', 'rdeps') |
143 |
+ default_arg_opts = { |
144 |
+ '--deselect' : ('n',), |
145 |
+ '--root-deps' : ('rdeps',), |
146 |
+ } |
147 |
arg_stack = args[:] |
148 |
arg_stack.reverse() |
149 |
while arg_stack: |
150 |
arg = arg_stack.pop() |
151 |
|
152 |
- if arg == root_deps_opt: |
153 |
+ default_arg_choices = default_arg_opts.get(arg) |
154 |
+ if default_arg_choices is not None: |
155 |
new_args.append(arg) |
156 |
- if arg_stack and arg_stack[-1] in root_deps_choices: |
157 |
+ if arg_stack and arg_stack[-1] in default_arg_choices: |
158 |
new_args.append(arg_stack.pop()) |
159 |
else: |
160 |
# insert default argument |
161 |
@@ -14897,6 +14945,12 @@ |
162 |
"choices":("y", "n") |
163 |
}, |
164 |
|
165 |
+ "--deselect": { |
166 |
+ "help" : "remove atoms from the world file", |
167 |
+ "type" : "choice", |
168 |
+ "choices" : ("True", "n") |
169 |
+ }, |
170 |
+ |
171 |
"--jobs": { |
172 |
|
173 |
"help" : "Specifies the number of packages to build " + \ |
174 |
@@ -14962,6 +15016,9 @@ |
175 |
|
176 |
myoptions, myargs = parser.parse_args(args=tmpcmdline) |
177 |
|
178 |
+ if myoptions.deselect == "True": |
179 |
+ myoptions.deselect = True |
180 |
+ |
181 |
if myoptions.root_deps == "True": |
182 |
myoptions.root_deps = True |
183 |
|
184 |
@@ -15019,6 +15076,9 @@ |
185 |
sys.exit(1) |
186 |
myaction = action_opt |
187 |
|
188 |
+ if myaction is None and myoptions.deselect is True: |
189 |
+ myaction = 'deselect' |
190 |
+ |
191 |
myfiles += myargs |
192 |
|
193 |
return myaction, myopts, myfiles |
194 |
@@ -15649,11 +15709,11 @@ |
195 |
action_search(trees[settings["ROOT"]]["root_config"], |
196 |
myopts, myfiles, spinner) |
197 |
|
198 |
- elif myaction in ('clean', 'depclean', 'prune', 'unmerge'): |
199 |
+ elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'): |
200 |
validate_ebuild_environment(trees) |
201 |
rval = action_uninstall(settings, trees, mtimedb["ldpath"], |
202 |
myopts, myaction, myfiles, spinner) |
203 |
- if not (buildpkgonly or fetchonly or pretend): |
204 |
+ if not (myaction == 'deselect' or buildpkgonly or fetchonly or pretend): |
205 |
post_emerge(root_config, myopts, mtimedb, rval) |
206 |
return rval |
207 |
|
208 |
|
209 |
Modified: main/branches/2.1.6/pym/_emerge/help.py |
210 |
=================================================================== |
211 |
--- main/branches/2.1.6/pym/_emerge/help.py 2009-04-30 07:18:51 UTC (rev 13518) |
212 |
+++ main/branches/2.1.6/pym/_emerge/help.py 2009-04-30 07:19:02 UTC (rev 13519) |
213 |
@@ -109,6 +109,18 @@ |
214 |
for line in wrap(paragraph, desc_width): |
215 |
print desc_indent + line |
216 |
print |
217 |
+ print " " + green("--deselect") + "[=%s]" % turquoise("n") |
218 |
+ |
219 |
+ paragraph = \ |
220 |
+ "Remove atoms from the world file. This action is implied " + \ |
221 |
+ "by uninstall actions, including --depclean, " + \ |
222 |
+ "--prune and --unmerge. Use --deselect=n " + \ |
223 |
+ "in order to prevent uninstall actions from removing " + \ |
224 |
+ "atoms from the world file." |
225 |
+ |
226 |
+ for line in wrap(paragraph, desc_width): |
227 |
+ print desc_indent + line |
228 |
+ print |
229 |
print " "+green("--info") |
230 |
print " Displays important portage variables that will be exported to" |
231 |
print " ebuild.sh when performing merges. This information is useful" |
232 |
|
233 |
Modified: main/branches/2.1.6/pym/portage/dep.py |
234 |
=================================================================== |
235 |
--- main/branches/2.1.6/pym/portage/dep.py 2009-04-30 07:18:51 UTC (rev 13518) |
236 |
+++ main/branches/2.1.6/pym/portage/dep.py 2009-04-30 07:19:02 UTC (rev 13519) |
237 |
@@ -558,6 +558,36 @@ |
238 |
raise AttributeError("Atom instances are immutable", |
239 |
self.__class__, name, value) |
240 |
|
241 |
+ def intersects(self, other): |
242 |
+ """ |
243 |
+ Atoms with different operator or cpv attributes cause this method to |
244 |
+ return False. TODO: Detect intersection when operators are present. |
245 |
+ @param other: The package atom to match |
246 |
+ @type other: Atom |
247 |
+ @rtype: Boolean |
248 |
+ @return: True if this atom and the other atom intersect, |
249 |
+ False otherwise. |
250 |
+ """ |
251 |
+ if not isinstance(other, Atom): |
252 |
+ raise TypeError("expected %s, got %s" % \ |
253 |
+ (Atom, type(other))) |
254 |
+ |
255 |
+ if self == other: |
256 |
+ return True |
257 |
+ |
258 |
+ if self.cp != other.cp or \ |
259 |
+ self.use != other.use or \ |
260 |
+ self.operator != other.operator or \ |
261 |
+ self.cpv != other.cpv: |
262 |
+ return False |
263 |
+ |
264 |
+ if self.slot is None or \ |
265 |
+ other.slot is None or \ |
266 |
+ self.slot == other.slot: |
267 |
+ return True |
268 |
+ |
269 |
+ return False |
270 |
+ |
271 |
# Implement some common str methods. |
272 |
|
273 |
def __eq__(self, other): |