cocoapods 1.6.2 → 1.7.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -7
  3. data/README.md +9 -9
  4. data/lib/cocoapods.rb +2 -0
  5. data/lib/cocoapods/command.rb +1 -1
  6. data/lib/cocoapods/command/init.rb +2 -12
  7. data/lib/cocoapods/command/install.rb +3 -0
  8. data/lib/cocoapods/command/lib/create.rb +1 -1
  9. data/lib/cocoapods/command/lib/lint.rb +5 -1
  10. data/lib/cocoapods/command/list.rb +3 -5
  11. data/lib/cocoapods/command/repo.rb +1 -0
  12. data/lib/cocoapods/command/repo/add.rb +4 -5
  13. data/lib/cocoapods/command/repo/add_cdn.rb +58 -0
  14. data/lib/cocoapods/command/repo/list.rb +5 -6
  15. data/lib/cocoapods/command/repo/push.rb +6 -5
  16. data/lib/cocoapods/command/spec/create.rb +12 -12
  17. data/lib/cocoapods/command/spec/lint.rb +1 -1
  18. data/lib/cocoapods/command/update.rb +3 -0
  19. data/lib/cocoapods/config.rb +1 -0
  20. data/lib/cocoapods/executable.rb +32 -7
  21. data/lib/cocoapods/gem_version.rb +1 -1
  22. data/lib/cocoapods/generator/app_target_helper.rb +1 -1
  23. data/lib/cocoapods/generator/embed_frameworks_script.rb +13 -0
  24. data/lib/cocoapods/generator/file_list.rb +39 -0
  25. data/lib/cocoapods/generator/module_map.rb +1 -1
  26. data/lib/cocoapods/installer.rb +188 -46
  27. data/lib/cocoapods/installer/analyzer.rb +64 -39
  28. data/lib/cocoapods/installer/analyzer/pod_variant.rb +14 -9
  29. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +11 -2
  30. data/lib/cocoapods/installer/installation_options.rb +70 -44
  31. data/lib/cocoapods/installer/pod_source_installer.rb +9 -4
  32. data/lib/cocoapods/installer/podfile_validator.rb +9 -0
  33. data/lib/cocoapods/installer/post_install_hooks_context.rb +5 -2
  34. data/lib/cocoapods/installer/project_cache/project_cache.rb +11 -0
  35. data/lib/cocoapods/installer/project_cache/project_cache_analysis_result.rb +53 -0
  36. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +156 -0
  37. data/lib/cocoapods/installer/project_cache/project_cache_version.rb +43 -0
  38. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +77 -0
  39. data/lib/cocoapods/installer/project_cache/project_metadata_cache.rb +63 -0
  40. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +134 -0
  41. data/lib/cocoapods/installer/project_cache/target_metadata.rb +70 -0
  42. data/lib/cocoapods/installer/sandbox_dir_cleaner.rb +89 -0
  43. data/lib/cocoapods/installer/sandbox_header_paths_installer.rb +45 -0
  44. data/lib/cocoapods/installer/target_uuid_generator.rb +32 -0
  45. data/lib/cocoapods/installer/user_project_integrator.rb +8 -6
  46. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +128 -63
  47. data/lib/cocoapods/installer/xcode.rb +3 -0
  48. data/lib/cocoapods/installer/xcode/multi_pods_project_generator.rb +72 -0
  49. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +102 -218
  50. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +75 -0
  51. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +1 -1
  52. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +29 -17
  53. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +31 -65
  54. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +155 -0
  55. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +265 -110
  56. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +70 -43
  57. data/lib/cocoapods/installer/xcode/pods_project_generator/pods_project_writer.rb +75 -0
  58. data/lib/cocoapods/installer/xcode/pods_project_generator/project_generator.rb +119 -0
  59. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +44 -7
  60. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +5 -7
  61. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +32 -0
  62. data/lib/cocoapods/installer/xcode/pods_project_generator_result.rb +35 -0
  63. data/lib/cocoapods/installer/xcode/single_pods_project_generator.rb +38 -0
  64. data/lib/cocoapods/installer/xcode/target_validator.rb +32 -25
  65. data/lib/cocoapods/native_target_extension.rb +54 -0
  66. data/lib/cocoapods/open-uri.rb +1 -1
  67. data/lib/cocoapods/podfile.rb +13 -0
  68. data/lib/cocoapods/project.rb +88 -10
  69. data/lib/cocoapods/resolver.rb +11 -8
  70. data/lib/cocoapods/resolver/resolver_specification.rb +7 -7
  71. data/lib/cocoapods/sandbox.rb +38 -9
  72. data/lib/cocoapods/sandbox/file_accessor.rb +21 -0
  73. data/lib/cocoapods/sandbox/headers_store.rb +18 -3
  74. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +1 -14
  75. data/lib/cocoapods/sources_manager.rb +11 -3
  76. data/lib/cocoapods/target.rb +67 -7
  77. data/lib/cocoapods/target/aggregate_target.rb +70 -8
  78. data/lib/cocoapods/target/build_settings.rb +124 -65
  79. data/lib/cocoapods/target/build_type.rb +139 -0
  80. data/lib/cocoapods/target/framework_paths.rb +12 -7
  81. data/lib/cocoapods/target/pod_target.rb +322 -65
  82. data/lib/cocoapods/user_interface.rb +2 -2
  83. data/lib/cocoapods/user_interface/error_report.rb +3 -0
  84. data/lib/cocoapods/user_interface/inspector_reporter.rb +1 -1
  85. data/lib/cocoapods/validator.rb +74 -39
  86. data/lib/cocoapods/version_metadata.rb +7 -0
  87. metadata +30 -6
