diff --git a/chef-dk.gemspec b/chef-dk.gemspec index 3d2bc0ea2..73a87e525 100644 --- a/chef-dk.gemspec +++ b/chef-dk.gemspec @@ -41,6 +41,8 @@ Gem::Specification.new do |gem| gem.add_dependency "mixlib-shellout", ">= 2.0.0.rc.0", "< 3.0.0" gem.add_dependency "ffi-yajl", ">= 1.0", "< 3.0" + gem.add_dependency "minitar", "~> 0.5.4" + gem.add_dependency "chef", "~> 12.0", ">= 12.2.1" gem.add_dependency "solve", "~> 2.0", ">= 2.0.1" diff --git a/lib/chef-dk/command/export.rb b/lib/chef-dk/command/export.rb index df537fe60..0aba0e937 100644 --- a/lib/chef-dk/command/export.rb +++ b/lib/chef-dk/command/export.rb @@ -86,7 +86,7 @@ def initialize(*args) def run(params = []) return 1 unless apply_params!(params) export_service.run - ui.msg("Exported policy '#{export_service.policyfile_lock.name}' to #{export_dir}") + ui.msg("Exported policy '#{export_service.policyfile_lock.name}' to #{export_target}") 0 rescue ExportDirNotEmpty => e ui.err("ERROR: " + e.message) @@ -97,6 +97,14 @@ def run(params = []) 1 end + def export_target + if archive? + export_service.archive_file_location + else + export_dir + end + end + def debug? !!config[:debug] end diff --git a/lib/chef-dk/policyfile_services/export_repo.rb b/lib/chef-dk/policyfile_services/export_repo.rb index f2a46b476..6b80f17f6 100644 --- a/lib/chef-dk/policyfile_services/export_repo.rb +++ b/lib/chef-dk/policyfile_services/export_repo.rb @@ -17,6 +17,9 @@ require 'fileutils' require 'tmpdir' +require 'zlib' + +require 'archive/tar/minitar' require 'chef-dk/service_exceptions' require 'chef-dk/policyfile_lock' @@ -93,7 +96,11 @@ def export create_repo_structure copy_cookbooks create_policyfile_data_item - mv_staged_repo + if archive? + create_archive + else + mv_staged_repo + end end rescue => error msg = "Failed to export policy (in #{policyfile_filename}) to #{export_dir}" @@ -115,6 +122,14 @@ def with_staging_dir end end + def create_archive + Zlib::GzipWriter.open(archive_file_location) do |gz_file| + Dir.chdir(staging_dir) do + Archive::Tar::Minitar.pack(".", gz_file) + end + end + end + def staging_dir @staging_dir end @@ -204,7 +219,7 @@ def assert_lockfile_exists! end def assert_export_dir_clean! - if !force_export? && !conflicting_fs_entries.empty? + if !force_export? && !conflicting_fs_entries.empty? && !archive? msg = "Export dir (#{export_dir}) not clean. Refusing to export. (Conflicting files: #{conflicting_fs_entries.join(', ')})" raise ExportDirNotEmpty, msg end diff --git a/spec/unit/policyfile_services/export_repo_spec.rb b/spec/unit/policyfile_services/export_repo_spec.rb index af6976c13..caf5ae11a 100644 --- a/spec/unit/policyfile_services/export_repo_spec.rb +++ b/spec/unit/policyfile_services/export_repo_spec.rb @@ -192,7 +192,6 @@ before do allow(export_service.policyfile_lock).to receive(:validate_cookbooks!).and_return(true) export_service.run - pp :export_run end let(:cookbook_files) do @@ -342,18 +341,54 @@ let(:archive) { true } - # TODO: - it "exports the repo as a tgz archive" + let(:expected_archive_path) do + File.join(export_dir, "install-example-60e5ad638dce219d8f87d589463ec4a9884007ba5e2adbb4c0a7021d67204f1a.tgz") + end + + it "exports the repo as a tgz archive" do + expect(File).to exist(expected_archive_path) + end include_examples "successful_export" do + # explode the tarball so the assertions can find the files before do - pp :archive_before_block + Zlib::GzipReader.open(expected_archive_path) do |gz_file| + tar = Archive::Tar::Minitar::Input.new(gz_file) + tar.each do |e| + tar.extract_entry(export_dir, e) + end + end end end - end + context "when the target dir has a cookbooks or data_bags dir" do + + let(:cookbooks_dir) { File.join(export_dir, "cookbooks") } + + let(:file_in_cookbooks_dir) { File.join(cookbooks_dir, "some_random_cruft") } + + let(:policyfiles_data_bag_dir) { File.join(export_dir, "data_bags", "policyfiles") } + + let(:extra_policyfile_data_item) { File.join(policyfiles_data_bag_dir, "leftover-policy.json") } + + before do + FileUtils.mkdir_p(export_dir) + FileUtils.mkdir_p(cookbooks_dir) + FileUtils.mkdir_p(policyfiles_data_bag_dir) + File.open(file_in_cookbooks_dir, "wb+") { |f| f.print "some random cruft" } + File.open(extra_policyfile_data_item, "wb+") { |f| f.print "some random cruft" } + end + + it "exports successfully" do + expect { export_service.run }.to_not raise_error + expect(File).to exist(expected_archive_path) + end + + end + + end # when archive mode is enabled end # copying the cookbooks to the export dir end