commit:     9d7b43779d17ca9f698bb90e0ac7b1f43afa9575
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Apr 21 06:05:34 2018 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Apr 22 18:30:52 2018 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=9d7b4377

EbuildBuildDir: add async_lock method (bug 614112)

Asynchronoulsy handle locking of both the category directory and
build directory.

Bug: https://bugs.gentoo.org/614112

 pym/_emerge/EbuildBuildDir.py | 76 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/pym/_emerge/EbuildBuildDir.py b/pym/_emerge/EbuildBuildDir.py
index 69f694992..9163deacf 100644
--- a/pym/_emerge/EbuildBuildDir.py
+++ b/pym/_emerge/EbuildBuildDir.py
@@ -1,6 +1,8 @@
 # Copyright 1999-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import functools
+
 from _emerge.AsynchronousLock import AsynchronousLock
 
 import portage
@@ -84,6 +86,80 @@ class EbuildBuildDir(SlotObject):
                        except OSError:
                                pass
 
+       def async_lock(self):
+               """
+               Acquire the lock asynchronously. Notification is available
+               via the add_done_callback method of the returned Future 
instance.
+
+               This raises an AlreadyLocked exception if async_lock() is called
+               while a lock is already held. In order to avoid this, call
+               async_unlock() or check whether the "locked" attribute is True
+               or False before calling async_lock().
+
+               @returns: Future, result is None
+               """
+               if self._lock_obj is not None:
+                       raise self.AlreadyLocked((self._lock_obj,))
+
+               dir_path = self.settings.get('PORTAGE_BUILDDIR')
+               if not dir_path:
+                       raise AssertionError('PORTAGE_BUILDDIR is unset')
+               catdir = os.path.dirname(dir_path)
+               self._catdir = catdir
+               catdir_lock = AsynchronousLock(path=catdir, 
scheduler=self.scheduler)
+               builddir_lock = AsynchronousLock(path=dir_path, 
scheduler=self.scheduler)
+               result = self.scheduler.create_future()
+
+               def catdir_locked(catdir_lock):
+                       try:
+                               self._assert_lock(catdir_lock)
+                       except AssertionError as e:
+                               result.set_exception(e)
+                               return
+
+                       try:
+                               portage.util.ensure_dirs(catdir,
+                                       gid=portage.portage_gid,
+                                       mode=0o70, mask=0)
+                       except PortageException as e:
+                               if not os.path.isdir(catdir):
+                                       result.set_exception(e)
+                                       return
+
+                       builddir_lock.addExitListener(builddir_locked)
+                       builddir_lock.start()
+
+               def builddir_locked(builddir_lock):
+                       try:
+                               self._assert_lock(builddir_lock)
+                       except AssertionError as e:
+                               catdir_lock.async_unlock.add_done_callback(
+                                       functools.partial(catdir_unlocked, 
exception=e))
+                               return
+
+                       self._lock_obj = builddir_lock
+                       self.locked = True
+                       self.settings['PORTAGE_BUILDDIR_LOCKED'] = '1'
+                       
catdir_lock.async_unlock().add_done_callback(catdir_unlocked)
+
+               def catdir_unlocked(future, exception=None):
+                       if not (exception is None and future.exception() is 
None):
+                               result.set_exception(exception or 
future.exception())
+                       else:
+                               result.set_result(None)
+
+               try:
+                       portage.util.ensure_dirs(os.path.dirname(catdir),
+                               gid=portage.portage_gid,
+                               mode=0o70, mask=0)
+               except PortageException:
+                       if not os.path.isdir(os.path.dirname(catdir)):
+                               raise
+
+               catdir_lock.addExitListener(catdir_locked)
+               catdir_lock.start()
+               return result
+
        def async_unlock(self):
                """
                Release the lock asynchronously. Release notification is 
available

Reply via email to