diff --git a/bindep/depends.py b/bindep/depends.py index 41763e3..2066d41 100644 --- a/bindep/depends.py +++ b/bindep/depends.py @@ -384,6 +384,9 @@ class Depends(object): elif distro_id in ["arch"]: atoms.add("pacman") self.platform = Pacman() + elif distro_id in ["alpine"]: + atoms.add("apk") + self.platform = Apk() else: self.platform = Unknown() return ["platform:%s" % (atom,) for atom in sorted(atoms)] @@ -530,6 +533,30 @@ class Pacman(Platform): return elements[1] +class Apk(Platform): + """apk (Alpine Linux) specific implementation. + + This shells out to apk + """ + + def get_pkg_version(self, pkg_name): + try: + output = subprocess.check_output( + ['apk', 'version', pkg_name], + stderr=subprocess.STDOUT).decode(getpreferredencoding(False)) + except subprocess.CalledProcessError as e: + if e.returncode == 1: + return None + raise + # output looks like + # version + output = output.strip() + elements = output.split() + if len(elements) < 4: + return None + return elements[4] + + def _eval_diff(operator, diff): """Return the boolean result for operator given diff. diff --git a/bindep/tests/fixtures/alpine/etc/os-release b/bindep/tests/fixtures/alpine/etc/os-release new file mode 100644 index 0000000..672f4e5 --- /dev/null +++ b/bindep/tests/fixtures/alpine/etc/os-release @@ -0,0 +1,6 @@ +NAME="Alpine Linux" +ID=alpine +VERSION_ID=3.7.0 +PRETTY_NAME="Alpine Linux v3.7" +HOME_URL="http://alpinelinux.org" +BUG_REPORT_URL="http://bugs.alpinelinux.org" diff --git a/bindep/tests/test_depends.py b/bindep/tests/test_depends.py index 2fb5ad1..a737ac2 100644 --- a/bindep/tests/test_depends.py +++ b/bindep/tests/test_depends.py @@ -37,6 +37,7 @@ from bindep.depends import Dpkg from bindep.depends import Emerge from bindep.depends import Pacman from bindep.depends import Rpm +from bindep.depends import Apk # NOTE(notmorgan): In python3 subprocess.check_output returns bytes not @@ -195,6 +196,12 @@ class TestDepends(TestCase): self.assertThat( depends.platform_profiles(), Contains("platform:ubuntu")) + def test_detects_alpine(self): + with DistroFixture("Alpine"): + depends = Depends("") + self.assertThat( + depends.platform_profiles(), Contains("platform:alpine")) + def test_detects_release(self): with DistroFixture("Ubuntu"): depends = Depends("") @@ -263,6 +270,13 @@ class TestDepends(TestCase): depends.platform_profiles(), Contains("platform:dpkg")) self.assertIsInstance(depends.platform, Dpkg) + def test_alpine_implies_apk(self): + with DistroFixture("Alpine"): + depends = Depends("") + self.assertThat( + depends.platform_profiles(), Contains("platform:apk")) + self.assertIsInstance(depends.platform, Apk) + def test_arch_implies_pacman(self): with DistroFixture("Arch"): depends = Depends("") @@ -678,6 +692,36 @@ class TestPacman(TestCase): stderr=subprocess.STDOUT) +class TestApk(TestCase): + + def test_unknown_package(self): + platform = Apk() + + def _side_effect_raise(*args, **kwargs): + raise subprocess.CalledProcessError( + 1, [], b"Installed: Available:") + + mock_checkoutput = self.useFixture( + fixtures.MockPatchObject(subprocess, "check_output")).mock + mock_checkoutput.side_effect = _side_effect_raise + + self.assertEqual(None, platform.get_pkg_version("foo")) + mock_checkoutput.assert_called_once_with( + ['apk', 'version', 'foo'], + stderr=subprocess.STDOUT) + self.assertEqual(None, platform.get_pkg_version("foo")) + + def test_installed_version(self): + platform = Apk() + mock_checkoutput = self.useFixture( + fixtures.MockPatchObject(subprocess, "check_output")).mock + mock_checkoutput.return_value = b'Insd: Able: foo-4.0.0-r1 = 4.0.0-r1' + self.assertEqual('4.0.0-r1', platform.get_pkg_version("foo")) + mock_checkoutput.assert_called_once_with( + ['apk', 'version', 'foo'], + stderr=subprocess.STDOUT) + + class TestRpm(TestCase): # NOTE: test_not_installed is not implemented as rpm seems to only be aware