Class: Pod::Installer::UserProjectIntegrator

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods/installer/user_project_integrator.rb,
lib/cocoapods/installer/user_project_integrator/target_integrator.rb,
lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb

Overview

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

Defined Under Namespace

Classes: TargetIntegrator

Integration steps collapse

IGNORED_KEYS =
%w(CODE_SIGN_IDENTITY).freeze
INHERITED_FLAGS =
%w($(inherited) ${inherited}).freeze

Instance Attribute Summary collapse

Integration steps collapse

Private Helpers collapse

Instance Method Summary collapse

Constructor Details

#initialize(podfile, sandbox, installation_root, targets, targets_to_integrate, use_input_output_paths: true) ⇒ UserProjectIntegrator

Initialize a new instance

Parameters:

  • podfile (Podfile)

    @see #podfile

  • sandbox (Sandbox)

    @see #sandbox

  • installation_root (Pathname)

    @see #installation_root

  • targets (Array<AggregateTarget>)

    @see #targets

  • targets_to_integrate (Array<AggregateTarget>)

    @see #targets_to_integrate

  • use_input_output_paths (Boolean) (defaults to: true)

    @see #use_input_output_paths



56
57
58
59
60
61
62
63
# 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

Instance Attribute Details

#installation_rootPathname (readonly)

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.

Returns the path of the installation.

Returns:

  • (Pathname)

    the path of the installation.



31
32
33
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 31

def installation_root
  @installation_root
end

#podfilePodfile (readonly)

Returns the podfile that should be integrated with the user projects.

Returns:

  • (Podfile)

    the podfile that should be integrated with the user projects.



19
20
21
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 19

def podfile
  @podfile
end

#sandboxSandbox (readonly)

Returns The sandbox used for this installation.

Returns:

  • (Sandbox)

    The sandbox used for this installation.



23
24
25
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 23

def sandbox
  @sandbox
end

#targetsArray<AggregateTarget> (readonly)

Returns the targets represented in the Podfile.

Returns:



35
36
37
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 35

def targets
  @targets
end

#targets_to_integrateArray<AggregateTarget> (readonly)

Returns the targets that require integration. This will always be equal or a smaller subset of #targets.

Returns:

  • (Array<AggregateTarget>)

    the targets that require integration. This will always be equal or a smaller subset of #targets.



40
41
42
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 40

def targets_to_integrate
  @targets_to_integrate
end

#use_input_output_pathsBoolean (readonly) Also known as: use_input_output_paths?

Returns whether to use input/output paths for build phase scripts.

Returns:

  • (Boolean)

    whether to use input/output paths for build phase scripts



44
45
46
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 44

def use_input_output_paths
  @use_input_output_paths
end

Instance Method Details

#create_workspacevoid (private)

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?

This method returns an undefined value.

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



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 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_targetsArray<Xcodeproj::PBXProject> (private)

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

Returns:

  • (Array<Xcodeproj::PBXProject>)

    The list of projects that were deintegrated.



120
121
122
123
124
125
126
127
128
129
130
131
# 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!void

This method returns an undefined value.

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



70
71
72
73
74
75
76
77
# 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

#integrate_user_targetsvoid (private)

Note:

TargetDefinition without dependencies are skipped prevent creating empty libraries for targets definitions which are only wrappers for others.

This method returns an undefined value.

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



142
143
144
145
146
147
# 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

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

Parameters:

  • aggregate_target (Target::AggregateTarget)

    The umbrella target.

  • user_target (Xcodeproj::PBXNativeTarget)

    The native target.

  • config (Xcodeproj::XCBuildConfiguration)

    The build configuration.

  • key (String)

    The key of the overridden build setting.



265
266
267
268
269
270
271
272
273
274
275
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 265

def print_override_warning(aggregate_target, user_target, config, key)
  actions = [
    'Use the `$(inherited)` flag, or',
    'Remove the build settings from the target.',
  ]
  message = "The `#{user_target.name} [#{config.name}]` " \
    "target overrides the `#{key}` build setting defined in " \
    "`#{aggregate_target.xcconfig_relative_path(config.name)}'. " \
    'This can lead to problems with the CocoaPods installation'
  UI.warn(message, actions)
end

#save_projects(projects) ⇒ void (private)

This method returns an undefined value.

Save all user projects.

Parameters:

  • projects (Array<Xcodeproj::PBXProject>)

    The projects to save.



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# 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_pathsArray<Pathname> (private)

Note:

Empty target definitions are ignored.

Returns the paths of all the user projects from all targets regardless of whether they are integrated or not.

Returns:

  • (Array<Pathname>)

    the paths of all the user projects from all targets regardless of whether they are integrated or not.



246
247
248
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 246

def user_project_paths
  targets.map(&:user_project_path).compact.uniq
end

#user_projectsArray<Xcodeproj::Project> (private)

Note:

Empty target definitions are ignored.

Returns the projects of all the targets regardless of whether they are integrated or not.

Returns:

  • (Array<Xcodeproj::Project>)

    the projects of all the targets regardless of whether they are integrated or not.



237
238
239
# File 'lib/cocoapods/installer/user_project_integrator.rb', line 237

def user_projects
  targets.map(&:user_project).compact.uniq
end

#user_projects_to_integrateArray<Xcodeproj::Project> (private)

Note:

Empty target definitions are ignored.

Returns the projects of all the targets that require integration.

Returns:

  • (Array<Xcodeproj::Project>)

    the projects of all the targets that require integration.



228
229
230
# 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_overridesObject (private)

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.



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# 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_pathPathname (private)

Returns the path where the workspace containing the Pods project and the user projects should be saved.

Returns:

  • (Pathname)

    the path where the workspace containing the Pods project and the user projects should be saved.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# 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