Since the Manifest "stable mtime" behavior could have undiscovered
bugs, disable it by default, and add a corresponding egencache option.

Suggested-by: Michał Górny <mgo...@gentoo.org>
---
[PATCH v4] fixes english børk in the Manifest.write comment block.

 bin/egencache                                      |  6 +++++-
 man/egencache.1                                    |  3 +++
 pym/portage/manifest.py                            | 23 +++++++++++++++++-----
 .../ebuild/_parallel_manifest/ManifestProcess.py   |  6 ++++--
 .../ebuild/_parallel_manifest/ManifestScheduler.py |  7 +++++--
 .../ebuild/_parallel_manifest/ManifestTask.py      |  8 +++++---
 6 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/bin/egencache b/bin/egencache
index 7e3387e..07665e8 100755
--- a/bin/egencache
+++ b/bin/egencache
@@ -120,6 +120,9 @@ def parse_args(args):
                choices=('y', 'n'),
                metavar="<y|n>",
                help="manually override layout.conf sign-manifests setting")
+       common.add_argument("--stable-mtime",
+               action="store_true",
+               help="apply stable mtime to generated manifests (for rsync)")
        common.add_argument("--strict-manifests",
                choices=('y', 'n'),
                metavar="<y|n>",
@@ -1151,7 +1154,8 @@ def egencache_main(args):
                        force_sign_key=force_sign_key,
                        max_jobs=options.jobs,
                        max_load=options.load_average,
-                       event_loop=event_loop)
+                       event_loop=event_loop,
+                       manifest_kwargs=dict(stable_mtime=options.stable_mtime))
 
                signum = run_main_scheduler(scheduler)
                if signum is not None:
diff --git a/man/egencache.1 b/man/egencache.1
index 7fd17c2..081e8c1 100644
--- a/man/egencache.1
+++ b/man/egencache.1
@@ -100,6 +100,9 @@ Manually override layout.conf sign-manifests setting.
 .BR "\-\-strict\-manifests< y | n >"
 Manually override "strict" FEATURES setting.
 .TP
+.BR "\-\-stable\-mtime"
+Apply stable mtime to generated manifests (for rsync).
+.TP
 .BR "\-\-thin\-manifests< y | n >"
 Manually override layout.conf thin-manifests setting.
 .TP