@@ -0,0 +1,134 @@
1
+ module Pod
2
+ class Installer
3
+ module ProjectCache
4
+ # Uniquely identifies a Target.
5
+ #
6
+ class TargetCacheKey
7
+ require 'cocoapods/target/pod_target.rb'
8
+ require 'cocoapods/target/aggregate_target.rb'
9
+ require 'digest'
10
+
11
+ # @return [Symbol]
12
+ # The type of target. Either aggregate or pod target.
13
+ #
14
+ attr_reader :type
15
+
16
+ # @return [Hash{String => Object}]
17
+ # The hash containing key-value pairs that identify the target.
18
+ #
19
+ attr_reader :key_hash
20
+
21
+ # Initialize a new instance.
22
+ #
23
+ # @param [Symbol] type @see #type
24
+ # @param [Hash{String => Object}] key_hash @see #key_hash
25
+ #
26
+ def initialize(type, key_hash)
27
+ @type = type
28
+ @key_hash = key_hash
29
+ end
30
+
31
+ # Equality function used to compare TargetCacheKey objects to each other.
32
+ #
33
+ # @param [TargetCacheKey] other
34
+ # Other object to compare itself against.
35
+ #
36
+ # @return [Symbol] The difference between this and another TargetCacheKey object.
37
+ # # Symbol :none means no difference.
38
+ #
39
+ def key_difference(other)
40
+ if other.type != type
41
+ :project
42
+ else
43
+ case type
44
+ when :pod_target
45
+ return :project if (other.key_hash.keys - key_hash.keys).any?
46
+ return :project if other.key_hash['CHECKSUM'] != key_hash['CHECKSUM']
47
+ return :project if other.key_hash['SPECS'] != key_hash['SPECS']
48
+ return :project if other.key_hash['FILES'] != key_hash['FILES']
49
+ end
50
+
51
+ this_build_settings = key_hash['BUILD_SETTINGS_CHECKSUM']
52
+ other_build_settings = other.key_hash['BUILD_SETTINGS_CHECKSUM']
53
+ return :project if this_build_settings != other_build_settings
54
+
55
+ this_checkout_options = key_hash['CHECKOUT_OPTIONS']
56
+ other_checkout_options = other.key_hash['CHECKOUT_OPTIONS']
57
+ return :project if this_checkout_options != other_checkout_options
58
+
59
+ :none
60
+ end
61
+ end
62
+
63
+ def to_h
64
+ key_hash
65
+ end
66
+
67
+ # Creates a TargetCacheKey instance from the given hash.
68
+ #
69
+ # @param [Hash{String => Object}] key_hash
70
+ # The hash used to construct a TargetCacheKey object.
71
+ #
72
+ # @return [TargetCacheKey]
73
+ #
74
+ def self.from_cache_hash(key_hash)
75
+ cache_hash = key_hash.dup
76
+ if files = cache_hash['FILES']
77
+ cache_hash['FILES'] = files.sort
78
+ end
79
+ type = cache_hash['CHECKSUM'] ? :pod_target : :aggregate
80
+ TargetCacheKey.new(type, cache_hash)
81
+ end
82
+
83
+ # Constructs a TargetCacheKey instance from a PodTarget.
84
+ #
85
+ # @param [PodTarget] pod_target
86
+ # The pod target used to construct a TargetCacheKey object.
87
+ #
88
+ # @param [Bool] is_local_pod
89
+ # Used to also include its local files in the cache key.
90
+ #
91
+ # @param [Hash] checkout_options
92
+ # The checkout options for this pod target.
93
+ #
94
+ # @return [TargetCacheKey]
95
+ #
96
+ def self.from_pod_target(pod_target, is_local_pod: false, checkout_options: nil)
97
+ build_settings = {}
98
+ build_settings[pod_target.label.to_s] = Digest::MD5.hexdigest(pod_target.build_settings.xcconfig.to_s)
99
+ pod_target.test_spec_build_settings.each do |name, settings|
100
+ build_settings[name] = Digest::MD5.hexdigest(settings.xcconfig.to_s)
101
+ end
102
+ pod_target.app_spec_build_settings.each do |name, settings|
103
+ build_settings[name] = Digest::MD5.hexdigest(settings.xcconfig.to_s)
104
+ end
105
+
106
+ contents = {
107
+ 'CHECKSUM' => pod_target.root_spec.checksum,
108
+ 'SPECS' => pod_target.specs.map(&:to_s).sort,
109
+ 'BUILD_SETTINGS_CHECKSUM' => build_settings,
110
+ }
111
+ contents['FILES'] = pod_target.all_files.sort if is_local_pod
112
+ contents['CHECKOUT_OPTIONS'] = checkout_options if checkout_options
113
+ TargetCacheKey.new(:pod_target, contents)
114
+ end
115
+
116
+ # Construct a TargetCacheKey instance from an AggregateTarget.
117
+ #
118
+ # @param [AggregateTarget] aggregate_target
119
+ # The aggregate target used to construct a TargetCacheKey object.
120
+ #
121
+ # @return [TargetCacheKey]
122
+ #
123
+ def self.from_aggregate_target(aggregate_target)
124
+ build_settings = {}
125
+ aggregate_target.user_build_configurations.keys.each do |configuration|
126
+ build_settings[configuration] = Digest::MD5.hexdigest(aggregate_target.build_settings(configuration).xcconfig.to_s)
127
+ end
128
+
129
+ TargetCacheKey.new(:aggregate, 'BUILD_SETTINGS_CHECKSUM' => build_settings)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,70 @@
1
+ module Pod
2
+ class Installer
3
+ module ProjectCache
4
+ # Metadata used to reconstruct a PBXTargetDependency.
5
+ #
6
+ class TargetMetadata
7
+ # @return [String]
8
+ # The label of the native target.
9
+ #
10
+ attr_reader :target_label
11
+
12
+ # @return [String]
13
+ # The UUID of the native target installed.
14
+ #
15
+ attr_reader :native_target_uuid
16
+
17
+ # @return [String]
18
+ # The path of the container project the native target was installed into.
19
+ #
20
+ attr_reader :container_project_path
21
+
22
+ # Initialize a new instance.
23
+ #
24
+ # @param [String] target_label @see #target_label
25
+ # @param [String] native_target_uuid @see #native_target_uuid
26
+ # @param [String] container_project_path @see #container_project_path
27
+ #
28
+ def initialize(target_label, native_target_uuid, container_project_path)
29
+ @target_label = target_label
30
+ @native_target_uuid = native_target_uuid
31
+ @container_project_path = container_project_path
32
+ end
33
+
34
+ def to_hash
35
+ {
36
+ 'LABEL' => target_label,
37
+ 'UUID' => native_target_uuid,
38
+ 'PROJECT_PATH' => container_project_path,
39
+ }
40
+ end
41
+
42
+ def to_s
43
+ "#{target_label} : #{native_target_uuid} : #{container_project_path}"
44
+ end
45
+
46
+ # Constructs a TargetMetadata instance from a hash.
47
+ #
48
+ # @param [Hash] hash
49
+ # The hash used to construct a new TargetMetadata instance.
50
+ #
51
+ # @return [TargetMetadata]
52
+ #
53
+ def self.from_hash(hash)
54
+ TargetMetadata.new(hash['LABEL'], hash['UUID'], hash['PROJECT_PATH'])
55
+ end
56
+
57
+ # Constructs a TargetMetadata instance from a native target.
58
+ #
59
+ # @param [PBXNativeTarget] native_target
60
+ # The native target used to construct a TargetMetadata instance.
61
+ #
62
+ # @return [TargetMetadata]
63
+ #
64
+ def self.from_native_target(native_target)
65
+ TargetMetadata.new(native_target.name, native_target.uuid, native_target.project.path.to_s)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,89 @@
1
+ module Pod
2
+ class Installer
3
+ # Cleans up the sandbox directory by removing stale target support files and headers.
4
+ #
5
+ class SandboxDirCleaner
6
+ # @return [Sandbox] The sandbox directory that will be cleaned.
7
+ #
8
+ attr_reader :sandbox
9
+
10
+ # @return [Array<PodTarget>]
11
+ # The list of all pod targets that will be installed into the Sandbox.
12
+ #
13
+ attr_reader :pod_targets
14
+
15
+ # @return [Array<AggregateTarget>]
16
+ # The list of all aggregate targets that will be installed into the Sandbox.
17
+ #
18
+ attr_reader :aggregate_targets
19
+
20
+ # Initialize a new instance
21
+ #
22
+ # @param [Sandbox] sandbox @see #sandbox
23
+ # @param [Array<PodTarget>] pod_targets @see #pod_targets
24
+ # @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
25
+ #
26
+ def initialize(sandbox, pod_targets, aggregate_targets)
27
+ @sandbox = sandbox
28
+ @pod_targets = pod_targets
29
+ @aggregate_targets = aggregate_targets
30
+ end
31
+
32
+ def clean!
33
+ UI.message('Cleaning up sandbox directory') do
34
+ # Clean up Target Support Files Directory
35
+ target_support_dirs_to_install = (pod_targets + aggregate_targets).map(&:support_files_dir)
36
+ target_support_dirs = sandbox_target_support_dirs
37
+
38
+ removed_target_support_dirs = target_support_dirs - target_support_dirs_to_install
39
+ removed_target_support_dirs.each { |dir| remove_dir(dir) }
40
+
41
+ # Clean up Sandbox Headers Directory
42
+ sandbox_private_headers_to_install = pod_targets.flat_map do |pod_target|
43
+ if pod_target.header_mappings_by_file_accessor.empty?
44
+ []
45
+ else
46
+ [pod_target.build_headers.root.join(pod_target.headers_sandbox)]
47
+ end
48
+ end
49
+ sandbox_public_headers_to_install = pod_targets.flat_map do |pod_target|
50
+ if pod_target.public_header_mappings_by_file_accessor.empty?
51
+ []
52
+ else
53
+ [sandbox.public_headers.root.join(pod_target.headers_sandbox)]
54
+ end
55
+ end
56
+
57
+ removed_sandbox_public_headers = sandbox_public_headers - sandbox_public_headers_to_install
58
+ removed_sandbox_public_headers.each { |path| remove_dir(path) }
59
+
60
+ removed_sandbox_private_headers = sandbox_private_headers(pod_targets) - sandbox_private_headers_to_install
61
+ removed_sandbox_private_headers.each { |path| remove_dir(path) }
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def sandbox_target_support_dirs
68
+ child_directories_of(sandbox.target_support_files_root)
69
+ end
70
+
71
+ def sandbox_private_headers(pod_targets)
72
+ pod_targets.flat_map { |pod_target| child_directories_of(pod_target.build_headers.root) }.uniq
73
+ end
74
+
75
+ def sandbox_public_headers
76
+ child_directories_of(sandbox.public_headers.root)
77
+ end
78
+
79
+ def child_directories_of(dir)
80
+ return [] unless dir.exist?
81
+ dir.children.select(&:directory?)
82
+ end
83
+
84
+ def remove_dir(path)
85
+ FileUtils.rm_rf(path)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,45 @@
1
+ module Pod
2
+ class Installer
3
+ # Adds all the search paths into the sandbox HeaderStore and each pod target's HeaderStore.
4
+ #
5
+ class SandboxHeaderPathsInstaller
6
+ # @return [Sandbox] The sandbox to use for this analysis.
7
+ #
8
+ attr_reader :sandbox
9
+
10
+ # @return [Array<PodTarget>] The list of pod targets to analyze.
11
+ #
12
+ attr_reader :pod_targets
13
+
14
+ # Initialize a new instance
15
+ #
16
+ # @param [Sandbox] sandbox @see #sandbox
17
+ # @param [Array<PodTarget>] pod_targets @see #pod_targets
18
+ #
19
+ def initialize(sandbox, pod_targets)
20
+ @pod_targets = pod_targets
21
+ @sandbox = sandbox
22
+ end
23
+
24
+ def install!
25
+ # Link all pod target header search paths into the HeaderStore.
26
+ pod_targets.each do |pod_target|
27
+ next if pod_target.build_as_framework? && pod_target.should_build?
28
+ install_target(pod_target)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def install_target(pod_target)
35
+ pod_target_header_mappings = pod_target.header_mappings_by_file_accessor.values
36
+ public_header_mappings = pod_target.public_header_mappings_by_file_accessor.values
37
+ added_build_headers = !pod_target_header_mappings.all?(&:empty?)
38
+ added_public_headers = !public_header_mappings.all?(&:empty?)
39
+
40
+ pod_target.build_headers.add_search_path(pod_target.headers_sandbox, pod_target.platform) if added_build_headers
41
+ sandbox.public_headers.add_search_path(pod_target.headers_sandbox, pod_target.platform) if added_public_headers
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+ module Pod
2
+ class Installer
3
+ # Generates stable UUIDs for Native Targets.
4
+ #
5
+ class TargetUUIDGenerator < Xcodeproj::Project::UUIDGenerator
6
+ # This method override is used to ONLY generate stable UUIDs for PBXNativeTarget instances and no other type.
7
+ # Stable native target UUIDs are necessary for incremental installation because other projects reference the
8
+ # target by its UUID in the remoteGlobalIDString field.
9
+ #
10
+ # @param [Array<Project>] projects
11
+ # The list of projects used to generate stabe target UUIDs.
12
+ #
13
+ def generate_all_paths_by_objects(projects)
14
+ @paths_by_object = {}
15
+ projects.each do |project|
16
+ project_basename = project.path.basename.to_s
17
+ project.objects.each do |object|
18
+ @paths_by_object[object] = if object.is_a? Xcodeproj::Project::Object::AbstractTarget
19
+ Digest::MD5.hexdigest(project_basename + object.name).upcase
20
+ else
21
+ object.uuid
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def uuid_for_path(path)
28
+ path
29
+ end
30
+ end
31
+ end
32
+ end
@@ -13,10 +13,6 @@ module Pod
13
13
  class UserProjectIntegrator
