Add FEATURES=merge-sync, for bug #439584.
authorZac Medico <zmedico@gentoo.org>
Thu, 25 Oct 2012 08:35:31 +0000 (01:35 -0700)
committerZac Medico <zmedico@gentoo.org>
Thu, 25 Oct 2012 08:45:22 +0000 (01:45 -0700)
cnf/make.globals
man/make.conf.5
pym/portage/const.py
pym/portage/dbapi/vartree.py

index e53f1867f1d13203853556656ee3686c11f4b80f..47ee787c6da776c99c54ba192ac260db188f7f9f 100644 (file)
@@ -53,7 +53,7 @@ FETCHCOMMAND_SFTP="bash -c \"x=\\\${2#sftp://} ; host=\\\${x%%/*} ; port=\\\${ho
 # Default user options
 FEATURES="assume-digests binpkg-logs
           config-protect-if-modified distlocks ebuild-locks
-          fixlafiles news parallel-fetch protect-owned
+          fixlafiles merge-sync news parallel-fetch protect-owned
           sandbox sfperms strict unknown-features-warn unmerge-logs
           unmerge-orphans userfetch"
 
index 4c86d38e66be72b160000f704b932acba37cc073..9152ab295d083193e0746ac4473ad3aad8ad9b24 100644 (file)
@@ -361,6 +361,11 @@ Do \fBNOT\fR use \fIlmirror\fR for clients that need to override \fBRESTRICT\fR
 when fetching from a local mirror, but instead use a "local" mirror setting
 in \fI/etc/portage/mirrors\fR, as described in \fBportage\fR(5).
 .TP
+.B merge\-sync
+After a package is merged or unmerged, sync relevant files to
+disk in order to avoid data\-loss in the event of a power failure.
+This feature is enabled by default.
+.TP
 .B metadata\-transfer
 Automatically perform a metadata transfer when `emerge \-\-sync` is run.
 In versions of portage >=2.1.5, this feature is disabled by
index 3242861cf9a2befb06d82d1f357f42d7a0b1928f..8c5bbf308e62f847548ac6df47fccac3b005d52f 100644 (file)
@@ -96,6 +96,7 @@ SUPPORTED_FEATURES       = frozenset([
                            "downgrade-backup", "ebuild-locks", "fakeroot",
                            "fail-clean", "force-mirror", "force-prefix", "getbinpkg",
                            "installsources", "keeptemp", "keepwork", "fixlafiles", "lmirror",
+                           "merge-sync",
                            "metadata-transfer", "mirror", "multilib-strict", "news",
                            "noauto", "noclean", "nodoc", "noinfo", "noman",
                            "nostrip", "notitles", "parallel-fetch", "parallel-install",
index cb7b39b02f8c86037426cb5eeaf2c652b053f375..edc477a09ba4c6d9fba07045d804efab0bfe27f1 100644 (file)
@@ -30,6 +30,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
        'portage.util.env_update:env_update',
        'portage.util.listdir:dircache,listdir',
        'portage.util.movefile:movefile',
+       'portage.util._ctypes:find_library,LoadLibrary',
        'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
        'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
        'portage.util._async.SchedulerInterface:SchedulerInterface',
@@ -73,6 +74,7 @@ import io
 from itertools import chain
 import logging
 import os as _os
+import platform
 import pwd
 import re
 import stat
@@ -4688,7 +4690,44 @@ class dblink(object):
                disk and avoid data-loss in the event of a power failure. This method
                does nothing if FEATURES=merge-sync is disabled.
                """
-               pass
+               if not self._device_path_map or \
+                       "merge-sync" not in self.settings.features:
+                       return
+
+               syncfs = self._get_syncfs()
+               if syncfs is None:
+                       try:
+                               proc = subprocess.Popen(["sync"])
+                       except EnvironmentError:
+                               pass
+                       else:
+                               proc.wait()
+               else:
+                       for path in self._device_path_map.values():
+                               try:
+                                       fd = os.open(path, os.O_RDONLY)
+                               except OSError:
+                                       pass
+                               else:
+                                       try:
+                                               syncfs(fd)
+                                       except OSError:
+                                               pass
+                                       finally:
+                                               os.close(fd)
+
+       def _get_syncfs(self):
+               if platform.system() == "Linux":
+                       filename = find_library("c")
+                       if filename is not None:
+                               library = LoadLibrary(filename)
+                               if library is not None:
+                                       try:
+                                               return library.syncfs
+                                       except AttributeError:
+                                               pass
+
+               return None
 
        def merge(self, mergeroot, inforoot, myroot=None, myebuild=None, cleanup=0,
                mydbapi=None, prev_mtimes=None, counter=None):