Class: Pod::Downloader::Cache
- Inherits:
-
Object
- Object
- Pod::Downloader::Cache
- Defined in:
- lib/cocoapods/downloader/cache.rb
Overview
The class responsible for managing Pod downloads, transparently caching them in a cache directory.
Instance Attribute Summary collapse
-
#root ⇒ Pathname
readonly
The root directory where this cache store its downloads.
Class Method Summary collapse
-
.lock(location, lock_type) ⇒ void
Creates a .lock file at
location
, aquires a lock of typelock_type
, checks that it is valid, and executes passed block while holding on to that lock. -
.read_lock(location, &block) ⇒ void
Convenience method for acquiring a shared lock to safely read from the cache.
-
.valid_lock?(file, filename) ⇒ Boolean
Checks that the lock is on a file that still exists on the filesystem.
-
.write_lock(location, &block) ⇒ void
Convenience method for acquiring an exclusive lock to safely write to the cache.
Instance Method Summary collapse
-
#cache_descriptors_per_pod ⇒ Hash<String, Hash<Symbol, String>>
A hash whose keys are the pod name And values are a hash with the following keys: :spec_file : path to the spec file :name : name of the pod :version : pod version :release : boolean to tell if that's a release pod :slug : the slug path where the pod cache is located.
-
#cached_pod(request) ⇒ Response
private
The download response for the given
request
that was found in the download cache. -
#cached_spec(request) ⇒ Specification
private
The cached specification for the given
request
. -
#copy_and_clean(source, destination, spec) ⇒ Void
private
Copies the
source
directory todestination
, cleaning the directory of any files unused byspec
. - #download(request, target) ⇒ Object private
-
#download_pod(request) ⇒ Response
Downloads the Pod from the given
request
. -
#ensure_matching_version ⇒ Void
private
Ensures the cache on disk was created with the same CocoaPods version as is currently running.
- #group_subspecs_by_platform(spec) ⇒ Object private
-
#in_tmpdir(&blk) ⇒ Object
private
Performs the given block inside a temporary directory, which is removed at the end of the block's scope.
-
#initialize(root) ⇒ Cache
constructor
Initialize a new instance.
-
#path_for_pod(request, slug_opts = {}) ⇒ Pathname
private
The path for the Pod downloaded from the given
request
. -
#path_for_spec(request, slug_opts = {}) ⇒ Pathname
private
The path for the podspec downloaded from the given
request
. -
#uncached_pod(request) ⇒ Response
private
The download response for the given
request
that was not found in the download cache. -
#write_spec(spec, path) ⇒ Void
private
Writes the given
spec
to the givenpath
.
Constructor Details
Instance Attribute Details
#root ⇒ Pathname (readonly)
Returns The root directory where this cache store its downloads.
13 14 15 |
# File 'lib/cocoapods/downloader/cache.rb', line 13 def root @root end |
Class Method Details
.lock(location, lock_type) ⇒ void
This method returns an undefined value.
Creates a .lock file at location
, aquires a lock of type
lock_type
, checks that it is valid, and executes passed block while
holding on to that lock. Afterwards, the .lock file is deleted, which is
why validation of the lock is necessary, as you might have a lock on a
file that doesn't exist on the filesystem anymore.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/cocoapods/downloader/cache.rb', line 117 def self.lock(location, lock_type) raise ArgumentError, 'no block given' unless block_given? lockfile = "#{location}.lock" f = nil loop do f.close if f f = File.open(lockfile, File::CREAT, 0o644) f.flock(lock_type) break if Cache.valid_lock?(f, lockfile) end begin yield location ensure if lock_type == File::LOCK_SH f.flock(File::LOCK_EX) File.delete(lockfile) if Cache.valid_lock?(f, lockfile) else File.delete(lockfile) end f.close end end |
.read_lock(location, &block) ⇒ void
This method returns an undefined value.
Convenience method for acquiring a shared lock to safely read from the
cache. See Cache.lock
for more details.
83 84 85 |
# File 'lib/cocoapods/downloader/cache.rb', line 83 def self.read_lock(location, &block) Cache.lock(location, File::LOCK_SH, &block) end |
.valid_lock?(file, filename) ⇒ Boolean
Checks that the lock is on a file that still exists on the filesystem.
151 152 153 154 155 |
# File 'lib/cocoapods/downloader/cache.rb', line 151 def self.valid_lock?(file, filename) file.stat.ino == File.stat(filename).ino rescue Errno::ENOENT false end |
.write_lock(location, &block) ⇒ void
This method returns an undefined value.
Convenience method for acquiring an exclusive lock to safely write to
the cache. See Cache.lock
for more details.
98 99 100 |
# File 'lib/cocoapods/downloader/cache.rb', line 98 def self.write_lock(location, &block) Cache.lock(location, File::LOCK_EX, &block) end |
Instance Method Details
#cache_descriptors_per_pod ⇒ Hash<String, Hash<Symbol, String>>
Returns A hash whose keys are the pod name And values are a hash with the following keys: :spec_file : path to the spec file :name : name of the pod :version : pod version :release : boolean to tell if that's a release pod :slug : the slug path where the pod cache is located.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/cocoapods/downloader/cache.rb', line 50 def cache_descriptors_per_pod specs_dir = root + 'Specs' release_specs_dir = specs_dir + 'Release' return {} unless specs_dir.exist? spec_paths = specs_dir.find.select { |f| f.fnmatch('*.podspec.json') } spec_paths.reduce({}) do |hash, spec_path| spec = Specification.from_file(spec_path) hash[spec.name] ||= [] is_release = spec_path.to_s.start_with?(release_specs_dir.to_s) request = Downloader::Request.new(:spec => spec, :released => is_release) hash[spec.name] << { :spec_file => spec_path, :name => spec.name, :version => spec.version, :release => is_release, :slug => root + request.slug, } hash end end |
#cached_pod(request) ⇒ Response (private)
Returns The download response for the given request
that
was found in the download cache.
209 210 211 212 213 214 215 216 |
# File 'lib/cocoapods/downloader/cache.rb', line 209 def cached_pod(request) cached_spec = cached_spec(request) path = path_for_pod(request) return unless cached_spec && path.directory? spec = request.spec || cached_spec Response.new(path, spec, request.params) end |
#cached_spec(request) ⇒ Specification (private)
Returns The cached specification for the given
request
.
224 225 226 227 228 229 |
# File 'lib/cocoapods/downloader/cache.rb', line 224 def cached_spec(request) path = path_for_spec(request) path.file? && Specification.from_file(path) rescue JSON::ParserError nil end |
#copy_and_clean(source, destination, spec) ⇒ Void (private)
Copies the source
directory to destination
, cleaning the directory
of any files unused by spec
.
282 283 284 285 286 287 288 289 290 291 |
# File 'lib/cocoapods/downloader/cache.rb', line 282 def copy_and_clean(source, destination, spec) specs_by_platform = group_subspecs_by_platform(spec) destination.parent.mkpath Cache.write_lock(destination) do FileUtils.rm_rf(destination) FileUtils.cp_r(source, destination) Pod::Installer::PodSourcePreparer.new(spec, destination).prepare! Sandbox::PodDirCleaner.new(destination, specs_by_platform).clean! end end |
#download(request, target) ⇒ Object (private)
255 256 257 |
# File 'lib/cocoapods/downloader/cache.rb', line 255 def download(request, target) Downloader.download_request(request, target) end |
#download_pod(request) ⇒ Response
Downloads the Pod from the given request
32 33 34 35 36 37 38 39 |
# File 'lib/cocoapods/downloader/cache.rb', line 32 def download_pod(request) cached_pod(request) || uncached_pod(request) rescue Informative raise rescue UI.puts("\n[!] Error installing #{request.name}".red) raise end |
#ensure_matching_version ⇒ Void (private)
Ensures the cache on disk was created with the same CocoaPods version as is currently running.
164 165 166 167 168 169 170 171 172 |
# File 'lib/cocoapods/downloader/cache.rb', line 164 def ensure_matching_version version_file = root + 'VERSION' version = version_file.read.strip if version_file.file? root.rmtree if version != Pod::VERSION && root.exist? root.mkpath version_file.open('w') { |f| f << Pod::VERSION } end |
#group_subspecs_by_platform(spec) ⇒ Object (private)
293 294 295 296 297 298 299 300 301 302 |
# File 'lib/cocoapods/downloader/cache.rb', line 293 def group_subspecs_by_platform(spec) specs_by_platform = {} [spec, *spec.recursive_subspecs].each do |ss| ss.available_platforms.each do |platform| specs_by_platform[platform] ||= [] specs_by_platform[platform] << ss end end specs_by_platform end |
#in_tmpdir(&blk) ⇒ Object (private)
Performs the given block inside a temporary directory, which is removed at the end of the block's scope.
264 265 266 267 268 269 |
# File 'lib/cocoapods/downloader/cache.rb', line 264 def in_tmpdir(&blk) tmpdir = Pathname(Dir.mktmpdir) blk.call(tmpdir) ensure FileUtils.remove_entry(tmpdir, :force => true) if tmpdir && tmpdir.exist? end |
#path_for_pod(request, slug_opts = {}) ⇒ Pathname (private)
Returns The path for the Pod downloaded from the given
request
.
184 185 186 |
# File 'lib/cocoapods/downloader/cache.rb', line 184 def path_for_pod(request, slug_opts = {}) root + request.slug(**slug_opts) end |
#path_for_spec(request, slug_opts = {}) ⇒ Pathname (private)
Returns The path for the podspec downloaded from the given
request
.
198 199 200 201 |
# File 'lib/cocoapods/downloader/cache.rb', line 198 def path_for_spec(request, slug_opts = {}) path = root + 'Specs' + request.slug(**slug_opts) Pathname.new(path.to_path + '.podspec.json') end |
#uncached_pod(request) ⇒ Response (private)
Returns The download response for the given request
that
was not found in the download cache.
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/cocoapods/downloader/cache.rb', line 237 def uncached_pod(request) in_tmpdir do |target| result, podspecs = download(request, target) result.location = nil podspecs.each do |name, spec| destination = path_for_pod(request, :name => name, :params => result.) copy_and_clean(target, destination, spec) write_spec(spec, path_for_spec(request, :name => name, :params => result.)) if request.name == name result.location = destination end end result end end |
#write_spec(spec, path) ⇒ Void (private)
Writes the given spec
to the given path
.
314 315 316 317 318 319 |
# File 'lib/cocoapods/downloader/cache.rb', line 314 def write_spec(spec, path) path.dirname.mkpath Cache.write_lock(path) do path.open('w') { |f| f.write spec.to_pretty_json } end end |