14
14
  autoload :TargetIntegrator, 'cocoapods/installer/user_project_integrator/target_integrator'
15
15
 
16
- include InstallationOptions::Mixin
17
-
18
- delegate_installation_options { podfile }
19
-
20
16
  # @return [Podfile] the podfile that should be integrated with the user
21
17
  # projects.
22
18
  #
@@ -41,6 +37,11 @@ module Pod
41
37
  #
42
38
  attr_reader :targets
43
39
 
40
+ # @return [Boolean] whether to use input/output paths for build phase scripts
41
+ #
42
+ attr_reader :use_input_output_paths
43
+ alias use_input_output_paths? use_input_output_paths
44
+
44
45
  # Init a new UserProjectIntegrator
45
46
  #
46
47
  # @param [Podfile] podfile @see #podfile
@@ -48,11 +49,12 @@ module Pod
48
49
  # @param [Pathname] installation_root @see #installation_root
49
50
  # @param [Array<AggregateTarget>] targets @see #targets
50
51
  #
51
- def initialize(podfile, sandbox, installation_root, targets)
52
+ def initialize(podfile, sandbox, installation_root, targets, use_input_output_paths: true)
52
53
  @podfile = podfile
53
54
  @sandbox = sandbox
54
55
  @installation_root = installation_root
