1 |
Since the Manifest "stable mtime" behavior could have undiscovered |
2 |
bugs, disable it by default, and add a corresponding egencache option. |
3 |
|
4 |
Suggested-by: Michał Górny <mgorny@g.o> |
5 |
--- |
6 |
[PATCH v4] fixes english børk in the Manifest.write comment block. |
7 |
|
8 |
bin/egencache | 6 +++++- |
9 |
man/egencache.1 | 3 +++ |
10 |
pym/portage/manifest.py | 23 +++++++++++++++++----- |
11 |
.../ebuild/_parallel_manifest/ManifestProcess.py | 6 ++++-- |
12 |
.../ebuild/_parallel_manifest/ManifestScheduler.py | 7 +++++-- |
13 |
.../ebuild/_parallel_manifest/ManifestTask.py | 8 +++++--- |
14 |
6 files changed, 40 insertions(+), 13 deletions(-) |
15 |
|
16 |
diff --git a/bin/egencache b/bin/egencache |
17 |
index 7e3387e..07665e8 100755 |
18 |
--- a/bin/egencache |
19 |
+++ b/bin/egencache |
20 |
@@ -120,6 +120,9 @@ def parse_args(args): |
21 |
choices=('y', 'n'), |
22 |
metavar="<y|n>", |
23 |
help="manually override layout.conf sign-manifests setting") |
24 |
+ common.add_argument("--stable-mtime", |
25 |
+ action="store_true", |
26 |
+ help="apply stable mtime to generated manifests (for rsync)") |
27 |
common.add_argument("--strict-manifests", |
28 |
choices=('y', 'n'), |
29 |
metavar="<y|n>", |
30 |
@@ -1151,7 +1154,8 @@ def egencache_main(args): |
31 |
force_sign_key=force_sign_key, |
32 |
max_jobs=options.jobs, |
33 |
max_load=options.load_average, |
34 |
- event_loop=event_loop) |
35 |
+ event_loop=event_loop, |
36 |
+ manifest_kwargs=dict(stable_mtime=options.stable_mtime)) |
37 |
|
38 |
signum = run_main_scheduler(scheduler) |
39 |
if signum is not None: |
40 |
diff --git a/man/egencache.1 b/man/egencache.1 |
41 |
index 7fd17c2..081e8c1 100644 |
42 |
--- a/man/egencache.1 |
43 |
+++ b/man/egencache.1 |
44 |
@@ -100,6 +100,9 @@ Manually override layout.conf sign-manifests setting. |
45 |
.BR "\-\-strict\-manifests< y | n >" |
46 |
Manually override "strict" FEATURES setting. |
47 |
.TP |
48 |
+.BR "\-\-stable\-mtime" |
49 |
+Apply stable mtime to generated manifests (for rsync). |
50 |
+.TP |
51 |
.BR "\-\-thin\-manifests< y | n >" |
52 |
Manually override layout.conf thin-manifests setting. |
53 |
.TP |
54 |
diff --git a/pym/portage/manifest.py b/pym/portage/manifest.py |
55 |
index f696f84..eaeecc5 100644 |
56 |
--- a/pym/portage/manifest.py |
57 |
+++ b/pym/portage/manifest.py |
58 |
@@ -128,7 +128,7 @@ class Manifest(object): |
59 |
def __init__(self, pkgdir, distdir=None, fetchlist_dict=None, |
60 |
manifest1_compat=DeprecationWarning, from_scratch=False, thin=False, |
61 |
allow_missing=False, allow_create=True, hashes=None, |
62 |
- find_invalid_path_char=None): |
63 |
+ find_invalid_path_char=None, stable_mtime=False): |
64 |
""" Create new Manifest instance for package in pkgdir. |
65 |
Do not parse Manifest file if from_scratch == True (only for internal use) |
66 |
The fetchlist_dict parameter is required only for generation of |
67 |
@@ -145,6 +145,7 @@ class Manifest(object): |
68 |
find_invalid_path_char = _find_invalid_path_char |
69 |
self._find_invalid_path_char = find_invalid_path_char |
70 |
self.pkgdir = _unicode_decode(pkgdir).rstrip(os.sep) + os.sep |
71 |
+ self.stable_mtime = stable_mtime |
72 |
self.fhashdict = {} |
73 |
self.hashes = set() |
74 |
|
75 |
@@ -283,7 +284,16 @@ class Manifest(object): |
76 |
myentries = list(self._createManifestEntries()) |
77 |
update_manifest = True |
78 |
preserved_stats = {} |
79 |
- preserved_stats[self.pkgdir.rstrip(os.sep)] = os.stat(self.pkgdir) |
80 |
+ if self.stable_mtime: |
81 |
+ # The pre-existing mtime of self.pkgdir is included in the |
82 |
+ # max mtime calculation in order to account for anything |
83 |
+ # that may have been renamed or removed in this directory |
84 |
+ # (including the Manifest itself). Note that the mtime of |
85 |
+ # this directory will always be bumped as a side-effect of |
86 |
+ # writing the Manifest (since write_atomic uses a rename |
87 |
+ # operation for atomicity), therefore it must be preserved |
88 |
+ # before writing the Manifest. |
89 |
+ preserved_stats[self.pkgdir.rstrip(os.sep)] = os.stat(self.pkgdir) |
90 |
if myentries and not force: |
91 |
try: |
92 |
f = io.open(_unicode_encode(self.getFullname(), |
93 |
@@ -291,7 +301,8 @@ class Manifest(object): |
94 |
mode='r', encoding=_encodings['repo.content'], |
95 |
errors='replace') |
96 |
oldentries = list(self._parseManifestLines(f)) |
97 |
- preserved_stats[self.getFullname()] = os.fstat(f.fileno()) |
98 |
+ if self.stable_mtime: |
99 |
+ preserved_stats[self.getFullname()] = os.fstat(f.fileno()) |
100 |
f.close() |
101 |
if len(oldentries) == len(myentries): |
102 |
update_manifest = False |
103 |
@@ -313,7 +324,8 @@ class Manifest(object): |
104 |
# non-empty for all currently known use cases. |
105 |
write_atomic(self.getFullname(), "".join("%s\n" % |
106 |
_unicode(myentry) for myentry in myentries)) |
107 |
- self._apply_max_mtime(preserved_stats, myentries) |
108 |
+ if self.stable_mtime: |
109 |
+ self._apply_max_mtime(preserved_stats, myentries) |
110 |
rval = True |
111 |
else: |
112 |
# With thin manifest, there's no need to have |
113 |
@@ -450,7 +462,8 @@ class Manifest(object): |
114 |
fetchlist_dict=self.fetchlist_dict, from_scratch=True, |
115 |
thin=self.thin, allow_missing=self.allow_missing, |
116 |
allow_create=self.allow_create, hashes=self.hashes, |
117 |
- find_invalid_path_char=self._find_invalid_path_char) |
118 |
+ find_invalid_path_char=self._find_invalid_path_char, |
119 |
+ stable_mtime=self.stable_mtime) |
120 |
pn = os.path.basename(self.pkgdir.rstrip(os.path.sep)) |
121 |
cat = self._pkgdir_category() |
122 |
|
123 |
diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py b/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py |
124 |
index 44e2576..01595a3 100644 |
125 |
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py |
126 |
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py |
127 |
@@ -10,14 +10,16 @@ from portage.util._async.ForkProcess import ForkProcess |
128 |
|
129 |
class ManifestProcess(ForkProcess): |
130 |
|
131 |
- __slots__ = ("cp", "distdir", "fetchlist_dict", "repo_config") |
132 |
+ __slots__ = ("cp", "distdir", "fetchlist_dict", "manifest_kwargs", |
133 |
+ "repo_config") |
134 |
|
135 |
MODIFIED = 16 |
136 |
|
137 |
def _run(self): |
138 |
mf = self.repo_config.load_manifest( |
139 |
os.path.join(self.repo_config.location, self.cp), |
140 |
- self.distdir, fetchlist_dict=self.fetchlist_dict) |
141 |
+ self.distdir, fetchlist_dict=self.fetchlist_dict, |
142 |
+ **(self.manifest_kwargs or {})) |
143 |
|
144 |
try: |
145 |
mf.create(assumeDistHashesAlways=True) |
146 |
diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py |
147 |
index 38ac482..8a1c1d0 100644 |
148 |
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py |
149 |
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py |
150 |
@@ -12,11 +12,13 @@ from .ManifestTask import ManifestTask |
151 |
class ManifestScheduler(AsyncScheduler): |
152 |
|
153 |
def __init__(self, portdb, cp_iter=None, |
154 |
- gpg_cmd=None, gpg_vars=None, force_sign_key=None, **kwargs): |
155 |
+ gpg_cmd=None, gpg_vars=None, force_sign_key=None, |
156 |
+ manifest_kwargs=None, **kwargs): |
157 |
|
158 |
AsyncScheduler.__init__(self, **kwargs) |
159 |
|
160 |
self._portdb = portdb |
161 |
+ self._manifest_kwargs = manifest_kwargs |
162 |
|
163 |
if cp_iter is None: |
164 |
cp_iter = self._iter_every_cp() |
165 |
@@ -79,7 +81,8 @@ class ManifestScheduler(AsyncScheduler): |
166 |
yield ManifestTask(cp=cp, distdir=distdir, |
167 |
fetchlist_dict=fetchlist_dict, repo_config=repo_config, |
168 |
gpg_cmd=self._gpg_cmd, gpg_vars=self._gpg_vars, |
169 |
- force_sign_key=self._force_sign_key) |
170 |
+ force_sign_key=self._force_sign_key, |
171 |
+ manifest_kwargs=self._manifest_kwargs) |
172 |
|
173 |
def _task_exit(self, task): |
174 |
|
175 |
diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py b/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py |
176 |
index 0ee2b91..fb5e16e 100644 |
177 |
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py |
178 |
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py |
179 |
@@ -18,8 +18,8 @@ from .ManifestProcess import ManifestProcess |
180 |
|
181 |
class ManifestTask(CompositeTask): |
182 |
|
183 |
- __slots__ = ("cp", "distdir", "fetchlist_dict", "gpg_cmd", |
184 |
- "gpg_vars", "repo_config", "force_sign_key", "_manifest_path") |
185 |
+ __slots__ = ("cp", "distdir", "fetchlist_dict", "force_sign_key", |
186 |
+ "gpg_cmd", "gpg_vars", "manifest_kwargs", "repo_config", "_manifest_path") |
187 |
|
188 |
_PGP_HEADER = b"BEGIN PGP SIGNED MESSAGE" |
189 |
_manifest_line_re = re.compile(r'^(%s) ' % "|".join(MANIFEST2_IDENTIFIERS)) |
190 |
@@ -30,7 +30,9 @@ class ManifestTask(CompositeTask): |
191 |
self._manifest_path = os.path.join(self.repo_config.location, |
192 |
self.cp, "Manifest") |
193 |
manifest_proc = ManifestProcess(cp=self.cp, distdir=self.distdir, |
194 |
- fetchlist_dict=self.fetchlist_dict, repo_config=self.repo_config, |
195 |
+ fetchlist_dict=self.fetchlist_dict, |
196 |
+ manifest_kwargs=self.manifest_kwargs, |
197 |
+ repo_config=self.repo_config, |
198 |
scheduler=self.scheduler) |
199 |
self._start_task(manifest_proc, self._manifest_proc_exit) |
200 |
|
201 |
-- |
202 |
2.4.10 |