class Pod::Installer::UserProjectIntegrator

The {UserProjectIntegrator} integrates the libraries generated by TargetDefinitions of the {Podfile} with their correspondent user projects.

Constants

IGNORED_KEYS
INHERITED_FLAGS

Attributes

installation_root[R]

@return [Pathname] the path of the installation.

@todo This is only used to compute the workspace path in case that it

should be inferred by the project. If the workspace should be in
the same dir of the project, this could be removed.
podfile[R]

@return [Podfile] the podfile that should be integrated with the user

projects.
sandbox[R]

@return [Sandbox] The sandbox used for this installation.

targets[R]

@return [Array<AggregateTarget>] the targets represented in the Podfile.

targets_to_integrate[R]

@return [Array<AggregateTarget>] the targets that require integration. This will always be equal or a smaller

subset of #targets.
use_input_output_paths[R]

@return [Boolean] whether to use input/output paths for build phase scripts

use_input_output_paths?[R]

@return [Boolean] whether to use input/output paths for build phase scripts

Public Class Methods

new(podfile, sandbox, installation_root, targets, targets_to_integrate, use_input_output_paths: true) click to toggle source

Initialize a new instance

@param [Podfile] podfile @see podfile @param [Sandbox] sandbox @see sandbox @param [Pathname] installation_root @see installation_root @param [Array<AggregateTarget>] targets @see targets @param [Array<AggregateTarget>] targets_to_integrate @see targets_to_integrate @param [Boolean] use_input_output_paths @see use_input_output_paths

# File lib/cocoapods/installer/user_project_integrator.rb, line 56
def initialize(podfile, sandbox, installation_root, targets, targets_to_integrate, use_input_output_paths: true)
  @podfile = podfile
  @sandbox = sandbox
  @installation_root = installation_root
  @targets = targets
  @targets_to_integrate = targets_to_integrate
  @use_input_output_paths = use_input_output_paths
end

Public Instance Methods

integrate!() click to toggle source

Integrates the user projects associated with the {TargetDefinitions} with the Pods project and its products.

@return [void]

# File lib/cocoapods/installer/user_project_integrator.rb, line 70
def integrate!
  create_workspace
  deintegrated_projects = deintegrate_removed_targets
  integrate_user_targets
  warn_about_xcconfig_overrides
  projects_to_save = (user_projects_to_integrate + deintegrated_projects).uniq
  save_projects(projects_to_save)
end

Private Instance Methods

create_workspace() click to toggle source

Creates and saved the workspace containing the Pods project and the user projects, if needed.

@note If the workspace already contains the projects it is not saved

to avoid Xcode from displaying the revert dialog: `Do you want to
keep the Xcode version or revert to the version on disk?`

@return [void]

# File lib/cocoapods/installer/user_project_integrator.rb, line 94
def create_workspace
  all_projects = user_project_paths.sort.push(sandbox.project_path).uniq
  file_references = all_projects.map do |path|
    relative_path = path.relative_path_from(workspace_path.dirname).to_s
    Xcodeproj::Workspace::FileReference.new(relative_path, 'group')
  end

  if workspace_path.exist?
    workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
    new_file_references = file_references - workspace.file_references
    unless new_file_references.empty?
      new_file_references.each { |fr| workspace << fr }
      workspace.save_as(workspace_path)
    end

  else
    UI.notice "Please close any current Xcode sessions and use `#{workspace_path.basename}` for this project from now on."
    workspace = Xcodeproj::Workspace.new(*file_references)
    workspace.save_as(workspace_path)
  end
end
deintegrate_removed_targets() click to toggle source

Deintegrates the targets of the user projects that are no longer part of the installation.

@return [Array<Xcodeproj::PBXProject>] The list of projects that were deintegrated.

# File lib/cocoapods/installer/user_project_integrator.rb, line 120
def deintegrate_removed_targets
  Config.instance.with_changes(:silent => true) do
    deintegrator = Deintegrator.new
    all_project_targets = user_projects.flat_map(&:native_targets).uniq
    all_native_targets = targets.flat_map(&:user_targets).uniq
    targets_to_deintegrate = all_project_targets - all_native_targets
    targets_to_deintegrate.each do |target|
      deintegrator.deintegrate_target(target)
    end
    return targets_to_deintegrate.map(&:project).select(&:dirty?).uniq
  end
end
integrate_user_targets() click to toggle source

Integrates the targets of the user projects with the libraries generated from the {Podfile}.