diff --git a/pym/portage/manifest.py b/pym/portage/manifest.py
index f696f84..eaeecc5 100644
--- a/pym/portage/manifest.py
+++ b/pym/portage/manifest.py
@@ -128,7 +128,7 @@ class Manifest(object):
        def __init__(self, pkgdir, distdir=None, fetchlist_dict=None,
                manifest1_compat=DeprecationWarning, from_scratch=False, 
thin=False,
                allow_missing=False, allow_create=True, hashes=None,
-               find_invalid_path_char=None):
+               find_invalid_path_char=None, stable_mtime=False):
                """ Create new Manifest instance for package in pkgdir.
                    Do not parse Manifest file if from_scratch == True (only 
for internal use)
                        The fetchlist_dict parameter is required only for 
generation of
@@ -145,6 +145,7 @@ class Manifest(object):
                        find_invalid_path_char = _find_invalid_path_char
                self._find_invalid_path_char = find_invalid_path_char
                self.pkgdir = _unicode_decode(pkgdir).rstrip(os.sep) + os.sep
+               self.stable_mtime = stable_mtime
                self.fhashdict = {}
                self.hashes = set()
 
@@ -283,7 +284,16 @@ class Manifest(object):
                        myentries = list(self._createManifestEntries())
                        update_manifest = True
                        preserved_stats = {}
-                       preserved_stats[self.pkgdir.rstrip(os.sep)] = 
os.stat(self.pkgdir)
+                       if self.stable_mtime:
+                               # The pre-existing mtime of self.pkgdir is 
included in the
+                               # max mtime calculation in order to account for 
anything
+                               # that may have been renamed or removed in this 
directory
+                               # (including the Manifest itself). Note that 
the mtime of
+                               # this directory will always be bumped as a 
side-effect of
+                               # writing the Manifest (since write_atomic uses 
a rename
+                               # operation for atomicity), therefore it must 
be preserved
+                               # before writing the Manifest.
+                               preserved_stats[self.pkgdir.rstrip(os.sep)] = 
os.stat(self.pkgdir)
                        if myentries and not force:
                                try:
                                        f = 
io.open(_unicode_encode(self.getFullname(),
@@ -291,7 +301,8 @@ class Manifest(object):
                                                mode='r', 
encoding=_encodings['repo.content'],
                                                errors='replace')
                                        oldentries = 
list(self._parseManifestLines(f))
-                                       preserved_stats[self.getFullname()] = 
os.fstat(f.fileno())
+                                       if self.stable_mtime:
+                                               
preserved_stats[self.getFullname()] = os.fstat(f.fileno())
                                        f.close()
                                        if len(oldentries) == len(myentries):
                                                update_manifest = False
@@ -313,7 +324,8 @@ class Manifest(object):
                                        # non-empty for all currently known use 
cases.
                                        write_atomic(self.getFullname(), 
"".join("%s\n" %
                                                _unicode(myentry) for myentry 
in myentries))
-                                       self._apply_max_mtime(preserved_stats, 
myentries)
+                                       if self.stable_mtime:
+                                               
self._apply_max_mtime(preserved_stats, myentries)
                                        rval = True
                                else:
                                        # With thin manifest, there's no need 
to have
@@ -450,7 +462,8 @@ class Manifest(object):
                        fetchlist_dict=self.fetchlist_dict, from_scratch=True,
                        thin=self.thin, allow_missing=self.allow_missing,
                        allow_create=self.allow_create, hashes=self.hashes,
-                       find_invalid_path_char=self._find_invalid_path_char)
+                       find_invalid_path_char=self._find_invalid_path_char,
+                       stable_mtime=self.stable_mtime)
                pn = os.path.basename(self.pkgdir.rstrip(os.path.sep))
                cat = self._pkgdir_category()
 
diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py 
b/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py
index 44e2576..01595a3 100644
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestProcess.py
@@ -10,14 +10,16 @@ from portage.util._async.ForkProcess import ForkProcess
 
 class ManifestProcess(ForkProcess):
 
-       __slots__ = ("cp", "distdir", "fetchlist_dict", "repo_config")
+       __slots__ = ("cp", "distdir", "fetchlist_dict", "manifest_kwargs",
+               "repo_config")
 
        MODIFIED = 16
 
        def _run(self):
                mf = self.repo_config.load_manifest(
                        os.path.join(self.repo_config.location, self.cp),
-                       self.distdir, fetchlist_dict=self.fetchlist_dict)
+                       self.distdir, fetchlist_dict=self.fetchlist_dict,
+                       **(self.manifest_kwargs or {}))
 
                try:
                        mf.create(assumeDistHashesAlways=True)
diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py 
b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
index 38ac482..8a1c1d0 100644
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
@@ -12,11 +12,13 @@ from .ManifestTask import ManifestTask
 class ManifestScheduler(AsyncScheduler):
 
        def __init__(self, portdb, cp_iter=None,
-               gpg_cmd=None, gpg_vars=None, force_sign_key=None, **kwargs):
+               gpg_cmd=None, gpg_vars=None, force_sign_key=None,
+               manifest_kwargs=None, **kwargs):
 
                AsyncScheduler.__init__(self, **kwargs)
 
                self._portdb = portdb
+               self._manifest_kwargs = manifest_kwargs
 
                if cp_iter is None:
                        cp_iter = self._iter_every_cp()
@@ -79,7 +81,8 @@ class ManifestScheduler(AsyncScheduler):
                                yield ManifestTask(cp=cp, distdir=distdir,
                                        fetchlist_dict=fetchlist_dict, 
repo_config=repo_config,
                                        gpg_cmd=self._gpg_cmd, 
gpg_vars=self._gpg_vars,
-                                       force_sign_key=self._force_sign_key)
+                                       force_sign_key=self._force_sign_key,
+                                       manifest_kwargs=self._manifest_kwargs)
 
        def _task_exit(self, task):
 
diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py 
b/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py
index 0ee2b91..fb5e16e 100644
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py
@@ -18,8 +18,8 @@ from .ManifestProcess import ManifestProcess
 
 class ManifestTask(CompositeTask):
 
-       __slots__ = ("cp", "distdir", "fetchlist_dict", "gpg_cmd",
-               "gpg_vars", "repo_config", "force_sign_key", "_manifest_path")
+       __slots__ = ("cp", "distdir", "fetchlist_dict", "force_sign_key",
+               "gpg_cmd", "gpg_vars", "manifest_kwargs", "repo_config", 
"_manifest_path")
 
        _PGP_HEADER = b"BEGIN PGP SIGNED MESSAGE"
        _manifest_line_re = re.compile(r'^(%s) ' % 
"|".join(MANIFEST2_IDENTIFIERS))
@@ -30,7 +30,9 @@ class ManifestTask(CompositeTask):
                self._manifest_path = os.path.join(self.repo_config.location,
                        self.cp, "Manifest")
                manifest_proc = ManifestProcess(cp=self.cp, 
distdir=self.distdir,
-                       fetchlist_dict=self.fetchlist_dict, 
repo_config=self.repo_config,
+                       fetchlist_dict=self.fetchlist_dict,
+                       manifest_kwargs=self.manifest_kwargs,
+                       repo_config=self.repo_config,
                        scheduler=self.scheduler)
                self._start_task(manifest_proc, self._manifest_proc_exit)
 
-- 
2.4.10


Reply via email to