Skip to content

Commit

Permalink
Merge pull request #11907 from jasonwbarnett/feature/add-component-strip
Browse files Browse the repository at this point in the history
Add strip_components property to archive_file
  • Loading branch information
tas50 committed Sep 21, 2021
2 parents 77a27db + 1f6613e commit 772863d
Show file tree
Hide file tree
Showing 5 changed files with 529 additions and 20 deletions.
14 changes: 11 additions & 3 deletions .expeditor/verify.pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ steps:
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- apt-get update -y
- apt-get install -y cron locales # needed for functional tests to pass
- apt-get install -y cron locales libarchive-dev # needed for functional tests to pass
- cd /workdir; bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:functional
Expand All @@ -72,6 +72,8 @@ steps:
- label: "Unit Ubuntu 18.04 :ruby: 3.0"
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- apt-get update -y
- apt-get install -y libarchive-dev
- bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:unit
Expand All @@ -97,7 +99,7 @@ steps:
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- apt-get update -y
- apt-get install -y cron locales # needed for functional tests to pass
- apt-get install -y cron locales libarchive-dev # needed for functional tests to pass
- cd /workdir; bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:functional
Expand All @@ -110,6 +112,8 @@ steps:
- label: "Unit Ubuntu 20.04 :ruby: 3.0"
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- apt-get update -y
- apt-get install -y libarchive-dev
- bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:unit
Expand All @@ -135,6 +139,7 @@ steps:
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- yum install -y crontabs e2fsprogs
- yum install -y libarchive-devel
- cd /workdir; bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:functional
Expand All @@ -147,6 +152,7 @@ steps:
- label: "Unit CentOS 7 :ruby: 3.0"
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- yum install -y libarchive-devel
- bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:unit
Expand All @@ -173,6 +179,7 @@ steps:
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- zypper install -y cronie insserv-compat
- zypper install -y libarchive-devel
- cd /workdir; bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:functional
Expand All @@ -185,7 +192,7 @@ steps:
- label: "Unit openSUSE 15 :ruby: 3.0"
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- zypper install -y cron insserv-compat
- zypper install -y cron insserv-compat libarchive-devel
- bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:unit
Expand Down Expand Up @@ -226,6 +233,7 @@ steps:
- label: "Unit Fedora :ruby: 3.0"
commands:
- /workdir/.expeditor/scripts/bk_container_prep.sh
- dnf install -y libarchive-devel
- bundle config set --local without omnibus_package
- bundle install --jobs=3 --retry=3 --path=vendor/bundle
- bundle exec rake spec:unit
Expand Down
31 changes: 17 additions & 14 deletions lib/chef/resource/archive_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ class ArchiveFile < Chef::Resource
description: "Should the resource overwrite the destination file contents if they already exist? If set to `:auto` the date stamp of files within the archive will be compared to those on disk and disk contents will be overwritten if they differ. This may cause unintended consequences if disk date stamps are changed between runs, which will result in the files being overwritten during each client run. Make sure to properly test any change to this property.",
default: false

property :strip_components, Integer,
description: "Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped. This behaves similarly to tar's --strip-components command line argument.",
introduced: "17.5",
default: 0

# backwards compatibility for the legacy cookbook names
alias_method :extract_options, :options
alias_method :extract_to, :destination
Expand Down Expand Up @@ -117,7 +122,7 @@ class ArchiveFile < Chef::Resource

if new_resource.owner || new_resource.group
converge_by("set owner of files extracted in #{new_resource.destination} to #{new_resource.owner}:#{new_resource.group}") do
archive = Archive::Reader.open_filename(new_resource.path)
archive = Archive::Reader.open_filename(new_resource.path, nil, strip_components: new_resource.strip_components)
archive.each_entry do |e|
FileUtils.chown(new_resource.owner, new_resource.group, "#{new_resource.destination}/#{e.pathname}")
end
Expand Down Expand Up @@ -160,18 +165,16 @@ def extract_option_map
# @return [Boolean]
def archive_differs_from_disk?(src, dest)
modified = false
Dir.chdir(dest) do
archive = Archive::Reader.open_filename(src)
Chef::Log.trace("Beginning the comparison of file mtime between contents of #{src} and #{dest}")
archive.each_entry do |e|
pathname = ::File.expand_path(e.pathname)
if ::File.exist?(pathname)
Chef::Log.trace("#{pathname} mtime is #{::File.mtime(pathname)} and archive is #{e.mtime}")
modified = true unless ::File.mtime(pathname) == e.mtime
else
Chef::Log.trace("#{pathname} doesn't exist on disk, but exists in the archive")
modified = true
end
archive = Archive::Reader.open_filename(src, nil, strip_components: new_resource.strip_components)
Chef::Log.trace("Beginning the comparison of file mtime between contents of #{src} and #{dest}")
archive.each_entry do |e|
pathname = ::File.expand_path(e.pathname, dest)
if ::File.exist?(pathname)
Chef::Log.trace("#{pathname} mtime is #{::File.mtime(pathname)} and archive is #{e.mtime}")
modified = true unless ::File.mtime(pathname) == e.mtime
else
Chef::Log.trace("#{pathname} doesn't exist on disk, but exists in the archive")
modified = true
end
end
modified
Expand All @@ -189,7 +192,7 @@ def extract(src, dest, options = [])
flags = [options].flatten.map { |option| extract_option_map[option] }.compact.reduce(:|)

