cocoapods 0.16.4 → 0.17.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +108 -0
  3. data/README.md +3 -3
  4. data/bin/pod +1 -1
  5. data/lib/cocoapods.rb +31 -31
  6. data/lib/cocoapods/command.rb +62 -107
  7. data/lib/cocoapods/command/inter_process_communication.rb +103 -0
  8. data/lib/cocoapods/command/list.rb +45 -44
  9. data/lib/cocoapods/command/outdated.rb +28 -25
  10. data/lib/cocoapods/command/project.rb +90 -0
  11. data/lib/cocoapods/command/push.rb +50 -32
  12. data/lib/cocoapods/command/repo.rb +125 -155
  13. data/lib/cocoapods/command/search.rb +23 -12
  14. data/lib/cocoapods/command/setup.rb +103 -64
  15. data/lib/cocoapods/command/spec.rb +329 -90
  16. data/lib/cocoapods/config.rb +197 -44
  17. data/lib/cocoapods/downloader.rb +47 -34
  18. data/lib/cocoapods/executable.rb +98 -41
  19. data/lib/cocoapods/external_sources.rb +325 -0
  20. data/lib/cocoapods/file_list.rb +8 -1
  21. data/lib/cocoapods/gem_version.rb +7 -0
  22. data/lib/cocoapods/generator/acknowledgements.rb +71 -7
  23. data/lib/cocoapods/generator/acknowledgements/markdown.rb +10 -9
  24. data/lib/cocoapods/generator/acknowledgements/plist.rb +9 -8
  25. data/lib/cocoapods/generator/copy_resources_script.rb +2 -2
  26. data/lib/cocoapods/generator/documentation.rb +153 -37
  27. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  28. data/lib/cocoapods/generator/target_header.rb +58 -0
  29. data/lib/cocoapods/generator/xcconfig.rb +130 -0
  30. data/lib/cocoapods/hooks/installer_representation.rb +123 -0
  31. data/lib/cocoapods/hooks/library_representation.rb +79 -0
  32. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  33. data/lib/cocoapods/installer.rb +398 -147
  34. data/lib/cocoapods/installer/analyzer.rb +556 -0
  35. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  36. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  37. data/lib/cocoapods/installer/pod_source_installer.rb +289 -0
  38. data/lib/cocoapods/installer/target_installer.rb +307 -112
  39. data/lib/cocoapods/installer/user_project_integrator.rb +140 -176
  40. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +193 -0
  41. data/lib/cocoapods/library.rb +195 -0
  42. data/lib/cocoapods/open_uri.rb +16 -14
  43. data/lib/cocoapods/project.rb +175 -52
  44. data/lib/cocoapods/resolver.rb +151 -164
  45. data/lib/cocoapods/sandbox.rb +276 -54
  46. data/lib/cocoapods/sandbox/file_accessor.rb +210 -0
  47. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  48. data/lib/cocoapods/sandbox/path_list.rb +178 -0
  49. data/lib/cocoapods/sources_manager.rb +218 -0
  50. data/lib/cocoapods/user_interface.rb +82 -18
  51. data/lib/cocoapods/{command → user_interface}/error_report.rb +5 -5
  52. data/lib/cocoapods/validator.rb +379 -0
  53. metadata +74 -55
  54. data/lib/cocoapods/command/install.rb +0 -55
  55. data/lib/cocoapods/command/linter.rb +0 -317
  56. data/lib/cocoapods/command/update.rb +0 -25
  57. data/lib/cocoapods/dependency.rb +0 -285
  58. data/lib/cocoapods/downloader/git.rb +0 -276
  59. data/lib/cocoapods/downloader/http.rb +0 -99
  60. data/lib/cocoapods/downloader/mercurial.rb +0 -26
  61. data/lib/cocoapods/downloader/subversion.rb +0 -42
  62. data/lib/cocoapods/local_pod.rb +0 -620
  63. data/lib/cocoapods/lockfile.rb +0 -274
  64. data/lib/cocoapods/platform.rb +0 -127
  65. data/lib/cocoapods/podfile.rb +0 -551
  66. data/lib/cocoapods/source.rb +0 -223
  67. data/lib/cocoapods/specification.rb +0 -579
  68. data/lib/cocoapods/specification/set.rb +0 -175
  69. data/lib/cocoapods/specification/statistics.rb +0 -112
  70. data/lib/cocoapods/user_interface/ui_pod.rb +0 -130
  71. data/lib/cocoapods/version.rb +0 -26
