cocoapods-square-stable 0.19.3

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1296 -0
  3. data/LICENSE +20 -0
  4. data/README.md +94 -0
  5. data/bin/pod +16 -0
  6. data/bin/sandbox-pod +120 -0
  7. data/lib/cocoapods.rb +77 -0
  8. data/lib/cocoapods/command.rb +116 -0
  9. data/lib/cocoapods/command/help.rb +23 -0
  10. data/lib/cocoapods/command/inter_process_communication.rb +178 -0
  11. data/lib/cocoapods/command/list.rb +77 -0
  12. data/lib/cocoapods/command/outdated.rb +56 -0
  13. data/lib/cocoapods/command/podfile_info.rb +91 -0
  14. data/lib/cocoapods/command/project.rb +88 -0
  15. data/lib/cocoapods/command/push.rb +172 -0
  16. data/lib/cocoapods/command/repo.rb +145 -0
  17. data/lib/cocoapods/command/search.rb +61 -0
  18. data/lib/cocoapods/command/setup.rb +134 -0
  19. data/lib/cocoapods/command/spec.rb +590 -0
  20. data/lib/cocoapods/config.rb +231 -0
  21. data/lib/cocoapods/downloader.rb +59 -0
  22. data/lib/cocoapods/executable.rb +118 -0
  23. data/lib/cocoapods/external_sources.rb +363 -0
  24. data/lib/cocoapods/file_list.rb +36 -0
  25. data/lib/cocoapods/gem_version.rb +7 -0
  26. data/lib/cocoapods/generator/acknowledgements.rb +107 -0
  27. data/lib/cocoapods/generator/acknowledgements/markdown.rb +40 -0
  28. data/lib/cocoapods/generator/acknowledgements/plist.rb +64 -0
  29. data/lib/cocoapods/generator/bridge_support.rb +22 -0
  30. data/lib/cocoapods/generator/copy_resources_script.rb +54 -0
  31. data/lib/cocoapods/generator/dummy_source.rb +22 -0
  32. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  33. data/lib/cocoapods/generator/target_environment_header.rb +86 -0
  34. data/lib/cocoapods/generator/xcconfig.rb +185 -0
  35. data/lib/cocoapods/hooks/installer_representation.rb +134 -0
  36. data/lib/cocoapods/hooks/library_representation.rb +94 -0
  37. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  38. data/lib/cocoapods/installer.rb +571 -0
  39. data/lib/cocoapods/installer/analyzer.rb +559 -0
  40. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  41. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  42. data/lib/cocoapods/installer/pod_source_installer.rb +248 -0
  43. data/lib/cocoapods/installer/target_installer.rb +379 -0
  44. data/lib/cocoapods/installer/user_project_integrator.rb +180 -0
  45. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +224 -0
  46. data/lib/cocoapods/library.rb +202 -0
  47. data/lib/cocoapods/open_uri.rb +24 -0
  48. data/lib/cocoapods/project.rb +209 -0
  49. data/lib/cocoapods/resolver.rb +212 -0
  50. data/lib/cocoapods/sandbox.rb +343 -0
  51. data/lib/cocoapods/sandbox/file_accessor.rb +217 -0
  52. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  53. data/lib/cocoapods/sandbox/path_list.rb +208 -0
  54. data/lib/cocoapods/sources_manager.rb +276 -0
  55. data/lib/cocoapods/user_interface.rb +304 -0
  56. data/lib/cocoapods/user_interface/error_report.rb +101 -0
  57. data/lib/cocoapods/validator.rb +350 -0
  58. metadata +238 -0