Dir.chdir(dest) do
archive = Archive::Reader.open_filename(src)
archive = Archive::Reader.open_filename(src, nil, strip_components: new_resource.strip_components)

archive.each_entry do |e|
archive.extract(e, flags.to_i)
Expand Down
Binary file added spec/data/archive_file/test_archive.tar.gz
Binary file not shown.
87 changes: 87 additions & 0 deletions spec/functional/resource/archive_file_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#
# Copyright:: Copyright (c) Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require "spec_helper"
require "tmpdir"

# Excluding this test on Windows until CI issues can be addressed.
describe Chef::Resource::ArchiveFile, :not_supported_on_windows do
include RecipeDSLHelper

let(:tmp_path) { Dir.mktmpdir }
let(:extract_destination) { "#{tmp_path}/extract_here" }
let(:test_archive_path) { File.expand_path("archive_file/test_archive.tar.gz", CHEF_SPEC_DATA) }

after do
FileUtils.remove_entry_secure(extract_destination) if File.exist?(extract_destination)
end

context "when strip_components is 0" do
it "extracts archive to destination" do
af = archive_file test_archive_path do
destination extract_destination
end
af.should_be_updated

expect(af.strip_components).to eq(0) # Validate defaults haven't changed here
expect(Dir.glob("#{extract_destination}/**/*").length).to eq(4)
expect(Dir.exist?("#{extract_destination}/folder-1")).to eq(true)
expect(File.exist?("#{extract_destination}/folder-1/file-1.txt")).to eq(true)
expect(Dir.exist?("#{extract_destination}/folder-1/folder-2")).to eq(true)
expect(File.exist?("#{extract_destination}/folder-1/folder-2/file-2.txt")).to eq(true)
end
end

context "when strip_components is 1" do
it "extracts archive to destination, with 1 component stripped" do
archive_file test_archive_path do
destination extract_destination
strip_components 1
end.should_be_updated

expect(Dir.exist?("#{extract_destination}/folder-1")).to eq(false)
expect(File.exist?("#{extract_destination}/folder-1/file-1.txt")).to eq(false)
expect(Dir.exist?("#{extract_destination}/folder-1/folder-2")).to eq(false)
expect(File.exist?("#{extract_destination}/folder-1/folder-2/file-2.txt")).to eq(false)

expect(Dir.glob("#{extract_destination}/**/*").length).to eq(3)
expect(File.exist?("#{extract_destination}/file-1.txt")).to eq(true)
expect(Dir.exist?("#{extract_destination}/folder-2")).to eq(true)
expect(File.exist?("#{extract_destination}/folder-2/file-2.txt")).to eq(true)
end
end

context "when strip_components is 2" do
it "extracts archive to destination, with 2 components stripped" do
archive_file test_archive_path do
destination extract_destination
strip_components 2
end.should_be_updated

expect(Dir.exist?("#{extract_destination}/folder-1")).to eq(false)
expect(File.exist?("#{extract_destination}/folder-1/file-1.txt")).to eq(false)
expect(Dir.exist?("#{extract_destination}/folder-1/folder-2")).to eq(false)
expect(File.exist?("#{extract_destination}/folder-1/folder-2/file-2.txt")).to eq(false)
expect(File.exist?("#{extract_destination}/file-1.txt")).to eq(false)
expect(Dir.exist?("#{extract_destination}/folder-2")).to eq(false)
expect(File.exist?("#{extract_destination}/folder-2/file-2.txt")).to eq(false)

expect(Dir.glob("#{extract_destination}/**/*").length).to eq(1)
expect(File.exist?("#{extract_destination}/file-2.txt")).to eq(true)
end
end
end
Loading

0 comments on commit 772863d

Please sign in to comment.