55
56
  @targets = targets
57
+ @use_input_output_paths = use_input_output_paths
56
58
  end
57
59
 
58
60
  # Integrates the user projects associated with the {TargetDefinitions}
@@ -115,7 +117,7 @@ module Pod
115
117
  #
116
118
  def integrate_user_targets
117
119
  target_integrators = targets_to_integrate.sort_by(&:name).map do |target|
118
- TargetIntegrator.new(target, installation_options)
120
+ TargetIntegrator.new(target, :use_input_output_paths => use_input_output_paths?)
119
121
  end
120
122
 
121
123
  Config.instance.with_changes(:silent => true) do
@@ -49,21 +49,68 @@ module Pod
49
49
  #
50
50
  attr_reader :target
51
51
 
52
- # @return [InstallationOptions] the installation options from the Podfile.
52
+ # @return [Boolean] whether to use input/output paths for build phase scripts
53
53
  #
54
- attr_reader :installation_options
54
+ attr_reader :use_input_output_paths
55
+ alias use_input_output_paths? use_input_output_paths
55
56
 
56
57
  # Init a new TargetIntegrator
57
58
  #
58
59
  # @param [AggregateTarget] target @see #target
59
- # @param [InstallationOptions] installation_options @see #installation_options
60
+ # @param [Boolean] use_input_output_paths @see #use_input_output_paths
60
61
  #
