1 |
Split out a first_existing function, in order to improve logic related |
2 |
to the _unprivileged_mode function so that it checks whether it's |
3 |
possible to create the specified target root (instead of requiring that |
4 |
the target root already exists). |
5 |
--- |
6 |
pym/portage/data.py | 20 +++++++++------ |
7 |
pym/portage/package/ebuild/config.py | 23 ++++++----------- |
8 |
pym/portage/util/path.py | 48 ++++++++++++++++++++++++++++++++++++ |
9 |
3 files changed, 67 insertions(+), 24 deletions(-) |
10 |
create mode 100644 pym/portage/util/path.py |
11 |
|
12 |
diff --git a/pym/portage/data.py b/pym/portage/data.py |
13 |
index 3e03eef..d9b36ee 100644 |
14 |
--- a/pym/portage/data.py |
15 |
+++ b/pym/portage/data.py |
16 |
@@ -8,6 +8,7 @@ import portage |
17 |
portage.proxy.lazyimport.lazyimport(globals(), |
18 |
'portage.output:colorize', |
19 |
'portage.util:writemsg', |
20 |
+ 'portage.util.path:first_existing', |
21 |
'subprocess' |
22 |
) |
23 |
from portage.localization import _ |
24 |
@@ -94,14 +95,16 @@ def _get_global(k): |
25 |
else: |
26 |
# The config class has equivalent code, but we also need to |
27 |
# do it here if _disable_legacy_globals() has been called. |
28 |
- eroot = os.path.join(os.environ.get('ROOT', os.sep), |
29 |
- portage.const.EPREFIX.lstrip(os.sep)) |
30 |
+ eroot_or_parent = first_existing(os.path.join( |
31 |
+ os.environ.get('ROOT', os.sep), |
32 |
+ portage.const.EPREFIX.lstrip(os.sep))) |
33 |
try: |
34 |
- eroot_st = os.stat(eroot) |
35 |
+ eroot_st = os.stat(eroot_or_parent) |
36 |
except OSError: |
37 |
pass |
38 |
else: |
39 |
- unprivileged = _unprivileged_mode(eroot, eroot_st) |
40 |
+ unprivileged = _unprivileged_mode( |
41 |
+ eroot_or_parent, eroot_st) |
42 |
|
43 |
v = 0 |
44 |
if uid == 0: |
45 |
@@ -206,14 +209,15 @@ def _get_global(k): |
46 |
else: |
47 |
# The config class has equivalent code, but we also need to |
48 |
# do it here if _disable_legacy_globals() has been called. |
49 |
- eroot = os.path.join(os.environ.get('ROOT', os.sep), |
50 |
- portage.const.EPREFIX.lstrip(os.sep)) |
51 |
+ eroot_or_parent = first_existing(os.path.join( |
52 |
+ os.environ.get('ROOT', os.sep), |
53 |
+ portage.const.EPREFIX.lstrip(os.sep))) |
54 |
try: |
55 |
- eroot_st = os.stat(eroot) |
56 |
+ eroot_st = os.stat(eroot_or_parent) |
57 |
except OSError: |
58 |
pass |
59 |
else: |
60 |
- if _unprivileged_mode(eroot, eroot_st): |
61 |
+ if _unprivileged_mode(eroot_or_parent, eroot_st): |
62 |
if k == '_portage_grpname': |
63 |
try: |
64 |
grp_struct = grp.getgrgid(eroot_st.st_gid) |
65 |
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py |
66 |
index c7308a4..bf39487 100644 |
67 |
--- a/pym/portage/package/ebuild/config.py |
68 |
+++ b/pym/portage/package/ebuild/config.py |
69 |
@@ -48,6 +48,7 @@ from portage.util import ensure_dirs, getconfig, grabdict, \ |
70 |
grabdict_package, grabfile, grabfile_package, LazyItemsDict, \ |
71 |
normalize_path, shlex_split, stack_dictlist, stack_dicts, stack_lists, \ |
72 |
writemsg, writemsg_level, _eapi_cache |
73 |
+from portage.util.path import first_existing |
74 |
from portage.util._path import exists_raise_eaccess, isdir_raise_eaccess |
75 |
from portage.versions import catpkgsplit, catsplit, cpv_getkey, _pkg_str |
76 |
|
77 |
@@ -848,14 +849,16 @@ class config(object): |
78 |
"PORTAGE_INST_UID": "0", |
79 |
} |
80 |
|
81 |
+ eroot_or_parent = first_existing(eroot) |
82 |
unprivileged = False |
83 |
try: |
84 |
- eroot_st = os.stat(eroot) |
85 |
+ eroot_st = os.stat(eroot_or_parent) |
86 |
except OSError: |
87 |
pass |
88 |
else: |
89 |
|
90 |
- if portage.data._unprivileged_mode(eroot, eroot_st): |
91 |
+ if portage.data._unprivileged_mode( |
92 |
+ eroot_or_parent, eroot_st): |
93 |
unprivileged = True |
94 |
|
95 |
default_inst_ids["PORTAGE_INST_GID"] = str(eroot_st.st_gid) |
96 |
@@ -897,20 +900,8 @@ class config(object): |
97 |
# In unprivileged mode, automatically make |
98 |
# depcachedir relative to target_root if the |
99 |
# default depcachedir is not writable. |
100 |
- current_dir = self.depcachedir |
101 |
- found_dir = False |
102 |
- while current_dir != os.sep and not found_dir: |
103 |
- try: |
104 |
- os.stat(current_dir) |
105 |
- found_dir = True |
106 |
- except OSError as e: |
107 |
- if e.errno == errno.ENOENT: |
108 |
- current_dir = os.path.dirname( |
109 |
- current_dir) |
110 |
- else: |
111 |
- found_dir = True |
112 |
- |
113 |
- if not os.access(current_dir, os.W_OK): |
114 |
+ if not os.access(first_existing(self.depcachedir), |
115 |
+ os.W_OK): |
116 |
self.depcachedir = os.path.join(eroot, |
117 |
DEPCACHE_PATH.lstrip(os.sep)) |
118 |
|
119 |
diff --git a/pym/portage/util/path.py b/pym/portage/util/path.py |
120 |
new file mode 100644 |
121 |
index 0000000..f77f30f |
122 |
--- /dev/null |
123 |
+++ b/pym/portage/util/path.py |
124 |
@@ -0,0 +1,48 @@ |
125 |
+# Copyright 2014 Gentoo Foundation |
126 |
+# Distributed under the terms of the GNU General Public License v2 |
127 |
+ |
128 |
+import errno |
129 |
+ |
130 |
+from portage import os |
131 |
+ |
132 |
+def first_existing(path): |
133 |
+ """ |
134 |
+ Returns the first existing path element, traversing from the given |
135 |
+ path to the root directory. A path is considered to exists if lstat |
136 |
+ either succeeds or raises an error other than ENOENT or ESTALE. |
137 |
+ |
138 |
+ This can be particularly useful to check if there is permission to |
139 |
+ create a particular file or directory, without actually creating |
140 |
+ anything. |
141 |
+ |
142 |
+ @param path: a filesystem path |
143 |
+ @type path: str |
144 |
+ @rtype: str |
145 |
+ @return: the element that exists |
146 |
+ """ |
147 |
+ existing = False |
148 |
+ for path in iter_parents(path): |
149 |
+ try: |
150 |
+ os.lstat(path) |
151 |
+ existing = True |
152 |
+ except OSError as e: |
153 |
+ if e.errno not in (errno.ENOENT, errno.ESTALE): |
154 |
+ existing = True |
155 |
+ |
156 |
+ if existing: |
157 |
+ return path |
158 |
+ |
159 |
+ return os.sep |
160 |
+ |
161 |
+def iter_parents(path): |
162 |
+ """ |
163 |
+ @param path: a filesystem path |
164 |
+ @type path: str |
165 |
+ @rtype: iterator |
166 |
+ @return: an iterator which yields path and all parents of path, |
167 |
+ ending with the root directory |
168 |
+ """ |
169 |
+ yield path |
170 |
+ while path != os.sep: |
171 |
+ path = os.path.dirname(path) |
172 |
+ yield path |
173 |
-- |
174 |
2.0.4 |