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