@@ -6,208 +6,172 @@ require 'active_support/core_ext/array/conversions'
6
6
 
7
7
  module Pod
8
8
  class Installer
9
+
10
+ # The {UserProjectIntegrator} integrates the libraries generated by
11
+ # TargetDefinitions of the {Podfile} with their correspondent user
12
+ # projects.
13
+ #
9
14
  class UserProjectIntegrator
10
- include Pod::Config::Mixin
11
15
 
12
- def initialize(podfile)
16
+ autoload :TargetIntegrator, 'cocoapods/installer/user_project_integrator/target_integrator'
17
+
18
+ # @return [Podfile] the podfile that should be integrated with the user
19
+ # projects.
20
+ #
21
+ attr_reader :podfile
22
+
23
+ # @return [Project] the pods project which contains the libraries to
24
+ # integrate.
25
+ #
26
+ # attr_reader :pods_project
27
+
28
+ attr_reader :sandbox
29
+
30
+ # @return [Pathname] the path of the installation.
31
+ #
32
+ # @todo This is only used to compute the workspace path in case that it
33
+ # should be inferred by the project. If the workspace should be in
34
+ # the same dir of the project, this could be removed.
35
+ #
36
+ attr_reader :installation_root
37
+
38
+ # @return [Library] the libraries generated by the installer.
39
+ #
40
+ attr_reader :libraries
41
+
42
+ # @param [Podfile] podfile @see #podfile
43
+ # @param [Sandbox] sandbox @see #sandbox
44
+ # @param [Pathname] installation_root @see #installation_root
45
+ # @param [Library] libraries @see #libraries
46
+ #
47
+ # @todo Too many initialization arguments
48
+ #
49
+ def initialize(podfile, sandbox, installation_root, libraries)
13
50
  @podfile = podfile
51
+ @sandbox = sandbox
52
+ @installation_root = installation_root
53
+ @libraries = libraries
14
54
  end
15
55
 
56
+ # Integrates the user projects associated with the {TargetDefinitions}
57
+ # with the Pods project and its products.
58
+ #
59
+ # @return [void]
60
+ #
16
61
  def integrate!
17
- create_workspace!
18
-
19
- # Only need to write out the user's project if any of the target
20
- # integrators actually did some work.
21
- target_integrators.map(&:integrate!)
22
- end
23
-
24
- def workspace_path
25
- @podfile.workspace || raise(Informative, "Could not automatically select an Xcode workspace. " \
26
- "Specify one in your Podfile.")
62
+ create_workspace
63
+ integrate_user_targets
64
+ warn_about_empty_podfile
27
65
  end
28
66
 
29
- def pods_project_path
30
- config.project_root + "Pods/Pods.xcodeproj"
31
- end
67
+ #-----------------------------------------------------------------------#
68
+
69
+ private
70
+
71
+ # @!group Integration steps
72
+
73
+ # Creates and saved the workspace containing the Pods project and the
74
+ # user projects, if needed.
75
+ #
76
+ # @note If the workspace already contains the projects it is not saved
77
+ # to avoid Xcode from displaying the revert dialog: `Do you want to
78
+ # keep the Xcode version or revert to the version on disk?`
79
+ #
80
+ # @return [void]
81
+ #
82
+ def create_workspace
83
+ all_projects = user_project_paths.sort.push(sandbox.project_path).uniq
84
+ projpaths = all_projects.map do |path|
85
+ path.relative_path_from(workspace_path.dirname).to_s
86
+ end
32
87
 
