1 |
Asynchronoulsy handle locking of both the category directory and |
2 |
build directory. |
3 |
|
4 |
Bug: https://bugs.gentoo.org/614112 |
5 |
--- |
6 |
pym/_emerge/EbuildBuildDir.py | 76 +++++++++++++++++++++++++++++++++++++++++++ |
7 |
1 file changed, 76 insertions(+) |
8 |
|
9 |
diff --git a/pym/_emerge/EbuildBuildDir.py b/pym/_emerge/EbuildBuildDir.py |
10 |
index 69f694992..9163deacf 100644 |
11 |
--- a/pym/_emerge/EbuildBuildDir.py |
12 |
+++ b/pym/_emerge/EbuildBuildDir.py |
13 |
@@ -1,6 +1,8 @@ |
14 |
# Copyright 1999-2012 Gentoo Foundation |
15 |
# Distributed under the terms of the GNU General Public License v2 |
16 |
|
17 |
+import functools |
18 |
+ |
19 |
from _emerge.AsynchronousLock import AsynchronousLock |
20 |
|
21 |
import portage |
22 |
@@ -84,6 +86,80 @@ class EbuildBuildDir(SlotObject): |
23 |
except OSError: |
24 |
pass |
25 |
|
26 |
+ def async_lock(self): |
27 |
+ """ |
28 |
+ Acquire the lock asynchronously. Notification is available |
29 |
+ via the add_done_callback method of the returned Future instance. |
30 |
+ |
31 |
+ This raises an AlreadyLocked exception if async_lock() is called |
32 |
+ while a lock is already held. In order to avoid this, call |
33 |
+ async_unlock() or check whether the "locked" attribute is True |
34 |
+ or False before calling async_lock(). |
35 |
+ |
36 |
+ @returns: Future, result is None |
37 |
+ """ |
38 |
+ if self._lock_obj is not None: |
39 |
+ raise self.AlreadyLocked((self._lock_obj,)) |
40 |
+ |
41 |
+ dir_path = self.settings.get('PORTAGE_BUILDDIR') |
42 |
+ if not dir_path: |
43 |
+ raise AssertionError('PORTAGE_BUILDDIR is unset') |
44 |
+ catdir = os.path.dirname(dir_path) |
45 |
+ self._catdir = catdir |
46 |
+ catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler) |
47 |
+ builddir_lock = AsynchronousLock(path=dir_path, scheduler=self.scheduler) |
48 |
+ result = self.scheduler.create_future() |
49 |
+ |
50 |
+ def catdir_locked(catdir_lock): |
51 |
+ try: |
52 |
+ self._assert_lock(catdir_lock) |
53 |
+ except AssertionError as e: |
54 |
+ result.set_exception(e) |
55 |
+ return |
56 |
+ |
57 |
+ try: |
58 |
+ portage.util.ensure_dirs(catdir, |
59 |
+ gid=portage.portage_gid, |
60 |
+ mode=0o70, mask=0) |
61 |
+ except PortageException as e: |
62 |
+ if not os.path.isdir(catdir): |
63 |
+ result.set_exception(e) |
64 |
+ return |
65 |
+ |
66 |
+ builddir_lock.addExitListener(builddir_locked) |
67 |
+ builddir_lock.start() |
68 |
+ |
69 |
+ def builddir_locked(builddir_lock): |
70 |
+ try: |
71 |
+ self._assert_lock(builddir_lock) |
72 |
+ except AssertionError as e: |
73 |
+ catdir_lock.async_unlock.add_done_callback( |
74 |
+ functools.partial(catdir_unlocked, exception=e)) |
75 |
+ return |
76 |
+ |
77 |
+ self._lock_obj = builddir_lock |
78 |
+ self.locked = True |
79 |
+ self.settings['PORTAGE_BUILDDIR_LOCKED'] = '1' |
80 |
+ catdir_lock.async_unlock().add_done_callback(catdir_unlocked) |
81 |
+ |
82 |
+ def catdir_unlocked(future, exception=None): |
83 |
+ if not (exception is None and future.exception() is None): |
84 |
+ result.set_exception(exception or future.exception()) |
85 |
+ else: |
86 |
+ result.set_result(None) |
87 |
+ |
88 |
+ try: |
89 |
+ portage.util.ensure_dirs(os.path.dirname(catdir), |
90 |
+ gid=portage.portage_gid, |
91 |
+ mode=0o70, mask=0) |
92 |
+ except PortageException: |
93 |
+ if not os.path.isdir(os.path.dirname(catdir)): |
94 |
+ raise |
95 |
+ |
96 |
+ catdir_lock.addExitListener(catdir_locked) |
97 |
+ catdir_lock.start() |
98 |
+ return result |
99 |
+ |
100 |
def async_unlock(self): |
101 |
""" |
102 |
Release the lock asynchronously. Release notification is available |
103 |
-- |
104 |
2.13.6 |