@note {TargetDefinition} without dependencies are skipped prevent

creating empty libraries for targets definitions which are only
wrappers for others.

@return [void]

# File lib/cocoapods/installer/user_project_integrator.rb, line 142
def integrate_user_targets
  target_integrators = targets_to_integrate.sort_by(&:name).map do |target|
    TargetIntegrator.new(target, :use_input_output_paths => use_input_output_paths?)
  end
  target_integrators.each(&:integrate!)
end
print_override_warning(aggregate_target, user_target, config, key) click to toggle source

Prints a warning informing the user that a build configuration of the integrated target is overriding the CocoaPods build settings.

@param [Target::AggregateTarget] aggregate_target

The umbrella target.

@param [Xcodeproj::PBXNativeTarget] user_target

The native target.

@param [Xcodeproj::XCBuildConfiguration] config

The build configuration.

@param [String] key

The key of the overridden build setting.
save_projects(projects) click to toggle source

Save all user projects.

@param [Array<Xcodeproj::PBXProject>] projects The projects to save.

@return [void]

# File lib/cocoapods/installer/user_project_integrator.rb, line 155
def save_projects(projects)
  projects.each do |project|
    if project.dirty?
      project.save
    else
      # There is a bug in Xcode where the process of deleting and
      # re-creating the xcconfig files used in the build
      # configuration cause building the user project to fail until
      # Xcode is relaunched.
      #
      # Touching/saving the project causes Xcode to reload these.
      #
      # https://github.com/CocoaPods/CocoaPods/issues/2665
      FileUtils.touch(project.path + 'project.pbxproj')
    end
  end
end
user_project_paths() click to toggle source

@return [Array<Pathname>] the paths of all the user projects from all targets regardless of whether they are

integrated or not.

@note Empty target definitions are ignored.

# File lib/cocoapods/installer/user_project_integrator.rb, line 246
def user_project_paths
  targets.map(&:user_project_path).compact.uniq
end
user_projects() click to toggle source

@return [Array<Xcodeproj::Project>] the projects of all the targets regardless of whether they are integrated

or not.

@note Empty target definitions are ignored.

# File lib/cocoapods/installer/user_project_integrator.rb, line 237
def user_projects
  targets.map(&:user_project).compact.uniq
end
user_projects_to_integrate() click to toggle source

@return [Array<Xcodeproj::Project>] the projects of all the targets that require integration.

@note Empty target definitions are ignored.

# File lib/cocoapods/installer/user_project_integrator.rb, line 228
def user_projects_to_integrate
  targets_to_integrate.map(&:user_project).compact.uniq
end
warn_about_xcconfig_overrides() click to toggle source

Checks whether the settings of the CocoaPods generated xcconfig are overridden by the build configuration of a target and prints a warning to inform the user if needed.

# File lib/cocoapods/installer/user_project_integrator.rb, line 180
def warn_about_xcconfig_overrides
  targets_to_integrate.each do |aggregate_target|
    aggregate_target.user_targets.each do |user_target|
      user_target.build_configurations.each do |config|
        xcconfig = aggregate_target.xcconfigs[config.name]
        if xcconfig
          (xcconfig.to_hash.keys - IGNORED_KEYS).each do |key|
            target_values = config.build_settings[key]
            if target_values &&
                !INHERITED_FLAGS.any? { |flag| target_values.include?(flag) }
              print_override_warning(aggregate_target, user_target, config, key)
            end
          end
        end
      end
    end
  end
end
workspace_path() click to toggle source

@return [Pathname] the path where the workspace containing the Pods

project and the user projects should be saved.
# File lib/cocoapods/installer/user_project_integrator.rb, line 207
def workspace_path
  if podfile.workspace_path
    declared_path = podfile.workspace_path
    path_with_ext = File.extname(declared_path) == '.xcworkspace' ? declared_path : "#{declared_path}.xcworkspace"
    podfile_dir   = File.dirname(podfile.defined_in_file || '')
    absolute_path = File.expand_path(path_with_ext, podfile_dir)
    Pathname.new(absolute_path)
  elsif user_project_paths.count == 1
    project = user_project_paths.first.basename('.xcodeproj')
    installation_root + "#{project}.xcworkspace"
  else
    raise Informative, 'Could not automatically select an Xcode ' \
      "workspace. Specify one in your Podfile like so:\n\n"       \
      "    workspace 'path/to/Workspace.xcworkspace'\n"
  end
end