33
- def target_integrators
34
- @target_integrators ||= @podfile.target_definitions.values.map do |definition|
35
- TargetIntegrator.new(definition) unless definition.empty?
36
- end.compact
37
- end
88
+ if workspace_path.exist?
89
+ workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
90
+ new_projpaths = projpaths - workspace.projpaths
91
+ unless new_projpaths.empty?
92
+ workspace.projpaths.concat(new_projpaths)
93
+ workspace.save_as(workspace_path)
94
+ end
38
95
 
39
- def user_project_paths
40
- @podfile.target_definitions.values.map do |td|
41
- next if td.empty?
42
- td.user_project.path #|| raise(Informative, "Could not resolve the Xcode project in which the " \
43
- # "`#{td.name}' target should be integrated.")
44
- end.compact
96
+ else
97
+ UI.notice "From now on use `#{workspace_path.basename}`."
98
+ workspace = Xcodeproj::Workspace.new(*projpaths)
99
+ workspace.save_as(workspace_path)
100
+ end
45
101
  end
46
102
 
47
- def create_workspace!
48
- workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
49
- [pods_project_path, *user_project_paths].each do |project_path|
50
- project_path = project_path.relative_path_from(config.project_root).to_s
51
- workspace << project_path unless workspace.include?(project_path)
52
- end
53
- unless workspace_path.exist? || config.silent?
54
- UI.notice "From now on use `#{workspace_path.basename}'."
103
+ # Integrates the targets of the user projects with the libraries
104
+ # generated from the {Podfile}.
105
+ #
106
+ # @note {TargetDefinition} without dependencies are skipped prevent
107
+ # creating empty libraries for targets definitions which are only
108
+ # wrappers for others.
109
+ #
110
+ # @return [void]
111
+ #
112
+ def integrate_user_targets
113
+ libraries_to_integrate.sort_by(&:name).each do |lib|
114
+ TargetIntegrator.new(lib).integrate!
55
115
  end
56
- workspace.save_as(workspace_path)
57
116
  end
58
117
 
59
- class TargetIntegrator
60
- include Pod::Config::Mixin
61
-
62
- attr_reader :target_definition
63
-
64
- def initialize(target_definition)
65
- @target_definition = target_definition
118
+ # Warns the user if the podfile is empty.
119
+ #
120
+ # @note The workspace is created in any case and all the user projects
121
+ # are added to it, however the projects are not integrated as
122
+ # there is no way to discern between target definitions which are
123
+ # empty and target definitions which just serve the purpose to
124
+ # wrap other ones. This is not an issue because empty target
125
+ # definitions generate empty libraries.
126
+ #
127
+ # @return [void]
128
+ #
129
+ def warn_about_empty_podfile
130
+ if podfile.target_definitions.values.all?{ |td| td.empty? }
131
+ UI.warn "[!] The Podfile does not contain any dependency."
66
132
  end
133
+ end
67
134
 
68
- def inspect
69
- "#<#{self.class} for target `#{@target_definition.label}'>"
70
- end
135
+ #-----------------------------------------------------------------------#
71
136
 
72
- # Integrates the user project targets. Only the targets that do **not**
73
- # already have the Pods library in their frameworks build phase are
74
- # processed.
75
- #
76
- # @return [void]
77
- #
78
- def integrate!
79
- return if targets.empty?
80
-
81
- UI.section("Integrating `#{@target_definition.lib_name}' into #{'target'.pluralize(targets.size)} " \
82
- "`#{targets.map(&:name).to_sentence}' of Xcode project #{UI.path user_project_path}.") do
83
- add_xcconfig_base_configuration
84
- add_pods_library
85
- add_copy_resources_script_phase
86
- user_project.save_as(@target_definition.user_project.path)
87
- end
88
- end
137
+ private
89
138
 
