module Pod class Command class Deintegrate < Command self.summary = 'Deintegrate CocoaPods from your project.' self.description = <<-DESC Deintegrate your project from CocoaPods. Removing all traces of CocoaPods from your Xcode project. If no xcodeproj is specified, then a search for an Xcode project will be made in the current directory. DESC self.arguments = [ CLAide::Argument.new('XCODE_PROJECT', false) ] def initialize(argv) path = argv.shift_argument() @project_path = Pathname.new(path) if path super end def validate! super unless @project_path xcodeprojs = Pathname.glob('*.xcodeproj') @project_path = xcodeprojs.first if xcodeprojs.size == 1 end help! 'A valid Xcode project file is required.' unless @project_path help! "#{@project_path} does not exist." unless @project_path.exist? help! "#{@project_path} is not a valid Xcode project." unless @project_path.directory? && (@project_path + 'project.pbxproj').exist? end def run # We don't traverse a Podfile and try to de-intergrate each target. # Instead, we're just deintegrating anything CP could have done to a # project. This is so that it will clean stale, and modified projects. UI.puts("Deintegrating #{@project_path.basename}".green) project = Xcodeproj::Project.open(@project_path) deintegrate_project(project) project.save() pods_directory = config.sandbox.root if pods_directory.exist? UI.puts("Removing `#{pods_directory.relative_path_from(Pathname.new(Dir.pwd))}` directory.") pods_directory.rmtree() end UI.puts('') UI.puts('Project has been deintegrated. No traces of CocoaPods left in project.'.green) UI.puts('Note: The workspace referencing the Pods project still remains.') end private def native_targets(project) project.targets.reject do |target| target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget end end def deintegrate_project(project) native_targets(project).each do |target| UI.section("Deintegrating target #{target.name}") do deintegrate_target(target) end delete_pods_file_references(project) end end def delete_pods_file_references(project) # The following implementation goes for files and empty groups so it # should catch cases where a user has changed the structure manually. groups = project.main_group.recursive_children_groups groups << project.main_group pod_files = groups.map do |group| group.files.select do |obj| obj.name =~ /^Pods.*\.xcconfig$/i or obj.path =~ /^(libPods.*\.a)|(Pods_.*\.framework)$/i end end.flatten unless pod_files.empty? UI.puts('Deleting Pod file references from project') pod_files.each do |file_reference| UI.puts("- #{file_reference.name || file_reference.path}") file_reference.remove_from_project end end # Delete empty `Pods` group if exists delete_empty_group(project, 'Pods') delete_empty_group(project, 'Frameworks') end def deintegrate_target(target) deintegrate_shell_script_phase(target, 'Copy Pods Resources') deintegrate_shell_script_phase(target, 'Check Pods Manifest.lock') deintegrate_shell_script_phase(target, 'Embed Pods Frameworks') deintegrate_pods_libraries(target) end def deintegrate_pods_libraries(target) frameworks_build_phase = target.frameworks_build_phase pods_build_files = frameworks_build_phase.files.select do |build_file| build_file.display_name =~ /^(libPods.*\.a)|(Pods_.*\.framework)$/i end unless pods_build_files.empty? UI.puts('Removing Pod libraries from build phase:') pods_build_files.each do |build_file| UI.puts("- #{build_file.display_name}") frameworks_build_phase.remove_build_file(build_file) end end end def deintegrate_shell_script_phase(target, phase_name) phases = target.shell_script_build_phases.select do |phase| phase.name == phase_name end unless phases.empty? phases.each do |phase| target.build_phases.delete(phase) end UI.puts("Deleted #{phases.count} '#{phase_name}' build phases.") end end def delete_empty_group(project, group_name) groups = project.main_group.recursive_children_groups.select do |group| group.name == group_name && group.children.empty? end unless groups.empty? groups.each(&:remove_from_project) UI.puts "Deleted #{groups.count} empty `#{group_name}` groups from project." end end end end end