Class: Pod::Project

Inherits:
Xcodeproj::Project
  • Object
show all
Defined in:
lib/cocoapods/project.rb,
lib/cocoapods/native_target_extension.rb

Overview

The Pods project.

Model class which provides helpers for working with the Pods project through the installation process.

Legacy Xcode build root collapse

LEGACY_BUILD_ROOT =

-------------------------------------------------------------------------#

'${SRCROOT}/../build'

Pod Groups collapse

SPEC_SUBGROUPS =

Returns The names of the specification subgroups by key.

Returns:

  • (Hash)

    The names of the specification subgroups by key.

{
  :resources  => 'Resources',
  :frameworks => 'Frameworks',
  :developer  => 'Pod',
}

Private helpers collapse

Instance Attribute Summary collapse

Legacy Xcode build root collapse

Pod Groups collapse

File references collapse

Private helpers collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, skip_initialization = false, object_version = Xcodeproj::Constants::DEFAULT_OBJECT_VERSION, pod_target_subproject: false) ⇒ Project

Initialize a new instance

Parameters:

  • path (Pathname, String)

    @see Xcodeproj::Project#path

  • skip_initialization (Boolean) (defaults to: false)

    Whether the project should be initialized from scratch.

  • object_version (Int) (defaults to: Xcodeproj::Constants::DEFAULT_OBJECT_VERSION)

    Object version to use for serialization, defaults to Xcode 3.2 compatible.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/cocoapods/project.rb', line 45

def initialize(path, skip_initialization = false,
                object_version = Xcodeproj::Constants::DEFAULT_OBJECT_VERSION, pod_target_subproject: false)
  @uuid_prefix = Digest('SHA256').hexdigest(File.basename(path)).upcase
  super(path, skip_initialization, object_version)
  @support_files_group = new_group('Targets Support Files')
  @refs_by_absolute_path = {}
  @variant_groups_by_path_and_name = {}
  @pods = new_group('Pods')
  @development_pods = new_group('Development Pods')
  @dependencies_group = new_group('Dependencies')
  @pod_target_subproject = pod_target_subproject
  @project_name = Pathname(path).basename('.*').to_s
  self.symroot = LEGACY_BUILD_ROOT
end

Instance Attribute Details

#dependencies_groupPBXGroup (readonly)

Used by #generate_multiple_pod_projects installation option.

Returns:

  • (PBXGroup)

    The group for dependencies.



27
28
29
# File 'lib/cocoapods/project.rb', line 27

def dependencies_group
  @dependencies_group
end

#development_podsPBXGroup (readonly)

Returns The group for Development Pods.

Returns:

  • (PBXGroup)

    The group for Development Pods.



22
23
24
# File 'lib/cocoapods/project.rb', line 22

def development_pods
  @development_pods
end

#pod_target_subprojectBoolean (readonly) Also known as: pod_target_subproject?

Used by generate_multiple_pod_projects installation option.

Returns:

  • (Boolean)

    Bool indicating if this project is a pod target subproject.



32
33
34
# File 'lib/cocoapods/project.rb', line 32

def pod_target_subproject
  @pod_target_subproject
end

#podsPBXGroup (readonly)

Returns The group for the Pods.

Returns:

  • (PBXGroup)

    The group for the Pods.



18
19
20
# File 'lib/cocoapods/project.rb', line 18

def pods
  @pods
end

#project_nameString (readonly)

Returns The basename of the project path without .xcodeproj extension.

Returns:

  • (String)

    The basename of the project path without .xcodeproj extension.



37
38
39
# File 'lib/cocoapods/project.rb', line 37

def project_name
  @project_name
end

#refs_by_absolute_pathHash{String => PBXFileReference} (readonly, private)

Returns The file references grouped by absolute path.

Returns:

  • (Hash{String => PBXFileReference})

    The file references grouped by absolute path.



412
413
414
# File 'lib/cocoapods/project.rb', line 412

def refs_by_absolute_path
  @refs_by_absolute_path
end

#support_files_groupPBXGroup (readonly)

