From a1ea2bd10a69a766736cbd1f23cdaafd3c90e2e3 Mon Sep 17 00:00:00 2001 From: James Treanor Date: Mon, 11 Dec 2017 12:14:05 +0000 Subject: [PATCH] Encapsulate PostInstallHooksContext within CocoapodsMangle::Context --- lib/cocoapods_mangle/builder.rb | 18 ++-- lib/cocoapods_mangle/config.rb | 14 +-- lib/cocoapods_mangle/context.rb | 91 ++++++++++-------- lib/cocoapods_mangle/post_install.rb | 1 - spec/unit/config_spec.rb | 28 ++---- spec/unit/context_spec.rb | 132 +++++++++++++++++---------- 6 files changed, 157 insertions(+), 127 deletions(-) diff --git a/lib/cocoapods_mangle/builder.rb b/lib/cocoapods_mangle/builder.rb index 25a18d8..6d41609 100644 --- a/lib/cocoapods_mangle/builder.rb +++ b/lib/cocoapods_mangle/builder.rb @@ -7,20 +7,20 @@ module CocoapodsMangle class Builder BUILT_PRODUCTS_DIR = 'build/Release-iphonesimulator' - # @param [Pod::Project] pods_project - # the pods project to build. + # @param [String] pods_project_path + # path to the pods project to build. # - # @param [Array] umbrella_pod_targets - # the umbrella pod targets to build. - def initialize(pods_project, umbrella_pod_targets) - @pods_project = pods_project - @umbrella_pod_targets = umbrella_pod_targets + # @param [Array] pod_target_labels + # the pod targets to build. + def initialize(pods_project_path, pod_target_labels) + @pods_project_path = pods_project_path + @pod_target_labels = pod_target_labels end # Build the pods project def build! FileUtils.remove_dir(BUILT_PRODUCTS_DIR, true) - @umbrella_pod_targets.each { |target| build_target(target.cocoapods_target_label) } + @pod_target_labels.each { |target| build_target(target) } end # Gives the built binaries to be mangled @@ -33,7 +33,7 @@ def binaries_to_mangle def build_target(target) Pod::UI.message "- Building '#{target}'" - output = `xcodebuild -project "#{@pods_project.path}" -target "#{target}" -configuration Release -sdk iphonesimulator build 2>&1` + output = `xcodebuild -project "#{@pods_project_path}" -target "#{target}" -configuration Release -sdk iphonesimulator build 2>&1` unless $?.success? raise "error: Building the Pods target '#{target}' failed.\ This is the build log:\n#{output}" end diff --git a/lib/cocoapods_mangle/config.rb b/lib/cocoapods_mangle/config.rb index 05f7718..aeadf18 100644 --- a/lib/cocoapods_mangle/config.rb +++ b/lib/cocoapods_mangle/config.rb @@ -17,7 +17,7 @@ def initialize(context) # Update the mangling xcconfig file with new mangling defines def update_mangling! Pod::UI.message '- Updating mangling xcconfig' do - builder = Builder.new(@context.pods_project, @context.umbrella_pod_targets) + builder = Builder.new(@context.pods_project_path, @context.pod_target_labels) builder.build! defines = Defines.mangling_defines(@context.mangle_prefix, builder.binaries_to_mangle) @@ -49,16 +49,8 @@ def needs_update? # Update all pod xcconfigs to use the mangling defines def update_pod_xcconfigs_for_mangling! - pod_xcconfigs = Set.new - - @context.pods_project.targets.each do |target| - target.build_configurations.each do |config| - pod_xcconfigs.add(config.base_configuration_reference.real_path) - end - end - - Pod::UI.message "- Updating Pod xcconfig files" do - pod_xcconfigs.each do |pod_xcconfig_path| + Pod::UI.message '- Updating Pod xcconfig files' do + @context.pod_xcconfig_paths.each do |pod_xcconfig_path| Pod::UI.message "- Updating '#{File.basename(pod_xcconfig_path)}'" update_pod_xcconfig_for_mangling!(pod_xcconfig_path) end diff --git a/lib/cocoapods_mangle/context.rb b/lib/cocoapods_mangle/context.rb index c75aeee..aba089d 100644 --- a/lib/cocoapods_mangle/context.rb +++ b/lib/cocoapods_mangle/context.rb @@ -1,20 +1,6 @@ module CocoapodsMangle # Context for mangling class Context - # @!attribute xcconfig_path - # @return [String] The path to the mangle xcconfig - attr_accessor :xcconfig_path - # @!attribute mangle_prefix - # @return [String] The mangle prefix to be used - attr_accessor :mangle_prefix - # @!attribute pods_project - # @return [Pod::Project] The Pods Xcode project - attr_accessor :pods_project - # @!attribute umbrella_pod_targets - # @return [Array] - # The umbrella targets to be mangled - attr_accessor :umbrella_pod_targets - # Initializes the context for mangling # @param [Pod::Installer::PostInstallHooksContext] installer_context # The post install context @@ -26,48 +12,73 @@ class Context # @option options [Array] :targets # The user targets whose dependencies should be mangled def initialize(installer_context, options) - @xcconfig_path = build_xcconfig_path(installer_context, options[:xcconfig_path]) - @pods_project = installer_context.pods_project - @umbrella_pod_targets = build_umbrella_pod_targets(installer_context, options[:targets]) - @mangle_prefix = build_mangle_prefix(@umbrella_pod_targets, options[:mangle_prefix]) + @installer_context = installer_context + @options = options + end + + # @return [String] The path to the mangle xcconfig + def xcconfig_path + return default_xcconfig_path unless @options[:xcconfig_path] + File.join(@installer_context.sandbox.root.parent, @options[:xcconfig_path]) + end + + # @return [String] The mangle prefix to be used + def mangle_prefix + return default_mangle_prefix unless @options[:mangle_prefix] + @options[:mangle_prefix] + end + + # @return [String] The path to pods project + def pods_project_path + @installer_context.pods_project.path + end + + # @return [Array] The targets in the pods project to be mangled + def pod_target_labels + umbrella_pod_targets.map(&:cocoapods_target_label) + end + + # @return [Array] Paths to all pod xcconfig files which should be updated + def pod_xcconfig_paths + pod_xcconfigs = [] + @installer_context.pods_project.targets.each do |target| + target.build_configurations.each do |config| + pod_xcconfigs << config.base_configuration_reference.real_path + end + end + pod_xcconfigs.uniq end # @return [String] A checksum representing the current state of the target dependencies def specs_checksum gem_summary = "#{CocoapodsMangle::NAME}=#{CocoapodsMangle::VERSION}" - specs = @umbrella_pod_targets.map(&:specs).flatten.uniq + specs = umbrella_pod_targets.map(&:specs).flatten.uniq specs_summary = specs.map(&:checksum).join(',') Digest::SHA1.hexdigest("#{gem_summary},#{specs_summary}") end private - def build_xcconfig_path(installer_context, user_xcconfig_path) - unless user_xcconfig_path - xcconfig_dir = installer_context.sandbox.target_support_files_root - xcconfig_filename = "#{CocoapodsMangle::NAME}.xcconfig" - return File.join(xcconfig_dir, xcconfig_filename) + def umbrella_pod_targets + if @options[:targets].nil? || @options[:targets].empty? + return @installer_context.umbrella_targets end - File.join(installer_context.sandbox.root.parent, user_xcconfig_path) - end - - def build_umbrella_pod_targets(installer_context, user_targets) - if user_targets.nil? || user_targets.empty? - return installer_context.umbrella_targets - end - installer_context.umbrella_targets.reject do |target| + @installer_context.umbrella_targets.reject do |target| target_names = target.user_targets.map(&:name) - (user_targets & target_names).empty? + (@options[:targets] & target_names).empty? end end - def build_mangle_prefix(umbrella_pod_targets, user_mangle_prefix) - unless user_mangle_prefix - project_path = umbrella_pod_targets.first.user_project.path - project_name = File.basename(project_path, '.xcodeproj') - return project_name.tr(' ', '_') + '_' - end - user_mangle_prefix + def default_xcconfig_path + xcconfig_dir = @installer_context.sandbox.target_support_files_root + xcconfig_filename = "#{CocoapodsMangle::NAME}.xcconfig" + File.join(xcconfig_dir, xcconfig_filename) + end + + def default_mangle_prefix + project_path = umbrella_pod_targets.first.user_project.path + project_name = File.basename(project_path, '.xcodeproj') + project_name.tr(' ', '_') + '_' end end end diff --git a/lib/cocoapods_mangle/post_install.rb b/lib/cocoapods_mangle/post_install.rb index c6c44b1..a5d3821 100644 --- a/lib/cocoapods_mangle/post_install.rb +++ b/lib/cocoapods_mangle/post_install.rb @@ -1,4 +1,3 @@ -require 'digest' require 'cocoapods' require 'cocoapods_mangle/config' diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb index e127f57..f6c167a 100644 --- a/spec/unit/config_spec.rb +++ b/spec/unit/config_spec.rb @@ -2,13 +2,14 @@ require 'cocoapods_mangle/config' describe CocoapodsMangle::Config do - let(:context) do + let(:context) do instance_double('Mangle context', xcconfig_path: 'path/to/mangle.xcconfig', - umbrella_pod_targets: [instance_double('target', cocoapods_target_label: 'Pods-A')], - pods_project: double('pods project'), + pod_target_labels: ['Pods-A'], + pods_project_path: 'path/to/Pods.xcodeproj', mangle_prefix: 'prefix_', - specs_checksum: 'checksum') + specs_checksum: 'checksum', + pod_xcconfig_paths: ['path/to/A.xcconfig', 'path/to/B.xcconfig']) end let(:subject) do CocoapodsMangle::Config.new(context) @@ -21,7 +22,7 @@ let(:builder) { double('builder') } before do - allow(CocoapodsMangle::Builder).to receive(:new).with(context.pods_project, context.umbrella_pod_targets).and_return(builder) + allow(CocoapodsMangle::Builder).to receive(:new).with(context.pods_project_path, context.pod_target_labels).and_return(builder) allow(builder).to receive(:build!) allow(builder).to receive(:binaries_to_mangle).and_return(binaries_to_mangle) allow(CocoapodsMangle::Defines).to receive(:mangling_defines).with(context.mangle_prefix, binaries_to_mangle).and_return(mangling_defines) @@ -88,21 +89,10 @@ end context '.update_pod_xcconfigs_for_mangling!' do - let(:pod_target) { double('target') } - let(:debug_build_configuration) { double('debug') } - let(:release_build_configuration) { double('release') } - - before do - allow(context.pods_project).to receive(:targets).and_return([pod_target]) - build_configurations = [debug_build_configuration, release_build_configuration] - allow(pod_target).to receive(:build_configurations).and_return(build_configurations) - build_configurations.each do |config| - allow(config).to receive_message_chain(:base_configuration_reference, :real_path).and_return('pod.xcconfig') - end - end - it 'updates each unique config' do - expect(subject).to receive(:update_pod_xcconfig_for_mangling!).with('pod.xcconfig').once + context.pod_xcconfig_paths.each do |pod_xcconfig| + expect(subject).to receive(:update_pod_xcconfig_for_mangling!).with(pod_xcconfig) + end subject.update_pod_xcconfigs_for_mangling! end end diff --git a/spec/unit/context_spec.rb b/spec/unit/context_spec.rb index 654d932..1e25b22 100644 --- a/spec/unit/context_spec.rb +++ b/spec/unit/context_spec.rb @@ -1,16 +1,6 @@ require File.expand_path('../../spec_helper', __FILE__) require 'cocoapods_mangle/context' -RSpec.shared_examples 'initializing context' do - it 'sets the correct values' do - context = CocoapodsMangle::Context.new(installer_context, options) - expect(context.xcconfig_path).to eq(xcconfig_path) - expect(context.umbrella_pod_targets).to eq(umbrella_pod_targets) - expect(context.pods_project).to eq(pods_project) - expect(context.mangle_prefix).to eq(mangle_prefix) - end -end - describe CocoapodsMangle::Context do let(:umbrella_targets) do [ @@ -19,57 +9,105 @@ instance_double('umbrella target C', cocoapods_target_label: 'Pods-C', user_targets: [instance_double('target C', name: 'C')]) ] end - let(:installer_context) { instance_double('installer', pods_project: double('pods project'), umbrella_targets: umbrella_targets) } + let(:installer_context) { instance_double('installer context', umbrella_targets: umbrella_targets) } + let(:options) { {} } + let(:subject) { CocoapodsMangle::Context.new(installer_context, options) } - before do - allow(installer_context).to receive_message_chain(:sandbox, :root, :parent).and_return( Pathname.new('/parent') ) - allow(installer_context).to receive_message_chain(:sandbox, :target_support_files_root).and_return( Pathname.new('/support_files') ) - allow(umbrella_targets.first).to receive_message_chain(:user_project, :path).and_return('path/to/Project.xcodeproj') - end + context '.xcconfig_path' do + before do + allow(installer_context).to receive_message_chain(:sandbox, :target_support_files_root).and_return( Pathname.new('/support_files') ) + allow(installer_context).to receive_message_chain(:sandbox, :root, :parent).and_return( Pathname.new('/parent') ) + end - context 'Initialization' do - context 'all user defined options' do - let(:options) { { targets: ['A', 'B'], xcconfig_path: 'path/to/mangle.xcconfig', mangle_prefix: 'prefix_' } } - let(:xcconfig_path) { "/parent/#{options[:xcconfig_path]}" } - let(:umbrella_pod_targets) { umbrella_targets[0..1] } - let(:pods_project) { installer_context.pods_project } - let(:mangle_prefix) { options[:mangle_prefix] } + context 'No options' do + it 'gives the default xcconfig path' do + expect(subject.xcconfig_path).to eq("/support_files/#{CocoapodsMangle::NAME}.xcconfig") + end + end - include_examples 'initializing context' + context 'User provided xcconfig path' do + let(:options) { { xcconfig_path: 'path/to/mangle.xcconfig' } } + it 'gives the user xcconfig path, relative to the project' do + expect(subject.xcconfig_path).to eq("/parent/#{options[:xcconfig_path]}") + end end + end - context 'only targets defined in options' do - let(:options) { { targets: ['A', 'B'] } } - let(:xcconfig_path) { "/support_files/#{CocoapodsMangle::NAME}.xcconfig" } - let(:umbrella_pod_targets) { umbrella_targets[0..1] } - let(:pods_project) { installer_context.pods_project } - let(:mangle_prefix) { 'Project_' } + context '.mangle_prefix' do + context 'No options' do + before do + allow(umbrella_targets.first).to receive_message_chain(:user_project, :path).and_return('path/to/Project.xcodeproj') + end - include_examples 'initializing context' + it 'gives the project name as the prefix' do + expect(subject.mangle_prefix).to eq('Project_') + end end - context 'only targets defined in options, with space in project name' do - let(:options) { { targets: ['A', 'B'] } } - let(:xcconfig_path) { "/support_files/#{CocoapodsMangle::NAME}.xcconfig" } - let(:umbrella_pod_targets) { umbrella_targets[0..1] } - let(:pods_project) { installer_context.pods_project } - let(:mangle_prefix) { 'Project_Name_' } - + context 'No options with space in project name' do before do allow(umbrella_targets.first).to receive_message_chain(:user_project, :path).and_return('path/to/Project Name.xcodeproj') end - include_examples 'initializing context' + it 'gives the project name with underscores as the prefix' do + expect(subject.mangle_prefix).to eq('Project_Name_') + end end - context 'no options' do - let(:options) { {} } - let(:xcconfig_path) { "/support_files/#{CocoapodsMangle::NAME}.xcconfig" } - let(:umbrella_pod_targets) { umbrella_targets[0..2] } - let(:pods_project) { installer_context.pods_project } - let(:mangle_prefix) { 'Project_' } + context 'User provided prefix' do + let(:options) { { mangle_prefix: 'Prefix_' } } + + it 'gives the user prefix' do + expect(subject.mangle_prefix).to eq(options[:mangle_prefix]) + end + end + end + + context '.pods_project_path' do + let(:pods_project) { instance_double('pods project', path: 'path/to/Pods.xcodeproj') } + + before do + allow(installer_context).to receive(:pods_project).and_return(pods_project) + end + + it 'gives the project path' do + expect(subject.pods_project_path).to eq(pods_project.path) + end + end + + context '.pod_target_labels' do + context 'No options' do + it 'gives all targets' do + expect(subject.pod_target_labels).to eq(['Pods-A', 'Pods-B', 'Pods-C']) + end + end + + context 'With targets' do + let(:options) { { targets: ['A', 'B'] } } + it 'gives only requested targets' do + expect(subject.pod_target_labels).to eq(['Pods-A', 'Pods-B']) + end + end + end + + context '.pod_xcconfig_paths' do + let(:pods_project) { instance_double('pods project', path: 'path/to/Pods.xcodeproj') } + let(:pod_target) { double('target') } + let(:debug_build_configuration) { double('debug') } + let(:release_build_configuration) { double('release') } + + before do + allow(installer_context).to receive(:pods_project).and_return(pods_project) + allow(pods_project).to receive(:targets).and_return([pod_target]) + build_configurations = [debug_build_configuration, release_build_configuration] + allow(pod_target).to receive(:build_configurations).and_return(build_configurations) + build_configurations.each do |config| + allow(config).to receive_message_chain(:base_configuration_reference, :real_path).and_return('path/to/pod.xcconfig') + end + end - include_examples 'initializing context' + it 'gives the pod xcconfigs' do + expect(subject.pod_xcconfig_paths).to eq(['path/to/pod.xcconfig']) end end @@ -77,7 +115,7 @@ let(:gem_summary) { "#{CocoapodsMangle::NAME}=#{CocoapodsMangle::VERSION}" } let(:spec_A) { instance_double('Spec A', checksum: 'checksum_A') } let(:spec_B) { instance_double('Spec B', checksum: 'checksum_B') } - let(:subject) { CocoapodsMangle::Context.new(installer_context, targets: ['A']) } + let(:options) { { targets: ['A'] } } before do allow(umbrella_targets.first).to receive(:specs).and_return([spec_A, spec_B])