diff --git a/lib/ansible/modules/files/unarchive.py b/lib/ansible/modules/files/unarchive.py index a323ff8d1b4..e99a3d7e832 100644 --- a/lib/ansible/modules/files/unarchive.py +++ b/lib/ansible/modules/files/unarchive.py @@ -647,7 +647,7 @@ class TgzArchive(object): if self.opts: cmd.extend(['--show-transformed-names'] + self.opts) if self.excludes: - cmd.extend(['--exclude=' + quote(f) for f in self.excludes]) + cmd.extend(['--exclude=' + f for f in self.excludes]) cmd.extend(['-f', self.src]) rc, out, err = self.module.run_command(cmd, cwd=self.dest, environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')) if rc != 0: @@ -658,14 +658,18 @@ class TgzArchive(object): # filename = filename.decode('string_escape') filename = to_native(codecs.escape_decode(filename)[0]) - if filename and filename not in self.excludes: - # We don't allow absolute filenames. If the user wants to unarchive rooted in "/" - # they need to use "dest: '/'". This follows the defaults for gtar, pax, etc. - # Allowing absolute filenames here also causes bugs: https://github.com/ansible/ansible/issues/21397 - if filename.startswith('/'): - filename = filename[1:] + # We don't allow absolute filenames. If the user wants to unarchive rooted in "/" + # they need to use "dest: '/'". This follows the defaults for gtar, pax, etc. + # Allowing absolute filenames here also causes bugs: https://github.com/ansible/ansible/issues/21397 + if filename.startswith('/'): + filename = filename[1:] - self._files_in_archive.append(filename) + if self.excludes: + for exclude in self.excludes: + if not fnmatch.fnmatch(filename, exclude): + self._files_in_archive.append(to_native(filename)) + else: + self._files_in_archive.append(to_native(filename)) return self._files_in_archive @@ -682,7 +686,7 @@ class TgzArchive(object): if self.module.params['keep_newer']: cmd.append('--keep-newer-files') if self.excludes: - cmd.extend(['--exclude=' + quote(f) for f in self.excludes]) + cmd.extend(['--exclude=' + f for f in self.excludes]) cmd.extend(['-f', self.src]) rc, out, err = self.module.run_command(cmd, cwd=self.dest, environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')) @@ -729,7 +733,7 @@ class TgzArchive(object): if self.module.params['keep_newer']: cmd.append('--keep-newer-files') if self.excludes: - cmd.extend(['--exclude=' + quote(f) for f in self.excludes]) + cmd.extend(['--exclude=' + f for f in self.excludes]) cmd.extend(['-f', self.src]) rc, out, err = self.module.run_command(cmd, cwd=self.dest, environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')) return dict(cmd=cmd, rc=rc, out=out, err=err) diff --git a/test/integration/targets/unarchive/tasks/main.yml b/test/integration/targets/unarchive/tasks/main.yml index c068a016afd..12cfcf10af9 100644 --- a/test/integration/targets/unarchive/tasks/main.yml +++ b/test/integration/targets/unarchive/tasks/main.yml @@ -60,6 +60,39 @@ - name: prep a zip file shell: zip test-unarchive.zip foo-unarchive.txt foo-unarchive-777.txt chdir={{output_dir}} +- name: Prepare - Create test dirs + file: + path: "{{output_dir}}/{{item}}" + state: directory + with_items: + - created/include + - created/exclude + - created/other + +- name: Prepare - Create test files + file: + path: "{{output_dir}}/created/{{item}}" + state: touch + with_items: + - include/include-1.txt + - include/include-2.txt + - include/include-3.txt + - exclude/exclude-1.txt + - exclude/exclude-2.txt + - exclude/exclude-3.txt + - other/include-1.ext + - other/include-2.ext + - other/exclude-1.ext + - other/exclude-2.ext + - other/other-1.ext + - other/other-2.ext + +- name: Prepare - zip file + shell: zip -r {{output_dir}}/unarchive-00.zip * chdir={{output_dir}}/created/ + +- name: Prepare - tar file + shell: tar czvf {{output_dir}}/unarchive-00.tar * chdir={{output_dir}}/created/ + - name: add a file with Windows permissions to zip file shell: zip -k test-unarchive.zip FOO-UNAR.TXT chdir={{output_dir}} @@ -187,22 +220,33 @@ - name: "Create {{ output_dir }}/exclude directory" file: state: directory - path: "{{ output_dir }}/exclude" + path: "{{ output_dir }}/exclude-{{item}}" + with_items: + - zip + - tar -- name: Unpack zip file excluding one file. +- name: Unpack archive file excluding glob files. unarchive: - src: "{{ output_dir }}/test-unarchive.zip" - dest: "{{ output_dir }}/exclude" - exclude: "foo-unarchive-*.txt" + src: "{{ output_dir }}/unarchive-00.{{item}}" + dest: "{{ output_dir }}/exclude-{{item}}" + exclude: "exclude/exclude-*.txt" + with_items: + - zip + - tar - name: verify that the file was unarchived - shell: find {{ output_dir }}/exclude chdir={{ output_dir }} - register: unarchive_dir01 + shell: find {{ output_dir }}/exclude-{{item}} chdir={{ output_dir }} + register: unarchive00 + with_items: + - zip + - tar -- name: verify that zip extraction excluded file +- name: verify that archive extraction excluded the files assert: that: - - "'foo-unarchive-777.txt' not in unarchive_dir01.stdout" + - "'exclude/exclude-1.txt' not in item.stdout" + with_items: + - "{{ unarchive00.results }}" - name: remove our zip unarchive destination file: path={{output_dir}}/test-unarchive-zip state=absent