Returns The group for the support files of the aggregate targets.

Returns:

  • (PBXGroup)

    The group for the support files of the aggregate targets.



14
15
16
# File 'lib/cocoapods/project.rb', line 14

def support_files_group
  @support_files_group
end

#variant_groups_by_path_and_nameHash{[Pathname, String] => PBXVariantGroup} (readonly, private)

Returns The variant groups grouped by absolute path of parent dir and name.

Returns:

  • (Hash{[Pathname, String] => PBXVariantGroup})

    The variant groups grouped by absolute path of parent dir and name.



417
418
419
# File 'lib/cocoapods/project.rb', line 417

def variant_groups_by_path_and_name
  @variant_groups_by_path_and_name
end

Class Method Details

.add_cached_dependency(sandbox, target, metadata) ⇒ void

This method returns an undefined value.

Adds a dependency on the given metadata cache.

Parameters:

  • sandbox (Sandbox)

    The sandbox used for this installation.

  • target (AbstractTarget)

    The parent target used to add a cached dependency.

  • metadata (MetadataCache)

    The metadata holding all the required metadata to construct a target as a dependency.

Raises:

  • (ArgumentError)


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/cocoapods/native_target_extension.rb', line 16

def self.add_cached_dependency(sandbox, target, )
  return if dependency_for_cached_target?(sandbox, target, )
  container_proxy = target.project.new(Xcodeproj::Project::PBXContainerItemProxy)

  subproject_reference = target.project.reference_for_path(sandbox.root + .container_project_path)
  raise ArgumentError, "add_dependency received target (#{target}) that belongs to a project that is not this project (#{self}) and is not a subproject of this project" unless subproject_reference
  container_proxy.container_portal = subproject_reference.uuid

  container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
  container_proxy.remote_global_id_string = .native_target_uuid
  container_proxy.remote_info = .target_label

  dependency = target.project.new(Xcodeproj::Project::PBXTargetDependency)
  dependency.name = .target_label
  dependency.target_proxy = container_proxy

  target.dependencies << dependency
end

.dependency_for_cached_target?(sandbox, target, cached_target) ⇒ Boolean

Checks whether this target has a dependency on the given target.

Parameters:

  • sandbox (Sandbox)

    The sandbox used for this installation.

  • target (AbstractTarget)

    The parent target used to add a cached dependency.

  • cached_target (TargetMetadata)

    the target to search for.

Returns:

  • (Boolean)


48
49
50
51
52
53
54
55
56
57
58
# File 'lib/cocoapods/native_target_extension.rb', line 48

def self.dependency_for_cached_target?(sandbox, target, cached_target)
  target.dependencies.find do |dep|
    if dep.target_proxy.remote?
      subproject_reference = target.project.reference_for_path(sandbox.root + cached_target.container_project_path)
      uuid = subproject_reference.uuid if subproject_reference
      dep.target_proxy.remote_global_id_string == cached_target.native_target_uuid && dep.target_proxy.container_portal == uuid
    else
      dep.target.uuid == cached_target.native_target_uuid
    end
  end
end

Instance Method Details

#add_build_configuration(name, type) ⇒ XCBuildConfiguration

Note:

This method extends the original Xcodeproj implementation to include a preprocessor definition named after the build setting. This is done to support the TargetEnvironmentHeader specification of Pods available only on certain build configurations.

Adds a new build configuration to the project and populates it with default settings according to the provided type.

Parameters:

  • name (String)

    The name of the build configuration.

  • type (Symbol)

    The type of the build configuration used to populate the build settings, must be :debug or :release.

Returns:

  • (XCBuildConfiguration)

    The new build configuration.



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/cocoapods/project.rb', line 374

def add_build_configuration(name, type)
  build_configuration = super
  settings = build_configuration.build_settings
  definitions = settings['GCC_PREPROCESSOR_DEFINITIONS'] || ['$(inherited)']
  defines = [defininition_for_build_configuration(name)]
  defines << 'DEBUG' if type == :debug
  defines.each do |define|
    value = "#{define}=1"
    unless definitions.include?(value)
      definitions.unshift(value)
    end
  end
  settings['GCC_PREPROCESSOR_DEFINITIONS'] = definitions

  if type == :debug
    settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = 'DEBUG'
  end

  build_configuration
