cocoapods-square-stable 0.19.3

Sign up to get free protection for your applications and to get access to all the features.
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,231 @@
1
+ module Pod
2
+
3
+ # Stores the global configuration of CocoaPods.
4
+ #
5
+ class Config
6
+
7
+ # The default settings for the configuration.
8
+ #
9
+ # Users can specify custom settings in `~/.cocoapods/config.yaml`.
10
+ # An example of the contents of this file might look like:
11
+ #
12
+ # ---
13
+ # skip_repo_update: true
14
+ # new_version_message: false
15
+ #
16
+ DEFAULTS = {
17
+ :verbose => false,
18
+ :silent => false,
19
+ :skip_repo_update => false,
20
+ :aggressive_cache => false,
21
+
22
+ :clean => true,
23
+ :integrate_targets => true,
24
+ :new_version_message => true,
25
+ }
26
+
27
+ #--------------------------------------#
28
+
29
+ # @!group UI
30
+
31
+ # @return [Bool] Whether CocoaPods should provide detailed output about the
32
+ # performed actions.
33
+ #
34
+ attr_accessor :verbose
35
+ alias_method :verbose?, :verbose
36
+
37
+ # @return [Bool] Whether CocoaPods should produce not output.
38
+ #
39
+ attr_accessor :silent
40
+ alias_method :silent?, :silent
41
+
42
+ # @return [Bool] Whether a message should be printed when a new version of
43
+ # CocoaPods is available.
44
+ #
45
+ attr_accessor :new_version_message
46
+ alias_method :new_version_message?, :new_version_message
47
+
48
+ #--------------------------------------#
49
+
50
+ # @!group Installation
51
+
52
+ # @return [Bool] Whether the installer should clean after the installation.
53
+ #
54
+ attr_accessor :clean
55
+ alias_method :clean?, :clean
56
+
57
+ # @return [Bool] Whether CocoaPods should integrate a user target and build
58
+ # the workspace or just create the Pods project.
59
+ #
60
+ attr_accessor :integrate_targets
61
+ alias_method :integrate_targets?, :integrate_targets
62
+
63
+
64
+ # @return [Bool] Whether the installer should skip the repos update.
65
+ #
66
+ attr_accessor :skip_repo_update
67
+ alias_method :skip_repo_update?, :skip_repo_update
68
+
69
+ # Allows to set whether the downloader should use more aggressive caching
70
+ # options.
71
+ #
72
+ # @note The aggressive cache has lead to issues if a tag is updated to
73
+ # point to another commit.
74
+ #
75
+ attr_writer :aggressive_cache
76
+
77
+ # @return [Bool] Whether the downloader should use more aggressive caching
78
+ # options.
79
+ #
80
+ def aggressive_cache?
81
+ @aggressive_cache || (ENV['CP_AGGRESSIVE_CACHE'] != 'FALSE')
82
+ end
83
+
84
+ #--------------------------------------#
85
+
86
+ # @!group Initialization
87
+
88
+ def initialize
89
+ configure_with(DEFAULTS)
90
+
91
+ if user_settings_file.exist?
92
+ require 'yaml'
93
+ user_settings = YAML.load_file(user_settings_file)
94
+ configure_with(user_settings)
95
+ end
96
+ end
97
+
98
+ def verbose
99
+ @verbose && !silent
100
+ end
101
+
102
+ #--------------------------------------#
103
+
104
+ # @!group Paths
105
+
106
+ # @return [Pathname] the directory where the CocoaPods sources are stored.
107
+ #
108
+ def repos_dir
109
+ @repos_dir ||= Pathname.new(ENV['CP_REPOS_DIR'] || "~/.cocoapods").expand_path
110
+ end
111
+
112
+ attr_writer :repos_dir
113
+
114
+ # @return [Pathname] the root of the CocoaPods installation where the
115
+ # Podfile is located.
116
+ #
117
+ def installation_root
118
+ @installation_root ||= Pathname.pwd
119
+ end
120
+
121
+ attr_writer :installation_root
122
+ alias :project_root :installation_root
123
+
124
+ # @return [Pathname] The root of the sandbox.
125
+ #
126
+ def sandbox_root
127
+ @sandbox_root ||= installation_root + 'Pods'
128
+ end
129
+
130
+ attr_writer :sandbox_root
131
+ alias :project_pods_root :sandbox_root
132
+
133
+ # @return [Sandbox] The sandbox of the current project.
134
+ #
135
+ def sandbox
136
+ @sandbox ||= Sandbox.new(sandbox_root)
137
+ end
138
+
139
+ # @return [Podfile] The Podfile to use for the current execution.
140
+ #
141
+ def podfile
142
+ @podfile ||= Podfile.from_file(podfile_path) if podfile_path.exist?
143
+ end
144
+ attr_writer :podfile
145
+
146
+ # @return [Lockfile] The Lockfile to use for the current execution.
147
+ #
148
+ def lockfile
149
+ @lockfile ||= Lockfile.from_file(lockfile_path) if lockfile_path.exist?
150
+ end
151
+
152
+ #--------------------------------------#
153
+
154
+ # @!group Helpers
155
+
156
+ # private
157
+
158
+ # @return [Pathname] The path of the file which contains the user settings.
159
+ #
160
+ def user_settings_file
161
+ repos_dir + "config.yaml"
162
+ end
163
+
164
+ # Sets the values of the attributes with the given hash.
165
+ #
166
+ # @param [Hash{String,Symbol => Object}] values_by_key
167
+ # The values of the attributes grouped by key.
168
+ #
169
+ # @return [void]
170
+ #
171
+ def configure_with(values_by_key)
172
+ return unless values_by_key
173
+ values_by_key.each do |key, value|
174
+ self.instance_variable_set("@#{key}", value)
175
+ end
176
+ end
177
+
178
+ # Returns the path of the Podfile.
179
+ #
180
+ # @note The Podfile can be named either `CocoaPods.podfile` or `Podfile`.
181
+ # The first is preferred as it allows to specify an OS X UTI.
182
+ #
183
+ def podfile_path
184
+ unless @podfile_path
185
+ path = installation_root + 'CocoaPods.podfile.yaml'
186
+ path = installation_root + 'CocoaPods.podfile' unless path.exist?
187
+ path = installation_root + 'Podfile' unless path.exist?
188
+ @podfile_path = path
189
+ end
190
+ @podfile_path
191
+ end
192
+
193
+ # Returns the path of the Lockfile.
194
+ #
195
+ # @note The Lockfile is named `Podfile.lock`.
196
+ #
197
+ def lockfile_path
198
+ @lockfile_path ||= installation_root + 'Podfile.lock'
199
+ end
200
+
201
+ #--------------------------------------#
202
+
203
+ # @return [Config] the current config instance creating one if needed.
204
+ #
205
+ def self.instance
206
+ @instance ||= new
207
+ end
208
+
209
+ # Sets the current config instance. If set to nil the config will be
210
+ # recreated when needed.
211
+ #
212
+ # @param [Config, Nil] the instance.
213
+ #
214
+ # @return [void]
215
+ #
216
+ def self.instance=(instance)
217
+ @instance = instance
218
+ end
219
+
220
+ #-------------------------------------------------------------------------#
221
+
222
+ # Provides support for accessing the configuration instance in other
223
+ # scopes.
224
+ #
225
+ module Mixin
226
+ def config
227
+ Config.instance
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,59 @@
1
+ require 'cocoapods-downloader'
2
+
3
+ module Pod
4
+ module Downloader
5
+ class Base
6
+
7
+ override_api do
8
+
9
+ def execute_command(executable, command, raise_on_failure = false)
10
+ Executable.execute_command(executable, command, raise_on_failure)
11
+ end
12
+
13
+ # Indicates that an action will be performed. The action is passed as a
14
+ # block.
15
+ #
16
+ # @param [String] message
17
+ # The message associated with the action.
18
+ #
19
+ # @yield The action, this block is always executed.
20
+ #
21
+ # @return [void]
22
+ #
23
+ def ui_action(message)
24
+ UI.section(" > #{message}", '', 1) do
25
+ yield
26
+ end
27
+ end
28
+
29
+ # Indicates that a minor action will be performed. The action is passed
30
+ # as a block.
31
+ #
32
+ # @param [String] message
33
+ # The message associated with the action.
34
+ #
35
+ # @yield The action, this block is always executed.
36
+ #
37
+ # @return [void]
38
+ #
39
+ def ui_sub_action(message)
40
+ UI.section(" > #{message}", '', 2) do
41
+ yield
42
+ end
43
+ end
44
+
45
+ # Prints an UI message.
46
+ #
47
+ # @param [String] message
48
+ # The message associated with the action.
49
+ #
50
+ # @return [void]
51
+ #
52
+ def ui_message(message)
53
+ UI.puts message
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,118 @@
1
+ module Pod
2
+
3
+ # Module which provides support for running executables.
4
+ #
5
+ # In a class it can be used as:
6
+ #
7
+ # extend Executable
8
+ # executable :git
9
+ #
10
+ # This will create two methods `git` and `git!` both accept a command but
11
+ # the later will raise on non successful executions. The methods return the
12
+ # output of the command.
13
+ #
14
+ module Executable
15
+
16
+ # Creates the methods for the executable with the given name.
17
+ #
18
+ # @param [Symbol] name
19
+ # the name of the executable.
20
+ #
21
+ # @return [void]
22
+ #
23
+ def executable(name)
24
+
25
+ define_method(name) do |command|
26
+ Executable.execute_command(name, command, false)
27
+ end
28
+
29
+ define_method(name.to_s + "!") do |command|
30
+ Executable.execute_command(name, command, true)
31
+ end
32
+ end
33
+
34
+ # Executes the given command displaying it if in verbose mode.
35
+ #
36
+ # @param [String] bin
37
+ # The binary to use.
38
+ #
39
+ # @param [String] command
40
+ # The command to send to the binary.
41
+ #
42
+ # @param [Bool] raise_on_failure
43
+ # Whether it should raise if the command fails.
44
+ #
45
+ # @raise If the executable could not be located.
46
+ #
47
+ # @raise If the command fails and the `raise_on_failure` is set to true.
48
+ #
49
+ # @return [String] the output of the command (STDOUT and STDERR).
50
+ #
51
+ # @todo Find a way to display the live output of the commands.
52
+ #
53
+ def self.execute_command(executable, command, raise_on_failure)
54
+
55
+ bin = `which #{executable}`.strip
56
+ raise Informative, "Unable to locate the executable `#{executable}`" if bin.empty?
57
+
58
+ require 'open4'
59
+
60
+ full_command = "#{bin} #{command}"
61
+
62
+ if Config.instance.verbose?
63
+ UI.message("$ #{full_command}")
64
+ stdout, stderr = Indenter.new(STDOUT), Indenter.new(STDERR)
65
+ else
66
+ stdout, stderr = Indenter.new, Indenter.new
67
+ end
68
+
69
+ options = {:stdout => stdout, :stderr => stderr, :status => true}
70
+ status = Open4.spawn(full_command, options)
71
+ output = stdout.join("\n") + stderr.join("\n")
72
+ unless status.success?
73
+ if raise_on_failure
74
+ raise Informative, "#{name} #{command}\n\n#{output}"
75
+ else
76
+ UI.message("[!] Failed: #{full_command}".red)
77
+ end
78
+ end
79
+ output
80
+ end
81
+
82
+ #-------------------------------------------------------------------------#
83
+
84
+ # Helper class that allows to write to an {IO} instance taking into account
85
+ # the UI indentation lever.
86
+ #
87
+ class Indenter < ::Array
88
+
89
+ # @return [Fixnum] The indentation level of the UI.
90
+ #
91
+ attr_accessor :indent
92
+
93
+ # @return [IO] the {IO} to which the output should be printed.
94
+ #
95
+ attr_accessor :io
96
+
97
+ # @param [IO] io @see io
98
+ #
99
+ def initialize(io = nil)
100
+ @io = io
101
+ @indent = ' ' * UI.indentation_level
102
+ end
103
+
104
+ # Stores a portion of the output and prints it to the {IO} instance.
105
+ #
106
+ # @param [String] value
107
+ # the output to print.
108
+ #
109
+ # @return [void]
110
+ #
111
+ def <<(value)
112
+ super
113
+ ensure
114
+ @io << "#{ indent }#{ value }" if @io
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,363 @@
1
+ module Pod
2
+
3
+ # Provides support for initializing the correct concrete class of an external
4
+ # source.
5
+ #
6
+ module ExternalSources
7
+
8
+ # @return [AbstractExternalSource] an initialized instance of the concrete
9
+ # external source class associated with the option specified in the
10
+ # hash.
11
+ #
12
+ def self.from_dependency(dependency, podfile_path)
13
+ name = dependency.root_name
14
+ params = dependency.external_source
15
+
16
+ klass = if params.key?(:git) then GitSource
17
+ elsif params.key?(:svn) then SvnSource
18
+ elsif params.key?(:hg) then MercurialSource
19
+ elsif params.key?(:podspec) then PodspecSource
20
+ elsif params.key?(:path) then PathSource
21
+ end
22
+
23
+ if params.key?(:local)
24
+ klass = PathSource
25
+ UI.warn "The `:local` option of the Podfile has been renamed to `:path` and is deprecated." \
26
+ end
27
+
28
+ if klass
29
+ klass.new(name, params, podfile_path)
30
+ else
31
+ msg = "Unknown external source parameters for `#{name}`: `#{params}`"
32
+ raise Informative, msg
33
+ end
34
+ end
35
+
36
+ #-------------------------------------------------------------------------#
37
+
38
+ # Abstract class that defines the common behaviour of external sources.
39
+ #
40
+ class AbstractExternalSource
41
+
42
+ # @return [String] the name of the Pod described by this external source.
43
+ #
44
+ attr_reader :name
45
+
46
+ # @return [Hash{Symbol => String}] the hash representation of the
47
+ # external source.
48
+ #
49
+ attr_reader :params
50
+
51
+ # @return [String] the path where the podfile is defined to resolve
52
+ # relative paths.
53
+ #
54
+ attr_reader :podfile_path
55
+
56
+ # @param [String] name @see name
57
+ # @param [Hash] params @see params
58
+ # @param [String] podfile_path @see podfile_path
59
+ #
60
+ def initialize(name, params, podfile_path)
61
+ @name = name
62
+ @params = params
63
+ @podfile_path = podfile_path
64
+ end
65
+
66
+ # @return [Bool] whether an external source source is equal to another
67
+ # according to the {#name} and to the {#params}.
68
+ #
69
+ def ==(other)
70
+ return false if other.nil?
71
+ name == other.name && params == other.params
72
+ end
73
+
74
+ #--------------------------------------#
75
+
76
+ public
77
+
78
+ # @!group Fetching
79
+
80
+ # Fetches the external source from the remote according to the params.
81
+ #
82
+ # @param [Sandbox] sandbox
83
+ # the sandbox where the specification should be stored.
84
+ #
85
+ # @return [void]
86
+ #
87
+ def fetch(sandbox)
88
+ raise "Abstract method"
89
+ end
90
+
91
+ #--------------------------------------#
92
+
93
+ public
94
+
95
+ # @!group Subclasses hooks
96
+
97
+ # Fetches the external source from the remote according to the params.
98
+ #
99
+ # @param [Sandbox] sandbox
100
+ # the sandbox where the specification should be stored.
101
+ #
102
+ # @return [void]
103
+ #
104
+ def fetch(sandbox)
105
+ raise "Abstract method"
106
+ end
107
+
108
+ # @return [String] a string representation of the source suitable for UI.
109
+ #
110
+ def description
111
+ raise "Abstract method"
112
+ end
113
+
114
+ #--------------------------------------#
115
+
116
+ private
117
+
118
+ # @! Subclasses helpers
119
+
120
+ # Pre-downloads a Pod passing the options to the downloader and informing
121
+ # the sandbox.
122
+ #
123
+ # @param [Sandbox] sandbox
124
+ # The sandbox where the Pod should be downloaded.
125
+ #
126
+ # @note To prevent a double download of the repository the pod is
127
+ # marked as pre-downloaded indicating to the installer that only
128
+ # clean operations are needed.
129
+ #
130
+ # @todo The downloader configuration is the same of the
131
+ # #{PodSourceInstaller} and it needs to be kept in sync.
132
+ #
133
+ # @return [void]
134
+ #
135
+ def pre_download(sandbox)
136
+ UI.titled_section("Pre-downloading: `#{name}` #{description}", { :verbose_prefix => "-> " }) do
137
+ target = sandbox.root + name
138
+ target.rmtree if target.exist?
139
+ downloader = Downloader.for_target(target, params)
140
+ downloader.cache_root = CACHE_ROOT.to_s
141
+ downloader.max_cache_size = MAX_CACHE_SIZE
142
+ downloader.aggressive_cache = false
143
+ downloader.download
144
+ store_podspec(sandbox, target + "#{name}.podspec")
145
+ sandbox.store_pre_downloaded_pod(name)
146
+ if downloader.options_specific?
147
+ source = params
148
+ else
149
+ source = downloader.checkout_options
150
+ end
151
+ sandbox.store_checkout_source(name, source)
152
+ end
153
+ end
154
+
155
+ # Stores the podspec in the sandbox and marks it as from an external
156
+ # source.
157
+ #
158
+ # @param [Sandbox] sandbox
159
+ # The sandbox where the specification should be stored.
160
+ #
161
+ # @param [Pathname, String] spec
162
+ # The path of the specification or its contents.
163
+ #
164
+ # @note All the concrete implementations of #{fetch} should invoke this
165
+ # method.
166
+ #
167
+ # @note The sandbox ensures that the podspec exists and that the names
168
+ # match.
169
+ #
170
+ # @return [void]
171
+ #
172
+ def store_podspec(sandbox, spec)
173
+ sandbox.store_podspec(name, spec, true)
174
+ end
175
+
176
+ end
177
+
178
+ #-------------------------------------------------------------------------#
179
+
180
+ # Provides support for fetching a specification file from a Git remote.
181
+ #
182
+ # Supports all the options of the downloader (is similar to the git key of
183
+ # `source` attribute of a specification).
184
+ #
185
+ # @note The podspec must be in the root of the repository and should have a
186
+ # name matching the one of the dependency.
187
+ #
188
+ class GitSource < AbstractExternalSource
189
+
190
+ # @see AbstractExternalSource#fetch
191
+ #
192
+ def fetch(sandbox)
193
+ pre_download(sandbox)
194
+ end
195
+
196
+ # @see AbstractExternalSource#description
197
+ #
198
+ def description
199
+ "from `#{params[:git]}`".tap do |description|
200
+ description << ", commit `#{params[:commit]}`" if params[:commit]
201
+ description << ", branch `#{params[:branch]}`" if params[:branch]
202
+ description << ", tag `#{params[:tag]}`" if params[:tag]
203
+ end
204
+ end
205
+ end
206
+
207
+ #-------------------------------------------------------------------------#
208
+
209
+ # Provides support for fetching a specification file from a SVN source
210
+ # remote.
211
+ #
212
+ # Supports all the options of the downloader (is similar to the git key of
213
+ # `source` attribute of a specification).
214
+ #
215
+ # @note The podspec must be in the root of the repository and should have a
216
+ # name matching the one of the dependency.
217
+ #
218
+ class SvnSource < AbstractExternalSource
219
+
220
+ # @see AbstractExternalSource#fetch
221
+ #
222
+ def fetch(sandbox)
223
+ pre_download(sandbox)
224
+ end
225
+
226
+ # @see AbstractExternalSource#description
227
+ #
228
+ def description
229
+ "from `#{params[:svn]}`".tap do |description|
230
+ description << ", folder `#{params[:folder]}`" if params[:folder]
231
+ description << ", tag `#{params[:tag]}`" if params[:tag]
232
+ description << ", revision `#{params[:revision]}`" if params[:revision]
233
+ end
234
+ end
235
+ end
236
+
237
+ #-------------------------------------------------------------------------#
238
+
239
+ # Provides support for fetching a specification file from a Mercurial
240
+ # source remote.
241
+ #
242
+ # Supports all the options of the downloader (is similar to the git key of
243
+ # `source` attribute of a specification).
244
+ #
245
+ # @note The podspec must be in the root of the repository and should have a
246
+ # name matching the one of the dependency.
247
+ #
248
+ class MercurialSource < AbstractExternalSource
249
+
250
+ # @see AbstractExternalSource#fetch
251
+ #
252
+ def fetch(sandbox)
253
+ pre_download(sandbox)
254
+ end
255
+
256
+ # @see AbstractExternalSource#description
257
+ #
258
+ def description
259
+ "from `#{params[:hg]}`".tap do |description|
260
+ description << ", revision `#{params[:revision]}`" if params[:revision]
261
+ end
262
+ end
263
+ end
264
+
265
+ #-------------------------------------------------------------------------#
266
+
267
+ # Provides support for fetching a specification file from an URL. Can be
268
+ # http, file, etc.
269
+ #
270
+ class PodspecSource < AbstractExternalSource
271
+
272
+ # @see AbstractExternalSource#fetch
273
+ #
274
+ def fetch(sandbox)
275
+ UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
276
+
277
+ require 'open-uri'
278
+ open(podspec_uri) { |io| store_podspec(sandbox, io.read) }
279
+ end
280
+ end
281
+
282
+ # @see AbstractExternalSource#description
283
+ #
284
+ def description
285
+ "from `#{params[:podspec]}`"
286
+ end
287
+
288
+ #--------------------------------------#
289
+
290
+ private
291
+
292
+ # @!group Helpers
293
+
294
+ # @return [String] The uri of the podspec appending the name of the file
295
+ # and expanding it if necessary.
296
+ #
297
+ # @note If the declared path is expanded only if the represents a path
298
+ # relative to the file system.
299
+ #
300
+ def podspec_uri
301
+ declared_path = params[:podspec].to_s
302
+ if declared_path.match(%r{^.+://})
303
+ declared_path
304
+ else
305
+ path_with_ext = File.extname(declared_path) == '.podspec' ? declared_path : "#{declared_path}/#{name}.podspec"
306
+ podfile_dir = File.dirname(podfile_path || '')
307
+ absolute_path = File.expand_path(path_with_ext, podfile_dir)
308
+ absolute_path
309
+ end
310
+ end
311
+ end
312
+
313
+ #-------------------------------------------------------------------------#
314
+
315
+ # Provides support for fetching a specification file from a path local to
316
+ # the machine running the installation.
317
+ #
318
+ # Works with the {LocalPod::LocalSourcedPod} class.
319
+ #
320
+ class PathSource < AbstractExternalSource
321
+
322
+ # @see AbstractExternalSource#fetch
323
+ #
324
+ def fetch(sandbox)
325
+ UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
326
+ podspec = podspec_path
327
+ store_podspec(sandbox, podspec)
328
+ sandbox.store_local_path(name, podspec.dirname)
329
+ end
330
+ end
331
+
332
+ # @see AbstractExternalSource#description
333
+ #
334
+ def description
335
+ "from `#{params[:path] || params[:local]}`"
336
+ end
337
+
338
+ #--------------------------------------#
339
+
340
+ private
341
+
342
+ # @!group Helpers
343
+
344
+ # @return [Pathname] the path of the podspec.
345
+ #
346
+ def podspec_path
347
+ declared_path = (params[:path] || params[:local]).to_s
348
+ path_with_ext = File.extname(declared_path) == '.podspec' ? declared_path : "#{declared_path}/#{name}.podspec"
349
+ podfile_dir = File.dirname(podfile_path || '')
350
+ absolute_path = File.expand_path(path_with_ext, podfile_dir)
351
+ pathname = Pathname.new(absolute_path)
352
+
353
+ unless pathname.exist?
354
+ raise Informative, "No podspec found for `#{name}` in `#{params[:local]}`"
355
+ end
356
+ pathname
357
+ end
358
+ end
359
+
360
+ #-------------------------------------------------------------------------#
361
+
362
+ end
363
+ end