[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/, pym/portage/util/futures/

2018-07-11 Thread Zac Medico
commit: edba848a013e1797faeacc1911a5e6571fca3ca7
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Jul  5 04:44:42 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Jul 11 07:40:59 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=edba848a

Add python2 compatible coroutine support (bug 660426)

For readability, it's desirable to make asynchronous code use
coroutines to avoid callbacks when possible. For python2 compatibility,
generators that yield Futures can be used to implement coroutines.

Add a compat_coroutine module which provides a @coroutine decorator
and a coroutine_return function that can be used to return a value
from a generator. The decorated function returns a Future which is
done when the generator is exhausted. Usage is very similar to asyncio
coroutine usage in python3.4 (see unit tests).

Bug: https://bugs.gentoo.org/660426

 .../tests/util/futures/test_compat_coroutine.py| 159 +
 pym/portage/util/futures/compat_coroutine.py   | 112 +++
 2 files changed, 271 insertions(+)

diff --git a/pym/portage/tests/util/futures/test_compat_coroutine.py 
b/pym/portage/tests/util/futures/test_compat_coroutine.py
new file mode 100644
index 0..cbc070869
--- /dev/null
+++ b/pym/portage/tests/util/futures/test_compat_coroutine.py
@@ -0,0 +1,159 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.util.futures import asyncio
+from portage.util.futures.compat_coroutine import (
+   coroutine,
+   coroutine_return,
+)
+from portage.tests import TestCase
+
+
+class CompatCoroutineTestCase(TestCase):
+
+   def test_returning_coroutine(self):
+   @coroutine
+   def returning_coroutine():
+   yield asyncio.sleep(0)
+   coroutine_return('success')
+
+   self.assertEqual('success',
+   
asyncio.get_event_loop().run_until_complete(returning_coroutine()))
+
+   def test_raising_coroutine(self):
+
+   class TestException(Exception):
+   pass
+
+   @coroutine
+   def raising_coroutine():
+   yield asyncio.sleep(0)
+   raise TestException('exception')
+
+   self.assertRaises(TestException,
+   asyncio.get_event_loop().run_until_complete, 
raising_coroutine())
+
+   def test_catching_coroutine(self):
+
+   class TestException(Exception):
+   pass
+
+   @coroutine
+   def catching_coroutine(loop=None):
+   loop = asyncio._wrap_loop(loop)
+   future = loop.create_future()
+   loop.call_soon(future.set_exception, 
TestException('exception'))
+   try:
+   yield future
+   except TestException:
+   self.assertTrue(True)
+   else:
+   self.assertTrue(False)
+   coroutine_return('success')
+
+   loop = asyncio.get_event_loop()
+   self.assertEqual('success',
+   loop.run_until_complete(catching_coroutine(loop=loop)))
+
+   def test_cancelled_coroutine(self):
+
+   @coroutine
+   def cancelled_coroutine(loop=None):
+   loop = asyncio._wrap_loop(loop)
+   while True:
+   yield loop.create_future()
+
+   loop = asyncio.get_event_loop()
+   future = cancelled_coroutine(loop=loop)
+   loop.call_soon(future.cancel)
+
+   self.assertRaises(asyncio.CancelledError,
+   loop.run_until_complete, future)
+
+   def test_cancelled_future(self):
+
+   @coroutine
+   def cancelled_future_coroutine(loop=None):
+   loop = asyncio._wrap_loop(loop)
+   while True:
+   future = loop.create_future()
+   loop.call_soon(future.cancel)
+   yield future
+
+   loop = asyncio.get_event_loop()
+   self.assertRaises(asyncio.CancelledError,
+   loop.run_until_complete, 
cancelled_future_coroutine(loop=loop))
+
+   def test_yield_expression_result(self):
+   @coroutine
+   def yield_expression_coroutine():
+   for i in range(3):
+   x = yield asyncio.sleep(0, result=i)
+   self.assertEqual(x, i)
+
+   
asyncio.get_event_loop().run_until_complete(yield_expression_coroutine())
+
+   def test_method_coroutine(self):
+
+   class Cubby(object):
+
+ 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/sync/

2018-07-05 Thread Zac Medico
commit: 82823b0c4de0a7cbb5654bb19d63aef874800afd
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Jul  5 10:18:55 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Jul  5 10:19:23 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=82823b0c

test_sync_local: fix GitSync coverage

Fixes: 0655b4a26e37 ("test_sync_local: add test for auto-sync set to 'no'")

 pym/portage/tests/sync/test_sync_local.py | 15 +--
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/pym/portage/tests/sync/test_sync_local.py 
b/pym/portage/tests/sync/test_sync_local.py
index 010c8f887..17ff6f200 100644
--- a/pym/portage/tests/sync/test_sync_local.py
+++ b/pym/portage/tests/sync/test_sync_local.py
@@ -102,17 +102,20 @@ class SyncLocalTestCase(TestCase):
os.unlink(os.path.join(metadata_dir, 'timestamp.chk'))
 
sync_cmds = (
+   (homedir, cmds["emerge"] + ("--sync",)),
+   (homedir, lambda: self.assertTrue(os.path.exists(
+   os.path.join(repo.location, "dev-libs", "A")
+   ), "dev-libs/A expected, but missing")),
+   (homedir, cmds["emaint"] + ("sync", "-A")),
+   )
+
+   sync_cmds_auto_sync = (
(homedir, lambda: repos_set_conf("rsync", 
auto_sync="no")),
(homedir, cmds["emerge"] + ("--sync",)),
(homedir, lambda: self.assertFalse(os.path.exists(
os.path.join(repo.location, "dev-libs", "A")
), "dev-libs/A found, expected missing")),
(homedir, lambda: repos_set_conf("rsync", 
auto_sync="yes")),
-   (homedir, cmds["emerge"] + ("--sync",)),
-   (homedir, lambda: self.assertTrue(os.path.exists(
-   os.path.join(repo.location, "dev-libs", "A")
-   ), "dev-libs/A expected, but missing")),
-   (homedir, cmds["emaint"] + ("sync", "-A")),
)
 
rename_repo = (
@@ -236,7 +239,7 @@ class SyncLocalTestCase(TestCase):
# triggered by python -Wd will be visible.
stdout = subprocess.PIPE
 
-   for cwd, cmd in rename_repo + sync_cmds + \
+   for cwd, cmd in rename_repo + sync_cmds_auto_sync + 
sync_cmds + \
rsync_opts_repos + rsync_opts_repos_default + \
rsync_opts_repos_default_ovr + 
rsync_opts_repos_default_cancel + \
delete_sync_repo + git_repo_create + 
sync_type_git + \



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/, pym/portage/util/

2018-06-26 Thread Zac Medico
commit: deb87a465306d05146d7eb55d27d7d89943725c0
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Jun 24 21:42:52 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Jun 27 03:15:08 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=deb87a46

{,PKG_}INSTALL_MASK: support trailing slash (bug 658322)

Fix the python INSTALL_MASK implementation so that a trailing slash
matches a directory, for compatibility with the previous bash
implementation.

Fixes: 3416876c0ee7 ("{,PKG_}INSTALL_MASK: python implementation")
Bug: https://bugs.gentoo.org/658322

 pym/portage/tests/util/test_install_mask.py | 129 
 pym/portage/util/install_mask.py|   7 +-
 2 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/util/test_install_mask.py 
b/pym/portage/tests/util/test_install_mask.py
new file mode 100644
index 0..f651eb4b7
--- /dev/null
+++ b/pym/portage/tests/util/test_install_mask.py
@@ -0,0 +1,129 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util.install_mask import InstallMask
+
+
+class InstallMaskTestCase(TestCase):
+
+   def testTrailingSlash(self):
+   """
+   Test that elements with a trailing slash match a directory
+   but not a regular file.
+   """
+   cases = (
+   (
+   '/foo/bar/ -/foo/bar/*.foo -*.baz',
+   (
+   (
+   'foo/bar/baz',
+   True,
+   ),
+   (
+   'foo/bar/',
+   True,
+   ),
+   # /foo/bar/ does not match
+   (
+   'foo/bar',
+   False,
+   ),
+   # this is excluded
+   (
+   'foo/bar/baz.foo',
+   False,
+   ),
+   # this is excluded
+   (
+   'foo/bar/baz.baz',
+   False,
+   ),
+   (
+   'foo/bar/baz.bar',
+   True,
+   ),
+   )
+   ),
+   (
+   '/foo/bar -/foo/bar/*.foo -*.baz',
+   (
+   (
+   'foo/bar/baz',
+   True,
+   ),
+   # /foo/bar matches both foo/bar/ and 
foo/bar
+   (
+   'foo/bar/',
+   True,
+   ),
+   (
+   'foo/bar',
+   True,
+   ),
+   # this is excluded
+   (
+   'foo/bar/baz.foo',
+   False,
+   ),
+   # this is excluded
+   (
+   'foo/bar/baz.baz',
+   False,
+   ),
+   (
+   'foo/bar/baz.bar',
+   True,
+   ),
+   )
+   ),
+   (
+   '/foo*',
+   (
+   (
+   'foo',
+   True,
+   ),
+

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/process/

2018-05-26 Thread Zac Medico
commit: ac5b48b253add3007034f9fdad02779cd3972281
Author: Zac Medico  gentoo  org>
AuthorDate: Sat May 26 22:38:58 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat May 26 22:38:58 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=ac5b48b2

PipeReaderTestCase: wait for consumer

 pym/portage/tests/process/test_poll.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pym/portage/tests/process/test_poll.py 
b/pym/portage/tests/process/test_poll.py
index d71c9b59c..f700a5585 100644
--- a/pym/portage/tests/process/test_poll.py
+++ b/pym/portage/tests/process/test_poll.py
@@ -78,6 +78,7 @@ class PipeReaderTestCase(TestCase):
producer.start()
os.close(slave_fd)
producer.wait()
+   consumer.wait()
 
self.assertEqual(producer.returncode, os.EX_OK)
self.assertEqual(consumer.returncode, os.EX_OK)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/process/

2018-05-26 Thread Zac Medico
commit: 3b0c52b9ef364dc8e69208ec5341255ac94d41d8
Author: Zac Medico  gentoo  org>
AuthorDate: Sat May 26 10:44:38 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat May 26 10:44:38 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=3b0c52b9

PipeReaderTestCase: cover sockets and named pipes

 pym/portage/tests/process/test_poll.py | 74 ++
 1 file changed, 49 insertions(+), 25 deletions(-)

diff --git a/pym/portage/tests/process/test_poll.py 
b/pym/portage/tests/process/test_poll.py
index 596ea3088..d71c9b59c 100644
--- a/pym/portage/tests/process/test_poll.py
+++ b/pym/portage/tests/process/test_poll.py
@@ -1,11 +1,16 @@
-# Copyright 1998-2013 Gentoo Foundation
+# Copyright 1998-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import functools
+import pty
+import shutil
+import socket
+import sys
 import subprocess
+import tempfile
 
 from portage import os
 from portage.tests import TestCase
-from portage.util._pty import _create_pty_or_pipe
 from portage.util._async.PopenProcess import PopenProcess
 from portage.util._eventloop.global_event_loop import global_event_loop
 from _emerge.PipeReader import PipeReader
@@ -13,28 +18,47 @@ from _emerge.PipeReader import PipeReader
 class PipeReaderTestCase(TestCase):
 
_use_array = False
-   _use_pty = False
_echo_cmd = "echo -n '%s'"
 
-   def _testPipeReader(self, test_string):
+   def test_pipe(self):
+   def make_pipes():
+   return os.pipe(), None
+   self._do_test(make_pipes)
+
+   def test_pty_device(self):
+   def make_pipes():
+   try:
+   return pty.openpty(), None
+   except EnvironmentError:
+   self.skipTest('pty not available')
+   self._do_test(make_pipes)
+
+   def test_domain_socket(self):
+   def make_pipes():
+   if sys.version_info >= (3, 2):
+   read_end, write_end = socket.socketpair()
+   return (read_end.detach(), write_end.detach()), 
None
+   else:
+   self.skipTest('socket detach not supported')
+   self._do_test(make_pipes)
+
+   def test_named_pipe(self):
+   def make_pipes():
+   tempdir = tempfile.mkdtemp()
+   fifo_path = os.path.join(tempdir, 'fifo')
+   os.mkfifo(fifo_path)
+   return ((os.open(fifo_path, os.O_NONBLOCK|os.O_RDONLY),
+   os.open(fifo_path, os.O_NONBLOCK|os.O_WRONLY)),
+   functools.partial(shutil.rmtree, tempdir))
+   self._do_test(make_pipes)
+
+   def _testPipeReader(self, master_fd, slave_fd, test_string):
"""
Use a poll loop to read data from a pipe and assert that
the data written to the pipe is identical to the data
read from the pipe.
"""
 
-   if self._use_pty:
-   got_pty, master_fd, slave_fd = _create_pty_or_pipe()
-   if not got_pty:
-   os.close(slave_fd)
-   os.close(master_fd)
-   skip_reason = "pty not acquired"
-   self.portage_skip = skip_reason
-   self.fail(skip_reason)
-   return
-   else:
-   master_fd, slave_fd = os.pipe()
-
# WARNING: It is very important to use unbuffered mode here,
# in order to avoid issue 5380 with python3.
master_file = os.fdopen(master_fd, 'rb', 0)
@@ -60,15 +84,18 @@ class PipeReaderTestCase(TestCase):
 
return consumer.getvalue().decode('ascii', 'replace')
 
-   def testPipeReader(self):
+   def _do_test(self, make_pipes):
for x in (1, 2, 5, 6, 7, 8, 2**5, 2**10, 2**12, 2**13, 2**14):
test_string = x * "a"
-   output = self._testPipeReader(test_string)
-   self.assertEqual(test_string, output,
-   "x = %s, len(output) = %s" % (x, len(output)))
+   (read_end, write_end), cleanup = make_pipes()
+   try:
+   output = self._testPipeReader(read_end, 
write_end, test_string)
+   self.assertEqual(test_string, output,
+   "x = %s, len(output) = %s" % (x, 
len(output)))
+   finally:
+   if cleanup is not None:
+   cleanup()
 
-class 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/, pym/portage/util/_eventloop/

2018-05-24 Thread Zac Medico
commit: adee194534f0b3d9762efd1e8e8713c316b93f5a
Author: Zac Medico  gentoo  org>
AuthorDate: Thu May 24 22:36:29 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri May 25 02:01:27 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=adee1945

AsyncioEventLoop: suppress BlockingIOError warning (bug 655656)

Override AbstractEventLoop.run_until_complete() to prevent
BlockingIOError from occurring when the event loop is not running,
by using signal.set_wakeup_fd(-1) to temporarily disable the wakeup
fd. In order to avoid potential interference with API consumers,
only modify wakeup fd when portage._interal_caller is True.

Bug: https://bugs.gentoo.org/655656

 .../util/futures/asyncio/test_wakeup_fd_sigchld.py | 76 ++
 pym/portage/util/_eventloop/asyncio_event_loop.py  | 37 +--
 2 files changed, 106 insertions(+), 7 deletions(-)

diff --git a/pym/portage/tests/util/futures/asyncio/test_wakeup_fd_sigchld.py 
b/pym/portage/tests/util/futures/asyncio/test_wakeup_fd_sigchld.py
new file mode 100644
index 0..abc67c241
--- /dev/null
+++ b/pym/portage/tests/util/futures/asyncio/test_wakeup_fd_sigchld.py
@@ -0,0 +1,76 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os
+import subprocess
+
+import portage
+from portage.const import PORTAGE_PYM_PATH
+from portage.tests import TestCase
+from portage.util._eventloop.global_event_loop import _asyncio_enabled
+
+
+class WakeupFdSigchldTestCase(TestCase):
+   def testWakeupFdSigchld(self):
+   """
+   This is expected to trigger a bunch of messages like the 
following
+   unless the fix for bug 655656 works as intended:
+
+   Exception ignored when trying to write to the signal wakeup fd:
+   BlockingIOError: [Errno 11] Resource temporarily unavailable
+   """
+   if not _asyncio_enabled:
+   self.skipTest('asyncio not enabled')
+
+   script = """
+import asyncio as _real_asyncio
+import os
+import signal
+import sys
+
+import portage
+
+# In order to avoid potential interference with API consumers, wakeup
+# fd handling is enabled only when portage._interal_caller is True.
+portage._internal_caller = True
+
+from portage.util.futures import asyncio
+
+loop = asyncio._wrap_loop()
+
+# Cause the loop to register a child watcher.
+proc = loop.run_until_complete(_real_asyncio.create_subprocess_exec('sleep', 
'0'))
+loop.run_until_complete(proc.wait())
+
+for i in range(8192):
+   os.kill(os.getpid(), signal.SIGCHLD)
+
+# Verify that the child watcher still works correctly
+# (this will hang if it doesn't).
+proc = loop.run_until_complete(_real_asyncio.create_subprocess_exec('sleep', 
'0'))
+loop.run_until_complete(proc.wait())
+loop.close()
+sys.stdout.write('success')
+sys.exit(os.EX_OK)
+"""
+
+   pythonpath = os.environ.get('PYTHONPATH', '').strip().split(':')
+   if not pythonpath or pythonpath[0] != PORTAGE_PYM_PATH:
+   pythonpath = [PORTAGE_PYM_PATH] + pythonpath
+   pythonpath = ':'.join(filter(None, pythonpath))
+
+   proc = subprocess.Popen(
+   [portage._python_interpreter, '-c', script],
+   stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+   env=dict(os.environ, PYTHONPATH=pythonpath))
+
+   out, err = proc.communicate()
+   try:
+   self.assertEqual(out[:100], b'success')
+   except Exception:
+   portage.writemsg(''.join('{}\n'.format(line)
+   for line in 
out.decode(errors='replace').splitlines()[:50]),
+   noiselevel=-1)
+   raise
+
+   self.assertEqual(proc.wait(), os.EX_OK)

diff --git a/pym/portage/util/_eventloop/asyncio_event_loop.py 
b/pym/portage/util/_eventloop/asyncio_event_loop.py
index bf5937de8..65b354544 100644
--- a/pym/portage/util/_eventloop/asyncio_event_loop.py
+++ b/pym/portage/util/_eventloop/asyncio_event_loop.py
@@ -1,6 +1,7 @@
 # Copyright 2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+import os
 import signal
 
 try:
@@ -11,6 +12,8 @@ except ImportError:
_real_asyncio = None
_AbstractEventLoop = object
 
+import portage
+
 
 class AsyncioEventLoop(_AbstractEventLoop):
"""
@@ -26,13 +29,15 @@ class AsyncioEventLoop(_AbstractEventLoop):
def __init__(self, loop=None):
loop = loop or _real_asyncio.get_event_loop()
self._loop = loop
-   self.run_until_complete = loop.run_until_complete
+   self.run_until_complete = (self._run_until_complete
+   if portage._internal_caller else 
loop.run_until_complete)

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/

2018-05-09 Thread Zac Medico
commit: 3a55ecd1f79c31f477d7bdd0b9f0e97d8a15eb9e
Author: Zac Medico  gentoo  org>
AuthorDate: Wed May  9 14:19:11 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed May  9 14:19:11 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=3a55ecd1

DefaultEventLoopPolicy: test NotImplementedError due to recursion

 .../asyncio/test_policy_wrapper_recursion.py   | 29 ++
 1 file changed, 29 insertions(+)

diff --git 
a/pym/portage/tests/util/futures/asyncio/test_policy_wrapper_recursion.py 
b/pym/portage/tests/util/futures/asyncio/test_policy_wrapper_recursion.py
new file mode 100644
index 0..d3cd94b35
--- /dev/null
+++ b/pym/portage/tests/util/futures/asyncio/test_policy_wrapper_recursion.py
@@ -0,0 +1,29 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+try:
+   import asyncio
+except ImportError:
+   asyncio = None
+
+from portage.tests import TestCase
+from portage.util.futures.unix_events import DefaultEventLoopPolicy
+
+
+class PolicyWrapperRecursionTestCase(TestCase):
+   def testPolicyWrapperRecursion(self):
+   if asyncio is None:
+   self.skipTest('asyncio is not available')
+
+   initial_policy = asyncio.get_event_loop_policy()
+   if not isinstance(initial_policy, DefaultEventLoopPolicy):
+   asyncio.set_event_loop_policy(DefaultEventLoopPolicy())
+
+   try:
+   with self.assertRaises(NotImplementedError):
+   asyncio.get_event_loop()
+
+   with self.assertRaises(NotImplementedError):
+   asyncio.get_child_watcher()
+   finally:
+   asyncio.set_event_loop_policy(initial_policy)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/

2018-05-09 Thread Zac Medico
commit: 0c96d2d0b18036cb94d68c42783441d32af2d9d3
Author: Zac Medico  gentoo  org>
AuthorDate: Wed May  9 07:54:26 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed May  9 07:59:56 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=0c96d2d0

SubprocessExecTestCase: fix unintended skipTest

The internal asyncio shim does not provide a
create_subprocess_exec attribute, so access it
directly from the real asyncio module.

Fixes 82a3cda6f1ff ("Minimize _asyncio_wrapper usage (bug 654390)")

 .../util/futures/asyncio/test_subprocess_exec.py| 21 +
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py 
b/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
index 534d79c53..5a812ba6a 100644
--- a/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
+++ b/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
@@ -4,6 +4,11 @@
 import os
 import subprocess
 
+try:
+   from asyncio import create_subprocess_exec
+except ImportError:
+   create_subprocess_exec = None
+
 from portage.process import find_binary
 from portage.tests import TestCase
 from portage.util._eventloop.global_event_loop import global_event_loop
@@ -71,7 +76,7 @@ class SubprocessExecTestCase(TestCase):

self.assertFalse(global_event_loop().is_closed())
 
def testEcho(self):
-   if not hasattr(asyncio, 'create_subprocess_exec'):
+   if create_subprocess_exec is None:
self.skipTest('create_subprocess_exec not implemented 
for python2')
 
args_tuple = (b'hello', b'world')
@@ -91,7 +96,7 @@ class SubprocessExecTestCase(TestCase):
try:
with open(os.devnull, 'rb', 0) as devnull:
proc = loop.run_until_complete(
-   asyncio.create_subprocess_exec(
+   create_subprocess_exec(
echo_binary, *args_tuple,
stdin=devnull, 
stdout=stdout_pw, stderr=stdout_pw))
 
@@ -114,7 +119,7 @@ class SubprocessExecTestCase(TestCase):
self._run_test(test)
 
def testCat(self):
-   if not hasattr(asyncio, 'create_subprocess_exec'):
+   if create_subprocess_exec is None:
self.skipTest('create_subprocess_exec not implemented 
for python2')
 
stdin_data = b'hello world'
@@ -138,7 +143,7 @@ class SubprocessExecTestCase(TestCase):
output = None
try:
proc = loop.run_until_complete(
-   asyncio.create_subprocess_exec(
+   create_subprocess_exec(
cat_binary,
stdin=stdin_pr, stdout=stdout_pw, 
stderr=stdout_pw))
 
@@ -173,7 +178,7 @@ class SubprocessExecTestCase(TestCase):
requires an AbstractEventLoop.connect_read_pipe implementation
(and a ReadTransport implementation for it to return).
"""
-   if not hasattr(asyncio, 'create_subprocess_exec'):
+   if create_subprocess_exec is None:
self.skipTest('create_subprocess_exec not implemented 
for python2')
 
args_tuple = (b'hello', b'world')
@@ -184,7 +189,7 @@ class SubprocessExecTestCase(TestCase):
def test(loop):
with open(os.devnull, 'rb', 0) as devnull:
proc = loop.run_until_complete(
-   asyncio.create_subprocess_exec(
+   create_subprocess_exec(
echo_binary, *args_tuple,
stdin=devnull,
stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT))
@@ -202,7 +207,7 @@ class SubprocessExecTestCase(TestCase):
requires an AbstractEventLoop.connect_write_pipe implementation
(and a WriteTransport implementation for it to return).
"""
-   if not hasattr(asyncio, 'create_subprocess_exec'):
+   if create_subprocess_exec is None:
self.skipTest('create_subprocess_exec not implemented 
for python2')
 
stdin_data = b'hello world'
@@ -212,7 +217,7 @@ class SubprocessExecTestCase(TestCase):
 
def test(loop):
proc = loop.run_until_complete(
-   asyncio.create_subprocess_exec(
+   create_subprocess_exec(
   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/

2018-05-06 Thread Zac Medico
commit: 299a9a40536209c4c2664857b5aecb018fa0a6f6
Author: Zac Medico  gentoo  org>
AuthorDate: Sun May  6 23:40:33 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon May  7 00:19:54 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=299a9a40

TestCase: handle SkipTest during setUp method

 pym/portage/tests/__init__.py | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/pym/portage/tests/__init__.py b/pym/portage/tests/__init__.py
index bf681c47e..e149b5c0c 100644
--- a/pym/portage/tests/__init__.py
+++ b/pym/portage/tests/__init__.py
@@ -207,18 +207,18 @@ class TestCase(unittest.TestCase):
result.startTest(self)
testMethod = getattr(self, self._testMethodName)
try:
-   try:
-   self.setUp()
-   except SystemExit:
-   raise
-   except KeyboardInterrupt:
-   raise
-   except:
-   result.addError(self, sys.exc_info())
-   return
-
ok = False
try:
+   try:
+   self.setUp()
+   except KeyboardInterrupt:
+   raise
+   except SkipTest:
+   raise
+   except Exception:
+   result.addError(self, sys.exc_info())
+   return
+
testMethod()
ok = True
except SkipTest as e:



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/

2018-05-06 Thread Zac Medico
commit: fefc6f1feb57503ce4826de1e405c12ef761c0ce
Author: Zac Medico  gentoo  org>
AuthorDate: Sun May  6 23:41:15 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon May  7 00:19:54 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=fefc6f1f

RetryTestCase: test ThreadPoolExecutor and ForkExecutor (bug 654390)

ThreadPoolExecutor is the default asyncio event loop's default executor,
so explicitly test it. Also explicitly test ForkExecutor, since it is
more useful in cases where tasks may need to be forcefully cancelled.

Bug: https://bugs.gentoo.org/654390

 pym/portage/tests/util/futures/test_retry.py | 37 ++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/util/futures/test_retry.py 
b/pym/portage/tests/util/futures/test_retry.py
index baf293d56..16ecccbc7 100644
--- a/pym/portage/tests/util/futures/test_retry.py
+++ b/pym/portage/tests/util/futures/test_retry.py
@@ -1,16 +1,24 @@
 # Copyright 2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
+try:
+   from concurrent.futures import ThreadPoolExecutor
+except ImportError:
+   ThreadPoolExecutor = None
+
 try:
import threading
 except ImportError:
import dummy_threading as threading
 
+import sys
+
 from portage.tests import TestCase
 from portage.util._eventloop.global_event_loop import global_event_loop
 from portage.util.backoff import RandomExponentialBackoff
 from portage.util.futures import asyncio
 from portage.util.futures.retry import retry
+from portage.util.futures.executor.fork import ForkExecutor
 from portage.util.monotonic import monotonic
 
 
@@ -155,13 +163,31 @@ class RetryTestCase(TestCase):
self.assertTrue(isinstance(done.pop().exception().__cause__, 
asyncio.TimeoutError))
 
 
-class RetryExecutorTestCase(RetryTestCase):
+class RetryForkExecutorTestCase(RetryTestCase):
"""
Wrap each coroutine function with AbstractEventLoop.run_in_executor,
in order to test the event loop's default executor. The executor
may use either a thread or a subprocess, and either case is
automatically detected and handled.
"""
+   def __init__(self, *pargs, **kwargs):
+   super(RetryForkExecutorTestCase, self).__init__(*pargs, 
**kwargs)
+   self._executor = None
+
+   def _setUpExecutor(self):
+   self._executor = ForkExecutor()
+
+   def _tearDownExecutor(self):
+   if self._executor is not None:
+   self._executor.shutdown(wait=True)
+   self._executor = None
+
+   def setUp(self):
+   self._setUpExecutor()
+
+   def tearDown(self):
+   self._tearDownExecutor()
+
def _wrap_coroutine_func(self, coroutine_func):
parent_loop = global_event_loop()
 
@@ -191,7 +217,7 @@ class RetryExecutorTestCase(RetryTestCase):
def execute_wrapper():
kill_switch = parent_loop.create_future()
parent_future = asyncio.ensure_future(
-   parent_loop.run_in_executor(None, wrapper, 
kill_switch),
+   parent_loop.run_in_executor(self._executor, 
wrapper, kill_switch),
loop=parent_loop)
parent_future.add_done_callback(
lambda parent_future: None if kill_switch.done()
@@ -199,3 +225,10 @@ class RetryExecutorTestCase(RetryTestCase):
return parent_future
 
return execute_wrapper
+
+
+class RetryThreadExecutorTestCase(RetryForkExecutorTestCase):
+   def _setUpExecutor(self):
+   if sys.version_info.major < 3:
+   self.skipTest('ThreadPoolExecutor not supported for 
python2')
+   self._executor = ThreadPoolExecutor(max_workers=1)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/

2018-05-05 Thread Zac Medico
commit: 87aeab1a62cc6fa1d48354a42ec4fa787dbe9603
Author: Zac Medico  gentoo  org>
AuthorDate: Sun May  6 01:19:08 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun May  6 01:26:50 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=87aeab1a

WriterPipeClosedTestCase: retry filling pipe

This should suppress spurious writer callback observed
twice for pypy in travis.

See: https://travis-ci.org/gentoo/portage/jobs/375411936
See: https://travis-ci.org/gentoo/portage/jobs/373734825

 .../tests/util/futures/asyncio/test_pipe_closed.py | 39 +-
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py 
b/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
index 5398ca35c..e63829888 100644
--- a/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
+++ b/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
@@ -105,25 +105,32 @@ class WriterPipeClosedTestCase(_PipeClosedTestCase, 
TestCase):
 
writer_callback.called = loop.create_future()
_set_nonblocking(write_end.fileno())
+   loop.add_writer(write_end.fileno(), writer_callback)
 
-   # Fill up the pipe, so that no writer callbacks should 
be
-   # received until the state has changed.
-   while True:
-   try:
-   os.write(write_end.fileno(), 512 * b'0')
-   except EnvironmentError as e:
-   if e.errno != errno.EAGAIN:
-   raise
+   # With pypy we've seen intermittent spurious writer 
callbacks
+   # here, so retry until the correct state is achieved.
+   tries = 10
+   while tries:
+   tries -= 1
+
+   # Fill up the pipe, so that no writer callbacks 
should be
+   # received until the state has changed.
+   while True:
+   try:
+   os.write(write_end.fileno(), 
512 * b'0')
+   except EnvironmentError as e:
+   if e.errno != errno.EAGAIN:
+   raise
+   break
+
+   # Allow the loop to check for IO events, and 
assert
+   # that our future is still not done.
+   loop.run_until_complete(asyncio.sleep(0, 
loop=loop))
+   if writer_callback.called.done():
+   writer_callback.called = 
loop.create_future()
+   else:
break
 
-   # We've seen at least one spurious writer callback when
-   # this was registered before the pipe was filled, so
-   # register it afterwards.
-   loop.add_writer(write_end.fileno(), writer_callback)
-
-   # Allow the loop to check for IO events, and assert
-   # that our future is still not done.
-   loop.run_until_complete(asyncio.sleep(0, loop=loop))
self.assertFalse(writer_callback.called.done())
 
# Demonstrate that the callback is called afer the



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/

2018-05-05 Thread Zac Medico
commit: 5a5ed99cb5a6e8913df2e9ca29b4b4d5c179c20f
Author: Zac Medico  gentoo  org>
AuthorDate: Sat May  5 23:04:10 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun May  6 00:35:44 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=5a5ed99c

RetryTestCase: support ThreadPoolExecutor (bug 654390)

In order to support the default asyncio event loop's
ThreadPoolExecutor, use a threading.Event instance to
support cancellation of tasks.

Bug: https://bugs.gentoo.org/654390

 pym/portage/tests/util/futures/test_retry.py | 96 +---
 1 file changed, 74 insertions(+), 22 deletions(-)

diff --git a/pym/portage/tests/util/futures/test_retry.py 
b/pym/portage/tests/util/futures/test_retry.py
index cdca7d294..781eac9a1 100644
--- a/pym/portage/tests/util/futures/test_retry.py
+++ b/pym/portage/tests/util/futures/test_retry.py
@@ -1,8 +1,6 @@
 # Copyright 2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import functools
-
 try:
import threading
 except ImportError:
@@ -28,10 +26,17 @@ class SucceedLater(object):
self._succeed_time = monotonic() + duration
 
def __call__(self):
+   loop = global_event_loop()
+   result = loop.create_future()
remaining = self._succeed_time - monotonic()
if remaining > 0:
-   raise SucceedLaterException('time until success: {} 
seconds'.format(remaining))
-   return 'success'
+   loop.call_soon_threadsafe(lambda: None if result.done() 
else
+   result.set_exception(SucceedLaterException(
+   'time until success: {} 
seconds'.format(remaining
+   else:
+   loop.call_soon_threadsafe(lambda: None if result.done() 
else
+   result.set_result('success'))
+   return result
 
 
 class SucceedNeverException(Exception):
@@ -43,7 +48,11 @@ class SucceedNever(object):
A callable object that never succeeds.
"""
def __call__(self):
-   raise SucceedNeverException('expected failure')
+   loop = global_event_loop()
+   result = loop.create_future()
+   loop.call_soon_threadsafe(lambda: None if result.done() else
+   result.set_exception(SucceedNeverException('expected 
failure')))
+   return result
 
 
 class HangForever(object):
@@ -51,14 +60,21 @@ class HangForever(object):
A callable object that sleeps forever.
"""
def __call__(self):
-   threading.Event().wait()
+   return global_event_loop().create_future()
 
 
 class RetryTestCase(TestCase):
+
+   def _wrap_coroutine_func(self, coroutine_func):
+   """
+   Derived classes may override this method in order to implement
+   alternative forms of execution.
+   """
+   return coroutine_func
+
def testSucceedLater(self):
loop = global_event_loop()
-   func = SucceedLater(1)
-   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   func_coroutine = self._wrap_coroutine_func(SucceedLater(1))
decorator = retry(try_max=,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
decorated_func = decorator(func_coroutine)
@@ -67,8 +83,7 @@ class RetryTestCase(TestCase):
 
def testSucceedNever(self):
loop = global_event_loop()
-   func = SucceedNever()
-   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   func_coroutine = self._wrap_coroutine_func(SucceedNever())
decorator = retry(try_max=4, try_timeout=None,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
decorated_func = decorator(func_coroutine)
@@ -78,8 +93,7 @@ class RetryTestCase(TestCase):
 
def testSucceedNeverReraise(self):
loop = global_event_loop()
-   func = SucceedNever()
-   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   func_coroutine = self._wrap_coroutine_func(SucceedNever())
decorator = retry(reraise=True, try_max=4, try_timeout=None,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
decorated_func = decorator(func_coroutine)
@@ -89,8 +103,7 @@ class RetryTestCase(TestCase):
 
def testHangForever(self):
loop = global_event_loop()
-   func = HangForever()
-   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   func_coroutine = self._wrap_coroutine_func(HangForever())
  

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

2018-05-04 Thread Zac Medico
commit: ce150da22e351a7ba52a6390b9cb7aa076c0c8ce
Author: Zac Medico  gentoo  org>
AuthorDate: Fri May  4 03:21:40 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri May  4 17:11:07 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=ce150da2

depgraph.autounmask_breakage_detected: ignore REQUIRED_USE violations (bug 
654782)

When autounmask USE changes violate REQUIRED_USE, rather than
recalculate with autounmask disabled, display the autounmask USE
changes along with the REQUIRED_USE violation. Adjust unit tests
to allow for the autounmask USE changes that were previously
discarded. For the case reported in bug 654782, the output will
appear as follows:

The following keyword changes are necessary to proceed:
 (see "package.accept_keywords" in the portage(5) man page for more details)
# required by =retext-7.0.1-r1 (argument)
=app-editors/retext-7.0.1-r1 ~amd64

The following USE changes are necessary to proceed:
 (see "package.use" in the portage(5) man page for more details)
# required by app-editors/retext-7.0.1-r1::gentoo
# required by =retext-7.0.1-r1 (argument)
>=dev-python/PyQt5-5.9.2 printsupport webengine network gui widgets

!!! The ebuild selected to satisfy 
"dev-python/PyQt5[gui,network,printsupport,webengine,widgets,python_targets_python3_4(-)?,python_targets_python3_5(-)?,python_targets_python3_6(-)?,-python_single_target_python3_4(-),-python_single_target_python3_5(-),-python_single_target_python3_6(-)]"
 has unmet requirements.
- dev-python/PyQt5-5.9.2::gentoo USE="-bluetooth -dbus -debug -declarative 
-designer -examples -gles2 -gui -help -location -multimedia -network -opengl 
-positioning -printsupport -sensors -serialport -sql -svg -testlib -webchannel 
-webengine -webkit -websockets -widgets -x11extras -xmlpatterns" 
PYTHON_TARGETS="python2_7 python3_4 python3_6 -python3_5"

  The following REQUIRED_USE flag constraints are unsatisfied:
webengine? ( widgets? ( webchannel ) )

  The above constraints are a subset of the following complete expression:
any-of ( python_targets_python2_7 python_targets_python3_4 
python_targets_python3_5 python_targets_python3_6 ) bluetooth? ( gui ) 
declarative? ( gui network ) designer? ( widgets ) help? ( gui widgets ) 
location? ( positioning ) multimedia? ( gui network ) opengl? ( gui widgets ) 
positioning? ( gui ) printsupport? ( gui widgets ) sensors? ( gui ) serialport? 
( gui ) sql? ( widgets ) svg? ( gui widgets ) testlib? ( widgets ) webchannel? 
( network ) webengine? ( network widgets? ( printsupport webchannel ) ) webkit? 
( gui network printsupport widgets ) websockets? ( network ) widgets? ( gui ) 
xmlpatterns? ( network )

(dependency required by "app-editors/retext-7.0.1-r1::gentoo" [ebuild])
(dependency required by "=retext-7.0.1-r1" [argument])

Bug: https://bugs.gentoo.org/654782
Reviewed-by: M. J. Everitt  iee.org>

 pym/_emerge/depgraph.py|  8 ++--
 pym/portage/tests/resolver/test_autounmask.py  | 48 --
 pym/portage/tests/resolver/test_slot_collisions.py | 20 +
 3 files changed, 61 insertions(+), 15 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index fbd16ad98..429d8871c 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -3009,6 +3009,10 @@ class depgraph(object):
{"myparent" : dep.parent, 
"show_req_use" : pkg}))
self._dynamic_config._required_use_unsatisfied 
= True
self._dynamic_config._skip_restart = True
+   # Add pkg to digraph in order to enable 
autounmask messages
+   # for this package, which is useful when 
autounmask USE
+   # changes have violated REQUIRED_USE.
+   self._dynamic_config.digraph.add(pkg, 
dep.parent, priority=priority)
return 0
 
if not pkg.onlydeps:
@@ -9428,10 +9432,6 @@ class depgraph(object):
return self._dynamic_config._need_config_reload
 
def autounmask_breakage_detected(self):
-   # Check for REQUIRED_USE violations.
-   for changes in 
self._dynamic_config._needed_use_config_changes.values():
-   if getattr(changes, 'required_use_satisfied', None) is 
False:
-   return True
try:
for pargs, kwargs in 
self._dynamic_config._unsatisfied_deps_for_display:
self._show_unsatisfied_dep(

diff --git a/pym/portage/tests/resolver/test_autounmask.py 
b/pym/portage/tests/resolver/test_autounmask.py
index 9042349ea..809d42104 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -251,15 +251,42 @@ class AutounmaskTestCase(TestCase):

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/

2018-05-02 Thread Zac Medico
commit: 10253819aae4cefee80f377e167ad521516d66a2
Author: Zac Medico  gentoo  org>
AuthorDate: Thu May  3 01:18:39 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu May  3 01:18:39 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=10253819

WriterPipeClosedTestCase: add_writer after pipe is filled

Hopefully this supresses a spurious writer callback observed
once for pypy in travis.

See: https://travis-ci.org/gentoo/portage/jobs/373734825

 pym/portage/tests/util/futures/asyncio/test_pipe_closed.py | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py 
b/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
index 1ecddab78..5398ca35c 100644
--- a/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
+++ b/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
@@ -105,7 +105,6 @@ class WriterPipeClosedTestCase(_PipeClosedTestCase, 
TestCase):
 
writer_callback.called = loop.create_future()
_set_nonblocking(write_end.fileno())
-   loop.add_writer(write_end.fileno(), writer_callback)
 
# Fill up the pipe, so that no writer callbacks should 
be
# received until the state has changed.
@@ -117,6 +116,11 @@ class WriterPipeClosedTestCase(_PipeClosedTestCase, 
TestCase):
raise
break
 
+   # We've seen at least one spurious writer callback when
+   # this was registered before the pipe was filled, so
+   # register it afterwards.
+   loop.add_writer(write_end.fileno(), writer_callback)
+
# Allow the loop to check for IO events, and assert
# that our future is still not done.
loop.run_until_complete(asyncio.sleep(0, loop=loop))



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

2018-05-01 Thread Zac Medico
commit: 4bda6c546aab816e835f62b326db9c2215e182ac
Author: Zac Medico  gentoo  org>
AuthorDate: Tue May  1 23:37:33 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue May  1 23:49:44 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=4bda6c54

Revert "phase-helpers.sh: fix best/has_version -b for cross-prefix"

This reverts commit a0ac6e6727abec8d2482c95b1e84d8df24d78619,
since BROOT is only supposed to be set in src_* phases.
Update SimpleEmergeTestCase to call best/has_version -b only
in src_install for EAPI 7.

Reported-by: James Le Cuirot  gentoo.org>

 bin/phase-helpers.sh|  2 +-
 pym/portage/tests/emerge/test_simple.py | 23 ---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
index 8b16d7d31..59c19cf67 100644
--- a/bin/phase-helpers.sh
+++ b/bin/phase-helpers.sh
@@ -912,7 +912,7 @@ ___best_version_and_has_version_common() {
case ${root_arg} in
-r) root=${EROOT} ;;
-d) root=${ESYSROOT} ;;
-   -b) 
root=${BROOT:-/${PORTAGE_OVERRIDE_EPREFIX#/}} ;;
+   -b) root=${BROOT:-/} ;;
esac
else
case ${root_arg} in

diff --git a/pym/portage/tests/emerge/test_simple.py 
b/pym/portage/tests/emerge/test_simple.py
index 204c23296..b1402ddd5 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -58,6 +58,8 @@ src_install() {
echo "blah blah blah" > "${T}"/latin-1-$(printf "\\xa9")-regular-file 
|| die
doins "${T}"/latin-1-$(printf "\\xa9")-regular-file
dosym latin-1-$(printf "\\xa9")-regular-file 
${latin_1_dir}/latin-1-$(printf "\\xa9")-symlink || die
+
+   call_has_and_best_version
 }
 
 pkg_config() {
@@ -69,14 +71,29 @@ pkg_info() {
 }
 
 pkg_preinst() {
+   if ! ___eapi_best_version_and_has_version_support_-b_-d_-r; then
+   # The BROOT variable is unset during pkg_* phases for EAPI 7,
+   # therefore best/has_version -b is expected to fail if we 
attempt
+   # to call it for EAPI 7 here.
+   call_has_and_best_version
+   fi
+}
+
+call_has_and_best_version() {
local root_arg
if ___eapi_best_version_and_has_version_support_-b_-d_-r; then
root_arg="-b"
else
root_arg="--host-root"
fi
-   einfo "called pkg_preinst for $CATEGORY/$PF"
-
+   einfo "called ${EBUILD_PHASE_FUNC} for $CATEGORY/$PF"
+   einfo "EPREFIX=${EPREFIX}"
+   einfo "PORTAGE_OVERRIDE_EPREFIX=${PORTAGE_OVERRIDE_EPREFIX}"
+   einfo "ROOT=${ROOT}"
+   einfo "EROOT=${EROOT}"
+   einfo "SYSROOT=${SYSROOT}"
+   einfo "ESYSROOT=${ESYSROOT}"
+   einfo "BROOT=${BROOT}"
# Test that has_version and best_version work correctly with
# prefix (involves internal ROOT -> EROOT calculation in order
# to support ROOT override via the environment with EAPIs 3
@@ -90,7 +107,7 @@ pkg_preinst() {
if [[ ${EPREFIX} != ${PORTAGE_OVERRIDE_EPREFIX} ]] ; then
if has_version ${root_arg} $CATEGORY/$PN:$SLOT ; then
einfo "has_version ${root_arg} detects an installed 
instance of $CATEGORY/$PN:$SLOT"
-   einfo "best_version ${root_arg} reports that the 
installed instance is $(best_version $CATEGORY/$PN:$SLOT)"
+   einfo "best_version ${root_arg} reports that the 
installed instance is $(best_version ${root_arg} $CATEGORY/$PN:$SLOT)"
else
einfo "has_version ${root_arg} does not detect an 
installed instance of $CATEGORY/$PN:$SLOT"
fi



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

2018-05-01 Thread Zac Medico
commit: 75d6df1a2988ba440feed3db02550b62ebe0c204
Author: Zac Medico  gentoo  org>
AuthorDate: Tue May  1 18:18:49 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue May  1 18:22:45 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=75d6df1a

Enable EAPI 7 (bug 654472)

Bug: https://bugs.gentoo.org/654472

 pym/portage/__init__.py | 2 +-
 pym/portage/const.py| 2 +-
 pym/portage/tests/emerge/test_simple.py | 6 +++---
 pym/portage/tests/resolver/test_eapi.py | 2 +-
 pym/portage/tests/resolver/test_required_use.py | 6 +++---
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py
index 15c404f6f..166bfc700 100644
--- a/pym/portage/__init__.py
+++ b/pym/portage/__init__.py
@@ -462,7 +462,7 @@ def abssymlink(symlink, target=None):
 
 _doebuild_manifest_exempt_depend = 0
 
-_testing_eapis = frozenset(["4-python", "4-slot-abi", "5-progress", 
"5-hdepend", "7_pre1"])
+_testing_eapis = frozenset(["4-python", "4-slot-abi", "5-progress", 
"5-hdepend", "7_pre1", "7"])
 _deprecated_eapis = frozenset(["4_pre1", "3_pre2", "3_pre1", "5_pre1", 
"5_pre2", "6_pre1"])
 _supported_eapis = frozenset([str(x) for x in range(portage.const.EAPI + 1)] + 
list(_testing_eapis) + list(_deprecated_eapis))
 

diff --git a/pym/portage/const.py b/pym/portage/const.py
index 16922a5e6..7f84bf0e9 100644
--- a/pym/portage/const.py
+++ b/pym/portage/const.py
@@ -204,7 +204,7 @@ SUPPORTED_FEATURES   = frozenset([
"xattr",
 ])
 
-EAPI = 6
+EAPI = 7
 
 HASHING_BLOCKSIZE= 32768
 

diff --git a/pym/portage/tests/emerge/test_simple.py 
b/pym/portage/tests/emerge/test_simple.py
index 495e22297..204c23296 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -1,4 +1,4 @@
-# Copyright 2011-2015 Gentoo Foundation
+# Copyright 2011-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import subprocess
@@ -116,13 +116,13 @@ pkg_preinst() {
"MISC_CONTENT": install_something,
},
"dev-libs/C-1": {
-   "EAPI" : "7_pre1",
+   "EAPI" : "7",
"KEYWORDS": "~x86",
"RDEPEND": "dev-libs/D[flag]",
"MISC_CONTENT": install_something,
},
"dev-libs/D-1": {
-   "EAPI" : "7_pre1",
+   "EAPI" : "7",
"KEYWORDS": "~x86",
"IUSE" : "flag",
"MISC_CONTENT": install_something,

diff --git a/pym/portage/tests/resolver/test_eapi.py 
b/pym/portage/tests/resolver/test_eapi.py
index fce05890b..50b9d90da 100644
--- a/pym/portage/tests/resolver/test_eapi.py
+++ b/pym/portage/tests/resolver/test_eapi.py
@@ -62,7 +62,7 @@ class EAPITestCase(TestCase):
 
#EAPI-7: implicit || ( ) no longer satisfies deps
"dev-libs/C-1": { "EAPI": "6", "IUSE": "foo", 
"RDEPEND": "|| ( foo? ( dev-libs/B ) )" }, 
-   "dev-libs/C-2": { "EAPI": "7_pre1", "IUSE": "foo", 
"RDEPEND": "|| ( foo? ( dev-libs/B ) )" }, 
+   "dev-libs/C-2": { "EAPI": "7", "IUSE": "foo", 
"RDEPEND": "|| ( foo? ( dev-libs/B ) )" },
}
 
test_cases = (

diff --git a/pym/portage/tests/resolver/test_required_use.py 
b/pym/portage/tests/resolver/test_required_use.py
index 7909f927f..c679ce300 100644
--- a/pym/portage/tests/resolver/test_required_use.py
+++ b/pym/portage/tests/resolver/test_required_use.py
@@ -51,9 +51,9 @@ class RequiredUSETestCase(TestCase):
"dev-libs/E-4" : {"EAPI": "5", "IUSE": "+foo +bar", 
"REQUIRED_USE": "?? ( foo bar )"},
"dev-libs/E-5" : {"EAPI": "5", "IUSE": "+foo +bar", 
"REQUIRED_USE": "?? ( )"},
 
-   "dev-libs/F-1" : {"EAPI": "7_pre1", "IUSE": "+foo 
+bar", "REQUIRED_USE": "|| ( )"},
-   "dev-libs/F-2" : {"EAPI": "7_pre1", "IUSE": "+foo 
+bar", "REQUIRED_USE": "^^ ( )"},
-   "dev-libs/F-3" : {"EAPI": "7_pre1", "IUSE": "+foo 
+bar", "REQUIRED_USE": "?? ( )"},
+   "dev-libs/F-1" : {"EAPI": "7", "IUSE": "+foo +bar", 
"REQUIRED_USE": "|| ( )"},
+   "dev-libs/F-2" : {"EAPI": "7", "IUSE": "+foo +bar", 
"REQUIRED_USE": "^^ ( )"},
+   "dev-libs/F-3" : {"EAPI": "7", "IUSE": "+foo +bar", 
"REQUIRED_USE": "?? ( )"},
}
 
test_cases = (



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

2018-05-01 Thread Zac Medico
commit: a0ac6e6727abec8d2482c95b1e84d8df24d78619
Author: Zac Medico  gentoo  org>
AuthorDate: Tue May  1 18:14:07 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue May  1 18:15:47 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=a0ac6e67

phase-helpers.sh: fix best/has_version -b for cross-prefix

Fixes: 43b6be7423aa ("phase-helpers.sh: Implement -r|-d|-b options for 
best/has_version")

 bin/phase-helpers.sh|  2 +-
 pym/portage/tests/emerge/test_simple.py | 12 
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
index 59c19cf67..8b16d7d31 100644
--- a/bin/phase-helpers.sh
+++ b/bin/phase-helpers.sh
@@ -912,7 +912,7 @@ ___best_version_and_has_version_common() {
case ${root_arg} in
-r) root=${EROOT} ;;
-d) root=${ESYSROOT} ;;
-   -b) root=${BROOT:-/} ;;
+   -b) 
root=${BROOT:-/${PORTAGE_OVERRIDE_EPREFIX#/}} ;;
esac
else
case ${root_arg} in

diff --git a/pym/portage/tests/emerge/test_simple.py 
b/pym/portage/tests/emerge/test_simple.py
index 17dcd548d..495e22297 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -119,11 +119,13 @@ pkg_preinst() {
"EAPI" : "7_pre1",
"KEYWORDS": "~x86",
"RDEPEND": "dev-libs/D[flag]",
+   "MISC_CONTENT": install_something,
},
"dev-libs/D-1": {
"EAPI" : "7_pre1",
"KEYWORDS": "~x86",
"IUSE" : "flag",
+   "MISC_CONTENT": install_something,
},
"virtual/foo-0": {
"EAPI" : "5",
@@ -326,6 +328,16 @@ pkg_preinst() {
portageq_cmd + ("match", eroot, "dev-libs/D[flag]"),
 
# Test cross-prefix usage, including chpathtool for 
binpkgs.
+   # EAPI 7
+   ({"EPREFIX" : cross_prefix},) + \
+   emerge_cmd + ("dev-libs/C",),
+   ({"EPREFIX" : cross_prefix},) + \
+   portageq_cmd + ("has_version", cross_prefix, 
"dev-libs/C"),
+   ({"EPREFIX" : cross_prefix},) + \
+   portageq_cmd + ("has_version", cross_prefix, 
"dev-libs/D"),
+   ({"ROOT": cross_root},) + emerge_cmd + ("dev-libs/D",),
+   portageq_cmd + ("has_version", cross_eroot, 
"dev-libs/D"),
+   # EAPI 5
({"EPREFIX" : cross_prefix},) + \
emerge_cmd + ("--usepkgonly", "dev-libs/A"),
({"EPREFIX" : cross_prefix},) + \



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

2018-05-01 Thread Zac Medico
commit: 844998daa50e9db0a337bc0cf9f665d224779665
Author: Zac Medico  gentoo  org>
AuthorDate: Tue May  1 17:49:07 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue May  1 17:52:02 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=844998da

SimpleEmergeTestCase: EAPI 7_pre1 has/best_version -b

 pym/portage/tests/emerge/test_simple.py | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/pym/portage/tests/emerge/test_simple.py 
b/pym/portage/tests/emerge/test_simple.py
index f99c77927..17dcd548d 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -69,6 +69,12 @@ pkg_info() {
 }
 
 pkg_preinst() {
+   local root_arg
+   if ___eapi_best_version_and_has_version_support_-b_-d_-r; then
+   root_arg="-b"
+   else
+   root_arg="--host-root"
+   fi
einfo "called pkg_preinst for $CATEGORY/$PF"
 
# Test that has_version and best_version work correctly with
@@ -82,11 +88,11 @@ pkg_preinst() {
einfo "has_version does not detect an installed instance of 
$CATEGORY/$PN:$SLOT"
fi
if [[ ${EPREFIX} != ${PORTAGE_OVERRIDE_EPREFIX} ]] ; then
-   if has_version --host-root $CATEGORY/$PN:$SLOT ; then
-   einfo "has_version --host-root detects an installed 
instance of $CATEGORY/$PN:$SLOT"
-   einfo "best_version --host-root reports that the 
installed instance is $(best_version $CATEGORY/$PN:$SLOT)"
+   if has_version ${root_arg} $CATEGORY/$PN:$SLOT ; then
+   einfo "has_version ${root_arg} detects an installed 
instance of $CATEGORY/$PN:$SLOT"
+   einfo "best_version ${root_arg} reports that the 
installed instance is $(best_version $CATEGORY/$PN:$SLOT)"
else
-   einfo "has_version --host-root does not detect an 
installed instance of $CATEGORY/$PN:$SLOT"
+   einfo "has_version ${root_arg} does not detect an 
installed instance of $CATEGORY/$PN:$SLOT"
fi
fi
 }
@@ -110,12 +116,12 @@ pkg_preinst() {
"MISC_CONTENT": install_something,
},
"dev-libs/C-1": {
-   "EAPI" : "6",
+   "EAPI" : "7_pre1",
"KEYWORDS": "~x86",
"RDEPEND": "dev-libs/D[flag]",
},
"dev-libs/D-1": {
-   "EAPI" : "6",
+   "EAPI" : "7_pre1",
"KEYWORDS": "~x86",
"IUSE" : "flag",
},



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

2018-05-01 Thread Zac Medico
commit: 90d78484d6be481a9caf22c017c62ea43f8ffe33
Author: Zac Medico  gentoo  org>
AuthorDate: Tue May  1 06:22:10 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue May  1 06:46:27 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=90d78484

_PortageEventLoop: add _asyncio_* properties for internal use

It's better to avoid accessing the _PortageEventLoop._loop
attribute which exposes *all* EventLoop methods, therefore expose
_asyncio_child_watcher and _asyncio_wrapper attributes for use by
portage internals, providing minimal compatibility between
_PortageEventloop and EventLoop.

 pym/portage/dbapi/porttree.py  |  2 +-
 .../util/futures/asyncio/test_subprocess_exec.py   |  2 +-
 .../tests/util/futures/test_iter_completed.py  |  2 +-
 pym/portage/util/futures/executor/fork.py  |  2 +-
 pym/portage/util/futures/iter_completed.py |  2 +-
 pym/portage/util/futures/unix_events.py| 22 ++
 6 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
index 3ce214cd7..6c38232bb 100644
--- a/pym/portage/dbapi/porttree.py
+++ b/pym/portage/dbapi/porttree.py
@@ -667,7 +667,7 @@ class portdbapi(dbapi):
 
proc = EbuildMetadataPhase(cpv=mycpv,
ebuild_hash=ebuild_hash, portdb=self,
-   repo_path=mylocation, scheduler=loop._loop,
+   repo_path=mylocation, scheduler=loop,
settings=self.doebuild_settings)
 
proc.addExitListener(functools.partial(self._aux_get_return,

diff --git a/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py 
b/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
index 8c8c395ca..be103a9e0 100644
--- a/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
+++ b/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
@@ -34,7 +34,7 @@ class _Reader(object):
def __init__(self, future, input_file, loop):
self._future = future
self._pipe_reader = PipeReader(
-   input_files={'input_file':input_file}, 
scheduler=loop._loop)
+   input_files={'input_file':input_file}, scheduler=loop)
 
self._future.add_done_callback(self._cancel_callback)
self._pipe_reader.addExitListener(self._eof)

diff --git a/pym/portage/tests/util/futures/test_iter_completed.py 
b/pym/portage/tests/util/futures/test_iter_completed.py
index 71343c22d..90668eb02 100644
--- a/pym/portage/tests/util/futures/test_iter_completed.py
+++ b/pym/portage/tests/util/futures/test_iter_completed.py
@@ -46,7 +46,7 @@ class IterCompletedTestCase(TestCase):
def future_generator():
for task in tasks:
task.future = loop.create_future()
-   task.scheduler = loop._loop
+   task.scheduler = loop
task.start()
yield task.future
 

diff --git a/pym/portage/util/futures/executor/fork.py 
b/pym/portage/util/futures/executor/fork.py
index 51367f934..81c292e2c 100644
--- a/pym/portage/util/futures/executor/fork.py
+++ b/pym/portage/util/futures/executor/fork.py
@@ -54,7 +54,7 @@ class ForkExecutor(object):
future, proc = self._submit_queue.popleft()

future.add_done_callback(functools.partial(self._cancel_cb, proc))
proc.addExitListener(functools.partial(self._proc_exit, 
future))
-   proc.scheduler = self._loop._loop
+   proc.scheduler = self._loop
proc.start()
self._running_tasks[id(proc)] = proc
 

diff --git a/pym/portage/util/futures/iter_completed.py 
b/pym/portage/util/futures/iter_completed.py
index 1d6a9a4bd..8b0f417d9 100644
--- a/pym/portage/util/futures/iter_completed.py
+++ b/pym/portage/util/futures/iter_completed.py
@@ -77,7 +77,7 @@ def async_iter_completed(futures, max_jobs=None, 
max_load=None, loop=None):
task_generator(),
max_jobs=max_jobs,
max_load=max_load,
-   event_loop=loop._loop)
+   event_loop=loop)
 
def done_callback(future_done_set, wait_result):
"""Propagate results from wait_result to future_done_set."""

diff --git a/pym/portage/util/futures/unix_events.py 
b/pym/portage/util/futures/unix_events.py
index 1a86ed439..00f522b61 100644
--- a/pym/portage/util/futures/unix_events.py
+++ b/pym/portage/util/futures/unix_events.py
@@ -72,6 +72,28 @@ class _PortageEventLoop(events.AbstractEventLoop):
self.set_debug = loop.set_debug
self.get_debug = loop.get_debug
 
+   @property
+   def _asyncio_child_watcher(self):

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/, pym/portage/util/_eventloop/

2018-04-29 Thread Zac Medico
commit: c77afbc31fa687cc612a6f946b324bf4d74d8175
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Apr 30 01:49:18 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Apr 30 02:14:41 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=c77afbc3

EventLoop: call add_reader/writer callbacks after pipe is closed (bug 654382)

Callbacks registered via add_reader/writer methods need to be called
when the other end of a pipe is closed, which does not result in a
normal read or write event. Therefore, respond to other event types
as well, for compatibility with the asyncio event loop implementation.

The included unit tests demonstrate asyncio compatible behavior for
both reader and writer callbacks.

Bug: https://bugs.gentoo.org/654382

 .../tests/util/futures/asyncio/test_pipe_closed.py | 133 +
 pym/portage/util/_eventloop/EventLoop.py   |   7 +-
 2 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py 
b/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
new file mode 100644
index 0..1ecddab78
--- /dev/null
+++ b/pym/portage/tests/util/futures/asyncio/test_pipe_closed.py
@@ -0,0 +1,133 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import os
+import pty
+import shutil
+import socket
+import sys
+import tempfile
+
+from portage.tests import TestCase
+from portage.util.futures import asyncio
+from portage.util.futures.unix_events import (
+   DefaultEventLoopPolicy,
+   _set_nonblocking,
+)
+
+
+class _PipeClosedTestCase(object):
+
+   def test_pipe(self):
+   read_end, write_end = os.pipe()
+   self._do_test(read_end, write_end)
+
+   def test_pty_device(self):
+   try:
+   read_end, write_end = pty.openpty()
+   except EnvironmentError:
+   self.skipTest('pty not available')
+   self._do_test(read_end, write_end)
+
+   def test_domain_socket(self):
+   if sys.version_info >= (3, 2):
+   read_end, write_end = socket.socketpair()
+   else:
+   self.skipTest('socket detach not supported')
+   self._do_test(read_end.detach(), write_end.detach())
+
+   def test_named_pipe(self):
+   tempdir = tempfile.mkdtemp()
+   try:
+   fifo_path = os.path.join(tempdir, 'fifo')
+   os.mkfifo(fifo_path)
+   self._do_test(os.open(fifo_path, 
os.O_NONBLOCK|os.O_RDONLY),
+   os.open(fifo_path, os.O_NONBLOCK|os.O_WRONLY))
+   finally:
+   shutil.rmtree(tempdir)
+
+
+class ReaderPipeClosedTestCase(_PipeClosedTestCase, TestCase):
+   """
+   Test that a reader callback is called after the other end of
+   the pipe has been closed.
+   """
+   def _do_test(self, read_end, write_end):
+   initial_policy = asyncio.get_event_loop_policy()
+   if not isinstance(initial_policy, DefaultEventLoopPolicy):
+   asyncio.set_event_loop_policy(DefaultEventLoopPolicy())
+
+   loop = asyncio.get_event_loop()
+   read_end = os.fdopen(read_end, 'rb', 0)
+   write_end = os.fdopen(write_end, 'wb', 0)
+   try:
+   def reader_callback():
+   if not reader_callback.called.done():
+   reader_callback.called.set_result(None)
+
+   reader_callback.called = loop.create_future()
+   loop.add_reader(read_end.fileno(), reader_callback)
+
+   # Allow the loop to check for IO events, and assert
+   # that our future is still not done.
+   loop.run_until_complete(asyncio.sleep(0, loop=loop))
+   self.assertFalse(reader_callback.called.done())
+
+   # Demonstrate that the callback is called afer the
+   # other end of the pipe has been closed.
+   write_end.close()
+   loop.run_until_complete(reader_callback.called)
+   finally:
+   loop.remove_reader(read_end.fileno())
+   write_end.close()
+   read_end.close()
+   asyncio.set_event_loop_policy(initial_policy)
+
+
+class WriterPipeClosedTestCase(_PipeClosedTestCase, TestCase):
+   """
+   Test that a writer callback is called after the other end of
+   the pipe has been closed.
+   """
+   def _do_test(self, read_end, write_end):
+   initial_policy = asyncio.get_event_loop_policy()
+   if not isinstance(initial_policy, 

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

2018-04-27 Thread Zac Medico
commit: 3e77f0199cb401acf974089fb6aa378fd45d0e90
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Apr 24 06:54:05 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri Apr 27 22:56:02 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=3e77f019

ManifestScheduler: async fetchlist_dict (bug 653946)

In order to avoid event loop recursion, pass fetchlist_dict to
ManifestTask as a Future.

Bug: https://bugs.gentoo.org/653946

 pym/portage/dbapi/porttree.py  | 70 ++
 .../ebuild/_parallel_manifest/ManifestScheduler.py | 25 
 .../ebuild/_parallel_manifest/ManifestTask.py  | 24 +++-
 pym/portage/tests/dbapi/test_portdb_cache.py   |  3 +-
 4 files changed, 105 insertions(+), 17 deletions(-)

diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
index 975f03d5e..3ce214cd7 100644
--- a/pym/portage/dbapi/porttree.py
+++ b/pym/portage/dbapi/porttree.py
@@ -37,6 +37,7 @@ from portage import _unicode_encode
 from portage import OrderedDict
 from portage.util._eventloop.EventLoop import EventLoop
 from portage.util._eventloop.global_event_loop import global_event_loop
+from portage.util.futures.iter_completed import iter_gather
 from _emerge.EbuildMetadataPhase import EbuildMetadataPhase
 
 import os as _os
@@ -1393,6 +1394,75 @@ class FetchlistDict(Mapping):
if sys.hexversion >= 0x300:
keys = __iter__
 
+
+def _async_manifest_fetchlist(portdb, repo_config, cp, cpv_list=None,
+   max_jobs=None, max_load=None, loop=None):
+   """
+   Asynchronous form of FetchlistDict, with max_jobs and max_load
+   parameters in order to control async_aux_get concurrency.
+
+   @param portdb: portdbapi instance
+   @type portdb: portdbapi
+   @param repo_config: repository configuration for a Manifest
+   @type repo_config: RepoConfig
+   @param cp: cp for a Manifest
+   @type cp: str
+   @param cpv_list: list of ebuild cpv values for a Manifest
+   @type cpv_list: list
+   @param max_jobs: max number of futures to process concurrently (default
+   is multiprocessing.cpu_count())
+   @type max_jobs: int
+   @param max_load: max load allowed when scheduling a new future,
+   otherwise schedule no more than 1 future at a time (default
+   is multiprocessing.cpu_count())
+   @type max_load: int or float
+   @param loop: event loop
+   @type loop: EventLoop
+   @return: a Future resulting in a Mapping compatible with FetchlistDict
+   @rtype: asyncio.Future (or compatible)
+   """
+   loop = loop or global_event_loop()
+   loop = getattr(loop, '_asyncio_wrapper', loop)
+   result = loop.create_future()
+   cpv_list = (portdb.cp_list(cp, mytree=repo_config.location)
+   if cpv_list is None else cpv_list)
+
+   def gather_done(gather_result):
+   # All exceptions must be consumed from gather_result before this
+   # function returns, in order to avoid triggering the event 
loop's
+   # exception handler.
+   e = None
+   if not gather_result.cancelled():
+   for future in gather_result.result():
+   if (future.done() and not future.cancelled() and
+   future.exception() is not None):
+   e = future.exception()
+
+   if result.cancelled():
+   return
+   elif e is None:
+   result.set_result(dict((k, list(v.result()))
+   for k, v in zip(cpv_list, 
gather_result.result(
+   else:
+   result.set_exception(e)
+
+   gather_result = iter_gather(
+   # Use a generator expression for lazy evaluation, so that 
iter_gather
+   # controls the number of concurrent async_fetch_map calls.
+   (portdb.async_fetch_map(cpv, mytree=repo_config.location, 
loop=loop)
+   for cpv in cpv_list),
+   max_jobs=max_jobs,
+   max_load=max_load,
+   loop=loop,
+   )
+
+   gather_result.add_done_callback(gather_done)
+   result.add_done_callback(lambda result:
+   gather_result.cancel() if result.cancelled() else None)
+
+   return result
+
+
 def _parse_uri_map(cpv, metadata, use=None):
 
myuris = use_reduce(metadata.get('SRC_URI', ''),

diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py 
b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
index 38ac4825e..fabea9bc1 100644
--- a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
+++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
@@ -1,10 +1,10 @@
-# Copyright 2012-2013 Gentoo Foundation
+# Copyright 

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

2018-04-25 Thread Zac Medico
commit: 71a5a82313226f7be0d966d49392a53139a96f6b
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Apr 24 02:47:11 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Apr 26 03:19:22 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=71a5a823

AsynchronousTask: add async_wait() method (bug 653856)

Since the AsynchronousTask.wait() method is prone to event loop
recursion, deprecate it, and add an async_wait() method method to
replace it. Instead of using task.wait() in order to implicitly run
the event loop, now loop.run_until_complete(task.async_wait()) will
be used to explicitly run the event loop. This explicit approach will
make it more obvious when code will trigger event loop recursion
which would not be compatible with asyncio's default event loop.

Bug: https://bugs.gentoo.org/653856

 pym/_emerge/AsynchronousTask.py | 23 +++
 pym/portage/tests/ebuild/test_ipc_daemon.py |  2 +-
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/AsynchronousTask.py b/pym/_emerge/AsynchronousTask.py
index e29324440..7d2e6253b 100644
--- a/pym/_emerge/AsynchronousTask.py
+++ b/pym/_emerge/AsynchronousTask.py
@@ -29,6 +29,26 @@ class AsynchronousTask(SlotObject):
self._start_hook()
self._start()
 
+   def async_wait(self):
+   """
+   Wait for returncode asynchronously. Notification is available
+   via the add_done_callback method of the returned Future 
instance.
+
+   @returns: Future, result is self.returncode
+   """
+   waiter = self.scheduler.create_future()
+   exit_listener = lambda self: waiter.set_result(self.returncode)
+   self.addExitListener(exit_listener)
+   waiter.add_done_callback(lambda waiter:
+   self.removeExitListener(exit_listener) if 
waiter.cancelled() else None)
+   if self.returncode is not None:
+   # If the returncode is not None, it means the exit 
event has already
+   # happened, so use _async_wait() to guarantee that the 
exit_listener
+   # is called. This does not do any harm because a given 
exit listener
+   # is never called more than once.
+   self._async_wait()
+   return waiter
+
def _start(self):
self.returncode = os.EX_OK
self.wait()
@@ -47,6 +67,9 @@ class AsynchronousTask(SlotObject):
return self.returncode
 
def wait(self):
+   """
+   Deprecated. Use async_wait() instead.
+   """
if self.returncode is None:
if not self._waiting:
self._waiting = True

diff --git a/pym/portage/tests/ebuild/test_ipc_daemon.py 
b/pym/portage/tests/ebuild/test_ipc_daemon.py
index bc18cdf64..e6da51a76 100644
--- a/pym/portage/tests/ebuild/test_ipc_daemon.py
+++ b/pym/portage/tests/ebuild/test_ipc_daemon.py
@@ -157,6 +157,6 @@ class IpcDaemonTestCase(TestCase):
try:
task_scheduler.start()
event_loop.run_until_complete(self._run_done)
-   task_scheduler.wait()
+   
event_loop.run_until_complete(task_scheduler.async_wait())
finally:
timeout_handle.cancel()



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/

2018-04-23 Thread Zac Medico
commit: c23d093d0330a9318534a1c521fb00d6360fabc0
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Apr 23 18:20:25 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Apr 23 18:24:11 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=c23d093d

tests: prove run_until_complete executes done callbacks

Prove that done callbacks are executed before run_until_complete
returns, which is how asyncio's default event loop behaves. This
behavior was implemented in portage's internal event loop in commit
25245d7eb86ed197b7d7cfead0dbe4ce8ad4bc5b.

Bug: https://bugs.gentoo.org/591760

 .../futures/asyncio/test_run_until_complete.py | 29 ++
 1 file changed, 29 insertions(+)

diff --git a/pym/portage/tests/util/futures/asyncio/test_run_until_complete.py 
b/pym/portage/tests/util/futures/asyncio/test_run_until_complete.py
new file mode 100644
index 0..fc8f198ca
--- /dev/null
+++ b/pym/portage/tests/util/futures/asyncio/test_run_until_complete.py
@@ -0,0 +1,29 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util.futures import asyncio
+from portage.util.futures.unix_events import DefaultEventLoopPolicy
+
+
+class RunUntilCompleteTestCase(TestCase):
+   def test_add_done_callback(self):
+   initial_policy = asyncio.get_event_loop_policy()
+   if not isinstance(initial_policy, DefaultEventLoopPolicy):
+   asyncio.set_event_loop_policy(DefaultEventLoopPolicy())
+
+   try:
+   loop = asyncio.get_event_loop()
+   f1 = loop.create_future()
+   f2 = loop.create_future()
+   f1.add_done_callback(f2.set_result)
+   loop.call_soon(lambda: f1.set_result(None))
+   loop.run_until_complete(f1)
+   self.assertEqual(f1.done(), True)
+
+   # This proves that done callbacks of f1 are executed 
before
+   # loop.run_until_complete(f1) returns, which is how 
asyncio's
+   # default event loop behaves.
+   self.assertEqual(f2.done(), True)
+   finally:
+   asyncio.set_event_loop_policy(initial_policy)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/

2018-04-22 Thread Zac Medico
commit: a6e9c7cf429741015e26b923c8036416cc6bff7d
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Apr 22 16:19:27 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Apr 22 16:24:37 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=a6e9c7cf

test_iter_completed: fix SleepProcess._future_done cancel race

Fixes: a9e8ebaa6979 ("Add async_iter_completed for asyncio migration (bug 
591760)")

 pym/portage/tests/util/futures/test_iter_completed.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pym/portage/tests/util/futures/test_iter_completed.py 
b/pym/portage/tests/util/futures/test_iter_completed.py
index 1344523c6..b07146ed3 100644
--- a/pym/portage/tests/util/futures/test_iter_completed.py
+++ b/pym/portage/tests/util/futures/test_iter_completed.py
@@ -19,7 +19,8 @@ class SleepProcess(ForkProcess):
ForkProcess._start(self)
 
def _future_done(self, task):
-   self.future.set_result(self.seconds)
+   if not self.future.cancelled():
+   self.future.set_result(self.seconds)
 
def _run(self):
time.sleep(self.seconds)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/asyncio/, pym/portage/util/futures/

2018-04-16 Thread Zac Medico
commit: 72914c0dbae1dfab7565a627451b616e330b8889
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Apr 15 10:11:21 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Apr 17 02:19:57 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=72914c0d

Implement AbstractEventLoop.connect_write_pipe (bug 649588)

In python versions that support asyncio, this allows API consumers
to use subprocess.PIPE for asyncio.create_subprocess_exec() stdin
parameters.

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

 .../util/futures/asyncio/test_subprocess_exec.py   |  34 +++
 pym/portage/util/futures/transports.py |  90 +++
 pym/portage/util/futures/unix_events.py| 259 -
 3 files changed, 373 insertions(+), 10 deletions(-)

diff --git a/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py 
b/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
index 94984fc93..8c8c395ca 100644
--- a/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
+++ b/pym/portage/tests/util/futures/asyncio/test_subprocess_exec.py
@@ -191,3 +191,37 @@ class SubprocessExecTestCase(TestCase):
self.assertEqual(loop.run_until_complete(proc.wait()), 
os.EX_OK)
 
self._run_test(test)
+
+   def testWriteTransport(self):
+   """
+   Test asyncio.create_subprocess_exec(stdin=subprocess.PIPE) which
+   requires an AbstractEventLoop.connect_write_pipe implementation
+   (and a WriteTransport implementation for it to return).
+   """
+   if not hasattr(asyncio, 'create_subprocess_exec'):
+   self.skipTest('create_subprocess_exec not implemented 
for python2')
+
+   stdin_data = b'hello world'
+   cat_binary = find_binary("cat")
+   self.assertNotEqual(cat_binary, None)
+   cat_binary = cat_binary.encode()
+
+   def test(loop):
+   proc = loop.run_until_complete(
+   asyncio.create_subprocess_exec(
+   cat_binary,
+   stdin=subprocess.PIPE,
+   stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT))
+
+   # This buffers data when necessary to avoid blocking.
+   proc.stdin.write(stdin_data)
+   # Any buffered data is written asynchronously after the
+   # close method is called.
+   proc.stdin.close()
+
+   self.assertEqual(
+   loop.run_until_complete(proc.stdout.read()),
+   stdin_data)
+   self.assertEqual(loop.run_until_complete(proc.wait()), 
os.EX_OK)
+
+   self._run_test(test)

diff --git a/pym/portage/util/futures/transports.py 
b/pym/portage/util/futures/transports.py
new file mode 100644
index 0..60ea93073
--- /dev/null
+++ b/pym/portage/util/futures/transports.py
@@ -0,0 +1,90 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+try:
+   from asyncio.transports import Transport as _Transport
+except ImportError:
+   _Transport = object
+
+
+class _FlowControlMixin(_Transport):
+   """
+   This is identical to the standard library's private
+   asyncio.transports._FlowControlMixin class.
+
+   All the logic for (write) flow control in a mix-in base class.
+
+   The subclass must implement get_write_buffer_size().  It must call
+   _maybe_pause_protocol() whenever the write buffer size increases,
+   and _maybe_resume_protocol() whenever it decreases.  It may also
+   override set_write_buffer_limits() (e.g. to specify different
+   defaults).
+
+   The subclass constructor must call super().__init__(extra).  This
+   will call set_write_buffer_limits().
+
+   The user may call set_write_buffer_limits() and
+   get_write_buffer_size(), and their protocol's pause_writing() and
+   resume_writing() may be called.
+   """
+
+   def __init__(self, extra=None, loop=None):
+   super().__init__(extra)
+   assert loop is not None
+   self._loop = loop
+   self._protocol_paused = False
+   self._set_write_buffer_limits()
+
+   def _maybe_pause_protocol(self):
+   size = self.get_write_buffer_size()
+   if size <= self._high_water:
+   return
+   if not self._protocol_paused:
+   self._protocol_paused = True
+   try:
+   self._protocol.pause_writing()
+   except Exception as exc:
+   self._loop.call_exception_handler({
+   'message': 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/, pym/portage/util/futures/, ...

2018-04-16 Thread Zac Medico
commit: ece99145a48157b60212d511c8053f8f6c0532a9
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Apr 16 16:27:39 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Apr 16 16:42:58 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=ece99145

Use asyncio.wait from standard library when available

 pym/portage/tests/util/futures/test_retry.py   | 46 +++---
 .../futures/{_asyncio.py => _asyncio/__init__.py}  | 11 ++
 .../util/futures/{wait.py => _asyncio/tasks.py}| 17 ++--
 pym/portage/util/futures/iter_completed.py |  5 ++-
 4 files changed, 51 insertions(+), 28 deletions(-)

diff --git a/pym/portage/tests/util/futures/test_retry.py 
b/pym/portage/tests/util/futures/test_retry.py
index 7641e4e92..409f50971 100644
--- a/pym/portage/tests/util/futures/test_retry.py
+++ b/pym/portage/tests/util/futures/test_retry.py
@@ -11,9 +11,9 @@ except ImportError:
 from portage.tests import TestCase
 from portage.util._eventloop.global_event_loop import global_event_loop
 from portage.util.backoff import RandomExponentialBackoff
+from portage.util.futures import asyncio
 from portage.util.futures.futures import TimeoutError
 from portage.util.futures.retry import retry
-from portage.util.futures.wait import wait
 from portage.util.monotonic import monotonic
 
 
@@ -57,7 +57,7 @@ class HangForever(object):
 
 class RetryTestCase(TestCase):
def testSucceedLater(self):
-   loop = global_event_loop()
+   loop = global_event_loop()._asyncio_wrapper
func = SucceedLater(1)
func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
decorator = retry(try_max=,
@@ -67,51 +67,51 @@ class RetryTestCase(TestCase):
self.assertEqual(result, 'success')
 
def testSucceedNever(self):
-   loop = global_event_loop()
+   loop = global_event_loop()._asyncio_wrapper
func = SucceedNever()
func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
decorator = retry(try_max=4, try_timeout=None,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
decorated_func = decorator(func_coroutine)
-   done, pending = 
loop.run_until_complete(wait([decorated_func()]))
+   done, pending = 
loop.run_until_complete(asyncio.wait([decorated_func()], loop=loop))
self.assertEqual(len(done), 1)
-   self.assertTrue(isinstance(done[0].exception().__cause__, 
SucceedNeverException))
+   self.assertTrue(isinstance(done.pop().exception().__cause__, 
SucceedNeverException))
 
def testSucceedNeverReraise(self):
-   loop = global_event_loop()
+   loop = global_event_loop()._asyncio_wrapper
func = SucceedNever()
func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
decorator = retry(reraise=True, try_max=4, try_timeout=None,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
decorated_func = decorator(func_coroutine)
-   done, pending = 
loop.run_until_complete(wait([decorated_func()]))
+   done, pending = 
loop.run_until_complete(asyncio.wait([decorated_func()], loop=loop))
self.assertEqual(len(done), 1)
-   self.assertTrue(isinstance(done[0].exception(), 
SucceedNeverException))
+   self.assertTrue(isinstance(done.pop().exception(), 
SucceedNeverException))
 
def testHangForever(self):
-   loop = global_event_loop()
+   loop = global_event_loop()._asyncio_wrapper
func = HangForever()
func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
decorator = retry(try_max=2, try_timeout=0.1,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
decorated_func = decorator(func_coroutine)
-   done, pending = 
loop.run_until_complete(wait([decorated_func()]))
+   done, pending = 
loop.run_until_complete(asyncio.wait([decorated_func()], loop=loop))
self.assertEqual(len(done), 1)
-   self.assertTrue(isinstance(done[0].exception().__cause__, 
TimeoutError))
+   self.assertTrue(isinstance(done.pop().exception().__cause__, 
TimeoutError))
 
def testHangForeverReraise(self):
-   loop = global_event_loop()
+   loop = global_event_loop()._asyncio_wrapper
func = HangForever()
func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
decorator = retry(reraise=True, try_max=2, try_timeout=0.1,
delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))

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

2018-04-11 Thread Zac Medico
commit: 600b329949f8770fe2962987ee97567b65393c7e
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Apr 10 21:29:44 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Apr 12 02:43:47 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=600b3299

_slot_operator.._reinstalls: probe binpkg rebuild (bug 652938)

If the parent is not installed, check if it needs to be rebuilt against
an installed instance, since otherwise it could trigger downgrade of
an installed instance.

Bug: https://bugs.gentoo.org/652938
Reviewed-by: Manuel Rüger  gentoo.org>

 pym/_emerge/depgraph.py| 10 -
 .../tests/resolver/test_slot_operator_rebuild.py   | 45 +-
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 160ea5e94..67f912f5e 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2571,17 +2571,23 @@ class depgraph(object):
isinstance(dep.parent, Package) and 
dep.parent.built):
continue
 
+   # If the parent is not installed, check if it 
needs to be
+   # rebuilt against an installed instance, since 
otherwise
+   # it could trigger downgrade of an installed 
instance as
+   # in bug #652938.
+   want_update_probe = dep.want_update or not 
dep.parent.installed
+
# Check for slot update first, since we don't 
want to
# trigger reinstall of the child package when a 
newer
# slot will be used instead.
-   if rebuild_if_new_slot and dep.want_update:
+   if rebuild_if_new_slot and want_update_probe:
new_dep = 
self._slot_operator_update_probe(dep,
new_child_slot=True)
if new_dep is not None:

self._slot_operator_update_backtrack(dep,

new_child_slot=new_dep.child)
 
-   if dep.want_update:
+   if want_update_probe:
if 
self._slot_operator_update_probe(dep):

self._slot_operator_update_backtrack(dep)
 

diff --git a/pym/portage/tests/resolver/test_slot_operator_rebuild.py 
b/pym/portage/tests/resolver/test_slot_operator_rebuild.py
index 42512aad8..381683331 100644
--- a/pym/portage/tests/resolver/test_slot_operator_rebuild.py
+++ b/pym/portage/tests/resolver/test_slot_operator_rebuild.py
@@ -1,4 +1,4 @@
-# Copyright 2014 Gentoo Foundation
+# Copyright 2014-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -31,6 +31,32 @@ class SlotOperatorRebuildTestCase(TestCase):
"RDEPEND": "|| ( app-misc/X app-misc/A:= )"
},
 
+   "app-misc/D-1" : {
+   "EAPI": "6",
+   "RDEPEND": "app-misc/E",
+   },
+
+   "app-misc/E-1" : {
+   "EAPI": "6",
+   "RDEPEND": "app-misc/F:=",
+   },
+
+   "app-misc/F-1" : {
+   "EAPI": "6",
+   "SLOT": "0/1"
+   },
+
+   "app-misc/F-2" : {
+   "EAPI": "6",
+   "SLOT": "0/2"
+   },
+   }
+
+   binpkgs = {
+   "app-misc/E-1" : {
+   "EAPI": "6",
+   "RDEPEND": "app-misc/F:0/1=",
+   },
}
 
installed = {
@@ -50,6 +76,10 @@ class SlotOperatorRebuildTestCase(TestCase):
"RDEPEND": "|| ( app-misc/X app-misc/A:0/1= )"
},
 
+   "app-misc/F-2" : {
+   "EAPI": "6",
+   "SLOT": "0/2"
+   },
}
 
world = ["app-misc/B", "app-misc/C"]
@@ -68,9 +98,20 @@ class SlotOperatorRebuildTestCase(TestCase):
mergelist = ['app-misc/A-2', ('app-misc/B-0', 
'app-misc/C-0')]
),
 
+   # Test bug #652938, where a binary package built 
against an
+   # older subslot triggered downgrade of an installed 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/, pym/portage/util/futures/

2018-04-10 Thread Zac Medico
commit: f2bece120b1e9bcd7c74fc782cef9016f2147555
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Apr 10 06:52:58 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Apr 11 01:44:34 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=f2bece12

iter_completed: support asyncio via _PortageEventLoopPolicy (bug 649588)

Support portage's internal EventLoop as well as the _PortageEventLoop
asyncio compatibility wrapper, by using the respective _loop and
_asyncio_wrapper attributes where appropriate.

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

 pym/portage/tests/util/futures/test_iter_completed.py | 4 ++--
 pym/portage/util/futures/iter_completed.py| 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/pym/portage/tests/util/futures/test_iter_completed.py 
b/pym/portage/tests/util/futures/test_iter_completed.py
index d0a7dbb45..9c23aefb1 100644
--- a/pym/portage/tests/util/futures/test_iter_completed.py
+++ b/pym/portage/tests/util/futures/test_iter_completed.py
@@ -29,7 +29,7 @@ class IterCompletedTestCase(TestCase):
# load causes the tasks to finish in an unexpected order.
self.todo = True
 
-   loop = global_event_loop()
+   loop = global_event_loop()._asyncio_wrapper
tasks = [
SleepProcess(seconds=0.200),
SleepProcess(seconds=0.100),
@@ -41,7 +41,7 @@ class IterCompletedTestCase(TestCase):
def future_generator():
for task in tasks:
task.future = loop.create_future()
-   task.scheduler = loop
+   task.scheduler = loop._loop
task.start()
yield task.future
 

diff --git a/pym/portage/util/futures/iter_completed.py 
b/pym/portage/util/futures/iter_completed.py
index ad6275b49..583a20f3b 100644
--- a/pym/portage/util/futures/iter_completed.py
+++ b/pym/portage/util/futures/iter_completed.py
@@ -30,6 +30,7 @@ def iter_completed(futures, max_jobs=None, max_load=None, 
loop=None):
@rtype: iterator
"""
loop = loop or global_event_loop()
+   loop = getattr(loop, '_asyncio_wrapper', loop)
max_jobs = max_jobs or multiprocessing.cpu_count()
max_load = max_load or multiprocessing.cpu_count()
 
@@ -43,7 +44,7 @@ def iter_completed(futures, max_jobs=None, max_load=None, 
loop=None):
task_generator(),
max_jobs=max_jobs,
max_load=max_load,
-   event_loop=loop)
+   event_loop=loop._loop)
 
try:
scheduler.start()



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, repoman/pym/repoman/tests/

2018-04-06 Thread Zac Medico
commit: 1733e574716d2e904dcd9b0338a61fbfe0a798e7
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Apr  7 00:32:43 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Apr  7 01:42:01 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=1733e574

ResolverPlayground: create ${EPREFIX}/usr/share/repoman

This solves the following issue when running the tests with
an installed instance of repoman like we do in travis:

testSimple (repoman.tests.simple.test_simple.SimpleRepomanTestCase) ... 
Traceback (most recent call last):
  File "/usr/bin/repoman", line 44, in 
repoman_main(sys.argv[1:])
  File 
"/home/travis/virtualenv/python2.7.14/lib/python2.7/site-packages/repoman/main.py",
 line 95, in repoman_main
repoman_settings, vcs_settings, options, qadata)
  File 
"/home/travis/virtualenv/python2.7.14/lib/python2.7/site-packages/repoman/repos.py",
 line 56, in __init__
if not self.qadata.load_repo_config(self.masters_list, options, 
repoman_settings.valid_versions):
  File 
"/home/travis/virtualenv/python2.7.14/lib/python2.7/site-packages/repoman/qa_data.py",
 line 46, in load_repo_config
repomanpaths = [os.path.join(cnfdir, _file_) for _file_ in 
os.listdir(cnfdir)]
OSError: [Errno 2] No such file or directory: 
'/tmp/tmpWkrEvP/usr/share/repoman/qa_data'

 pym/portage/tests/resolver/ResolverPlayground.py | 10 ++
 repoman/pym/repoman/tests/__init__.py|  3 +++
 2 files changed, 13 insertions(+)

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index d3a5d8092..e2e061669 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -26,6 +26,11 @@ from _emerge.create_depgraph_params import 
create_depgraph_params
 from _emerge.depgraph import backtrack_depgraph
 from _emerge.RootConfig import RootConfig
 
+try:
+   from repoman.tests import cnf_path_repoman
+except ImportError:
+   cnf_path_repoman = None
+
 if sys.hexversion >= 0x300:
# pylint: disable=W0622
basestring = str
@@ -457,6 +462,11 @@ class ResolverPlayground(object):
for line in lines:
f.write("%s\n" % line)
 
+   if cnf_path_repoman is not None:
+   #Create /usr/share/repoman
+   repoman_share_dir = os.path.join(self.eroot, 'usr', 
'share', 'repoman')
+   os.symlink(cnf_path_repoman, repoman_share_dir)
+
def _create_world(self, world, world_sets):
#Create /var/lib/portage/world
var_lib_portage = os.path.join(self.eroot, "var", "lib", 
"portage")

diff --git a/repoman/pym/repoman/tests/__init__.py 
b/repoman/pym/repoman/tests/__init__.py
index 3421493f4..d57ca9b10 100644
--- a/repoman/pym/repoman/tests/__init__.py
+++ b/repoman/pym/repoman/tests/__init__.py
@@ -33,11 +33,14 @@ from portage.const import EPREFIX, GLOBAL_CONFIG_PATH, 
PORTAGE_BIN_PATH
 
 if repoman._not_installed:
cnf_path = os.path.join(REPOMAN_BASE_PATH, 'cnf')
+   cnf_path_repoman = cnf_path
cnf_etc_path = cnf_path
cnf_bindir = os.path.join(REPOMAN_BASE_PATH, 'bin')
cnf_sbindir = cnf_bindir
 else:
cnf_path = os.path.join(EPREFIX or '/', GLOBAL_CONFIG_PATH)
+   cnf_path_repoman = os.path.join(EPREFIX or '/',
+   sys.prefix.lstrip(os.sep), 'share', 'repoman')
cnf_etc_path = os.path.join(EPREFIX or '/', 'etc')
cnf_eprefix = EPREFIX
cnf_bindir = os.path.join(EPREFIX or '/', 'usr', 'bin')



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/, pym/portage/util/futures/

2018-04-02 Thread Zac Medico
commit: 1aa9a71731f3ab05e10190493956c70998abf12a
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Mar 16 19:37:54 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Apr  2 16:53:24 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=1aa9a717

Add retry decorator (API inspired by tenacity)

This decorator will be useful for retrying asynchronous
operations, such as gpg key refresh (bug 649276). The
API is inspired by tenacity, but is simpler. Only
asynchronous functions (like @asyncio.coroutine functions)
are supported. In order to retry a synchronous function,
first convert it to an asynchronous function as follows:

asynchronous_func = functools.partial(
loop.run_in_executor, None, synchronous_func)

Bug: https://bugs.gentoo.org/649276
See: https://github.com/jd/tenacity
Reviewed-by: Alec Warner  gentoo.org>

 pym/portage/tests/util/futures/test_retry.py | 147 +
 pym/portage/util/futures/futures.py  |   6 +
 pym/portage/util/futures/retry.py| 183 +++
 3 files changed, 336 insertions(+)

diff --git a/pym/portage/tests/util/futures/test_retry.py 
b/pym/portage/tests/util/futures/test_retry.py
new file mode 100644
index 0..7641e4e92
--- /dev/null
+++ b/pym/portage/tests/util/futures/test_retry.py
@@ -0,0 +1,147 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import functools
+
+try:
+   import threading
+except ImportError:
+   import dummy_threading as threading
+
+from portage.tests import TestCase
+from portage.util._eventloop.global_event_loop import global_event_loop
+from portage.util.backoff import RandomExponentialBackoff
+from portage.util.futures.futures import TimeoutError
+from portage.util.futures.retry import retry
+from portage.util.futures.wait import wait
+from portage.util.monotonic import monotonic
+
+
+class SucceedLaterException(Exception):
+   pass
+
+
+class SucceedLater(object):
+   """
+   A callable object that succeeds some duration of time has passed.
+   """
+   def __init__(self, duration):
+   self._succeed_time = monotonic() + duration
+
+   def __call__(self):
+   remaining = self._succeed_time - monotonic()
+   if remaining > 0:
+   raise SucceedLaterException('time until success: {} 
seconds'.format(remaining))
+   return 'success'
+
+
+class SucceedNeverException(Exception):
+   pass
+
+
+class SucceedNever(object):
+   """
+   A callable object that never succeeds.
+   """
+   def __call__(self):
+   raise SucceedNeverException('expected failure')
+
+
+class HangForever(object):
+   """
+   A callable object that sleeps forever.
+   """
+   def __call__(self):
+   threading.Event().wait()
+
+
+class RetryTestCase(TestCase):
+   def testSucceedLater(self):
+   loop = global_event_loop()
+   func = SucceedLater(1)
+   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   decorator = retry(try_max=,
+   delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
+   decorated_func = decorator(func_coroutine)
+   result = loop.run_until_complete(decorated_func())
+   self.assertEqual(result, 'success')
+
+   def testSucceedNever(self):
+   loop = global_event_loop()
+   func = SucceedNever()
+   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   decorator = retry(try_max=4, try_timeout=None,
+   delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
+   decorated_func = decorator(func_coroutine)
+   done, pending = 
loop.run_until_complete(wait([decorated_func()]))
+   self.assertEqual(len(done), 1)
+   self.assertTrue(isinstance(done[0].exception().__cause__, 
SucceedNeverException))
+
+   def testSucceedNeverReraise(self):
+   loop = global_event_loop()
+   func = SucceedNever()
+   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   decorator = retry(reraise=True, try_max=4, try_timeout=None,
+   delay_func=RandomExponentialBackoff(multiplier=0.1, 
base=2))
+   decorated_func = decorator(func_coroutine)
+   done, pending = 
loop.run_until_complete(wait([decorated_func()]))
+   self.assertEqual(len(done), 1)
+   self.assertTrue(isinstance(done[0].exception(), 
SucceedNeverException))
+
+   def testHangForever(self):
+   loop = global_event_loop()
+   func = HangForever()
+   func_coroutine = functools.partial(loop.run_in_executor, None, 
func)
+   decorator = 

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

2018-03-26 Thread Zac Medico
commit: 6a810e0cdb586fb05f210a1c7ba2b5401f38c332
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Mar 21 18:50:43 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Mar 26 17:35:33 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=6a810e0c

emerge: add --ignore-world [ y | n ] option (bug 608564)

Ignore the @world package set and its dependencies. This may be useful
if there is a desire to perform an action even though it might break
the dependencies of some installed packages (it might also remove
installed packages in order to solve blockers). This also alters the
behavior of --complete-graph options so that only deep dependencies
of packages given as arguments are included in the dependency graph.
This option may be useful as an alternative to --nodeps in cases where
it is desirable to account for dependencies of packages given as
arguments.

Bug: https://bugs.gentoo.org/608564

 man/emerge.1  | 19 ++-
 pym/_emerge/create_depgraph_params.py |  6 +-
 pym/_emerge/depgraph.py   |  8 ++--
 pym/_emerge/main.py   | 11 ++-
 pym/portage/tests/resolver/test_complete_graph.py | 20 +++-
 5 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/man/emerge.1 b/man/emerge.1
index a17b65ed2..27a1193fe 100644
--- a/man/emerge.1
+++ b/man/emerge.1
@@ -1,4 +1,4 @@
-.TH "EMERGE" "1" "Jul 2016" "Portage VERSION" "Portage"
+.TH "EMERGE" "1" "Mar 2018" "Portage VERSION" "Portage"
 .SH "NAME"
 emerge \- Command\-line interface to the Portage system
 .SH "SYNOPSIS"
@@ -630,6 +630,23 @@ Therefore, \fB\-\-usepkgonly\fR (or 
\fB\-\-getbinpkgonly\fR) must be
 used in order to enable soname depedency resolution when installing
 packages.
 .TP
+.BR "\-\-ignore\-world [ y | n ]"
+Ignore the @world package set and its dependencies. This may be useful
+if there is a desire to perform an action even though it might break
+the dependencies of some installed packages (it might also remove
+installed packages in order to solve blockers). This also alters the
+behavior of \fB\-\-complete\-graph\fR options so that only deep
+dependencies of packages given as arguments are included in the
+dependency graph. This option may be useful as an alternative to
+\fB\-\-nodeps\fR in cases where it is desirable to account for
+dependencies of packages given as arguments.
+
+\fBWARNING:\fR
+This option is intended to be used only with great caution, since it is
+possible for it to make nonsensical changes which may lead to system
+breakage. Therefore, it is advisable to use \fB\-\-ask\fR together with
+this option.
+.TP
 .BR \-j\ [JOBS] ", "  \-\-jobs[=JOBS]
 Specifies the number of packages to build simultaneously. If this option is
 given without an argument, emerge will not limit the number of jobs that can

diff --git a/pym/_emerge/create_depgraph_params.py 
b/pym/_emerge/create_depgraph_params.py
index fc7fa60d7..ff18f3acc 100644
--- a/pym/_emerge/create_depgraph_params.py
+++ b/pym/_emerge/create_depgraph_params.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2014 Gentoo Foundation
+# Copyright 1999-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import logging
@@ -26,6 +26,7 @@ def create_depgraph_params(myopts, myaction):
# ignore_soname_deps: ignore the soname dependencies of built
#   packages, so that they do not trigger dependency resolution
#   failures, or cause packages to be rebuilt or replaced.
+   # ignore_world: ignore the @world package set and its dependencies
# with_test_deps: pull in test deps for packages matched by arguments
# changed_deps: rebuild installed packages with outdated deps
# changed_deps_report: report installed packages with outdated deps
@@ -56,6 +57,9 @@ def create_depgraph_params(myopts, myaction):
myparams["selective"] = True
return myparams
 
+   if myopts.get('--ignore-world') is True:
+   myparams['ignore_world'] = True
+
rebuild_if_new_slot = myopts.get('--rebuild-if-new-slot')
if rebuild_if_new_slot is not None:
myparams['rebuild_if_new_slot'] = rebuild_if_new_slot

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 6c728684f..f7ea27c37 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -163,7 +163,10 @@ class _frozen_depgraph_config(object):
self.trees[myroot]["bintree"] = DummyTree(

DbapiProvidesIndex(trees[myroot]["bintree"].dbapi))
 
-   self._required_set_names = set(["world"])
+   if params.get("ignore_world", False):
+   self._required_set_names = set()
+   else:
+   self._required_set_names = set(["world"])
 
atoms = ' 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/bin/, bin/

2018-03-11 Thread Michał Górny
commit: 08d405f72e85125b64f5074e49714e759d85eaf6
Author: Michał Górny  gentoo  org>
AuthorDate: Mon Feb 19 15:38:28 2018 +
Commit: Michał Górny  gentoo  org>
CommitDate: Sun Mar 11 11:43:41 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=08d405f7

Add EAPI 7 version comparison & manipulation functions

The function code is copied from eapi7-ver.eclass which has been written
by Ulrich Müller and me.

Bug: https://bugs.gentoo.org/482170

 bin/eapi.sh   |   4 +
 bin/eapi7-ver-funcs.sh| 191 
 bin/isolated-functions.sh |   4 +
 pym/portage/tests/bin/test_eapi7_ver_funcs.py | 240 ++
 4 files changed, 439 insertions(+)

diff --git a/bin/eapi.sh b/bin/eapi.sh
index fa254485c..1d5ea802d 100644
--- a/bin/eapi.sh
+++ b/bin/eapi.sh
@@ -100,6 +100,10 @@ ___eapi_has_in_iuse() {
[[ ! ${1-${EAPI-0}} =~ 
^(0|1|2|3|4|4-python|4-slot-abi|5|5-hdepend|5-progress)$ ]]
 }
 
+___eapi_has_version_functions() {
+   [[ ! ${1-${EAPI-0}} =~ ^(0|1|2|3|4|4-python|4-slot-abi|5|5-progress|6)$ 
]]
+}
+
 ___eapi_has_master_repositories() {
[[ ${1-${EAPI-0}} =~ ^(5-progress)$ ]]
 }

diff --git a/bin/eapi7-ver-funcs.sh b/bin/eapi7-ver-funcs.sh
new file mode 100644
index 0..b4e98f4e7
--- /dev/null
+++ b/bin/eapi7-ver-funcs.sh
@@ -0,0 +1,191 @@
+#!/bin/bash
+# Copyright 1999-2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__eapi7_ver_parse_range() {
+   local range=${1}
+   local max=${2}
+
+   [[ ${range} == [0-9]* ]] \
+   || die "${FUNCNAME}: range must start with a number"
+   start=${range%-*}
+   [[ ${range} == *-* ]] && end=${range#*-} || end=${start}
+   if [[ ${end} ]]; then
+   [[ ${start} -le ${end} ]] \
+   || die "${FUNCNAME}: end of range must be >= start"
+   [[ ${end} -le ${max} ]] || end=${max}
+   else
+   end=${max}
+   fi
+}
+
+__eapi7_ver_split() {
+   local v=${1} LC_ALL=C
+
+   comp=()
+
+   # get separators and components
+   local s c
+   while [[ ${v} ]]; do
+   # cut the separator
+   s=${v%%[a-zA-Z0-9]*}
+   v=${v:${#s}}
+   # cut the next component; it can be either digits or letters
+   [[ ${v} == [0-9]* ]] && c=${v%%[^0-9]*} || c=${v%%[^a-zA-Z]*}
+   v=${v:${#c}}
+
+   comp+=( "${s}" "${c}" )
+   done
+}
+
+ver_cut() {
+   local range=${1}
+   local v=${2:-${PV}}
+   local start end
+   local -a comp
+
+   __eapi7_ver_split "${v}"
+   local max=$((${#comp[@]}/2))
+   __eapi7_ver_parse_range "${range}" "${max}"
+
+   local IFS=
+   if [[ ${start} -gt 0 ]]; then
+   start=$(( start*2 - 1 ))
+   fi
+   echo "${comp[*]:start:end*2-start}"
+}
+
+ver_rs() {
+   local v
+   (( ${#} & 1 )) && v=${@: -1} || v=${PV}
+   local start end i
+   local -a comp
+
+   __eapi7_ver_split "${v}"
+   local max=$((${#comp[@]}/2 - 1))
+
+   while [[ ${#} -ge 2 ]]; do
+   __eapi7_ver_parse_range "${1}" "${max}"
+   for (( i = start*2; i <= end*2; i+=2 )); do
+   [[ ${i} -eq 0 && -z ${comp[i]} ]] && continue
+   comp[i]=${2}
+   done
+   shift 2
+   done
+
+   local IFS=
+   echo "${comp[*]}"
+}
+
+__eapi7_ver_compare_int() {
+   local a=$1 b=$2 d=$(( ${#1}-${#2} ))
+
+   # Zero-pad to equal length if necessary.
+   if [[ ${d} -gt 0 ]]; then
+   printf -v b "%0${d}d%s" 0 "${b}"
+   elif [[ ${d} -lt 0 ]]; then
+   printf -v a "%0$(( -d ))d%s" 0 "${a}"
+   fi
+
+   [[ ${a} > ${b} ]] && return 3
+   [[ ${a} == "${b}" ]]
+}
+
+__eapi7_ver_compare() {
+   local va=${1} vb=${2} a an al as ar b bn bl bs br re LC_ALL=C
+
+   
re="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$"
+
+   [[ ${va} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${va}"
+   an=${BASH_REMATCH[1]}
+   al=${BASH_REMATCH[3]}
+   as=${BASH_REMATCH[4]}
+   ar=${BASH_REMATCH[7]}
+
+   [[ ${vb} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${vb}"
+   bn=${BASH_REMATCH[1]}
+   bl=${BASH_REMATCH[3]}
+   bs=${BASH_REMATCH[4]}
+   br=${BASH_REMATCH[7]}
+
+   # Compare numeric components (PMS algorithm 3.2)
+   # First component
+   __eapi7_ver_compare_int "${an%%.*}" "${bn%%.*}" || return
+
+   while [[ ${an} == *.* && ${bn} == *.* ]]; do
+   # Other components (PMS algorithm 3.3)
+   an=${an#*.}
+   bn=${bn#*.}
+   a=${an%%.*}
+   b=${bn%%.*}
+   if [[ ${a} == 0* || ${b} == 0* ]]; then
+   # Remove any trailing zeros
+

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/

2018-03-04 Thread Michał Górny
commit: ea4456cf197fd7ac8644ab0396fb629ce612ae6f
Author: Michał Górny  gentoo  org>
AuthorDate: Mon Feb 26 12:40:15 2018 +
Commit: Michał Górny  gentoo  org>
CommitDate: Sun Mar  4 21:03:52 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=ea4456cf

test_required_use: Add tests for ?? operator

 pym/portage/tests/resolver/test_required_use.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pym/portage/tests/resolver/test_required_use.py 
b/pym/portage/tests/resolver/test_required_use.py
index d4004..ac748ca3b 100644
--- a/pym/portage/tests/resolver/test_required_use.py
+++ b/pym/portage/tests/resolver/test_required_use.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2011 Gentoo Foundation
+# Copyright 2010-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/portage/dep/

2018-03-04 Thread Michał Górny
commit: 9ebd5865559aa17186c23c90c6a90894449dc3ac
Author: Michał Górny  gentoo  org>
AuthorDate: Mon Feb 26 13:09:32 2018 +
Commit: Michał Górny  gentoo  org>
CommitDate: Sun Mar  4 21:03:52 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=9ebd5865

Empty || *DEPEND group no longer satisfy deps in EAPI 7

Bug: https://bugs.gentoo.org/636596

 pym/portage/dep/__init__.py | 3 +++
 pym/portage/tests/resolver/test_eapi.py | 9 -
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py
index 2a081f3d8..3d4bca08f 100644
--- a/pym/portage/dep/__init__.py
+++ b/pym/portage/dep/__init__.py
@@ -562,6 +562,9 @@ def use_reduce(depstr, uselist=[], masklist=[], 
matchall=False, excludeall=[], i
basestring):
if stack[level][-1] == "||" and not l:
#Optimize: || ( ) -> .
+   if not 
eapi_attrs.empty_groups_always_true:
+   # in EAPI 7+, we need 
to fail here
+   l.append((token_class 
or _unicode)("__const__/empty-any-of"))
stack[level].pop()
elif stack[level][-1][-1] == "?":
#The last token before the '(' 
that matches the current ')'

diff --git a/pym/portage/tests/resolver/test_eapi.py 
b/pym/portage/tests/resolver/test_eapi.py
index 525b58532..fce05890b 100644
--- a/pym/portage/tests/resolver/test_eapi.py
+++ b/pym/portage/tests/resolver/test_eapi.py
@@ -1,4 +1,4 @@
-# Copyright 2010 Gentoo Foundation
+# Copyright 2010-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -59,6 +59,10 @@ class EAPITestCase(TestCase):
"dev-libs/A-7.4": { "EAPI": "4", "IUSE": "foo +bar", 
"REQUIRED_USE": "|| ( foo bar )" }, 
 
"dev-libs/B-1": {"EAPI": 1, "IUSE": "+foo"}, 
+
+   #EAPI-7: implicit || ( ) no longer satisfies deps
+   "dev-libs/C-1": { "EAPI": "6", "IUSE": "foo", 
"RDEPEND": "|| ( foo? ( dev-libs/B ) )" }, 
+   "dev-libs/C-2": { "EAPI": "7_pre1", "IUSE": "foo", 
"RDEPEND": "|| ( foo? ( dev-libs/B ) )" }, 
}
 
test_cases = (
@@ -104,6 +108,9 @@ class EAPITestCase(TestCase):
ResolverPlaygroundTestCase(["=dev-libs/A-7.2"], success 
= False),
ResolverPlaygroundTestCase(["=dev-libs/A-7.3"], success 
= False),
ResolverPlaygroundTestCase(["=dev-libs/A-7.4"], success 
= True, mergelist = ["dev-libs/A-7.4"]),
+
+   ResolverPlaygroundTestCase(["=dev-libs/C-1"], success = 
True, mergelist = ["dev-libs/C-1"]),
+   ResolverPlaygroundTestCase(["=dev-libs/C-2"], success = 
False),
)
 
playground = ResolverPlayground(ebuilds=ebuilds)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/futures/, pym/portage/util/futures/, ...

2018-02-28 Thread Zac Medico
commit: e43f6c583ed9205abbdcb11340c81d7dd97ccc11
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Feb 25 23:19:58 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Feb 28 17:22:20 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=e43f6c58

Add iter_completed convenience function (bug 648790)

The iter_completed function is similar to asyncio.as_completed, but
takes an iterator of futures as input, and includes support for
max_jobs and max_load parameters. The default values for max_jobs
and max_load correspond to multiprocessing.cpu_count().

Example usage for async_aux_get:

  import portage
  from portage.util.futures.iter_completed import iter_completed

  portdb = portage.portdb
  # aux_get has many inputs, and the same cpv can exist in multiple
  # repositories, so the caller is responsibe for mapping futures
  # back to their aux_get inputs
  future_cpv = {}

  def future_generator():
for cpv in portdb.cp_list('sys-apps/portage'):
  future = portdb.async_aux_get(cpv, portage.auxdbkeys)
  future_cpv[id(future)] = cpv
  yield future

  for future in iter_completed(future_generator()):
cpv = future_cpv.pop(id(future))
try:
  result = future.result()
except KeyError as e:
  # aux_get failed
  print('error:', cpv, e)
else:
  print(cpv, result)

See: https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed
Bug: https://bugs.gentoo.org/648790

 .../tests/util/futures/test_iter_completed.py  |  50 ++
 pym/portage/util/_async/AsyncTaskFuture.py |  31 +++
 pym/portage/util/futures/iter_completed.py |  63 +
 pym/portage/util/futures/wait.py   | 102 +
 4 files changed, 246 insertions(+)

diff --git a/pym/portage/tests/util/futures/test_iter_completed.py 
b/pym/portage/tests/util/futures/test_iter_completed.py
new file mode 100644
index 0..d0a7dbb45
--- /dev/null
+++ b/pym/portage/tests/util/futures/test_iter_completed.py
@@ -0,0 +1,50 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import time
+from portage.tests import TestCase
+from portage.util._async.ForkProcess import ForkProcess
+from portage.util._eventloop.global_event_loop import global_event_loop
+from portage.util.futures.iter_completed import iter_completed
+
+
+class SleepProcess(ForkProcess):
+   __slots__ = ('future', 'seconds')
+   def _start(self):
+   self.addExitListener(self._future_done)
+   ForkProcess._start(self)
+
+   def _future_done(self, task):
+   self.future.set_result(self.seconds)
+
+   def _run(self):
+   time.sleep(self.seconds)
+
+
+class IterCompletedTestCase(TestCase):
+
+   def testIterCompleted(self):
+
+   # Mark this as todo, since we don't want to fail if heavy system
+   # load causes the tasks to finish in an unexpected order.
+   self.todo = True
+
+   loop = global_event_loop()
+   tasks = [
+   SleepProcess(seconds=0.200),
+   SleepProcess(seconds=0.100),
+   SleepProcess(seconds=0.001),
+   ]
+
+   expected_order = sorted(task.seconds for task in tasks)
+
+   def future_generator():
+   for task in tasks:
+   task.future = loop.create_future()
+   task.scheduler = loop
+   task.start()
+   yield task.future
+
+   for seconds, future in zip(expected_order, 
iter_completed(future_generator(),
+   max_jobs=True, max_load=None, loop=loop)):
+   self.assertEqual(seconds, future.result())

diff --git a/pym/portage/util/_async/AsyncTaskFuture.py 
b/pym/portage/util/_async/AsyncTaskFuture.py
new file mode 100644
index 0..ee39183fe
--- /dev/null
+++ b/pym/portage/util/_async/AsyncTaskFuture.py
@@ -0,0 +1,31 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os
+import signal
+
+from _emerge.AsynchronousTask import AsynchronousTask
+
+
+class AsyncTaskFuture(AsynchronousTask):
+   """
+   Wraps a Future in an AsynchronousTask, which is useful for
+   scheduling with TaskScheduler.
+   """
+   __slots__ = ('future', 'scheduler')
+   def _start(self):
+   self.future.add_done_callback(self._done_callback)
+
+   def _cancel(self):
+   if not self.future.done():
+   self.future.cancel()
+
+   def _done_callback(self, future):
+   if future.cancelled():
+   self.cancelled = True
+   self.returncode = -signal.SIGINT
+   elif future.exception() is None:
+ 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/

2018-02-26 Thread Michał Górny
commit: 45bdfae8b20dc24559d325db7322576855d6a582
Author: Michał Górny  gentoo  org>
AuthorDate: Mon Feb 26 12:40:15 2018 +
Commit: Michał Górny  gentoo  org>
CommitDate: Mon Feb 26 22:07:36 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=45bdfae8

test_required_use: Add tests for ?? operator

Reviewed-by: Zac Medico  gentoo.org>

 pym/portage/tests/resolver/test_required_use.py | 12 
 1 file changed, 12 insertions(+)

diff --git a/pym/portage/tests/resolver/test_required_use.py 
b/pym/portage/tests/resolver/test_required_use.py
index c8810faef..d4004 100644
--- a/pym/portage/tests/resolver/test_required_use.py
+++ b/pym/portage/tests/resolver/test_required_use.py
@@ -44,6 +44,12 @@ class RequiredUSETestCase(TestCase):
"dev-libs/D-3" : {"EAPI": "4", "IUSE": "+w +x y z", 
"REQUIRED_USE": "w? ( x || ( y z ) )"},
"dev-libs/D-4" : {"EAPI": "4", "IUSE": "+w x +y +z",
"REQUIRED_USE": "w? ( x || ( y z ) )"},
"dev-libs/D-5" : {"EAPI": "4", "IUSE": "w x y z",   
"REQUIRED_USE": "w? ( x || ( y z ) )"},
+
+   "dev-libs/E-1" : {"EAPI": "5", "IUSE": "foo bar",   
"REQUIRED_USE": "?? ( foo bar )"},
+   "dev-libs/E-2" : {"EAPI": "5", "IUSE": "foo +bar",  
"REQUIRED_USE": "?? ( foo bar )"},
+   "dev-libs/E-3" : {"EAPI": "5", "IUSE": "+foo bar",  
"REQUIRED_USE": "?? ( foo bar )"},
+   "dev-libs/E-4" : {"EAPI": "5", "IUSE": "+foo +bar", 
"REQUIRED_USE": "?? ( foo bar )"},
+   "dev-libs/E-5" : {"EAPI": "5", "IUSE": "+foo +bar", 
"REQUIRED_USE": "?? ( )"},
}
 
test_cases = (
@@ -79,6 +85,12 @@ class RequiredUSETestCase(TestCase):
ResolverPlaygroundTestCase(["=dev-libs/D-3"],  success 
= False),
ResolverPlaygroundTestCase(["=dev-libs/D-4"],  success 
= False),
ResolverPlaygroundTestCase(["=dev-libs/D-5"],  success 
= True, mergelist=["dev-libs/D-5"]),
+
+   ResolverPlaygroundTestCase(["=dev-libs/E-1"], success = 
True, mergelist=["dev-libs/E-1"]),
+   ResolverPlaygroundTestCase(["=dev-libs/E-2"], success = 
True, mergelist=["dev-libs/E-2"]),
+   ResolverPlaygroundTestCase(["=dev-libs/E-3"], success = 
True, mergelist=["dev-libs/E-3"]),
+   ResolverPlaygroundTestCase(["=dev-libs/E-4"], success = 
False),
+   ResolverPlaygroundTestCase(["=dev-libs/E-5"], success = 
True, mergelist=["dev-libs/E-5"]),
)
 
playground = ResolverPlayground(ebuilds=ebuilds)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/ebuild/, pym/portage/util/_eventloop/

2018-02-24 Thread Zac Medico
commit: 81baf80258393938152d6c8fc53d33d5f85de23c
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Feb 25 06:17:40 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Feb 25 06:19:18 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=81baf802

EventLoop: implement call_later for asyncio compat (bug 591760)

Bug: https://bugs.gentoo.org/591760

 pym/portage/tests/ebuild/test_ipc_daemon.py | 12 ++--
 pym/portage/util/_eventloop/EventLoop.py| 28 
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/pym/portage/tests/ebuild/test_ipc_daemon.py 
b/pym/portage/tests/ebuild/test_ipc_daemon.py
index fc7916541..1152f31b4 100644
--- a/pym/portage/tests/ebuild/test_ipc_daemon.py
+++ b/pym/portage/tests/ebuild/test_ipc_daemon.py
@@ -31,7 +31,7 @@ class SleepProcess(ForkProcess):
 
 class IpcDaemonTestCase(TestCase):
 
-   _SCHEDULE_TIMEOUT = 4 # 40 seconds
+   _SCHEDULE_TIMEOUT = 40 # seconds
 
def testIpcDaemon(self):
event_loop = global_event_loop()
@@ -103,8 +103,8 @@ class IpcDaemonTestCase(TestCase):
# Intentionally short timeout test for 
EventLoop/AsyncScheduler.
# Use a ridiculously long sleep_time_s in case the 
user's
# system is heavily loaded (see bug #436334).
-   sleep_time_s = 600 #600.000 seconds
-   short_timeout_ms = 10  #  0.010 seconds
+   sleep_time_s = 600   # seconds
+   short_timeout_s = 0.010  # seconds
 
for i in range(3):
exit_command = ExitCommand()
@@ -123,7 +123,7 @@ class IpcDaemonTestCase(TestCase):
 
exit_command.reply_hook = exit_command_callback
start_time = time.time()
-   self._run(event_loop, task_scheduler, 
short_timeout_ms)
+   self._run(event_loop, task_scheduler, 
short_timeout_s)
 
hardlock_cleanup(env['PORTAGE_BUILDDIR'],
remove_all_locks=True)
@@ -150,7 +150,7 @@ class IpcDaemonTestCase(TestCase):
 
def _run(self, event_loop, task_scheduler, timeout):
self._run_done = event_loop.create_future()
-   timeout_id = event_loop.timeout_add(timeout,
+   timeout_handle = event_loop.call_later(timeout,
self._timeout_callback, task_scheduler)
task_scheduler.addExitListener(self._exit_callback)
 
@@ -159,4 +159,4 @@ class IpcDaemonTestCase(TestCase):
event_loop.run_until_complete(self._run_done)
task_scheduler.wait()
finally:
-   event_loop.source_remove(timeout_id)
+   timeout_handle.cancel()

diff --git a/pym/portage/util/_eventloop/EventLoop.py 
b/pym/portage/util/_eventloop/EventLoop.py
index cd154005f..89ac2a3b3 100644
--- a/pym/portage/util/_eventloop/EventLoop.py
+++ b/pym/portage/util/_eventloop/EventLoop.py
@@ -684,6 +684,34 @@ class EventLoop(object):
# The call_soon method inherits thread safety from the idle_add method.
call_soon_threadsafe = call_soon
 
+   def call_later(self, delay, callback, *args):
+   """
+   Arrange for the callback to be called after the given delay 
seconds
+   (either an int or float).
+
+   An instance of asyncio.Handle is returned, which can be used to 
cancel
+   the callback.
+
+   callback will be called exactly once per call to call_later(). 
If two
+   callbacks are scheduled for exactly the same time, it is 
undefined
+   which will be called first.
+
+   The optional positional args will be passed to the callback when
+   it is called. If you want the callback to be called with some 
named
+   arguments, use a closure or functools.partial().
+
+   Use functools.partial to pass keywords to the callback.
+
+   @type delay: int or float
+   @param delay: delay seconds
+   @type callback: callable
+   @param callback: a function to call
+   @return: a handle which can be used to cancel the callback
+   @rtype: asyncio.Handle (or compatible)
+   """
+   return self._handle(self.timeout_add(
+   delay * 1000, self._call_soon_callback(callback, 
args)), self)
+
 
 _can_poll_device = None
 



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/bin/

2018-02-21 Thread Zac Medico
commit: 572861a1201ca67e18ce2ccae87480a2600b6ae2
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Feb 21 23:35:21 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Feb 21 23:36:24 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=572861a1

test_filter_bash_env.py: fix DeprecationWarning: invalid escape sequence \$

Fixes: f1367a2eeb0c ("filter-bash-environment.py: use buffered input, raw bytes 
(bug 647654)")

 pym/portage/tests/bin/test_filter_bash_env.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/bin/test_filter_bash_env.py 
b/pym/portage/tests/bin/test_filter_bash_env.py
index 10847bb7d..d906ea793 100644
--- a/pym/portage/tests/bin/test_filter_bash_env.py
+++ b/pym/portage/tests/bin/test_filter_bash_env.py
@@ -16,7 +16,7 @@ class TestFilterBashEnv(TestCase):
test_cases = (
(
'RDEPEND BASH.* _EPATCH_ECLASS',
-   b'''declare -ir BASHPID="28997"
+   br'''declare -ir BASHPID="28997"
 declare -rx A="portage-2.3.24.tar.bz2"
 declare -- DESKTOP_DATABASE_DIR="/usr/share/applications"
 declare PDEPEND="
@@ -53,7 +53,7 @@ use_if_iuse ()
 use $1
 }
 ''',
-   b'''declare -x A="portage-2.3.24.tar.bz2"
+   br'''declare -x A="portage-2.3.24.tar.bz2"
 declare -- DESKTOP_DATABASE_DIR="/usr/share/applications"
 declare PDEPEND="
 !build? (



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/dep/, pym/portage/dep/, pym/portage/tests/resolver/

2018-02-02 Thread Zac Medico
commit: 0ddfb5802d98c618bd20742be49a520c9a54b394
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Feb  2 06:08:59 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri Feb  2 12:01:25 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=0ddfb580

dep_zapdeps: sort by new_slot_count for DNF only (bug 645002)

Sorting of choices by new_slot_count causes the order of
choices specified in the ebuild to be discarded, and
new_slot_count may have variance related to the order that
packages are added to the graph. This variance can
contribute to outcomes that appear to be random, like when
catalyst stage1 builds sometimes pull in paludis to
satisfy perl-cleaner dependencies.

Meanwhile, the order specified in the ebuild has no
variance, and the preferences that it specifies can serve
as a crucial sources of guidance. Therefore, take advantage
of the order specified in the ebuild whenever possible, and
use new_slot_count only when it is needed to select optimal
choices from DNF (as in bug 632026).

This fixes random outcomes in the unit test for bug 645002.
Previously, the unit test pulled in paludis randomly unless
portage-utils was added to the arguments. With this patch,
the portage-utils argument is no longer needed for the unit
test to succeed consistently. The perl-cleaner dependencies
do not have any overlapping || deps, so the DNF conversion
and new_slot_count sorting do not apply, and the first
choice is preferred regardless of the number of slots that
it pulls in:

|| (
  ( sys-apps/portage app-portage/portage-utils )
  sys-apps/pkgcore
  sys-apps/paludis
)

The _overlap_dnf function now returns the argument object
when there is no overlap, so OverlapDNFTestCase has to be
adjusted to account for this.

Bug: https://bugs.gentoo.org/645002
Fixes: 9fdaf9bdbdf5 ("dep_check: use DNF to optimize overlapping virtual || 
deps (bug 632026)")

 pym/portage/dep/dep_check.py   | 49 ++
 pym/portage/tests/dep/test_overlap_dnf.py  |  2 +-
 .../resolver/test_virtual_minimize_children.py | 12 +++---
 3 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
index 7e5a3186e..2896e2389 100644
--- a/pym/portage/dep/dep_check.py
+++ b/pym/portage/dep/dep_check.py
@@ -298,7 +298,8 @@ class _dep_choice(SlotObject):
__slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
'all_installed_slots', 'new_slot_count')
 
-def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
+def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
+   minimize_slots=False):
"""
Takes an unreduced and reduced deplist and removes satisfied 
dependencies.
Returned deplist contains steps that must be taken to satisfy 
dependencies.
@@ -314,7 +315,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, 
trees=None):
for x, satisfied in zip(unreduced, reduced):
if isinstance(x, list):
unresolved += dep_zapdeps(x, satisfied, myroot,
-   use_binaries=use_binaries, trees=trees)
+   use_binaries=use_binaries, trees=trees,
+   minimize_slots=minimize_slots)
elif not satisfied:
unresolved.append(x)
return unresolved
@@ -386,7 +388,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, 
trees=None):
for x, satisfied in zip(deps, satisfieds):
if isinstance(x, list):
atoms = dep_zapdeps(x, satisfied, myroot,
-   use_binaries=use_binaries, trees=trees)
+   use_binaries=use_binaries, trees=trees,
+   minimize_slots=minimize_slots)
else:
atoms = [x]
if vardb is None:
@@ -663,9 +666,28 @@ def dep_zapdeps(unreduced, reduced, myroot, 
use_binaries=0, trees=None):
for choices in choice_bins:
if len(choices) < 2:
continue
-   # Prefer choices with all_installed_slots for bug #480736, and
-   # choices with a smaller number of new slots for bug #632026.
-   choices.sort(key=lambda x: (not x.all_installed_slots, 
x.new_slot_count))
+
+   sort_keys = []
+   # Prefer choices with all_installed_slots for bug #480736.
+   sort_keys.append(lambda x: not x.all_installed_slots)
+
+   if minimize_slots:
+   # Prefer choices having fewer new slots. When used with 
DNF form,
+   # this can eliminate unecessary packages that depclean 
would
+   # ultimately eliminate (see bug 632026). Only use this 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/portage/dep/

2018-01-20 Thread Zac Medico
commit: 74d0f516a346c7fb6c52a2508ca16b8949b3b65f
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Jan 21 00:00:02 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Jan 21 00:09:11 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=74d0f516

dep_zapdeps: exclude virtuals from new_slot_count (bug 645190)

Fix new_slot_count to exclude virtual packages, since they are considered
to have zero-cost. This solves an issue where the catalyst stage1 build
would unexpectedly pull in static-dev to satisfy virtual/dev-manager,
but eudev is the preferred choice.

Bug: https://bugs.gentoo.org/645190
Fixes: 9fdaf9bdbdf5 ("dep_check: use DNF to optimize overlapping virtual || 
deps (bug 632026)")
Reported-by: Ben Kohler  gmail.com>

 pym/portage/dep/dep_check.py   |  3 +-
 .../resolver/test_virtual_minimize_children.py | 61 ++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
index 7cf338819..c56f545ec 100644
--- a/pym/portage/dep/dep_check.py
+++ b/pym/portage/dep/dep_check.py
@@ -499,7 +499,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, 
trees=None):
cp_map[avail_pkg.cp] = avail_pkg
 
new_slot_count = (len(slot_map) if graph_db is None else
-   sum(not graph_db.match_pkgs(slot_atom) for slot_atom in 
slot_map))
+   sum(not graph_db.match_pkgs(slot_atom) for slot_atom in 
slot_map
+   if not slot_atom.cp.startswith("virtual/")))
 
this_choice = _dep_choice(atoms=atoms, slot_map=slot_map,
cp_map=cp_map, all_available=all_available,

diff --git a/pym/portage/tests/resolver/test_virtual_minimize_children.py 
b/pym/portage/tests/resolver/test_virtual_minimize_children.py
index 6eb0409f2..287445e58 100644
--- a/pym/portage/tests/resolver/test_virtual_minimize_children.py
+++ b/pym/portage/tests/resolver/test_virtual_minimize_children.py
@@ -226,3 +226,64 @@ class VirtualMinimizeChildrenTestCase(TestCase):
finally:
playground.debug = False
playground.cleanup()
+
+   def testVirtualDevManager(self):
+   ebuilds = {
+   'sys-fs/eudev-3.1.5': {},
+   'sys-fs/static-dev-0.1': {},
+   'sys-fs/udev-233': {},
+   'virtual/dev-manager-0': {
+   'RDEPEND': '''
+   || (
+   virtual/udev
+   sys-fs/static-dev
+   )'''
+   },
+   'virtual/udev-0': {
+   'RDEPEND': '''
+   || (
+   >=sys-fs/eudev-2.1.1
+   >=sys-fs/udev-217
+   )'''
+   },
+   }
+
+   test_cases = (
+   # Test bug 645190, where static-dev was pulled in 
instead
+   # of eudev.
+   ResolverPlaygroundTestCase(
+   [
+   'virtual/dev-manager',
+   ],
+   success=True,
+   mergelist=(
+   'sys-fs/eudev-3.1.5',
+   'virtual/udev-0',
+   'virtual/dev-manager-0',
+   ),
+   ),
+   # Test static-dev preference.
+   ResolverPlaygroundTestCase(
+   [
+   'sys-fs/static-dev',
+   'virtual/dev-manager',
+   ],
+   all_permutations=True,
+   success=True,
+   mergelist=(
+   'sys-fs/static-dev-0.1',
+   'virtual/dev-manager-0',
+   ),
+   ),
+   )
+
+   playground = ResolverPlayground(debug=False, ebuilds=ebuilds)
+
+   try:
+   for test_case in test_cases:
+   playground.run_TestCase(test_case)
+   self.assertEqual(test_case.test_success, True,
+   test_case.fail_msg)
+   finally:
+   playground.debug = False
+   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/portage/dep/

2018-01-20 Thread Zac Medico
commit: e2134e9f72a86734552bb67e9414a017cfc4ea51
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Jan 20 00:28:42 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Jan 20 23:08:42 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=e2134e9f

dep_zapdeps: prefer choices with fewer new slots (bug 645002)

Prefer choices with fewer new slots, rather than choices with the lowest
total number of slots. This fixes a case triggered by the catalyst stage1
build, where paludis was selected to satisfy perl-cleaner dependencies
because that choice happened to have a smaller number of slots:

  || (
( sys-apps/portage app-portage/portage-utils )
sys-apps/pkgcore
sys-apps/paludis
  )

Bug: https://bugs.gentoo.org/645002
Fixes: 9fdaf9bdbdf5 ("dep_check: use DNF to optimize overlapping virtual || 
deps (bug 632026)")
Tested-by: Ben Kohler  gmail.com>

 pym/portage/dep/dep_check.py   | 14 ++--
 .../resolver/test_virtual_minimize_children.py | 85 +-
 2 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
index 291626f56..7cf338819 100644
--- a/pym/portage/dep/dep_check.py
+++ b/pym/portage/dep/dep_check.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2015 Gentoo Foundation
+# Copyright 2010-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import unicode_literals
@@ -296,7 +296,7 @@ def dep_eval(deplist):
 
 class _dep_choice(SlotObject):
__slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
-   'all_installed_slots')
+   'all_installed_slots', 'new_slot_count')
 
 def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
"""
@@ -498,9 +498,13 @@ def dep_zapdeps(unreduced, reduced, myroot, 
use_binaries=0, trees=None):
if current_higher or (all_match_current and not 
all_match_previous):
cp_map[avail_pkg.cp] = avail_pkg
 
+   new_slot_count = (len(slot_map) if graph_db is None else
+   sum(not graph_db.match_pkgs(slot_atom) for slot_atom in 
slot_map))
+
this_choice = _dep_choice(atoms=atoms, slot_map=slot_map,
cp_map=cp_map, all_available=all_available,
-   all_installed_slots=False)
+   all_installed_slots=False,
+   new_slot_count=new_slot_count)
if all_available:
# The "all installed" criterion is not version or slot 
specific.
# If any version of a package is already in the graph 
then we
@@ -655,8 +659,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, 
trees=None):
if len(choices) < 2:
continue
# Prefer choices with all_installed_slots for bug #480736, and
-   # choices with a smaller number of packages for bug #632026.
-   choices.sort(key=lambda x: (not x.all_installed_slots, 
len(x.slot_map)))
+   # choices with a smaller number of new slots for bug #632026.
+   choices.sort(key=lambda x: (not x.all_installed_slots, 
x.new_slot_count))
for choice_1 in choices[1:]:
cps = set(choice_1.cp_map)
for choice_2 in choices:

diff --git a/pym/portage/tests/resolver/test_virtual_minimize_children.py 
b/pym/portage/tests/resolver/test_virtual_minimize_children.py
index 83ae34e77..6eb0409f2 100644
--- a/pym/portage/tests/resolver/test_virtual_minimize_children.py
+++ b/pym/portage/tests/resolver/test_virtual_minimize_children.py
@@ -1,4 +1,4 @@
-# Copyright 2017 Gentoo Foundation
+# Copyright 2017-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -143,3 +143,86 @@ class VirtualMinimizeChildrenTestCase(TestCase):
finally:
playground.debug = False
playground.cleanup()
+
+   def testVirtualPackageManager(self):
+   ebuilds = {
+   'app-admin/perl-cleaner-2.25': {
+   'RDEPEND': '''
+   || (
+   ( sys-apps/portage 
app-portage/portage-utils )
+   sys-apps/pkgcore
+   sys-apps/paludis
+   )'''
+   },
+   'app-portage/portage-utils-0.64': {},
+   'sys-apps/paludis-2.6.0': {},
+   'sys-apps/portage-2.3.19-r1': {},
+   'virtual/package-manager-0': {
+   'RDEPEND': '''
+  

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/portage/dep/

2018-01-11 Thread Zac Medico
commit: 86ba22da7a2f34848cdb5a6f1090c22c264e577e
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Jan  9 03:34:22 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Jan 11 19:23:34 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=86ba22da

dep_zapdeps: install new package, allow upgrade (bug 643974)

Prefer to install a new package in order to allow upgrade of an
installed package. This generalizes the code from bug 635540 so
that it both allows desirable upgrades and prevents unwanted
downgrades.

Fixes: 7c58e3737616 ("dep_zapdeps: install new package, avoid downgrade (bug 
635540)")
Bug: https://bugs.gentoo.org/643974
Reviewed-by: Alec Warner  gentoo.org>

 pym/portage/dep/dep_check.py   |  11 +--
 .../tests/resolver/test_or_upgrade_installed.py| 101 +
 2 files changed, 106 insertions(+), 6 deletions(-)

diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
index 2bb9dc339..291626f56 100644
--- a/pym/portage/dep/dep_check.py
+++ b/pym/portage/dep/dep_check.py
@@ -366,10 +366,8 @@ def dep_zapdeps(unreduced, reduced, myroot, 
use_binaries=0, trees=None):
want_update_pkg = trees[myroot].get("want_update_pkg")
downgrade_probe = trees[myroot].get("downgrade_probe")
vardb = None
-   vardb_match_pkgs = None
if "vartree" in trees[myroot]:
vardb = trees[myroot]["vartree"].dbapi
-   vardb_match_pkgs = getattr(vardb, 'match_pkgs', None)
if use_binaries:
mydbapi = trees[myroot]["bintree"].dbapi
else:
@@ -465,10 +463,11 @@ def dep_zapdeps(unreduced, reduced, myroot, 
use_binaries=0, trees=None):
avail_pkg = avail_pkg_use
avail_slot = Atom("%s:%s" % (atom.cp, 
avail_pkg.slot))
 
-   if vardb_match_pkgs is not None and downgrade_probe is 
not None:
-   inst_pkg = vardb_match_pkgs(avail_slot)
-   if (inst_pkg and avail_pkg < inst_pkg[-1] and
-   not downgrade_probe(inst_pkg[-1])):
+   if downgrade_probe is not None:
+   highest_in_slot = mydbapi_match_pkgs(avail_slot)
+   if (avail_pkg and highest_in_slot and
+   avail_pkg < highest_in_slot[-1] and
+   not downgrade_probe(avail_pkg)):
installed_downgrade = True
 
slot_map[avail_slot] = avail_pkg

diff --git a/pym/portage/tests/resolver/test_or_upgrade_installed.py 
b/pym/portage/tests/resolver/test_or_upgrade_installed.py
new file mode 100644
index 0..6e01d321d
--- /dev/null
+++ b/pym/portage/tests/resolver/test_or_upgrade_installed.py
@@ -0,0 +1,101 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+   ResolverPlayground,
+   ResolverPlaygroundTestCase,
+)
+
+class OrUpgradeInstalledTestCase(TestCase):
+
+   def testOrUpgradeInstalled(self):
+   ebuilds = {
+   'net-misc/foo-1': {
+   'EAPI': '6',
+   'RDEPEND': '|| ( sys-libs/glibc[rpc(-)]  
net-libs/libtirpc )'
+   },
+   'net-libs/libtirpc-1': {
+   'EAPI': '6',
+   },
+   'sys-libs/glibc-2.26': {
+   'EAPI': '6',
+   'IUSE': ''
+   },
+   'sys-libs/glibc-2.24': {
+   'EAPI': '6',
+   'IUSE': '+rpc'
+   },
+   }
+
+   installed = {
+   'sys-libs/glibc-2.24': {
+   'EAPI': '6',
+   'IUSE': '+rpc',
+   'USE': 'rpc',
+   },
+   }
+
+   world = ['sys-libs/glibc']
+
+   test_cases = (
+   # Test bug 643974, where we need to install libtirpc
+   # in order to upgrade glibc.
+   ResolverPlaygroundTestCase(
+   ['net-misc/foo', '@world'],
+   options={'--update': True, '--deep': True},
+   success=True,
+   ambiguous_merge_order=True,
+   mergelist=(
+   (
+   'net-libs/libtirpc-1',
+   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/bin/

2018-01-09 Thread Zac Medico
commit: c040200175b33e637a4807278925e92cf61eb725
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Jan  9 20:28:27 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Jan  9 20:41:58 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=c0402001

testDoInsOption: fix timestamp comparison to work in travis

Use integer comparison in order to avoid failures like the
following:

AssertionError: 1515530127.479328 != 1515530127.479327

 pym/portage/tests/bin/test_doins.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/bin/test_doins.py 
b/pym/portage/tests/bin/test_doins.py
index 9b6c55d85..e3d5153b3 100644
--- a/pym/portage/tests/bin/test_doins.py
+++ b/pym/portage/tests/bin/test_doins.py
@@ -45,8 +45,9 @@ class DoIns(setup_env.BinTestCase):
st = os.lstat(env['D'] + '/test')
if stat.S_IMODE(st.st_mode) != 0o644:
raise tests.TestCase.failureException
-   if os.stat(os.path.join(env['S'], 'test')).st_mtime != 
st.st_mtime:
-   raise tests.TestCase.failureException
+   self.assertEqual(
+   os.stat(os.path.join(env['S'], 
'test'))[stat.ST_MTIME],
+   st[stat.ST_MTIME])
finally:
self.cleanup()
 



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/

2017-12-15 Thread Zac Medico
commit: b47daf4d12ad54668c75f53661da4b252e665c22
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Dec 16 03:15:58 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Dec 16 03:16:30 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=b47daf4d

MultirepoTestCase: add missing EAPI definitions needed for slot deps

 pym/portage/tests/resolver/test_multirepo.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/resolver/test_multirepo.py 
b/pym/portage/tests/resolver/test_multirepo.py
index 2b1a6d073..dabec6af9 100644
--- a/pym/portage/tests/resolver/test_multirepo.py
+++ b/pym/portage/tests/resolver/test_multirepo.py
@@ -42,7 +42,7 @@ class MultirepoTestCase(TestCase):
}
 
installed = {
-   "dev-libs/H-1": { "RDEPEND" : "|| ( dev-libs/I:2 
dev-libs/I:1 )"},
+   "dev-libs/H-1": { "RDEPEND" : "|| ( dev-libs/I:2 
dev-libs/I:1 )", "EAPI" : "3" },
"dev-libs/I-2::repo1": {"SLOT" : "2"},
"dev-libs/K-1::repo1": { },
}
@@ -277,7 +277,7 @@ class MultirepoTestCase(TestCase):
}
 
installed = {
-   "dev-libs/J-1": { "RDEPEND" : "|| ( dev-libs/I:2 
dev-libs/I:1 )"},
+   "dev-libs/J-1": { "RDEPEND" : "|| ( dev-libs/I:2 
dev-libs/I:1 )", "EAPI" : "3" },
"dev-libs/I-2::repo1": {"SLOT" : "2"},
}
 



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/sync/, pym/portage/sync/modules/rsync/, ...

2017-11-21 Thread Zac Medico
commit: 7d4612795d1d36d4284ad7bcbff5b88e3c74e993
Author: Ilya Tumaykin  gmail  com>
AuthorDate: Mon May 23 13:43:48 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Nov 21 20:41:43 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=7d461279

Fix sync_uri parsing for paths beginning with file://

Portage allows file URLs, i.e. paths beginning with 'file://',
in sync_uri. According to RFC-1738 [1] a file URL must take the form
'file:///foo/bar' or 'file:///foo/bar', when  is omitted
(in this case localhost is assumed).

Portage incorrectly parses file URLs because it leaves the second slash
from the 'file://' prefix as a part of the URL. Additionally test suite
incorrectly uses file URLs beginning with 'file:/' instead of 'file://'.

This patch adjusts string offset so that file URLs are parsed correctly:

>>> sync_uri='/foo/bar/baz'
>>> ('file://' + sync_uri)[6:]
'//foo/bar/baz'
>>> ('file://' + sync_uri)[6:] == sync_uri
False
>>> ('file://' + sync_uri)[7:]
'/foo/bar/baz'
>>> ('file://' + sync_uri)[7:] == sync_uri
True

Additionally test suite is updated to use file URLs of the form
'file:///foo/bar' as required by the aforementioned RFC.

[1]: https://tools.ietf.org/html/rfc1738#section-3.10

Closes: https://github.com/gentoo/portage/pull/28

 pym/portage/sync/modules/git/git.py   | 2 +-
 pym/portage/sync/modules/rsync/rsync.py   | 2 +-
 pym/portage/tests/sync/test_sync_local.py | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/pym/portage/sync/modules/git/git.py 
b/pym/portage/sync/modules/git/git.py
index 8068149c7..8b4cab273 100644
--- a/pym/portage/sync/modules/git/git.py
+++ b/pym/portage/sync/modules/git/git.py
@@ -47,7 +47,7 @@ class GitSync(NewBase):
 
sync_uri = self.repo.sync_uri
if sync_uri.startswith("file://"):
-   sync_uri = sync_uri[6:]
+   sync_uri = sync_uri[7:]
 
git_cmd_opts = ""
if self.repo.module_specific_options.get('sync-git-env'):

diff --git a/pym/portage/sync/modules/rsync/rsync.py 
b/pym/portage/sync/modules/rsync/rsync.py
index 01e4e5924..c80641ba3 100644
--- a/pym/portage/sync/modules/rsync/rsync.py
+++ b/pym/portage/sync/modules/rsync/rsync.py
@@ -111,7 +111,7 @@ class RsyncSync(NewBase):
 
if syncuri.startswith("file://"):
self.proto = "file"
-   dosyncuri = syncuri[6:]
+   dosyncuri = syncuri[7:]
is_synced, exitcode, updatecache_flg = self._do_rsync(
dosyncuri, timestamp, opts)
self._process_exitcode(exitcode, dosyncuri, out, 1)

diff --git a/pym/portage/tests/sync/test_sync_local.py 
b/pym/portage/tests/sync/test_sync_local.py
index 1d3856265..010c8f887 100644
--- a/pym/portage/tests/sync/test_sync_local.py
+++ b/pym/portage/tests/sync/test_sync_local.py
@@ -41,7 +41,7 @@ class SyncLocalTestCase(TestCase):
[test_repo]
location = %(EPREFIX)s/var/repositories/test_repo
sync-type = %(sync-type)s
-   sync-uri = 
file:/%(EPREFIX)s/var/repositories/test_repo_sync
+   sync-uri = 
file://%(EPREFIX)s/var/repositories/test_repo_sync
auto-sync = %(auto-sync)s
%(repo_extra_keys)s
""")



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/dep/, pym/portage/dep/, pym/portage/tests/resolver/

2017-11-13 Thread Zac Medico
commit: 9fdaf9bdbdf500b7120aa95cb2ca421b931e6cea
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Nov  5 22:21:43 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Nov 14 03:35:19 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=9fdaf9bd

dep_check: use DNF to optimize overlapping virtual || deps (bug 632026)

Deps like these:

  || ( foo bar ) || ( bar baz )

Translate to disjunctive normal form (DNF):

  || ( ( foo bar ) ( foo baz ) ( bar bar ) ( bar baz ) )

Using DNF, if none of the packages are currently installed,
then the ( bar bar ) choice will be automatically preferred
since it is satisfied by the fewest number of packages.
If the ( foo baz ) choice is already satisfied, then that
choice will be preferred instead.

Since DNF results in exponential explosion of the formula,
only use DNF for the parts of the dependencies that have
overlapping atoms.

In order to simplify the implementation of the dnf_convert
function, this patch also fixes _expand_new_virtuals to
normalize results in the same way as use_reduce (with no
redundant nested lists).

Bug: https://bugs.gentoo.org/632026
Reviewed-by: Manuel Rüger  gentoo.org>
Reviewed-by: Alec Warner  gentoo.org>

 pym/portage/dep/_dnf.py|  90 +
 pym/portage/dep/dep_check.py   | 136 ++-
 pym/portage/tests/dep/test_dnf_convert.py  |  48 +++
 pym/portage/tests/dep/test_overlap_dnf.py  |  28 
 .../resolver/test_virtual_minimize_children.py | 145 +
 5 files changed, 440 insertions(+), 7 deletions(-)

diff --git a/pym/portage/dep/_dnf.py b/pym/portage/dep/_dnf.py
new file mode 100644
index 0..59657fd6a
--- /dev/null
+++ b/pym/portage/dep/_dnf.py
@@ -0,0 +1,90 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import unicode_literals
+
+import itertools
+
+
+def dnf_convert(dep_struct):
+   """
+   Convert dep_struct to disjunctive normal form (DNF), where dep_struct
+   is either a conjunction or disjunction of the form produced by
+   use_reduce(opconvert=True).
+   """
+   # Normalize input to have a top-level conjunction.
+   if isinstance(dep_struct, list):
+   if dep_struct and dep_struct[0] == '||':
+   dep_struct = [dep_struct]
+   else:
+   dep_struct = [dep_struct]
+
+   conjunction = []
+   disjunctions = []
+
+   for x in dep_struct:
+   if isinstance (x, list):
+   assert x and x[0] == '||', \
+   'Normalization error, nested conjunction found 
in %s' % (dep_struct,)
+   if any(isinstance(element, list) for element in x):
+   x_dnf = ['||']
+   for element in x[1:]:
+   if isinstance(element, list):
+   # Due to normalization, a 
disjunction must not be
+   # nested directly in another 
disjunction, so this
+   # must be a conjunction.
+   assert element, 'Normalization 
error, empty conjunction found in %s' % (x,)
+   assert element[0] != '||', \
+   'Normalization error, 
nested disjunction found in %s' % (x,)
+   element = dnf_convert(element)
+   if 
contains_disjunction(element):
+   assert (len(element) == 
1 and
+   element[0] and 
element[0][0] == '||'), \
+   'Normalization 
error, expected single disjunction in %s' % (element,)
+   
x_dnf.extend(element[0][1:])
+   else:
+   x_dnf.append(element)
+   else:
+   x_dnf.append(element)
+   x = x_dnf
+   disjunctions.append(x)
+   else:
+   conjunction.append(x)
+
+   if disjunctions and (conjunction or len(disjunctions) > 1):
+   dnf_form = ['||']
+   for x in itertools.product(*[x[1:] for x in disjunctions]):
+   normalized = conjunction[:]
+   for element in x:
+   if isinstance(element, list):
+   normalized.extend(element)
+ 

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

2017-09-29 Thread Zac Medico
commit: 5a65670ec2b0850c278b85c6417c20d8a4ca7734
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Sep 29 07:02:27 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri Sep 29 17:22:27 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=5a65670e

_solve_..slot_conflicts: make "forced" set recursive (bug 632210)

When the slot conflict solver decides that it is "forced"
to choose a particular package, recursively force the
dependencies as well. Prior to this fix, substitution of
@world in the arguments for SlotConflictMaskUpdateTestCase
caused the test to fail because the solver removed
boost-build-1.53.0 from the graph event though it had
added the parent boost-1.53.0 package to the "forced"
set.

X-Gentoo-bug: 632210
X-Gentoo-bug-url: https://bugs.gentoo.org/632210
Acked-by: Brian Dolbec  gentoo.org>

 pym/_emerge/depgraph.py | 13 +
 pym/portage/tests/resolver/test_slot_conflict_update.py |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 785c036b8..3b81c5c76 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1457,6 +1457,19 @@ class depgraph(object):
 
# Remove 'non_conflict_node' and or_tuples from 'forced'.
forced = set(pkg for pkg in forced if isinstance(pkg, Package))
+
+   # Add dependendencies of forced packages.
+   stack = list(forced)
+   traversed = set()
+   while stack:
+   pkg = stack.pop()
+   traversed.add(pkg)
+   for child in conflict_graph.child_nodes(pkg):
+   if (isinstance(child, Package) and
+   child not in traversed):
+   forced.add(child)
+   stack.append(child)
+
non_forced = set(pkg for pkg in conflict_pkgs if pkg not in 
forced)
 
if debug:

diff --git a/pym/portage/tests/resolver/test_slot_conflict_update.py 
b/pym/portage/tests/resolver/test_slot_conflict_update.py
index 331e5788b..f251d01f1 100644
--- a/pym/portage/tests/resolver/test_slot_conflict_update.py
+++ b/pym/portage/tests/resolver/test_slot_conflict_update.py
@@ -80,7 +80,7 @@ class SlotConflictUpdateTestCase(TestCase):
# this behavior makes SlotConflictMaskUpdateTestCase
# fail.
ResolverPlaygroundTestCase(
-   world,
+   ['@world'],
all_permutations = True,
options = {"--update": True, "--deep": True},
success = True,



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

2017-09-11 Thread Zac Medico
commit: 504f66b0e25281e4465ebeceb799c3e54ff2b884
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Sep 11 21:01:39 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Sep 11 21:07:30 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=504f66b0

AsynchronousLock: allow missing dummy_threading for Python 3.7

Python 3.7 does not support thread-less builds.

Reported-by: Arfrever Frehtes Taifersar Arahesis  Apache.Org>
See: https://bugs.python.org/issue31370
X-Gentoo-bug: 630730
X-Gentoo-bug-url: https://bugs.gentoo.org/630730

 pym/_emerge/AsynchronousLock.py   | 6 +-
 pym/portage/tests/locks/test_asynchronous_lock.py | 8 +++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/pym/_emerge/AsynchronousLock.py b/pym/_emerge/AsynchronousLock.py
index 6a32d2d40..fb0c2b30d 100644
--- a/pym/_emerge/AsynchronousLock.py
+++ b/pym/_emerge/AsynchronousLock.py
@@ -1,13 +1,17 @@
 # Copyright 2010-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import dummy_threading
 import fcntl
 import errno
 import logging
 import sys
 
 try:
+   import dummy_threading
+except ImportError:
+   dummy_threading = None
+
+try:
import threading
 except ImportError:
threading = dummy_threading

diff --git a/pym/portage/tests/locks/test_asynchronous_lock.py 
b/pym/portage/tests/locks/test_asynchronous_lock.py
index ab67242d5..6493b6da6 100644
--- a/pym/portage/tests/locks/test_asynchronous_lock.py
+++ b/pym/portage/tests/locks/test_asynchronous_lock.py
@@ -5,6 +5,11 @@ import itertools
 import signal
 import tempfile
 
+try:
+   import dummy_threading
+except ImportError:
+   dummy_threading = None
+
 from portage import os
 from portage import shutil
 from portage.tests import TestCase
@@ -20,7 +25,8 @@ class AsynchronousLockTestCase(TestCase):
path = os.path.join(tempdir, 'lock_me')
for force_async, async_unlock in itertools.product(
(True, False), repeat=2):
-   for force_dummy in (True, False):
+   for force_dummy in ((False,) if dummy_threading 
is None
+   else (True, False)):
async_lock = AsynchronousLock(path=path,
scheduler=scheduler, 
_force_async=force_async,
_force_thread=True,



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

2017-08-12 Thread Zac Medico
commit: 46fac6698e5c73fda964819b508f1fe9dd341393
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Aug 12 17:16:46 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Aug 12 23:48:14 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=46fac669

emerge: add --autounmask-keep-keywords option (bug 622480)

The option prevents --autounmask from making changes to
package.accept_keywords. This option does not imply
--autounmask-keep-masks, so --autounmask is still allowed
to create package.unmask changes unless the
--autounmask-keep-masks is also specified.

X-Gentoo-bug: 622480
X-Gentoo-bug-url: https://bugs.gentoo.org/622480
Reviewed-by: Manuel Rüger  gentoo.org>

 man/emerge.1   |  7 +++
 pym/_emerge/depgraph.py| 12 ++--
 pym/_emerge/main.py|  9 +++
 .../resolver/test_autounmask_keep_keywords.py  | 72 ++
 4 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/man/emerge.1 b/man/emerge.1
index ffb453efb..12a0db166 100644
--- a/man/emerge.1
+++ b/man/emerge.1
@@ -395,6 +395,13 @@ using the \'=\' operator will be written. With this
 option, \'>=\' operators will be used whenever possible.
 USE and license changes always use the latter behavior.
 .TP
+.BR "\-\-autounmask\-keep\-keywords [ y | n ]"
+If \-\-autounmask is enabled, no package.accept_keywords changes will
+be created. This leads to unsatisfied dependencies if any keyword
+changes are required. This option does not imply \-\-autounmask\-keep\-masks,
+so \-\-autounmask is still allowed to create package.unmask changes unless
+the \-\-autounmask\-keep\-masks is also specified.
+.TP
 .BR "\-\-autounmask\-keep\-masks [ y | n ]"
 If \-\-autounmask is enabled, no package.unmask or ** keyword changes
 will be created. This leads to unsatisfied dependencies if

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index abe2cb1bd..b4fc5f297 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5707,6 +5707,7 @@ class depgraph(object):
if self._dynamic_config._autounmask is not True:
return
 
+   autounmask_keep_keywords = 
self._frozen_config.myopts.get("--autounmask-keep-keywords", "n") != "n"
autounmask_keep_masks = 
self._frozen_config.myopts.get("--autounmask-keep-masks", "n") != "n"
autounmask_level = self._AutounmaskLevel()
 
@@ -5716,14 +5717,16 @@ class depgraph(object):
autounmask_level.allow_license_changes = True
yield autounmask_level
 
-   autounmask_level.allow_unstable_keywords = True
-   yield autounmask_level
-
-   if not autounmask_keep_masks:
+   if not autounmask_keep_keywords:
+   autounmask_level.allow_unstable_keywords = True
+   yield autounmask_level
 
+   if not (autounmask_keep_keywords or autounmask_keep_masks):
+   autounmask_level.allow_unstable_keywords = True
autounmask_level.allow_missing_keywords = True
yield autounmask_level
 
+   if not autounmask_keep_masks:
# 4. USE + license + masks
# Try to respect keywords while discarding
# package.mask (see bug #463394).
@@ -5732,6 +5735,7 @@ class depgraph(object):
autounmask_level.allow_unmasks = True
yield autounmask_level
 
+   if not (autounmask_keep_keywords or autounmask_keep_masks):
autounmask_level.allow_unstable_keywords = True
 
for missing_keyword, unmask in ((False, True), (True, 
True)):

diff --git a/pym/_emerge/main.py b/pym/_emerge/main.py
index 2132aa63c..d3a415b91 100644
--- a/pym/_emerge/main.py
+++ b/pym/_emerge/main.py
@@ -129,6 +129,7 @@ def insert_optional_args(args):
'--autounmask'   : y_or_n,
'--autounmask-continue'  : y_or_n,
'--autounmask-only'  : y_or_n,
+   '--autounmask-keep-keywords' : y_or_n,
'--autounmask-keep-masks': y_or_n,
'--autounmask-unrestricted-atoms' : y_or_n,
'--autounmask-write' : y_or_n,
@@ -348,6 +349,11 @@ def parse_opts(tmpcmdline, silent=False):
"choices" : true_y_or_n
},
 
+   "--autounmask-keep-keywords": {
+   "help": "don't add package.accept_keywords entries",
+   "choices" : true_y_or_n
+   },
+
"--autounmask-keep-masks": {
"help": "don't add package.unmask entries",
"choices" : true_y_or_n
@@ -797,6 +803,9 @@ def parse_opts(tmpcmdline, silent=False):
if 

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

2017-06-01 Thread Zac Medico
commit: 60af7e2696b96b47b0cd9e70caabd10546206b8b
Author: Zac Medico  gentoo  org>
AuthorDate: Mon May 29 08:22:40 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Fri Jun  2 05:38:02 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=60af7e26

depgraph: prune unnecessary rebuilds for --autounmask-continue (bug 619626)

When there are autounmask USE changes, avoid unnecessary rebuilds
by accepting binary packages that were rejected due to the preexisting
USE configuration. This reuses the prune_rebuilds backtracker support
which was added for bug 439688.

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

 pym/_emerge/depgraph.py| 96 ++
 .../tests/resolver/test_autounmask_binpkg_use.py   | 64 +++
 2 files changed, 142 insertions(+), 18 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 2dc432431..abe2cb1bd 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -5,6 +5,7 @@ from __future__ import division, print_function, 
unicode_literals
 
 import collections
 import errno
+import functools
 import io
 import logging
 import stat
@@ -856,17 +857,11 @@ class depgraph(object):
for parent in 
self._forced_rebuilds[root][child]:
writemsg_stdout("%s\n" % (parent,), 
noiselevel=-1)
 
-   def _show_ignored_binaries(self):
+   def _eliminate_ignored_binaries(self):
"""
-   Show binaries that have been ignored because their USE didn't
-   match the user's config.
+   Eliminate any package from self._dynamic_config.ignored_binaries
+   for which a more optimal alternative exists.
"""
-   if not self._dynamic_config.ignored_binaries \
-   or '--quiet' in self._frozen_config.myopts:
-   return
-
-   ignored_binaries = {}
-
for pkg in list(self._dynamic_config.ignored_binaries):
 
for selected_pkg in 
self._dynamic_config._package_tracker.match(
@@ -894,10 +889,67 @@ class depgraph(object):

self._dynamic_config.ignored_binaries.pop(pkg)
break
 
-   else:
-   for reason, info in self._dynamic_config.\
-   ignored_binaries[pkg].items():
-   ignored_binaries.setdefault(reason, 
{})[pkg] = info
+   def _ignored_binaries_autounmask_backtrack(self):
+   """
+   Check if there are ignored binaries that would have been
+   accepted with the current autounmask USE changes.
+
+   @rtype: bool
+   @return: True if there are unnecessary rebuilds that
+   can be avoided by backtracking
+   """
+   if not all([
+   self._dynamic_config._allow_backtracking,
+   self._dynamic_config._needed_use_config_changes,
+   self._dynamic_config.ignored_binaries]):
+   return False
+
+   self._eliminate_ignored_binaries()
+
+   # _eliminate_ignored_binaries may have eliminated
+   # all of the ignored binaries
+   if not self._dynamic_config.ignored_binaries:
+   return False
+
+   use_changes = collections.defaultdict(
+   functools.partial(collections.defaultdict, dict))
+   for pkg, (new_use, changes) in 
self._dynamic_config._needed_use_config_changes.items():
+   if pkg in self._dynamic_config.digraph:
+   use_changes[pkg.root][pkg.slot_atom] = (pkg, 
new_use)
+
+   for pkg in self._dynamic_config.ignored_binaries:
+   selected_pkg, new_use = use_changes[pkg.root].get(
+   pkg.slot_atom, (None, None))
+   if new_use is None:
+   continue
+
+   if new_use != pkg.use.enabled:
+   continue
+
+   if selected_pkg > pkg:
+   continue
+
+   return True
+
+   return False
+
+   def _show_ignored_binaries(self):
+   """
+   Show binaries that have been ignored because their USE didn't
+   match the user's config.
+   """
+   if not self._dynamic_config.ignored_binaries \
+   or '--quiet' in self._frozen_config.myopts:
+   return
+
+   self._eliminate_ignored_binaries()
+
+   

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

2017-05-29 Thread Zac Medico
commit: 565ceb1bebc83ec1a5572a672e2e08ea7d91e7a8
Author: Zac Medico  gentoo  org>
AuthorDate: Sun May 28 08:55:27 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue May 30 03:30:50 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=565ceb1b

emerge: warn for --autounmask-continue with --autounmask=n (bug 619612)

In order to avoid possible confusion when the user has specified
--autounmask-continue and EMERGE_DEFAULT_OPTS contains
--autounmask=n, display a warning message as follows:

 * --autounmask-continue has been disabled by --autounmask=n

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

 pym/_emerge/actions.py  | 6 ++
 pym/portage/tests/emerge/test_simple.py | 5 -
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
index 1bc20c3ed..c8a62fb01 100644
--- a/pym/_emerge/actions.py
+++ b/pym/_emerge/actions.py
@@ -2862,6 +2862,12 @@ def run_action(emerge_config):
adjust_configs(emerge_config.opts, emerge_config.trees)
apply_priorities(emerge_config.target_config.settings)
 
+   if ("--autounmask-continue" in emerge_config.opts and
+   emerge_config.opts.get("--autounmask") == "n"):
+   writemsg_level(
+   " %s --autounmask-continue has been disabled by 
--autounmask=n\n" %
+   warn("*"), level=logging.WARNING, noiselevel=-1)
+
for fmt in 
emerge_config.target_config.settings.get("PORTAGE_BINPKG_FORMAT", "").split():
if not fmt in portage.const.SUPPORTED_BINPKG_FORMATS:
if "--pkg-format" in emerge_config.opts:

diff --git a/pym/portage/tests/emerge/test_simple.py 
b/pym/portage/tests/emerge/test_simple.py
index 5930f6cc8..f99c77927 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -311,7 +311,10 @@ pkg_preinst() {
emerge_cmd + ("--unmerge", "--quiet", "dev-libs/A"),
emerge_cmd + ("-C", "--quiet", "dev-libs/B"),
 
-   emerge_cmd + ("--autounmask-continue", "dev-libs/C",),
+   # If EMERGE_DEFAULT_OPTS contains --autounmask=n, then 
--autounmask
+   # must be specified with --autounmask-continue.
+   ({"EMERGE_DEFAULT_OPTS" : "--autounmask=n"},) + \
+   emerge_cmd + ("--autounmask", 
"--autounmask-continue", "dev-libs/C",),
# Verify that the above --autounmask-continue command 
caused
# USE=flag to be applied correctly to dev-libs/D.
portageq_cmd + ("match", eroot, "dev-libs/D[flag]"),



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/, pym/portage/util/

2017-04-20 Thread Zac Medico
commit: c8c038fd4c201a582c420004b5ff759f28fe626b
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Apr 19 04:39:31 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Apr 20 19:39:00 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=c8c038fd

digraph: add update and clear methods

Also, optimize the add method to avoid creating a lot of
duplicate priorities when called by the update method.

Acked-by: Brian Dolbec  gentoo.org>

 pym/portage/tests/util/test_digraph.py |  4 +++-
 pym/portage/util/digraph.py| 26 --
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/pym/portage/tests/util/test_digraph.py 
b/pym/portage/tests/util/test_digraph.py
index f519536d3..01e075c99 100644
--- a/pym/portage/tests/util/test_digraph.py
+++ b/pym/portage/tests/util/test_digraph.py
@@ -88,7 +88,9 @@ class DigraphTest(TestCase):
g.add("D", "A", 2)
 
f = g.clone()
-   for x in g, f:
+   h = digraph()
+   h.update(f)
+   for x in g, f, h:
self.assertEqual(bool(x), True)
self.assertEqual(x.contains("A"), True)
self.assertEqual(x.firstzero(), None)

diff --git a/pym/portage/util/digraph.py b/pym/portage/util/digraph.py
index 99b24fa1d..ba0e81c07 100644
--- a/pym/portage/util/digraph.py
+++ b/pym/portage/util/digraph.py
@@ -44,8 +44,10 @@ class digraph(object):
priorities = []
self.nodes[node][1][parent] = priorities
self.nodes[parent][0][node] = priorities
-   priorities.append(priority)
-   priorities.sort()
+
+   if not priorities or priorities[-1] is not priority:
+   priorities.append(priority)
+   priorities.sort()
 
def discard(self, node):
"""
@@ -73,6 +75,26 @@ class digraph(object):
del self.nodes[node]
self.order.remove(node)
 
+   def update(self, other):
+   """
+   Add all nodes and edges from another digraph instance.
+   """
+   for node in other.order:
+   children, parents, node = other.nodes[node]
+   if parents:
+   for parent, priorities in parents.items():
+   for priority in priorities:
+   self.add(node, parent, 
priority=priority)
+   else:
+   self.add(node, None)
+
+   def clear(self):
+   """
+   Remove all nodes and edges.
+   """
+   self.nodes.clear()
+   del self.order[:]
+
def difference_update(self, t):
"""
Remove all given nodes from node_set. This is more efficient



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

2017-04-03 Thread Zac Medico
commit: 916a0733c7201b7a8b22f5262bd5be8cbc8992a6
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Apr  2 20:50:09 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Apr  3 20:07:59 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=916a0733

AsynchronousLock: add async_unlock method (bug 614108)

Add an async_unlock method, in order to avoid event loop
recursion which is incompatible with asyncio.

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

 pym/_emerge/AsynchronousLock.py   | 89 +--
 pym/portage/tests/locks/test_asynchronous_lock.py | 15 +++-
 2 files changed, 92 insertions(+), 12 deletions(-)

diff --git a/pym/_emerge/AsynchronousLock.py b/pym/_emerge/AsynchronousLock.py
index c0b9b26dc..6a32d2d40 100644
--- a/pym/_emerge/AsynchronousLock.py
+++ b/pym/_emerge/AsynchronousLock.py
@@ -35,7 +35,7 @@ class AsynchronousLock(AsynchronousTask):
 
__slots__ = ('path', 'scheduler',) + \
('_imp', '_force_async', '_force_dummy', '_force_process', \
-   '_force_thread')
+   '_force_thread', '_unlock_future')
 
_use_process_by_default = True
 
@@ -84,6 +84,11 @@ class AsynchronousLock(AsynchronousTask):
return self.returncode
 
def unlock(self):
+   """
+   This method is deprecated in favor of async_unlock, since 
waiting
+   for the child process to respond can trigger event loop 
recursion
+   which is incompatible with asyncio.
+   """
if self._imp is None:
raise AssertionError('not locked')
if isinstance(self._imp, (_LockProcess, _LockThread)):
@@ -92,6 +97,28 @@ class AsynchronousLock(AsynchronousTask):
unlockfile(self._imp)
self._imp = None
 
+   def async_unlock(self):
+   """
+   Release the lock asynchronously. Release notification is 
available
+   via the add_done_callback method of the returned Future 
instance.
+
+   @returns: Future, result is None
+   """
+   if self._imp is None:
+   raise AssertionError('not locked')
+   if self._unlock_future is not None:
+   raise AssertionError("already unlocked")
+   if isinstance(self._imp, (_LockProcess, _LockThread)):
+   unlock_future = self._imp.async_unlock()
+   else:
+   unlockfile(self._imp)
+   unlock_future = self.scheduler.create_future()
+   self.scheduler.call_soon(unlock_future.set_result, None)
+   self._imp = None
+   self._unlock_future = unlock_future
+   return unlock_future
+
+
 class _LockThread(AbstractPollTask):
"""
This uses the portage.locks module to acquire a lock asynchronously,
@@ -105,7 +132,7 @@ class _LockThread(AbstractPollTask):
"""
 
__slots__ = ('path',) + \
-   ('_force_dummy', '_lock_obj', '_thread',)
+   ('_force_dummy', '_lock_obj', '_thread', '_unlock_future')
 
def _start(self):
self._registered = True
@@ -132,13 +159,35 @@ class _LockThread(AbstractPollTask):
pass
 
def unlock(self):
+   """
+   This method is deprecated in favor of async_unlock, for 
compatibility
+   with _LockProcess.
+   """
+   self._unlock()
+   self._unlock_future.set_result(None)
+
+   def _unlock(self):
if self._lock_obj is None:
raise AssertionError('not locked')
if self.returncode is None:
raise AssertionError('lock not acquired yet')
+   if self._unlock_future is not None:
+   raise AssertionError("already unlocked")
+   self._unlock_future = self.scheduler.create_future()
unlockfile(self._lock_obj)
self._lock_obj = None
 
+   def async_unlock(self):
+   """
+   Release the lock asynchronously. Release notification is 
available
+   via the add_done_callback method of the returned Future 
instance.
+
+   @returns: Future, result is None
+   """
+   self._unlock()
+   self.scheduler.call_soon(self._unlock_future.set_result, None)
+   return self._unlock_future
+
def _unregister(self):
self._registered = False
 
@@ -156,7 +205,8 @@ class _LockProcess(AbstractPollTask):
"""
 
__slots__ = ('path',) + \
-   ('_acquired', '_kill_test', '_proc', '_files', '_reg_id', 
'_unlocked')
+   ('_acquired', 

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

2017-03-31 Thread Zac Medico
commit: a83bb83909c5a6ac232c8eb5931b28027f4175af
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Apr  1 03:53:03 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Apr  1 05:46:26 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=a83bb839

depgraph: trigger slot operator rebuilds via _complete_graph (bug 614390)

Fix _complete_graph to trigger rebuilds of parent packages when they
pull in installed packages that had already been scheduled for rebuild
by the previous calculation.

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

 pym/_emerge/depgraph.py|  15 +++
 .../resolver/test_slot_operator_complete_graph.py  | 141 +
 2 files changed, 156 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 04e724d8d..8a614c495 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6649,6 +6649,21 @@ class depgraph(object):
# will be appropriately reported as a slot 
collision
# (possibly solvable via backtracking).
pkg = matches[-1] # highest match
+
+   if (self._dynamic_config._allow_backtracking and
+   not self._want_installed_pkg(pkg) and 
(dep.atom.soname or (
+   dep.atom.package and 
dep.atom.slot_operator_built))):
+   # If pkg was already scheduled for 
rebuild by the previous
+   # calculation, then pulling in the 
installed instance will
+   # trigger a slot conflict that may go 
unsolved. Therefore,
+   # trigger a rebuild of the parent if 
appropriate.
+   dep.child = pkg
+   new_dep = 
self._slot_operator_update_probe(dep)
+   if new_dep is not None:
+   
self._slot_operator_update_backtrack(
+   dep, new_dep=new_dep)
+   continue
+
if not self._add_pkg(pkg, dep):
return 0
if not 
self._create_graph(allow_unsatisfied=True):

diff --git a/pym/portage/tests/resolver/test_slot_operator_complete_graph.py 
b/pym/portage/tests/resolver/test_slot_operator_complete_graph.py
new file mode 100644
index 0..1d59bcef1
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_complete_graph.py
@@ -0,0 +1,141 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+   ResolverPlayground,
+   ResolverPlaygroundTestCase,
+)
+
+class SlotOperatorCompleteGraphTestCase(TestCase):
+
+   def testSlotOperatorCompleteGraph(self):
+
+   ebuilds = {
+   "app-misc/meta-pkg-2" : {
+   "EAPI": "6",
+   "DEPEND": "=app-misc/B-2 =app-misc/C-1  
=app-misc/D-1 =dev-libs/foo-2",
+   "RDEPEND": "=app-misc/B-2 =app-misc/C-1 
=app-misc/D-1 =dev-libs/foo-2",
+   },
+
+   "app-misc/meta-pkg-1" : {
+   "EAPI": "6",
+   "DEPEND": "=app-misc/B-1 =app-misc/C-1  
=app-misc/D-1 =dev-libs/foo-1",
+   "RDEPEND": "=app-misc/B-1 =app-misc/C-1 
=app-misc/D-1 =dev-libs/foo-1",
+   },
+
+   "app-misc/B-1" : {
+   "EAPI": "6",
+   "DEPEND": "dev-libs/foo:=",
+   "RDEPEND": "dev-libs/foo:=",
+   },
+
+   "app-misc/B-2" : {
+   "EAPI": "6",
+   "DEPEND": "dev-libs/foo:=",
+   "RDEPEND": "dev-libs/foo:=",
+   },
+
+   "app-misc/C-1" : {
+   "EAPI": "6",
+   "DEPEND": "dev-libs/foo:= app-misc/B",
+   "RDEPEND": "dev-libs/foo:= app-misc/B",
+   },
+
+   "app-misc/C-2" : {
+   "EAPI": "6",
+   "DEPEND": "dev-libs/foo:= app-misc/B",
+   "RDEPEND": "dev-libs/foo:= app-misc/B",
+   },
+
+   "app-misc/D-1" : {
+   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/eventloop/

2017-03-26 Thread Zac Medico
commit: 96f0ed20ba8e079e351b2dd729d3386e59838ef3
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Mar 26 07:03:00 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Mar 26 07:03:26 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=96f0ed20

tests: add missing files in util/eventloop directory

Fixes: 04b1012594bf ("EventLoop: implement call_soon for asyncio compat (bug 
591760)")

 pym/portage/tests/util/eventloop/__init__.py | 0
 pym/portage/tests/util/eventloop/__test__.py | 0
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/pym/portage/tests/util/eventloop/__init__.py 
b/pym/portage/tests/util/eventloop/__init__.py
new file mode 100644
index 0..e69de29bb

diff --git a/pym/portage/tests/util/eventloop/__test__.py 
b/pym/portage/tests/util/eventloop/__test__.py
new file mode 100644
index 0..e69de29bb



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

2017-03-22 Thread Zac Medico
commit: 82bfd91325b052a4c9250a04939641c15b3d2a20
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Mar 20 23:13:42 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Mar 22 08:58:44 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=82bfd913

emerge: fix --usepkg when ebuild is not available (bug 613360)

Fix emerge --usepkg to use a binary package when the corresponding
ebuild is not available (and --use-ebuild-visibility is not enabled),
in cases when no other package is available to satisfy the dependency.
This reverts an unintended behavior change from commit
e309323f156528a8a79a1f755e1326e8880346b7.

Fixes: e309323f1565 ("emerge: fix --use-ebuild-visibility to reject binary 
packages (bug 612960)")
X-Gentoo-bug: 613360
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=613360
Acked-by: Brian Dolbec  gentoo.org>

 pym/_emerge/depgraph.py|  3 ++-
 .../resolver/test_binary_pkg_ebuild_visibility.py  | 26 ++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 543f4dc78..7c9130b38 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6062,7 +6062,8 @@ class depgraph(object):

identical_binary = True

break
 
-   if not identical_binary and 
pkg.built:
+   if (not identical_binary and 
pkg.built and
+   (use_ebuild_visibility 
or matched_packages)):
# If the ebuild 
no longer exists or it's
# keywords have 
been dropped, reject built
# instances 
(installed or binary).

diff --git a/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py 
b/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py
index ea65abded..0d01d0696 100644
--- a/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py
+++ b/pym/portage/tests/resolver/test_binary_pkg_ebuild_visibility.py
@@ -104,6 +104,32 @@ class BinaryPkgEbuildVisibilityTestCase(TestCase):
'[binary]app-misc/foo-3',
],
),
+
+   # The default behavior is to enforce ebuild visibility 
as
+   # long as a visible package is available to satisfy the
+   # current atom. In the following test case, ebuild 
visibility
+   # is ignored in order to satisfy the =app-misc/foo-3 
atom.
+   ResolverPlaygroundTestCase(
+   ["=app-misc/foo-3"],
+   options = {
+   "--usepkg": True,
+   },
+   success = True,
+   mergelist = [
+   '[binary]app-misc/foo-3',
+   ],
+   ),
+
+   # Verify that --use-ebuild-visibility works with 
--usepkg
+   # when no other visible package is available.
+   ResolverPlaygroundTestCase(
+   ["=app-misc/foo-3"],
+   options = {
+   "--use-ebuild-visibility": "y",
+   "--usepkg": True,
+   },
+   success = False,
+   ),
)
 
playground = ResolverPlayground(binpkgs=binpkgs, 
ebuilds=ebuilds,



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

2017-03-15 Thread Zac Medico
commit: 15e67f5516e0779d2cba37704c15b42193808197
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Mar 15 21:34:37 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Mar 16 04:47:41 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=15e67f55

depgraph: fix slot operator rebuild for llvm:0 to llvm:4 upgrade (bug 612772)

Fix check_reverse_dependencies to ignore dependencies of parent packages
that could be uninstalled in order to solve a blocker conflict. This case
is similar to the one from bug 584626, except that the relevant parent
package is in an older slot which is blocked by a newer slot. In this
case, the _upgrade_available method returns False, because the package
in the older slot is the highest version version available for its
slot. Therefore, a new _in_blocker_conflict method is needed to detect
parent packages that could be uninstalled. The included unit test fails
without this fix.

Since the _in_blocker_conflict method requires information that is
collected by the _validate_blockers method, the _validate_blockers
method now has to be called before the _process_slot_conflict and
_slot_operator_trigger_reinstalls methods.

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

 pym/_emerge/depgraph.py|  59 ---
 .../resolver/test_slot_operator_exclusive_slots.py | 109 +
 2 files changed, 155 insertions(+), 13 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 1379b0563..ad94fb70f 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -387,7 +387,10 @@ class _dynamic_depgraph_config(object):
# Contains only unsolvable Package -> Blocker edges
self._unsolvable_blockers = digraph()
# Contains all Blocker -> Blocked Package edges
-   self._blocked_pkgs = digraph()
+   # Do not initialize this until the depgraph _validate_blockers
+   # method is called, so that the _in_blocker_conflict method can
+   # assert that _validate_blockers has been called first.
+   self._blocked_pkgs = None
# Contains world packages that have been protected from
# uninstallation but may not have been added to the graph
# if the graph is not complete yet.
@@ -1466,9 +1469,22 @@ class depgraph(object):
 
self._solve_non_slot_operator_slot_conflicts()
 
+   if not self._validate_blockers():
+   # Blockers don't trigger the _skip_restart flag, since
+   # backtracking may solve blockers when it solves slot
+   # conflicts (or by blind luck).
+   raise self._unknown_internal_error()
+
+   # Both _process_slot_conflict and 
_slot_operator_trigger_reinstalls
+   # can call _slot_operator_update_probe, which requires that
+   # self._dynamic_config._blocked_pkgs has been initialized by a
+   # call to the _validate_blockers method.
for conflict in 
self._dynamic_config._package_tracker.slot_conflicts():
self._process_slot_conflict(conflict)
 
+   if self._dynamic_config._allow_backtracking:
+   self._slot_operator_trigger_reinstalls()
+
def _process_slot_conflict(self, conflict):
"""
Process slot conflict data to identify specific atoms which
@@ -1829,9 +1845,12 @@ class depgraph(object):
not 
self._frozen_config.excluded_pkgs.
findAtomForPackage(parent,

modified_use=self._pkg_use_enabled(parent)) and
-   
self._upgrade_available(parent)):
+   
(self._upgrade_available(parent) or
+   (parent.installed and 
self._in_blocker_conflict(parent:
# This parent may be 
irrelevant, since an
-   # update is available (see bug 
584626).
+   # update is available (see bug 
584626), or
+   # it could be uninstalled in 
order to solve
+   # a blocker conflict (bug 
612772).
continue
 
atom_set = 
InternalPackageSet(initial_atoms=(atom,),
@@ -2125,6 +2144,24 @@ class depgraph(object):
 
self._dynamic_config._need_restart = True
 
+   def _in_blocker_conflict(self, pkg):
+   """
+   Check if pkg is 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/, pym/portage/

2017-03-13 Thread Michał Górny
commit: b773fc08fe7b20b46a810b6eca85e489a69fb8ac
Author: Michał Górny  gentoo  org>
AuthorDate: Sun Mar 12 16:50:48 2017 +
Commit: Michał Górny  gentoo  org>
CommitDate: Mon Mar 13 21:46:30 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=b773fc08

Support STREEBOG{256,512} hash function (from pygcrypt), #597736

 pym/portage/checksum.py |  5 -
 pym/portage/const.py|  3 ++-
 pym/portage/tests/util/test_checksum.py | 18 ++
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/pym/portage/checksum.py b/pym/portage/checksum.py
index 92b41b133..3ee100c3f 100644
--- a/pym/portage/checksum.py
+++ b/pym/portage/checksum.py
@@ -137,7 +137,8 @@ if "SHA3_256" not in hashfunc_map or "SHA3_512" not in 
hashfunc_map:
 
 # Support pygcrypt as fallback using optimized routines from libgcrypt
 # (GnuPG).
-gcrypt_algos = frozenset(('RMD160', 'WHIRLPOOL', 'SHA3_256', 'SHA3_512'))
+gcrypt_algos = frozenset(('RMD160', 'WHIRLPOOL', 'SHA3_256', 'SHA3_512',
+   'STREEBOG256', 'STREEBOG512'))
 if gcrypt_algos.difference(hashfunc_map):
try:
import binascii
@@ -158,6 +159,8 @@ if gcrypt_algos.difference(hashfunc_map):
'WHIRLPOOL': 'whirlpool',
'SHA3_256': 'sha3-256',
'SHA3_512': 'sha3-512',
+   'STREEBOG256': 'stribog256',
+   'STREEBOG512': 'stribog512',
}
 
for local_name, gcry_name in name_mapping.items():

diff --git a/pym/portage/const.py b/pym/portage/const.py
index 0cef2e8ae..7e415ba9c 100644
--- a/pym/portage/const.py
+++ b/pym/portage/const.py
@@ -232,7 +232,8 @@ MANIFEST1_REQUIRED_HASH  = "MD5"
 # - Remove redundant settings from gentoo-x86/metadata/layout.conf.
 
 MANIFEST2_HASH_FUNCTIONS = ("SHA256", "SHA512", "WHIRLPOOL",
-   "BLAKE2B", "BLAKE2S", "SHA3_256", "SHA3_512")
+   "BLAKE2B", "BLAKE2S", "SHA3_256", "SHA3_512",
+   "STREEBOG256", "STREEBOG512")
 MANIFEST2_HASH_DEFAULTS = frozenset(["SHA256", "SHA512", "WHIRLPOOL"])
 MANIFEST2_REQUIRED_HASH  = "SHA256"
 

diff --git a/pym/portage/tests/util/test_checksum.py 
b/pym/portage/tests/util/test_checksum.py
index 72b8cef3f..01ac8f9d0 100644
--- a/pym/portage/tests/util/test_checksum.py
+++ b/pym/portage/tests/util/test_checksum.py
@@ -86,3 +86,21 @@ class ChecksumTestCase(TestCase):

'6634c004dc31822fa65c2f1e2e3bbf0cfa35085653cca1ca9ca42f8f3f13c908405e0b665918146181c9fc9a9d793fc05429d669c35a55517820dfaa071425ca')
except DigestException:
self.skipTest('SHA3_512 implementation not available')
+
+   def test_streebog256(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'STREEBOG256'),
+   
'3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb')
+   self.assertEqual(checksum_str(self.text, 'STREEBOG256'),
+   
'4992f1239c46f15b89e7b83ded4d83fb5966da3692788a4a1a6d118f78c08444')
+   except DigestException:
+   self.skipTest('STREEBOG256 implementation not 
available')
+
+   def test_streebog512(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'STREEBOG512'),
+   
'8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a')
+   self.assertEqual(checksum_str(self.text, 'STREEBOG512'),
+   
'330f5c26437f4e22c0163c72b12e93b8c27202f0750627355bdee43a0e0b253c90fbf0a27adbe5414019ff01ed84b7b240a1da1cbe10fae3adffc39c2d87a51f')
+   except DigestException:
+   self.skipTest('STREEBOG512 implementation not 
available')



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/

2017-03-13 Thread Michał Górny
commit: 04c2bbaba38e766250fee019fd9bbb98ba582038
Author: Michał Górny  gentoo  org>
AuthorDate: Sun Mar 12 15:12:48 2017 +
Commit: Michał Górny  gentoo  org>
CommitDate: Mon Mar 13 21:46:29 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=04c2bbab

tests: Add minimal safety checks for checksums

 pym/portage/tests/util/test_checksum.py | 88 +
 1 file changed, 88 insertions(+)

diff --git a/pym/portage/tests/util/test_checksum.py 
b/pym/portage/tests/util/test_checksum.py
new file mode 100644
index 0..72b8cef3f
--- /dev/null
+++ b/pym/portage/tests/util/test_checksum.py
@@ -0,0 +1,88 @@
+# Copyright 2011-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+
+from portage.checksum import checksum_str
+from portage.exception import DigestException
+
+class ChecksumTestCase(TestCase):
+   text = b'Some test string used to check if the hash works'
+
+   def test_md5(self):
+   self.assertEqual(checksum_str(b'', 'MD5'),
+   'd41d8cd98f00b204e9800998ecf8427e')
+   self.assertEqual(checksum_str(self.text, 'MD5'),
+   '094c3bf4732f59b39d577e9726f1e934')
+
+   def test_sha1(self):
+   self.assertEqual(checksum_str(b'', 'SHA1'),
+   'da39a3ee5e6b4b0d3255bfef95601890afd80709')
+   self.assertEqual(checksum_str(self.text, 'SHA1'),
+   '5c572017d4e4d49e4aa03a2eda12dbb54a1e2e4f')
+
+   def test_sha256(self):
+   self.assertEqual(checksum_str(b'', 'SHA256'),
+   
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
+   self.assertEqual(checksum_str(self.text, 'SHA256'),
+   
'e3d4a1135181fe156d61455615bb6296198e8ca5b2f20ddeb85cb4cd27f62320')
+
+   def test_sha512(self):
+   self.assertEqual(checksum_str(b'', 'SHA512'),
+   
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e')
+   self.assertEqual(checksum_str(self.text, 'SHA512'),
+   
'c8eaa902d48a2c82c2185a92f1c8bab8115c63c8d7a9966a8e8e81b07abcb9762f4707a6b27075e9d720277ba9fec072a59840d6355dd2ee64681d8f39a50856')
+
+   def test_rmd160(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'RMD160'),
+   
'9c1185a5c5e9fc54612808977ee8f548b2258d31')
+   self.assertEqual(checksum_str(self.text, 'RMD160'),
+   
'fc453174f63fc011d6f64abd2c45fb6a53c8239b')
+   except DigestException:
+   self.skipTest('RMD160 implementation not available')
+
+   def test_whirlpool(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'WHIRLPOOL'),
+   
'19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3')
+   self.assertEqual(checksum_str(self.text, 'WHIRLPOOL'),
+   
'8f556a079b87057f19e0880eed6d833e40c916f4b133196f6842281a2517873074d399832470c11ee251696b4844a10197714a069ba3e3415c8a4eced8f91b48')
+   except DigestException:
+   self.skipTest('WHIRLPOOL implementation not available')
+
+   def test_blake2b(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'BLAKE2B'),
+   
'786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce')
+   self.assertEqual(checksum_str(self.text, 'BLAKE2B'),
+   
'84cb3c88838c7147bc9797c6525f812adcdcb40137f9c075963e3a3ed1fe06aaeeb4d2bb5589bad286864dc1aa834cfc4d66b8d7e4d4a246d91d45ce3a6eee43')
+   except DigestException:
+   self.skipTest('BLAKE2B implementation not available')
+
+   def test_blake2s(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'BLAKE2S'),
+   
'69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9')
+   self.assertEqual(checksum_str(self.text, 'BLAKE2S'),
+   
'823ab2429f27690450efe888b0404d092fe2ee72a9bd63d5342c251b4dbb373d')
+   except DigestException:
+   self.skipTest('BLAKE2S implementation not available')
+
+   def test_sha3_256(self):
+   try:
+   self.assertEqual(checksum_str(b'', 'SHA3_256'),
+ 

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

2017-03-09 Thread Zac Medico
commit: c01f3fbd23def329eb1d1b0fc8f79959119a8a82
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Mar  8 22:25:56 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Mar  9 19:33:54 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=c01f3fbd

depgraph: fix runtime package mask interaction with slot operator rebuilds (bug 
612094)

In some cases the backtracking runtime package mask can interact badly
with slot operator rebuilds, preventing a solution from being found.
This patch fixes the problem, which is demonstrated by the included
unit test.

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

 pym/_emerge/depgraph.py|  28 +++--
 .../test_slot_operator_runtime_pkg_mask.py | 136 +
 2 files changed, 152 insertions(+), 12 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index bb3e307f0..1379b0563 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1597,9 +1597,6 @@ class depgraph(object):
atom.package and atom.slot_operator_built):
continue
 
-   if pkg not in conflict_pkgs:
-   continue
-
for other_pkg in slot_nodes:
if other_pkg in conflict_pkgs:
continue
@@ -2569,18 +2566,25 @@ class depgraph(object):
# runtime_pkg_mask, since that would trigger an
# infinite backtracking loop.
if self._dynamic_config._allow_backtracking:
-   if dep.parent in 
self._dynamic_config._runtime_pkg_mask:
-   if debug:
-   writemsg(
-   "!!! backtracking loop 
detected: %s %s\n" % \
-   (dep.parent,
-   
self._dynamic_config._runtime_pkg_mask[
-   dep.parent]), 
noiselevel=-1)
-   elif dep.atom.package and 
dep.atom.slot_operator_built and \
-   
self._slot_operator_unsatisfied_probe(dep):
+   if (dep.parent not in 
self._dynamic_config._runtime_pkg_mask and
+   dep.atom.package and 
dep.atom.slot_operator_built and
+   
self._slot_operator_unsatisfied_probe(dep)):

self._slot_operator_unsatisfied_backtrack(dep)
return 1
else:
+   # This is for backward-compatibility 
with previous
+   # behavior, so that installed packages 
with unsatisfied
+   # dependencies trigger an error message 
but do not
+   # cause the dependency calculation to 
fail. Only do
+   # this if the parent is already in the 
runtime package
+   # mask, since otherwise we need to 
backtrack.
+   if (dep.parent.installed and
+   dep.parent in 
self._dynamic_config._runtime_pkg_mask and
+   not 
any(self._iter_match_pkgs_any(
+   dep.parent.root_config, 
dep.atom))):
+   
self._dynamic_config._initially_unsatisfied_deps.append(dep)
+   return 1
+
# Do not backtrack if only USE have to 
be changed in
# order to satisfy the dependency. Note 
that when
# want_restart_for_use_change sets the 
need_restart

diff --git a/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py 
b/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py
new file mode 100644
index 0..0a5a7fa78
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py
@@ -0,0 +1,136 @@
+# Copyright 2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+   ResolverPlayground,
+   ResolverPlaygroundTestCase,
+)
+
+class SlotOperatorRuntimePkgMaskTestCase(TestCase):
+
+   def testSlotOperatorRuntimePkgMask(self):
+
+   ebuilds = {
+ 

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

2017-03-08 Thread Zac Medico
commit: 7c01a73c5a3ff969ddaa43e91730a7372a8a10c8
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Mar  8 01:30:05 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Mar  8 19:36:20 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=7c01a73c

depgraph: fix backtracking for slot operator rebuilds (bug 612042)

Fix package selection logic to avoid pulling in undesirable
rebuilds/updates during backtracking for slot operator rebuilds.
The undesirable rebuilds/updates have sent some calculations off
course, by triggering more and more rebuilds/updates with each
backtracking run.

In order to solve the problem, make various adjustments to the
package selection logic so that installed packages are preferred
over rebuilds/updates when appropriate. Also update unit tests
to work with these adjustments.

Fixes: 5842e87872fd ("Fix slot operator handling bug")
X-Gentoo-bug: 612042
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=612042
Acked-by: Brian Dolbec  gentoo.org>

 pym/_emerge/depgraph.py  | 11 +--
 .../resolver/soname/test_slot_conflict_reinstall.py  | 16 +++-
 pym/portage/tests/resolver/test_slot_abi.py  | 12 +---
 pym/portage/tests/resolver/test_slot_conflict_rebuild.py |  8 +++-
 4 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 02a32260a..bb3e307f0 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -2304,7 +2304,7 @@ class depgraph(object):
# Check for slot update first, since we don't 
want to
# trigger reinstall of the child package when a 
newer
# slot will be used instead.
-   if rebuild_if_new_slot:
+   if rebuild_if_new_slot and dep.want_update:
new_dep = 
self._slot_operator_update_probe(dep,
new_child_slot=True)
if new_dep is not None:
@@ -6241,7 +6241,7 @@ class depgraph(object):
if highest_installed is 
None or pkg.version > highest_installed.version:

highest_installed = pkg
 
-   if highest_installed:
+   if highest_installed and 
self._want_update_pkg(parent, highest_installed):
non_installed = [pkg for pkg in 
matched_packages \
if not pkg.installed 
and pkg.version > highest_installed.version]
 
@@ -6285,11 +6285,18 @@ class depgraph(object):
built_timestamp != 
installed_timestamp:
return built_pkg, 
existing_node
 
+   inst_pkg = None
for pkg in matched_packages:
+   if pkg.installed:
+   inst_pkg = pkg
if pkg.installed and pkg.invalid:
matched_packages = [x for x in \
matched_packages if x is not 
pkg]
 
+   if (inst_pkg is not None and parent is not None and
+   not self._want_update_pkg(parent, inst_pkg)):
+   return inst_pkg, existing_node
+
if avoid_update:
for pkg in matched_packages:
if pkg.installed and 
self._pkg_visibility_check(pkg, autounmask_level):

diff --git a/pym/portage/tests/resolver/soname/test_slot_conflict_reinstall.py 
b/pym/portage/tests/resolver/soname/test_slot_conflict_reinstall.py
index f4747611f..f7154442e 100644
--- a/pym/portage/tests/resolver/soname/test_slot_conflict_reinstall.py
+++ b/pym/portage/tests/resolver/soname/test_slot_conflict_reinstall.py
@@ -251,13 +251,27 @@ class SonameSlotConflictReinstallTestCase(TestCase):
success = True,
mergelist = [
'[binary]app-misc/B-2',
+   '[binary]app-misc/A-2',
+   ]
+   ),
+   ResolverPlaygroundTestCase(
+   ["@world"],
+   options = {
+   "--ignore-soname-deps": "n",
+   "--usepkgonly": True,
+   "--update": True,
+   

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

2017-03-08 Thread Zac Medico
commit: 852c729bdef3d4c2e2d459a43dc21f0a05dfa2ba
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Mar  4 06:24:21 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Mar  8 19:19:53 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=852c729b

emerge: auto-enable --with-bdeps if --usepkg is not enabled (bug 598444)

It's useful to automatically enable --with-bdeps so that @world updates
will update all packages that are not eligible for removal by
emerge --depclean. However, many users of binary packages do not want
unnecessary build time dependencies installed, therefore do not
auto-enable --with-bdeps for installation actions when the --usepkg
option is enabled.

A new --with-bdeps-auto= option is provided, making it possible to
enable or disable the program logic that causes --with-bdeps to be
automatically enabled. Use --with-bdeps-auto=n to prevent --with-bdeps
from being automatically enabled for installation actions. This is useful
for some rare cases in which --with-bdeps triggers unsolvable dependency
conflicts (and putting --with-bdeps=n in EMERGE_DEFAULT_OPTS would cause
undesirable --depclean behavior).

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

 man/emerge.1 |  37 +++-
 pym/_emerge/create_depgraph_params.py|   5 +
 pym/_emerge/depgraph.py  |   4 +-
 pym/_emerge/main.py  |   5 +
 pym/portage/tests/resolver/ResolverPlayground.py |   5 +
 pym/portage/tests/resolver/test_bdeps.py | 215 +++
 6 files changed, 266 insertions(+), 5 deletions(-)

diff --git a/man/emerge.1 b/man/emerge.1
index 5b6122023..7db427199 100644
--- a/man/emerge.1
+++ b/man/emerge.1
@@ -986,13 +986,44 @@ The default is set to "y" (on).
 .TP
 .BR "\-\-with\-bdeps < y | n >"
 In dependency calculations, pull in build time dependencies
-that are not strictly required. This defaults to \'n\' for
-installation actions, meaning they will not be installed, and
-\'y\' for the \fB\-\-depclean\fR action, meaning they will not be removed.
+that are not strictly required. This option is automatically enabled for
+installation actions, meaning they will be installed, and defaults to
+\(aqy\(aq for the \fB\-\-depclean\fR action, meaning they will not be
+removed. In order to prevent the \fB\-\-with\-bdeps\fR option from being
+automatically enabled for installation actions, specify
+\fB\-\-with\-bdeps\-auto=n\fR in either the command line or
+\fBEMERGE_DEFAULT_OPTS\fR.
+
+Since many users of binary packages do not want unnecessary build time
+dependencies installed, this option is not automatically enabled for
+installation actions when the \fB\-\-usepkg\fR option is enabled. In
+order to pull in build time dependencies for binary packages with
+\fB\-\-usepkg\fR, \fB\-\-with\-bdeps=y\fR must be specified explicitly.
+This also applies to options that enable the \fB\-\-usepkg\fR option
+implicitly, such as \fB\-\-getbinpkg\fR.
+
 This setting can be added to
 \fBEMERGE_DEFAULT_OPTS\fR (see make.conf(5)) and later overridden via the
 command line.
 .TP
+.BR "\-\-with\-bdeps\-auto < y | n >"
+This option is used to enable or disable the program logic that causes
+\fB\-\-with\-bdeps\fR is to be automatically enabled for installation
+actions. This option is enabled by default. Use
+\fB\-\-with\-bdeps\-auto=n\fR to prevent \fB\-\-with\-bdeps\fR from
+being automatically enabled for installation actions. This setting can
+be added to \fBEMERGE_DEFAULT_OPTS\fR (see make.conf(5)) and later
+overridden via the command line.
+
+\fBNOTE:\fR The program logic that causes \fB\-\-with\-bdeps\fR to be
+automatically enabled for installation actions does not affect removal
+actions such as the \fB\-\-depclean\fR action. Therefore, when
+\fB\-\-with\-bdeps\-auto=n\fR is specified in \fBEMERGE_DEFAULT_OPTS\fR,
+it does not affect the default \fB\-\-with\-bdeps=y\fR setting that
+applies to the \fB\-\-depclean\fR action. The default
+\fB\-\-with\-bdeps=y\fR setting that applies to the \fB\-\-depclean\fR
+action can be overridden only by specifying \fB\-\-with\-bdeps=n\fR.
+.TP
 .BR "\-\-with\-test\-deps [ y | n ]"
 For packages matched by arguments, this option will pull in dependencies
 that are conditional on the "test" USE flag, even if "test" is not

diff --git a/pym/_emerge/create_depgraph_params.py 
b/pym/_emerge/create_depgraph_params.py
index 2c6492883..cdea029ba 100644
--- a/pym/_emerge/create_depgraph_params.py
+++ b/pym/_emerge/create_depgraph_params.py
@@ -13,6 +13,8 @@ def create_depgraph_params(myopts, myaction):
# deep:  go into the dependencies of already merged packages
# empty: pretend nothing is merged
# complete:  completely account for all known dependencies
+   # bdeps: satisfy build time dependencies of packages that are
+   #   already 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/sync/

2017-01-31 Thread Zac Medico
commit: 0655b4a26e378cf409c9a033514f41c307d01371
Author: Alexandru Elisei  gmail  com>
AuthorDate: Sun Jan 29 18:07:34 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Jan 31 21:02:50 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=0655b4a2

test_sync_local: add test for auto-sync set to 'no'

 pym/portage/tests/sync/test_sync_local.py | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/sync/test_sync_local.py 
b/pym/portage/tests/sync/test_sync_local.py
index bec2e6a..1d38562 100644
--- a/pym/portage/tests/sync/test_sync_local.py
+++ b/pym/portage/tests/sync/test_sync_local.py
@@ -42,7 +42,7 @@ class SyncLocalTestCase(TestCase):
location = %(EPREFIX)s/var/repositories/test_repo
sync-type = %(sync-type)s
sync-uri = 
file:/%(EPREFIX)s/var/repositories/test_repo_sync
-   auto-sync = yes
+   auto-sync = %(auto-sync)s
%(repo_extra_keys)s
""")
 
@@ -87,9 +87,11 @@ class SyncLocalTestCase(TestCase):
committer_name = "Gentoo Dev"
committer_email = "gentoo-...@gentoo.org"
 
-   def repos_set_conf(sync_type, dflt_keys=None, xtra_keys=None):
+   def repos_set_conf(sync_type, dflt_keys=None, xtra_keys=None,
+   auto_sync="yes"):
env["PORTAGE_REPOSITORIES"] = repos_conf % {\
"EPREFIX": eprefix, "sync-type": sync_type,
+   "auto-sync": auto_sync,
"default_keys": "" if dflt_keys is None else 
dflt_keys,
"repo_extra_keys": "" if xtra_keys is None else 
xtra_keys}
 
@@ -100,6 +102,12 @@ class SyncLocalTestCase(TestCase):
os.unlink(os.path.join(metadata_dir, 'timestamp.chk'))
 
sync_cmds = (
+   (homedir, lambda: repos_set_conf("rsync", 
auto_sync="no")),
+   (homedir, cmds["emerge"] + ("--sync",)),
+   (homedir, lambda: self.assertFalse(os.path.exists(
+   os.path.join(repo.location, "dev-libs", "A")
+   ), "dev-libs/A found, expected missing")),
+   (homedir, lambda: repos_set_conf("rsync", 
auto_sync="yes")),
(homedir, cmds["emerge"] + ("--sync",)),
(homedir, lambda: self.assertTrue(os.path.exists(
os.path.join(repo.location, "dev-libs", "A")



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/sync/

2017-01-28 Thread Zac Medico
commit: b43f542614d136f69328dbc956f902bddb3db9c2
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Jan 28 20:45:16 2017 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Jan 28 20:55:22 2017 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=b43f5426

test_sync_local: fix emaint command path to be valid for travis

 pym/portage/tests/sync/test_sync_local.py | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/sync/test_sync_local.py 
b/pym/portage/tests/sync/test_sync_local.py
index b57bdba..bec2e6a 100644
--- a/pym/portage/tests/sync/test_sync_local.py
+++ b/pym/portage/tests/sync/test_sync_local.py
@@ -71,8 +71,15 @@ class SyncLocalTestCase(TestCase):
 
cmds = {}
for cmd in ("emerge", "emaint"):
-   cmds[cmd] =  (portage._python_interpreter,
-   "-b", "-Wd", os.path.join(self.bindir, cmd))
+   for bindir in (self.bindir, self.sbindir):
+   path = os.path.join(bindir, cmd)
+   if os.path.exists(path):
+   cmds[cmd] =  
(portage._python_interpreter,
+   "-b", "-Wd", path)
+   break
+   else:
+   raise AssertionError('%s binary not found in %s 
or %s' %
+   (cmd, self.bindir, self.sbindir))
 
git_binary = find_binary("git")
git_cmd = (git_binary,)



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/news/

2016-09-14 Thread Zac Medico
commit: 216297a9a7e91e48b74ef796b6642fd8c15085fc
Author: Mike Gilbert  gentoo  org>
AuthorDate: Thu Sep 15 01:30:37 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Sep 15 01:43:28 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=216297a9

test_NewsItem: Add News-Item-Format to template

 pym/portage/tests/news/test_NewsItem.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pym/portage/tests/news/test_NewsItem.py 
b/pym/portage/tests/news/test_NewsItem.py
index a4e76f3..2f183a7 100644
--- a/pym/portage/tests/news/test_NewsItem.py
+++ b/pym/portage/tests/news/test_NewsItem.py
@@ -17,6 +17,7 @@ Author: Ciaran McCreesh 
 Content-Type: text/plain
 Posted: 01-Nov-2005
 Revision: 1
+News-Item-Format: 1.0
 #Display-If-Installed:
 #Display-If-Profile:
 #Display-If-Arch:



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/ebuild/, pym/portage/util/_eventloop/

2016-08-23 Thread Zac Medico
commit: 995f0f983386e2a82dbce65d4366ee7f58f59138
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Aug 20 21:59:55 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Aug 23 16:33:47 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=995f0f98

EventLoop: add run_until_complete method (bug 591760)

This emulates the asyncio.AbstractEventLoop.run_until_complete(future)
interface, which will make it possible to reduce latency in situations
where it is desirable for a loop to exit at the earliest opportunity.

The most tangible benefit of this change is that it provides a
migration path to asyncio, which will allow us to rely on a standard
library instead of our own internal event loop implementation.

In order to migrate to asyncio, more work is planned:

* Migrate all internal use of the EventLoop.iteration method to the new
run_until_complete(future) method, and remove the EventLoop.iteration
method (or make it private as long as it's needed to implement
run_until_complete for older python versions).

* Implement all EventLoop methods using asyncio.AbstractEventLoop
methods (but keep existing implementations for use with older python).

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

 pym/portage/tests/ebuild/test_ipc_daemon.py | 23 ++-
 pym/portage/util/_eventloop/EventLoop.py| 17 -
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/pym/portage/tests/ebuild/test_ipc_daemon.py 
b/pym/portage/tests/ebuild/test_ipc_daemon.py
index 835f51f..68f139a 100644
--- a/pym/portage/tests/ebuild/test_ipc_daemon.py
+++ b/pym/portage/tests/ebuild/test_ipc_daemon.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2015 Gentoo Foundation
+# Copyright 2010-2016 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import tempfile
@@ -16,6 +16,7 @@ from portage.util import ensure_dirs
 from portage.util._async.ForkProcess import ForkProcess
 from portage.util._async.TaskScheduler import TaskScheduler
 from portage.util._eventloop.global_event_loop import global_event_loop
+from portage.util.futures.futures import Future
 from _emerge.SpawnProcess import SpawnProcess
 from _emerge.EbuildBuildDir import EbuildBuildDir
 from _emerge.EbuildIpcDaemon import EbuildIpcDaemon
@@ -140,19 +141,23 @@ class IpcDaemonTestCase(TestCase):
build_dir.unlock()
shutil.rmtree(tmpdir)
 
-   def _timeout_callback(self):
-   self._timed_out = True
+   def _timeout_callback(self, task_scheduler):
+   task_scheduler.cancel()
+   self._exit_callback(task_scheduler)
+
+   def _exit_callback(self, task_scheduler):
+   if not self._run_done.done():
+   self._run_done.set_result(True)
 
def _run(self, event_loop, task_scheduler, timeout):
-   self._timed_out = False
-   timeout_id = event_loop.timeout_add(timeout, 
self._timeout_callback)
+   self._run_done = Future()
+   timeout_id = event_loop.timeout_add(timeout,
+   self._timeout_callback, task_scheduler)
+   task_scheduler.addExitListener(self._exit_callback)
 
try:
task_scheduler.start()
-   while not self._timed_out and task_scheduler.poll() is 
None:
-   event_loop.iteration()
-   if self._timed_out:
-   task_scheduler.cancel()
+   event_loop.run_until_complete(self._run_done)
task_scheduler.wait()
finally:
event_loop.source_remove(timeout_id)

diff --git a/pym/portage/util/_eventloop/EventLoop.py 
b/pym/portage/util/_eventloop/EventLoop.py
index 8095400..8f13de3 100644
--- a/pym/portage/util/_eventloop/EventLoop.py
+++ b/pym/portage/util/_eventloop/EventLoop.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2014 Gentoo Foundation
+# Copyright 1999-2016 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import division
@@ -577,6 +577,21 @@ class EventLoop(object):
del self._poll_event_handlers[f]
return True
 
+   def run_until_complete(self, future):
+   """
+   Run until the Future is done.
+
+   @type future: asyncio.Future
+   @param future: a Future to wait for
+   @rtype: object
+   @return: the Future's result
+   @raise: the Future's exception
+   """
+   while not future.done():
+   self.iteration()
+
+   return future.result()
+
 _can_poll_device = None
 
 def can_poll_device():



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

2016-08-07 Thread Zac Medico
commit: 6412205462671735f6e8b3196a780bc4b0d6a077
Author: Zac Medico  gentoo  org>
AuthorDate: Fri Aug  5 02:15:14 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Aug  7 17:44:20 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=64122054

depgraph._serialize_tasks: improve runtime cycle handling (bug 590514)

Previously, it was possible for _serialize_tasks to count some
dependencies of a runtime cycle as part of that cycle, leading to
sub-optimal merge order for these dependencies because they got
grouped together with the cycle in the overall merge order. Fix
it to separate these dependencies from the cycle, and merge them
earlier.

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

 pym/_emerge/depgraph.py| 50 +++
 .../resolver/test_runtime_cycle_merge_order.py | 72 ++
 2 files changed, 98 insertions(+), 24 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index fc957f5..26037ad 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -7415,36 +7415,38 @@ class depgraph(object):
selected_nodes = set()
if gather_deps(ignore_priority,
mergeable_nodes, 
selected_nodes, node):
-   # When selecting 
asap_nodes, we need to ensure
-   # that we haven't 
selected a large runtime cycle
-   # that is obviously 
sub-optimal. This will be
-   # obvious if any of the 
non-asap selected_nodes
-   # is a leaf node when 
medium_soft deps are
-   # ignored.
-   if prefer_asap and 
asap_nodes and \
-   
len(selected_nodes) > 1:
-   for node in 
selected_nodes.difference(
-   
asap_nodes):
-   if not 
mygraph.child_nodes(node,
-   
ignore_priority =
-   
DepPriorityNormalRange.ignore_medium_soft):
-   
selected_nodes = None
-   
break
-   if selected_nodes:
-   if 
smallest_cycle is None or \
-   
len(selected_nodes) < len(smallest_cycle):
-   
smallest_cycle = selected_nodes
+   if smallest_cycle is 
None or \
+   
len(selected_nodes) < len(smallest_cycle):
+   smallest_cycle 
= selected_nodes
 
selected_nodes = smallest_cycle
 
-   if selected_nodes and debug:
-   writemsg("\nruntime cycle 
digraph (%s nodes):\n\n" %
-   (len(selected_nodes),), 
noiselevel=-1)
+   if selected_nodes is not None:
cycle_digraph = mygraph.copy()

cycle_digraph.difference_update([x for x in
cycle_digraph if x not 
in selected_nodes])
-   cycle_digraph.debug_print()
-   writemsg("\n", noiselevel=-1)
+
+   leaves = 
cycle_digraph.leaf_nodes()
+   if leaves:
+   # NOTE: This case 
should only be triggered when
+   # prefer_asap is True, 
since otherwise these
+   # leaves would have 
been selected to merge
+   # before this 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/

2016-06-26 Thread Zac Medico
commit: ac6f924fa3d9296778d493a16a1d428ab54dda97
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Jun 23 06:17:17 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Jun 26 23:49:29 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=ac6f924f

Add a unit test which reproduces bug 584626

X-Gentoo-Bug: 584626
X-Gentoo-Bug-url: https://bugs.gentoo.org/show_bug.cgi?id=584626

 .../resolver/test_slot_operator_reverse_deps.py| 109 +
 1 file changed, 109 insertions(+)

diff --git a/pym/portage/tests/resolver/test_slot_operator_reverse_deps.py 
b/pym/portage/tests/resolver/test_slot_operator_reverse_deps.py
new file mode 100644
index 000..72879f8
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_reverse_deps.py
@@ -0,0 +1,109 @@
+# Copyright 2016 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+   ResolverPlayground,
+   ResolverPlaygroundTestCase,
+)
+
+class SlotOperatorReverseDepsTestCase(TestCase):
+
+   def testSlotOperatorReverseDeps(self):
+
+   ebuilds = {
+
+   "media-libs/mesa-11.2.2" : {
+   "EAPI": "6",
+   "SLOT": "0",
+   "RDEPEND": ">=sys-devel/llvm-3.6.0:="
+   },
+
+   "sys-devel/clang-3.7.1-r100" : {
+   "EAPI": "6",
+   "SLOT": "0/3.7",
+   "RDEPEND": "~sys-devel/llvm-3.7.1"
+   },
+
+   "sys-devel/clang-3.8.0-r100" : {
+   "EAPI": "6",
+   "SLOT": "0/3.8",
+   "RDEPEND": "~sys-devel/llvm-3.8.0"
+   },
+
+   "sys-devel/llvm-3.7.1-r2" : {
+   "EAPI": "6",
+   "SLOT": "0/3.7.1",
+   "PDEPEND": "=sys-devel/clang-3.7.1-r100"
+   },
+
+   "sys-devel/llvm-3.8.0-r2" : {
+   "EAPI": "6",
+   "SLOT": "0/3.8.0",
+   "PDEPEND": "=sys-devel/clang-3.8.0-r100"
+   },
+
+   }
+
+   installed = {
+
+   "media-libs/mesa-11.2.2" : {
+   "EAPI": "6",
+   "SLOT": "0",
+   "RDEPEND": ">=sys-devel/llvm-3.6.0:0/3.7.1="
+   },
+
+   "sys-devel/clang-3.7.1-r100" : {
+   "EAPI": "6",
+   "SLOT": "0/3.7",
+   "RDEPEND": "~sys-devel/llvm-3.7.1"
+   },
+
+   "sys-devel/llvm-3.7.1-r2" : {
+   "EAPI": "6",
+   "SLOT": "0/3.7.1",
+   "PDEPEND": "=sys-devel/clang-3.7.1-r100"
+   },
+
+   }
+
+   world = ["media-libs/mesa"]
+
+   test_cases = (
+
+   # Test bug #584626, where an llvm update is missed due 
to
+   # the check_reverse_dependencies function seeing that
+   # updating llvm will break a dependency of the installed
+   # version of clang (though a clang update is available).
+   ResolverPlaygroundTestCase(
+   ["@world"],
+   options = {"--update": True, "--deep": True},
+   success = True,
+   mergelist = [],
+   ),
+
+   ResolverPlaygroundTestCase(
+   ["@world"],
+   options = {
+   "--update": True,
+   "--deep": True,
+   "--ignore-built-slot-operator-deps": 
"y",
+   },
+   success = True,
+   mergelist = [
+   'sys-devel/llvm-3.8.0-r2',
+   'sys-devel/clang-3.8.0-r100',
+   ],
+   ),
+
+   )
+
+   playground = ResolverPlayground(ebuilds=ebuilds,
+   installed=installed, world=world, debug=False)
+   try:
+   for test_case in test_cases:
+   playground.run_TestCase(test_case)
+   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/util/, cnf/

2016-05-07 Thread Zac Medico
commit: a810a92d615c904db59326188e1437fdab74e705
Author: Zac Medico  gentoo  org>
AuthorDate: Thu May  5 17:12:13 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat May  7 20:02:51 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=a810a92d

make.globals: Respect ssh_config port (bug 499198)

Fix FETCHCOMMAND_SSH and FETCHCOMMAND_SFTP to respect ssh_config port.

X-Gentoo-bug: 499198
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=499198
Acked-by: Alexander Berntsen  gentoo.org>

 cnf/make.globals | 4 ++--
 pym/portage/tests/util/test_getconfig.py | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/cnf/make.globals b/cnf/make.globals
index 836bb5c..18eba94 100644
--- a/cnf/make.globals
+++ b/cnf/make.globals
@@ -43,11 +43,11 @@ FETCHCOMMAND_RSYNC="rsync -avP \"\${URI}\" 
\"\${DISTDIR}/\${FILE}\""
 RESUMECOMMAND_RSYNC="rsync -avP \"\${URI}\" \"\${DISTDIR}/\${FILE}\""
 
 # NOTE: rsync will evaluate quotes embedded inside PORTAGE_SSH_OPTS
-FETCHCOMMAND_SSH="bash -c \"x=\\\${2#ssh://} ; host=\\\${x%%/*} ; 
port=\\\${host##*:} ; host=\\\${host%:*} ; [[ \\\${host} = \\\${port} ]] && 
port=22 ; exec rsync --rsh=\\\"ssh -p\\\${port} \\\${3}\\\" -avP 
\\\"\\\${host}:/\\\${x#*/}\\\" \\\"\\\$1\\\"\" rsync \"\${DISTDIR}/\${FILE}\" 
\"\${URI}\" \"\${PORTAGE_SSH_OPTS}\""
+FETCHCOMMAND_SSH="bash -c \"x=\\\${2#ssh://} ; host=\\\${x%%/*} ; 
port=\\\${host##*:} ; host=\\\${host%:*} ; [[ \\\${host} = \\\${port} ]] && 
port= ; exec rsync --rsh=\\\"ssh \\\${port:+-p\\\${port}} \\\${3}\\\" -avP 
\\\"\\\${host}:/\\\${x#*/}\\\" \\\"\\\$1\\\"\" rsync \"\${DISTDIR}/\${FILE}\" 
\"\${URI}\" \"\${PORTAGE_SSH_OPTS}\""
 RESUMECOMMAND_SSH=${FETCHCOMMAND_SSH}
 
 # NOTE: bash eval is used to evaluate quotes embedded inside PORTAGE_SSH_OPTS
-FETCHCOMMAND_SFTP="bash -c \"x=\\\${2#sftp://} ; host=\\\${x%%/*} ; 
port=\\\${host##*:} ; host=\\\${host%:*} ; [[ \\\${host} = \\\${port} ]] && 
port=22 ; eval \\\"declare -a ssh_opts=(\\\${3})\\\" ; exec sftp -P \\\${port} 
\\\"\\\${ssh_opts[@]}\\\" \\\"\\\${host}:/\\\${x#*/}\\\" \\\"\\\$1\\\"\" sftp 
\"\${DISTDIR}/\${FILE}\" \"\${URI}\" \"\${PORTAGE_SSH_OPTS}\""
+FETCHCOMMAND_SFTP="bash -c \"x=\\\${2#sftp://} ; host=\\\${x%%/*} ; 
port=\\\${host##*:} ; host=\\\${host%:*} ; [[ \\\${host} = \\\${port} ]] && 
port= ; eval \\\"declare -a ssh_opts=(\\\${3})\\\" ; exec sftp \\\${port:+-P 
\\\${port}} \\\"\\\${ssh_opts[@]}\\\" \\\"\\\${host}:/\\\${x#*/}\\\" 
\\\"\\\$1\\\"\" sftp \"\${DISTDIR}/\${FILE}\" \"\${URI}\" 
\"\${PORTAGE_SSH_OPTS}\""
 
 # Default user options
 FEATURES="assume-digests binpkg-logs

diff --git a/pym/portage/tests/util/test_getconfig.py 
b/pym/portage/tests/util/test_getconfig.py
index b72bd6a..05e3147 100644
--- a/pym/portage/tests/util/test_getconfig.py
+++ b/pym/portage/tests/util/test_getconfig.py
@@ -20,8 +20,8 @@ class GetConfigTestCase(TestCase):
_cases = {
'FETCHCOMMAND' : 'wget -t 3 -T 60 --passive-ftp -O 
"${DISTDIR}/${FILE}" "${URI}"',
'FETCHCOMMAND_RSYNC'   : 'rsync -avP "${URI}" 
"${DISTDIR}/${FILE}"',
-   'FETCHCOMMAND_SFTP': 'bash -c "x=\\${2#sftp://} ; 
host=\\${x%%/*} ; port=\\${host##*:} ; host=\\${host%:*} ; [[ \\${host} = 
\\${port} ]] && port=22 ; eval \\"declare -a ssh_opts=(\\${3})\\" ; exec sftp 
-P \\${port} \\"\\${ssh_opts[@]}\\" \\"\\${host}:/\\${x#*/}\\" \\"\\$1\\"" sftp 
"${DISTDIR}/${FILE}" "${URI}" "${PORTAGE_SSH_OPTS}"',
-   'FETCHCOMMAND_SSH' : 'bash -c "x=\\${2#ssh://} ; 
host=\\${x%%/*} ; port=\\${host##*:} ; host=\\${host%:*} ; [[ \\${host} = 
\\${port} ]] && port=22 ; exec rsync --rsh=\\"ssh -p\\${port} \\${3}\\" -avP 
\\"\\${host}:/\\${x#*/}\\" \\"\\$1\\"" rsync "${DISTDIR}/${FILE}" "${URI}" 
"${PORTAGE_SSH_OPTS}"',
+   'FETCHCOMMAND_SFTP': 'bash -c "x=\\${2#sftp://} ; 
host=\\${x%%/*} ; port=\\${host##*:} ; host=\\${host%:*} ; [[ \\${host} = 
\\${port} ]] && port= ; eval \\"declare -a ssh_opts=(\\${3})\\" ; exec sftp 
\\${port:+-P \\${port}} \\"\\${ssh_opts[@]}\\" \\"\\${host}:/\\${x#*/}\\" 
\\"\\$1\\"" sftp "${DISTDIR}/${FILE}" "${URI}" "${PORTAGE_SSH_OPTS}"',
+   'FETCHCOMMAND_SSH' : 'bash -c "x=\\${2#ssh://} ; 
host=\\${x%%/*} ; port=\\${host##*:} ; host=\\${host%:*} ; [[ \\${host} = 
\\${port} ]] && port= ; exec rsync --rsh=\\"ssh \\${port:+-p\\${port}} 
\\${3}\\" -avP \\"\\${host}:/\\${x#*/}\\" \\"\\$1\\"" rsync 
"${DISTDIR}/${FILE}" "${URI}" "${PORTAGE_SSH_OPTS}"',
'PORTAGE_ELOG_MAILSUBJECT' : '[portage] ebuild log for 
${PACKAGE} on ${HOST}'
}
 



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/repoman/

2016-02-24 Thread Zac Medico
commit: 4d7792fc2d633011b158780d670e57212961f933
Author: Zac Medico  gentoo  org>
AuthorDate: Wed Feb 24 23:17:45 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Wed Feb 24 23:19:33 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=4d7792fc

SimpleRepomanTestCase: suppress metadata.dtd fetch (fix travis-ci failure)

 pym/portage/tests/repoman/test_simple.py | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/pym/portage/tests/repoman/test_simple.py 
b/pym/portage/tests/repoman/test_simple.py
index af6f95d..98220c4 100644
--- a/pym/portage/tests/repoman/test_simple.py
+++ b/pym/portage/tests/repoman/test_simple.py
@@ -7,7 +7,6 @@ import time
 
 import portage
 from portage import os
-from portage import shutil
 from portage import _unicode_decode
 from portage.const import PORTAGE_BASE_PATH, PORTAGE_PYM_PATH
 from portage.process import find_binary
@@ -273,11 +272,9 @@ class SimpleRepomanTestCase(TestCase):
# involving canonical vs. non-canonical paths.
test_repo_symlink = os.path.join(eroot, 
"test_repo_symlink")
os.symlink(test_repo_location, test_repo_symlink)
-   # repoman checks metadata.dtd for recent CTIME, so copy 
the file in
-   # order to ensure that the CTIME is current
-   # NOTE: if we don't have the file around, let repoman 
try to fetch it.
-   if os.path.exists(metadata_dtd):
-   shutil.copyfile(metadata_dtd, 
os.path.join(distdir, "metadata.dtd"))
+   metadata_dtd_dest = os.path.join(test_repo_location, 
'metadata/dtd/metadata.dtd')
+   os.makedirs(os.path.dirname(metadata_dtd_dest))
+   os.symlink(metadata_dtd, metadata_dtd_dest)
 
if debug:
# The subprocess inherits both stdout and 
stderr, for



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/ebuild/

2016-01-16 Thread Zac Medico
commit: 44aeab7fad440a289316ced8738b287d88d475d0
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Jan 17 02:52:02 2016 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Jan 17 02:54:27 2016 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=44aeab7f

DoebuildFdPipesTestCase: use extra pipe for test output

Since commit 3767128cf08a0a21559eb9c41ba393dcabc6f087, this test has
failed due to additional output produced by src_install. Fix it to
use a separate pipe for test output.

 pym/portage/tests/ebuild/test_doebuild_fd_pipes.py | 36 +++---
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py 
b/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py
index 2a65537..b894218 100644
--- a/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py
+++ b/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py
@@ -1,8 +1,6 @@
-# Copyright 2013-2015 Gentoo Foundation
+# Copyright 2013-2016 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import textwrap
-
 import portage
 from portage import os
 from portage.tests import TestCase
@@ -10,7 +8,6 @@ from portage.tests.resolver.ResolverPlayground import 
ResolverPlayground
 from portage.package.ebuild._ipc.QueryCommand import QueryCommand
 from portage.util._async.ForkProcess import ForkProcess
 from portage.util._async.TaskScheduler import TaskScheduler
-from portage.util._eventloop.global_event_loop import global_event_loop
 from _emerge.Package import Package
 from _emerge.PipeReader import PipeReader
 
@@ -31,19 +28,16 @@ class DoebuildFdPipesTestCase(TestCase):
supported for API consumers (see bug #475812).
"""
 
-   ebuild_body = textwrap.dedent("""
-   S=${WORKDIR}
-   pkg_info() { echo info ; }
-   pkg_nofetch() { echo nofetch ; }
-   pkg_pretend() { echo pretend ; }
-   pkg_setup() { echo setup ; }
-   src_unpack() { echo unpack ; }
-   src_prepare() { echo prepare ; }
-   src_configure() { echo configure ; }
-   src_compile() { echo compile ; }
-   src_test() { echo test ; }
-   src_install() { echo install ; }
-   """)
+   output_fd = 200
+   ebuild_body = ['S=${WORKDIR}']
+   for phase_func in ('pkg_info', 'pkg_nofetch', 'pkg_pretend',
+   'pkg_setup', 'src_unpack', 'src_prepare', 
'src_configure',
+   'src_compile', 'src_test', 'src_install'):
+   ebuild_body.append(('%s() { echo ${EBUILD_PHASE}'
+   ' 1>&%s; }') % (phase_func, output_fd))
+
+   ebuild_body.append('')
+   ebuild_body = '\n'.join(ebuild_body)
 
ebuilds = {
'app-misct/foo-1': {
@@ -60,6 +54,7 @@ class DoebuildFdPipesTestCase(TestCase):
self.assertEqual(true_binary is None, False,
"true command not found")
 
+   dev_null = open(os.devnull, 'wb')
playground = ResolverPlayground(ebuilds=ebuilds)
try:
QueryCommand._db = playground.trees
@@ -106,7 +101,11 @@ class DoebuildFdPipesTestCase(TestCase):
doebuild_kwargs={"settings" : settings,
"mydbapi": portdb, "tree": 
"porttree",
"vartree": 
root_config.trees["vartree"],
-   "fd_pipes": {1: pw, 2: pw},
+   "fd_pipes": {
+   1: dev_null.fileno(),
+   2: dev_null.fileno(),
+   output_fd: pw,
+   },
"prev_mtimes": {}})
 
consumer = PipeReader(
@@ -134,5 +133,6 @@ class DoebuildFdPipesTestCase(TestCase):
self.assertEqual(phase, output)
 
finally:
+   dev_null.close()
playground.cleanup()
QueryCommand._db = None



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/ebuild/, pym/portage/package/ebuild/, pym/portage/repository/

2015-12-07 Thread Arfrever Frehtes Taifersar Arahesis
commit: 10647652ebeff52c3dbc0419ab9030ba76d46122
Author: Arfrever Frehtes Taifersar Arahesis  Apache  Org>
AuthorDate: Tue Dec  8 06:58:36 2015 +
Commit: Arfrever Frehtes Taifersar Arahesis  apache  org>
CommitDate: Tue Dec  8 06:58:36 2015 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=10647652

portage.repository.config.RepoConfig: Delete user_location attribute and 
consistently use location attribute everywhere.

 pym/portage/package/ebuild/config.py|  4 ++--
 pym/portage/repository/config.py| 21 ++---
 pym/portage/tests/ebuild/test_config.py |  4 ++--
 3 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index 7cf5a4c..b6217e7 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -539,13 +539,13 @@ class config(object):
#filling PORTDIR and PORTDIR_OVERLAY variable for 
compatibility
main_repo = self.repositories.mainRepo()
if main_repo is not None:
-   self["PORTDIR"] = main_repo.user_location
+   self["PORTDIR"] = main_repo.location
self.backup_changes("PORTDIR")
expand_map["PORTDIR"] = self["PORTDIR"]
 
# repoman controls PORTDIR_OVERLAY via the environment, 
so no
# special cases are needed here.
-   portdir_overlay = 
list(self.repositories.repoUserLocationList())
+   portdir_overlay = 
list(self.repositories.repoLocationList())
if portdir_overlay and portdir_overlay[0] == 
self["PORTDIR"]:
portdir_overlay = portdir_overlay[1:]
 

diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py
index b987b56..b792d78 100644
--- a/pym/portage/repository/config.py
+++ b/pym/portage/repository/config.py
@@ -91,8 +91,8 @@ class RepoConfig(object):
'profile_formats', 'sign_commit', 'sign_manifest',
'sync_depth', 'sync_hooks_only_on_change',
'sync_type', 'sync_umask', 'sync_uri', 'sync_user', 
'thin_manifest',
-   'update_changelog', 'user_location', '_eapis_banned',
-   '_eapis_deprecated', '_masters_orig', 'module_specific_options',
+   'update_changelog', '_eapis_banned', '_eapis_deprecated',
+   '_masters_orig', 'module_specific_options',
)
 
def __init__(self, name, repo_opts, local_config=True):
@@ -189,7 +189,6 @@ class RepoConfig(object):
self.format = format
 
location = repo_opts.get('location')
-   self.user_location = location
if location is not None and location.strip():
if os.path.isdir(location) or portage._sync_mode:
location = os.path.realpath(location)
@@ -410,8 +409,8 @@ class RepoConfig(object):
repo_msg.append(self.name)
if self.format:
repo_msg.append(indent + "format: " + self.format)
-   if self.user_location:
-   repo_msg.append(indent + "location: " + 
self.user_location)
+   if self.location:
+   repo_msg.append(indent + "location: " + self.location)
if self.sync_type:
repo_msg.append(indent + "sync-type: " + self.sync_type)
if self.sync_umask:
@@ -527,7 +526,7 @@ class RepoConfigLoader(object):
old_location == 
default_portdir):

ignored_map.setdefault(repo.name, []).append(old_location)
if old_location == 
portdir:
-   portdir = 
repo.user_location
+   portdir = 
repo.location
 
if repo.priority is None:
if base_priority == 0 and ov == 
portdir_orig:
@@ -826,7 +825,7 @@ class RepoConfigLoader(object):
master_repos = []
for master_name in repo.masters:
if master_name not in prepos:
-   layout_filename = 
os.path.join(repo.user_location,
+   layout_filename = 
os.path.join(repo.location,
"metadata", 
"layout.conf")
writemsg_level(_("Unavailable 
repository '%s' " \
  

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

2015-12-01 Thread Arfrever Frehtes Taifersar Arahesis
commit: 48c2af4538d581fb2225c0ac9620b7fcfe4eae2e
Author: Arfrever Frehtes Taifersar Arahesis  Apache  Org>
AuthorDate: Wed Dec  2 01:16:34 2015 +
Commit: Arfrever Frehtes Taifersar Arahesis  apache  org>
CommitDate: Wed Dec  2 01:16:34 2015 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=48c2af45

Respect PYTHONDONTWRITEBYTECODE in test suite.

 pym/portage/package/ebuild/_config/special_env_vars.py | 2 +-
 pym/portage/tests/dbapi/test_portdb_cache.py   | 3 ++-
 pym/portage/tests/ebuild/test_doebuild_fd_pipes.py | 3 ++-
 pym/portage/tests/ebuild/test_doebuild_spawn.py| 3 ++-
 pym/portage/tests/ebuild/test_ipc_daemon.py| 3 ++-
 pym/portage/tests/emerge/test_config_protect.py| 3 ++-
 pym/portage/tests/emerge/test_emerge_slot_abi.py   | 3 ++-
 pym/portage/tests/emerge/test_simple.py| 3 ++-
 pym/portage/tests/repoman/test_simple.py   | 3 ++-
 pym/portage/tests/sync/test_sync_local.py  | 3 ++-
 10 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/pym/portage/package/ebuild/_config/special_env_vars.py 
b/pym/portage/package/ebuild/_config/special_env_vars.py
index 8479cf5..9ae53c1 100644
--- a/pym/portage/package/ebuild/_config/special_env_vars.py
+++ b/pym/portage/package/ebuild/_config/special_env_vars.py
@@ -77,7 +77,7 @@ environ_whitelist += [
"PORTAGE_SIGPIPE_STATUS", "PORTAGE_SOCKS5_PROXY",
"PORTAGE_TMPDIR", "PORTAGE_UPDATE_ENV", "PORTAGE_USERNAME",
"PORTAGE_VERBOSE", "PORTAGE_WORKDIR_MODE", "PORTAGE_XATTR_EXCLUDE",
-   "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH",
+   "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH", "PYTHONDONTWRITEBYTECODE",
"REPLACING_VERSIONS", "REPLACED_BY_VERSION",
"ROOT", "ROOTPATH", "T", "TMP", "TMPDIR",
"USE_EXPAND", "USE_ORDER", "WORKDIR",

diff --git a/pym/portage/tests/dbapi/test_portdb_cache.py 
b/pym/portage/tests/dbapi/test_portdb_cache.py
index 5ac9b03..bd93446 100644
--- a/pym/portage/tests/dbapi/test_portdb_cache.py
+++ b/pym/portage/tests/dbapi/test_portdb_cache.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2014 Gentoo Foundation
+# Copyright 2012-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import subprocess
@@ -134,6 +134,7 @@ class PortdbCacheTestCase(TestCase):
"PORTAGE_OVERRIDE_EPREFIX" : eprefix,
"PORTAGE_PYTHON" : portage_python,
"PORTAGE_REPOSITORIES" : 
settings.repositories.config_string(),
+   "PYTHONDONTWRITEBYTECODE" : 
os.environ.get("PYTHONDONTWRITEBYTECODE", ""),
"PYTHONPATH" : pythonpath,
}
 

diff --git a/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py 
b/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py
index 61392dd..2a65537 100644
--- a/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py
+++ b/pym/portage/tests/ebuild/test_doebuild_fd_pipes.py
@@ -1,4 +1,4 @@
-# Copyright 2013 Gentoo Foundation
+# Copyright 2013-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import textwrap
@@ -75,6 +75,7 @@ class DoebuildFdPipesTestCase(TestCase):
settings.features.add("test")
settings['PORTAGE_PYTHON'] = portage._python_interpreter
settings['PORTAGE_QUIET'] = "1"
+   settings['PYTHONDONTWRITEBYTECODE'] = 
os.environ.get("PYTHONDONTWRITEBYTECODE", "")
 
fake_bin = os.path.join(settings["EPREFIX"], "bin")
portage.util.ensure_dirs(fake_bin)

diff --git a/pym/portage/tests/ebuild/test_doebuild_spawn.py 
b/pym/portage/tests/ebuild/test_doebuild_spawn.py
index ae9a5c5..6b34465 100644
--- a/pym/portage/tests/ebuild/test_doebuild_spawn.py
+++ b/pym/portage/tests/ebuild/test_doebuild_spawn.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2012 Gentoo Foundation
+# Copyright 2010-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import textwrap
@@ -65,6 +65,7 @@ class DoebuildSpawnTestCase(TestCase):
settings['PORTAGE_PYTHON'] = _python_interpreter
settings['PORTAGE_BUILDDIR'] = os.path.join(
settings['PORTAGE_TMPDIR'], cpv)
+   settings['PYTHONDONTWRITEBYTECODE'] = 
os.environ.get('PYTHONDONTWRITEBYTECODE', '')
settings['T'] = os.path.join(
settings['PORTAGE_BUILDDIR'], 'temp')
for x in ('PORTAGE_BUILDDIR', 'T'):

diff --git a/pym/portage/tests/ebuild/test_ipc_daemon.py 
b/pym/portage/tests/ebuild/test_ipc_daemon.py
index a871076..835f51f 100644
--- a/pym/portage/tests/ebuild/test_ipc_daemon.py
+++ b/pym/portage/tests/ebuild/test_ipc_daemon.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2012 Gentoo Foundation
+# Copyright 2010-2015 

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

2015-11-24 Thread Zac Medico
commit: 0c00530c92ecca3499c7d98fedae41a9ab559d17
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Nov 24 09:14:41 2015 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Nov 24 16:43:58 2015 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=0c00530c

depgraph: autounmask for conditional USE deps (bug 566704)

For parents with unsatisfied conditional dependencies, translate
USE change suggestions into autounmask changes.

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

 pym/_emerge/depgraph.py| 35 +-
 .../tests/resolver/test_autounmask_parent.py   | 43 ++
 2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 57040ab..f659b0a 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -4075,6 +4075,7 @@ class depgraph(object):
# Now that the root packages have been added to the graph,
# process the dependencies.
if not self._create_graph():
+   self._apply_parent_use_changes()
return 0, myfavorites
 
try:
@@ -4162,6 +4163,24 @@ class depgraph(object):
# We're true here unless we are missing binaries.
return (True, myfavorites)
 
+   def _apply_parent_use_changes(self):
+   """
+   For parents with unsatisfied conditional dependencies, translate
+   USE change suggestions into autounmask changes.
+   """
+   if (self._dynamic_config._unsatisfied_deps_for_display and
+   self._dynamic_config._autounmask):
+   remaining_items = []
+   for item in 
self._dynamic_config._unsatisfied_deps_for_display:
+   pargs, kwargs = item
+   kwargs = kwargs.copy()
+   kwargs['collect_use_changes'] = True
+   if not self._show_unsatisfied_dep(*pargs,
+   **portage._native_kwargs(kwargs)):
+   remaining_items.append(item)
+   if len(remaining_items) != 
len(self._dynamic_config._unsatisfied_deps_for_display):
+   
self._dynamic_config._unsatisfied_deps_for_display = remaining_items
+
def _set_args(self, args):
"""
Create the "__non_set_args__" package set from atoms and 
packages given as
@@ -4718,7 +4737,8 @@ class depgraph(object):
 
 
def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None,
-   check_backtrack=False, check_autounmask_breakage=False, 
show_req_use=None):
+   check_backtrack=False, check_autounmask_breakage=False, 
show_req_use=None,
+   collect_use_changes=False):
"""
When check_backtrack=True, no output is produced and
the method either returns or raises _backtrack_mask if
@@ -4962,15 +4982,28 @@ class depgraph(object):

"defined by %s: '%s'" % (myparent.cpv, \

human_readable_required_use(required_use))
 
+   target_use = {}
for flag in involved_flags:
if flag in 
self._pkg_use_enabled(myparent):
+   target_use[flag] = False

changes.append(colorize("blue", "-" + flag))
else:
+   target_use[flag] = True

changes.append(colorize("red", "+" + flag))
+
+   if collect_use_changes and not 
required_use_warning:
+   previous_changes = 
self._dynamic_config._needed_use_config_changes.get(myparent)
+   self._pkg_use_enabled(myparent, 
target_use=target_use)
+   if previous_changes is not 
self._dynamic_config._needed_use_config_changes.get(myparent):
+   return True
+
mreasons.append("Change USE: %s" % " 
".join(changes) + required_use_warning)
if (myparent, mreasons) not in 
missing_use_reasons:

missing_use_reasons.append((myparent, mreasons))
 
+   if 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/sync/, pym/portage/util/_async/, ...

2015-08-13 Thread Zac Medico
commit: 496ff326dc18890889d1ea5d2aec590394635960
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Mon Aug 10 07:42:51 2015 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Thu Aug 13 19:49:39 2015 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=496ff326

sync repositories in parallel (bug 557426)

Repos will now be synced in parallel (including their post-sync hooks),
but a given repo will only be synced after its master(s) have synced (in
case that matters for hooks). Output of concurrent processes will be mixed
(irrelevant with --quiet). Support for FEATURES=metadata-transfer will be
handled in the main process, which may be required for some backends (such
as sqlite).

X-Gentoo-Bug: 557426
X-Gentoo-Bug-url: https://bugs.gentoo.org/show_bug.cgi?id=557426
Acked-by: Brian Dolbec dolsen AT gentoo.org

 pym/portage/emaint/modules/sync/sync.py   | 129 --
 pym/portage/sync/controller.py|  31 +--
 pym/portage/tests/sync/test_sync_local.py |   6 +-
 pym/portage/util/_async/AsyncFunction.py  |  67 
 4 files changed, 219 insertions(+), 14 deletions(-)

diff --git a/pym/portage/emaint/modules/sync/sync.py 
b/pym/portage/emaint/modules/sync/sync.py
index b463073..879d0f0 100644
--- a/pym/portage/emaint/modules/sync/sync.py
+++ b/pym/portage/emaint/modules/sync/sync.py
@@ -13,6 +13,10 @@ from portage.output import bold, red, create_color_func
 from portage._global_updates import _global_updates
 from portage.sync.controller import SyncManager
 from portage.util import writemsg_level
+from portage.util.digraph import digraph
+from portage.util._async.AsyncScheduler import AsyncScheduler
+from portage.util._eventloop.global_event_loop import global_event_loop
+from portage.util._eventloop.EventLoop import EventLoop
 
 import _emerge
 from _emerge.emergelog import emergelog
@@ -201,6 +205,7 @@ class SyncRepos(object):
k = -- + k.replace(_, -)
self.emerge_config.opts[k] = v
 
+   selected_repos = [repo for repo in selected_repos if 
repo.sync_type is not None]
msgs = []
if not selected_repos:
msgs.append(Emaint sync, nothing to sync... returning)
@@ -213,13 +218,20 @@ class SyncRepos(object):
 
sync_manager = SyncManager(
self.emerge_config.target_config.settings, emergelog)
-   retvals = []
-   for repo in selected_repos:
-   if repo.sync_type is not None:
-   returncode, message = 
sync_manager.sync(self.emerge_config, repo)
-   retvals.append((repo.name, returncode))
-   if message:
-   msgs.append(message)
+
+   max_jobs = (self.emerge_config.opts.get('--jobs', 1)
+   if 'parallel-fetch' in self.emerge_config.
+   target_config.settings.features else 1)
+   sync_scheduler = SyncScheduler(emerge_config=self.emerge_config,
+   selected_repos=selected_repos, 
sync_manager=sync_manager,
+   max_jobs=max_jobs,
+   event_loop=global_event_loop() if 
portage._internal_caller else
+   EventLoop(main=False))
+
+   sync_scheduler.start()
+   sync_scheduler.wait()
+   retvals = sync_scheduler.retvals
+   msgs.extend(sync_scheduler.msgs)
 
# Reload the whole config.
portage._sync_mode = False
@@ -287,3 +299,106 @@ class SyncRepos(object):
messages.append(Action: %s for repo: %s, returned code 
= %s
% (action, rval[0], rval[1]))
return messages
+
+
+class SyncScheduler(AsyncScheduler):
+   '''
+   Sync repos in parallel, but don't sync a given repo until all
+   of its masters have synced.
+   '''
+   def __init__(self, **kwargs):
+   '''
+   @param emerge_config: an emerge_config instance
+   @param selected_repos: list of RepoConfig instances
+   @param sync_manager: a SyncManger instance
+   '''
+   self._emerge_config = kwargs.pop('emerge_config')
+   self._selected_repos = kwargs.pop('selected_repos')
+   self._sync_manager = kwargs.pop('sync_manager')
+   AsyncScheduler.__init__(self, **kwargs)
+   self._init_graph()
+   self.retvals = []
+   self.msgs = []
+
+   def _init_graph(self):
+   '''
+   Graph relationships between repos and their masters.
+   '''
+   self._sync_graph = digraph()
+   self._leaf_nodes = []
+   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/portage/tests/resolver/binpkg_multi_instance/

2015-03-04 Thread Zac Medico
commit: 6d4eb498e59ff6477b4290047bee78c77bd28676
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Tue Feb 17 22:56:47 2015 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Wed Mar  4 21:32:07 2015 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=6d4eb498

binpkg-multi-instance 4 of 7

Add a test case to verify that emerge --rebuilt-binaries works with
binpkg-multi-instance. This relies on the fact that binary packages of
the same version are ordered by BUILD_TIME, so that the latest builds
are preferred when appropriate.

 pym/portage/tests/resolver/ResolverPlayground.py   |  25 -
 .../resolver/binpkg_multi_instance/__init__.py |   2 +
 .../resolver/binpkg_multi_instance/__test__.py |   2 +
 .../binpkg_multi_instance/test_rebuilt_binaries.py | 101 +
 4 files changed, 126 insertions(+), 4 deletions(-)

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index 84ad17c..6bdf2c7 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -39,6 +39,7 @@ class ResolverPlayground(object):
 
config_files = frozenset((eapi, layout.conf, make.conf, 
package.accept_keywords,
package.keywords, package.license, package.mask, 
package.properties,
+   package.provided, packages,
package.unmask, package.use, package.use.aliases, 
package.use.stable.mask,
soname.provided,
unpack_dependencies, use.aliases, use.force, use.mask, 
layout.conf))
@@ -208,12 +209,18 @@ class ResolverPlayground(object):
raise AssertionError('digest creation failed 
for %s' % ebuild_path)
 
def _create_binpkgs(self, binpkgs):
-   for cpv, metadata in binpkgs.items():
+   # When using BUILD_ID, there can be mutiple instances for the
+   # same cpv. Therefore, binpkgs may be an iterable instead of
+   # a dict.
+   items = getattr(binpkgs, 'items', None)
+   items = items() if items is not None else binpkgs
+   for cpv, metadata in items:
a = Atom(= + cpv, allow_repo=True)
repo = a.repo
if repo is None:
repo = test_repo
 
+   pn = catsplit(a.cp)[1]
cat, pf = catsplit(a.cpv)
metadata = metadata.copy()
metadata.setdefault(SLOT, 0)
@@ -225,8 +232,13 @@ class ResolverPlayground(object):
 
repo_dir = self.pkgdir
category_dir = os.path.join(repo_dir, cat)
-   binpkg_path = os.path.join(category_dir, pf + .tbz2)
-   ensure_dirs(category_dir)
+   if BUILD_ID in metadata:
+   binpkg_path = os.path.join(category_dir, pn,
+   %s-%s.xpak% (pf, 
metadata[BUILD_ID]))
+   else:
+   binpkg_path = os.path.join(category_dir, pf + 
.tbz2)
+
+   ensure_dirs(os.path.dirname(binpkg_path))
t = portage.xpak.tbz2(binpkg_path)
t.recompose_mem(portage.xpak.xpak_mem(metadata))
 
@@ -252,6 +264,7 @@ class ResolverPlayground(object):
unknown_keys = set(metadata).difference(
portage.dbapi.dbapi._known_keys)
unknown_keys.discard(BUILD_TIME)
+   unknown_keys.discard(BUILD_ID)
unknown_keys.discard(COUNTER)
unknown_keys.discard(repository)
unknown_keys.discard(USE)
@@ -749,7 +762,11 @@ class ResolverPlaygroundResult(object):
repo_str = 
if x.repo != test_repo:
repo_str = _repo_separator + 
x.repo
-   mergelist_str = x.cpv + repo_str
+   build_id_str = 
+   if (x.type_name == binary and
+   x.cpv.build_id is not None):
+   build_id_str = -%s % 
x.cpv.build_id
+   mergelist_str = x.cpv + build_id_str + 
repo_str
if x.built:
if x.operation == merge:
desc = x.type_name

diff --git a/pym/portage/tests/resolver/binpkg_multi_instance/__init__.py 
b/pym/portage/tests/resolver/binpkg_multi_instance/__init__.py
new file mode 100644

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/lint/

2015-02-01 Thread Michał Górny
commit: 70a41bd4404502a3eacf6335c8d2c9503129
Author: Michał Górny mgorny AT gentoo DOT org
AuthorDate: Fri Jan 30 22:53:50 2015 +
Commit: Michał Górny mgorny AT gentoo DOT org
CommitDate: Sun Feb  1 09:06:41 2015 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=70a41bd4

test_compile_modules: skip files that require newer Python version

Support skipping Python modules and scripts that require newer Python
version than currently used during compile tests. Add a metadata db that
can be used to store additional information about Python files, and
store the required language version there.

---
 pym/portage/tests/lint/metadata.py | 11 +++
 pym/portage/tests/lint/test_compile_modules.py | 13 +
 2 files changed, 24 insertions(+)

diff --git a/pym/portage/tests/lint/metadata.py 
b/pym/portage/tests/lint/metadata.py
new file mode 100644
index 000..e3f90cb
--- /dev/null
+++ b/pym/portage/tests/lint/metadata.py
@@ -0,0 +1,11 @@
+# Copyright 2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+module_metadata = {
+}
+
+script_metadata = {
+   'socks5-server.py': {
+   'required_python': '3.3',
+   },
+}

diff --git a/pym/portage/tests/lint/test_compile_modules.py 
b/pym/portage/tests/lint/test_compile_modules.py
index 4826cad..51eb8cd 100644
--- a/pym/portage/tests/lint/test_compile_modules.py
+++ b/pym/portage/tests/lint/test_compile_modules.py
@@ -4,9 +4,11 @@
 import errno
 import itertools
 import stat
+import sys
 
 from portage.const import PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, 
PORTAGE_PYM_PACKAGES
 from portage.tests import TestCase
+from portage.tests.lint.metadata import module_metadata, script_metadata
 from portage import os
 from portage import _encodings
 from portage import _unicode_decode, _unicode_encode
@@ -30,6 +32,17 @@ class CompileModulesTestCase(TestCase):
st = os.lstat(x)
if not stat.S_ISREG(st.st_mode):
continue
+
+   bin_path = os.path.relpath(x, PORTAGE_BIN_PATH)
+   mod_path = os.path.relpath(x, PORTAGE_PYM_PATH)
+
+   meta = module_metadata.get(mod_path) or 
script_metadata.get(bin_path)
+   if meta:
+   req_py = tuple(int(x) for x
+   in 
meta.get('required_python', '0.0').split('.'))
+   if sys.version_info  req_py:
+   continue
+
do_compile = False
if x[-3:] == '.py':
do_compile = True



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

2015-01-18 Thread Zac Medico
commit: 1891388ea0ae0dd58903a71a3adc779731523601
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sat Jan 17 22:56:47 2015 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Sun Jan 18 18:54:24 2015 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=1891388e

emerge: default --backtrack=3 (bug #536926)

The previous default emerge --backtrack=10 setting could lead to lots
of wasted cpu time in cases where it will ultimately fail to find a
valid solution anyway. Therefore, reduce the default to --backtrack=3.

In order for the BacktrackingTestCase.testBacktrackNoWrongRebuilds to
succeed, the test now needs to specify --backtrack=6. This is a rather
obscure case though, so it does not seem worthwhile to increase the
default because of it.

X-Gentoo-Bug: 536926
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=536926
Acked-by: Brian Dolbec dolsen AT gentoo.org

---
 man/emerge.1| 2 +-
 pym/_emerge/depgraph.py | 2 +-
 pym/portage/tests/resolver/test_backtracking.py | 9 +++--
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/man/emerge.1 b/man/emerge.1
index aea7cae..fd9140f 100644
--- a/man/emerge.1
+++ b/man/emerge.1
@@ -384,7 +384,7 @@ precedence over existing changes. This option is 
automatically enabled with
 .BR \-\-backtrack=COUNT
 Specifies an integer number of times to backtrack if
 dependency calculation fails due to a conflict or an
-unsatisfied dependency (default: \'10\').
+unsatisfied dependency (default: \'3\').
 .TP
 .BR \-\-binpkg\-changed\-deps [ y | n ]
 Tells emerge to ignore binary packages for which the corresponding

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 3e9bfdd..1184dd6 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -8950,7 +8950,7 @@ def _backtrack_depgraph(settings, trees, myopts, 
myparams, myaction, myfiles, sp
 
debug = --debug in myopts
mydepgraph = None
-   max_retries = myopts.get('--backtrack', 10)
+   max_retries = myopts.get('--backtrack', 3)
max_depth = max(1, (max_retries + 1) // 2)
allow_backtracking = max_retries  0
backtracker = Backtracker(max_depth)

diff --git a/pym/portage/tests/resolver/test_backtracking.py 
b/pym/portage/tests/resolver/test_backtracking.py
index 3b69eda..6567153 100644
--- a/pym/portage/tests/resolver/test_backtracking.py
+++ b/pym/portage/tests/resolver/test_backtracking.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2014 Gentoo Foundation
+# Copyright 2010-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -154,7 +154,12 @@ class BacktrackingTestCase(TestCase):
 
world = [dev-libs/B, dev-libs/C]
 
-   options = {'--update' : True, '--deep' : True, '--selective' : 
True}
+   options = {
+   '--backtrack': 6,
+   '--deep' : True,
+   '--selective' : True,
+   '--update' : True,
+   }
 
test_cases = (
ResolverPlaygroundTestCase(



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

2015-01-18 Thread Zac Medico
commit: a9aea5f9a055e6a38acfbaa1b6190d0c627cb299
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sat Dec 20 21:08:35 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Sun Jan 18 18:39:12 2015 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=a9aea5f9

TestFakedbapi: override EPREFIX for bug #492932

For tests, override portage.const.EPREFIX in order to avoid unwanted
access to /etc/portage. This override may seem evil, but it is a
convenient way to simulate a prefix install, and it is reasonable to do
this because tests should be self-contained such that the real value
of portage.const.EPREFIX is entirely irrelevant.

X-Gentoo-Bug: 492932
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=492932
Acked-by: Brian Dolbec dolsen AT gentoo.org

---
 pym/portage/tests/dbapi/test_fakedbapi.py| 11 ++-
 pym/portage/tests/resolver/ResolverPlayground.py |  8 +++-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/pym/portage/tests/dbapi/test_fakedbapi.py 
b/pym/portage/tests/dbapi/test_fakedbapi.py
index 7713563..e4f5dd7 100644
--- a/pym/portage/tests/dbapi/test_fakedbapi.py
+++ b/pym/portage/tests/dbapi/test_fakedbapi.py
@@ -1,8 +1,9 @@
-# Copyright 2011-2013 Gentoo Foundation
+# Copyright 2011-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import tempfile
 
+import portage
 from portage import os
 from portage import shutil
 from portage.dbapi.virtual import fakedbapi
@@ -49,6 +50,14 @@ class TestFakedbapi(TestCase):
env = {
PORTAGE_REPOSITORIES: [DEFAULT]\nmain-repo = 
test_repo\n[test_repo]\nlocation = %s % test_repo
}
+
+   # Tests may override portage.const.EPREFIX in order to
+   # simulate a prefix installation. It's reasonable to do
+   # this because tests should be self-contained such that
+   # the real value of portage.const.EPREFIX is entirely
+   # irrelevant (see bug #492932).
+   portage.const.EPREFIX = tempdir
+
fakedb = 
fakedbapi(settings=config(config_profile_path=,
env=env, eprefix=tempdir))
for cpv, metadata in packages:

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index 0be5d81..b5c0446 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2014 Gentoo Foundation
+# Copyright 2010-2015 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from itertools import permutations
@@ -72,6 +72,12 @@ class ResolverPlayground(object):
self.eprefix = normalize_path(tempfile.mkdtemp())
else:
self.eprefix = normalize_path(eprefix)
+
+   # Tests may override portage.const.EPREFIX in order to
+   # simulate a prefix installation. It's reasonable to do
+   # this because tests should be self-contained such that
+   # the real value of portage.const.EPREFIX is entirely
+   # irrelevant (see bug #492932).
portage.const.EPREFIX = self.eprefix.rstrip(os.sep)
 
self.eroot = self.eprefix + os.sep



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

2015-01-05 Thread Zac Medico
commit: a9064d08ef4c92a5d0d1bfb3dc8a01b7850812b0
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sun Dec 21 04:11:30 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Mon Jan  5 19:43:59 2015 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=a9064d08

Solve more slot-operator conflicts (531656)

Add some heuristics to handle slot conflicts triggered by interaction
of slot-operator dependencies with dependencies like those of labgl:

ocaml:= || ( labltk ocaml-4.02 )

The new heuristics involve some behavior modifications in the depgraph
_solve_non_slot_operator_slot_conflicts method and in dep_zapdeps. The
dep_zapdeps changes affect the behavior of _select_atoms_probe calls
in the depgraph _slot_operator_update_probe method.

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

---
 pym/_emerge/depgraph.py   | 32 ++-
 pym/portage/dep/dep_check.py  | 16 +-
 pym/portage/tests/resolver/test_or_choices.py | 80 ++-
 3 files changed, 124 insertions(+), 4 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 28abea4..6266c79 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.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 division, print_function, unicode_literals
@@ -451,6 +451,7 @@ class _dynamic_depgraph_config(object):
self._graph_trees[myroot][graph_db]   = 
graph_tree.dbapi
self._graph_trees[myroot][graph]  = self.digraph
self._graph_trees[myroot][want_update_pkg] = 
depgraph._want_update_pkg
+   self._graph_trees[myroot][downgrade_probe] = 
depgraph._downgrade_probe
def filtered_tree():
pass
filtered_tree.dbapi = _dep_check_composite_db(depgraph, 
myroot)
@@ -478,6 +479,7 @@ class _dynamic_depgraph_config(object):
self._filtered_trees[myroot][vartree] = \
depgraph._frozen_config.trees[myroot][vartree]
self._filtered_trees[myroot][want_update_pkg] = 
depgraph._want_update_pkg
+   self._filtered_trees[myroot][downgrade_probe] = 
depgraph._downgrade_probe
 
dbs = []
#   (db, pkg_type, built, installed, 
db_keys)
@@ -1144,7 +1146,13 @@ class depgraph(object):
writemsg_level(  pkg: %s\n % pkg, 
level=logging.DEBUG, noiselevel=-1)
 
all_parent_atoms = set()
+   highest_pkg = None
+   inst_pkg = None
for pkg in conflict:
+   if pkg.installed:
+   inst_pkg = pkg
+   if highest_pkg is None or highest_pkg  pkg:
+   highest_pkg = pkg
all_parent_atoms.update(

self._dynamic_config._parent_atoms.get(pkg, []))
 
@@ -1167,6 +1175,15 @@ class depgraph(object):
 
matched = []
for pkg in conflict:
+   if (pkg is highest_pkg and
+   not highest_pkg.installed and
+   inst_pkg is not None and
+   inst_pkg.sub_slot != 
highest_pkg.sub_slot and
+   not 
self._downgrade_probe(highest_pkg)):
+   # If an upgrade is desired, 
force the highest
+   # version into the graph (bug 
#531656).
+   
non_matching_forced.add(highest_pkg)
+
if atom_set.findAtomForPackage(pkg, \

modified_use=self._pkg_use_enabled(pkg)) and \
not (is_arg_parent and 
pkg.installed):
@@ -1220,14 +1237,20 @@ class depgraph(object):
# the packages in the tuple. This way we don't have
# to choose one.
unexplored_tuples = set()
+   explored_nodes = set()
 
while unexplored:
# Handle all unexplored packages.
while unexplored:
node = unexplored.pop()
for child in 

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

2014-12-15 Thread Arfrever Frehtes Taifersar Arahesis
commit: c953151486b3cf92d931affc7fd3bb0b4fbe1a43
Author: Arfrever Frehtes Taifersar Arahesis Arfrever AT Apache DOT Org
AuthorDate: Mon Dec 15 16:26:23 2014 +
Commit: Arfrever Frehtes Taifersar Arahesis arfrever AT apache DOT org
CommitDate: Mon Dec 15 16:26:23 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c9531514

portage.tests.dbapi.test_portdb_cache: Delete deprecated code.

9 calls to deprecated 
portage.repository.config.RepoConfigLoader.mainRepoLocation()
function have been deleted.

---
 pym/portage/tests/dbapi/test_portdb_cache.py | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/pym/portage/tests/dbapi/test_portdb_cache.py 
b/pym/portage/tests/dbapi/test_portdb_cache.py
index f08d0f8..5ac9b03 100644
--- a/pym/portage/tests/dbapi/test_portdb_cache.py
+++ b/pym/portage/tests/dbapi/test_portdb_cache.py
@@ -47,7 +47,7 @@ class PortdbCacheTestCase(TestCase):
(lambda: not os.path.exists(md5_cache_dir),),
python_cmd + (textwrap.dedent(
import os, sys, portage
-   if 
portage.portdb.repositories.mainRepoLocation() in portage.portdb._pregen_auxdb:
+   if 
portage.portdb.repositories['test_repo'].location in 
portage.portdb._pregen_auxdb:
sys.exit(1)
),),
 
@@ -56,13 +56,13 @@ class PortdbCacheTestCase(TestCase):
(lambda: os.path.exists(md5_cache_dir),),
python_cmd + (textwrap.dedent(
import os, sys, portage
-   if 
portage.portdb.repositories.mainRepoLocation() not in 
portage.portdb._pregen_auxdb:
+   if 
portage.portdb.repositories['test_repo'].location not in 
portage.portdb._pregen_auxdb:
sys.exit(1)
),),
python_cmd + (textwrap.dedent(
import os, sys, portage
from portage.cache.flat_hash import md5_database
-   if not 
isinstance(portage.portdb._pregen_auxdb[portage.portdb.repositories.mainRepoLocation()],
 md5_database):
+   if not 
isinstance(portage.portdb._pregen_auxdb[portage.portdb.repositories['test_repo'].location],
 md5_database):
sys.exit(1)
),),
 
@@ -73,13 +73,13 @@ class PortdbCacheTestCase(TestCase):
(lambda: os.path.exists(md5_cache_dir),),
python_cmd + (textwrap.dedent(
import os, sys, portage
-   if 
portage.portdb.repositories.mainRepoLocation() not in 
portage.portdb._pregen_auxdb:
+   if 
portage.portdb.repositories['test_repo'].location not in 
portage.portdb._pregen_auxdb:
sys.exit(1)
),),
python_cmd + (textwrap.dedent(
import os, sys, portage
from portage.cache.flat_hash import md5_database
-   if not 
isinstance(portage.portdb._pregen_auxdb[portage.portdb.repositories.mainRepoLocation()],
 md5_database):
+   if not 
isinstance(portage.portdb._pregen_auxdb[portage.portdb.repositories['test_repo'].location],
 md5_database):
sys.exit(1)
),),
 
@@ -90,13 +90,13 @@ class PortdbCacheTestCase(TestCase):
(cache-formats = pms md5-dict, 
layout_conf_path,,
(portage_python, -b, -Wd, 
-Wi::DeprecationWarning, -c) + (textwrap.dedent(
import os, sys, portage
-   if 
portage.portdb.repositories.mainRepoLocation() not in 
portage.portdb._pregen_auxdb:
+   if 
portage.portdb.repositories['test_repo'].location not in 
portage.portdb._pregen_auxdb:
sys.exit(1)
),),
(portage_python, -b, -Wd, 
-Wi::DeprecationWarning, -c) + (textwrap.dedent(
import os, sys, portage
from portage.cache.metadata import database as 
pms_database
-   if not 
isinstance(portage.portdb._pregen_auxdb[portage.portdb.repositories.mainRepoLocation()],
 pms_database):
+   if not 
isinstance(portage.portdb._pregen_auxdb[portage.portdb.repositories['test_repo'].location],
 pms_database):
sys.exit(1)
),),
 
@@ -105,13 +105,13 

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

2014-12-02 Thread Michał Górny
commit: 8c6d7eb2b77c82b904c16ad812a794acb9731d66
Author: Michał Górny mgorny AT gentoo DOT org
AuthorDate: Sat Nov 29 22:28:06 2014 +
Commit: Michał Górny mgorny AT gentoo DOT org
CommitDate: Tue Dec  2 23:05:39 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=8c6d7eb2

Restore sbindir install support

Restore the ability to install sbin-tools into sbindir since it works
fine with pure distutils. The issue is python-exec/eclass-specific and
therefore all the relevant workarounds belong in the ebuild.

---
 pym/portage/tests/__init__.py |  4 +---
 setup.py  | 23 +++
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/pym/portage/tests/__init__.py b/pym/portage/tests/__init__.py
index afa57e3..708dd59 100644
--- a/pym/portage/tests/__init__.py
+++ b/pym/portage/tests/__init__.py
@@ -197,9 +197,7 @@ class TestCase(unittest.TestCase):
self.cnf_path = cnf_path
self.cnf_etc_path = cnf_etc_path
self.bindir = cnf_bindir
-   # sbin scripts are installed by setup.py to the bindir
-   # they are relocated to /usr/sbin dir by the ebuild later
-   self.sbindir = self.bindir
+   self.sbindir = cnf_sbindir
 
def defaultTestResult(self):
return TextTestResult()

diff --git a/setup.py b/setup.py
index dba8539..8231c0a 100755
--- a/setup.py
+++ b/setup.py
@@ -30,10 +30,12 @@ import sys
 
 x_scripts = {
'bin': [
-   'bin/archive-conf', 'bin/dispatch-conf', 'bin/ebuild', 
'bin/egencache',
-   'bin/emaint', 'bin/emerge', 'bin/emerge-webrsync', 
'bin/emirrordist',
-   'bin/env-update', 'bin/etc-update', 'bin/fixpackages', 
'bin/portageq',
-   'bin/quickpkg', 'bin/regenworld', 'bin/repoman',
+   'bin/ebuild', 'bin/egencache', 'bin/emerge', 
'bin/emerge-webrsync',
+   'bin/emirrordist', 'bin/portageq', 'bin/quickpkg', 'bin/repoman'
+   ],
+   'sbin': [
+   'bin/archive-conf', 'bin/dispatch-conf', 'bin/emaint', 
'bin/env-update',
+   'bin/etc-update', 'bin/fixpackages', 'bin/regenworld'
],
 }
 
@@ -224,6 +226,10 @@ class x_build_scripts_bin(x_build_scripts_custom):
dir_name = 'bin'
 
 
+class x_build_scripts_sbin(x_build_scripts_custom):
+   dir_name = 'sbin'
+
+
 class x_build_scripts_portagebin(x_build_scripts_custom):
dir_name = 'portage'
 
@@ -238,6 +244,7 @@ class x_build_scripts(build_scripts):
def run(self):
self.run_command('build_scripts_bin')
self.run_command('build_scripts_portagebin')
+   self.run_command('build_scripts_sbin')
 
 
 class x_clean(clean):
@@ -473,6 +480,11 @@ class x_install_scripts_bin(x_install_scripts_custom):
var_name = 'bindir'
 
 
+class x_install_scripts_sbin(x_install_scripts_custom):
+   dir_name = 'sbin'
+   var_name = 'sbindir'
+
+
 class x_install_scripts_portagebin(x_install_scripts_custom):
dir_name = 'portage'
var_name = 'portage_bindir'
@@ -488,6 +500,7 @@ class x_install_scripts(install_scripts):
def run(self):
self.run_command('install_scripts_bin')
self.run_command('install_scripts_portagebin')
+   self.run_command('install_scripts_sbin')
 
 
 class x_sdist(sdist):
@@ -624,6 +637,7 @@ setup(
'build_scripts': x_build_scripts,
'build_scripts_bin': x_build_scripts_bin,
'build_scripts_portagebin': x_build_scripts_portagebin,
+   'build_scripts_sbin': x_build_scripts_sbin,
'build_tests': build_tests,
'clean': x_clean,
'docbook': docbook,
@@ -636,6 +650,7 @@ setup(
'install_scripts': x_install_scripts,
'install_scripts_bin': x_install_scripts_bin,
'install_scripts_portagebin': x_install_scripts_portagebin,
+   'install_scripts_sbin': x_install_scripts_sbin,
'sdist': x_sdist,
'test': test,
},



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

2014-11-27 Thread Zac Medico
commit: ffbc3416f535752e50a60adfaf0d64486c50a035
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sun Nov 23 21:03:21 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Thu Nov 27 08:02:00 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=ffbc3416

make.defaults: negative incrementals in USE_EXPAND (530222)

Previously, USE_EXPAND variable settings in profile make.defaults only
supported positive incremental settings. This patch adds support for
negative settings like PYTHON_TARGETS=-python3_3, which brings
behavior into alignment with PMS.

Notably, this patch does not change behavior for settings in make.conf.
In make.conf, settings to USE_EXPAND variables remain entirely
non-incremental. PMS does not govern make.conf behavior.

X-Gentoo-Bug: 530222
X-Gentoo-Url: https://bugs.gentoo.org/show_bug.cgi?id=530222
Acked-by: Brian Dolbec dolsen AT gentoo.org

---
 pym/portage/package/ebuild/config.py   |  19 ++-
 .../tests/ebuild/test_use_expand_incremental.py| 132 +
 pym/portage/tests/resolver/ResolverPlayground.py   |  10 ++
 3 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index bf39487..01876cd 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -2332,22 +2332,21 @@ class config(object):
if v is None:
continue
prefix = k.lower() + '_'
-   if k in myincrementals:
-   for x in v.split():
-   if x[:1] == '-':
-   
expand_use.append('-' + prefix + x[1:])
-   else:
-   
expand_use.append(prefix + x)
-   else:
-   for x in v.split():
+   for x in v.split():
+   if x[:1] == '-':
+   expand_use.append('-' + 
prefix + x[1:])
+   else:

expand_use.append(prefix + x)
+
if expand_use:
expand_use.append(use)
use  = ' '.join(expand_use)
self.make_defaults_use.append(use)
self.make_defaults_use = tuple(self.make_defaults_use)
-   configdict_defaults['USE'] = ' '.join(
-   stack_lists([x.split() for x in 
self.make_defaults_use]))
+   # Preserve both positive and negative flags here, since
+   # negative flags may later interact with other flags 
pulled
+   # in via USE_ORDER.
+   configdict_defaults['USE'] = ' 
'.join(self.make_defaults_use)
# Set to None so this code only runs once.
self._make_defaults = None
 

diff --git a/pym/portage/tests/ebuild/test_use_expand_incremental.py 
b/pym/portage/tests/ebuild/test_use_expand_incremental.py
new file mode 100644
index 000..a58f08c
--- /dev/null
+++ b/pym/portage/tests/ebuild/test_use_expand_incremental.py
@@ -0,0 +1,132 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import unicode_literals
+
+import io
+
+from portage import os, _encodings
+from portage.dep import Atom
+from portage.package.ebuild.config import config
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground
+from portage.util import ensure_dirs
+
+class UseExpandIncrementalTestCase(TestCase):
+
+   def testUseExpandIncremental(self):
+
+   profiles = (
+   (
+   'base',
+   {
+   eapi: (5,),
+   parent: (..,),
+   make.defaults: (
+   INPUT_DEVICES=\keyboard 
mouse\,
+   PYTHON_TARGETS=\python2_7 
python3_3\,
+   (USE_EXPAND=\INPUT_DEVICES 
PYTHON_TARGETS 
+   VIDEO_CARDS\),
+   )
+   }
+   ),
+ 

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

2014-11-27 Thread Zac Medico
commit: 10f991041672f36b05a42752c81ffc6ede0c3326
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sun Nov 23 21:03:21 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Thu Nov 27 08:15:33 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=10f99104

make.defaults: negative incrementals in USE_EXPAND (530222)

Previously, USE_EXPAND variable settings in profile make.defaults only
supported positive incremental settings. This patch adds support for
negative settings like PYTHON_TARGETS=-python3_3, which brings
behavior into alignment with PMS.

Notably, this patch does not change behavior for settings in make.conf.
In make.conf, settings to USE_EXPAND variables remain entirely
non-incremental. PMS does not govern make.conf behavior.

X-Gentoo-Bug: 530222
X-Gentoo-Url: https://bugs.gentoo.org/show_bug.cgi?id=530222
Acked-by: Brian Dolbec dolsen AT gentoo.org

---
 pym/portage/package/ebuild/config.py   |  23 ++--
 .../tests/ebuild/test_use_expand_incremental.py| 132 +
 pym/portage/tests/resolver/ResolverPlayground.py   |  10 ++
 3 files changed, 155 insertions(+), 10 deletions(-)

diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index bf39487..c7ac486 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -2314,6 +2314,7 @@ class config(object):
# equivalent USE flags so that useful incremental behavior
# is enabled (for sub-profiles).
configdict_defaults = self.configdict['defaults']
+   defaults_use = []
if self._make_defaults is not None:
for i, cfg in enumerate(self._make_defaults):
if not cfg:
@@ -2332,22 +2333,24 @@ class config(object):
if v is None:
continue
prefix = k.lower() + '_'
-   if k in myincrementals:
-   for x in v.split():
-   if x[:1] == '-':
-   
expand_use.append('-' + prefix + x[1:])
-   else:
-   
expand_use.append(prefix + x)
-   else:
-   for x in v.split():
+   for x in v.split():
+   if x[:1] == '-':
+   expand_use.append('-' + 
prefix + x[1:])
+   else:

expand_use.append(prefix + x)
+
+   defaults_use.extend(expand_use)
+   defaults_use.extend(use.split())
+
if expand_use:
expand_use.append(use)
use  = ' '.join(expand_use)
self.make_defaults_use.append(use)
self.make_defaults_use = tuple(self.make_defaults_use)
-   configdict_defaults['USE'] = ' '.join(
-   stack_lists([x.split() for x in 
self.make_defaults_use]))
+   # Preserve both positive and negative flags here, since
+   # negative flags may later interact with other flags 
pulled
+   # in via USE_ORDER.
+   configdict_defaults['USE'] = ' '.join(defaults_use)
# Set to None so this code only runs once.
self._make_defaults = None
 

diff --git a/pym/portage/tests/ebuild/test_use_expand_incremental.py 
b/pym/portage/tests/ebuild/test_use_expand_incremental.py
new file mode 100644
index 000..a58f08c
--- /dev/null
+++ b/pym/portage/tests/ebuild/test_use_expand_incremental.py
@@ -0,0 +1,132 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import unicode_literals
+
+import io
+
+from portage import os, _encodings
+from portage.dep import Atom
+from portage.package.ebuild.config import config
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground
+from portage.util import ensure_dirs
+
+class UseExpandIncrementalTestCase(TestCase):
+
+   def testUseExpandIncremental(self):
+
+   profiles = (
+   (
+   'base',
+   {
+   eapi: (5,),

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

2014-11-27 Thread Zac Medico
commit: b9c06a6a2dd4ccc875f8b9dd3139ea582e1e5621
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sun Nov 23 21:03:21 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Thu Nov 27 08:45:40 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=b9c06a6a

make.defaults: negative incrementals in USE_EXPAND (530222)

Previously, USE_EXPAND variable settings in profile make.defaults only
supported positive incremental settings. This patch adds support for
negative settings like PYTHON_TARGETS=-python3_3, which brings
behavior into alignment with PMS.

Notably, this patch does not change behavior for settings in make.conf.
In make.conf, settings to USE_EXPAND variables remain entirely
non-incremental. PMS does not govern make.conf behavior.

X-Gentoo-Bug: 530222
X-Gentoo-Url: https://bugs.gentoo.org/show_bug.cgi?id=530222
Acked-by: Brian Dolbec dolsen AT gentoo.org

---
 pym/portage/package/ebuild/config.py   |  18 +--
 .../tests/ebuild/test_use_expand_incremental.py| 132 +
 pym/portage/tests/resolver/ResolverPlayground.py   |  10 ++
 3 files changed, 151 insertions(+), 9 deletions(-)

diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index bf39487..aca27f2 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -2332,22 +2332,22 @@ class config(object):
if v is None:
continue
prefix = k.lower() + '_'
-   if k in myincrementals:
-   for x in v.split():
-   if x[:1] == '-':
-   
expand_use.append('-' + prefix + x[1:])
-   else:
-   
expand_use.append(prefix + x)
-   else:
-   for x in v.split():
+   for x in v.split():
+   if x[:1] == '-':
+   expand_use.append('-' + 
prefix + x[1:])
+   else:

expand_use.append(prefix + x)
+
if expand_use:
expand_use.append(use)
use  = ' '.join(expand_use)
self.make_defaults_use.append(use)
self.make_defaults_use = tuple(self.make_defaults_use)
+   # Preserve both positive and negative flags here, since
+   # negative flags may later interact with other flags 
pulled
+   # in via USE_ORDER.
configdict_defaults['USE'] = ' '.join(
-   stack_lists([x.split() for x in 
self.make_defaults_use]))
+   filter(None, self.make_defaults_use))
# Set to None so this code only runs once.
self._make_defaults = None
 

diff --git a/pym/portage/tests/ebuild/test_use_expand_incremental.py 
b/pym/portage/tests/ebuild/test_use_expand_incremental.py
new file mode 100644
index 000..a58f08c
--- /dev/null
+++ b/pym/portage/tests/ebuild/test_use_expand_incremental.py
@@ -0,0 +1,132 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import unicode_literals
+
+import io
+
+from portage import os, _encodings
+from portage.dep import Atom
+from portage.package.ebuild.config import config
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground
+from portage.util import ensure_dirs
+
+class UseExpandIncrementalTestCase(TestCase):
+
+   def testUseExpandIncremental(self):
+
+   profiles = (
+   (
+   'base',
+   {
+   eapi: (5,),
+   parent: (..,),
+   make.defaults: (
+   INPUT_DEVICES=\keyboard 
mouse\,
+   PYTHON_TARGETS=\python2_7 
python3_3\,
+   (USE_EXPAND=\INPUT_DEVICES 
PYTHON_TARGETS 
+   VIDEO_CARDS\),
+   )
+   }
+   ),
+   (
+ 

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

2014-11-16 Thread Zac Medico
commit: 390f90c2bee92ee5c845cdd765824b48ed6718ad
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sun Nov 16 04:32:43 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Sun Nov 16 08:58:53 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=390f90c2

_slot_operator_update_probe: fix bug #528610

This fixes a case inside _slot_operator_update_probe where it would
select an inappropriate replacement_parent of a lower version than
desired. The problem is solved by rejecting replacement_parent if its
version is lower than the existing parent, and a downgrade is not
desired.

X-Gentoo-Bug: 528610
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=528610
Acked-by: Brian Dolbec dolsen AT gentoo.org

---
 pym/_emerge/depgraph.py|  8 +++
 ..._slot_operator_update_probe_parent_downgrade.py | 68 ++
 2 files changed, 76 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 94eaed8..2a839d0 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1659,6 +1659,7 @@ class depgraph(object):
debug = --debug in self._frozen_config.myopts
selective = selective in self._dynamic_config.myparams
want_downgrade = None
+   want_downgrade_parent = None
 
def check_reverse_dependencies(existing_pkg, candidate_pkg,
replacement_parent=None):
@@ -1706,6 +1707,13 @@ class depgraph(object):
for replacement_parent in 
self._iter_similar_available(dep.parent,
dep.parent.slot_atom, 
autounmask_level=autounmask_level):
 
+   if replacement_parent  dep.parent:
+   if want_downgrade_parent is None:
+   want_downgrade_parent = 
self._downgrade_probe(
+   dep.parent)
+   if not want_downgrade_parent:
+   continue
+
if not check_reverse_dependencies(dep.parent, 
replacement_parent):
continue
 

diff --git 
a/pym/portage/tests/resolver/test_slot_operator_update_probe_parent_downgrade.py
 
b/pym/portage/tests/resolver/test_slot_operator_update_probe_parent_downgrade.py
new file mode 100644
index 000..2ec15b6
--- /dev/null
+++ 
b/pym/portage/tests/resolver/test_slot_operator_update_probe_parent_downgrade.py
@@ -0,0 +1,68 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import \
+   ResolverPlayground, ResolverPlaygroundTestCase
+
+class SlotOperatorUpdateProbeParentDowngradeTestCase(TestCase):
+
+   def testSlotOperatorUpdateProbeParentDowngrade(self):
+
+   ebuilds = {
+   net-nds/openldap-2.4.40-r3: {
+   EAPI: 5,
+   RDEPEND: sys-libs/db-6.0:=  + \
+   || ( sys-libs/db:5.3 sys-libs/db:5.1 )
+   },
+   net-nds/openldap-2.4.40: {
+   EAPI: 5,
+   RDEPEND: sys-libs/db
+   },
+   sys-libs/db-6.0: {
+   SLOT: 6.0,
+   },
+   sys-libs/db-5.3: {
+   SLOT: 5.3,
+   },
+   }
+
+   installed = {
+   net-nds/openldap-2.4.40-r3: {
+   EAPI: 5,
+   RDEPEND: sys-libs/db-6.0:5.3/5.3=  + \
+   || ( sys-libs/db:5.3 sys-libs/db:5.1 )
+   },
+   sys-libs/db-6.0: {
+   SLOT: 6.0,
+   },
+   sys-libs/db-5.3: {
+   SLOT: 5.3,
+   },
+   }
+
+   world = (
+   net-nds/openldap,
+   )
+
+   test_cases = (
+   # bug 528610 - openldap rebuild was triggered
+   # inappropriately, due to slot_operator_update_probe
+   # selecting an inappropriate replacement parent of
+   # a lower version than desired.
+   ResolverPlaygroundTestCase(
+   [@world],
+   success = True,
+   options = { --update: True, --deep: True },
+   mergelist = []),
+   )
+
+   playground = ResolverPlayground(ebuilds=ebuilds,
+  

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

2014-11-14 Thread Zac Medico
commit: 3b08575233ecf1d3e6f31f959741a4826aeac4a9
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Fri Nov 14 06:57:45 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Fri Nov 14 17:28:19 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=3b085752

portageq: fix eroot parameter (bug #529200)

The portageq eroot parameter has been broken since commit
c9f6aa9f0151adb3c86706eaef1914cdbdcf2b6d, due to premature instantiation
of portage.settings (before the ROOT variable was set). Premature access
to the portage.settings attribute must be avoided by using other
available means to determine the EPREFIX.

Fixes: c9f6aa9f0151 (Add cross-prefix support)
X-Gentoo-Bug: 529200
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=529200
Acked-by: Alexander Berntsen bernalex AT gentoo.org

---
 bin/portageq|  9 -
 pym/portage/tests/emerge/test_simple.py | 10 --
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/bin/portageq b/bin/portageq
index 009f116..ef565d1 100755
--- a/bin/portageq
+++ b/bin/portageq
@@ -1392,7 +1392,14 @@ def main(argv):
sys.stderr.write(Run portageq with --help for info\n)
sys.stderr.flush()
sys.exit(os.EX_USAGE)
-   eprefix = portage.settings[EPREFIX]
+   # Calculate EPREFIX and ROOT that will be used to construct
+   # portage.settings later. It's tempting to use
+   # portage.settings[EPREFIX] here, but that would force
+   # instantiation of portage.settings, which we don't want to do
+   # until after we've calculated ROOT (see bug #529200).
+   eprefix = os.environ.get(EPREFIX, portage.const.EPREFIX)
+   if eprefix:
+   eprefix = portage.util.normalize_path(eprefix)
eroot = portage.util.normalize_path(argv[2])
 
if eprefix:

diff --git a/pym/portage/tests/emerge/test_simple.py 
b/pym/portage/tests/emerge/test_simple.py
index 6c20a07..0101362 100644
--- a/pym/portage/tests/emerge/test_simple.py
+++ b/pym/portage/tests/emerge/test_simple.py
@@ -217,6 +217,8 @@ pkg_preinst() {
self.assertFalse(test_ebuild is None)
 
cross_prefix = os.path.join(eprefix, cross_prefix)
+   cross_root = os.path.join(eprefix, cross_root)
+   cross_eroot = os.path.join(cross_root, eprefix.lstrip(os.sep))
 
test_commands = (
env_update_cmd,
@@ -318,6 +320,10 @@ pkg_preinst() {
portageq_cmd + (has_version, cross_prefix, 
dev-libs/A),
({EPREFIX : cross_prefix},) + \
portageq_cmd + (has_version, cross_prefix, 
dev-libs/B),
+
+   # Test ROOT support
+   ({ROOT: cross_root},) + emerge_cmd + (dev-libs/B,),
+   portageq_cmd + (has_version, cross_eroot, 
dev-libs/B),
)
 
distdir = playground.distdir
@@ -372,8 +378,8 @@ pkg_preinst() {
os.environ[__PORTAGE_TEST_HARDLINK_LOCKS]
 
updates_dir = os.path.join(test_repo_location, profiles, 
updates)
-   dirs = [cachedir, cachedir_pregen, cross_prefix, distdir, 
fake_bin,
-   portage_tmpdir, updates_dir,
+   dirs = [cachedir, cachedir_pregen, cross_eroot, cross_prefix,
+   distdir, fake_bin, portage_tmpdir, updates_dir,
user_config_dir, var_cache_edb]
etc_symlinks = (dispatch-conf.conf, etc-update.conf)
# Override things that may be unavailable, or may have 
portability



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

2014-10-27 Thread Zac Medico
commit: d3be49fe6827aa1974856dffe6d5a1aca80a7bed
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Mon Oct 27 00:32:36 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Mon Oct 27 09:21:06 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=d3be49fe

depgraph: fix bug #526160

This fixes _dep_check_composite_db to mask packages that aren't the
highest visible match, but only if an update is desirable. This causes
desirable updates to get pulled in for cases like bug #526160. The
included unit test simulates the virtual/pypy update that triggered
the bug.

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

---
 pym/_emerge/depgraph.py | 24 +
 pym/portage/tests/resolver/test_virtual_slot.py | 66 +
 2 files changed, 90 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 5180db5..78b9236 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -527,6 +527,8 @@ class depgraph(object):
self._event_loop = (portage._internal_caller and
global_event_loop() or EventLoop(main=False))
 
+   self._select_atoms_parent = None
+
self.query = UserQuery(myopts).query
 
def _load_vdb(self):
@@ -4062,11 +4064,13 @@ class depgraph(object):
self._dynamic_config._autounmask = False
# backup state for restoration, in case of recursive
# calls to this method
+   backup_parent = self._select_atoms_parent
backup_state = mytrees.copy()
try:
# clear state from previous call, in case this
# call is recursive (we have a backup, that we
# will use to restore it later)
+   self._select_atoms_parent = None
mytrees.pop(pkg_use_enabled, None)
mytrees.pop(parent, None)
mytrees.pop(atom_graph, None)
@@ -4074,6 +4078,7 @@ class depgraph(object):
 
mytrees[pkg_use_enabled] = 
self._pkg_use_enabled
if parent is not None:
+   self._select_atoms_parent = parent
mytrees[parent] = parent
mytrees[atom_graph] = atom_graph
if priority is not None:
@@ -4085,6 +4090,7 @@ class depgraph(object):
finally:
# restore state
self._dynamic_config._autounmask = 
_autounmask_backup
+   self._select_atoms_parent = backup_parent
mytrees.pop(pkg_use_enabled, None)
mytrees.pop(parent, None)
mytrees.pop(atom_graph, None)
@@ -8529,6 +8535,24 @@ class _dep_check_composite_db(dbapi):
elif not 
self._depgraph._equiv_ebuild_visible(pkg):
return False
 
+   if pkg.cp.startswith(virtual/):
+   # Force virtual updates to be pulled in when appropriate
+   # for bug #526160.
+   want_update = False
+   if self._depgraph._select_atoms_parent is not None:
+   want_update = \
+   self._depgraph._want_update_pkg(
+   self._depgraph._select_atoms_parent, 
pkg)
+
+   if want_update:
+   for new_child in 
self._depgraph._iter_similar_available(
+   pkg, next(iter(atom_set))):
+   if not 
self._depgraph._virt_deps_visible(
+   new_child, ignore_use=True):
+   continue
+   if pkg  new_child:
+   return False
+
in_graph = 
next(self._depgraph._dynamic_config._package_tracker.match(
self._root, pkg.slot_atom, installed=False), None)
 

diff --git a/pym/portage/tests/resolver/test_virtual_slot.py 
b/pym/portage/tests/resolver/test_virtual_slot.py
index 1b19d77..2e5ca7f 100644
--- a/pym/portage/tests/resolver/test_virtual_slot.py
+++ b/pym/portage/tests/resolver/test_virtual_slot.py
@@ -92,6 +92,72 @@ class VirtualSlotResolverTestCase(TestCase):
finally:

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

2014-10-22 Thread Zac Medico
commit: 1364fcd89384c9f60e6d72d7057dc00d8caba175
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Mon Sep 29 18:18:42 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Wed Oct 22 23:11:58 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=1364fcd8

Support unprivileged mode for bug #433453.

This takes the existing unprivileged prefix support and enables it to
work when EPREFIX is empty. This unprivileged mode is automatically
enabled if the current user is not root, but has write access to the
EROOT directory (not due to the 0002 bit). For use in conditional logic
(for example, see doebuild.py diff), unprivileged is automatically
added to the FEATURES variable.

X-Gentoo-Bug: 433453
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=433453

---
 pym/portage/const.py|  1 +
 pym/portage/data.py | 95 ++---
 pym/portage/package/ebuild/config.py| 21 +---
 pym/portage/package/ebuild/doebuild.py  |  4 +-
 pym/portage/tests/emerge/test_simple.py |  2 +-
 5 files changed, 83 insertions(+), 40 deletions(-)

diff --git a/pym/portage/const.py b/pym/portage/const.py
index acb90f9..d472075 100644
--- a/pym/portage/const.py
+++ b/pym/portage/const.py
@@ -189,6 +189,7 @@ SUPPORTED_FEATURES   = frozenset([
unmerge-backup,
unmerge-logs,
unmerge-orphans,
+   unprivileged,
userfetch,
userpriv,
usersandbox,

diff --git a/pym/portage/data.py b/pym/portage/data.py
index 54e3a8d..3d91e48 100644
--- a/pym/portage/data.py
+++ b/pym/portage/data.py
@@ -59,6 +59,15 @@ def portage_group_warning():
 # If the wheel group does not exist then wheelgid falls back to 0.
 # If the portage group does not exist then portage_uid falls back to 
wheelgid.
 
+# If the current user is not root, but has write access to the
+# EROOT directory (not due to the 0002 bit), then use unprivileged
+# mode which sets secpass = 2 and uses the UID and GID of the EROOT
+# directory to generate default PORTAGE_INST_GID, PORTAGE_INST_UID,
+# PORTAGE_USERNAME, and PORTAGE_GRPNAME settings.
+def _unprivileged_mode(eroot, eroot_st):
+   return os.getuid() != 0 and os.access(eroot, os.W_OK) and \
+   not eroot_st.st_mode  0o0002
+
 uid = os.getuid()
 wheelgid = 0
 try:
@@ -77,13 +86,33 @@ def _get_global(k):
if k in _initialized_globals:
return globals()[k]
 
-   if k in ('portage_gid', 'portage_uid', 'secpass'):
-   global portage_gid, portage_uid, secpass
-   secpass = 0
+   if k == 'secpass':
+
+   unprivileged = False
+   if hasattr(portage, 'settings'):
+   unprivileged = unprivileged in 
portage.settings.features
+   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))
+   try:
+   eroot_st = os.stat(eroot)
+   except OSError:
+   pass
+   else:
+   unprivileged = _unprivileged_mode(eroot, 
eroot_st)
+
+   v = 0
if uid == 0:
-   secpass = 2
-   elif portage.const.EPREFIX:
-   secpass = 2
+   v = 2
+   elif unprivileged:
+   v = 2
+   elif portage_gid in os.getgroups():
+   v = 1
+
+   elif k in ('portage_gid', 'portage_uid'):
+
#Discover the uid and gid of the portage user/group
keyerror = False
try:
@@ -98,9 +127,6 @@ def _get_global(k):
keyerror = True
portage_gid = 0
 
-   if secpass  1 and portage_gid in os.getgroups():
-   secpass = 1
-
# Suppress this error message if both PORTAGE_GRPNAME and
# PORTAGE_USERNAME are set to root, for things like
# Android (see bug #454060).
@@ -118,16 +144,15 @@ def _get_global(k):
noiselevel=-1)
portage_group_warning()
 
+   globals()['portage_gid'] = portage_gid
_initialized_globals.add('portage_gid')
+   globals()['portage_uid'] = portage_uid
_initialized_globals.add('portage_uid')
-   _initialized_globals.add('secpass')
 
if k == 'portage_gid':
return portage_gid
elif k == 'portage_uid':
return portage_uid
-   elif k == 

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

2014-10-19 Thread Zac Medico
commit: 5f7b4865ecafe4f04a92c5e1158f657b0dcd41d6
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Fri Sep 26 03:02:41 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Sun Oct 19 17:23:07 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=5f7b4865

dblink.mergeme: implement bug #523684

If a CONFIG_PROTECTed file was installed but no longer exists in the
file system, then it may have been deleted or renamed by the admin.
Therefore, force the file to be merged with a ._cfg name, so that the
admin will be prompted for this update.

X-Gentoo-Bug: 523684
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=523684

---
 pym/portage/dbapi/vartree.py| 32 
 pym/portage/tests/emerge/test_simple.py | 19 +--
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index b46ba0b..11384bf 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -4687,10 +4687,7 @@ class dblink(object):
zing = !!!
mymtime = None
protected = self.isprotected(mydest)
-   if mydmode != None:
-   # destination file exists
-
-   if stat.S_ISDIR(mydmode):
+   if mydmode is not None and 
stat.S_ISDIR(mydmode):
# install of destination is 
blocked by an existing directory with the same name
newdest = 
self._new_backup_path(mydest)
msg = []
@@ -4703,12 +4700,15 @@ class dblink(object):
self._eerror(preinst, msg)
mydest = newdest
 
-   elif stat.S_ISREG(mydmode) or 
(stat.S_ISLNK(mydmode) and os.path.exists(mydest) and 
stat.S_ISREG(os.stat(mydest)[stat.ST_MODE])):
+   elif mydmode is None or stat.S_ISREG(mydmode) 
or \
+   (stat.S_ISLNK(mydmode) and 
os.path.exists(mydest)
+   and 
stat.S_ISREG(os.stat(mydest)[stat.ST_MODE])):
# install of destination is 
blocked by an existing regular file,
# or by a symlink to an 
existing regular file;
# now, config file management 
may come into play.
# we only need to tweak mydest 
if cfg file management is in play.
-   if protected:
+   destmd5 = None
+   if protected and mydmode is not 
None:
destmd5 = 
perform_md5(mydest, calc_prelink=calc_prelink)
if protect_if_modified:
contents_key = \
@@ -4721,7 +4721,21 @@ class dblink(object):
if protected:
# we have a protection 
path; enable config file management.
cfgprot = 0
-   if mymd5 == destmd5:
+   cfgprot_force = False
+   if mydmode is None:
+   if 
self._installed_instance is not None and \
+   
self._installed_instance._match_contents(
+   
myrealdest) is not False:
+   # If 
the file doesn't exist, then it may
+   # have 
been deleted or renamed by the
+   # 
admin. Therefore, force the file to be
+   # 
merged with a ._cfg name, so that the
+   # admin 
will be prompted for this update
+   # (see 
bug #523684).
+   
cfgprot_force = True
+  

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/

2014-09-29 Thread Brian Dolbec
commit: 02ed485976fbf88a548c7b83978e23e3b50f41a2
Author: Brian Dolbec dolsen AT gentoo DOT org
AuthorDate: Mon Sep 29 21:48:20 2014 +
Commit: Brian Dolbec brian.dolbec AT gmail DOT com
CommitDate: Mon Sep 29 22:26:35 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=02ed4859

Fix travis test failures due to setup.py installing future sbin scripts in 
bindir

---
 pym/portage/tests/__init__.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pym/portage/tests/__init__.py b/pym/portage/tests/__init__.py
index 708dd59..afa57e3 100644
--- a/pym/portage/tests/__init__.py
+++ b/pym/portage/tests/__init__.py
@@ -197,7 +197,9 @@ class TestCase(unittest.TestCase):
self.cnf_path = cnf_path
self.cnf_etc_path = cnf_etc_path
self.bindir = cnf_bindir
-   self.sbindir = cnf_sbindir
+   # sbin scripts are installed by setup.py to the bindir
+   # they are relocated to /usr/sbin dir by the ebuild later
+   self.sbindir = self.bindir
 
def defaultTestResult(self):
return TextTestResult()



[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/

2014-09-19 Thread Zac Medico
commit: 52970a73754160a203e34684e7000ba6f8a47667
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Fri Sep 19 08:47:59 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Fri Sep 19 08:47:59 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=52970a73

ResolverPlayground: inline _iter_forced_rebuilds

Use an inline generator expression rather than a function, since the
function was only used once.

---
 pym/portage/tests/resolver/ResolverPlayground.py | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index 646987d..d74a410 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -778,12 +778,10 @@ class ResolverPlaygroundResult(object):
for dep_info in 
self.depgraph._dynamic_config._unsatisfied_deps_for_display)
 
if self.depgraph._forced_rebuilds:
-   self.forced_rebuilds = 
dict(self._iter_forced_rebuilds())
-
-   def _iter_forced_rebuilds(self):
-   for child_dict in self.depgraph._forced_rebuilds.values():
-   for child, parents in child_dict.items():
-   yield child.cpv, set(parent.cpv for parent in 
parents)
+   self.forced_rebuilds = dict(
+   (child.cpv, set(parent.cpv for parent in 
parents))
+   for child_dict in 
self.depgraph._forced_rebuilds.values()
+   for child, parents in child_dict.items())
 
 class ResolverPlaygroundDepcleanResult(object):
 



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

2014-09-19 Thread Zac Medico
commit: beecd610f21497609679a08f867fd88090c71fb7
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Fri Sep 19 09:16:32 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Fri Sep 19 09:16:32 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=beecd610

_backtrack_depgraph: fix bug #523048

This fixes _backtrack_depgraph to immediately report necessary
REQUIRED_USE changes instead of discarding the graph. This is
accomplished by replacing the depgraph.success_without_autounmask
method with a new need_config_change method that accounts for both
autounmask and REQUIRED_USE changes.

X-Gentoo-Bug: 523048
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=523048
Acked-by: Brian Dolbec dolsen AT gentoo.org
Acked-by: Alexander Berntsen bernalex AT gentoo.org

---
 pym/_emerge/depgraph.py| 11 ++--
 pym/portage/tests/resolver/ResolverPlayground.py   | 19 +-
 .../resolver/test_slot_operator_required_use.py| 72 ++
 3 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 6332733..e7ae720 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -421,6 +421,7 @@ class _dynamic_depgraph_config(object):
self._buildpkgonly_deps_unsatisfied = False
self._autounmask = 
depgraph._frozen_config.myopts.get('--autounmask') != 'n'
self._success_without_autounmask = False
+   self._required_use_unsatisfied = False
self._traverse_ignored_deps = False
self._complete_mode = False
self._slot_operator_deps = {}
@@ -2461,6 +2462,7 @@ class depgraph(object):

self._dynamic_config._unsatisfied_deps_for_display.append(
((pkg.root, atom),
{myparent : dep.parent, 
show_req_use : pkg}))
+   self._dynamic_config._required_use_unsatisfied 
= True
self._dynamic_config._skip_restart = True
return 0
 
@@ -8390,8 +8392,9 @@ class depgraph(object):
return self._dynamic_config._need_restart and \
not self._dynamic_config._skip_restart
 
-   def success_without_autounmask(self):
-   return self._dynamic_config._success_without_autounmask
+   def need_config_change(self):
+   return self._dynamic_config._success_without_autounmask or \
+   self._dynamic_config._required_use_unsatisfied
 
def autounmask_breakage_detected(self):
try:
@@ -8665,7 +8668,7 @@ def _backtrack_depgraph(settings, trees, myopts, 
myparams, myaction, myfiles, sp
backtrack_parameters=backtrack_parameters)
success, favorites = mydepgraph.select_files(myfiles)
 
-   if success or mydepgraph.success_without_autounmask():
+   if success or mydepgraph.need_config_change():
break
elif not allow_backtracking:
break
@@ -8677,7 +8680,7 @@ def _backtrack_depgraph(settings, trees, myopts, 
myparams, myaction, myfiles, sp
else:
break
 
-   if not (success or mydepgraph.success_without_autounmask()) and 
backtracked:
+   if not (success or mydepgraph.need_config_change()) and backtracked:
 
if debug:
writemsg_level(

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index d74a410..2d16251 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -674,7 +674,8 @@ class ResolverPlaygroundTestCase(object):
expected = x
break
elif key in (unstable_keywords, 
needed_p_mask_changes,
-   unsatisfied_deps) and expected is not None:
+   unsatisfied_deps, required_use_unsatisfied) 
and \
+   expected is not None:
expected = set(expected)
 
elif key == forced_rebuilds and expected is not None:
@@ -692,11 +693,14 @@ class ResolverPlaygroundTestCase(object):
 class ResolverPlaygroundResult(object):
 
checks = (
-   success, mergelist, use_changes, license_changes, 
unstable_keywords, slot_collision_solutions,
-   circular_dependency_solutions, needed_p_mask_changes, 
unsatisfied_deps, forced_rebuilds
+   success, mergelist, use_changes, license_changes,
+   unstable_keywords, slot_collision_solutions,
+   

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

2014-09-19 Thread Zac Medico
commit: c81f3f4586b7b6164f5038ac778098911fef9404
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Fri Sep 19 09:24:58 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Fri Sep 19 09:26:15 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c81f3f45

_solve_..slot_conflicts: fix bug #522084

Fix _solve_non_slot_operator_slot_conflicts to add all parents to the
conflict_graph, even for parents where the atom matches all relevant
nodes. Otherwise, we risk removing all of the matched nodes from the
graph, which would cause a missed update.

X-Gentoo-Bug: 522084
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=522084
Reviewed-by: Alexander Berntsen bernalex AT gentoo.org

---
 pym/_emerge/depgraph.py| 14 ++--
 .../test_solve_non_slot_operator_slot_conflicts.py | 75 ++
 2 files changed, 82 insertions(+), 7 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index e7ae720..f4e5a1b 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1172,12 +1172,15 @@ class depgraph(object):
for match in matched:
writemsg_level( match: 
%s\n % match, level=logging.DEBUG, noiselevel=-1)
 
-   if len(matched) == len(conflict):
-   # All packages match.
-   continue
+   if len(matched)  1:
+   # Even if all packages match, this 
parent must still
+   # be added to the conflict_graph. 
Otherwise, we risk
+   # removing all of these packages from 
the depgraph,
+   # which could cause a missed update 
(bug #522084).
+   conflict_graph.add(or_tuple(matched), 
parent)
elif len(matched) == 1:
conflict_graph.add(matched[0], parent)
-   elif len(matched) == 0:
+   else:
# This typically means that autounmask 
broke a
# USE-dep, but it could also be due to 
the slot
# not matching due to multislot (bug 
#220341).
@@ -1189,9 +1192,6 @@ class depgraph(object):
for pkg in conflict:
writemsg_level(
 non-match: %s\n % pkg,

level=logging.DEBUG, noiselevel=-1)
-   else:
-   # More than one packages matched, but 
not all.
-   conflict_graph.add(or_tuple(matched), 
parent)
 
for pkg in indirect_conflict_pkgs:
for parent, atom in 
self._dynamic_config._parent_atoms.get(pkg, []):

diff --git 
a/pym/portage/tests/resolver/test_solve_non_slot_operator_slot_conflicts.py 
b/pym/portage/tests/resolver/test_solve_non_slot_operator_slot_conflicts.py
new file mode 100644
index 000..c6024f4
--- /dev/null
+++ b/pym/portage/tests/resolver/test_solve_non_slot_operator_slot_conflicts.py
@@ -0,0 +1,75 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+   ResolverPlaygroundTestCase)
+
+class SolveNonSlotOperatorSlotConflictsTestCase(TestCase):
+
+   def testSolveNonSlotOperatorSlotConflicts(self):
+
+   ebuilds = {
+
+   app-misc/A-1 : {
+   EAPI: 5,
+   SLOT: 0/1,
+   PDEPEND: app-misc/B
+   },
+
+   app-misc/A-2 : {
+   EAPI: 5,
+   SLOT: 0/2,
+   PDEPEND: app-misc/B
+   },
+
+   app-misc/B-0 : {
+   EAPI: 5,
+   RDEPEND: app-misc/A:=
+   },
+
+   }
+
+   installed = {
+
+   app-misc/A-1 : {
+   EAPI: 5,
+   SLOT: 0/1,
+   PDEPEND: app-misc/B
+   },
+
+   app-misc/B-0 : {
+   EAPI: 5,
+   RDEPEND: app-misc/A:0/1=
+   },
+
+   }
+
+   world = 

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

2014-09-17 Thread Zac Medico
commit: 3f0799054b4e5ef88feb59d20d262668ca79df33
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Fri Sep 12 07:07:13 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Wed Sep 17 16:29:07 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=3f079905

_compute_abi_rebuild_info: fix bug #521990

Since self._dynamic_config._slot_operator_deps only contains deps for
packages added to the graph, it doesn't contain potentially relevant
deps of installed packages that have not been added to the graph.
Therefore, generate pseudo-deps for such installed packages, and use
those to generate the rebuild info.

X-Gentoo-Bug: 521990
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=521990

---
 pym/_emerge/depgraph.py| 100 +
 pym/portage/tests/resolver/ResolverPlayground.py   |  15 +++-
 .../resolver/test_slot_conflict_force_rebuild.py   |  84 +
 3 files changed, 183 insertions(+), 16 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index d85494a..6332733 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -647,26 +647,96 @@ class depgraph(object):
# Go through all slot operator deps and check if one of these 
deps
# has a parent that is matched by one of the atoms from above.
forced_rebuilds = {}
-   for (root, slot_atom), deps in 
self._dynamic_config._slot_operator_deps.items():
-   rebuild_atoms = atoms.get(root, set())
 
-   for dep in deps:
-   if not isinstance(dep.parent, Package):
-   continue
+   for root, rebuild_atoms in atoms.items():
 
-   if dep.parent.installed or dep.child.installed 
or \
-   dep.parent.slot_atom not in 
rebuild_atoms:
-   continue
+   for slot_atom in rebuild_atoms:
+
+   inst_pkg, reinst_pkg = \
+   self._select_pkg_from_installed(root, 
slot_atom)
 
-   # Make sure the child's slot/subslot has 
changed. If it hasn't,
-   # then another child has forced this rebuild.
-   installed_pkg = 
self._select_pkg_from_installed(root, dep.child.slot_atom)[0]
-   if installed_pkg and installed_pkg.slot == 
dep.child.slot and \
-   installed_pkg.sub_slot == 
dep.child.sub_slot:
+   if inst_pkg is reinst_pkg or reinst_pkg is None:
continue
 
-   # The child has forced a rebuild of the parent
-   forced_rebuilds.setdefault(root, 
{}).setdefault(dep.child, set()).add(dep.parent)
+   # Generate pseudo-deps for any slot-operator 
deps of
+   # inst_pkg. Its deps aren't in 
_slot_operator_deps
+   # because it hasn't been added to the graph, 
but we
+   # are interested in any rebuilds that it 
triggered.
+   built_slot_op_atoms = []
+   if inst_pkg is not None:
+   selected_atoms = 
self._select_atoms_probe(
+   inst_pkg.root, inst_pkg)
+   for atom in selected_atoms:
+   if atom.slot_operator_built:
+   
built_slot_op_atoms.append(atom)
+
+   if not built_slot_op_atoms:
+   continue
+
+   # Use a cloned list, since we may append to it 
below.
+   deps = 
self._dynamic_config._slot_operator_deps.get(
+   (root, slot_atom), [])[:]
+
+   if built_slot_op_atoms and reinst_pkg is not 
None:
+   for child in 
self._dynamic_config.digraph.child_nodes(
+   reinst_pkg):
+
+   if child.installed:
+   continue
+
+   for atom in built_slot_op_atoms:
+   # NOTE: Since atom 
comes from inst_pkg, and
+   # reinst_pkg is the 
replacement parent, there's
+   # no 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/

2014-09-16 Thread Brian Dolbec
commit: 4fcf4fa56c0033d726eb0755e3ca67b3337ad944
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sat Sep 13 00:41:00 2014 +
Commit: Brian Dolbec brian.dolbec AT gmail DOT com
CommitDate: Tue Sep 16 03:29:41 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=4fcf4fa5

Add test for bug #522652 with slot-operator

This test case uses || ( bar foo:= ) syntax that is forbidden by PMS.

---
 .../tests/resolver/test_slot_operator_rebuild.py   | 80 ++
 1 file changed, 80 insertions(+)

diff --git a/pym/portage/tests/resolver/test_slot_operator_rebuild.py 
b/pym/portage/tests/resolver/test_slot_operator_rebuild.py
new file mode 100644
index 000..42512aa
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_rebuild.py
@@ -0,0 +1,80 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+   ResolverPlaygroundTestCase)
+
+class SlotOperatorRebuildTestCase(TestCase):
+
+   def testSlotOperatorRebuild(self):
+
+   ebuilds = {
+
+   app-misc/A-1 : {
+   EAPI: 5,
+   SLOT: 0/1
+   },
+
+   app-misc/A-2 : {
+   EAPI: 5,
+   SLOT: 0/2
+   },
+
+   app-misc/B-0 : {
+   EAPI: 5,
+   RDEPEND: app-misc/A:=
+   },
+
+   app-misc/C-0 : {
+   EAPI: 5,
+   RDEPEND: || ( app-misc/X app-misc/A:= )
+   },
+
+   }
+
+   installed = {
+
+   app-misc/A-1 : {
+   EAPI: 5,
+   SLOT: 0/1
+   },
+
+   app-misc/B-0 : {
+   EAPI: 5,
+   RDEPEND: app-misc/A:0/1=
+   },
+
+   app-misc/C-0 : {
+   EAPI: 5,
+   RDEPEND: || ( app-misc/X app-misc/A:0/1= )
+   },
+
+   }
+
+   world = [app-misc/B, app-misc/C]
+
+   test_cases = (
+
+   # Test bug #522652, where the unsatisfiable app-misc/X
+   # atom is selected, and the dependency is placed into
+   # _initially_unsatisfied_deps where it is ignored, 
causing
+   # the app-misc/C-0 rebuild to be missed.
+   ResolverPlaygroundTestCase(
+   [app-misc/A],
+   options = {--dynamic-deps: n},
+   success = True,
+   ambiguous_merge_order = True,
+   mergelist = ['app-misc/A-2', ('app-misc/B-0', 
'app-misc/C-0')]
+   ),
+
+   )
+
+   playground = ResolverPlayground(ebuilds=ebuilds,
+   installed=installed, world=world, debug=False)
+   try:
+   for test_case in test_cases:
+   playground.run_TestCase(test_case)
+   self.assertEqual(test_case.test_success, True, 
test_case.fail_msg)
+   finally:
+   playground.cleanup()



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

2014-09-16 Thread Brian Dolbec
commit: 38d9d0d3aa260c29b0a49ad0933e425e8e729b07
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Tue Sep 16 17:57:49 2014 +
Commit: Brian Dolbec brian.dolbec AT gmail DOT com
CommitDate: Tue Sep 16 20:25:13 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=38d9d0d3

_solve_..slot_conflicts: fix bug #510270

This fixes an IndexError in _solve_non_slot_operator_slot_conflicts
which occurs when none of the conflict packages matched a particular
atom. This typically means that autounmask broke a USE-dep, but it could
also be due to the slot not matching due to multislot (bug #220341).
Either way, don't try to solve this conflict. Instead, force all of the
associated conflict nodes into the graph so that they are protected from
removal by the conflict solver.

X-Gentoo-Bug: 510270
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=510270

---
 pym/_emerge/depgraph.py| 14 +
 pym/portage/tests/resolver/ResolverPlayground.py   |  9 
 .../tests/resolver/test_autounmask_use_breakage.py | 63 ++
 3 files changed, 86 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index cc87d9f..d85494a 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1059,6 +1059,7 @@ class depgraph(object):
def __str__(self):
return (%s) % ,.join(str(pkg) for pkg in 
self)
 
+   non_matching_forced = set()
for conflict in conflicts:
if debug:
writemsg_level(   conflict:\n, 
level=logging.DEBUG, noiselevel=-1)
@@ -1105,6 +1106,18 @@ class depgraph(object):
continue
elif len(matched) == 1:
conflict_graph.add(matched[0], parent)
+   elif len(matched) == 0:
+   # This typically means that autounmask 
broke a
+   # USE-dep, but it could also be due to 
the slot
+   # not matching due to multislot (bug 
#220341).
+   # Either way, don't try to solve this 
conflict.
+   # Instead, force them all into the 
graph so that
+   # they are protected from removal.
+   non_matching_forced.update(conflict)
+   if debug:
+   for pkg in conflict:
+   writemsg_level(
 non-match: %s\n % pkg,
+   
level=logging.DEBUG, noiselevel=-1)
else:
# More than one packages matched, but 
not all.
conflict_graph.add(or_tuple(matched), 
parent)
@@ -1125,6 +1138,7 @@ class depgraph(object):
# Now select required packages. Collect them in the
# 'forced' set.
forced = set([non_conflict_node])
+   forced.update(non_matching_forced)
unexplored = set([non_conflict_node])
# or_tuples get special handling. We first explore
# all packages in the hope of having forced one of

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index 77a5b5c..b1974d7 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -549,6 +549,7 @@ class ResolverPlaygroundTestCase(object):
self.all_permutations = kwargs.pop(all_permutations, False)
self.ignore_mergelist_order = 
kwargs.pop(ignore_mergelist_order, False)
self.ambiguous_merge_order = 
kwargs.pop(ambiguous_merge_order, False)
+   self.ambiguous_slot_collision_solutions = 
kwargs.pop(ambiguous_slot_collision_solutions, False)
self.check_repo_names = kwargs.pop(check_repo_names, False)
self.merge_order_assertions = 
kwargs.pop(merge_order_assertions, False)
 
@@ -664,6 +665,14 @@ class ResolverPlaygroundTestCase(object):

str((node1, node2))) + \
, got: 
 + str(got))
 
+   elif key == slot_collision_solutions and \
+   self.ambiguous_slot_collision_solutions:
+   # Tests that use all_permutations can have 
multiple
+   # outcomes here.
+   for x in expected:
+   

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/resolver/, pym/portage/dep/

2014-09-14 Thread Brian Dolbec
commit: d1e8d3468d0cee24480f6cbe16b2ca82ec7dc9fa
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sat Sep 13 00:32:53 2014 +
Commit: Brian Dolbec brian.dolbec AT gmail DOT com
CommitDate: Mon Sep 15 04:00:15 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=d1e8d346

dep_zapdeps: fix bug #522652

For cases such as || ( X A-2 ), where X is unsatisfiable and A-1 is
installed, fix dep_zapdeps to make the correct choice.

---
 pym/portage/dep/dep_check.py  | 10 
 pym/portage/tests/resolver/test_or_choices.py | 73 +++
 2 files changed, 83 insertions(+)

diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
index 22eed96..4386b5e 100644
--- a/pym/portage/dep/dep_check.py
+++ b/pym/portage/dep/dep_check.py
@@ -287,6 +287,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, 
trees=None):
unsat_use_non_installed = []
other_installed = []
other_installed_some = []
+   other_installed_any_slot = []
other = []
 
# unsat_use_* must come after preferred_non_installed
@@ -301,6 +302,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, 
trees=None):
unsat_use_non_installed,
other_installed,
other_installed_some,
+   other_installed_any_slot,
other,
)
 
@@ -504,6 +506,14 @@ def dep_zapdeps(unreduced, reduced, myroot, 
use_binaries=0, trees=None):
other_installed.append(this_choice)
elif some_installed:
other_installed_some.append(this_choice)
+
+   # Use Atom(atom.cp) for a somewhat fuzzy match, since
+   # the whole atom may be too specific. For example, see
+   # bug #522652, where using the whole atom leads to an
+   # unsatisfiable choice.
+   elif any(vardb.match(Atom(atom.cp)) for atom in atoms
+   if not atom.blocker):
+   other_installed_any_slot.append(this_choice)
else:
other.append(this_choice)
 

diff --git a/pym/portage/tests/resolver/test_or_choices.py 
b/pym/portage/tests/resolver/test_or_choices.py
index 90e6814..d9d14f0 100644
--- a/pym/portage/tests/resolver/test_or_choices.py
+++ b/pym/portage/tests/resolver/test_or_choices.py
@@ -132,3 +132,76 @@ class OrChoicesTestCase(TestCase):
self.assertEqual(test_case.test_success, True, 
test_case.fail_msg)
finally:
playground.cleanup()
+
+
+   def testInitiallyUnsatisfied(self):
+
+   ebuilds = {
+
+   app-misc/A-1 : {
+   EAPI: 5,
+   SLOT: 0/1
+   },
+
+   app-misc/A-2 : {
+   EAPI: 5,
+   SLOT: 0/2
+   },
+
+   app-misc/B-0 : {
+   EAPI: 5,
+   RDEPEND: app-misc/A:=
+   },
+
+   app-misc/C-0 : {
+   EAPI: 5,
+   RDEPEND: || ( app-misc/X app-misc/A-2 )
+   },
+
+   }
+
+   installed = {
+
+   app-misc/A-1 : {
+   EAPI: 5,
+   SLOT: 0/1
+   },
+
+   app-misc/B-0 : {
+   EAPI: 5,
+   RDEPEND: app-misc/A:0/1=
+   },
+
+   app-misc/C-0 : {
+   EAPI: 5,
+   RDEPEND: || ( app-misc/X app-misc/A-2 )
+   },
+
+   }
+
+   world = [app-misc/B, app-misc/C]
+
+   test_cases = (
+
+   # Test bug #522652, where the unsatisfiable app-misc/X
+   # atom is selected, and the dependency is placed into
+   # _initially_unsatisfied_deps where it is ignored, 
causing
+   # upgrade to app-misc/A-2 (breaking a dependency of
+   # app-misc/C-0).
+   ResolverPlaygroundTestCase(
+   [app-misc/A],
+   options = {},
+   success = True,
+   mergelist = ['app-misc/A-1']
+   ),
+
+   )
+
+   playground = ResolverPlayground(ebuilds=ebuilds,
+   installed=installed, world=world, debug=False)
+   try:
+ 

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

2014-09-11 Thread Zac Medico
commit: 336ab90212c80ce9548362bf4fbdafd388c3515c
Author: Zac Medico zmedico AT gentoo DOT org
AuthorDate: Sun Sep  7 05:19:46 2014 +
Commit: Zac Medico zmedico AT gentoo DOT org
CommitDate: Thu Sep 11 21:36:08 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=336ab902

depgraph._add_dep: fix bug #520950

This handles a case which occurs when
_solve_non_slot_operator_slot_conflicts calls _create_graph. In this
case, ignore unsatisfied deps for installed packages only if their depth
is beyond the depth requested by the user and the dep was initially
unsatisfied (not broken by a slot conflict in the current graph).

Since depth is meaningless for packages that are not reachable as deep
dependencies of arguments, the _UNREACHABLE_DEPTH constant is used as
the depth value for any packages added via _complete_graph. Also, any
sets added via _complete_graph have their reset_depth attribute set to
False.

The sys.stderr - writemsg changes are necessary to ensure that the test
cases do not output unwanted error messages.

X-Gentoo-Bug: 520950
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=520950

---
 pym/_emerge/depgraph.py| 128 -
 pym/portage/tests/resolver/ResolverPlayground.py   |  11 +-
 .../test_slot_conflict_unsatisfied_deep_deps.py| 115 ++
 3 files changed, 226 insertions(+), 28 deletions(-)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index d6cd24d..cc87d9f 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -107,7 +107,7 @@ def _wildcard_set(atoms):
 
 class _frozen_depgraph_config(object):
 
-   def __init__(self, settings, trees, myopts, spinner):
+   def __init__(self, settings, trees, myopts, params, spinner):
self.settings = settings
self.target_root = settings[EROOT]
self.myopts = myopts
@@ -115,6 +115,7 @@ class _frozen_depgraph_config(object):
if settings.get(PORTAGE_DEBUG, ) == 1:
self.edebug = 1
self.spinner = spinner
+   self.requested_depth = params.get(deep, 0)
self._running_root = trees[trees._running_eroot][root_config]
self.pkgsettings = {}
self.trees = {}
@@ -502,13 +503,18 @@ class _dynamic_depgraph_config(object):
 
 class depgraph(object):
 
+   # Represents the depth of a node that is unreachable from explicit
+   # user arguments (or their deep dependencies). Such nodes are pulled
+   # in by the _complete_graph method.
+   _UNREACHABLE_DEPTH = object()
+
pkg_tree_map = RootConfig.pkg_tree_map
 
def __init__(self, settings, trees, myopts, myparams, spinner,
frozen_config=None, backtrack_parameters=BacktrackParameter(), 
allow_backtracking=False):
if frozen_config is None:
frozen_config = _frozen_depgraph_config(settings, trees,
-   myopts, spinner)
+   myopts, myparams, spinner)
self._frozen_config = frozen_config
self._dynamic_config = _dynamic_depgraph_config(self, myparams,
allow_backtracking, backtrack_parameters)
@@ -2095,6 +2101,13 @@ class depgraph(object):
arg = arg_stack.pop()
if arg in traversed_set_args:
continue
+
+   # If a node with the same hash already exists in
+   # the digraph, preserve the existing instance 
which
+   # may have a different reset_depth attribute
+   # (distiguishes user arguments from sets added 
for
+   # another reason such as complete mode).
+   arg = self._dynamic_config.digraph.get(arg, arg)
traversed_set_args.add(arg)
 
if add_to_digraph:
@@ -2114,8 +2127,16 @@ class depgraph(object):
if nested_set is None:
nested_set = 
root_config.sets.get(s)
if nested_set is not None:
+   # Propagate the reset_depth 
attribute from
+   # parent set to nested set.
nested_arg = SetArg(arg=token, 
pset=nested_set,
+   
reset_depth=arg.reset_depth,
root_config=root_config)
+
+   # Preserve instances already in 
the graph (same
+   # reason as for the arg 

[gentoo-commits] proj/portage:master commit in: pym/portage/tests/unicode/, /, pym/portage/tests/sets/files/, ...

2014-09-11 Thread Brian Dolbec
commit: 9fd70e67f3bc1ddae84b6097c5b651cce713b91a
Author: Michał Górny mgorny AT gentoo DOT org
AuthorDate: Sat Aug  9 07:54:37 2014 +
Commit: Brian Dolbec brian.dolbec AT gmail DOT com
CommitDate: Thu Sep 11 23:44:25 2014 +
URL:
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=9fd70e67

tests: Append .py to files that need to be installed

Append .py to the runTests script and __test__ files so that they could
be easily picked up by setup.py.

---
 .travis.yml | 2 +-
 Makefile| 2 +-
 pym/portage/tests/__init__.py   | 4 ++--
 pym/portage/tests/bin/{__test__ = __test__.py} | 0
 pym/portage/tests/dbapi/{__test__ = __test__.py}   | 0
 pym/portage/tests/dep/{__test__ = __test__.py} | 0
 pym/portage/tests/ebuild/{__test__ = __test__.py}  | 0
 pym/portage/tests/emerge/{__test__ = __test__.py}  | 0
 pym/portage/tests/env/{__test__ = __test__.py} | 0
 pym/portage/tests/env/config/{__test__ = __test__.py}  | 0
 pym/portage/tests/glsa/{__test__ = __test__.py}| 0
 pym/portage/tests/lafilefixer/{__test__ = __test__.py} | 0
 pym/portage/tests/lazyimport/{__test__ = __test__.py}  | 0
 pym/portage/tests/lint/{__test__ = __test__.py}| 0
 pym/portage/tests/locks/{__test__ = __test__.py}   | 0
 pym/portage/tests/news/{__test__ = __test__.py}| 0
 pym/portage/tests/process/{__test__ = __test__.py} | 0
 pym/portage/tests/repoman/{__test__ = __test__.py} | 0
 pym/portage/tests/resolver/{__test__ = __test__.py}| 0
 pym/portage/tests/{runTests = runTests.py} | 0
 pym/portage/tests/sets/base/{__test__ = __test__.py}   | 0
 pym/portage/tests/sets/files/{__test__ = __test__.py}  | 0
 pym/portage/tests/sets/shell/{__test__ = __test__.py}  | 0
 pym/portage/tests/unicode/{__test__ = __test__.py} | 0
 pym/portage/tests/update/{__test__ = __test__.py}  | 0
 pym/portage/tests/util/{__test__ = __test__.py}| 0
 pym/portage/tests/versions/{__test__ = __test__.py}| 0
 pym/portage/tests/xpak/{__test__ = __test__.py}| 0
 runtests.sh | 2 +-
 29 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 6c8d873..52ca444 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,4 +7,4 @@ python:
 - 3.4
 - pypy
 script:
-- python -b -Wd pym/portage/tests/runTests
+- python -b -Wd pym/portage/tests/runTests.py

diff --git a/Makefile b/Makefile
index 92ea195..9eb6e66 100644
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,7 @@ epydoc:
 
 test:
set -e; \
-   $(srcdir)/pym/portage/tests/runTests; \
+   $(srcdir)/pym/portage/tests/runTests.py; \
 
 install:
set -e; \

diff --git a/pym/portage/tests/__init__.py b/pym/portage/tests/__init__.py
index 84e732a..697b800 100644
--- a/pym/portage/tests/__init__.py
+++ b/pym/portage/tests/__init__.py
@@ -83,11 +83,11 @@ def getTestFromCommandLine(args, base_path):
return result
 
 def getTestDirs(base_path):
-   TEST_FILE = b'__test__'
+   TEST_FILE = b'__test__.py'
testDirs = []
 
# the os.walk help mentions relative paths as being quirky
-   # I was tired of adding dirs to the list, so now we add __test__
+   # I was tired of adding dirs to the list, so now we add __test__.py
# to each dir we want tested.
for root, dirs, files in os.walk(base_path):
try:

diff --git a/pym/portage/tests/bin/__test__ b/pym/portage/tests/bin/__test__.py
similarity index 100%
rename from pym/portage/tests/bin/__test__
rename to pym/portage/tests/bin/__test__.py

diff --git a/pym/portage/tests/dbapi/__test__ 
b/pym/portage/tests/dbapi/__test__.py
similarity index 100%
rename from pym/portage/tests/dbapi/__test__
rename to pym/portage/tests/dbapi/__test__.py

diff --git a/pym/portage/tests/dep/__test__ b/pym/portage/tests/dep/__test__.py
similarity index 100%
rename from pym/portage/tests/dep/__test__
rename to pym/portage/tests/dep/__test__.py

diff --git a/pym/portage/tests/ebuild/__test__ 
b/pym/portage/tests/ebuild/__test__.py
similarity index 100%
rename from pym/portage/tests/ebuild/__test__
rename to pym/portage/tests/ebuild/__test__.py

diff --git a/pym/portage/tests/emerge/__test__ 
b/pym/portage/tests/emerge/__test__.py
similarity index 100%
rename from pym/portage/tests/emerge/__test__
rename to pym/portage/tests/emerge/__test__.py

diff --git a/pym/portage/tests/env/__test__ b/pym/portage/tests/env/__test__.py
similarity index 100%
rename from pym/portage/tests/env/__test__
rename to pym/portage/tests/env/__test__.py

diff --git a/pym/portage/tests/env/config/__test__ 
b/pym/portage/tests/env/config/__test__.py
similarity index 100%
rename from pym/portage/tests/env/config/__test__
rename to pym/portage/tests/env/config/__test__.py

diff --git a/pym/portage/tests/glsa/__test__ 

  1   2   >