end

#add_cached_pod_subproject(sandbox, metadata, development = false) ⇒ PBXFileReference

Creates a new subproject reference for the given cached metadata and configures its group location.

Parameters:

  • sandbox (Sandbox)

    The sandbox used for installation.

  • metadata (TargetMetadata)

    The project metadata to be added.

  • development (Boolean) (defaults to: false)

    Whether the project should be added to the Development Pods group. For projects where pod_target_subproject is enabled, all subprojects are added into the Dependencies group.

Returns:

  • (PBXFileReference)

    The new file reference.



165
166
167
168
# File 'lib/cocoapods/project.rb', line 165

def add_cached_pod_subproject(sandbox, , development = false)
  parent_group = group_for_subproject_reference(development)
  add_cached_subproject_reference(sandbox, , parent_group)
end

#add_cached_subproject_reference(sandbox, metadata, group) ⇒ PBXFileReference

Adds a file reference for a cached project as a child of the given group.

Parameters:

  • sandbox (Sandbox)

    The sandbox used for installation.

  • metadata (MetadataCache)

    The metadata holding the required properties to create a subproject reference.

  • group (PBXGroup)

    The group for the new subproject reference.

Returns:

  • (PBXFileReference)

    The new file reference.



308
309
310
# File 'lib/cocoapods/project.rb', line 308

def add_cached_subproject_reference(sandbox, , group)
  new_subproject_file_reference(sandbox.root + .container_project_path, group)
end

#add_file_reference(absolute_path, group, reflect_file_system_structure = false, base_path = nil) ⇒ PBXFileReference

Adds a file reference to given path as a child of the given group.

Parameters:

  • absolute_path (Array<Pathname,String>)

    The path of the file.

  • group (PBXGroup)

    The group for the new file reference.

  • reflect_file_system_structure (Boolean) (defaults to: false)

    Whether group structure should reflect the file system structure. If yes, where needed, intermediate groups are created, similar to how mkdir -p operates.

  • base_path (Pathname) (defaults to: nil)

    The base path for newly created groups when reflect_file_system_structure is true. If nil, the provided group's real_path is used.

Returns:

  • (PBXFileReference)

    The new file reference.



267
268
269
270
271
272
273
274
275
276
# File 'lib/cocoapods/project.rb', line 267

def add_file_reference(absolute_path, group, reflect_file_system_structure = false, base_path = nil)
  file_path_name = absolute_path.is_a?(Pathname) ? absolute_path : Pathname(absolute_path)
  if ref = reference_for_path(file_path_name)
    return ref
  end

  group = group_for_path_in_group(file_path_name, group, reflect_file_system_structure, base_path)
  ref = group.new_file(file_path_name.realpath)
  @refs_by_absolute_path[file_path_name.to_s] = ref
end

#add_pod_group(pod_name, path, development = false, absolute = false) ⇒ PBXGroup

Creates a new group for the Pod with the given name and configures its path.