61
- def initialize(target, installation_options)
62
+ def initialize(target, use_input_output_paths: true)
62
63
  @target = target
63
- @installation_options = installation_options
64
+ @use_input_output_paths = use_input_output_paths
64
65
  end
65
66
 
67
+ # @private
68
+ #
69
+ XCFileListConfigKey = Struct.new(:file_list_path, :file_list_relative_path)
70
+
66
71
  class << self
72
+ # @param [Xcodeproj::Project::Object::AbstractObject] object
73
+ #
74
+ # @return [Boolean] Whether input & output paths for the given object
75
+ # should be stored in a file list file.
76
+ #
77
+ def input_output_paths_use_filelist?(object)
78
+ object.project.object_version.to_i >= 50
79
+ end
80
+
81
+ # Sets the input & output paths for the given script build phase.
82
+ #
83
+ # @param [Xcodeproj::Project::Object::PBXShellScriptBuildPhase] phase
84
+ # The phase to set input & output paths on.
85
+ #
86
+ # @param [Hash] input_paths_by_config
87
+ #
88
+ # @return [Void]
89
+ def set_input_output_paths(phase, input_paths_by_config, output_paths_by_config)
90
+ if input_output_paths_use_filelist?(phase)
91
+ [input_paths_by_config, output_paths_by_config].each do |hash|
92
+ hash.each do |file_list, files|
93
+ generator = Generator::FileList.new(files)
94
+ Xcode::PodsProjectGenerator::TargetInstallerHelper.update_changed_file(generator, file_list.file_list_path)
95
+ end
96
+ end
97
+
98
+ phase.input_paths = nil
99
+ phase.output_paths = nil
100
+ phase.input_file_list_paths = input_paths_by_config.each_key.map(&:file_list_relative_path).uniq
101
+ phase.output_file_list_paths = output_paths_by_config.each_key.map(&:file_list_relative_path).uniq
102
+ else
103
+ input_paths = input_paths_by_config.values.flatten(1).uniq
104
+ output_paths = output_paths_by_config.values.flatten(1).uniq
105
+ TargetIntegrator.validate_input_output_path_limit(input_paths, output_paths)
106
+
107
+ phase.input_paths = input_paths
108
+ phase.output_paths = output_paths
109
+ phase.input_file_list_paths = nil
110
+ phase.output_file_list_paths = nil
111
+ end
112
+ end
113
+
67
114
  # Adds a shell script build phase responsible to copy (embed) the frameworks
