From e22403958665ce210482676b029164619fb92d3d Mon Sep 17 00:00:00 2001 From: Leigh Jenkin Date: Thu, 22 Feb 2018 00:34:44 +1100 Subject: [PATCH] Fixes #12353 #20977 adds new option to galaxy cli to preserve scm meta (#34642) --- lib/ansible/cli/galaxy.py | 2 ++ lib/ansible/galaxy/role.py | 9 ++------ lib/ansible/playbook/role/requirement.py | 26 ++++++++++++++++-------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/ansible/cli/galaxy.py b/lib/ansible/cli/galaxy.py index 2c72130d07..a31a203257 100644 --- a/lib/ansible/cli/galaxy.py +++ b/lib/ansible/cli/galaxy.py @@ -91,6 +91,8 @@ class GalaxyCLI(CLI): help='Ignore errors and continue with the next specified role.') self.parser.add_option('-n', '--no-deps', dest='no_deps', action='store_true', default=False, help='Don\'t download roles listed as dependencies') self.parser.add_option('-r', '--role-file', dest='role_file', help='A file containing a list of roles to be imported') + self.parser.add_option('-g', '--keep-scm-meta', dest='keep_scm_meta', action='store_true', + default=False, help='Use tar instead of the scm archive option when packaging the role') elif self.action == "remove": self.parser.set_usage("usage: %prog remove role1 role2 ...") elif self.action == "list": diff --git a/lib/ansible/galaxy/role.py b/lib/ansible/galaxy/role.py index dad7002404..c9d8ddd3eb 100644 --- a/lib/ansible/galaxy/role.py +++ b/lib/ansible/galaxy/role.py @@ -194,17 +194,12 @@ class GalaxyRole(object): return False def install(self): - # the file is a tar, so open it that way and extract it - # to the specified (or default) roles directory - local_file = False if self.scm: # create tar file from scm url - tmp_file = RoleRequirement.scm_archive_role(**self.spec) + tmp_file = RoleRequirement.scm_archive_role(keep_scm_meta=self.options.keep_scm_meta, **self.spec) elif self.src: if os.path.isfile(self.src): - # installing a local tar.gz - local_file = True tmp_file = self.src elif '://' in self.src: role_data = self.src @@ -337,7 +332,7 @@ class GalaxyRole(object): # return the parsed yaml metadata display.display("- %s was installed successfully" % str(self)) - if not local_file: + if not (self.src and os.path.isfile(self.src)): try: os.unlink(tmp_file) except (OSError, IOError) as e: diff --git a/lib/ansible/playbook/role/requirement.py b/lib/ansible/playbook/role/requirement.py index cbad40b537..c0e4a56933 100644 --- a/lib/ansible/playbook/role/requirement.py +++ b/lib/ansible/playbook/role/requirement.py @@ -23,6 +23,7 @@ import os import shutil import subprocess import tempfile +import tarfile from ansible.errors import AnsibleError from ansible.module_utils.six import string_types @@ -182,7 +183,7 @@ class RoleRequirement(RoleDefinition): return role @staticmethod - def scm_archive_role(src, scm='git', name=None, version='HEAD'): + def scm_archive_role(src, scm='git', name=None, version='HEAD', keep_scm_meta=False): if scm not in ['hg', 'git']: raise AnsibleError("- scm %s is not currently supported" % scm) tempdir = tempfile.mkdtemp() @@ -208,24 +209,31 @@ class RoleRequirement(RoleDefinition): raise AnsibleError("- command %s failed in directory %s (rc=%s)" % (' '.join(checkout_cmd), tempdir, rc)) temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.tar') - if scm == 'hg': + archive_cmd = None + if keep_scm_meta: + display.vvv('tarring %s from %s to %s' % (name, tempdir, temp_file.name)) + with tarfile.open(temp_file.name, "w") as tar: + tar.add(os.path.join(tempdir, name), arcname=name) + elif scm == 'hg': archive_cmd = ['hg', 'archive', '--prefix', "%s/" % name] if version: archive_cmd.extend(['-r', version]) archive_cmd.append(temp_file.name) - if scm == 'git': + elif scm == 'git': archive_cmd = ['git', 'archive', '--prefix=%s/' % name, '--output=%s' % temp_file.name] if version: archive_cmd.append(version) else: archive_cmd.append('HEAD') - with open('/dev/null', 'w') as devnull: - popen = subprocess.Popen(archive_cmd, cwd=os.path.join(tempdir, name), - stderr=devnull, stdout=devnull) - rc = popen.wait() - if rc != 0: - raise AnsibleError("- command %s failed in directory %s (rc=%s)" % (' '.join(archive_cmd), tempdir, rc)) + if archive_cmd is not None: + display.vvv('archiving %s' % archive_cmd) + with open('/dev/null', 'w') as devnull: + popen = subprocess.Popen(archive_cmd, cwd=os.path.join(tempdir, name), + stderr=devnull, stdout=devnull) + rc = popen.wait() + if rc != 0: + raise AnsibleError("- command %s failed in directory %s (rc=%s)" % (' '.join(archive_cmd), tempdir, rc)) shutil.rmtree(tempdir, ignore_errors=True) return temp_file.name