remove_spm_dependencies.rb 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #!/usr/bin/env ruby
  2. # Copyright 2025 Google LLC
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may
  7. # obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. require 'xcodeproj'
  17. require 'set'
  18. # This script removes all Swift Package Manager dependencies from an Xcode project.
  19. # It's designed to be used in CI to prepare a project for framework-based testing.
  20. # --- Argument Parsing ---
  21. unless ARGV.length == 1
  22. puts "Usage: #{$0} <path_to.xcodeproj>"
  23. exit 1
  24. end
  25. project_path = ARGV[0]
  26. # --- Main Logic ---
  27. begin
  28. project = Xcodeproj::Project.open(project_path)
  29. rescue => e
  30. puts "Error opening project at #{project_path}: #{e.message}"
  31. exit 1
  32. end
  33. puts "Opened project: #{project.path}"
  34. # --- Step 1: Find all SPM product dependencies ---
  35. package_product_dependencies = project.objects.select do |obj|
  36. obj.is_a?(Xcodeproj::Project::Object::XCSwiftPackageProductDependency)
  37. end
  38. if package_product_dependencies.empty?
  39. puts "No SPM product dependencies found to remove."
  40. else
  41. puts "Found #{package_product_dependencies.count} SPM product dependencies. Removing all references..."
  42. package_product_dep_uuids = package_product_dependencies.map(&:uuid).to_set
  43. # --- Step 2: Find all BuildFile objects that reference these SPM products ---
  44. build_files_to_remove = project.objects.select do |obj|
  45. obj.is_a?(Xcodeproj::Project::Object::PBXBuildFile) &&
  46. obj.product_ref &&
  47. package_product_dep_uuids.include?(obj.product_ref.uuid)
  48. end
  49. build_file_uuids_to_remove = build_files_to_remove.map(&:uuid).to_set
  50. # --- Step 3: Remove references from all targets ---
  51. project.targets.each do |target|
  52. puts "Cleaning target '#{target.name}'..."
  53. # Remove from target dependencies list
  54. removed_deps = target.dependencies.reject! do |dep|
  55. package_product_dep_uuids.include?(dep.uuid)
  56. end
  57. if removed_deps
  58. puts " - Removed #{removed_deps.count} SPM target dependencies."
  59. end
  60. # Remove from build phases (e.g., "Link Binary With Libraries")
  61. target.build_phases.each do |phase|
  62. next unless phase.respond_to?(:files)
  63. original_file_count = phase.files.count
  64. phase.files.reject! do |build_file|
  65. build_file_uuids_to_remove.include?(build_file.uuid)
  66. end
  67. removed_count = original_file_count - phase.files.count
  68. if removed_count > 0
  69. puts " - Removed #{removed_count} SPM build file references from '#{phase.display_name}'."
  70. end
  71. end
  72. end
  73. # --- Step 4: Delete the now-orphaned BuildFile and dependency objects ---
  74. puts "Deleting #{build_files_to_remove.count} SPM BuildFile object(s)..."
  75. build_files_to_remove.each(&:remove_from_project)
  76. puts "Deleting #{package_product_dependencies.count} SPM product dependency object(s)..."
  77. package_product_dependencies.each(&:remove_from_project)
  78. end
  79. # --- Step 5: Remove package references from the project root ---
  80. unless project.root_object.package_references.empty?
  81. puts "Removing #{project.root_object.package_references.count} package reference(s)..."
  82. project.root_object.package_references.clear
  83. puts "All package references removed from the project."
  84. else
  85. puts "No package references found in the project."
  86. end
  87. # --- Step 6: Save the modified project ---
  88. begin
  89. project.save
  90. puts "Project saved successfully."
  91. rescue => e
  92. puts "Error saving project: #{e.message}"
  93. exit 1
  94. end