68
115
  # generated by the TargetDefinition to the bundle of the product of the
69
116
  # targets.
@@ -74,19 +121,18 @@ module Pod
74
121
  # @param [String] script_path
75
122
  # The script path to execute as part of this script phase.
76
123
  #
77
- # @param [Array<String>] input_paths
124
+ # @param [Hash<Array, String>] input_paths_by_config
78
125
  # The input paths (if any) to include for this script phase.
79
126
  #
80
- # @param [Array<String>] output_paths
127
+ # @param [Hash<Array, String>] output_paths_by_config
81
128
  # The output paths (if any) to include for this script phase.
82
129
  #
83
130
  # @return [void]
84
131
  #
85
- def create_or_update_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths = [], output_paths = [])
86
- phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + EMBED_FRAMEWORK_PHASE_NAME)
132
+ def create_or_update_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths_by_config = {}, output_paths_by_config = {})
133
+ phase = TargetIntegrator.create_or_update_shell_script_build_phase(native_target, BUILD_PHASE_PREFIX + EMBED_FRAMEWORK_PHASE_NAME)
87
134
  phase.shell_script = %("#{script_path}"\n)
88
- phase.input_paths = input_paths
89
- phase.output_paths = output_paths
135
+ TargetIntegrator.set_input_output_paths(phase, input_paths_by_config, output_paths_by_config)
90
136
  end
91
137
 
92
138
  # Delete a 'Embed Pods Frameworks' Copy Files Build Phase if present
@@ -110,20 +156,19 @@ module Pod
110
156
  # @param [String] script_path
111
157
  # The script path to execute as part of this script phase.
112
158
  #
113
- # @param [Array<String>] input_paths
159
+ # @param [Hash<Array, String>] input_paths_by_config
114
160
  # The input paths (if any) to include for this script phase.
115
161
  #
116
- # @param [Array<String>] output_paths
162
+ # @param [Hash<Array, String>] output_paths_by_config
117
163
  # The output paths (if any) to include for this script phase.
118
164
  #
119
165
  # @return [void]
120
166
  #
121
- def create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths = [], output_paths = [])
167
+ def create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths_by_config = {}, output_paths_by_config = {})
122
168
  phase_name = COPY_PODS_RESOURCES_PHASE_NAME
123
- phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
169
+ phase = TargetIntegrator.create_or_update_shell_script_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
124
170
  phase.shell_script = %("#{script_path}"\n)
125
- phase.input_paths = input_paths
126
- phase.output_paths = output_paths
171
+ TargetIntegrator.set_input_output_paths(phase, input_paths_by_config, output_paths_by_config)
127
172
  end
128
173
 
129
174
  # Delete a 'Copy Pods Resources' script phase if present
@@ -142,21 +187,24 @@ module Pod
142
187
  # @param [PBXNativeTarget] native_target
143
188
  # The native target to add the script phase into.
144
189
  #
145
- # @param [String] phase_name
146
- # The name of the phase to use.
190
+ # @param [String] script_phase_name
191
+ # The name of the script phase to use.
147
192
  #