90
- # @return [Pathname] the path of the user project.
91
- #
92
- # @raises If the path doesn't exits.
93
- #
94
- # @raises If the project is implicit and there are multiple projects.
95
- #
96
- def user_project_path
97
- if path = @target_definition.user_project.path
98
- unless path.exist?
99
- raise Informative, "The Xcode project `#{path}' does not exist."
100
- end
101
- path
102
- else
103
- raise Informative, "Could not automatically select an Xcode project.\n" \
104
- "Specify one in your Podfile like so:\n\n" \
105
- " xcodeproj 'path/to/XcodeProject'"
106
- end
107
- end
139
+ # @!group Helpers.
108
140
 
109
- # @return [Xcodeproj::Project] Returns the project of the user.
110
- #
111
- def user_project
112
- @user_project ||= Xcodeproj::Project.new(user_project_path)
141
+ # @return [Pathname] the path where the workspace containing the Pods
142
+ # project and the user projects should be saved.
143
+ #
144
+ def workspace_path
145
+ if podfile.workspace_path
146
+ podfile.workspace_path
147
+ elsif user_project_paths.count == 1
148
+ project = user_project_paths.first.basename('.xcodeproj')
149
+ installation_root + "#{project}.xcworkspace"
150
+ else
151
+ raise Informative, "Could not automatically select an Xcode " \
152
+ "workspace. Specify one in your Podfile like so:\n\n" \
153
+ " workspace 'path/to/Workspace.xcworkspace'\n"
113
154
  end
155
+ end
114
156
 
115
- # @return [Array<PBXNativeTarget>] Returns the user’s targets,
116
- # excluding aggregate targets.
117
- def native_targets
118
- user_project.targets.reject do |target|
119
- target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget
120
- end
121
- end
157
+ # @return [Array<Pathname>] the paths of all the user projects referenced
158
+ # by the target definitions.
159
+ #
160
+ # @note Empty target definitions are ignored.
161
+ #
162
+ def user_project_paths
163
+ libraries.map do |lib|
164
+ lib.user_project_path
165
+ end.compact.uniq
166
+ end
122
167
 
123
- # This returns a list of the targets from the user’s project to which
124
- # this Pods static library should be linked. If no explicit target was
125
- # specified, then the first encountered target is assumed.
126
- #
127
- # In addition this will only return targets that do **not** already
128
- # have the Pods library in their frameworks build phase.
129
- #
130
- # @return [Array<PBXNativeTarget>] Returns the list of targets that
131
- # the Pods lib should be linked with.
132
- def targets
133
- if @targets.nil?
134
- targets = nil
135
- # Find explicitly linked targets.
136
- if link_with = @target_definition.link_with
137
- targets = native_targets.select do |target|
138
- link_with.include? target.name
139
- end
140
-
141
- # Otherwise try to find a target matching the name.
142
- elsif @target_definition.name != :default
143
- target = native_targets.find do |target|
144
- target.name == @target_definition.name.to_s
145
- end
146
- unless target
147
- raise Informative, "Unable to find a target named `#{@target_definition.name.to_s}'"
148
- end
149
- targets = [target]
150
-
151
- # Default to the first target, which in a simple project is
152
- # probably an app target.
153
- else
154
- targets = [native_targets.first]
155
- end
156
-
157
- # Reject any target that already has this Pods library in one of
158
- # its frameworks build phases
159
- @targets = targets.reject do |target|
160
- target.frameworks_build_phase.files.any? do |build_file|
161
- file_ref = build_file.file_ref
162
- !file_ref.proxy? && file_ref.display_name == @target_definition.lib_name
163
- end
164
- end
165
- end
166
- @targets
167
- end
168
168
 
