1 |
commit: f807bb54317db5f8073f8904897cf4b9d87bf2cd |
2 |
Author: Zac Medico <zmedico <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Jul 1 07:53:52 2012 +0000 |
4 |
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Jul 1 07:53:52 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=f807bb54 |
7 |
|
8 |
Support FEATURES={downgrade,unmerge}-backup |
9 |
|
10 |
This will fix bug #156282 and bug #424275. |
11 |
|
12 |
--- |
13 |
bin/quickpkg | 15 ++++--- |
14 |
man/make.conf.5 | 13 +++++- |
15 |
pym/portage/const.py | 4 +- |
16 |
pym/portage/dbapi/vartree.py | 93 +++++++++++++++++++++++++++++++++++++---- |
17 |
4 files changed, 108 insertions(+), 17 deletions(-) |
18 |
|
19 |
diff --git a/bin/quickpkg b/bin/quickpkg |
20 |
index d908c03..a6bd4d4 100755 |
21 |
--- a/bin/quickpkg |
22 |
+++ b/bin/quickpkg |
23 |
@@ -1,5 +1,5 @@ |
24 |
#!/usr/bin/python |
25 |
-# Copyright 1999-2010 Gentoo Foundation |
26 |
+# Copyright 1999-2012 Gentoo Foundation |
27 |
# Distributed under the terms of the GNU General Public License v2 |
28 |
|
29 |
from __future__ import print_function |
30 |
@@ -68,11 +68,14 @@ def quickpkg_atom(options, infos, arg, eout): |
31 |
bintree.prevent_collision(cpv) |
32 |
dblnk = vardb._dblink(cpv) |
33 |
have_lock = False |
34 |
- try: |
35 |
- dblnk.lockdb() |
36 |
- have_lock = True |
37 |
- except PermissionDenied: |
38 |
- pass |
39 |
+ |
40 |
+ if "__PORTAGE_INHERIT_VARDB_LOCK" not in settings: |
41 |
+ try: |
42 |
+ dblnk.lockdb() |
43 |
+ have_lock = True |
44 |
+ except PermissionDenied: |
45 |
+ pass |
46 |
+ |
47 |
try: |
48 |
if not dblnk.exists(): |
49 |
# unmerged by a concurrent process |
50 |
|
51 |
diff --git a/man/make.conf.5 b/man/make.conf.5 |
52 |
index 7d07344..876a8a3 100644 |
53 |
--- a/man/make.conf.5 |
54 |
+++ b/man/make.conf.5 |
55 |
@@ -1,4 +1,4 @@ |
56 |
-.TH "MAKE.CONF" "5" "May 2012" "Portage VERSION" "Portage" |
57 |
+.TH "MAKE.CONF" "5" "Jul 2012" "Portage VERSION" "Portage" |
58 |
.SH "NAME" |
59 |
make.conf \- custom settings for Portage |
60 |
.SH "SYNOPSIS" |
61 |
@@ -293,6 +293,12 @@ strangely configured Samba server (oplocks off, NFS re\-export). A tool |
62 |
/usr/lib/portage/bin/clean_locks exists to help handle lock issues |
63 |
when a problem arises (normally due to a crash or disconnect). |
64 |
.TP |
65 |
+.B downgrade\-backup |
66 |
+When a package is downgraded to a lower version, call \fBquickpkg\fR(1) |
67 |
+in order to create a backup of the installed version before it is |
68 |
+unmerged (if a binary package of the same version does not already |
69 |
+exist). Also see the related \fIunmerge\-backup\fR feature. |
70 |
+.TP |
71 |
.B ebuild\-locks |
72 |
Use locks to ensure that unsandboxed ebuild phases never execute |
73 |
concurrently. Also see \fIparallel\-install\fR. |
74 |
@@ -514,6 +520,11 @@ continue to execute the remaining phases as if the failure had not occurred. |
75 |
Note that the test phase for a specific package may be disabled by masking |
76 |
the "test" \fBUSE\fR flag in \fBpackage.use.mask\fR (see \fBportage\fR(5)). |
77 |
.TP |
78 |
+.B unmerge\-backup |
79 |
+Call \fBquickpkg\fR(1) to create a backup of each package before it is |
80 |
+unmerged (if a binary package of the same version does not already exist). |
81 |
+Also see the related \fIdowngrade\-backup\fR feature. |
82 |
+.TP |
83 |
.B unmerge\-logs |
84 |
Keep logs from successful unmerge phases. This is relevant only when |
85 |
\fBPORT_LOGDIR\fR is set. |
86 |
|
87 |
diff --git a/pym/portage/const.py b/pym/portage/const.py |
88 |
index 3607df0..4a07710 100644 |
89 |
--- a/pym/portage/const.py |
90 |
+++ b/pym/portage/const.py |
91 |
@@ -90,7 +90,8 @@ SUPPORTED_FEATURES = frozenset([ |
92 |
"ccache", "chflags", "clean-logs", |
93 |
"collision-protect", "compress-build-logs", "compressdebug", |
94 |
"config-protect-if-modified", |
95 |
- "digest", "distcc", "distcc-pump", "distlocks", "ebuild-locks", "fakeroot", |
96 |
+ "digest", "distcc", "distcc-pump", "distlocks", |
97 |
+ "downgrade-backup", "ebuild-locks", "fakeroot", |
98 |
"fail-clean", "force-mirror", "force-prefix", "getbinpkg", |
99 |
"installsources", "keeptemp", "keepwork", "fixlafiles", "lmirror", |
100 |
"metadata-transfer", "mirror", "multilib-strict", "news", |
101 |
@@ -103,6 +104,7 @@ SUPPORTED_FEATURES = frozenset([ |
102 |
"sign", "skiprocheck", "split-elog", "split-log", "splitdebug", |
103 |
"strict", "stricter", "suidctl", "test", "test-fail-continue", |
104 |
"unknown-features-filter", "unknown-features-warn", |
105 |
+ "unmerge-backup", |
106 |
"unmerge-logs", "unmerge-orphans", "userfetch", "userpriv", |
107 |
"usersandbox", "usersync", "webrsync-gpg", "xattr"]) |
108 |
|
109 |
|
110 |
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py |
111 |
index 34098ea..0d7327a 100644 |
112 |
--- a/pym/portage/dbapi/vartree.py |
113 |
+++ b/pym/portage/dbapi/vartree.py |
114 |
@@ -21,6 +21,7 @@ portage.proxy.lazyimport.lazyimport(globals(), |
115 |
'portage.package.ebuild.doebuild:doebuild_environment,' + \ |
116 |
'_merge_unicode_error', '_spawn_phase', |
117 |
'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs', |
118 |
+ 'portage.package.ebuild._ipc.QueryCommand:QueryCommand', |
119 |
'portage.update:fixdbentries', |
120 |
'portage.util:apply_secpass_permissions,ConfigProtect,ensure_dirs,' + \ |
121 |
'writemsg,writemsg_level,write_atomic,atomic_ofstream,writedict,' + \ |
122 |
@@ -62,6 +63,7 @@ from _emerge.EbuildPhase import EbuildPhase |
123 |
from _emerge.emergelog import emergelog |
124 |
from _emerge.PollScheduler import PollScheduler |
125 |
from _emerge.MiscFunctionsProcess import MiscFunctionsProcess |
126 |
+from _emerge.SpawnProcess import SpawnProcess |
127 |
|
128 |
import errno |
129 |
import fnmatch |
130 |
@@ -1777,6 +1779,11 @@ class dblink(object): |
131 |
showMessage = self._display_merge |
132 |
if self.vartree.dbapi._categories is not None: |
133 |
self.vartree.dbapi._categories = None |
134 |
+ |
135 |
+ # When others_in_slot is not None, the backup has already been |
136 |
+ # handled by the caller. |
137 |
+ caller_handles_backup = others_in_slot is not None |
138 |
+ |
139 |
# When others_in_slot is supplied, the security check has already been |
140 |
# done for this slot, so it shouldn't be repeated until the next |
141 |
# replacement or unmerge operation. |
142 |
@@ -1842,6 +1849,11 @@ class dblink(object): |
143 |
prepare_build_dirs(settings=self.settings, cleanup=True) |
144 |
log_path = self.settings.get("PORTAGE_LOG_FILE") |
145 |
|
146 |
+ if not caller_handles_backup: |
147 |
+ retval = self._pre_unmerge_backup(background) |
148 |
+ if retval != os.EX_OK: |
149 |
+ return retval |
150 |
+ |
151 |
# Log the error after PORTAGE_LOG_FILE is initialized |
152 |
# by prepare_build_dirs above. |
153 |
if eapi_unsupported: |
154 |
@@ -3833,6 +3845,20 @@ class dblink(object): |
155 |
self.delete() |
156 |
ensure_dirs(self.dbtmpdir) |
157 |
|
158 |
+ downgrade = False |
159 |
+ if self._installed_instance is not None and \ |
160 |
+ vercmp(self.mycpv.version, |
161 |
+ self._installed_instance.mycpv.version) < 0: |
162 |
+ downgrade = True |
163 |
+ |
164 |
+ if self._installed_instance is not None: |
165 |
+ rval = self._pre_merge_backup(self._installed_instance, downgrade) |
166 |
+ if rval != os.EX_OK: |
167 |
+ showMessage(_("!!! FAILED preinst: ") + |
168 |
+ "quickpkg: %s\n" % rval, |
169 |
+ level=logging.ERROR, noiselevel=-1) |
170 |
+ return rval |
171 |
+ |
172 |
# run preinst script |
173 |
showMessage(_(">>> Merging %(cpv)s to %(destroot)s\n") % \ |
174 |
{"cpv":self.mycpv, "destroot":destroot}) |
175 |
@@ -3866,20 +3892,15 @@ class dblink(object): |
176 |
#if we have a file containing previously-merged config file md5sums, grab it. |
177 |
self.vartree.dbapi._fs_lock() |
178 |
try: |
179 |
+ # Always behave like --noconfmem is enabled for downgrades |
180 |
+ # so that people who don't know about this option are less |
181 |
+ # likely to get confused when doing upgrade/downgrade cycles. |
182 |
cfgfiledict = grabdict(self.vartree.dbapi._conf_mem_file) |
183 |
- if "NOCONFMEM" in self.settings: |
184 |
+ if "NOCONFMEM" in self.settings or downgrade: |
185 |
cfgfiledict["IGNORE"]=1 |
186 |
else: |
187 |
cfgfiledict["IGNORE"]=0 |
188 |
|
189 |
- # Always behave like --noconfmem is enabled for downgrades |
190 |
- # so that people who don't know about this option are less |
191 |
- # likely to get confused when doing upgrade/downgrade cycles. |
192 |
- for other in others_in_slot: |
193 |
- if vercmp(self.mycpv.version, other.mycpv.version) < 0: |
194 |
- cfgfiledict["IGNORE"] = 1 |
195 |
- break |
196 |
- |
197 |
rval = self._merge_contents(srcroot, destroot, cfgfiledict) |
198 |
if rval != os.EX_OK: |
199 |
return rval |
200 |
@@ -4682,6 +4703,60 @@ class dblink(object): |
201 |
"Is this a regular package (does it have a CATEGORY file? A dblink can be virtual *and* regular)" |
202 |
return os.path.exists(os.path.join(self.dbdir, "CATEGORY")) |
203 |
|
204 |
+ def _pre_merge_backup(self, backup_dblink, downgrade): |
205 |
+ |
206 |
+ if ("unmerge-backup" in self.settings.features or |
207 |
+ (downgrade and "downgrade-backup" in self.settings.features)): |
208 |
+ return self._quickpkg_dblink(backup_dblink, False, None) |
209 |
+ |
210 |
+ return os.EX_OK |
211 |
+ |
212 |
+ def _pre_unmerge_backup(self, background): |
213 |
+ |
214 |
+ if "unmerge-backup" in self.settings.features : |
215 |
+ logfile = None |
216 |
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess": |
217 |
+ logfile = self.settings.get("PORTAGE_LOG_FILE") |
218 |
+ return self._quickpkg_dblink(self, background, logfile) |
219 |
+ |
220 |
+ return os.EX_OK |
221 |
+ |
222 |
+ def _quickpkg_dblink(self, backup_dblink, background, logfile): |
223 |
+ |
224 |
+ trees = QueryCommand.get_db()[self.settings["EROOT"]] |
225 |
+ bintree = trees["bintree"] |
226 |
+ binpkg_path = bintree.getname(backup_dblink.mycpv) |
227 |
+ if os.path.exists(binpkg_path) and \ |
228 |
+ backup_dblink.mycpv not in bintree.invalids: |
229 |
+ return os.EX_OK |
230 |
+ |
231 |
+ self.lockdb() |
232 |
+ try: |
233 |
+ |
234 |
+ if not backup_dblink.exists(): |
235 |
+ # It got unmerged by a concurrent process. |
236 |
+ return os.EX_OK |
237 |
+ |
238 |
+ # Call quickpkg for support of QUICKPKG_DEFAULT_OPTS and stuff. |
239 |
+ quickpkg_binary = os.path.join(self.settings["PORTAGE_BIN_PATH"], |
240 |
+ "quickpkg") |
241 |
+ |
242 |
+ # Let quickpkg inherit the global vartree config's env. |
243 |
+ env = dict(self.vartree.settings.items()) |
244 |
+ env["__PORTAGE_INHERIT_VARDB_LOCK"] = "1" |
245 |
+ |
246 |
+ quickpkg_proc = SpawnProcess( |
247 |
+ args=[portage._python_interpreter, quickpkg_binary, |
248 |
+ "=%s" % (backup_dblink.mycpv,)], |
249 |
+ background=background, env=env, |
250 |
+ scheduler=self._scheduler, logfile=logfile) |
251 |
+ quickpkg_proc.start() |
252 |
+ |
253 |
+ return quickpkg_proc.wait() |
254 |
+ |
255 |
+ finally: |
256 |
+ self.unlockdb() |
257 |
+ |
258 |
def merge(mycat, mypkg, pkgloc, infloc, |
259 |
myroot=None, settings=None, myebuild=None, |
260 |
mytree=None, mydbapi=None, vartree=None, prev_mtimes=None, blockers=None, |