148
- # @param [Class] phase_class
149
- # The class of the phase to use.
193
+ # @param [String] show_env_vars_in_log
194
+ # The value to set for show environment variables in the log during execution of this script phase or
195
+ # `nil` for not setting the value at all.
150
196
  #
151
197
  # @return [void]
152
198
  #
153
- def create_or_update_build_phase(native_target, phase_name, phase_class = Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
154
- build_phases = native_target.build_phases.grep(phase_class)
155
- build_phases.find { |phase| phase.name && phase.name.end_with?(phase_name) }.tap { |p| p.name = phase_name if p } ||
156
- native_target.project.new(phase_class).tap do |phase|
157
- UI.message("Adding Build Phase '#{phase_name}' to project.") do
158
- phase.name = phase_name
159
- phase.show_env_vars_in_log = '0'
199
+ def create_or_update_shell_script_build_phase(native_target, script_phase_name, show_env_vars_in_log = '0')
200
+ build_phases = native_target.build_phases.grep(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
201
+ build_phases.find { |phase| phase.name && phase.name.end_with?(script_phase_name) }.tap { |p| p.name = script_phase_name if p } ||
202
+ native_target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase).tap do |phase|
203
+ UI.message("Adding Build Phase '#{script_phase_name}' to project.") do
204
+ phase.name = script_phase_name
205
+ unless show_env_vars_in_log.nil?
206
+ phase.show_env_vars_in_log = show_env_vars_in_log
207
+ end
160
208
  native_target.build_phases << phase
161
209
  end
162
210
  end
@@ -180,12 +228,16 @@ module Pod
180
228
  # Create or update the ones that are expected to be.
181
229
  script_phases.each do |script_phase|
182
230
  name_with_prefix = USER_BUILD_PHASE_PREFIX + script_phase[:name]
183
- phase = TargetIntegrator.create_or_update_build_phase(native_target, name_with_prefix)
231
+ phase = TargetIntegrator.create_or_update_shell_script_build_phase(native_target, name_with_prefix, nil)
184
232
  phase.shell_script = script_phase[:script]
185
- phase.shell_path = script_phase[:shell_path] if script_phase.key?(:shell_path)
186
- phase.input_paths = script_phase[:input_files] if script_phase.key?(:input_files)
187
- phase.output_paths = script_phase[:output_files] if script_phase.key?(:output_files)
188
- phase.show_env_vars_in_log = script_phase[:show_env_vars_in_log] ? '1' : '0' if script_phase.key?(:show_env_vars_in_log)
233
+ phase.shell_path = script_phase[:shell_path] || '/bin/sh'
234
+ phase.input_paths = script_phase[:input_files]
235
+ phase.output_paths = script_phase[:output_files]
236
+ # At least with Xcode 10 `showEnvVarsInLog` is *NOT* set to any value even if it's checked and it only
237
+ # gets set to '0' if the user has explicitly disabled this.
238
+ if (show_env_vars_in_log = script_phase.fetch(:show_env_vars_in_log, '1')) == '0'
239
+ phase.show_env_vars_in_log = show_env_vars_in_log
240
+ end
189
241
 
190
242
  execution_position = script_phase[:execution_position]
191
243
  unless execution_position == :any
@@ -321,22 +373,25 @@ module Pod
321
373
  frameworks = user_project.frameworks_group
322
374
  native_targets.each do |native_target|
323
375
  build_phase = native_target.frameworks_build_phase
376
+ product_name = target.product_name
377
+
378
+ # Delete previously integrated references.
379
+ product_build_files = build_phase.files.select do |build_file|
380
+ build_file.display_name =~ Pod::Deintegrator::FRAMEWORK_NAMES
381
+ end
324
382
 
325
- # Find and delete possible reference for the other product type
326
- old_product_name = target.requires_frameworks? ? target.static_library_name : target.framework_name
327
- old_product_ref = frameworks.files.find { |f| f.path == old_product_name }
328
- if old_product_ref.present?
329
- UI.message("Removing old Pod product reference #{old_product_name} from project.")
330
- build_phase.remove_file_reference(old_product_ref)
331
- frameworks.remove_reference(old_product_ref)
383
+ product_build_files.each do |product_file|
384
+ next unless product_name != product_file.display_name
385
+ UI.message("Removing old product reference `#{product_file.display_name}` from project.")
386
+ frameworks.remove_reference(product_file.file_ref)
387
+ build_phase.remove_build_file(product_file)
332
388
  end
333
389
 
334
390
  # Find or create and add a reference for the current product type
335
- target_basename = target.product_basename
336
- new_product_ref = frameworks.files.find { |f| f.path == target.product_name } ||
337
- frameworks.new_product_ref_for_target(target_basename, target.product_type)
391
+ new_product_ref = frameworks.files.find { |f| f.path == product_name } ||
392
+ frameworks.new_product_ref_for_target(target.product_basename, target.product_type)
338
393
  build_phase.build_file(new_product_ref) ||
339
- build_phase.add_file_reference(new_product_ref, true)
394
+ build_phase.add_file_reference(new_product_ref, true)
340
395
  end
341
396
  end
342
397
 
@@ -351,20 +406,24 @@ module Pod
351
406
  end
352
407
  return
353
408
  end
409
+
354
410
  script_path = target.copy_resources_script_relative_path
355
- input_paths = []
356
- output_paths = []
357
- unless installation_options.disable_input_output_paths?
358
- resource_paths_by_config = target.resource_paths_by_config
359
- resource_paths_flattened = resource_paths_by_config.values.flatten.uniq
360
- input_paths = [target.copy_resources_script_relative_path, *resource_paths_flattened]
361
- output_paths = TargetIntegrator.resource_output_paths(resource_paths_flattened)
411
+ input_paths_by_config = {}
412
+ output_paths_by_config = {}
413
+ if use_input_output_paths
414
+ target.resource_paths_by_config.each do |config, resource_paths|
415
+ input_paths_key = XCFileListConfigKey.new(target.copy_resources_script_input_files_path(config), target.copy_resources_script_input_files_relative_path)
416
+ input_paths_by_config[input_paths_key] = [script_path] + resource_paths
417
+
418
+ output_paths_key = XCFileListConfigKey.new(target.copy_resources_script_output_files_path(config), target.copy_resources_script_output_files_relative_path)
419
+ output_paths_by_config[output_paths_key] = TargetIntegrator.resource_output_paths(resource_paths)
420
+ end
362
421
  end
363
- TargetIntegrator.validate_input_output_path_limit(input_paths, output_paths)
422
+
364
423
  native_targets.each do |native_target|
365
424
  # Static library targets cannot include resources. Skip this phase from being added instead.
366
425
  next if native_target.symbol_type == :static_library
367
- TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths, output_paths)
426
+ TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths_by_config, output_paths_by_config)
368
427
  end
