summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2018-12-06 22:22:48 -0800
committerTim Smith <tsmith@chef.io>2019-04-15 10:27:10 -0700
commit49ca8ca5070d171b8d64d3158f93531ee0573c4b (patch)
tree3241093f3747132c967217a562f51f8d41262da5
parentce11470525cf03df6b464112db9501d7c49fd29b (diff)
downloadchef-49ca8ca5070d171b8d64d3158f93531ee0573c4b.tar.gz
Add a new archive_file resource from the libarchive cookbook
This adds the archive_file resource from the libarchive cookbook. I've updated the property names in that cookbook to allow us to add a :create action later on. This code matches the code in the cookbook nearly 100%. Signed-off-by: Tim Smith <tsmith@chef.io>
-rw-r--r--Gemfile.lock4
-rw-r--r--chef.gemspec3
-rw-r--r--lib/chef/resource/archive_file.rb132
-rw-r--r--lib/chef/resources.rb1
-rw-r--r--spec/unit/resource/archive_file_spec.rb40
5 files changed, 178 insertions, 2 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 9a72f0b45b..f01b89a943 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -35,6 +35,7 @@ PATH
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
ffi (~> 1.9, >= 1.9.25)
+ ffi-libarchive
ffi-yajl (~> 2.2)
highline (~> 1.6, >= 1.6.9)
iniparse (~> 1.4)
@@ -59,6 +60,7 @@ PATH
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
ffi (~> 1.9, >= 1.9.25)
+ ffi-libarchive
ffi-yajl (~> 2.2)
highline (~> 1.6, >= 1.6.9)
iniparse (~> 1.4)
@@ -136,6 +138,8 @@ GEM
ffi (1.10.0)
ffi (1.10.0-x64-mingw32)
ffi (1.10.0-x86-mingw32)
+ ffi-libarchive (0.4.6)
+ ffi (~> 1.0)
ffi-win32-extensions (1.0.3)
ffi
ffi-yajl (2.3.1)
diff --git a/chef.gemspec b/chef.gemspec
index bb0c1f290e..f6d8e93ab7 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -32,9 +32,8 @@ Gem::Specification.new do |s|
s.add_dependency "highline", "~> 1.6", ">= 1.6.9"
s.add_dependency "erubis", "~> 2.7"
s.add_dependency "diff-lcs", "~> 1.2", ">= 1.2.4"
-
+ s.add_dependency "ffi-libarchive"
s.add_dependency "chef-zero", ">= 14.0.11"
-
s.add_dependency "plist", "~> 3.2"
s.add_dependency "iniparse", "~> 1.4"
s.add_dependency "addressable"
diff --git a/lib/chef/resource/archive_file.rb b/lib/chef/resource/archive_file.rb
new file mode 100644
index 0000000000..1c0a073dde
--- /dev/null
+++ b/lib/chef/resource/archive_file.rb
@@ -0,0 +1,132 @@
+#
+# Copyright:: Copyright 2017-2018, Chef Software Inc.
+# Author:: Jamie Winsor (<jamie@vialstudios.com>)
+# Author:: Tim Smith (<tsmith@chef.io>)
+#
+# 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 "chef/resource"
+
+class Chef
+ class Resource
+ class ArchiveFile < Chef::Resource
+
+ resource_name :archive_file
+ provides :archive_file
+ provides :libarchive_file # legacy cookbook name
+
+ introduced "15.0"
+
+ property :path, String,
+ name_property: true,
+ coerce: proc { |f| ::File.expand_path(f) },
+ description: ""
+
+ property :owner, String,
+ description: ""
+
+ property :group, String,
+ description: ""
+
+ property :mode, [String, Integer],
+ description: "",
+ default: "755"
+
+ property :destination, String,
+ description: "",
+ required: true
+
+ property :options, [Array, Symbol],
+ description: "",
+ default: lazy { [] }
+
+ # backwards compatibility for the legacy cookbook names
+ alias_method :extract_options, :options
+ alias_method :extract_to, :destination
+
+ action :extract do
+ require "fileutils"
+
+ unless ::File.exist?(new_resource.path)
+ raise Errno::ENOENT, "No archive found at #{new_resource.path}!"
+ end
+
+ unless Dir.exist?(new_resource.destination)
+ converge_by("create directory #{new_resource.destination}") do
+ FileUtils.mkdir_p(new_resource.destination, mode: new_resource.mode.to_i)
+ end
+ end
+
+ converge_by("extract #{new_resource.path} to #{new_resource.destination}") do
+ extract(new_resource.path, new_resource.destination,
+ Array(new_resource.options))
+ end
+
+ if new_resource.owner || new_resource.group
+ converge_by("set owner of #{new_resource.destination} to #{new_resource.owner}:#{new_resource.group}") do
+ FileUtils.chown_R(new_resource.owner, new_resource.group, new_resource.destination)
+ end
+ end
+ end
+
+ action_class do
+ # This can't be a constant since we might not have required 'ffi-libarchive' yet.
+ def extract_option_map
+ {
+ owner: Archive::EXTRACT_OWNER,
+ permissions: Archive::EXTRACT_PERM,
+ time: Archive::EXTRACT_TIME,
+ no_overwrite: Archive::EXTRACT_NO_OVERWRITE,
+ acl: Archive::EXTRACT_ACL,
+ fflags: Archive::EXTRACT_FFLAGS,
+ extended_information: Archive::EXTRACT_XATTR,
+ xattr: Archive::EXTRACT_XATTR,
+ no_overwrite_newer: Archive::EXTRACT_NO_OVERWRITE_NEWER,
+ }
+ end
+
+ # @param [String] src
+ # @param [String] dest
+ # @param [Array] options
+ #
+ # @return [Boolean] was the file extraction performed or not
+ def extract(src, dest, options = [])
+ require "ffi-libarchive"
+
+ flags = [options].flatten.map { |option| extract_option_map[option] }.compact.reduce(:|)
+ modified = false
+
+ Dir.chdir(dest) do
+ archive = Archive::Reader.open_filename(src)
+
+ archive.each_entry do |e|
+ pathname = ::File.expand_path(e.pathname)
+ if ::File.exist?(pathname)
+ modified = true unless ::File.mtime(pathname) == e.mtime
+ else
+ modified = true
+ end
+
+ archive.extract(e, flags.to_i)
+ end
+ archive.close
+ end
+ modified
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 0a74fcea23..59cae3558a 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -20,6 +20,7 @@ require "chef/resource/apt_package"
require "chef/resource/apt_preference"
require "chef/resource/apt_repository"
require "chef/resource/apt_update"
+require "chef/resource/archive_file"
require "chef/resource/bash"
require "chef/resource/batch"
require "chef/resource/breakpoint"
diff --git a/spec/unit/resource/archive_file_spec.rb b/spec/unit/resource/archive_file_spec.rb
new file mode 100644
index 0000000000..053c8d614a
--- /dev/null
+++ b/spec/unit/resource/archive_file_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2018, 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"
+
+describe Chef::Resource::ArchiveFile do
+
+ let(:resource) { Chef::Resource::ArchiveFile.new("foo") }
+
+ it "has a resource name of :archive_file" do
+ expect(resource.resource_name).to eql(:archive_file)
+ end
+
+ it "has a name property of path" do
+ expect(resource.path).to eql("foo")
+ end
+
+ it "sets the default action as :extract" do
+ expect(resource.action).to eql([:extract])
+ end
+
+ it "supports :extract action" do
+ expect { resource.action :extract }.not_to raise_error
+ end
+
+end