[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/

2018-07-15 Thread Zac Medico
commit: 27eeeb6e4fc8e68efa003b2db5bbd8cc4afe336a
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Jul 13 22:19:29 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Jul 15 05:10:51 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=27eeeb6e

portdbapi.cp_list: cache repo associations (bug 650814)

Make portdbapi.cp_list return _pkg_str instances that have a 'repo'
attribute (bindbapi.cp_list already does this), with results
in ascending order by (pkg.version, repo.priority). Optimize
portdbapi.findname2 to use the 'repo' attribute to enable cached
results for files previously found by the portdbapi.cp_list
method, avoiding filesystem access when possible. Optimize the
depgraph._iter_match_pkgs_atom method by elimination of the repo
loop, since portdbapi.cp_list now returns separate items when the
same package version is found in multiple repos.

Bug: https://bugs.gentoo.org/650814
Reviewed-by: Brian Dolbec  gentoo.org>

 pym/_emerge/depgraph.py   | 12 +++-
 pym/portage/dbapi/porttree.py | 41 +
 2 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 42857c1a5..b63d4f242 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5613,10 +5613,6 @@ class depgraph(object):
if cp_list:
atom_set = InternalPackageSet(initial_atoms=(atom,),
allow_repo=True)
-   if atom.repo is None and hasattr(db, "getRepositories"):
-   repo_list = 
db.getRepositories(catpkg=atom_exp.cp)
-   else:
-   repo_list = [atom.repo]
 
# descending order
cp_list.reverse()
@@ -5624,13 +5620,11 @@ class depgraph(object):
# Call match_from_list on one cpv at a time, in 
order
# to avoid unnecessary match_from_list 
comparisons on
# versions that are never yielded from this 
method.
-   if not match_from_list(atom_exp, [cpv]):
-   continue
-   for repo in repo_list:
-
+   if match_from_list(atom_exp, [cpv]):
try:
pkg = self._pkg(cpv, pkg_type, 
root_config,
-   installed=installed, 
onlydeps=onlydeps, myrepo=repo)
+   installed=installed, 
onlydeps=onlydeps,
+   myrepo=getattr(cpv, 
'repo', None))
except 
portage.exception.PackageNotFound:
pass
else:

diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
index 3e36024ff..f6076ee2b 100644
--- a/pym/portage/dbapi/porttree.py
+++ b/pym/portage/dbapi/porttree.py
@@ -459,6 +459,9 @@ class portdbapi(dbapi):
mytree = self.treemap.get(myrepo)
if mytree is None:
return (None, 0)
+   elif mytree is not None:
+   # myrepo enables cached results when available
+   myrepo = self.repositories.location_map.get(mytree)
 
mysplit = mycpv.split("/")
psplit = pkgsplit(mysplit[1])
@@ -495,6 +498,14 @@ class portdbapi(dbapi):
relative_path = mysplit[0] + _os.sep + psplit[0] + _os.sep + \
mysplit[1] + ".ebuild"
 