369
428
  end
370
429
 
@@ -394,19 +453,25 @@ module Pod
394
453
  end
395
454
  return
396
455
  end
456
+
397
457
  script_path = target.embed_frameworks_script_relative_path
398
- input_paths = []
399
- output_paths = []
400
- unless installation_options.disable_input_output_paths?
401
- framework_paths = target.framework_paths_by_config.values.flatten.uniq
402
- framework_input_paths = framework_paths.flat_map { |path| [path.source_path, path.dsym_path] }.compact
403
- input_paths = [target.embed_frameworks_script_relative_path, *framework_input_paths]
404
- output_paths = TargetIntegrator.framework_output_paths(framework_paths)
405
- TargetIntegrator.validate_input_output_path_limit(input_paths, output_paths)
458
+ input_paths_by_config = {}
459
+ output_paths_by_config = {}
460
+ if use_input_output_paths?
461
+ target.framework_paths_by_config.each do |config, framework_paths|
462
+ input_paths_key = XCFileListConfigKey.new(target.embed_frameworks_script_input_files_path(config), target.embed_frameworks_script_input_files_relative_path)
463
+ input_paths = input_paths_by_config[input_paths_key] = [script_path]
464
+ framework_paths.each do |path|
465
+ input_paths.concat(path.all_paths)
466
+ end
467
+
468
+ output_paths_key = XCFileListConfigKey.new(target.embed_frameworks_script_output_files_path(config), target.embed_frameworks_script_output_files_relative_path)
469
+ output_paths_by_config[output_paths_key] = TargetIntegrator.framework_output_paths(framework_paths)
470
+ end
406
471
  end
407
472
 
408
473
  native_targets_to_embed_in.each do |native_target|
409
- TargetIntegrator.create_or_update_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths, output_paths)
474
+ TargetIntegrator.create_or_update_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths_by_config, output_paths_by_config)
410
475
  end
411
476
  end
412
477
 
@@ -433,7 +498,7 @@ module Pod
433
498
  def add_check_manifest_lock_script_phase
434
499
  phase_name = CHECK_MANIFEST_PHASE_NAME
435
500
  native_targets.each do |native_target|
436
- phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
501
+ phase = TargetIntegrator.create_or_update_shell_script_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
437
502
  native_target.build_phases.unshift(phase).uniq! unless native_target.build_phases.first == phase
438
503
  phase.shell_script = <<-SH.strip_heredoc
439
504
  diff "${PODS_PODFILE_DIR_PATH}/Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null