@@ -0,0 +1,209 @@
1
+ require 'xcodeproj'
2
+
3
+ module Pod
4
+
5
+ # The Pods project.
6
+ #
7
+ # Model class which provides helpers for working with the Pods project
8
+ # through the installation process.
9
+ #
10
+ class Project < Xcodeproj::Project
11
+
12
+ # @return [Pathname] the path of the xcodeproj file which stores the
13
+ # project.
14
+ #
15
+ attr_reader :path
16
+
17
+ # @param [Sandbox] sandbox @see #sandbox
18
+ #
19
+ def initialize(path = nil)
20
+ super(nil) # Recreate the project from scratch for now.
21
+ @path = path
22
+ @support_files_group = new_group('Targets Support Files')
23
+
24
+ @refs_by_absolute_path = {}
25
+ end
26
+
27
+ # @return [Pathname] the path of the xcodeproj file which stores the
28
+ # project.
29
+ #
30
+ attr_reader :path
31
+
32
+ # @return [Pathname] the directory where the project is stored.
33
+ #
34
+ def root
35
+ @root ||= path.dirname
36
+ end
37
+
38
+ # @return [Pathname] Returns the relative path from the project root.
39
+ #
40
+ # @param [Pathname] path
41
+ # The path that needs to be converted to the relative format.
42
+ #
43
+ # @note If the two absolute paths don't share the same root directory an
44
+ # extra `../` is added to the result of
45
+ # {Pathname#relative_path_from}.
46
+ #
47
+ # @example
48
+ #
49
+ # path = Pathname.new('/Users/dir')
50
+ # @sandbox.root #=> Pathname('/tmp/CocoaPods/Lint/Pods')
51
+ #
52
+ # @sandbox.relativize(path) #=> '../../../../Users/dir'
53
+ # @sandbox.relativize(path) #=> '../../../../../Users/dir'
54
+ #
55
+ def relativize(path)
56
+ unless path.absolute?
57
+ raise StandardError, "[Bug] Attempt to add relative path `#{path}` to the Pods project"
58
+ end
59
+
60
+ result = path.relative_path_from(root)
61
+ unless root.to_s.split('/')[1] == path.to_s.split('/')[1]
62
+ result = Pathname.new('../') + result
63
+ end
64
+ result
65
+ end
66
+
67
+ # @return [String] a string representation suited for debugging.
68
+ #
69
+ def inspect
70
+ "#<#{self.class}> path:#{path}"
71
+ end
72
+
73
+ #-------------------------------------------------------------------------#
74
+
75
+ public
76
+
77
+ # @!group Groups
78
+
79
+ # @return [PBXGroup] the group where the support files for the Pod
80
+ # libraries should be added.
81
+ #
82
+ attr_reader :support_files_group
83
+
84
+ # Returns the `Pods` group, creating it if needed.
85
+ #
86
+ # @return [PBXGroup] the group.
87
+ #
88
+ def pods
89
+ @pods ||= new_group('Pods')
90
+ end
91
+
92
+ # Returns the `Local Pods` group, creating it if needed. This group is used
93
+ # to contain locally sourced pods.
94
+ #
95
+ # @return [PBXGroup] the group.
96
+ #
97
+ def local_pods
98
+ @local_pods ||= new_group('Local Pods')
99
+ end
100
+
101
+ # Returns the `Local Pods` group, creating it if needed. This group is used
102
+ # to contain locally sourced pods.
103
+ #
104
+ # @return [PBXGroup] the group.
105
+ #
106
+ def resources
107
+ @resources ||= new_group('Resources')
108
+ end
109
+
110
+ # Adds a group as child to the `Pods` group namespacing subspecs.
111
+ #
112
+ # @param [String] spec_name
113
+ # The full name of the specification.
114
+ #
115
+ # @param [PBXGroup] root_group
116
+ # The group where to add the specification. Either `Pods` or `Local
117
+ # Pods`.
118
+ #
119
+ # @return [PBXGroup] the group for the spec with the given name.
120
+ #
121
+ def add_spec_group(spec_name, root_group)
122
+ current_group = root_group
123
+ group = nil
124
+ spec_name.split('/').each do |name|
125
+ group = current_group[name] || current_group.new_group(name)
126
+ current_group = group
127
+ end
128
+ group
129
+ end
130
+
131
+ #-------------------------------------------------------------------------#
132
+
133
+ public
134
+
135
+ # @!group File references
136
+
137
+ # Adds a file reference for each one of the given files in the specified
138
+ # group, namespaced by specification unless a file reference for the given
139
+ # path already exits.
140
+ #
141
+ # @note With this set-up different subspecs might not reference the same
142
+ # file (i.e. the first will win). Not sure thought if this is a
143
+ # limitation or a feature.
144
+ #
145
+ # @param [Array<Pathname,String>] paths
146
+ # The files for which the file reference is needed.
147
+ #
148
+ # @param [String] spec_name
149
+ # The full name of the specification.
150
+ #
151
+ # @param [PBXGroup] parent_group
152
+ # The group where the file references should be added.
153
+ #
154
+ # @return [void]
155
+ #
156
+ def add_file_references(absolute_path, spec_name, parent_group)
157
+ group = add_spec_group(spec_name, parent_group)
158
+ absolute_path.each do |file|
159
+ existing = file_reference(file)
160
+ unless existing
161
+ file = Pathname.new(file)
162
+ ref = group.new_file(relativize(file))
163
+ @refs_by_absolute_path[file] = ref
164
+ end
165
+ end
166
+ end
167
+
168
+ # Returns the file reference for the given absolute file path.
169
+ #
170
+ # @param [Pathname,String] absolute_path
171
+ # The absolute path of the file whose reference is needed.
172
+ #
173
+ # @return [PBXFileReference] The file reference.
174
+ # @return [Nil] If no file reference could be found.
175
+ #
176
+ def file_reference(absolute_path)
177
+ absolute_path = Pathname.new(absolute_path)
178
+ refs_by_absolute_path[absolute_path]
179
+ end
180
+
181
+ # Adds a file reference to the podfile.
182
+ #
183
+ # @param [Pathname,String] podfile_path
184
+ # the path of the podfile
185
+ #
186
+ # @return [PBXFileReference] the file reference.
187
+ #
188
+ def add_podfile(podfile_path)
189
+ podfile_path = Pathname.new(podfile_path)
190
+ podfile_ref = new_file(relativize(podfile_path))
191
+ podfile_ref.xc_language_specification_identifier = 'xcode.lang.ruby'
192
+ podfile_ref
193
+ end
194
+
195
+ #-------------------------------------------------------------------------#
196
+
197
+ private
198
+
199
+ # @!group Private helpers
200
+
201
+ # @return [Hash{Pathname => PBXFileReference}] The file references grouped
202
+ # by absolute path.
203
+ #
204
+ attr_reader :refs_by_absolute_path
205
+
206
+ #-------------------------------------------------------------------------#
207
+
208
+ end
209
+ end
@@ -0,0 +1,212 @@
1
+ module Pod
2
+
3
+ # The resolver is responsible of generating a list of specifications grouped
4
+ # by target for a given Podfile.
5
+ #
6
+ # @todo Its current implementation is naive, in the sense that it can't do full
7
+ # automatic resolves like Bundler:
8
+ # [how-does-bundler-bundle](http://patshaughnessy.net/2011/9/24/how-does-bundler-bundle)
9
+ #
10
+ # @todo Another limitation is that the order of the dependencies matter. The
11
+ # current implementation could create issues, for example, if a
12
+ # specification is loaded for a target definition and later for another
13
+ # target is set in head mode. The first specification will not be in head
14
+ # mode.
15
+ #
16
+ #
17
+ class Resolver
18
+
19
+ # @return [Sandbox] the Sandbox used by the resolver to find external
20
+ # dependencies.
21
+ #
22
+ attr_reader :sandbox
23
+
24
+ # @return [Podfile] the Podfile used by the resolver.
25
+ #
26
+ attr_reader :podfile
27
+
28
+ # @return [Array<Dependency>] the list of dependencies locked to a specific
29
+ # version.
30
+ #
31
+ attr_reader :locked_dependencies
32
+
33
+ # @param [Sandbox] sandbox @see sandbox
34
+ # @param [Podfile] podfile @see podfile
35
+ # @param [Array<Dependency>] locked_dependencies @see locked_dependencies
36
+ #
37
+ def initialize(sandbox, podfile, locked_dependencies = [])
38
+ @sandbox = sandbox
39
+ @podfile = podfile
40
+ @locked_dependencies = locked_dependencies
41
+ end
42
+
43
+ #-------------------------------------------------------------------------#
44
+
45
+ public
46
+
47
+ # @!group Resolution
48
+
49
+ # Identifies the specifications that should be installed.
50
+ #
51
+ # @return [Hash{TargetDefinition => Array<Specification>}] specs_by_target
52
+ # the specifications that need to be installed grouped by target
53
+ # definition.
54
+ #
55
+ def resolve
56
+ @cached_sources = SourcesManager.aggregate
57
+ @cached_sets = {}
58
+ @cached_specs = {}
59
+ @specs_by_target = {}
60
+
61
+ target_definitions = podfile.target_definition_list
62
+ target_definitions.each do |target|
63
+ UI.section "Resolving dependencies for target `#{target.name}' (#{target.platform})" do
64
+ @loaded_specs = []
65
+ find_dependency_specs(podfile, target.dependencies, target)
66
+ specs = cached_specs.values_at(*@loaded_specs).sort_by(&:name)
67
+ specs_by_target[target] = specs
68
+ end
69
+ end
70
+
71
+ cached_specs.values.sort_by(&:name)
72
+ specs_by_target
73
+ end
74
+
75
+ # @return [Hash{Podfile::TargetDefinition => Array<Specification>}]
76
+ # returns the resolved specifications grouped by target.
77
+ #
78
+ # @note The returned specifications can be subspecs.
79
+ #
80
+ attr_reader :specs_by_target
81
+
82
+ #-------------------------------------------------------------------------#
83
+
84
+ private
85
+
86
+ # !@ Resolution context
87
+
88
+ # @return [Source::Aggregate] A cache of the sources needed to find the
89
+ # podspecs.
90
+ #
91
+ # @note The sources are cached because frequently accessed by the
92
+ # resolver and loading them requires disk activity.
93
+ #
94
+ attr_accessor :cached_sources
95
+
96
+ # @return [Hash<String => Set>] A cache that keeps tracks of the sets
97
+ # loaded by the resolution process.
98
+ #
99
+ # @note Sets store the resolved dependencies and return the highest
100
+ # available specification found in the sources. This is done
101
+ # globally and not per target definition because there can be just
102
+ # one Pod installation, so different version of the same Pods for
103
+ # target definitions are not allowed.
104
+ #
105
+ attr_accessor :cached_sets
106
+
107
+ # @return [Hash<String => Specification>] The loaded specifications grouped
108
+ # by name.
109
+ #
110
+ attr_accessor :cached_specs
111
+
112
+ #-------------------------------------------------------------------------#
113
+
114
+ private
115
+
116
+ # @!group Private helpers
117
+
118
+ # Resolves recursively the dependencies of a specification and stores them
119
+ # in the @cached_specs ivar.
120
+ #
121
+ # @param [Podfile, Specification, #to_s] dependent_spec
122
+ # the specification whose dependencies are being resolved. Used
123
+ # only for UI purposes.
124
+ #
125
+ # @param [Array<Dependency>] dependencies
126
+ # the dependencies of the specification.
127
+ #
128
+ # @param [TargetDefinition] target_definition
129
+ # the target definition that owns the specification.
130
+ #
131
+ # @note If there is a locked dependency with the same name of a
132
+ # given dependency the locked one is used in place of the
133
+ # dependency of the specification. In this way it is possible to
134
+ # prevent the update of the version of installed pods not changed
135
+ # in the Podfile.
136
+ #
137
+ # @note The recursive process checks if a dependency has already been
138
+ # loaded to prevent an infinite loop.
139
+ #
140
+ # @note The set class merges all (of all the target definitions) the
141
+ # dependencies and thus it keeps track of whether it is in head
142
+ # mode or from an external source because {Dependency#merge}
143
+ # preserves this information.
144
+ #
145
+ # @return [void]
146
+ #
147
+ def find_dependency_specs(dependent_spec, dependencies, target_definition)
148
+ dependencies.each do |dependency|
149
+ locked_dep = locked_dependencies.find { |ld| ld.name == dependency.name }
150
+ dependency = locked_dep if locked_dep
151
+
152
+ UI.message("- #{dependency}", '', 2) do
153
+ set = find_cached_set(dependency)
154
+ set.required_by(dependency, dependent_spec.to_s)
155
+
156
+ unless @loaded_specs.include?(dependency.name)
157
+ spec = set.specification.subspec_by_name(dependency.name)
158
+ @loaded_specs << spec.name
159
+ cached_specs[spec.name] = spec
160
+ validate_platform(spec, target_definition)
161
+ spec.version.head = dependency.head?
162
+
163
+ spec_dependencies = spec.all_dependencies(target_definition.platform)
164
+ find_dependency_specs(spec, spec_dependencies, target_definition)
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ # Loads or returns a previously initialized for the Pod of the given
171
+ # dependency.
172
+ #
173
+ # @param [Dependency] dependency
174
+ # the dependency for which the set is needed.
175
+ #
176
+ # @return [Set] the cached set for a given dependency.
177
+ #
178
+ def find_cached_set(dependency)
179
+ name = dependency.root_name
180
+ unless cached_sets[name]
181
+ if dependency.external_source
182
+ spec = sandbox.specification(dependency.root_name)
183
+ unless spec
184
+ raise StandardError, "[Bug] Unable to find the specification for `#{dependency}`."
185
+ end
186
+ set = Specification::Set::External.new(spec)
187
+ else
188
+ set = cached_sources.search(dependency)
189
+ end
190
+ cached_sets[name] = set
191
+ unless set
192
+ raise Informative, "Unable to find a specification for `#{dependency}`."
193
+ end
194
+ end
195
+ cached_sets[name]
196
+ end
197
+
198
+ # Ensures that a specification is compatible with the platform of a target.
199
+ #
200
+ # @raise If the specification is not supported by the target.
201
+ #
202
+ # @return [void]
203
+ #
204
+ def validate_platform(spec, target)
205
+ unless spec.available_platforms.any? { |p| target.platform.supports?(p) }
206
+ raise Informative, "The platform of the target `#{target.name}` " \
207
+ "(#{target.platform}) is not compatible with `#{spec}` which has " \
208
+ "a minimum requirement of #{spec.available_platforms.join(' - ')}."
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,343 @@
1
+ require 'fileutils'
2
+
3
+ module Pod
4
+
5
+ # The sandbox provides support for the directory that CocoaPods uses for an
6
+ # installation. In this directory the Pods projects, the support files and
7
+ # the sources of the Pods are stored.
8
+ #
9
+ # CocoaPods assumes to have control of the sandbox.
10
+ #
11
+ # Once completed the sandbox will have the following file structure:
12
+ #
13
+ # Pods
14
+ # |
15
+ # +-- User
16
+ # | +-- [Target Name]-configuration.h
17
+ # | +-- Specs
18
+ # | +-- Scripts
19
+ # |
20
+ # +-- Generated
21
+ # +-- Headers
22
+ # | +-- Private
23
+ # | | +-- [Pod Name]
24
+ # | +-- Public
25
+ # | +-- [Pod Name]
26
+ # |
27
+ # +-- Sources
28
+ # | +-- [Pod Name]
29
+ # |
30
+ # +-- Specs
31
+ # | +-- External Sources
32
+ # | +-- Normal Sources
33
+ # |
34
+ # +-- Target Support Files
35
+ # | +-- [Target Name]
36
+ # | +-- Pods-acknowledgements.markdown
37
+ # | +-- Pods-acknowledgements.plist
38
+ # | +-- Pods-dummy.m
39
+ # | +-- Pods-prefix.pch
40
+ # | +-- Pods.xcconfig
41
+ # |
42
+ # +-- Manifest.lock
43
+ # |
44
+ # +-- Pods.xcodeproj
45
+ #
46
+ # See #833
47
+ #
48
+ class Sandbox
49
+
50
+ autoload :FileAccessor, 'cocoapods/sandbox/file_accessor'
51
+ autoload :HeadersStore, 'cocoapods/sandbox/headers_store'
52
+ autoload :PathList, 'cocoapods/sandbox/path_list'
53
+
54
+ # @return [Pathname] the root of the sandbox.
55
+ #
56
+ attr_reader :root
57
+
58
+ # @return [HeadersStore] the header directory for the Pods libraries.
59
+ #
60
+ attr_reader :build_headers
61
+
62
+ # @return [HeadersStore] the header directory for the user targets.
63
+ #
64
+ attr_reader :public_headers
65
+
66
+ # @param [String, Pathname] root @see root
67
+ #
68
+ def initialize(root)
69
+ @root = Pathname.new(root)
70
+ @build_headers = HeadersStore.new(self, "BuildHeaders")
71
+ @public_headers = HeadersStore.new(self, "Headers")
72
+ @predownloaded_pods = []
73
+ @checkout_sources = {}
74
+ @local_pods = {}
75
+ FileUtils.mkdir_p(@root)
76
+ end
77
+
78
+ # @return [Lockfile] the manifest which contains the information about the
79
+ # installed pods.
80
+ #
81
+ def manifest
82
+ Lockfile.from_file(manifest_path) if manifest_path.exist?
83
+ end
84
+
85
+ # @return [Project] the Pods project.
86
+ #
87
+ attr_accessor :project
88
+
89
+ # Removes the sandbox.
90
+ #
91
+ # @return [void]
92
+ #
93
+ def implode
94
+ root.rmtree
95
+ end
96
+
97
+ #
98
+ #
99
+ #
100
+ def clean_pod(name)
101
+ root_name = Specification.root_name(name)
102
+ unless local?(root_name)
103
+ path = pod_dir(name)
104
+ path.rmtree if path.exist?
105
+ end
106
+ podspe_path = specification_path(name)
107
+ podspe_path.rmtree if podspe_path
108
+ end
109
+
110
+ # @return [String] a string representation suitable for debugging.
111
+ #
112
+ def inspect
113
+ "#<#{self.class}> with root #{root}"
114
+ end
115
+
116
+ #-------------------------------------------------------------------------#
117
+
118
+ public
119
+
120
+ # @!group Paths
121
+
122
+ # @return [Pathname] the path of the manifest.
123
+ #
124
+ def manifest_path
125
+ root + "Manifest.lock"
126
+ end
127
+
128
+ # @return [Pathname] the path of the Pods project.
129
+ #
130
+ def project_path
131
+ root + "Pods.xcodeproj"
132
+ end
133
+
134
+ # Returns the path for the directory where to store the support files of
135
+ # a target.
136
+ #
137
+ # @param [String] name
138
+ # The name of the target.
139
+ #
140
+ # @return [Pathname] the path of the support files.
141
+ #
142
+ def library_support_files_dir(name)
143
+ # root + "Target Support Files/#{name}"
144
+ root
145
+ end
146
+
147
+ # Returns the path where the Pod with the given name is stored, taking into
148
+ # account whether the Pod is locally sourced.
149
+ #
150
+ # @param [String] name
151
+ # The name of the Pod.
152
+ #
153
+ # @return [Pathname] the path of the Pod.
154
+ #
155
+ def pod_dir(name)
156
+ root_name = Specification.root_name(name)
157
+ if local?(root_name)
158
+ Pathname.new(local_pods[root_name])
159
+ else
160
+ # root + "Sources/#{name}"
161
+ root + root_name
162
+ end
163
+ end
164
+
165
+ # @return [Pathname] the directory where to store the documentation.
166
+ #
167
+ def documentation_dir
168
+ root + 'Documentation'
169
+ end
170
+
171
+ #-------------------------------------------------------------------------#
172
+
173
+ public
174
+
175
+ # @!group Specification store
176
+
177
+ # Returns the specification for the Pod with the given name.
178
+ #
179
+ # @param [String] name
180
+ # the name of the Pod for which the specification is requested.
181
+ #
182
+ # @return [Specification] the specification if the file is found.
183
+ #
184
+ def specification(name)
185
+ if file = specification_path(name)
186
+ Specification.from_file(file)
187
+ end
188
+ end
189
+
190
+ # @return [Pathname] the path for the directory where to store the
191
+ # specifications.
192
+ #
193
+ # @todo Migrate old installations and store the for all the pods.
194
+ # Two folders should be created `External Sources` and `Podspecs`.
195
+ #
196
+ def specifications_dir(external_source = false)
197
+ # root + "Specifications"
198
+ root + "Local Podspecs"
199
+ end
200
+
201
+ # Returns the path of the specification for the Pod with the
202
+ # given name, if one is stored.
203
+ #
204
+ # @param [String] name
205
+ # the name of the Pod for which the podspec file is requested.
206
+ #
207
+ # @return [Pathname] the path or nil.
208
+ # @return [Nil] if the podspec is not stored.
209
+ #
210
+ def specification_path(name)
211
+ path = specifications_dir + "#{name}.podspec"
212
+ path.exist? ? path : nil
213
+ end
214
+
215
+ # Stores a specification in the `Local Podspecs` folder.
216
+ #
217
+ # @param [Sandbox] sandbox
218
+ # the sandbox where the podspec should be stored.
219
+ #
220
+ # @param [String, Pathname] podspec
221
+ # The contents of the specification (String) or the path to a
222
+ # podspec file (Pathname).
223
+ #
224
+ # @todo Store all the specifications (including those not originating
225
+ # from external sources) so users can check them.
226
+ #
227
+ def store_podspec(name, podspec, external_source = false)
228
+ output_path = specifications_dir(external_source) + "#{name}.podspec"
229
+ output_path.dirname.mkpath
230
+ if podspec.is_a?(String)
231
+ output_path.open('w') { |f| f.puts(podspec) }
232
+ else
233
+ unless podspec.exist?
234
+ raise Informative, "No podspec found for `#{name}` in #{podspec}"
235
+ end
236
+ FileUtils.copy(podspec, output_path)
237
+ end
238
+ spec = Specification.from_file(output_path)
239
+ unless spec.name == name
240
+ raise Informative, "The name of the given podspec `#{spec.name}` doesn't match the expected one `#{name}`"
241
+ end
242
+ end
243
+
244
+ #-------------------------------------------------------------------------#
245
+
246
+ public
247
+
248
+ # @!group Pods information
249
+
250
+ # Marks a Pod as pre-downloaded
251
+ #
252
+ # @param [String] name
253
+ # The name of the Pod.
254
+ #
255
+ # @return [void]
256
+ #
257
+ def store_pre_downloaded_pod(name)
258
+ root_name = Specification.root_name(name)
259
+ predownloaded_pods << root_name
260
+ end
261
+
262
+ # @return [Array<String>] The names of the pods that have been
263
+ # pre-downloaded from an external source.
264
+ #
265
+ attr_reader :predownloaded_pods
266
+
267
+ # Checks if a Pod has been pre-downloaded by the resolver in order to fetch
268
+ # the podspec.
269
+ #
270
+ # @param [String] name
271
+ # The name of the Pod.
272
+ #
273
+ # @return [Bool] Whether the Pod has been pre-downloaded.
274
+ #
275
+ def predownloaded?(name)
276
+ root_name = Specification.root_name(name)
277
+ predownloaded_pods.include?(root_name)
278
+ end
279
+
280
+ #--------------------------------------#
281
+
282
+ # Stores the local path of a Pod.
283
+ #
284
+ # @param [String] name
285
+ # The name of the Pod.
286
+ #
287
+ # @param [Hash] source
288
+ # The hash which contains the options as returned by the
289
+ # downloader.
290
+ #
291
+ # @return [void]
292
+ #
293
+ def store_checkout_source(name, source)
294
+ root_name = Specification.root_name(name)
295
+ checkout_sources[root_name] = source
296
+ end
297
+
298
+ # @return [Hash{String=>Hash}] The options necessary to recreate the exact
299
+ # checkout of a given Pod grouped by its name.
300
+ #
301
+ attr_reader :checkout_sources
302
+
303
+ #--------------------------------------#
304
+
305
+ # Stores the local path of a Pod.
306
+ #
307
+ # @param [String] name
308
+ # The name of the Pod.
309
+ #
310
+ # @param [#to_s] path
311
+ # The local path where the Pod is stored.
312
+ #
313
+ # @return [void]
314
+ #
315
+ def store_local_path(name, path)
316
+ root_name = Specification.root_name(name)
317
+ local_pods[root_name] = path.to_s
318
+ end
319
+
320
+ # @return [Hash{String=>String}] The path of the Pods with a local source
321
+ # grouped by their name.
322
+ #
323
+ # @todo Rename (e.g. `pods_with_local_path`)
324
+ #
325
+ attr_reader :local_pods
326
+
327
+ # Checks if a Pod is locally sourced?
328
+ #
329
+ # @param [String] name
330
+ # The name of the Pod.
331
+ #
332
+ # @return [Bool] Whether the Pod is locally sourced.
333
+ #
334
+ def local?(name)
335
+ root_name = Specification.root_name(name)
336
+ !local_pods[root_name].nil?
337
+ end
338
+
339
+ #-------------------------------------------------------------------------#
340
+
341
+ end
342
+ end
343
+