169
- def add_xcconfig_base_configuration
170
- xcconfig = user_project.new_file(@target_definition.xcconfig_relative_path)
171
- targets.each do |target|
172
- config_build_names_by_overriden_key = {}
173
- target.build_configurations.each do |config|
174
- config_name = config.name
175
- if @target_definition.xcconfig
176
- @target_definition.xcconfig.attributes.each do |key, value|
177
- target_value = config.build_settings[key]
178
- if target_value && !target_value.include?('$(inherited)')
179
- config_build_names_by_overriden_key[key] ||= []
180
- config_build_names_by_overriden_key[key] << config_name
181
- end
182
- end
183
- end
184
-
185
- config.base_configuration_reference = xcconfig
186
- end
187
-
188
- config_build_names_by_overriden_key.each do |key, config_build_names|
189
- name = "#{target.name} [#{config_build_names.join(' - ')}]"
190
- actions = [ "Use the `$(inherited)' flag, or", "Remove the build settings from the target." ]
191
- UI.warn("The target `#{name}' overrides the `#{key}' build setting defined in `#{@target_definition.xcconfig_relative_path}'.", actions)
192
- end
193
- end
194
- end
169
+ def libraries_to_integrate
170
+ libraries.reject { |lib| lib.target_definition.empty? }
171
+ end
195
172
 
196
- def add_pods_library
197
- frameworks = user_project.frameworks_group
198
- pods_library = frameworks.new_static_library(@target_definition.label)
199
- targets.each do |target|
200
- target.frameworks_build_phase.add_file_reference(pods_library)
201
- end
202
- end
173
+ #-----------------------------------------------------------------------#
203
174
 
204
- def add_copy_resources_script_phase
205
- targets.each do |target|
206
- phase = target.new_shell_script_build_phase('Copy Pods Resources')
207
- phase.shell_script = %{"#{@target_definition.copy_resources_script_relative_path}"\n}
208
- end
209
- end
210
- end
211
175
  end
212
176
  end
213
177
  end
