Skip to content

Commit

Permalink
Merge pull request #21 from byohay/feature/add-existing-subproject
Browse files Browse the repository at this point in the history
apply_change_to_project: Fix adding subproject that already exist.
  • Loading branch information
ashdnazg authored Oct 26, 2021
2 parents 7cbdfdf + ffb9654 commit d10e5e1
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ RSpec/ExampleLength:
RSpec/DescribeClass:
Enabled: false

RSpec/MultipleExpectations:
Enabled: false

AllCops:
DisplayCopNames: true
TargetRubyVersion: 2.5
Expand Down
54 changes: 40 additions & 14 deletions lib/kintsugi/apply_change_to_project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,22 @@ def add_child_to_component(component, change)
def add_reference_proxy(containing_component, change)
case containing_component
when Xcodeproj::Project::PBXBuildFile
containing_component.file_ref = find_file(containing_component.project, change)
# If there are two file references that refer to the same file, one with a build file and
# the other one without, this method will prefer to take the one without the build file.
# This assumes that it's preferred to have a file reference with build file than a file
# reference without/with two build files.
filter_references_without_build_files = lambda do |reference|
reference.referrers.find do |referrer|
referrer.is_a?(Xcodeproj::Project::PBXBuildFile)
end.nil?
end
file_reference =
find_reference_proxy(containing_component.project, change["remoteRef"],
reference_filter: filter_references_without_build_files)
if file_reference.nil?
file_reference = find_reference_proxy(containing_component.project, change["remoteRef"])
end
containing_component.file_ref = file_reference
when Xcodeproj::Project::PBXGroup
reference_proxy = containing_component.project.new(Xcodeproj::Project::PBXReferenceProxy)
containing_component << reference_proxy
Expand Down Expand Up @@ -461,7 +476,14 @@ def find_containing_project_uuid(project, container_item_proxy_change)
end

def add_subproject_reference(root_object, project_reference_change)
subproject_reference = find_file(root_object.project, project_reference_change["ProjectRef"])
filter_subproject_without_project_references = lambda do |file_reference|
root_object.project_references.find do |project_reference|
project_reference.project_ref.uuid == file_reference.uuid
end.nil?
end
subproject_reference =
find_file(root_object.project, project_reference_change["ProjectRef"],
file_filter: filter_subproject_without_project_references)

attribute =
Xcodeproj::Project::PBXProject.references_by_keys_attributes
Expand Down Expand Up @@ -564,25 +586,29 @@ def add_attributes_to_component(component, change, ignore_keys: [])
end
end

def find_file(project, file_reference_change)
case file_reference_change["isa"]
when "PBXFileReference"
project.files.find do |file_reference|
next file_reference.path == file_reference_change["path"]
end
when "PBXReferenceProxy"
find_reference_proxy(project, file_reference_change["remoteRef"])
else
raise "Unsupported file reference change of type #{file_reference["isa"]}."
def find_file(project, file_reference_change, file_filter: ->(_) { true })
file_references = project.files.select do |file_reference|
file_reference.path == file_reference_change["path"] && file_filter.call(file_reference)
end
if file_references.length > 1
puts "Debug: Found more than one matching file with path " \
"'#{file_reference_change["path"]}'. Using the first one."
elsif file_references.empty?
puts "Debug: No file reference found for file with path " \
"'#{file_reference_change["path"]}'."
return
end

file_references.first
end

def find_reference_proxy(project, container_item_proxy_change)
def find_reference_proxy(project, container_item_proxy_change, reference_filter: ->(_) { true })
reference_proxies = project.root_object.project_references.map do |project_ref_and_products|
project_ref_and_products[:product_group].children.find do |product|
product.remote_ref.remote_global_id_string ==
container_item_proxy_change["remoteGlobalIDString"] &&
product.remote_ref.remote_info == container_item_proxy_change["remoteInfo"]
product.remote_ref.remote_info == container_item_proxy_change["remoteInfo"] &&
reference_filter.call(product)
end
end.compact

Expand Down
52 changes: 48 additions & 4 deletions spec/kintsugi_apply_change_to_project_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@
expect(base_project).to be_equivalent_to_project(theirs_project, ignore_keys: ["containerPortal"])
end

it "adds subproject that already exists" do
theirs_project = create_copy_of_project(base_project.path, "theirs")

subproject = add_new_subproject_to_project(theirs_project, "foo", "foo")
theirs_project.save

ours_project = create_copy_of_project(base_project.path, "ours")
add_existing_subproject_to_project(ours_project, subproject, "foo")

changes_to_apply = get_diff(theirs_project, base_project)

described_class.apply_change_to_project(ours_project, changes_to_apply)
ours_project.save

expect(ours_project.root_object.project_references[0][:project_ref].uuid)
.not_to equal(ours_project.root_object.project_references[1][:project_ref].uuid)
expect(ours_project.root_object.project_references[0][:project_ref].proxy_containers).not_to be_empty
expect(ours_project.root_object.project_references[1][:project_ref].proxy_containers).not_to be_empty
end

# Checks that the order the changes are applied in is correct.
it "adds new subproject and reference to its framework" do
theirs_project = create_copy_of_project(base_project.path, "theirs")
Expand Down Expand Up @@ -429,6 +449,30 @@
expect(base_project).to be_equivalent_to_project(theirs_project, ignore_keys: ["containerPortal"])
end

it "adds build file to a file reference that already exist" do
file_reference = base_project.main_group.new_reference("bar")
base_project.targets[0].frameworks_build_phase.add_file_reference(file_reference)

base_project.main_group.new_reference("bar")

base_project.save

theirs_project = create_copy_of_project(base_project.path, "theirs")

theirs_file_reference = theirs_project.main_group.files.find do |file|
!file.referrers.find { |referrer| referrer.is_a?(Xcodeproj::Project::PBXBuildFile) } &&
file.display_name == "bar"
end
theirs_project.targets[0].frameworks_build_phase.add_file_reference(theirs_file_reference)

changes_to_apply = get_diff(theirs_project, base_project)

described_class.apply_change_to_project(base_project, changes_to_apply)
base_project.save

expect(base_project).to be_equivalent_to_project(theirs_project)
end

it "adds file reference to build file" do
file_reference = base_project.main_group.new_reference("bar")

Expand Down Expand Up @@ -801,7 +845,7 @@
expect(ours_project).to be_equivalent_to_project(theirs_project)
end

it "identifies subproject added in separate times" do
it "identifies subproject added at separate times when adding a product to the subproject" do
framework_filename = "baz"

subproject = new_subproject("subproj", framework_filename)
Expand Down Expand Up @@ -882,10 +926,10 @@ def add_existing_subproject_to_project(project, subproject, subproject_product_n
file_reference.path == subproject_product_name
end.remove_from_project

project.root_object.project_references[0][:product_group] =
project.root_object.project_references[-1][:product_group] =
project.new(Xcodeproj::Project::PBXGroup)
project.root_object.project_references[0][:product_group].name = "Products"
project.root_object.project_references[0][:product_group] <<
project.root_object.project_references[-1][:product_group].name = "Products"
project.root_object.project_references[-1][:product_group] <<
create_reference_proxy_from_product_reference(project, subproject_reference,
subproject.products_group.files[0])
end
Expand Down

0 comments on commit d10e5e1

Please sign in to comment.