Parameters:

  • pod_name (String)

    The name of the Pod.

  • path (#to_s)

    The path to the root of the Pod.

  • development (Boolean) (defaults to: false)

    Whether the group should be added to the Development Pods group.

  • absolute (Boolean) (defaults to: false)

    Whether the path of the group should be set as absolute.

Returns:

  • (PBXGroup)

    The new group.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/cocoapods/project.rb', line 118

def add_pod_group(pod_name, path, development = false, absolute = false)
  raise '[BUG]' if pod_group(pod_name)

  parent_group =
    if pod_target_subproject
      main_group
    else
      development ? development_pods : pods
    end
  source_tree = absolute ? :absolute : :group

  group = parent_group.new_group(pod_name, path, source_tree)
  group
end

#add_pod_subproject(project, development = false) ⇒ PBXFileReference

Creates a new subproject reference for the given project and configures its group location.

Parameters:

  • project (Project)

    The subproject to be added.

  • development (Boolean) (defaults to: false)

    Whether the project should be added to the Development Pods group. For projects where pod_target_subproject is enabled, all subprojects are added into the Dependencies group.

Returns:

  • (PBXFileReference)

    The new file reference.



145
146
147
148
# File 'lib/cocoapods/project.rb', line 145

def add_pod_subproject(project, development = false)
  parent_group = group_for_subproject_reference(development)
  add_subproject_reference(project, parent_group)
end

#add_podfile(podfile_path) ⇒ PBXFileReference

Adds a file reference to the Podfile.

Parameters:

  • podfile_path (#to_s)

    The path of the Podfile.

Returns:

  • (PBXFileReference)

    The new file reference.



336
337
338
339
340
# File 'lib/cocoapods/project.rb', line 336

def add_podfile(podfile_path)
  new_file(podfile_path, :project).tap do |podfile_ref|
    mark_ruby_file_ref(podfile_ref)
  end
end

#add_subproject_reference(project, group) ⇒ PBXFileReference

Adds a file reference for a project as a child of the given group.

Parameters:

  • project (Project)

    The project to add as a subproject reference.

  • group (PBXGroup)

    The group for the new subproject reference.

Returns:

  • (PBXFileReference)

    The new file reference.



291
292
293
# File 'lib/cocoapods/project.rb', line 291

def add_subproject_reference(project, group)
  new_subproject_file_reference(project.path, group)
end

#defininition_for_build_configuration(name) ⇒ String

Returns The preprocessor definition to set for the configuration.

Parameters:

  • name (String)

    The name of the build configuration.

Returns:

  • (String)

    The preprocessor definition to set for the configuration.



400
401
402
# File 'lib/cocoapods/project.rb', line 400

def defininition_for_build_configuration(name)
  "POD_CONFIGURATION_#{name.underscore}".gsub(/[^a-zA-Z0-9_]/, '_').upcase
end

#generate_available_uuid_list(count = 100) ⇒ Void

Note:

Overridden to generate UUIDs in a much faster way, since we don't need to check for collisions (as the Pods project is regenerated each time, and thus all UUIDs will have come from this method)

Generates a list of new UUIDs that created objects can be assigned.

Parameters:

  • count (Integer) (defaults to: 100)

    The number of UUIDs to generate

Returns:

  • (Void)


70
71
72
73
74
75
# File 'lib/cocoapods/project.rb', line 70

def generate_available_uuid_list(count = 100)
  start = @generated_uuids.size
  uniques = Array.new(count) { |i| format('%.6s%07X0', @uuid_prefix, start + i) }
  @generated_uuids += uniques
  @available_uuids += uniques
end

#group_for_path_in_group(absolute_pathname, group, reflect_file_system_structure, base_path = nil) ⇒ PBXGroup (private)

Returns the group for an absolute file path in another group. Creates subgroups to reflect the file system structure if reflect_file_system_structure is set to true. Makes a variant group if the path points to a localized file inside a *.lproj directory. To support Apple Base Internationalization, the same variant group is returned for interface files and strings files with the same name.

Parameters:

  • absolute_pathname (Pathname)

    The pathname of the file to get the group for.

  • group (PBXGroup)

    The parent group used as the base of the relative path.

  • reflect_file_system_structure (Boolean)

    Whether group structure should reflect the file system structure. If yes, where needed, intermediate groups are created, similar to how mkdir -p operates.

  • base_path (Pathname) (defaults to: nil)

    The base path for the newly created group. If nil, the provided group's real_path is used.

Returns:

  • (PBXGroup)

    The appropriate group for the filepath. Can be PBXVariantGroup, if the file is localized.



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/cocoapods/project.rb', line 444

def group_for_path_in_group(absolute_pathname, group, reflect_file_system_structure, base_path = nil)
  unless absolute_pathname.absolute?
    raise ArgumentError, "Paths must be absolute #{absolute_pathname}"
  end
  unless base_path.nil? || base_path.absolute?
    raise ArgumentError, "Paths must be absolute #{base_path}"
  end

  relative_base = base_path.nil? ? group.real_path : base_path.realdirpath
  relative_pathname = absolute_pathname.relative_path_from(relative_base)
  relative_dir = relative_pathname.dirname

  # Add subgroups for directories, but treat .lproj as a file
  if reflect_file_system_structure
    path = relative_base
    relative_dir.each_filename do |name|
      break if name.to_s.downcase.include? '.lproj'
      next if name == '.'
      # Make sure groups have the correct absolute path set, as intermittent
      # directories may not be included in the group structure
      path += name
      group = group.children.find { |c| c.display_name == name } || group.new_group(name, path)
    end
  end

  # Turn files inside .lproj directories into a variant group
  if relative_dir.basename.to_s.downcase.include? '.lproj'
    group_name = variant_group_name(absolute_pathname)
    lproj_parent_dir = absolute_pathname.dirname.dirname
    group = @variant_groups_by_path_and_name[[lproj_parent_dir, group_name]] ||=
              group.new_variant_group(group_name, lproj_parent_dir)
  end

  group
end

#group_for_spec(spec_name, subgroup_key = nil) ⇒ PBXGroup

Returns the group for the specification with the give name creating it if needed.

Parameters:

  • spec_name (String)

    The full name of the specification.

Returns:

  • (PBXGroup)

    The group.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/cocoapods/project.rb', line 207

def group_for_spec(spec_name, subgroup_key = nil)
  pod_name = Specification.root_name(spec_name)
  group = pod_group(pod_name)
  raise "[Bug] Unable to locate group for Pod named `#{pod_name}`" unless group
  if spec_name != pod_name
    subspecs_names = spec_name.gsub(pod_name + '/', '').split('/')
    subspecs_names.each do |name|
      group = group[name] || group.new_group(name)
    end
  end

  if subgroup_key
    subgroup_name = SPEC_SUBGROUPS[subgroup_key]
    raise ArgumentError, "Unrecognized subgroup key `#{subgroup_key}`" unless subgroup_name
    group = group[subgroup_name] || group.new_group(subgroup_name)
  end

  group
end

#group_for_subproject_reference(development) ⇒ Object (private)

Returns the parent group a new subproject reference should belong to.



534
535
536
537
538
539
540
# File 'lib/cocoapods/project.rb', line 534

def group_for_subproject_reference(development)
  if pod_target_subproject
    dependencies_group
  else
    development ? development_pods : pods
  end
end

#mark_ruby_file_ref(file_ref) ⇒ Object

Sets the syntax of the provided file reference to be Ruby, in the case that the file does not already have a ".rb" file extension (ex. the Podfile)

Parameters:

  • file_ref (PBXFileReference)

    The file reference to change



348
349
350
351
352
353
354
# File 'lib/cocoapods/project.rb', line 348

def mark_ruby_file_ref(file_ref)
  file_ref.xc_language_specification_identifier = 'xcode.lang.ruby'
  file_ref.explicit_file_type = 'text.script.ruby'
  file_ref.last_known_file_type = 'text'
  file_ref.tab_width = '2'
  file_ref.indent_width = '2'
end

#new_subproject_file_reference(project_path, group) ⇒ Object (private)



511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
# File 'lib/cocoapods/project.rb', line 511

def new_subproject_file_reference(project_path, group)
  if ref = reference_for_path(project_path)
    return ref
  end

  # We call into the private function `FileReferencesFactory.new_file_reference` instead of `FileReferencesFactory.new_reference`
  # because it delegates into `FileReferencesFactory.new_subproject` which has the extra behavior of opening the Project which
  # is an expensive operation for large projects.
  #
  ref = Xcodeproj::Project::FileReferencesFactory.send(:new_file_reference, group, project_path, :group)
  ref.name = Pathname(project_path).basename('.*').to_s
  ref.include_in_index = nil

  attribute = PBXProject.references_by_keys_attributes.find { |attrb| attrb.name == :project_references }
  project_reference = ObjectDictionary.new(attribute, group.project.root_object)
  project_reference[:project_ref] = ref
  root_object.project_references << project_reference
  refs_by_absolute_path[project_path.to_s] = ref
  ref
end

#pod_group(pod_name) ⇒ PBXGroup

Returns the group for the Pod with the given name.

Parameters:

  • pod_name (String)

    The name of the Pod.

Returns:

  • (PBXGroup)

    The group.



187
188
189
# File 'lib/cocoapods/project.rb', line 187

def pod_group(pod_name)
  pod_groups.find { |group| group.name == pod_name }
end

#pod_groupsArray<PBXGroup>

Returns all the group of the Pods.

Returns:

  • (Array<PBXGroup>)

    Returns all the group of the Pods.



172
173
174
175
176
177
178
# File 'lib/cocoapods/project.rb', line 172

def pod_groups
  if pod_target_subproject
    main_group.children.objects
  else
    pods.children.objects + development_pods.children.objects
  end
end

#pod_support_files_group(pod_name, dir) ⇒ PBXGroup

Returns the support files group for the Pod with the given name.

Parameters:

  • pod_name (String)

    The name of the Pod.

Returns:

  • (PBXGroup)

    The group.



234
235
236
237
238
239
240
241
# File 'lib/cocoapods/project.rb', line 234

def pod_support_files_group(pod_name, dir)
  group = pod_group(pod_name)
  support_files_group = group['Support Files']
  unless support_files_group
    support_files_group = group.new_group('Support Files', dir)
  end
  support_files_group
end

#reference_for_path(absolute_path) ⇒ PBXFileReference, Nil

Returns the file reference for the given absolute path.

Parameters:

  • absolute_path (#to_s)

    The absolute path of the file whose reference is needed.

Returns:

  • (PBXFileReference)

    The file reference.

  • (Nil)

    If no file reference could be found.



320
321
322
323
324
325
326
327
# File 'lib/cocoapods/project.rb', line 320

def reference_for_path(absolute_path)
  absolute_path = absolute_path.is_a?(Pathname) ? absolute_path : Pathname(absolute_path)
  unless absolute_path.absolute?
    raise ArgumentError, "Paths must be absolute #{absolute_path}"
  end

  refs_by_absolute_path[absolute_path.to_s] ||= refs_by_absolute_path[absolute_path.realpath.to_s]
end

#symroot=(symroot) ⇒ void

This method returns an undefined value.

Parameters:

  • symroot (String)

    The build root that is used when Xcode is configured to not use the workspace’s build root. Defaults to ${SRCROOT}/../build.



90
91
92
93
94
# File 'lib/cocoapods/project.rb', line 90

def symroot=(symroot)
  root_object.build_configuration_list.build_configurations.each do |config|
    config.build_settings['SYMROOT'] = symroot
  end
end

#variant_group_name(path) ⇒ String (private)

Returns the name to be used for a the variant group for a file at a given path. The path must be localized (within an *.lproj directory).

Parameters:

  • path (Pathname)

    The localized path to get a variant group name for.

Returns:

  • (String)

    The variant group name.



487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/cocoapods/project.rb', line 487

def variant_group_name(path)
  unless path.to_s.downcase.include?('.lproj/')
    raise ArgumentError, 'Only localized resources can be added to variant groups.'
  end

  # When using Base Internationalization for XIBs and Storyboards a strings
  # file is generated with the same name as the XIB/Storyboard in each .lproj
  # directory:
  #   Base.lproj/MyViewController.xib
  #   fr.lproj/MyViewController.strings
  #
  # In this scenario we want the variant group to be the same as the XIB or Storyboard.
  #
  # Base Internationalization: https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/InternationalizingYourUserInterface/InternationalizingYourUserInterface.html
  if path.extname.downcase == '.strings'
    %w(.xib .storyboard).each do |extension|
      possible_interface_file = path.dirname.dirname + 'Base.lproj' + path.basename.sub_ext(extension)
      return possible_interface_file.basename.to_s if possible_interface_file.exist?
    end
  end

  path.basename.to_s
end