Improve galaxy handling of tgz roles

Gerrithub presents tgz downloads that do not have a containing
directory. This causes a stack trace.

As all roles must contain a meta/main.yml, change ansible-galaxy
to use that to determine the enclosing directory (in the case
of multiple meta/main.yml files, use the one with the shortest parent)

Fixes #15413
This commit is contained in:
Will Thames 2016-04-14 13:26:15 +10:00 committed by Brian Coca
parent 2797cff773
commit 19d390135e

View file

@ -272,8 +272,17 @@ class GalaxyRole(object):
# next find the metadata file
for member in members:
if self.META_MAIN in member.name:
meta_file = member
break
# Look for parent of meta/main.yml
# Due to possibility of sub roles each containing meta/main.yml
# look for shortest length parent
meta_parent_dir = os.path.dirname(os.path.dirname(member.name))
if not meta_file:
archive_parent_dir = meta_parent_dir
meta_file = member
else:
if len(meta_parent_dir) < len(archive_parent_dir):
archive_parent_dir = meta_parent_dir
meta_file = member
if not meta_file:
raise AnsibleError("this role does not appear to have a meta/main.yml file.")
else:
@ -282,9 +291,9 @@ class GalaxyRole(object):
except:
raise AnsibleError("this role does not appear to have a valid meta/main.yml file.")
# we strip off the top-level directory for all of the files contained within
# the tar file here, since the default is 'github_repo-target', and change it
# to the specified role's name
# we strip off any higher-level directories for all of the files contained within
# the tar file here. The default is 'github_repo-target'. Gerrit instances, on the other
# hand, does not have a parent directory at all.
installed = False
while not installed:
display.display("- extracting %s to %s" % (self.name, self.path))
@ -305,9 +314,9 @@ class GalaxyRole(object):
for member in members:
# we only extract files, and remove any relative path
# bits that might be in the file for security purposes
# and drop the leading directory, as mentioned above
# and drop any containing directory, as mentioned above
if member.isreg() or member.issym():
parts = member.name.split(os.sep)[1:]
parts = member.name.replace(archive_parent_dir, "").split(os.sep)
final_parts = []
for part in parts:
if part != '..' and '~' not in part and '$' not in part: