Class: Pod::Lockfile

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods-core/lockfile.rb

Overview

The Lockfile stores information about the pods that were installed by CocoaPods.

It is used in combination with the Podfile to resolve the exact version of the Pods that should be installed (i.e. to prevent ‘pod install` from upgrading dependencies).

Moreover it is used as a manifest of an installation to detect which Pods need to be installed or removed.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash) ⇒ Lockfile

Returns a new instance of Lockfile.

Parameters:

  • hash (Hash)

    a hash representation of the Lockfile.



25
26
27
# File 'lib/cocoapods-core/lockfile.rb', line 25

def initialize(hash)
  @internal_data = hash
end

Instance Attribute Details

#defined_in_fileString

Returns the file where the Lockfile is serialized.

Returns:

  • (String)

    the file where the Lockfile is serialized.



54
55
56
# File 'lib/cocoapods-core/lockfile.rb', line 54

def defined_in_file
  @defined_in_file
end

#internal_dataString (readonly)

Returns the hash used to initialize the Lockfile.

Returns:

  • (String)

    the hash used to initialize the Lockfile.



20
21
22
# File 'lib/cocoapods-core/lockfile.rb', line 20

def internal_data
  @internal_data
end

Class Method Details

.from_file(path) ⇒ Lockfile

Note:

This method returns nil if the given path doesn’t exists.

Loads a lockfile form the given path.

Parameters:

  • path (Pathname)

    the path where the lockfile is serialized.

Returns:

Raises:

  • If there is a syntax error loading the YAML data.



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/cocoapods-core/lockfile.rb', line 40

def self.from_file(path)
  return nil unless path.exist?
  require 'yaml'
  hash = YAML.load(File.open(path))
  unless hash && hash.is_a?(Hash)
    raise Informative, "Invalid Lockfile in `#{path}`"
  end
  lockfile = Lockfile.new(hash)
  lockfile.defined_in_file = path
  lockfile
end

.generate(podfile, specs) ⇒ Lockfile

Generates a hash representation of the Lockfile generated from a given Podfile and the list of resolved Specifications. This representation is suitable for serialization.

Parameters:

  • podfile (Podfile)

    the podfile that should be used to generate the lockfile.

  • specs (Array<Specification>)

    an array containing the podspec that were generated by resolving the given podfile.

Returns:



329
330
331
332
333
334
335
336
337
338
# File 'lib/cocoapods-core/lockfile.rb', line 329

def generate(podfile, specs)
  hash = {
    'PODS'             => generate_pods_data(specs),
    'DEPENDENCIES'     => generate_dependencies_data(podfile),
    'EXTERNAL SOURCES' => generate_external_sources_data(podfile),
    'SPEC CHECKSUMS'   => generate_checksums(specs),
    'COCOAPODS'        => CORE_VERSION
  }
  Lockfile.new(hash)
end

Instance Method Details

#==(other) ⇒ Bool

Returns Whether the Podfiles are equal.

Returns:

  • (Bool)

    Whether the Podfiles are equal.



58
59
60
# File 'lib/cocoapods-core/lockfile.rb', line 58

def ==(other)
  other && self.to_hash == other.to_hash
end

#checksum(name) ⇒ String, Nil

Returns the checksum for the given Pod.

Parameters:

  • The (name)

    name of the Pod (root name of the specification).

Returns:

  • (String)

    The checksum of the specification for the given Pod.

  • (Nil)

    If there is no checksum stored for the given name.



104
105
106
# File 'lib/cocoapods-core/lockfile.rb', line 104

def checksum(name)
  checksum_data[name]
end

#dependenciesArray<Dependency>

Note:

It includes only the dependencies explicitly required in the podfile and not those triggered by the Resolver.

Returns the dependencies of the Podfile used for the last installation.

Returns:

  • (Array<Dependency>)

    the dependencies of the Podfile used for the last installation.



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/cocoapods-core/lockfile.rb', line 113

def dependencies
  unless @dependencies
    data = internal_data['DEPENDENCIES'] || []
    @dependencies = data.map do |string|
      dep = Dependency.from_string(string)
      dep.external_source = external_sources_data[dep.root_name]
      dep
    end
  end
  @dependencies
end

#dependency_to_lock_pod_named(name) ⇒ Dependency

Note:

The generated dependencies used are by the Resolver from upgrading a Pod during an installation.

Generates a dependency that requires the exact version of the Pod with the given name.

Parameters:

  • name (String)

    the name of the Pod

Returns:

Raises:

  • If there is no version stored for the given name.



138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/cocoapods-core/lockfile.rb', line 138

def dependency_to_lock_pod_named(name)
  dep = dependencies.find { |d| d.name == name || d.root_name == name }
  version = version(name)

  unless dep && version
    raise StandardError, "Attempt to lock the `#{name}` Pod without an known dependency."
  end

  locked_dependency = dep.dup
  locked_dependency.specific_version = version
  locked_dependency
end

#detect_changes_with_podfile(podfile) ⇒ Hash{Symbol=>Array[Strings]}

TODO:

Why do we look for compatibility instead of just comparing if the two dependencies are equal?

Analyzes the Pod::Lockfile and detects any changes applied to the Podfile since the last installation.

For each Pod, it detects one state among the following:

  • added: Pods that weren’t present in the Podfile.

  • changed: Pods that were present in the Podfile but changed:

    • Pods whose version is not compatible anymore with Podfile,

    • Pods that changed their head or external options.

  • removed: Pods that were removed form the Podfile.

  • unchanged: Pods that are still compatible with Podfile.

Parameters:

  • podfile (Podfile)

    the podfile that should be analyzed.

Returns:

  • (Hash{Symbol=>Array[Strings]})

    a hash where pods are grouped by the state in which they are.



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/cocoapods-core/lockfile.rb', line 225

def detect_changes_with_podfile(podfile)
  result = {}
  [ :added, :changed, :removed, :unchanged ].each { |k| result[k] = [] }

  installed_deps = dependencies.map { |d| dependency_to_lock_pod_named(d.name) }
  all_dep_names  = (dependencies + podfile.dependencies).map(&:name).uniq
  all_dep_names.each do |name|
    installed_dep = installed_deps.find { |d| d.name == name }
    podfile_dep   = podfile.dependencies.find { |d| d.name == name }

    if installed_dep.nil?  then key = :added
    elsif podfile_dep.nil? then key = :removed
    elsif podfile_dep.compatible?(installed_dep ) then key = :unchanged
    else key = :changed
    end
    result[key] << name
  end
  result
end

#inspectString

Returns a string representation suitable for debugging.

Returns:

  • (String)

    a string representation suitable for debugging.



64
65
66
# File 'lib/cocoapods-core/lockfile.rb', line 64

def inspect
  "#<#{self.class}>"
end

#pod_namesArray<String>

Returns the names of the installed Pods.

Returns:

  • (Array<String>)

    the names of the installed Pods.



76
77
78
79
# File 'lib/cocoapods-core/lockfile.rb', line 76

def pod_names
  generate_pod_names_and_versions unless @pod_names
  @pod_names
end

#to_hashHash{String=>Array,Hash,String}

Returns a hash representation of the Lockfile.

Examples:

Output


{
  'PODS'             => [ { BananaLib (1.0) => [monkey (< 1.0.9, ~> 1.0.1)] },
                          "JSONKit (1.4)",
                          "monkey (1.0.8)"]
  'DEPENDENCIES'     => [ "BananaLib (~> 1.0)",
                          "JSONKit (from `path/JSONKit.podspec`)" ],
  'EXTERNAL SOURCES' => { "JSONKit" => { :podspec => path/JSONKit.podspec } },
  'SPEC CHECKSUMS'   => { "BananaLib" => "439d9f683377ecf4a27de43e8cf3bce6be4df97b",
                          "JSONKit", "92ae5f71b77c8dec0cd8d0744adab79d38560949" },
  'COCOAPODS'        => "0.17.0"
}

Returns:

  • (Hash{String=>Array,Hash,String})

    a hash representation of the Lockfile.



282
283
284
285
286
287
288
# File 'lib/cocoapods-core/lockfile.rb', line 282

def to_hash
  hash = {}
  internal_data.each do |key, value|
    hash[key] = value unless value.empty?
  end
  hash
end

#to_yamlString

Note:

Empty root keys are discarded.

Note:

The YAML string is prettified.

Returns the YAML representation of the Lockfile, used for serialization.

Returns:

  • (String)

    the YAML representation of the Lockfile, used for serialization.



297
298
299
300
301
302
303
304
305
306
# File 'lib/cocoapods-core/lockfile.rb', line 297

def to_yaml
  keys_hint = [
    "PODS",
    "DEPENDENCIES",
    "EXTERNAL SOURCES",
    "SPEC CHECKSUMS",
    "COCOAPODS"
  ]
  YAMLConverter.convert_hash(to_hash, keys_hint, "\n\n")
end

#version(pod_name) ⇒ Version, Nil

Returns the version of the given Pod.

Parameters:

  • The (name)

    name of the Pod (root name of the specification).

Returns:

  • (Version)

    The version of the pod.

  • (Nil)

    If there is no version stored for the given name.



89
90
91
92
93
94
# File 'lib/cocoapods-core/lockfile.rb', line 89

def version(pod_name)
  version = pod_versions[pod_name]
  return version if version
  root_name = pod_versions.keys.find { |name| Specification.root_name(name) == pod_name }
  pod_versions[root_name]
end

#write_to_disk(path) ⇒ void

This method returns an undefined value.

Writes the Lockfile to the given path.

Parameters:

  • path (Pathname)

    the path where the lockfile should be saved.



258
259
260
261
262
# File 'lib/cocoapods-core/lockfile.rb', line 258

def write_to_disk(path)
  path.dirname.mkpath unless path.dirname.exist?
  File.open(path, 'w') {|f| f.write(to_yaml) }
  self.defined_in_file = path
end