# # Copyright:: Copyright (c) 2014 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 'stringio' require 'omnibus/packagers/mac_pkg' require 'spec_helper' describe Omnibus::Packagers::MacPkg do let(:project_name) { 'myproject' } let(:mac_pkg_identifier) { 'com.mycorp.myproject' } let(:omnibus_root) { '/omnibus/project/root' } let(:scripts_path) { "#{omnibus_root}/scripts" } let(:package_dir) { '/home/someuser/omnibus-myproject/pkg' } let(:package_tmp) { '/var/cache/omnibus/pkg-tmp' } let(:files_path) { "#{omnibus_root}/files" } let(:expected_distribution_content) do <<-EOH <?xml version="1.0" standalone="no"?> <installer-gui-script minSpecVersion="1"> <title>Myproject</title> <background file="background.png" alignment="bottomleft" mime-type="image/png"/> <welcome file="welcome.html" mime-type="text/html"/> <license file="license.html" mime-type="text/html"/> <!-- Generated by productbuild - - synthesize --> <pkg-ref id="com.mycorp.myproject"/> <options customize="never" require-scripts="false"/> <choices-outline> <line choice="default"> <line choice="com.mycorp.myproject"/> </line> </choices-outline> <choice id="default"/> <choice id="com.mycorp.myproject" visible="false"> <pkg-ref id="com.mycorp.myproject"/> </choice> <pkg-ref id="com.mycorp.myproject" version="23.4.2" onConclusion="none">myproject-core.pkg</pkg-ref> </installer-gui-script> EOH end let(:expected_distribution_path) { '/var/cache/omnibus/pkg-tmp/mac-pkg/Distribution' } let(:productbuild_argv) do %W[ productbuild --distribution #{expected_distribution_path} --resources /omnibus/project/root/files/mac_pkg/Resources /home/someuser/omnibus-myproject/pkg/myproject.pkg ] end let(:pkgbuild_argv) do %w[ pkgbuild --identifier com.mycorp.myproject --version 23.4.2 --scripts /omnibus/project/root/scripts --root /opt/myproject --install-location /opt/myproject myproject-core.pkg ] end let(:shellout_opts) do { timeout: 3600, cwd: File.join(package_tmp, 'mac-pkg'), } end let(:project) do double Omnibus::Project, name: project_name, build_version: '23.4.2', maintainer: "Joe's Software", install_path: '/opt/myproject', package_scripts_path: scripts_path, files_path: files_path, package_dir: package_dir, package_tmp: package_tmp, mac_pkg_identifier: mac_pkg_identifier end let(:packager) do Omnibus::Packagers::MacPkg.new(project) end it "uses the project's version" do expect(packager.version).to eq(project.build_version) end it "uses the project's name" do expect(packager.name).to eq(project.name) end it "uses the project's mac_pkg_identifier" do expect(packager.identifier).to eq(mac_pkg_identifier) end it "uses the project's install_path as the package root" do expect(packager.pkg_root).to eq(project.install_path) end it "uses the project's install_path as the package install location" do expect(packager.install_location).to eq(project.install_path) end it 'names the component package PROJECT_NAME-core.pkg' do expect(packager.component_pkg_name).to eq('myproject-core.pkg') end it 'names the product package PROJECT_NAME.pkg' do # NOTE: #package_name is used by Project, so it's part of the **PUBLIC** # API. expect(packager.package_name).to eq('myproject.pkg') expect(packager.product_pkg_name).to eq('myproject.pkg') end it "use's the project's package_scripts_path" do expect(packager.scripts).to eq(project.package_scripts_path) end it "makes a list of required files to generate the 'product' pkg file" do project_file_path = '/omnibus/project/root/files/mac_pkg/Resources' required_files = %w[background.png welcome.html license.html].map do |basename| File.join(project_file_path, basename) end expect(packager.required_files).to match_array(required_files) end it 'validates that all required files are present' do expected_error_text = <<-E Your omnibus repo is missing the following files required to build Mac packages: * /omnibus/project/root/files/mac_pkg/Resources/background.png * /omnibus/project/root/files/mac_pkg/Resources/license.html * /omnibus/project/root/files/mac_pkg/Resources/welcome.html E # RSpec 2.14.1 doesn't do nice diffs of expected error strings, so do this # the hard way for now. e = nil begin packager.validate_omnibus_project! rescue => e end expect(e).to be_a(Omnibus::MissingMacPkgResource) expect(e.to_s).to eq(expected_error_text) end it 'clears and recreates the staging dir' do expect(FileUtils).to receive(:rm_rf).with('/var/cache/omnibus/pkg-tmp/mac-pkg') expect(FileUtils).to receive(:mkdir_p).with('/var/cache/omnibus/pkg-tmp/mac-pkg') packager.setup_staging_dir! end it 'generates a pkgbuild command' do expect(packager.pkgbuild_command).to eq(pkgbuild_argv) end it 'runs pkgbuild' do expected_args = pkgbuild_argv + [shellout_opts] expect(packager).to receive(:shellout!).with(*expected_args) packager.build_component_pkg end it 'has a temporary staging location for the distribution file' do expect(packager.staging_dir).to eq('/var/cache/omnibus/pkg-tmp/mac-pkg') end it 'generates a Distribution file describing the product package content' do expect(packager.distribution).to eq(expected_distribution_content) end it 'generates a productbuild command' do expect(packager.productbuild_command).to eq(productbuild_argv) end describe 'building the product package' do let(:distribution_file) { StringIO.new } before do expect(File).to receive(:open) .with(expected_distribution_path, File::RDWR | File::CREAT | File::EXCL, 0600) .and_yield(distribution_file) end it 'writes the distribution file to the staging directory' do packager.generate_distribution expect(distribution_file.string).to eq(expected_distribution_content) end it 'generates the distribution and runs productbuild' do expected_shellout_args = productbuild_argv + [shellout_opts] expect(packager).to receive(:shellout!).with(*expected_shellout_args) packager.build_product_pkg expect(distribution_file.string).to eq(expected_distribution_content) end end context "when the mac_pkg_identifier isn't specified by the project" do let(:mac_pkg_identifier) { nil } let(:project_name) { 'My $Project' } it 'sanitizes the MAINTAINER name' do expect(packager.sanitized_maintainer).to eq('joessoftware') end it 'sanitizes the project name' do expect(packager.sanitized_name).to eq('myproject') end it 'uses com.example.PROJECT_NAME as the identifier' do expect(packager.identifier).to eq('test.joessoftware.pkg.myproject') end end context 'when the project has the required Resource files' do before do project_file_path = '/omnibus/project/root/files/mac_pkg/Resources' %w[background.png welcome.html license.html].each do |basename| path = File.join(project_file_path, basename) File.stub(:exist?).with(path).and_return(true) end end it 'validates the presence of the required files' do expect(packager.validate_omnibus_project!).to be_true end end end