@@ -0,0 +1,193 @@
1
+ module Pod
2
+ class Installer
3
+ class UserProjectIntegrator
4
+
5
+ # This class is responsible for integrating the library generated by a
6
+ # {TargetDefinition} with its destination project.
7
+ #
8
+ class TargetIntegrator
9
+
10
+ # @return [Library] the library that should be integrated.
11
+ #
12
+ attr_reader :library
13
+
14
+ # @param [Library] library @see #target_definition
15
+ #
16
+ def initialize(library)
17
+ @library = library
18
+ end
19
+
20
+ # Integrates the user project targets. Only the targets that do **not**
21
+ # already have the Pods library in their frameworks build phase are
22
+ # processed.
23
+ #
24
+ # @return [void]
25
+ #
26
+ def integrate!
27
+ return if targets.empty?
28
+ UI.section(integration_message) do
29
+ add_xcconfig_base_configuration
30
+ add_pods_library
31
+ add_copy_resources_script_phase
32
+ save_user_project
33
+ end
34
+ end
35
+
36
+ # @return [Array<PBXNativeTarget>] the list of targets that the Pods
37
+ # lib that need to be integrated.
38
+ #
39
+ # @note A target is considered integrated if it already references
40
+ #
41
+ def targets
42
+ unless @targets
43
+ target_uuids = library.user_target_uuids
44
+ targets = target_uuids.map do |uuid|
45
+ target = user_project.objects_by_uuid[uuid]
46
+ unless target
47
+ raise Informative, "[Bug] Unable to find the target with " \
48
+ "the `#{uuid}` UUID for the `#{library}` library"
49
+ end
50
+ target
51
+ end
52
+ non_integrated = targets.reject do |target|
53
+ target.frameworks_build_phase.files.any? do |build_file|
54
+ file_ref = build_file.file_ref
55
+ !file_ref.proxy? && file_ref.display_name == library.product_name
56
+ end
57
+ end
58
+ @targets = non_integrated
59
+ end
60
+ @targets
61
+ end
62
+
63
+ # Read the project from the disk to ensure that it is up to date as
64
+ # other TargetIntegrators might have modified it.
65
+ #
66
+ def user_project
67
+ @user_project ||= Xcodeproj::Project.new(library.user_project_path)
68
+ end
69
+
70
+ # @return [String] a string representation suitable for debugging.
71
+ #
72
+ def inspect
73
+ "#<#{self.class} for target `#{target_definition.label}'>"
74
+ end
75
+
76
+ #---------------------------------------------------------------------#
77
+
78
+ # @!group Integration steps
79
+
80
+ private
81
+
82
+ # Adds the `xcconfig` configurations files generated for the current
83
+ # {TargetDefinition} to the build configurations of the targets that
84
+ # should be integrated.
85
+ #
86
+ # @note It also checks if any build setting of the build
87
+ # configurations overrides the `xcconfig` file and warns the
88
+ # user.
89
+ #
90
+ # @todo If the xcconfig is already set don't override it and inform
91
+ # the user.
92
+ #
93
+ # @return [void]
94
+ #
95
+ def add_xcconfig_base_configuration
96
+ xcconfig = user_project.new_file(library.xcconfig_relative_path)
97
+ targets.each do |target|
98
+ check_overridden_build_settings(library.xcconfig, target)
99
+ target.build_configurations.each do |config|
100
+ config.base_configuration_reference = xcconfig
101
+ end
102
+ end
103
+ end
104
+
105
+ # Adds a file reference to the library of the {TargetDefinition} and
106
+ # adds it to the frameworks build phase of the targets.
107
+ #
108
+ # @return [void]
109
+ #
110
+ def add_pods_library
111
+ frameworks = user_project.frameworks_group
112
+ pods_library = frameworks.new_static_library(library.label)
113
+ targets.each do |target|
114
+ target.frameworks_build_phase.add_file_reference(pods_library)
115
+ end
116
+ end
117
+
118
+ # Adds a shell script build phase responsible to copy the resources
119
+ # generated by the TargetDefinition to the bundle of the product of the
120
+ # targets.
121
+ #
122
+ # @return [void]
123
+ #
124
+ def add_copy_resources_script_phase
125
+ targets.each do |target|
126
+ phase = target.new_shell_script_build_phase('Copy Pods Resources')
127
+ path = library.copy_resources_script_relative_path
128
+ phase.shell_script = %{"#{path}"\n}
129
+ end
130
+ end
131
+
132
+ # Saves the changes to the user project to the disk.
133
+ #
134
+ # @return [void]
135
+ #
136
+ def save_user_project
137
+ user_project.save_as(library.user_project_path)
138
+ end
139
+
140
+ #---------------------------------------------------------------------#
141
+
142
+ # @!group Private helpers.
143
+
144
+ private
145
+
146
+ # Informs the user about any build setting of the target which might
147
+ # override the given xcconfig file.
148
+ #
149
+ # @return [void]
150
+ #
151
+ def check_overridden_build_settings(xcconfig, target)
152
+ return unless xcconfig
153
+
154
+ configs_by_overridden_key = {}
155
+ target.build_configurations.each do |config|
156
+ xcconfig.attributes.keys.each do |key|
157
+ target_value = config.build_settings[key]
158
+
159
+ if target_value && !target_value.include?('$(inherited)')
160
+ configs_by_overridden_key[key] ||= []
161
+ configs_by_overridden_key[key] << config.name
162
+ end
163
+ end
164
+
165
+ configs_by_overridden_key.each do |key, config_names|
166
+ name = "#{target.name} [#{config_names.join(' - ')}]"
167
+ actions = [
168
+ "Use the `$(inherited)` flag, or",
169
+ "Remove the build settings from the target."
170
+ ]
171
+ UI.warn("The target `#{name}` overrides the `#{key}` build " \
172
+ "setting defined in `#{library.xcconfig_relative_path}'.",
173
+ actions)
174
+ end
175
+ end
176
+ end
177
+
178
+ # @return [String] the message that should be displayed for the target
179
+ # integration.
180
+ #
181
+ def integration_message
182
+ "Integrating `#{library.product_name}` into " \
183
+ "#{'target'.pluralize(targets.size)} " \
184
+ "`#{targets.map(&:name).to_sentence}` " \
185
+ "of project #{UI.path library.user_project_path}."
186
+ end
187
+
188
+ #---------------------------------------------------------------------#
189
+
190
+ end
191
+ end
192
+ end
193
+ end