portage_util: improve Classify return value and add tests
The return value of this func is getting a bit out of hand as we add
more classifications, so turn it into a named tuple. The func lacks
direct testing, so add some unittests.
In the process, notice that we mishandle trailing comments on KEYWORDS
lines, so fix that too.
BUG=chromium:997354
TEST=`./run_tests` passes
Change-Id: Id9090fd7b92f272e6e1ac6cb1f44288223d4d2c7
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1929751
Reviewed-by: Alex Klein <saklein@chromium.org>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
diff --git a/lib/portage_util.py b/lib/portage_util.py
index d3c7bcc..57d1e2f 100644
--- a/lib/portage_util.py
+++ b/lib/portage_util.py
@@ -352,6 +352,11 @@
super(EbuildFormatIncorrectError, self).__init__(message)
+# Container for Classify return values.
+EBuildClassifyAttributes = collections.namedtuple('EBuildClassifyAttributes', (
+ 'is_workon', 'is_stable', 'is_blacklisted', 'has_test'))
+
+
class EBuild(object):
"""Wrapper class for information about an ebuild."""
@@ -540,7 +545,10 @@
if EBuild._ECLASS_IMPLIES_TEST & eclasses:
has_test = True
elif line.startswith('KEYWORDS='):
- for keyword in line.split('=', 1)[1].strip('"\'').split():
+ # Strip off the comments, then extract the value of the variable, then
+ # strip off any quotes.
+ line = line.split('#', 1)[0].split('=', 1)[1].strip('"\'')
+ for keyword in line.split():
if not keyword.startswith('~') and keyword != '-*':
is_stable = True
elif line.startswith('CROS_WORKON_BLACKLIST='):
@@ -549,7 +557,8 @@
line.startswith('platform_pkg_test()')):
has_test = True
fileinput.close()
- return is_workon, is_stable, is_blacklisted, has_test
+ return EBuildClassifyAttributes(
+ is_workon, is_stable, is_blacklisted, has_test)
def _ReadEBuild(self, path):
"""Determine the settings of `is_workon`, `is_stable` and is_blacklisted
diff --git a/lib/portage_util_unittest.py b/lib/portage_util_unittest.py
index 1cf987c..cca890f 100644
--- a/lib/portage_util_unittest.py
+++ b/lib/portage_util_unittest.py
@@ -243,6 +243,44 @@
self.assertFalse(
AlmostSameEBuilds(self._EBUILD_BASE, self._EBUILD_DIFFERENT_CONTENT))
+ def testClassifySimple(self):
+ """Test Classify on a simple ebuild."""
+ ebuild_path = os.path.join(self.tempdir, 'foo-1.ebuild')
+ osutils.WriteFile(ebuild_path, '')
+ attrs = portage_util.EBuild.Classify(ebuild_path)
+ self.assertFalse(attrs.is_workon)
+ self.assertFalse(attrs.is_stable)
+ self.assertFalse(attrs.is_blacklisted)
+ self.assertFalse(attrs.has_test)
+
+ def testClassifyUnstable(self):
+ """Test Classify handling of non-stable KEYWORDS."""
+ ebuild_path = os.path.join(self.tempdir, 'foo-1.ebuild')
+ TESTS = (
+ 'KEYWORDS=',
+ 'KEYWORDS= # Yep.',
+ 'KEYWORDS="-*"',
+ 'KEYWORDS="-* ~arm"',
+ 'KEYWORDS="~*"',
+ )
+ for keywords in TESTS:
+ osutils.WriteFile(ebuild_path, keywords)
+ attrs = portage_util.EBuild.Classify(ebuild_path)
+ self.assertFalse(attrs.is_stable, msg='Failing: %s' % (keywords,))
+
+ def testClassifyStable(self):
+ """Test Classify handling of stable KEYWORDS."""
+ ebuild_path = os.path.join(self.tempdir, 'foo-1.ebuild')
+ TESTS = (
+ 'KEYWORDS="*"',
+ 'KEYWORDS="*" # Yep.',
+ 'KEYWORDS="-* arm"',
+ )
+ for keywords in TESTS:
+ osutils.WriteFile(ebuild_path, keywords)
+ attrs = portage_util.EBuild.Classify(ebuild_path)
+ self.assertTrue(attrs.is_stable, msg='Failing: %s' % (keywords,))
+
class ProjectAndPathTest(cros_test_lib.MockTempDirTestCase):
"""Project and Path related tests."""
diff --git a/service/dependency.py b/service/dependency.py
index 4b6d2da..72e08d3 100644
--- a/service/dependency.py
+++ b/service/dependency.py
@@ -201,11 +201,11 @@
buildroot = os.path.join(constants.CHROOT_SOURCE_ROOT, 'src')
manifest = git.ManifestCheckout.Cached(buildroot)
for package, ebuild_path in packages_to_ebuild_paths.items():
- is_workon, _, is_blacklisted, _ = portage_util.EBuild.Classify(ebuild_path)
- if (not is_workon or
+ attrs = portage_util.EBuild.Classify(ebuild_path)
+ if (not attrs.is_workon or
# Blacklisted ebuild is pinned to a specific git sha1, so change in
# that repo matter to the ebuild.
- is_blacklisted):
+ attrs.is_blacklisted):
continue
ebuild = portage_util.EBuild(ebuild_path)
workon_subtrees = ebuild.GetSourceInfo(buildroot, manifest).subtrees