summaryrefslogtreecommitdiff
path: root/lib/chef/knife/cookbook_site_install.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/knife/cookbook_site_install.rb')
-rw-r--r--lib/chef/knife/cookbook_site_install.rb171
1 files changed, 5 insertions, 166 deletions
diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb
index 18cddb19f4..18e75442ca 100644
--- a/lib/chef/knife/cookbook_site_install.rb
+++ b/lib/chef/knife/cookbook_site_install.rb
@@ -17,180 +17,19 @@
#
require "chef/knife"
-require "chef/exceptions"
-require "shellwords"
-require "mixlib/archive"
+require "chef/knife/supermarket_install"
class Chef
class Knife
- class CookbookSiteInstall < Knife
+ class CookbookSiteInstall < Knife::SupermarketInstall
- deps do
- require "chef/mixin/shell_out"
- require "chef/knife/core/cookbook_scm_repo"
- require "chef/cookbook/metadata"
- end
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
banner "knife cookbook site install COOKBOOK [VERSION] (options)"
category "cookbook site"
- option :no_deps,
- short: "-D",
- long: "--skip-dependencies",
- boolean: true,
- default: false,
- description: "Skips automatic dependency installation."
-
- option :cookbook_path,
- short: "-o PATH:PATH",
- long: "--cookbook-path PATH:PATH",
- description: "A colon-separated path to look for cookbooks in",
- proc: lambda { |o| o.split(":") }
-
- option :default_branch,
- short: "-B BRANCH",
- long: "--branch BRANCH",
- description: "Default branch to work with",
- default: "master"
-
- option :use_current_branch,
- short: "-b",
- long: "--use-current-branch",
- description: "Use the current branch",
- boolean: true,
- default: false
-
- option :supermarket_site,
- short: "-m SUPERMARKET_SITE",
- long: "--supermarket-site SUPERMARKET_SITE",
- description: "Supermarket Site",
- default: "https://supermarket.chef.io",
- proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
-
- attr_reader :cookbook_name
- attr_reader :vendor_path
-
- def run
- extend Chef::Mixin::ShellOut
-
- if config[:cookbook_path]
- Chef::Config[:cookbook_path] = config[:cookbook_path]
- else
- config[:cookbook_path] = Chef::Config[:cookbook_path]
- end
-
- @cookbook_name = parse_name_args!
- # Check to ensure we have a valid source of cookbooks before continuing
- #
- @install_path = File.expand_path(Array(config[:cookbook_path]).first)
- ui.info "Installing #{@cookbook_name} to #{@install_path}"
-
- @repo = CookbookSCMRepo.new(@install_path, ui, config)
- # cookbook_path = File.join(vendor_path, name_args[0])
- upstream_file = File.join(@install_path, "#{@cookbook_name}.tar.gz")
-
- @repo.sanity_check
- unless config[:use_current_branch]
- @repo.reset_to_default_state
- @repo.prepare_to_import(@cookbook_name)
- end
-
- downloader = download_cookbook_to(upstream_file)
- clear_existing_files(File.join(@install_path, @cookbook_name))
- extract_cookbook(upstream_file, downloader.version)
-
- # TODO: it'd be better to store these outside the cookbook repo and
- # keep them around, e.g., in ~/Library/Caches on OS X.
- ui.info("Removing downloaded tarball")
- File.unlink(upstream_file)
-
- if @repo.finalize_updates_to(@cookbook_name, downloader.version)
- unless config[:use_current_branch]
- @repo.reset_to_default_state
- end
- @repo.merge_updates_from(@cookbook_name, downloader.version)
- else
- unless config[:use_current_branch]
- @repo.reset_to_default_state
- end
- end
-
- unless config[:no_deps]
- preferred_metadata.dependencies.each_key do |cookbook|
- # Doesn't do versions.. yet
- nv = self.class.new
- nv.config = config
- nv.name_args = [ cookbook ]
- nv.run
- end
- end
- end
-
- def parse_name_args!
- if name_args.empty?
- ui.error("Please specify a cookbook to download and install.")
- exit 1
- elsif name_args.size >= 2
- unless name_args.last.match(/^(\d+)(\.\d+){1,2}$/) && name_args.size == 2
- ui.error("Installing multiple cookbooks at once is not supported.")
- exit 1
- end
- end
- name_args.first
- end
-
- def download_cookbook_to(download_path)
- downloader = Chef::Knife::CookbookSiteDownload.new
- downloader.config[:file] = download_path
- downloader.config[:supermarket_site] = config[:supermarket_site]
- downloader.name_args = name_args
- downloader.run
- downloader
- end
-
- def extract_cookbook(upstream_file, version)
- ui.info("Uncompressing #{@cookbook_name} version #{version}.")
- Mixlib::Archive.new(convert_path(upstream_file)).extract(@install_path, perms: false)
- end
-
- def clear_existing_files(cookbook_path)
- ui.info("Removing pre-existing version.")
- FileUtils.rmtree(cookbook_path) if File.directory?(cookbook_path)
- end
-
- def convert_path(upstream_file)
- # converts a Windows path (C:\foo) to a mingw path (/c/foo)
- if ENV["MSYSTEM"] == "MINGW32"
- upstream_file.sub(/^([[:alpha:]]):/, '/\1')
- else
- Shellwords.escape upstream_file
- end
- end
-
- # Get the preferred metadata path on disk. Chef prefers the metadata.rb
- # over the metadata.json.
- #
- # @raise if there is no metadata in the cookbook
- #
- # @return [Chef::Cookbook::Metadata]
- def preferred_metadata
- md = Chef::Cookbook::Metadata.new
-
- rb = File.join(@install_path, @cookbook_name, "metadata.rb")
- if File.exist?(rb)
- md.from_file(rb)
- return md
- end
-
- json = File.join(@install_path, @cookbook_name, "metadata.json")
- if File.exist?(json)
- json = IO.read(json)
- md.from_json(json)
- return md
- end
-
- raise Chef::Exceptions::MetadataNotFound.new(@install_path, @cookbook_name)
- end
end
end
end