commit:     acf5d6bee0c99dd50d13a963243933fca1d8120c
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Nov 15 06:22:15 2014 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Nov 17 14:56:24 2014 +0000
URL:        
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=acf5d6be

unprivileged mode: use first_existing helper func

Split out a first_existing function, in order to improve logic related
to the _unprivileged_mode function so that it checks whether it's
possible to create the specified target root (instead of requiring that
the target root already exists).

Acked-by: Alexander Berntsen <bernalex <AT> gentoo.org>

---
 pym/portage/data.py                  | 20 +++++++++------
 pym/portage/package/ebuild/config.py | 23 ++++++-----------
 pym/portage/util/path.py             | 48 ++++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 24 deletions(-)

diff --git a/pym/portage/data.py b/pym/portage/data.py
index 3e03eef..d9b36ee 100644
--- a/pym/portage/data.py
+++ b/pym/portage/data.py
@@ -8,6 +8,7 @@ import portage
 portage.proxy.lazyimport.lazyimport(globals(),
        'portage.output:colorize',
        'portage.util:writemsg',
+       'portage.util.path:first_existing',
        'subprocess'
 )
 from portage.localization import _
@@ -94,14 +95,16 @@ def _get_global(k):
                else:
                        # The config class has equivalent code, but we also 
need to
                        # do it here if _disable_legacy_globals() has been 
called.
-                       eroot = os.path.join(os.environ.get('ROOT', os.sep),
-                               portage.const.EPREFIX.lstrip(os.sep))
+                       eroot_or_parent = first_existing(os.path.join(
+                               os.environ.get('ROOT', os.sep),
+                               portage.const.EPREFIX.lstrip(os.sep)))
                        try:
-                               eroot_st = os.stat(eroot)
+                               eroot_st = os.stat(eroot_or_parent)
                        except OSError:
                                pass
                        else:
-                               unprivileged = _unprivileged_mode(eroot, 
eroot_st)
+                               unprivileged = _unprivileged_mode(
+                                       eroot_or_parent, eroot_st)
 
                v = 0
                if uid == 0:
@@ -206,14 +209,15 @@ def _get_global(k):
                else:
                        # The config class has equivalent code, but we also 
need to
                        # do it here if _disable_legacy_globals() has been 
called.
-                       eroot = os.path.join(os.environ.get('ROOT', os.sep),
-                               portage.const.EPREFIX.lstrip(os.sep))
+                       eroot_or_parent = first_existing(os.path.join(
+                               os.environ.get('ROOT', os.sep),
+                               portage.const.EPREFIX.lstrip(os.sep)))
                        try:
-                               eroot_st = os.stat(eroot)
+                               eroot_st = os.stat(eroot_or_parent)
                        except OSError:
                                pass
                        else:
-                               if _unprivileged_mode(eroot, eroot_st):
+                               if _unprivileged_mode(eroot_or_parent, 
eroot_st):
                                        if k == '_portage_grpname':
                                                try:
                                                        grp_struct = 
grp.getgrgid(eroot_st.st_gid)

diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index c7308a4..bf39487 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -48,6 +48,7 @@ from portage.util import ensure_dirs, getconfig, grabdict, \
        grabdict_package, grabfile, grabfile_package, LazyItemsDict, \
        normalize_path, shlex_split, stack_dictlist, stack_dicts, stack_lists, \
        writemsg, writemsg_level, _eapi_cache
+from portage.util.path import first_existing
 from portage.util._path import exists_raise_eaccess, isdir_raise_eaccess
 from portage.versions import catpkgsplit, catsplit, cpv_getkey, _pkg_str
 
@@ -848,14 +849,16 @@ class config(object):
                                "PORTAGE_INST_UID": "0",
                        }
 
+                       eroot_or_parent = first_existing(eroot)
                        unprivileged = False
                        try:
-                               eroot_st = os.stat(eroot)
+                               eroot_st = os.stat(eroot_or_parent)
                        except OSError:
                                pass
                        else:
 
-                               if portage.data._unprivileged_mode(eroot, 
eroot_st):
+                               if portage.data._unprivileged_mode(
+                                       eroot_or_parent, eroot_st):
                                        unprivileged = True
 
                                        default_inst_ids["PORTAGE_INST_GID"] = 
str(eroot_st.st_gid)
@@ -897,20 +900,8 @@ class config(object):
                                        # In unprivileged mode, automatically 
make
                                        # depcachedir relative to target_root 
if the
                                        # default depcachedir is not writable.
-                                       current_dir = self.depcachedir
-                                       found_dir = False
-                                       while current_dir != os.sep and not 
found_dir:
-                                               try:
-                                                       os.stat(current_dir)
-                                                       found_dir = True
-                                               except OSError as e:
-                                                       if e.errno == 
errno.ENOENT:
-                                                               current_dir = 
os.path.dirname(
-                                                                       
current_dir)
-                                                       else:
-                                                               found_dir = True
-
-                                       if not os.access(current_dir, os.W_OK):
+                                       if not 
os.access(first_existing(self.depcachedir),
+                                               os.W_OK):
                                                self.depcachedir = 
os.path.join(eroot,
                                                        
DEPCACHE_PATH.lstrip(os.sep))
 

diff --git a/pym/portage/util/path.py b/pym/portage/util/path.py
new file mode 100644
index 0000000..a0b96c7
--- /dev/null
+++ b/pym/portage/util/path.py
@@ -0,0 +1,48 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+
+from portage import os
+
+def first_existing(path):
+       """
+       Returns the first existing path element, traversing from the given
+       path to the root directory. A path is considered to exist if lstat
+       either succeeds or raises an error other than ENOENT or ESTALE.
+
+       This can be particularly useful to check if there is permission to
+       create a particular file or directory, without actually creating
+       anything.
+
+       @param path: a filesystem path
+       @type path: str
+       @rtype: str
+       @return: the element that exists
+       """
+       existing = False
+       for path in iter_parents(path):
+               try:
+                       os.lstat(path)
+                       existing = True
+               except OSError as e:
+                       if e.errno not in (errno.ENOENT, errno.ESTALE):
+                               existing = True
+
+               if existing:
+                       return path
+
+       return os.sep
+
+def iter_parents(path):
+       """
+       @param path: a filesystem path
+       @type path: str
+       @rtype: iterator
+       @return: an iterator which yields path and all parents of path,
+               ending with the root directory
+       """
+       yield path
+       while path != os.sep:
+               path = os.path.dirname(path)
+               yield path

Reply via email to