PageRenderTime 66ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/cocoapods/external_sources.rb

https://bitbucket.org/aagraz/cocoapods
Ruby | 363 lines | 153 code | 59 blank | 151 comment | 19 complexity | 9b1f11b18a6e5ccc71eb109815a63698 MD5 | raw file
  1. module Pod
  2. # Provides support for initializing the correct concrete class of an external
  3. # source.
  4. #
  5. module ExternalSources
  6. # @return [AbstractExternalSource] an initialized instance of the concrete
  7. # external source class associated with the option specified in the
  8. # hash.
  9. #
  10. def self.from_dependency(dependency, podfile_path)
  11. name = dependency.root_name
  12. params = dependency.external_source
  13. klass = if params.key?(:git) then GitSource
  14. elsif params.key?(:svn) then SvnSource
  15. elsif params.key?(:hg) then MercurialSource
  16. elsif params.key?(:podspec) then PodspecSource
  17. elsif params.key?(:path) then PathSource
  18. end
  19. if params.key?(:local)
  20. klass = PathSource
  21. UI.warn "The `:local` option of the Podfile has been renamed to `:path` and is deprecated." \
  22. end
  23. if klass
  24. klass.new(name, params, podfile_path)
  25. else
  26. msg = "Unknown external source parameters for `#{name}`: `#{params}`"
  27. raise Informative, msg
  28. end
  29. end
  30. #-------------------------------------------------------------------------#
  31. # Abstract class that defines the common behaviour of external sources.
  32. #
  33. class AbstractExternalSource
  34. # @return [String] the name of the Pod described by this external source.
  35. #
  36. attr_reader :name
  37. # @return [Hash{Symbol => String}] the hash representation of the
  38. # external source.
  39. #
  40. attr_reader :params
  41. # @return [String] the path where the podfile is defined to resolve
  42. # relative paths.
  43. #
  44. attr_reader :podfile_path
  45. # @param [String] name @see name
  46. # @param [Hash] params @see params
  47. # @param [String] podfile_path @see podfile_path
  48. #
  49. def initialize(name, params, podfile_path)
  50. @name = name
  51. @params = params
  52. @podfile_path = podfile_path
  53. end
  54. # @return [Bool] whether an external source source is equal to another
  55. # according to the {#name} and to the {#params}.
  56. #
  57. def ==(other)
  58. return false if other.nil?
  59. name == other.name && params == other.params
  60. end
  61. #--------------------------------------#
  62. public
  63. # @!group Fetching
  64. # Fetches the external source from the remote according to the params.
  65. #
  66. # @param [Sandbox] sandbox
  67. # the sandbox where the specification should be stored.
  68. #
  69. # @return [void]
  70. #
  71. def fetch(sandbox)
  72. raise "Abstract method"
  73. end
  74. #--------------------------------------#
  75. public
  76. # @!group Subclasses hooks
  77. # Fetches the external source from the remote according to the params.
  78. #
  79. # @param [Sandbox] sandbox
  80. # the sandbox where the specification should be stored.
  81. #
  82. # @return [void]
  83. #
  84. def fetch(sandbox)
  85. raise "Abstract method"
  86. end
  87. # @return [String] a string representation of the source suitable for UI.
  88. #
  89. def description
  90. raise "Abstract method"
  91. end
  92. #--------------------------------------#
  93. private
  94. # @! Subclasses helpers
  95. # Pre-downloads a Pod passing the options to the downloader and informing
  96. # the sandbox.
  97. #
  98. # @param [Sandbox] sandbox
  99. # The sandbox where the Pod should be downloaded.
  100. #
  101. # @note To prevent a double download of the repository the pod is
  102. # marked as pre-downloaded indicating to the installer that only
  103. # clean operations are needed.
  104. #
  105. # @todo The downloader configuration is the same of the
  106. # #{PodSourceInstaller} and it needs to be kept in sync.
  107. #
  108. # @return [void]
  109. #
  110. def pre_download(sandbox)
  111. UI.titled_section("Pre-downloading: `#{name}` #{description}", { :verbose_prefix => "-> " }) do
  112. target = sandbox.root + name
  113. target.rmtree if target.exist?
  114. downloader = Downloader.for_target(target, params)
  115. downloader.cache_root = CACHE_ROOT.to_s
  116. downloader.max_cache_size = MAX_CACHE_SIZE
  117. downloader.aggressive_cache = false
  118. downloader.download
  119. store_podspec(sandbox, target + "#{name}.podspec")
  120. sandbox.store_pre_downloaded_pod(name)
  121. if downloader.options_specific?
  122. source = params
  123. else
  124. source = downloader.checkout_options
  125. end
  126. sandbox.store_checkout_source(name, source)
  127. end
  128. end
  129. # Stores the podspec in the sandbox and marks it as from an external
  130. # source.
  131. #
  132. # @param [Sandbox] sandbox
  133. # The sandbox where the specification should be stored.
  134. #
  135. # @param [Pathname, String] spec
  136. # The path of the specification or its contents.
  137. #
  138. # @note All the concrete implementations of #{fetch} should invoke this
  139. # method.
  140. #
  141. # @note The sandbox ensures that the podspec exists and that the names
  142. # match.
  143. #
  144. # @return [void]
  145. #
  146. def store_podspec(sandbox, spec)
  147. sandbox.store_podspec(name, spec, true)
  148. end
  149. end
  150. #-------------------------------------------------------------------------#
  151. # Provides support for fetching a specification file from a Git remote.
  152. #
  153. # Supports all the options of the downloader (is similar to the git key of
  154. # `source` attribute of a specification).
  155. #
  156. # @note The podspec must be in the root of the repository and should have a
  157. # name matching the one of the dependency.
  158. #
  159. class GitSource < AbstractExternalSource
  160. # @see AbstractExternalSource#fetch
  161. #
  162. def fetch(sandbox)
  163. pre_download(sandbox)
  164. end
  165. # @see AbstractExternalSource#description
  166. #
  167. def description
  168. "from `#{params[:git]}`".tap do |description|
  169. description << ", commit `#{params[:commit]}`" if params[:commit]
  170. description << ", branch `#{params[:branch]}`" if params[:branch]
  171. description << ", tag `#{params[:tag]}`" if params[:tag]
  172. end
  173. end
  174. end
  175. #-------------------------------------------------------------------------#
  176. # Provides support for fetching a specification file from a SVN source
  177. # remote.
  178. #
  179. # Supports all the options of the downloader (is similar to the git key of
  180. # `source` attribute of a specification).
  181. #
  182. # @note The podspec must be in the root of the repository and should have a
  183. # name matching the one of the dependency.
  184. #
  185. class SvnSource < AbstractExternalSource
  186. # @see AbstractExternalSource#fetch
  187. #
  188. def fetch(sandbox)
  189. pre_download(sandbox)
  190. end
  191. # @see AbstractExternalSource#description
  192. #
  193. def description
  194. "from `#{params[:svn]}`".tap do |description|
  195. description << ", folder `#{params[:folder]}`" if params[:folder]
  196. description << ", tag `#{params[:tag]}`" if params[:tag]
  197. description << ", revision `#{params[:revision]}`" if params[:revision]
  198. end
  199. end
  200. end
  201. #-------------------------------------------------------------------------#
  202. # Provides support for fetching a specification file from a Mercurial
  203. # source remote.
  204. #
  205. # Supports all the options of the downloader (is similar to the git key of
  206. # `source` attribute of a specification).
  207. #
  208. # @note The podspec must be in the root of the repository and should have a
  209. # name matching the one of the dependency.
  210. #
  211. class MercurialSource < AbstractExternalSource
  212. # @see AbstractExternalSource#fetch
  213. #
  214. def fetch(sandbox)
  215. pre_download(sandbox)
  216. end
  217. # @see AbstractExternalSource#description
  218. #
  219. def description
  220. "from `#{params[:hg]}`".tap do |description|
  221. description << ", revision `#{params[:revision]}`" if params[:revision]
  222. end
  223. end
  224. end
  225. #-------------------------------------------------------------------------#
  226. # Provides support for fetching a specification file from an URL. Can be
  227. # http, file, etc.
  228. #
  229. class PodspecSource < AbstractExternalSource
  230. # @see AbstractExternalSource#fetch
  231. #
  232. def fetch(sandbox)
  233. UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
  234. require 'open-uri'
  235. open(podspec_uri) { |io| store_podspec(sandbox, io.read) }
  236. end
  237. end
  238. # @see AbstractExternalSource#description
  239. #
  240. def description
  241. "from `#{params[:podspec]}`"
  242. end
  243. #--------------------------------------#
  244. private
  245. # @!group Helpers
  246. # @return [String] The uri of the podspec appending the name of the file
  247. # and expanding it if necessary.
  248. #
  249. # @note If the declared path is expanded only if the represents a path
  250. # relative to the file system.
  251. #
  252. def podspec_uri
  253. declared_path = params[:podspec].to_s
  254. if declared_path.match(%r{^.+://})
  255. declared_path
  256. else
  257. path_with_ext = File.extname(declared_path) == '.podspec' ? declared_path : "#{declared_path}/#{name}.podspec"
  258. podfile_dir = File.dirname(podfile_path || '')
  259. absolute_path = File.expand_path(path_with_ext, podfile_dir)
  260. absolute_path
  261. end
  262. end
  263. end
  264. #-------------------------------------------------------------------------#
  265. # Provides support for fetching a specification file from a path local to
  266. # the machine running the installation.
  267. #
  268. # Works with the {LocalPod::LocalSourcedPod} class.
  269. #
  270. class PathSource < AbstractExternalSource
  271. # @see AbstractExternalSource#fetch
  272. #
  273. def fetch(sandbox)
  274. UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
  275. podspec = podspec_path
  276. store_podspec(sandbox, podspec)
  277. sandbox.store_local_path(name, podspec.dirname)
  278. end
  279. end
  280. # @see AbstractExternalSource#description
  281. #
  282. def description
  283. "from `#{params[:path] || params[:local]}`"
  284. end
  285. #--------------------------------------#
  286. private
  287. # @!group Helpers
  288. # @return [Pathname] the path of the podspec.
  289. #
  290. def podspec_path
  291. declared_path = (params[:path] || params[:local]).to_s
  292. path_with_ext = File.extname(declared_path) == '.podspec' ? declared_path : "#{declared_path}/#{name}.podspec"
  293. podfile_dir = File.dirname(podfile_path || '')
  294. absolute_path = File.expand_path(path_with_ext, podfile_dir)
  295. pathname = Pathname.new(absolute_path)
  296. unless pathname.exist?
  297. raise Informative, "No podspec found for `#{name}` in `#{params[:local]}`"
  298. end
  299. pathname
  300. end
  301. end
  302. #-------------------------------------------------------------------------#
  303. end
  304. end