From d257e2be8cd06d41be1c223c37bc5d8df93ac545 Mon Sep 17 00:00:00 2001 From: Conrado Buhrer Date: Mon, 26 Jan 2015 12:56:35 -0200 Subject: [PATCH 1/5] added: build-dep to apt module #349 Original code provided by @nathanhruby --- packaging/os/apt.py | 46 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/packaging/os/apt.py b/packaging/os/apt.py index 9f5b8fd4cda..02576ef1a74 100644 --- a/packaging/os/apt.py +++ b/packaging/os/apt.py @@ -82,6 +82,12 @@ options: required: false default: "yes" choices: [ "yes", "safe", "full", "dist"] + build_dep: + description: + - Instead, install the build dependencies for the named pkg (equivalent to 'apt-get build-dep foo') + required: false + default: "no" + choises: [ "yes", "no" ] dpkg_options: description: - Add dpkg options to apt command. Defaults to '-o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold"' @@ -133,6 +139,9 @@ EXAMPLES = ''' # Install a .deb package - apt: deb=/tmp/mypackage.deb + +# Install the build dependencies for package "foo" +- apt: pkg=foo build_dep=yes ''' @@ -484,6 +493,37 @@ def upgrade(m, mode="yes", force=False, default_release=None, m.exit_json(changed=False, msg=out, stdout=out, stderr=err) m.exit_json(changed=True, msg=out, stdout=out, stderr=err) +def build_dep(m, pkgspec, cache, force=False, + dpkg_options=expand_dpkg_options(DPKG_OPTIONS)): + if m.check_mode: + check_arg = '--simulate' + else: + check_arg = '' + + if force: + force_yes = '--force-yes' + else: + force_yes = '' + + packages = '' + pkgspec = expand_pkgspec_from_fnmatches(m, pkgspec, cache) + for package in pkgspec: + name, version = package_split(package) + packages += "'%s' " % package + if len(packages) == 0: + m.exit_json(changed=False) + else: + for (k,v) in APT_ENV_VARS.iteritems(): + os.environ[k] = v + apt_cmd_path = m.get_bin_path(APT_GET_CMD, required=True) + cmd = '%s -y %s %s %s build-dep %s' % (apt_cmd_path, dpkg_options, force_yes, check_arg, packages) + rc, out, err = m.run_command(cmd) + if rc: + m.fail_json(msg="'%s' failed: %s" % (cmd, err), stdout=out) + if APT_GET_ZERO in out: + m.exit_json(changed=False, msg=out, stdout=out, stderr=err) + m.exit_json(changed=True, msg=out, stdout=out, stderr=err) + def main(): module = AnsibleModule( argument_spec = dict( @@ -497,10 +537,11 @@ def main(): install_recommends = dict(default='yes', aliases=['install-recommends'], type='bool'), force = dict(default='no', type='bool'), upgrade = dict(choices=['yes', 'safe', 'full', 'dist']), + build_dep = dict(default='no', type='bool'), dpkg_options = dict(default=DPKG_OPTIONS) ), mutually_exclusive = [['package', 'upgrade', 'deb']], - required_one_of = [['package', 'upgrade', 'update_cache', 'deb']], + required_one_of = [['package', 'upgrade', 'update_cache', 'build-dep', 'deb']], supports_check_mode = True ) @@ -595,6 +636,9 @@ def main(): if latest and '=' in package: module.fail_json(msg='version number inconsistent with state=latest: %s' % package) + if p['build_dep']: + build_dep(module, packages, cache, force=force_yes, dpkg_options=dpkg_options) + if p['state'] == 'latest': result = install(module, packages, cache, upgrade=True, default_release=p['default_release'], From 711005fe9b61b3ba533928ba68203a08eb53d2a4 Mon Sep 17 00:00:00 2001 From: Conrado Buhrer Date: Mon, 26 Jan 2015 15:36:35 -0200 Subject: [PATCH 2/5] changed: state=build-dep; refactored into install() --- packaging/os/apt.py | 78 +++++++++++---------------------------------- 1 file changed, 19 insertions(+), 59 deletions(-) diff --git a/packaging/os/apt.py b/packaging/os/apt.py index 02576ef1a74..b629a762c1f 100644 --- a/packaging/os/apt.py +++ b/packaging/os/apt.py @@ -34,10 +34,10 @@ options: default: null state: description: - - Indicates the desired package state. C(latest) ensures that the latest version is installed. + - Indicates the desired package state. C(latest) ensures that the latest version is installed. C(build-dep) ensures the package build dependencies are installed. required: false default: present - choices: [ "latest", "absent", "present" ] + choices: [ "latest", "absent", "present", "build-dep" ] update_cache: description: - Run the equivalent of C(apt-get update) before the operation. Can be run as part of the package installation or as a separate step. @@ -82,12 +82,6 @@ options: required: false default: "yes" choices: [ "yes", "safe", "full", "dist"] - build_dep: - description: - - Instead, install the build dependencies for the named pkg (equivalent to 'apt-get build-dep foo') - required: false - default: "no" - choises: [ "yes", "no" ] dpkg_options: description: - Add dpkg options to apt command. Defaults to '-o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold"' @@ -141,7 +135,7 @@ EXAMPLES = ''' - apt: deb=/tmp/mypackage.deb # Install the build dependencies for package "foo" -- apt: pkg=foo build_dep=yes +- apt: pkg=foo state=build-dep ''' @@ -308,13 +302,18 @@ def expand_pkgspec_from_fnmatches(m, pkgspec, cache): def install(m, pkgspec, cache, upgrade=False, default_release=None, install_recommends=True, force=False, - dpkg_options=expand_dpkg_options(DPKG_OPTIONS)): + dpkg_options=expand_dpkg_options(DPKG_OPTIONS), + build_dep=False): pkg_list = [] packages = "" pkgspec = expand_pkgspec_from_fnmatches(m, pkgspec, cache) for package in pkgspec: name, version = package_split(package) installed, upgradable, has_files = package_status(m, name, version, cache, state='install') + if build_dep: + # Let apt decide what to install + pkg_list.append("'%s'" % package) + continue if not installed or (upgrade and upgradable): pkg_list.append("'%s'" % package) if installed and upgradable and version: @@ -341,7 +340,10 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None, for (k,v) in APT_ENV_VARS.iteritems(): os.environ[k] = v - cmd = "%s -y %s %s %s install %s" % (APT_GET_CMD, dpkg_options, force_yes, check_arg, packages) + if build_dep: + cmd = "%s -y %s %s %s build-dep %s" % (APT_GET_CMD, dpkg_options, force_yes, check_arg, packages) + else: + cmd = "%s -y %s %s %s install %s" % (APT_GET_CMD, dpkg_options, force_yes, check_arg, packages) if default_release: cmd += " -t '%s'" % (default_release,) @@ -350,7 +352,7 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None, rc, out, err = m.run_command(cmd) if rc: - return (False, dict(msg="'apt-get install %s' failed: %s" % (packages, err), stdout=out, stderr=err)) + return (False, dict(msg="'%s' failed: %s" % (cmd, err), stdout=out, stderr=err)) else: return (True, dict(changed=True, stdout=out, stderr=err)) else: @@ -493,41 +495,10 @@ def upgrade(m, mode="yes", force=False, default_release=None, m.exit_json(changed=False, msg=out, stdout=out, stderr=err) m.exit_json(changed=True, msg=out, stdout=out, stderr=err) -def build_dep(m, pkgspec, cache, force=False, - dpkg_options=expand_dpkg_options(DPKG_OPTIONS)): - if m.check_mode: - check_arg = '--simulate' - else: - check_arg = '' - - if force: - force_yes = '--force-yes' - else: - force_yes = '' - - packages = '' - pkgspec = expand_pkgspec_from_fnmatches(m, pkgspec, cache) - for package in pkgspec: - name, version = package_split(package) - packages += "'%s' " % package - if len(packages) == 0: - m.exit_json(changed=False) - else: - for (k,v) in APT_ENV_VARS.iteritems(): - os.environ[k] = v - apt_cmd_path = m.get_bin_path(APT_GET_CMD, required=True) - cmd = '%s -y %s %s %s build-dep %s' % (apt_cmd_path, dpkg_options, force_yes, check_arg, packages) - rc, out, err = m.run_command(cmd) - if rc: - m.fail_json(msg="'%s' failed: %s" % (cmd, err), stdout=out) - if APT_GET_ZERO in out: - m.exit_json(changed=False, msg=out, stdout=out, stderr=err) - m.exit_json(changed=True, msg=out, stdout=out, stderr=err) - def main(): module = AnsibleModule( argument_spec = dict( - state = dict(default='present', choices=['installed', 'latest', 'removed', 'absent', 'present']), + state = dict(default='present', choices=['installed', 'latest', 'removed', 'absent', 'present', 'build-dep']), update_cache = dict(default=False, aliases=['update-cache'], type='bool'), cache_valid_time = dict(type='int'), purge = dict(default=False, type='bool'), @@ -537,7 +508,6 @@ def main(): install_recommends = dict(default='yes', aliases=['install-recommends'], type='bool'), force = dict(default='no', type='bool'), upgrade = dict(choices=['yes', 'safe', 'full', 'dist']), - build_dep = dict(default='no', type='bool'), dpkg_options = dict(default=DPKG_OPTIONS) ), mutually_exclusive = [['package', 'upgrade', 'deb']], @@ -636,23 +606,13 @@ def main(): if latest and '=' in package: module.fail_json(msg='version number inconsistent with state=latest: %s' % package) - if p['build_dep']: - build_dep(module, packages, cache, force=force_yes, dpkg_options=dpkg_options) - - if p['state'] == 'latest': + if p['state'] in ('latest', 'present', 'build-dep'): + build_dep = p.get('build-dep', False) result = install(module, packages, cache, upgrade=True, default_release=p['default_release'], install_recommends=install_recommends, - force=force_yes, dpkg_options=dpkg_options) - (success, retvals) = result - if success: - module.exit_json(**retvals) - else: - module.fail_json(**retvals) - elif p['state'] == 'present': - result = install(module, packages, cache, default_release=p['default_release'], - install_recommends=install_recommends,force=force_yes, - dpkg_options=dpkg_options) + force=force_yes, dpkg_options=dpkg_options, + build_dep=build_dep) (success, retvals) = result if success: module.exit_json(**retvals) From ef3f486f6e88ddb2770789c3c8a793042d5bbaec Mon Sep 17 00:00:00 2001 From: Conrado Buhrer Date: Mon, 26 Jan 2015 17:32:34 -0200 Subject: [PATCH 3/5] fixed: removed build-deb from required_one_of --- packaging/os/apt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/os/apt.py b/packaging/os/apt.py index b629a762c1f..e00ec4b98d7 100644 --- a/packaging/os/apt.py +++ b/packaging/os/apt.py @@ -511,7 +511,7 @@ def main(): dpkg_options = dict(default=DPKG_OPTIONS) ), mutually_exclusive = [['package', 'upgrade', 'deb']], - required_one_of = [['package', 'upgrade', 'update_cache', 'build-dep', 'deb']], + required_one_of = [['package', 'upgrade', 'update_cache', 'deb']], supports_check_mode = True ) From 3155656eef66d94855b8548a682250a64ae0710e Mon Sep 17 00:00:00 2001 From: Conrado Buhrer Date: Mon, 26 Jan 2015 17:48:03 -0200 Subject: [PATCH 4/5] fixed: missing check for upgrade flag --- packaging/os/apt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/os/apt.py b/packaging/os/apt.py index e00ec4b98d7..93809602afa 100644 --- a/packaging/os/apt.py +++ b/packaging/os/apt.py @@ -608,7 +608,8 @@ def main(): if p['state'] in ('latest', 'present', 'build-dep'): build_dep = p.get('build-dep', False) - result = install(module, packages, cache, upgrade=True, + upgrade = p.get('latest', False) + result = install(module, packages, cache, upgrade=upgrade, default_release=p['default_release'], install_recommends=install_recommends, force=force_yes, dpkg_options=dpkg_options, From a5114bfa398ec5c1c39f3c36dcf9368075d5a312 Mon Sep 17 00:00:00 2001 From: Conrado Buhrer Date: Mon, 26 Jan 2015 18:16:42 -0200 Subject: [PATCH 5/5] fixed: erroneous logic --- packaging/os/apt.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packaging/os/apt.py b/packaging/os/apt.py index 93809602afa..90d1716e2ca 100644 --- a/packaging/os/apt.py +++ b/packaging/os/apt.py @@ -607,8 +607,12 @@ def main(): module.fail_json(msg='version number inconsistent with state=latest: %s' % package) if p['state'] in ('latest', 'present', 'build-dep'): - build_dep = p.get('build-dep', False) - upgrade = p.get('latest', False) + upgrade = False + build_dep = False + if p['state'] == 'latest': + upgrade = True + if p['state'] == 'build-dep': + build_dep = True result = install(module, packages, cache, upgrade=upgrade, default_release=p['default_release'], install_recommends=install_recommends,