+   # There is no need to access the filesystem when the package
+   # comes from this db and the package repo attribute corresponds
+   # to the desired repo, since the file was previously found by
+   # the cp_list method.
+   if (myrepo is not None and myrepo == getattr(mycpv, 'repo', 
None)
+   and self is getattr(mycpv, '_db', None)):
+   return (mytree + _os.sep + relative_path, mytree)
+
for x in mytrees:
filename = x + _os.sep + relative_path
if _os.access(_unicode_encode(filename,
@@ -950,18 +961,23 @@ class portdbapi(dbapi):
return cachelist[:]
mysplit = mycp.split("/")
invalid_category = mysplit[0] not in self._categories
-   d={}
+   # Process repos in ascending order by repo.priority, so that
+   # stable sort by version produces results ordered by
+   # (pkg.version, repo.priority).
if mytree is not None:
 

[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/

2018-07-14 Thread Zac Medico
commit: e691f07bf0572fad7686a54d628c1a29aec4ebe4
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Jul 12 09:48:32 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Jul 14 23:31:34 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=e691f07b

dbapi: fix repoman implicit IUSE (bug 660982)

Account for repoman modifications of the portdbapi self.settings
reference, and treat all flags as valid for the empty profile
because it does not have any implicit IUSE settings.

Bug: https://bugs.gentoo.org/660982
Reviewed-by: Brian Dolbec  gentoo.org>

 pym/_emerge/Package.py|  5 -
 pym/portage/dbapi/__init__.py | 16 
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/Package.py b/pym/_emerge/Package.py
index a7ce00bc9..5f34f3d27 100644
--- a/pym/_emerge/Package.py
+++ b/pym/_emerge/Package.py
@@ -93,7 +93,10 @@ class Package(Task):
# sync metadata with validated repo (may be UNKNOWN_REPO)
self._metadata['repository'] = self.cpv.repo
 
-   implicit_match = db._iuse_implicit_cnstr(self.cpv, 
self._metadata)
+   if self.root_config.settings.local_config:
+   implicit_match = db._iuse_implicit_cnstr(self.cpv, 
self._metadata)
+   else:
+   implicit_match = 
db._repoman_iuse_implicit_cnstr(self.cpv, self._metadata)
usealiases = 
self.root_config.settings._use_manager.getUseAliases(self)
self.iuse = self._iuse(self, self._metadata["IUSE"].split(),
implicit_match, usealiases, self.eapi)

diff --git a/pym/portage/dbapi/__init__.py b/pym/portage/dbapi/__init__.py
index d320cc75f..61d301839 100644
--- a/pym/portage/dbapi/__init__.py
+++ b/pym/portage/dbapi/__init__.py
@@ -216,6 +216,22 @@ class dbapi(object):
 
yield cpv
 
+   def _repoman_iuse_implicit_cnstr(self, pkg, metadata):
+   """
+   In repoman's version of _iuse_implicit_cnstr, account for 
modifications
+   of the self.settings reference between calls, and treat all 
flags as
+   valid for the empty profile because it does not have any 
implicit IUSE
+   settings. See bug 660982.
+   """
+   eapi_attrs = _get_eapi_attrs(metadata["EAPI"])
+   if eapi_attrs.iuse_effective:
+   iuse_implicit_match = lambda flag: (True if not 
self.settings.profile_path
+   else self.settings._iuse_effective_match(flag))
+   else:
+   iuse_implicit_match = lambda flag: (True if not 
self.settings.profile_path
+   else self.settings._iuse_implicit_match(flag))
+   return iuse_implicit_match
+
def _iuse_implicit_cnstr(self, pkg, metadata):
"""
Construct a callable that checks if a given USE flag should



[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/, pym/portage/tests/ebuild/, ...

2018-04-20 Thread Zac Medico
commit: 90fa156df0e6ef4fa9ef1a80c495511f4630de86
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Apr 20 15:21:58 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri Apr 20 15:50:43 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=90fa156d

EbuildBuildDir: remove synchronous unlock method (bug 614108)

The synchronous unlock method can trigger event loop recursion if the
event loop is already running, which is incompatible with asyncio's
default event loop. Therefore, migrate the last consumers to use the
async_unlock method, and remove the synchronous unlock method.

Bug: https://bugs.gentoo.org/614108
Bug: https://bugs.gentoo.org/649588

 pym/_emerge/EbuildBuildDir.py   | 21 -
 pym/_emerge/Scheduler.py|  2 +-
 pym/portage/dbapi/vartree.py|  3 ++-
 pym/portage/package/ebuild/doebuild.py  |  9 ++---
 pym/portage/tests/ebuild/test_ipc_daemon.py |  2 +-
 5 files changed, 10 insertions(+), 27 deletions(-)

diff --git a/pym/_emerge/EbuildBuildDir.py b/pym/_emerge/EbuildBuildDir.py
index 1f1385a3b..69f694992 100644
--- a/pym/_emerge/EbuildBuildDir.py
+++ b/pym/_emerge/EbuildBuildDir.py
@@ -84,27 +84,6 @@ class EbuildBuildDir(SlotObject):
except OSError:
pass
 
-   def unlock(self):
-   if self._lock_obj is None:
-   return
-
-   # Keep this legacy implementation until all consumers have 
migrated
-   # to async_unlock, since run_until_complete(self.async_unlock())
-   # would add unwanted event loop recursion here.
-   self._lock_obj.unlock()
-   self._lock_obj = None
-   self.locked = False
-   self.settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
-   catdir_lock = AsynchronousLock(path=self._catdir, 
scheduler=self.scheduler)
-   catdir_lock.start()
-   if catdir_lock.wait() == os.EX_OK:
-   try:
-   os.rmdir(self._catdir)
-   except OSError:
-   pass
-   finally:
-   catdir_lock.unlock()
-
def async_unlock(self):
"""
Release the lock asynchronously. Release notification is 
available

diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py
index eb1cd0108..a248f5974 100644
--- a/pym/_emerge/Scheduler.py
+++ b/pym/_emerge/Scheduler.py
@@ -911,7 +911,7 @@ class Scheduler(PollScheduler):
clean_phase.start()
clean_phase.wait()
 
-   build_dir.unlock()
+   
sched_iface.run_until_complete(build_dir.async_unlock())
 
if failures:
return FAILURE

diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index c274248e3..8ad6957a3 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -2199,7 +2199,8 @@ class dblink(object):
retval = phase.wait()
finally:
if builddir_lock is not None:
-   builddir_lock.unlock()
+   scheduler.run_until_complete(
+   
builddir_lock.async_unlock())
 
if log_path is not None:
 

diff --git a/pym/portage/package/ebuild/doebuild.py 
b/pym/portage/package/ebuild/doebuild.py
index 8436c0b10..bdcdfbe87 100644
--- a/pym/portage/package/ebuild/doebuild.py
+++ b/pym/portage/package/ebuild/doebuild.py
@@ -819,7 +819,8 @@ def doebuild(myebuild, mydo, _unused=DeprecationWarning, 
settings=None, debug=0,
fd_pipes=fd_pipes, returnpid=returnpid)
finally:
if builddir_lock is not None:
-   builddir_lock.unlock()
+   
builddir_lock.scheduler.run_until_complete(
+   builddir_lock.async_unlock())
 
# get possible slot information from the deps file
if mydo == "depend":
@@ -943,7 +944,8 @@ def doebuild(myebuild, mydo, _unused=DeprecationWarning, 
settings=None, debug=0,
_spawn_phase("clean", 
mysettings)
finally:
if builddir_lock is not None:
-   builddir_lock.unlock()
+   
builddir_lock.scheduler.run_until_complete(
+

[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/

2017-03-26 Thread Zac Medico
commit: dfa317d0b8572a6c463ad5e778a8ca4633086f1b
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Mar 26 23:54:04 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Mar 27 02:07:23 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=dfa317d0

emerge: use asyncio interfaces for spinner during owner lookup (bug 591760)

X-Gentoo-bug: 591760
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=591760
Acked-by: Brian Dolbec  gentoo.org>

 pym/_emerge/depgraph.py  | 13 -
 pym/portage/dbapi/vartree.py | 22 +-
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 7c9130b38..04e724d8d 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3668,17 +3668,20 @@ class depgraph(object):
def select_files(self, args):
# Use the global event loop for spinner progress
# indication during file owner lookups (bug #461412).
-   spinner_id = None
+   def spinner_cb():
+   self._frozen_config.spinner.update()
+   spinner_cb.handle = 
self._event_loop.call_soon(spinner_cb)
+
+   spinner_cb.handle = None
try:
spinner = self._frozen_config.spinner
if spinner is not None and \
spinner.update is not spinner.update_quiet:
-   spinner_id = self._event_loop.idle_add(
-   self._frozen_config.spinner.update)
+   spinner_cb.handle = 
self._event_loop.call_soon(spinner_cb)
return self._select_files(args)
finally:
-   if spinner_id is not None:
-   self._event_loop.source_remove(spinner_id)
+   if spinner_cb.handle is not None:
+   spinner_cb.handle.cancel()
 
def _select_files(self, myfiles):
"""Given a list of .tbz2s, .ebuilds sets, and deps, populate

diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index c421dc50b..7c8f150bb 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -1369,32 +1369,28 @@ class vardbapi(dbapi):
global_event_loop() or EventLoop(main=False))
root = self._vardb._eroot
 
-   def search_pkg(cpv):
+   def search_pkg(cpv, search_future):
dblnk = self._vardb._dblink(cpv)
+   results = []
for path, name, is_basename in path_info_list:
if is_basename:
for p in dblnk._contents.keys():
if os.path.basename(p) 
== name:
-   
search_pkg.results.append((dblnk,
+   
results.append((dblnk,

dblnk._contents.unmap_key(

p)[len(root):]))
else:
key = 
dblnk._match_contents(path)
if key is not False:
-   
search_pkg.results.append(
+   results.append(
(dblnk, 
key[len(root):]))
-   search_pkg.complete = True
-   return False
-
-   search_pkg.results = []
+   search_future.set_result(results)
 
for cpv in self._vardb.cpv_all():
-   del search_pkg.results[:]
-   search_pkg.complete = False
-   event_loop.idle_add(search_pkg, cpv)
-   while not search_pkg.complete:
-   event_loop.iteration()
-   for result in search_pkg.results:
+   search_future = event_loop.create_future()
+   event_loop.call_soon(search_pkg, cpv, 
search_future)
+   event_loop.run_until_complete(search_future)
+   for result in search_future.result():
yield result
 
 class vartree(object):



[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/, pym/portage/tests/emerge/

2016-05-18 Thread Zac Medico
commit: dccd4687999aed1788dfe5c3461523f2b23ca79f
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Mar 13 07:12:15 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed May 18 16:11:35 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=dccd4687

dblink: add locks for parallel-install with blockers (bug 576888)

For parallel-install, lock package slots of the current package and
blocked packages, in order to account for blocked packages being
removed or replaced concurrently. Acquire locks in predictable order,
preventing deadlocks with competitors that may be trying to acquire
overlapping locks.

X-Gentoo-Bug: 576888
X-Gentoo-Bug-url: https://bugs.gentoo.org/show_bug.cgi?id=576888
Acked-by: Alexander Berntsen  gentoo.org>
Acked-by: Brian Dolbec  gentoo.org>

 pym/_emerge/Scheduler.py   |   9 +-
 pym/portage/dbapi/vartree.py   |  99 +++-
 .../emerge/test_emerge_blocker_file_collision.py   | 168 +
 3 files changed, 267 insertions(+), 9 deletions(-)

diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py
index 20a4e85..97b826a 100644
--- a/pym/_emerge/Scheduler.py
+++ b/pym/_emerge/Scheduler.py
@@ -586,18 +586,15 @@ class Scheduler(PollScheduler):
 
blocker_db = self._blocker_db[new_pkg.root]
 
-   blocker_dblinks = []
+   blocked_pkgs = []
for blocking_pkg in blocker_db.findInstalledBlockers(new_pkg):
if new_pkg.slot_atom == blocking_pkg.slot_atom:
continue
if new_pkg.cpv == blocking_pkg.cpv:
continue
-   blocker_dblinks.append(portage.dblink(
-   blocking_pkg.category, blocking_pkg.pf, 
blocking_pkg.root,
-   self.pkgsettings[blocking_pkg.root], 
treetype="vartree",
-   
vartree=self.trees[blocking_pkg.root]["vartree"]))
+   blocked_pkgs.append(blocking_pkg)
 
-   return blocker_dblinks
+   return blocked_pkgs
 
def _generate_digests(self):
"""

diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index e7effca..6209a86 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -168,6 +168,7 @@ class vardbapi(dbapi):
self._conf_mem_file = self._eroot + CONFIG_MEMORY_FILE
self._fs_lock_obj = None
self._fs_lock_count = 0
+   self._slot_locks = {}
 
if vartree is None:
vartree = portage.db[settings['EROOT']]['vartree']
@@ -284,6 +285,38 @@ class vardbapi(dbapi):
self._fs_lock_obj = None
self._fs_lock_count -= 1
 
+   def _slot_lock(self, slot_atom):
+   """
+   Acquire a slot lock (reentrant).
+
+   WARNING: The varbapi._slot_lock method is not safe to call
+   in the main process when that process is scheduling
+   install/uninstall tasks in parallel, since the locks would
+   be inherited by child processes. In order to avoid this sort
+   of problem, this method should be called in a subprocess
+   (typically spawned by the MergeProcess class).
+   """
+   lock, counter = self._slot_locks.get(slot_atom, (None, 0))
+   if lock is None:
+   lock_path = self.getpath("%s:%s" % (slot_atom.cp, 
slot_atom.slot))
+   ensure_dirs(os.path.dirname(lock_path))
+   lock = lockfile(lock_path, wantnewlockfile=True)
+   self._slot_locks[slot_atom] = (lock, counter + 1)
+
+   def _slot_unlock(self, slot_atom):
+   """
+   Release a slot lock (or decrementing recursion level).
+   """
+   lock, counter = self._slot_locks.get(slot_atom, (None, 0))
+   if lock is None:
+   raise AssertionError("not locked")
+   counter -= 1
+   if counter == 0:
+   unlockfile(lock)
+   del self._slot_locks[slot_atom]
+   else:
+   self._slot_locks[slot_atom] = (lock, counter)
+
def _bump_mtime(self, cpv):
"""
This is called before an after any modifications, so that 
consumers
@@ -1590,6 +1623,7 @@ class dblink(object):
# compliance with RESTRICT=preserve-libs.
self._preserve_libs = "preserve-libs" in mysettings.features
self._contents = ContentsCaseSensitivityManager(self)
+   self._slot_locks = []
 
def __hash__(self):
return hash(self._hash_key)
@@ -1623,6 +1657,58 @@ class dblink(object):
def unl

[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/

2015-04-24 Thread Zac Medico
commit: 89a48c206f007d4b1e323c089842cd6475c1eea2
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Apr 24 16:25:45 2015 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri Apr 24 17:54:24 2015 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=89a48c20

VdbMetadataDelta.applyDelta: remove replaced versions (bug 547532)

Since commit d800d224ab38c0f524d3fe858ebe201cbfa903c1, emerge --search
could randomly report incorrect results for the installed version
due to the replaced version of a given slot remaining in the cache.

Fixes: d800d224ab38 ("Log changes between vdb_metadata.pickle updates")
X-Gentoo-Bug: 547532
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=547532
Acked-by: Brian Dolbec  gentoo.org>

 pym/_emerge/search.py  | 10 --
 pym/portage/dbapi/_VdbMetadataDelta.py | 22 +-
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/pym/_emerge/search.py b/pym/_emerge/search.py
index e7f6f44..5a8143c 100644
--- a/pym/_emerge/search.py
+++ b/pym/_emerge/search.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2014 Gentoo Foundation
+# Copyright 1999-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import unicode_literals
@@ -442,7 +442,13 @@ class search(object):
def getInstallationStatus(self,package):
installed_package = self._vardb.match(package)
if installed_package:
-   installed_package = installed_package[-1]
+   try:
+   self._vardb.match_unordered
+   except AttributeError:
+   installed_package = installed_package[-1]
+   else:
+   installed_package = 
portage.best(installed_package)
+
else:
installed_package = ""
result = ""

diff --git a/pym/portage/dbapi/_VdbMetadataDelta.py 
b/pym/portage/dbapi/_VdbMetadataDelta.py
index 3e3ff18..2dbb07a 100644
--- a/pym/portage/dbapi/_VdbMetadataDelta.py
+++ b/pym/portage/dbapi/_VdbMetadataDelta.py
@@ -1,4 +1,4 @@
-# Copyright 2014 Gentoo Foundation
+# Copyright 2014-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import errno
@@ -8,6 +8,7 @@ import os
 
 from portage import _encodings
 from portage.util import atomic_ofstream
+from portage.versions import cpv_getkey
 
 class VdbMetadataDelta(object):
 
@@ -138,10 +139,12 @@ class VdbMetadataDelta(object):
 
def applyDelta(self, data):
packages = self._vardb._aux_cache["packages"]
+   added_slots = {}
for delta in data["deltas"]:
cpv = delta["package"] + "-" + delta["version"]
event = delta["event"]
if event == "add":
+   added_slots[cpv] = delta
# Use aux_get to populate the cache
# for this cpv.
if cpv not in packages:
@@ -151,3 +154,20 @@ class VdbMetadataDelta(object):
pass
elif event == "remove":
packages.pop(cpv, None)
+
+   # Remove replaced versions from updated slots
+   for cached_cpv, (mtime, metadata) in list(packages.items()):
+   if cached_cpv in added_slots:
+   continue
+   replaced = False
+   for cpv, delta in added_slots.items():
+   if (cached_cpv.startswith(delta["package"]) and
+   metadata.get("SLOT") == delta["slot"] 
and
+   cpv_getkey(cached_cpv) == 
delta["package"]):
+   replaced = True
+   break
+   if replaced:
+   del packages[cached_cpv]
+   del added_slots[cpv]
+   if not added_slots:
+   break



[gentoo-commits] proj/portage:master commit in: pym/_emerge/, pym/portage/dbapi/

2014-11-23 Thread Zac Medico
commit: 206efe5f6341bce99a5e9994a0458c304513b2c3
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Nov 20 12:38:59 2014 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Nov 24 07:38:51 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=206efe5f

emerge: check for writable PKGDIR (490732)

If there are packages to be merged and "buildpkg" or "buildsyspkg" is
enabled, then bail out early if PKGDIR is not writable (in order to
avoid a fatal EROFS error which would otherwise occur later on).
Behavior remains unchanged for --pretend, --fetchonly and
--fetch-all-uri. For --ask, it will bail out just after the last
relevant --ask prompt.

X-Gentoo-Bug: 490732
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=490732
Acked-by: Alexander Berntsen  gentoo.org>

---
 pym/_emerge/actions.py   | 28 ++--
 pym/portage/dbapi/bintree.py | 12 
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
index 6f7dfe0..dec5b04 100644
--- a/pym/_emerge/actions.py
+++ b/pym/_emerge/actions.py
@@ -428,7 +428,18 @@ def action_build(settings, trees, mtimedb,
# least show warnings about missed updates and such.
mydepgraph.display_problems()
 
-   if not Scheduler._opts_no_self_update.intersection(myopts):
+
+   need_write_vardb = not Scheduler. \
+   _opts_no_self_update.intersection(myopts)
+
+   need_write_bindb = not any(x in myopts for x in
+   ("--fetchonly", "--fetch-all-uri", "--pretend")) and \
+   (any("buildpkg" in trees[eroot]["root_config"].
+   settings.features for eroot in trees) or
+   any("buildsyspkg" in trees[eroot]["root_config"].
+   settings.features for eroot in trees))
+
+   if need_write_bindb or need_write_vardb:
 
eroots = set()
for x in mydepgraph.altlist():
@@ -436,13 +447,26 @@ def action_build(settings, trees, mtimedb,
eroots.add(x.root)
 
for eroot in eroots:
-   if not trees[eroot]["vartree"].dbapi.writable:
+   if need_write_vardb and \
+   not 
trees[eroot]["vartree"].dbapi.writable:
writemsg_level("!!! %s\n" %
_("Read-only file system: %s") %

trees[eroot]["vartree"].dbapi._dbroot,
level=logging.ERROR, 
noiselevel=-1)
return 1
 
+   if need_write_bindb and \
+   ("buildpkg" in 
trees[eroot]["root_config"].
+   settings.features or
+   "buildsyspkg" in 
trees[eroot]["root_config"].
+   settings.features) and \
+   not 
trees[eroot]["bintree"].dbapi.writable:
+   writemsg_level("!!! %s\n" %
+   _("Read-only file system: %s") %
+   trees[eroot]["bintree"].pkgdir,
+   level=logging.ERROR, 
noiselevel=-1)
+   return 1
+
if ("--resume" in myopts):
favorites=mtimedb["resume"]["favorites"]
 

diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py
index a5d7ac9..b56c8c1 100644
--- a/pym/portage/dbapi/bintree.py
+++ b/pym/portage/dbapi/bintree.py
@@ -18,6 +18,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
'portage.util:atomic_ofstream,ensure_dirs,normalize_path,' + \
'writemsg,writemsg_stdout',
'portage.util.listdir:listdir',
+   'portage.util.path:first_existing',
'portage.util._urlopen:urlopen@_urlopen',
'portage.versions:best,catpkgsplit,catsplit,_pkg_str',
 )
@@ -85,6 +86,17 @@ class bindbapi(fakedbapi):
self._aux_cache_slot_dict = 
slot_dict_class(self._aux_cache_keys)
self._aux_cache = {}
 
+   @property
+   def writable(self):
+   """
+   Check if PKGDIR is writable, or permissions are sufficient
+   to create it if it does not exist yet.
+   @rtype: bool
+   @return: True if PKGDIR is writable or can be created,
+   False otherwise
+   """
+   return os.access(first_existing(self.bintree.pkgdir), os.W_OK)
+
def match(self, *pargs, **k