From 236ec082509b20803aa83d8144c1f3425b0446ab Mon Sep 17 00:00:00 2001 From: David Cournapeau Date: Wed, 17 Dec 2014 09:58:35 -0800 Subject: [PATCH] FEAT: first short at installing .pkg/.mpkg on OS X. --- salt/modules/darwin_pkgutil.py | 68 ++++++++++++++++++ tests/unit/modules/darwin_pkgutil_test.py | 85 +++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 salt/modules/darwin_pkgutil.py create mode 100644 tests/unit/modules/darwin_pkgutil_test.py diff --git a/salt/modules/darwin_pkgutil.py b/salt/modules/darwin_pkgutil.py new file mode 100644 index 0000000000..16498815b2 --- /dev/null +++ b/salt/modules/darwin_pkgutil.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +''' +Installer support for OS X. + +Installer is the native .pkg/.mpkg package manager for OS X. +''' +import os.path + +from salt.ext.six.moves import urllib + + +PKGUTIL = "/usr/sbin/pkgutil" + + +def __virtual__(): + ''' + Set the virtual pkg module if the os is Solaris + ''' + if __grains__['os'] == 'MacOS': + return 'darwin_pkgutil' + return False + + +def list(): + ''' + List the installed packages. + ''' + cmd = PKGUTIL + ' --pkgs' + return __salt__['cmd.run_stdout'](cmd) + + +def is_installed(package_id): + ''' + Returns whether a given package id is installed. + ''' + def has_package_id(lines): + for line in lines: + if line == package_id: + return True + return False + + cmd = PKGUTIL + ' --pkgs' + out = __salt__['cmd.run_stdout'](cmd) + return has_package_id(out.splitlines()) + + +def _install_from_path(path): + if not os.path.exists(path): + msg = "Path {0!r} does not exist, cannot install".format(path) + raise ValueError(msg) + else: + cmd = 'installer -pkg "{0}" -target /'.format(path) + return __salt__['cmd.retcode'](cmd) + + +def install(source, package_id=None): + ''' + Install a .pkg from an URI or an absolute path. + ''' + if package_id is not None and is_installed(package_id): + return '' + + uri = urllib.parse.urlparse(source) + if uri.scheme == "": + return _install_from_path(source) + else: + msg = "Unsupported scheme for source uri: {0!r}".format(uri.scheme) + raise ValueError(msg) diff --git a/tests/unit/modules/darwin_pkgutil_test.py b/tests/unit/modules/darwin_pkgutil_test.py new file mode 100644 index 0000000000..7a0b4b6774 --- /dev/null +++ b/tests/unit/modules/darwin_pkgutil_test.py @@ -0,0 +1,85 @@ +from salt.modules import darwin_pkgutil + +from salttesting import TestCase, skipIf +from salttesting.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch + + +darwin_pkgutil.__salt__ = {} + + +@skipIf(NO_MOCK, NO_MOCK_REASON) +class DarwingPkgutilTestCase(TestCase): + def test_list_installed_command(self): + # Given + r_output = "com.apple.pkg.iTunes" + + # When + mock_cmd = MagicMock(return_value=r_output) + with patch.dict(darwin_pkgutil.__salt__, {'cmd.run_stdout': mock_cmd}): + output = darwin_pkgutil.list() + + # Then + mock_cmd.assert_called_with("/usr/sbin/pkgutil --pkgs") + + def test_list_installed_output(self): + # Given + r_output = "com.apple.pkg.iTunes" + + # When + mock_cmd = MagicMock(return_value=r_output) + with patch.dict(darwin_pkgutil.__salt__, {'cmd.run_stdout': mock_cmd}): + output = darwin_pkgutil.list() + + # Then + self.assertEqual(output, r_output) + + def test_is_installed(self): + # Given + r_output = "com.apple.pkg.iTunes" + + # When + mock_cmd = MagicMock(return_value=r_output) + with patch.dict(darwin_pkgutil.__salt__, {'cmd.run_stdout': mock_cmd}): + ret = darwin_pkgutil.is_installed("com.apple.pkg.iTunes") + + # Then + self.assertTrue(ret) + + # When + with patch.dict(darwin_pkgutil.__salt__, {'cmd.run_stdout': mock_cmd}): + ret = darwin_pkgutil.is_installed("com.apple.pkg.Safari") + + # Then + self.assertFalse(ret) + + def test_install(self): + # Given + source = "/foo/bar/fubar.pkg" + package_id = "com.foo.fubar.pkg" + + # When + mock_cmd = MagicMock(return_value=True) + with patch("salt.modules.darwin_pkgutil.is_installed", + return_value=False) as is_installed: + with patch("salt.modules.darwin_pkgutil._install_from_path", + return_value=True) as _install_from_path: + ret = darwin_pkgutil.install(source, package_id) + + # Then + _install_from_path.assert_called_with(source) + + def test_install_already_there(self): + # Given + source = "/foo/bar/fubar.pkg" + package_id = "com.foo.fubar.pkg" + + # When + mock_cmd = MagicMock(return_value=True) + with patch("salt.modules.darwin_pkgutil.is_installed", + return_value=True) as is_installed: + with patch("salt.modules.darwin_pkgutil._install_from_path", + return_value=True) as _install_from_path: + ret = darwin_pkgutil.install(source, package_id) + + # Then + self.assertEqual(_install_from_path.called, 0)