cocoapods 0.16.4 → 0.17.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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