From 55dd9f702eccda4ef6a4a8f3b9d13fb0955ded7d Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 Mar 2023 17:52:48 +0400 Subject: [PATCH 1/4] Allow mainGroup to be replaced when mutating existing PBXProject Signed-off-by: Daniel Lacasse --- .../dev/nokee/xcode/objects/PBXProject.java | 9 +-- .../xcode/project/PBXProjectBuilderTests.java | 65 +++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 subprojects/xcode-ide-kit/src/test/java/dev/nokee/xcode/project/PBXProjectBuilderTests.java diff --git a/subprojects/xcode-ide-kit/src/main/java/dev/nokee/xcode/objects/PBXProject.java b/subprojects/xcode-ide-kit/src/main/java/dev/nokee/xcode/objects/PBXProject.java index eecd1a8e4c..b632994302 100644 --- a/subprojects/xcode-ide-kit/src/main/java/dev/nokee/xcode/objects/PBXProject.java +++ b/subprojects/xcode-ide-kit/src/main/java/dev/nokee/xcode/objects/PBXProject.java @@ -30,7 +30,6 @@ import dev.nokee.xcode.project.KeyedCoders; import dev.nokee.xcode.project.KeyedObject; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -163,6 +162,7 @@ public Builder group(Consumer builderConsumer) { public Builder mainGroup(PBXGroup mainGroup) { this.mainGroup = mainGroup; this.mainGroupChildren.clear(); + builder.put(CodeablePBXProject.CodingKeys.mainGroup, mainGroup); return this; } @@ -188,13 +188,10 @@ public Builder packageReferences(Iterable it.path("Foo").child(PBXFileReference.ofGroup("Foo.h"))) // + .file(PBXFileReference.ofSourceRoot("makefile")).build().getMainGroup(); + assertThat(newMainGroup.getChildren().get(0).getPath(), optionalWithValue(equalTo("Foo"))); + assertThat(newMainGroup.getChildren().get(1), equalTo(PBXFileReference.ofSourceRoot("makefile"))); + } + } + + @Nested + class WhenNoMainGroupSpecified { + PBXProject subject = new PBXProject.Builder().build(); + + @Test + void createsEmptyMainGroup() { + assertThat(subject.getMainGroup().getName(), optionalWithValue(equalTo("mainGroup"))); + assertThat(subject.getMainGroup().getChildren(), emptyIterable()); + assertThat(subject.getMainGroup().getSourceTree(), equalTo(PBXSourceTree.GROUP)); + } + } +} From 1bc6fd8cc736020408db8eb13c1696670d42eb94 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 Mar 2023 18:04:50 +0400 Subject: [PATCH 2/4] Extract derived data directory assembling to seperated task Signed-off-by: Daniel Lacasse --- .../ConfigurationSelectionFunctionalTest.java | 4 +- ...ojectTargetDependenciesFunctionalTest.java | 4 +- .../xcode/SdkSelectionFunctionalTest.java | 11 +- ...ataAssemblingRunnableIntegrationTests.java | 14 +-- .../AssembleDerivedDataDirectoryTask.java | 104 ++++++++++++++++++ .../plugins/XcodeBuildAdapterPlugin.java | 14 ++- .../internal/plugins/XcodeTargetExecTask.java | 14 --- 7 files changed, 125 insertions(+), 40 deletions(-) create mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/AssembleDerivedDataDirectoryTask.java diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/ConfigurationSelectionFunctionalTest.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/ConfigurationSelectionFunctionalTest.java index 0815c076d5..1efa2b7961 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/ConfigurationSelectionFunctionalTest.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/ConfigurationSelectionFunctionalTest.java @@ -49,7 +49,7 @@ void beforeEachCreateProject() throws IOException { @Test void executesForDefaultConfigurationByDefault(GradleRunner runner) { runner.withTasks("DualMacOsIosFramework").build(); - assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/Release-macosx"), anExistingDirectory()); + assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFrameworkRelease/Build/Products/Release"), anExistingDirectory()); } @ParameterizedTest @@ -57,6 +57,6 @@ void executesForDefaultConfigurationByDefault(GradleRunner runner) { void canSelectSdkToUse(String configurationToSelect, GradleRunner runner) { runner.withTasks("DualMacOsIosFramework").withArgument("-Dconfiguration=" + configurationToSelect).build(); - assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/" + configurationToSelect + "-macosx"), anExistingDirectory()); + assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework" + configurationToSelect + "/Build/Products/" + configurationToSelect), anExistingDirectory()); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/CrossProjectTargetDependenciesFunctionalTest.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/CrossProjectTargetDependenciesFunctionalTest.java index c131204663..329731beb5 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/CrossProjectTargetDependenciesFunctionalTest.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/CrossProjectTargetDependenciesFunctionalTest.java @@ -31,7 +31,7 @@ import java.nio.file.Path; import static dev.gradleplugins.buildscript.blocks.PluginsBlock.plugins; -import static dev.gradleplugins.fixtures.runnerkit.BuildResultMatchers.tasksExecuted; +import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.MatcherAssert.assertThat; @EnabledOnOs(OS.MAC) @@ -49,6 +49,6 @@ static void setup(GradleRunner runner) throws IOException { @Test void doesNotFailTheBuild() { - assertThat(result, tasksExecuted(":Library:GreeterLibRelease", ":CrossProjectReference:GreeterAppRelease", ":CrossProjectReference:GreeterApp")); + assertThat(result.getExecutedTaskPaths(), hasItems(":Library:GreeterLibRelease", ":CrossProjectReference:GreeterAppRelease", ":CrossProjectReference:GreeterApp")); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/SdkSelectionFunctionalTest.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/SdkSelectionFunctionalTest.java index e8364d5f17..67629283ef 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/SdkSelectionFunctionalTest.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/SdkSelectionFunctionalTest.java @@ -15,15 +15,11 @@ */ package dev.nokee.buildadapter.xcode; -import dev.gradleplugins.runnerkit.BuildResult; import dev.gradleplugins.runnerkit.GradleRunner; -import dev.gradleplugins.runnerkit.TaskOutcome; import dev.nokee.DualMacosIosFramework; import dev.nokee.internal.testing.junit.jupiter.ContextualGradleRunnerParameterResolver; -import dev.nokee.platform.xcode.XcodeSwiftApp; import net.nokeedev.testing.junit.jupiter.io.TestDirectory; import net.nokeedev.testing.junit.jupiter.io.TestDirectoryExtension; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -36,11 +32,8 @@ import java.nio.file.Path; import static dev.gradleplugins.buildscript.blocks.PluginsBlock.plugins; -import static dev.nokee.internal.testing.FileSystemMatchers.aFile; import static dev.nokee.internal.testing.FileSystemMatchers.anExistingDirectory; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertTrue; @EnabledOnOs(OS.MAC) @ExtendWith({TestDirectoryExtension.class, ContextualGradleRunnerParameterResolver.class}) @@ -56,7 +49,7 @@ void beforeEachCreateProject() throws IOException { @Test void executesForDefaultSdkByDefault(GradleRunner runner) { runner.withTasks("DualMacOsIosFramework").build(); - assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/Release-macosx"), anExistingDirectory()); + assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFrameworkRelease/Build/Products/Release"), anExistingDirectory()); } @ParameterizedTest @@ -64,6 +57,6 @@ void executesForDefaultSdkByDefault(GradleRunner runner) { void canSelectSdkToUse(String sdkToSelect, GradleRunner runner) { runner.withTasks("DualMacOsIosFramework").withArgument("-Dsdk=" + sdkToSelect).build(); - assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/Release-" + sdkToSelect), anExistingDirectory()); + assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFrameworkRelease/Build/Products/Release-" + sdkToSelect), anExistingDirectory()); } } diff --git a/subprojects/build-adapter-xcode/src/integrationTest/java/dev/nokee/buildadapter/xcode/internal/DerivedDataAssemblingRunnableIntegrationTests.java b/subprojects/build-adapter-xcode/src/integrationTest/java/dev/nokee/buildadapter/xcode/internal/DerivedDataAssemblingRunnableIntegrationTests.java index 03f7d32fcc..034ce6d4b3 100644 --- a/subprojects/build-adapter-xcode/src/integrationTest/java/dev/nokee/buildadapter/xcode/internal/DerivedDataAssemblingRunnableIntegrationTests.java +++ b/subprojects/build-adapter-xcode/src/integrationTest/java/dev/nokee/buildadapter/xcode/internal/DerivedDataAssemblingRunnableIntegrationTests.java @@ -15,8 +15,7 @@ */ package dev.nokee.buildadapter.xcode.internal; -import dev.nokee.buildadapter.xcode.internal.plugins.XcodeTargetExecTask; -import dev.nokee.internal.testing.testdoubles.MockitoBuilder; +import dev.nokee.buildadapter.xcode.internal.plugins.AssembleDerivedDataDirectoryTask; import net.nokeedev.testing.junit.jupiter.io.TestDirectory; import net.nokeedev.testing.junit.jupiter.io.TestDirectoryExtension; import org.junit.jupiter.api.BeforeEach; @@ -43,18 +42,15 @@ @ExtendWith(TestDirectoryExtension.class) class DerivedDataAssemblingRunnableIntegrationTests { @TestDirectory Path testDirectory; - Path outputDirectory; Path derivedDataDirectory; - XcodeTargetExecTask.DerivedDataAssemblingRunnable.Parameters parameters; - XcodeTargetExecTask.DerivedDataAssemblingRunnable subject; - Runnable delegate = MockitoBuilder.newMock(Runnable.class).instance(); + AssembleDerivedDataDirectoryTask.DerivedDataAssemblingRunnable.Parameters parameters; + AssembleDerivedDataDirectoryTask.DerivedDataAssemblingRunnable subject; @BeforeEach void givenSubject() { - parameters = objectFactory().newInstance(XcodeTargetExecTask.DerivedDataAssemblingRunnable.Parameters.class); - subject = new XcodeTargetExecTask.DerivedDataAssemblingRunnable(fileSystemOperations(), parameters, delegate); + parameters = objectFactory().newInstance(AssembleDerivedDataDirectoryTask.DerivedDataAssemblingRunnable.Parameters.class); + subject = new AssembleDerivedDataDirectoryTask.DerivedDataAssemblingRunnable(fileSystemOperations(), parameters); - parameters.getOutgoingDerivedDataPath().set((outputDirectory = testDirectory.resolve("output")).toFile()); parameters.getXcodeDerivedDataPath().set((derivedDataDirectory = testDirectory.resolve("derived-data")).toFile()); } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/AssembleDerivedDataDirectoryTask.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/AssembleDerivedDataDirectoryTask.java new file mode 100644 index 0000000000..b6384c01c7 --- /dev/null +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/AssembleDerivedDataDirectoryTask.java @@ -0,0 +1,104 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dev.nokee.buildadapter.xcode.internal.plugins; + +import dev.nokee.buildadapter.xcode.internal.files.PreserveLastModifiedFileSystemOperation; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.Directory; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.DuplicatesStrategy; +import org.gradle.api.file.FileSystemOperations; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.OutputFiles; +import org.gradle.api.tasks.TaskAction; +import org.gradle.workers.WorkAction; +import org.gradle.workers.WorkParameters; +import org.gradle.workers.WorkerExecutor; + +import javax.inject.Inject; + +@SuppressWarnings("UnstableApiUsage") +public abstract class AssembleDerivedDataDirectoryTask extends DefaultTask { + private final WorkerExecutor workerExecutor; + + @InputFiles + public abstract ConfigurableFileCollection getIncomingDerivedDataPaths(); + + @OutputFiles + public abstract ConfigurableFileCollection getOutputFiles(); + + @Internal + public abstract DirectoryProperty getXcodeDerivedDataPath(); + + @Inject + public AssembleDerivedDataDirectoryTask(WorkerExecutor workerExecutor) { + this.workerExecutor = workerExecutor; + getOutputFiles().from(getXcodeDerivedDataPath().dir("Build/Products").map(Directory::getAsFileTree)); // only track Build/Products/** + } + + @TaskAction + private void doAssemble() { + workerExecutor.noIsolation().submit(CopyAction.class, parameters -> { + parameters.getIncomingDerivedDataPaths().from(getIncomingDerivedDataPaths()); + parameters.getXcodeDerivedDataPath().set(getXcodeDerivedDataPath()); + }); + } + + public static abstract class CopyAction implements WorkAction { + private final FileSystemOperations fileOperations; + + public interface Parameters extends WorkParameters, DerivedDataAssemblingRunnable.Parameters { + ConfigurableFileCollection getIncomingDerivedDataPaths(); + DirectoryProperty getXcodeDerivedDataPath(); + } + + @Inject + public CopyAction(FileSystemOperations fileOperations) { + this.fileOperations = fileOperations; + } + + @Override + public void execute() { + new DerivedDataAssemblingRunnable(fileOperations, getParameters()).run(); + } + } + + public static final class DerivedDataAssemblingRunnable implements Runnable { + private final FileSystemOperations fileOperations; + private final Parameters parameters; + + public DerivedDataAssemblingRunnable(FileSystemOperations fileOperations, Parameters parameters) { + this.fileOperations = fileOperations; + this.parameters = parameters; + } + + @Override + public void run() { + new PreserveLastModifiedFileSystemOperation(fileOperations::copy).execute(spec -> { + spec.from(parameters.getIncomingDerivedDataPaths()); + spec.into(parameters.getXcodeDerivedDataPath()); + spec.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE); + }); + } + + public interface Parameters { + ConfigurableFileCollection getIncomingDerivedDataPaths(); + DirectoryProperty getXcodeDerivedDataPath(); + } + } +} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeBuildAdapterPlugin.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeBuildAdapterPlugin.java index fe241275b0..f8c3b84c02 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeBuildAdapterPlugin.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeBuildAdapterPlugin.java @@ -100,7 +100,6 @@ import static dev.nokee.utils.CallableUtils.ofSerializableCallable; import static dev.nokee.utils.ProviderUtils.finalizeValueOnRead; import static dev.nokee.utils.ProviderUtils.forUseAtConfigurationTime; -import static dev.nokee.utils.TaskUtils.temporaryDirectoryPath; import static dev.nokee.utils.TransformerUtils.Transformer.of; import static dev.nokee.utils.TransformerUtils.toListTransformer; import static dev.nokee.utils.TransformerUtils.transformEach; @@ -229,16 +228,23 @@ public static Action forXcodeProject(XCProjectReference reference, Acti )).orElse(Collections.emptyList())); }); + val derivedDataTask = project.getExtensions().getByType(ModelRegistry.class).register(DomainObjectEntities.newEntity(TaskName.of("assemble", "derivedDataDir"), AssembleDerivedDataDirectoryTask.class, it -> it.ownedBy(entity))) + .as(AssembleDerivedDataDirectoryTask.class) + .configure(task -> { + task.getIncomingDerivedDataPaths().from(derivedData); + task.getXcodeDerivedDataPath().set(project.getLayout().getBuildDirectory().dir("tmp-derived-data/" + target.getName() + "-" + variantInfo.getName())); + }); + val targetTask = project.getExtensions().getByType(ModelRegistry.class).register(DomainObjectEntities.newEntity(TaskName.lifecycle(), XcodeTargetExecTask.class, it -> it.ownedBy(entity))) .as(XcodeTargetExecTask.class) .configure(task -> { + task.dependsOn(derivedDataTask); task.getXcodeProject().set(reference); task.getTargetName().set(target.getName()); task.getOutputs().upToDateWhen(because(String.format("a shell script build phase of %s has no inputs or outputs defined", reference.ofTarget(target.getName())), everyShellScriptBuildPhaseHasDeclaredInputsAndOutputs())); - task.getDerivedDataPath().set(project.getLayout().getBuildDirectory().dir(temporaryDirectoryPath(task) + "/derivedData")); - task.getOutputDirectory().set(project.getLayout().getBuildDirectory().dir("derivedData/" + target.getName())); + task.getDerivedDataPath().set(derivedDataTask.flatMap(AssembleDerivedDataDirectoryTask::getXcodeDerivedDataPath)); + task.getOutputDirectory().set(project.getLayout().getBuildDirectory().dir("derivedData/" + task.getName())); task.getXcodeInstallation().set(project.getProviders().of(CurrentXcodeInstallationValueSource.class, ActionUtils.doNothing())); - task.getInputDerivedData().from(derivedData); task.getConfiguration().set(variantInfo.getName()); action.execute(task); }); diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java index abc14340eb..fea6a8fad6 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java @@ -38,9 +38,7 @@ import dev.nokee.xcode.project.PBXProjWriter; import lombok.val; import org.gradle.api.DefaultTask; -import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.file.DuplicatesStrategy; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileSystemOperations; import org.gradle.api.model.ObjectFactory; @@ -49,7 +47,6 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.OutputDirectory; @@ -96,9 +93,6 @@ public abstract class XcodeTargetExecTask extends DefaultTask implements Xcodebu @Input public abstract Property getTargetName(); - @InputFiles - public abstract ConfigurableFileCollection getInputDerivedData(); - @OutputDirectory public abstract DirectoryProperty getOutputDirectory(); @@ -236,7 +230,6 @@ private void doExec() { workerExecutor.noIsolation().submit(XcodebuildExec.class, spec -> { spec.getOutgoingDerivedDataPath().set(getOutputDirectory()); spec.getXcodeDerivedDataPath().set(getDerivedDataPath()); - spec.getIncomingDerivedDataPaths().setFrom(getInputDerivedData()); spec.getOriginalProjectLocation().set(getXcodeProject().get().getLocation().toFile()); spec.getIsolatedProjectLocation().set(isolatedProjectLocation); @@ -259,12 +252,6 @@ public DerivedDataAssemblingRunnable(FileSystemOperations fileOperations, Parame @Override public void run() { - new PreserveLastModifiedFileSystemOperation(fileOperations::copy).execute(spec -> { - spec.from(parameters.getIncomingDerivedDataPaths()); - spec.into(parameters.getXcodeDerivedDataPath()); - spec.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE); - }); - delegate.run(); new PreserveLastModifiedFileSystemOperation(fileOperations::sync).execute(spec -> { @@ -274,7 +261,6 @@ public void run() { } public interface Parameters { - ConfigurableFileCollection getIncomingDerivedDataPaths(); DirectoryProperty getXcodeDerivedDataPath(); DirectoryProperty getOutgoingDerivedDataPath(); } From d68d9336529eb2972daeae43880715a572e64db2 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Sat, 18 Mar 2023 16:14:13 +0400 Subject: [PATCH 3/4] Include build settings in Xcode arguments Signed-off-by: Daniel Lacasse --- .../xcode/internal/plugins/XcodeTargetExecTask.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java index fea6a8fad6..34cfcf7608 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/XcodeTargetExecTask.java @@ -125,6 +125,10 @@ public XcodeTargetExecTask(WorkerExecutor workerExecutor, ObjectFactory objects) .map(derivedDataPath -> of("PODS_BUILD_DIR=" + derivedDataPath.resolve("Build/Products")))); getAllArguments().addAll(getDerivedDataPath().map(FileSystemLocationUtils::asPath) .map(new DerivedDataPathAsBuildSettings()).map(this::asFlags)); + getAllArguments().addAll(getDerivedDataPath().map(FileSystemLocationUtils::asPath).map(derivedDataPath -> { + val path = derivedDataPath.resolve("Build/Products/" + getConfiguration().get() + getSdk().map(it -> "-" + it).getOrElse("")); + return of("CONFIGURATION_BUILD_DIR=" + path, "BUILT_PRODUCT_DIR=" + path); + })); getAllArguments().addAll(codeSigningDisabled()); finalizeValueOnRead(disallowChanges(getAllArguments())); @@ -151,6 +155,7 @@ public XcodeTargetExecTask(WorkerExecutor workerExecutor, ObjectFactory objects) @Override public String get(String name) { switch (name) { + case "CONFIGURATION_BUILD_DIR": case "BUILT_PRODUCT_DIR": // TODO: The following is only an approximation of what the BUILT_PRODUCT_DIR would be, use -showBuildSettings // TODO: Guard against the missing derived data path From 25aa6f19f3a1fdf3b93d4c5713a8a8ad5a811824 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Sat, 18 Mar 2023 16:15:39 +0400 Subject: [PATCH 4/4] Include input files in up-to-date check Signed-off-by: Daniel Lacasse --- .../xcode/PBXProjectTestUtils.java | 96 +++- ...geToPBXAggregateTargetFunctionalTests.java | 32 +- ...PBXCopyFilesBuildPhaseFunctionalTests.java | 113 +++- ...BXFrameworksBuildPhaseFunctionalTests.java | 80 ++- ...ToPBXHeadersBuildPhaseFunctionalTests.java | 120 +++- ...hangeToPBXLegacyTargetFunctionalTests.java | 31 +- ...hangeToPBXNativeTargetFunctionalTests.java | 28 +- ...PBXResourcesBuildPhaseFunctionalTests.java | 80 ++- ...XShellScriptBuildPhaseFunctionalTests.java | 97 ++-- ...ToPBXSourcesBuildPhaseFunctionalTests.java | 77 ++- .../xcode/uptodate/UpToDateCheckSpec.java | 180 +++++- ...ctSpecEncoder.java => AtInputEncoder.java} | 31 +- ...cEncoder.java => AtInputFilesEncoder.java} | 30 +- .../specs/AtNestedCollectionEncoder.java | 77 +++ .../plugins/specs/AtNestedMapEncoder.java | 137 +++++ ...ectSpec.java => CompositeXCBuildPlan.java} | 24 +- ...er.java => FileSystemLocationEncoder.java} | 27 +- .../plugins/specs/InputLocationSpec.java | 46 -- .../plugins/specs/ListSpecEncoder.java | 35 -- .../plugins/specs/NestedListSpec.java | 63 --- .../internal/plugins/specs/NestedMapSpec.java | 119 ---- .../specs/XCBuildSpecCodingKeyCoders.java | 38 +- .../dev/nokee/xcode/XCBuildSpecLoader.java | 4 +- .../nokee/xcode/XCFileReferencesLoader.java | 2 +- .../up-to-date-check/App/FileToRemove.swift | 8 + .../src/templates/up-to-date-check/Bar/Bar.h | 18 + .../src/templates/up-to-date-check/Bar/Bar.m | 8 + .../up-to-date-check/Common/Common.c | 8 - .../Common/Common.docc/Common.md | 13 - .../up-to-date-check/Common/Common.h | 18 - .../CommonTests/CommonTests.swift | 36 -- .../src/templates/up-to-date-check/Foo/Foo.h | 18 + .../templates/up-to-date-check/Foo/Foo.swift | 8 + .../UpToDateCheck.xcodeproj/project.pbxproj | 526 +++++++++--------- .../xcshareddata/xcschemes/App.xcscheme | 11 + .../src/templates/up-to-date-check/makefile | 2 + ...derTests.java => AtInputEncoderTests.java} | 6 +- ...va => AtNestedCollectionEncoderTests.java} | 8 +- ...ests.java => AtNestedMapEncoderTests.java} | 6 +- ...va => FileSystemLocationEncoderTests.java} | 6 +- .../XCBuildSpecCodingKeyCodersTests.java | 23 +- 41 files changed, 1450 insertions(+), 840 deletions(-) rename subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{InputObjectSpecEncoder.java => AtInputEncoder.java} (58%) rename subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{MapSpecEncoder.java => AtInputFilesEncoder.java} (56%) create mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoder.java create mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoder.java rename subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{InputObjectSpec.java => CompositeXCBuildPlan.java} (65%) rename subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{InputLocationSpecEncoder.java => FileSystemLocationEncoder.java} (56%) delete mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpec.java delete mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoder.java delete mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedListSpec.java delete mode 100644 subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedMapSpec.java create mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/App/FileToRemove.swift create mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.h create mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.m delete mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.c delete mode 100755 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.docc/Common.md delete mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.h delete mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/CommonTests/CommonTests.swift create mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.h create mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.swift create mode 100644 subprojects/build-adapter-xcode/src/templates/up-to-date-check/makefile rename subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{InputObjectSpecEncoderTests.java => AtInputEncoderTests.java} (90%) rename subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{ListSpecEncoderTests.java => AtNestedCollectionEncoderTests.java} (85%) rename subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{MapSpecEncoderTests.java => AtNestedMapEncoderTests.java} (94%) rename subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/{InputLocationSpecEncoderTests.java => FileSystemLocationEncoderTests.java} (90%) diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/PBXProjectTestUtils.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/PBXProjectTestUtils.java index e9094eabbd..4822758be2 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/PBXProjectTestUtils.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/PBXProjectTestUtils.java @@ -23,10 +23,16 @@ import dev.nokee.xcode.objects.buildphase.BuildFileAwareBuilder; import dev.nokee.xcode.objects.buildphase.PBXBuildFile; import dev.nokee.xcode.objects.buildphase.PBXBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXFrameworksBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXHeadersBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXResourcesBuildPhase; import dev.nokee.xcode.objects.buildphase.PBXShellScriptBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXSourcesBuildPhase; import dev.nokee.xcode.objects.files.GroupChild; import dev.nokee.xcode.objects.files.PBXFileReference; import dev.nokee.xcode.objects.files.PBXGroup; +import dev.nokee.xcode.objects.files.PBXReference; import dev.nokee.xcode.objects.targets.BuildPhaseAwareBuilder; import dev.nokee.xcode.objects.targets.PBXLegacyTarget; import dev.nokee.xcode.objects.targets.PBXTarget; @@ -43,6 +49,7 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -53,7 +60,7 @@ import static com.google.common.collect.MoreCollectors.onlyElement; public final class PBXProjectTestUtils { - public static Consumer mutateProject(UnaryOperator action) { + public static Consumer mutateProject(Function action) { return path -> { assert path.getFileName().toString().endsWith(".xcodeproj"); try (val reader = new PBXProjReader(new AsciiPropertyListReader(Files.newBufferedReader(path.resolve("project.pbxproj"))))) { @@ -75,6 +82,10 @@ public static UnaryOperator mainGroup(BiFunction project.toBuilder().mainGroup(action.apply(project, project.getMainGroup())).build(); } + public static UnaryOperator productsGroup(BiFunction action) { + return mainGroup(children(matching(childNameOrPath("Products"), asGroup(action)))); + } + public static BiFunction children(BiFunction, ? extends List> action) { return (project, group) -> { return group.toBuilder().children(action.apply(project, group.getChildren())).build(); @@ -83,22 +94,21 @@ public static BiFunction children(BiFunction BiFunction, List> matching(Predicate predicate, BiFunction action) { return (self, values) -> { + boolean found = false; val builder = ImmutableList.builder(); for (E value : values) { if (predicate.test(value)) { + found = true; builder.add(action.apply(self, value)); } else { builder.add(value); } } + assert found : "no item matched predicate"; return builder.build(); }; } - public static BiFunction childNamed(String name, BiFunction action) { - return children(matching(childName(name), action)); - } - public static Predicate childName(String value) { return it -> it.getName().map(value::equals).orElse(false); } @@ -107,10 +117,22 @@ public static Predicate childPath(String value) { return it -> it.getPath().map(value::equals).orElse(false); } - public static Predicate nameOrPath(String value) { + public static Predicate childNameOrPath(String value) { return childName(value).or(childPath(value)); } + public static Predicate referenceName(String value) { + return it -> it.getName().map(value::equals).orElse(false); + } + + public static Predicate referencePath(String value) { + return it -> it.getPath().map(value::equals).orElse(false); + } + + public static Predicate referenceNameOrPath(String value) { + return referenceName(value).or(referencePath(value)); + } + public static BiFunction asGroup(BiFunction action) { return (self, e) -> { assert e instanceof PBXGroup; @@ -132,6 +154,19 @@ public static BiFunction, List> removeLast() { return (__, values) -> values.subList(0, values.size() - 1); } + public static BiFunction, List> removeIf(Predicate predicate) { + return (__, values) -> { + val newValues = new ArrayList<>(values); + boolean found = newValues.removeIf(predicate); + assert found; + return newValues; + }; + } + + public static BiFunction, List> clear() { + return (__, values) -> ImmutableList.of(); + } + public static BiFunction, List> add(Function action) { return (self, values) -> { return ImmutableList.builder().addAll(values).add(action.apply(self)).build(); @@ -146,12 +181,16 @@ public static Function targetDependencyTo(Strin public static Function buildFileToProduct(String productName) { return self -> { - val productGroup = (PBXGroup) self.getMainGroup().getChildren().stream().filter(childName("Products")).collect(onlyElement()); - val productFile = (PBXFileReference) productGroup.getChildren().stream().filter(nameOrPath(productName)).collect(onlyElement()); + val productGroup = (PBXGroup) self.getMainGroup().getChildren().stream().filter(childNameOrPath("Products")).collect(onlyElement()); + val productFile = (PBXFileReference) productGroup.getChildren().stream().filter(childNameOrPath(productName)).collect(onlyElement()); return PBXBuildFile.ofFile(productFile); }; } + public static Function buildFileToProduct(Function action) { + return self -> PBXBuildFile.ofFile(action.apply(self)); + } + public static UnaryOperator targets(BiFunction, ? extends List> action) { return project -> project.toBuilder().targets(action.apply(project, project.getTargets())).build(); } @@ -192,11 +231,13 @@ public static BiFunction dependencies(BiFuncti }; } - public static BiFunction files(BiFunction, ? extends List> action) { + public static BiFunction files(BiFunction, ? extends List> action) { return (self, buildPhase) -> { val builder = buildPhase.toBuilder(); ((BuildFileAwareBuilder) builder).files(action.apply(self, buildPhase.getFiles())); - return builder.build(); + @SuppressWarnings("unchecked") + val result = (T) builder.build(); + return result; }; } @@ -211,6 +252,41 @@ public static BiFunction as }; } + public static BiFunction asCopyFiles(BiFunction action) { + return (self, buildPhase) -> { + assert buildPhase instanceof PBXCopyFilesBuildPhase; + return action.apply(self, (PBXCopyFilesBuildPhase) buildPhase); + }; + } + + public static BiFunction asFrameworks(BiFunction action) { + return (self, buildPhase) -> { + assert buildPhase instanceof PBXFrameworksBuildPhase; + return action.apply(self, (PBXFrameworksBuildPhase) buildPhase); + }; + } + + public static BiFunction asHeaders(BiFunction action) { + return (self, buildPhase) -> { + assert buildPhase instanceof PBXHeadersBuildPhase; + return action.apply(self, (PBXHeadersBuildPhase) buildPhase); + }; + } + + public static BiFunction asResources(BiFunction action) { + return (self, buildPhase) -> { + assert buildPhase instanceof PBXResourcesBuildPhase; + return action.apply(self, (PBXResourcesBuildPhase) buildPhase); + }; + } + + public static BiFunction asSources(BiFunction action) { + return (self, buildPhase) -> { + assert buildPhase instanceof PBXSourcesBuildPhase; + return action.apply(self, (PBXSourcesBuildPhase) buildPhase); + }; + } + public static BiFunction shellPath(String value) { return (self, buildPhase) -> buildPhase.toBuilder().shellPath(value).build(); } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXAggregateTargetFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXAggregateTargetFunctionalTests.java index 5ba485d835..af5727ed8b 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXAggregateTargetFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXAggregateTargetFunctionalTests.java @@ -15,42 +15,48 @@ */ package dev.nokee.buildadapter.xcode.uptodate; -import dev.gradleplugins.runnerkit.GradleRunner; -import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; +import java.io.IOException; + import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.removeLast; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.clear; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static org.hamcrest.MatcherAssert.assertThat; @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXAggregateTargetFunctionalTests extends UpToDateCheckSpec { + @BeforeEach + void setup() throws IOException { + xcodeproj(targetUnderTest(buildPhases(add(aBuildPhase())))); + + ensureUpToDate(executer); + } + @Override - GradleRunner configure(GradleRunner runner) { - return runner.withTasks("AggregateDebug"); + protected String targetUnderTestName() { + return "AppAggregate"; } @Nested class BuildPhasesField { @Test - void outOfDateWhenNewBuildPhase() { - mutateProject(targetNamed("Aggregate", buildPhases(add(PBXCopyFilesBuildPhase.builder().destination(it -> it.frameworks("")).build())))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenBuildPhaseAdded() { + xcodeproj(targetUnderTest(buildPhases(add(aBuildPhase())))); - assertThat(executer.build().task(":UpToDateCheck:AggregateDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } @Test - void outOfDateWhenRemoveBuildPhase() { - mutateProject(targetNamed("Aggregate", buildPhases(removeLast()))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenBuildPhaseRemoved() { + xcodeproj(targetUnderTest(buildPhases(clear()))); - assertThat(executer.build().task(":UpToDateCheck:AggregateDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXCopyFilesBuildPhaseFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXCopyFilesBuildPhaseFunctionalTests.java index c3e4e366c3..05c85f1a88 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXCopyFilesBuildPhaseFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXCopyFilesBuildPhaseFunctionalTests.java @@ -15,65 +15,134 @@ */ package dev.nokee.buildadapter.xcode.uptodate; +import com.google.common.collect.ImmutableMap; +import dev.nokee.xcode.objects.PBXProject; import dev.nokee.xcode.objects.buildphase.PBXBuildFile; -import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase; import dev.nokee.xcode.objects.files.PBXFileReference; import dev.nokee.xcode.objects.files.PBXGroup; import lombok.val; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; import java.io.IOException; -import java.nio.file.Path; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import static com.google.common.collect.ImmutableList.of; import static com.google.common.collect.MoreCollectors.onlyElement; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.childName; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.clear; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.dependencies; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.nameOrPath; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.files; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.childNameOrPath; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetDependencyTo; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static java.nio.file.Files.delete; import static org.hamcrest.MatcherAssert.assertThat; @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXCopyFilesBuildPhaseFunctionalTests extends UpToDateCheckSpec { - void setup(Path location) { - embedCommonFrameworkIntoApp().accept(location); + @BeforeEach + void setup() throws IOException { + xcodeproj(embedFrameworkIntoApp("Foo")); + xcodeproj(targetUnderTest(dependencies(add(targetDependencyTo("Foo"))))); + + ensureUpToDate(executer); + } + + @Override + protected String targetUnderTestName() { + return "App"; } // TODO: modifying Common/Common.h should have no effect because it's not part of the final output... It is excluded by the built-in copy // builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -exclude Headers -exclude PrivateHeaders -exclude Modules -exclude \*.tbd -resolve-src-symlinks /Users/daniel/Library/Developer/Xcode/DerivedData/UpToDateCheck-cimdnpufgfbcnjaylgddbeqklcsy/Build/Products/Debug/Common.framework /Users/daniel/Library/Developer/Xcode/DerivedData/UpToDateCheck-cimdnpufgfbcnjaylgddbeqklcsy/Build/Products/Debug/App.app/Contents/Frameworks + // It seems to be ATTRIBUTES = (RemoveHeadersOnCopy) // Not sure if this is the norm or just specific to this case... // Note that if PBXFrameworksBuildPhase points to the framework, it will snapshot the entire Common.framework - @Test - void outOfDateWhenCompiledFrameworkChange() throws IOException { - appendMeaningfulChangeToCFile(testDirectory.resolve("Common/Common.c")); + @Nested + class FilesField { + @Test + void outOfDateWhenCompiledFrameworkChanges() throws IOException { + appendChangeToSwiftFile(file("Foo/Foo.swift")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileAdded() { + xcodeproj(embedFrameworkIntoApp("Bar")); + xcodeproj(targetUnderTest(dependencies(add(targetDependencyTo("Bar"))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileRemoved() { + xcodeproj(targetUnderTest(copyFilesBuildPhases(files(clear())))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileEntryDuplicated() { + xcodeproj(embedFrameworkIntoApp("Foo")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + @Test + void outOfDateWhenResolvedFileDuplicated() { + xcodeproj(alternateBuiltProduct("Foo.framework")); + xcodeproj(embedFrameworkIntoApp("alternate-Foo")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileOrderingChanged() { + xcodeproj(embedFrameworkIntoApp("Bar")); + xcodeproj(targetUnderTest(dependencies(add(targetDependencyTo("Bar"))))); + + ensureUpToDate(executer); + + xcodeproj(targetUnderTest(copyFilesBuildPhases(files(shuffleOrdering())))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } } @Disabled("outputs are not yet tracked") @Test void outOfDateWhenInputCopyFileRemoved() throws IOException { - delete(appDebugProductsDirectory().resolve("App.app/Contents/Frameworks/Common.framework/Common")); + delete(appDebugProductsDirectory().resolve("App.app/Contents/Frameworks/Foo.framework/Foo")); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } - private static Consumer embedCommonFrameworkIntoApp() { - return mutateProject(project -> { - val productsGroup = (PBXGroup) project.getMainGroup().getChildren().stream().filter(childName("Products")).collect(onlyElement()); - val commonFrameworkFile = (PBXFileReference) productsGroup.getChildren().stream().filter(nameOrPath("Common.framework")).collect(onlyElement()); - val newProject = targetNamed("App", buildPhases(add(PBXCopyFilesBuildPhase.builder().dstSubfolderSpec(PBXCopyFilesBuildPhase.SubFolder.Frameworks).dstPath("").file(PBXBuildFile.ofFile(commonFrameworkFile)).build()))).apply(project); - return targetNamed("App", dependencies(add(targetDependencyTo("Common")))).apply(newProject); - }); + private UnaryOperator embedFrameworkIntoApp(String frameworkName) { + return targetUnderTest(copyFilesBuildPhases(files(add(framework(frameworkName))))); + } + + private static Function framework(String frameworkName) { + return framework(frameworkName, builder -> builder.settings(ImmutableMap.of("ATTRIBUTES", of("CodeSignOnCopy", "RemoveHeadersOnCopy")))); + } + + private static Function framework(String frameworkName, Consumer action) { + assert !frameworkName.endsWith(".framework"); + return project -> { + val productsGroup = (PBXGroup) project.getMainGroup().getChildren().stream().filter(childNameOrPath("Products")).collect(onlyElement()); + val frameworkFile = (PBXFileReference) productsGroup.getChildren().stream().filter(childNameOrPath(frameworkName + ".framework")).collect(onlyElement()); + + val builder = PBXBuildFile.builder(); + action.accept(builder); + return builder.fileRef(frameworkFile).build(); + }; } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXFrameworksBuildPhaseFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXFrameworksBuildPhaseFunctionalTests.java index 08cd421401..111e3b5c07 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXFrameworksBuildPhaseFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXFrameworksBuildPhaseFunctionalTests.java @@ -15,48 +15,92 @@ */ package dev.nokee.buildadapter.xcode.uptodate; -import dev.nokee.xcode.objects.buildphase.PBXFrameworksBuildPhase; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; import java.io.IOException; -import java.nio.file.Path; -import static com.google.common.base.Predicates.instanceOf; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildFileToProduct; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.dependencies; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.clear; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.files; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.matching; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetDependencyTo; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static java.nio.file.Files.delete; import static org.hamcrest.MatcherAssert.assertThat; @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXFrameworksBuildPhaseFunctionalTests extends UpToDateCheckSpec { - void setup(Path location) { - mutateProject(targetNamed("App", dependencies(add(targetDependencyTo("Common"))))).accept(location); - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXFrameworksBuildPhase.class), files(add(buildFileToProduct("Common.framework"))))))).accept(location); + @BeforeEach + void setup() throws IOException { + xcodeproj(targetUnderTest(frameworksBuildPhases(files(add(buildFileToProduct("Foo.framework")))))); + + ensureUpToDate(executer); } - @Test - void outOfDateWhenConsumedFrameworkRebuild() throws IOException { - appendMeaningfulChangeToCFile(testDirectory.resolve("Common/Common.c")); + @Override + protected String targetUnderTestName() { + return "App"; + } + + @Nested + class FilesField { + @Test + void outOfDateWhenConsumedFrameworkRebuilt() throws IOException { + appendChangeToSwiftFile(file("Foo/Foo.swift")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileAdded() { + xcodeproj(targetUnderTest(frameworksBuildPhases(files(add(buildFileToProduct("Bar.framework")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileRemoved() { + xcodeproj(targetUnderTest(frameworksBuildPhases(files(clear())))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileEntryDuplicated() { + xcodeproj(targetUnderTest(frameworksBuildPhases(files(add(buildFileToProduct("Foo.framework")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenResolvedFileDuplicated() { + xcodeproj(alternateBuiltProduct("Foo.framework")); + xcodeproj(targetUnderTest(frameworksBuildPhases(files(add(buildFileToProduct("alternate-Foo.framework")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileOrderingChanged() { + xcodeproj(targetUnderTest(frameworksBuildPhases(files(add(buildFileToProduct("Bar.framework")))))); + + ensureUpToDate(executer.withArgument("-i")); + + xcodeproj(targetUnderTest(frameworksBuildPhases(files(shuffleOrdering())))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); + } } @Disabled("outputs are not yet tracked") @Test void outOfDateWhenConsumedFrameworkChange() throws IOException { - delete(appDebugProductsDirectory().resolve("Common.framework/Common")); + delete(appDebugProductsDirectory().resolve("Foo.framework/Foo")); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXHeadersBuildPhaseFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXHeadersBuildPhaseFunctionalTests.java index 9780f25916..82a9be7a4f 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXHeadersBuildPhaseFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXHeadersBuildPhaseFunctionalTests.java @@ -15,43 +15,139 @@ */ package dev.nokee.buildadapter.xcode.uptodate; -import dev.gradleplugins.runnerkit.TaskOutcome; +import com.google.common.collect.ImmutableMap; +import dev.nokee.xcode.objects.buildphase.PBXBuildFile; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; import java.io.IOException; -import java.nio.file.Path; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.function.Consumer; +import static com.google.common.collect.ImmutableList.of; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.children; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.clear; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.dependencies; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.files; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetDependencyTo; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; +import static dev.nokee.xcode.objects.files.PBXFileReference.ofGroup; import static java.nio.file.Files.delete; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXHeadersBuildPhaseFunctionalTests extends UpToDateCheckSpec { - void setup(Path location) { - mutateProject(targetNamed("App", dependencies(add(targetDependencyTo("Common"))))).accept(location); + @BeforeEach + void setup() throws IOException { + xcodeproj(targetNamed("App", dependencies(add(targetDependencyTo(targetUnderTestName()))))); + + executer = executer.withTasks("AppDebug"); // ensure the App is built which depends on the target under test + + ensureUpToDate(executer); + } + + @Override + protected String targetUnderTestName() { + return "Foo"; } - @Test - void outOfDateWhenPrivateHeaderChange() throws IOException { - appendChangeToCHeader(testDirectory.resolve("Common/Common.h")); + @Nested + class FilesField { + @Test // TODO: check here + void outOfDateWhenPrivateHeaderChange() throws IOException { + appendChangeToCHeader(file("Foo/Foo.h")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test // TODO: What about public/protected + void outOfDateWhenPublicHeaderFileAdded() throws IOException { + xcodeproj(groupUnderTest(children(add(ofGroup("MyApp.h"))))); + xcodeproj(targetUnderTest(headersBuildPhases(files(add(buildFileTo("MyApp.h", asPublic())))))); + Files.write(file("Foo/MyApp.h"), Arrays.asList("// my app header")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test // TODO: What about public/protected + void outOfDateWhenPrivateHeaderFileAdded() throws IOException { + xcodeproj(groupUnderTest(children(add(ofGroup("MyApp.h"))))); + xcodeproj(targetUnderTest(headersBuildPhases(files(add(buildFileTo("MyApp.h", asPrivate())))))); + Files.write(file("Foo/MyApp.h"), Arrays.asList("// my app header")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test // TODO: What about public/protected + void outOfDateWhenProjectHeaderFileAdded() throws IOException { + xcodeproj(groupUnderTest(children(add(ofGroup("MyApp.h"))))); + xcodeproj(targetUnderTest(headersBuildPhases(files(add(buildFileTo("MyApp.h", asProject())))))); + Files.write(file("Foo/MyApp.h"), Arrays.asList("// my app header")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileRemoved() { + xcodeproj(targetUnderTest(headersBuildPhases(files(clear())))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } - assertThat(executer.build().task(":UpToDateCheck:CommonDebug"), outOfDate()); + @Test + void outOfDateWhenFileEntryDuplicated() { + xcodeproj(targetUnderTest(headersBuildPhases(files(add(buildFileTo("Foo.h", asPublic())))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenResolvedFileDuplicated() { + xcodeproj(alternateFileUnderTest("Foo.h")); + xcodeproj(targetUnderTest(headersBuildPhases(files(add(buildFileTo("alternate-Foo.h", asPublic())))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenHeadersOrderingChanged() throws IOException { + Files.write(file("Foo/MyApp.h"), Arrays.asList("// my app header"), StandardOpenOption.CREATE, StandardOpenOption.WRITE); + xcodeproj(groupUnderTest(children(add(ofGroup("MyApp.h"))))); + xcodeproj(targetUnderTest(headersBuildPhases(files(add(buildFileTo("MyApp.h", asPublic())))))); + + ensureUpToDate(executer); + + xcodeproj(targetUnderTest(headersBuildPhases(files(shuffleOrdering())))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } } @Disabled("outputs are not yet tracked") @Test // TODO: This may actually trigger the productReference.... void outOfDateWhenDeletePrivateHeaderFromFramework() throws IOException { - delete(appDebugProductsDirectory().resolve("Common.framework/Versions/A/Headers/Common.h")); + delete(appDebugProductsDirectory().resolve("Foo.framework/Versions/A/Headers/Foo.h")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + public static Consumer asPublic() { + return it -> it.settings(ImmutableMap.of("ATTRIBUTES", of("Public"))); + } + + public static Consumer asPrivate() { + return it -> it.settings(ImmutableMap.of("ATTRIBUTES", of("Private"))); + } - assertThat(executer.build().task(":UpToDateCheck:CommonDebug").getOutcome(), equalTo(TaskOutcome.SUCCESS)); + public static Consumer asProject() { + return it -> it.settings(ImmutableMap.of("ATTRIBUTES", of("Project"))); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXLegacyTargetFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXLegacyTargetFunctionalTests.java index d062081de4..22b4dffd95 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXLegacyTargetFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXLegacyTargetFunctionalTests.java @@ -15,50 +15,47 @@ */ package dev.nokee.buildadapter.xcode.uptodate; -import dev.gradleplugins.runnerkit.GradleRunner; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.util.Arrays; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asLegacyTarget; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildArgumentsString; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildToolPath; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static java.nio.file.attribute.PosixFilePermissions.fromString; import static org.hamcrest.MatcherAssert.assertThat; @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXLegacyTargetFunctionalTests extends UpToDateCheckSpec { - @Override - void setup(Path location) throws IOException { - Files.write(location.getParent().resolve("makefile"), Arrays.asList("null:", "\t@:")); + @BeforeEach + void setup() throws IOException { + ensureUpToDate(executer); } @Override - GradleRunner configure(GradleRunner runner) { - return runner.withTasks("LegacyDebug"); + protected String targetUnderTestName() { + return "AppLegacy"; } @Test - void outOfDateWhenBuildToolChange() throws IOException { - Files.write(testDirectory.resolve("my-make"), Arrays.asList("#!/usr/bin/env bash", "make $@")); - Files.setPosixFilePermissions(testDirectory.resolve("my-make"), fromString("rwx------")); - mutateProject(targetNamed("Legacy", asLegacyTarget(buildToolPath(testDirectory.resolve("my-make").toString())))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenBuildToolChanged() throws IOException { + Files.write(file("my-make"), Arrays.asList("#!/usr/bin/env bash", "make $@")); + Files.setPosixFilePermissions(file("my-make"), fromString("rwx------")); + xcodeproj(targetUnderTest(asLegacyTarget(buildToolPath(file("my-make").toString())))); - assertThat(executer.build().task(":UpToDateCheck:LegacyDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } @Test - void outOfDateWhenBuildArgumentsChange() { - mutateProject(targetNamed("Legacy", asLegacyTarget(buildArgumentsString("build")))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenBuildArgumentsChanged() { + xcodeproj(targetUnderTest(asLegacyTarget(buildArgumentsString("build")))); - assertThat(executer.build().task(":UpToDateCheck:LegacyDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXNativeTargetFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXNativeTargetFunctionalTests.java index 33fea6f7ac..00c2c0db56 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXNativeTargetFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXNativeTargetFunctionalTests.java @@ -15,38 +15,46 @@ */ package dev.nokee.buildadapter.xcode.uptodate; -import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; -import java.nio.file.Path; +import java.io.IOException; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.removeLast; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static org.hamcrest.MatcherAssert.assertThat; @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXNativeTargetFunctionalTests extends UpToDateCheckSpec { + @BeforeEach + void setup() throws IOException { + ensureUpToDate(executer); + } + + @Override + protected String targetUnderTestName() { + return "App"; + } + @Nested class BuildPhasesField { @Test - void outOfDateWhenNewBuildPhase() { - mutateProject(targetNamed("App", buildPhases(add(PBXCopyFilesBuildPhase.builder().destination(it -> it.frameworks("")).build())))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenBuildPhaseAdded() { + xcodeproj(targetUnderTest(buildPhases(add(aBuildPhase())))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } @Test - void outOfDateWhenRemoveBuildPhase() { - mutateProject(targetNamed("App", buildPhases(removeLast()))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenBuildPhaseRemoved() { + xcodeproj(targetUnderTest(buildPhases(removeLast()))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXResourcesBuildPhaseFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXResourcesBuildPhaseFunctionalTests.java index 9c64e89a41..d9480b4cba 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXResourcesBuildPhaseFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXResourcesBuildPhaseFunctionalTests.java @@ -15,19 +15,18 @@ */ package dev.nokee.buildadapter.xcode.uptodate; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; import java.io.IOException; -import java.nio.file.Path; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asGroup; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.childNamed; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.children; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mainGroup; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.clear; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.files; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static dev.nokee.internal.testing.GradleRunnerMatchers.upToDate; import static dev.nokee.xcode.objects.files.PBXFileReference.ofGroup; @@ -35,19 +34,76 @@ @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXResourcesBuildPhaseFunctionalTests extends UpToDateCheckSpec { - @Test - void outOfDateWhenNewColorSet() throws IOException { - writeColorSet(testDirectory.resolve("App/Assets.xcassets/NewColor.colorset")); + @BeforeEach + void setup() throws IOException { + ensureUpToDate(executer); + } + + @Override + protected String targetUnderTestName() { + return "App"; + } + + @Nested + class FilesField { + @Test + void outOfDateWhenXCAssetsChanged() throws IOException { + writeColorSet(file("App/Assets.xcassets/NewColor.colorset")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileAdded() { + xcodeproj(groupUnderTest(children(add(ofGroup("OtherAssets.xcassets"))))); + xcodeproj(targetUnderTest(resourcesBuildPhases(files(add(buildFileTo("OtherAssets.xcassets")))))); + xcodeproj(run(() -> writeColorSet(file("App/OtherAssets.xcassets/NewColor.colorset")))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileRemoved() { + xcodeproj(targetUnderTest(resourcesBuildPhases(files(clear())))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileEntryDuplicated() { + xcodeproj(targetUnderTest(resourcesBuildPhases(files(add(buildFileTo("Assets.xcassets")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenResolvedFileDuplicated() { + xcodeproj(alternateFileUnderTest("Assets.xcassets")); + xcodeproj(targetUnderTest(resourcesBuildPhases(files(add(buildFileTo("alternate-Assets.xcassets")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileOrderingChanged() throws IOException { + writeColorSet(file("App/OtherAssets.xcassets/NewColor.colorset")); + xcodeproj(groupUnderTest(children(add(ofGroup("OtherAssets.xcassets"))))); + xcodeproj(targetUnderTest(resourcesBuildPhases(files(add(buildFileTo("OtherAssets.xcassets")))))); + + ensureUpToDate(executer); + + xcodeproj(targetUnderTest(resourcesBuildPhases(files(shuffleOrdering())))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); + } } @Test void ignoresNewUnlinkedAssets() throws IOException { - writeColorSet(testDirectory.resolve("App/OtherAssets.xcassets/NewColor.colorset")); - mutateProject(mainGroup(childNamed("App", asGroup(children(add(ofGroup("OtherAssets.xcassets"))))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + writeColorSet(file("App/OtherAssets.xcassets/NewColor.colorset")); + xcodeproj(groupUnderTest(children(add(ofGroup("OtherAssets.xcassets"))))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), upToDate()); + assertThat(targetUnderTestExecution(), upToDate()); } // TODO: Modifying storyboard should make this out-of-date but it doesn't work because how we calculate paths for PBXVariantGroup is broken diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXShellScriptBuildPhaseFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXShellScriptBuildPhaseFunctionalTests.java index ffe847fd90..adce4605b2 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXShellScriptBuildPhaseFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXShellScriptBuildPhaseFunctionalTests.java @@ -15,9 +15,8 @@ */ package dev.nokee.buildadapter.xcode.uptodate; -import com.google.common.base.Predicates; import dev.nokee.xcode.objects.buildphase.PBXShellScriptBuildPhase; -import lombok.val; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -26,26 +25,17 @@ import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Arrays; -import static com.google.common.base.Predicates.instanceOf; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asGroup; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asShellScript; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.childNamed; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.children; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.inputPaths; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mainGroup; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.matching; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.removeFirst; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.scriptPhaseName; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.shellPath; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.shellScript; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static dev.nokee.internal.testing.GradleRunnerMatchers.upToDate; import static dev.nokee.xcode.objects.files.PBXFileReference.ofGroup; @@ -54,65 +44,84 @@ @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXShellScriptBuildPhaseFunctionalTests extends UpToDateCheckSpec { - void setup(Path location) { - mutateProject(targetNamed("App", buildPhases(add(PBXShellScriptBuildPhase.builder().name("Lint main component").shellScript("echo \"dummy-result\" > \"$DERIVED_FILE_DIR/App-result.txt\"").inputPath("$(SRCROOT)/App/AppDelegate.swift").inputPath("$(SRCROOT)/App/ViewController.swift").outputPath("$(DERIVED_FILE_DIR)/App-result.txt").build())))).accept(location); + @BeforeEach + void setup() throws IOException { + xcodeproj(targetUnderTest(buildPhases(add(PBXShellScriptBuildPhase.builder() + .name("Lint main component") + .shellScript("echo \"dummy-result\" > \"$DERIVED_FILE_DIR/App-result.txt\"") + .inputPath("$(SRCROOT)/App/AppDelegate.swift") + .inputPath("$(SRCROOT)/App/ViewController.swift") + .outputPath("$(DERIVED_FILE_DIR)/App-result.txt") + .build())))); + + ensureUpToDate(executer); + } + + @Override + protected String targetUnderTestName() { + return "App"; } @Nested class InputPathsField { @Test - void outOfDateWhenFileContentChange() throws IOException { - appendChangeToSwiftFile(testDirectory.resolve("App/AppDelegate.swift")); + void outOfDateWhenInputPathContentChanged() throws IOException { + appendChangeToSwiftFile(file("App/AppDelegate.swift")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenInputPathAdded() { + xcodeproj(groupUnderTest(children(add(ofGroup("NewFile.swift"))))); + xcodeproj(targetUnderTest(shellScriptBuildPhases(inputPaths(add("$(SRCROOT)/App/NewFile.swift"))))); + xcodeproj(run(() -> Files.write(file("App/NewFile.swift"), Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.CREATE))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } @Test - void outOfDateWhenNewFileEntry() throws IOException { - mutateProject(mainGroup(childNamed("App", asGroup(children(add(ofGroup("NewFile.swift"))))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(inputPaths(add("$(SRCROOT)/App/NewFile.swift"))))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); - Files.write(testDirectory.resolve("App/NewFile.swift"), Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + void ignoresDuplicatedInputPaths() { + xcodeproj(targetUnderTest(shellScriptBuildPhases(inputPaths(add("$(SRCROOT)/App/AppDelegate.swift"))))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), upToDate()); } @Test - @Disabled - void ignoresDuplicatedPaths() { - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(inputPaths(add("$(SRCROOT)/App/AppDelegate.swift"))))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void ignoresDuplicatedResolvedInputPaths() { + xcodeproj(targetUnderTest(shellScriptBuildPhases(inputPaths(add("$(SOURCE_ROOT)/App/AppDelegate.swift"))))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), upToDate()); + assertThat(targetUnderTestExecution(), upToDate()); } @Test - @Disabled - void ignoresPathsThatResolvesToDuplicatedFiles() { - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(inputPaths(add("$(SOURCE_ROOT)/App/AppDelegate.swift"))))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void ignoresInputPathsOrderingChanges() { + xcodeproj(targetUnderTest(shellScriptBuildPhases(inputPaths(shuffleOrdering())))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), upToDate()); + assertThat(targetUnderTestExecution(), upToDate()); } @Test - void outOfDateWhenFilesRemoved() { - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(inputPaths(removeFirst())))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenInputPathRemoved() { + xcodeproj(targetUnderTest(shellScriptBuildPhases(inputPaths(removeFirst())))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } } @Test void ignoresNewUnlinkedFile() throws IOException { - mutateProject(mainGroup(childNamed("App", asGroup(children(add(ofGroup("UnusedFile.swift"))))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); - Files.write(testDirectory.resolve("App/UnusedFile.swift"), Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + xcodeproj(groupUnderTest(children(add(ofGroup("UnusedFile.swift"))))); + Files.write(file("App/UnusedFile.swift"), Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), upToDate()); + assertThat(targetUnderTestExecution(), upToDate()); } @Test void ignoresChangesToBuildPhaseName() { - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(scriptPhaseName("Lint 'App' component")))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + xcodeproj(targetUnderTest(shellScriptBuildPhases(scriptPhaseName("Lint 'App' component")))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), upToDate()); + assertThat(targetUnderTestExecution(), upToDate()); } @Disabled("outputs are not yet tracked") @@ -120,20 +129,20 @@ void ignoresChangesToBuildPhaseName() { void outOfDateWhenOutputFileRemoved() throws IOException { delete(buildDirectory().resolve("tmp/AppDebug/derivedData/Build/Intermediates.noindex/UpToDateCheck.build/Debug/App.build/DerivedSources/App-result.txt")); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } @Test - void outOfDateWhenShellPathChange() { - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(shellPath("/bin/bash")))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenShellPathChanged() { + xcodeproj(targetUnderTest(shellScriptBuildPhases(shellPath("/bin/bash")))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } @Test - void outOfDateWhenShellScriptChange() { - mutateProject(targetNamed("App", buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(shellScript("echo \"less-dummy-result\" > \"$DERIVED_FILE_DIR/App-result.txt\"")))))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + void outOfDateWhenShellScriptChanged() { + xcodeproj(targetUnderTest(shellScriptBuildPhases(shellScript("echo \"less-dummy-result\" > \"$DERIVED_FILE_DIR/App-result.txt\"")))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXSourcesBuildPhaseFunctionalTests.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXSourcesBuildPhaseFunctionalTests.java index aff6591292..2a2dc6833b 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXSourcesBuildPhaseFunctionalTests.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckDetectsChangeToPBXSourcesBuildPhaseFunctionalTests.java @@ -15,22 +15,23 @@ */ package dev.nokee.buildadapter.xcode.uptodate; +import dev.nokee.xcode.objects.files.PBXReference; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Arrays; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asGroup; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.childNamed; import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.children; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mainGroup; -import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.files; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.referenceNameOrPath; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.removeIf; import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate; import static dev.nokee.internal.testing.GradleRunnerMatchers.upToDate; import static dev.nokee.xcode.objects.files.PBXFileReference.ofGroup; @@ -38,19 +39,69 @@ @EnabledOnOs(OS.MAC) class UpToDateCheckDetectsChangeToPBXSourcesBuildPhaseFunctionalTests extends UpToDateCheckSpec { - @Test - void outOfDateWhenInputSourceFileChange() throws IOException { - appendChangeToSwiftFile(testDirectory.resolve("App/ViewController.swift")); + @BeforeEach + void setup() throws IOException { + ensureUpToDate(executer); + } + + @Override + protected String targetUnderTestName() { + return "App"; + } + + @Nested + class FilesField { + @Test + void outOfDateWhenSourceFileChanged() throws IOException { + appendChangeToSwiftFile(file("App/ViewController.swift")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileAdded() throws IOException { + xcodeproj(groupUnderTest(children(add(ofGroup("OtherSource.swift"))))); + xcodeproj(targetUnderTest(sourcesBuildPhases(files(add(buildFileTo("OtherSource.swift")))))); + Files.write(file("App/OtherSource.swift"), Arrays.asList("// my new file")); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileRemoved() { + xcodeproj(targetUnderTest(sourcesBuildPhases(files(removeIf(it -> it.getFileRef().map(PBXReference.class::cast).filter(referenceNameOrPath("FileToRemove.swift")).isPresent()))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFileEntryDuplicated() { + xcodeproj(targetUnderTest(sourcesBuildPhases(files(add(buildFileTo("AppDelegate.swift")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenResolvedFileDuplicated() { + xcodeproj(alternateFileUnderTest("AppDelegate.swift")); + xcodeproj(targetUnderTest(sourcesBuildPhases(files(add(buildFileTo("alternate-AppDelegate.swift")))))); + + assertThat(targetUnderTestExecution(), outOfDate()); + } + + @Test + void outOfDateWhenFilesOrderingChanged() throws IOException { + xcodeproj(targetUnderTest(sourcesBuildPhases(files(shuffleOrdering())))); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), outOfDate()); + assertThat(targetUnderTestExecution(), outOfDate()); + } } @Test void ignoresNewUnlinkedSourceFiles() throws IOException { - mutateProject(mainGroup(childNamed("App", asGroup(children(add(ofGroup("UnusedFile.swift"))))))) - .accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); - Files.write(testDirectory.resolve("App/UnusedFile.swift"), Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + xcodeproj(groupUnderTest(children(add(ofGroup("UnusedFile.swift"))))); + Files.write(file("App/UnusedFile.swift"), Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); - assertThat(executer.build().task(":UpToDateCheck:AppDebug"), upToDate()); + assertThat(targetUnderTestExecution(), upToDate()); } } diff --git a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckSpec.java b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckSpec.java index a05b9523ea..1a417ed317 100644 --- a/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckSpec.java +++ b/subprojects/build-adapter-xcode/src/functionalTest/java/dev/nokee/buildadapter/xcode/uptodate/UpToDateCheckSpec.java @@ -15,21 +15,62 @@ */ package dev.nokee.buildadapter.xcode.uptodate; +import com.google.common.collect.ImmutableList; +import dev.gradleplugins.runnerkit.BuildTask; import dev.gradleplugins.runnerkit.GradleRunner; import dev.nokee.UpToDateCheck; import dev.nokee.internal.testing.junit.jupiter.ContextualGradleRunnerParameterResolver; +import dev.nokee.xcode.objects.PBXProject; +import dev.nokee.xcode.objects.buildphase.PBXBuildFile; +import dev.nokee.xcode.objects.buildphase.PBXBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXFrameworksBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXHeadersBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXResourcesBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXShellScriptBuildPhase; +import dev.nokee.xcode.objects.buildphase.PBXSourcesBuildPhase; +import dev.nokee.xcode.objects.files.PBXFileReference; +import dev.nokee.xcode.objects.files.PBXGroup; +import dev.nokee.xcode.objects.files.PBXSourceTree; +import dev.nokee.xcode.objects.targets.PBXTarget; +import lombok.val; import net.nokeedev.testing.junit.jupiter.io.TestDirectory; import net.nokeedev.testing.junit.jupiter.io.TestDirectoryExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.function.Executable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import static com.google.common.base.Predicates.instanceOf; +import static com.google.common.collect.MoreCollectors.onlyElement; import static dev.gradleplugins.buildscript.blocks.PluginsBlock.plugins; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asCopyFiles; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asFrameworks; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asGroup; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asHeaders; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asResources; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asShellScript; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.asSources; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.children; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mainGroup; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.matching; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.childNameOrPath; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.productsGroup; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetName; +import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targets; import static dev.nokee.internal.testing.GradleRunnerMatchers.skipped; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.everyItem; @@ -39,32 +80,105 @@ public abstract class UpToDateCheckSpec { GradleRunner executer; @TestDirectory Path testDirectory; + protected static UnaryOperator alternateBuiltProduct(String filename) { + return project -> { + PBXProject result = project; + val productsGroup = (PBXGroup) project.getMainGroup().getChildren().stream().filter(childNameOrPath("Products")).collect(onlyElement()); + val sourceFile = (PBXFileReference) productsGroup.getChildren().stream().filter(childNameOrPath(filename)).collect(onlyElement()); + + val builder = PBXFileReference.builder().sourceTree(PBXSourceTree.of("CONFIGURATION_BUILD_DIR")); + sourceFile.getPath().ifPresent(builder::path); + builder.name("alternate-" + filename); + val alternateFile = builder.build(); + + result = productsGroup(children(add(alternateFile))).apply(result); + return result; + }; + } + + static PBXBuildPhase aBuildPhase() { + return PBXCopyFilesBuildPhase.builder().destination(it -> it.resources("")).build(); + } + + protected UnaryOperator alternateFileUnderTest(String filename) { + return project -> { + PBXProject result = project; + val groupUnderTest = (PBXGroup) project.getMainGroup().getChildren().stream().filter(childNameOrPath(targetUnderTestName())).collect(onlyElement()); + val sourceFile = (PBXFileReference) groupUnderTest.getChildren().stream().filter(childNameOrPath(filename)).collect(onlyElement()); + + val builder = PBXFileReference.builder().sourceTree(PBXSourceTree.of("SOURCE_ROOT")); + builder.path(targetUnderTestName() + "/" + filename); + builder.name("alternate-" + filename); + val alternateFile = builder.build(); + + result = groupUnderTest(children(add(alternateFile))).apply(result); + return result; + }; + } + + + protected static BiFunction copyFilesBuildPhases(BiFunction action) { + return buildPhases(matching(instanceOf(PBXCopyFilesBuildPhase.class), asCopyFiles(action))); + } + + protected static BiFunction frameworksBuildPhases(BiFunction action) { + return buildPhases(matching(instanceOf(PBXFrameworksBuildPhase.class), asFrameworks(action))); + } + + protected static BiFunction headersBuildPhases(BiFunction action) { + return buildPhases(matching(instanceOf(PBXHeadersBuildPhase.class), asHeaders(action))); + } + + protected static BiFunction resourcesBuildPhases(BiFunction action) { + return buildPhases(matching(instanceOf(PBXResourcesBuildPhase.class), asResources(action))); + } + + protected static BiFunction sourcesBuildPhases(BiFunction action) { + return buildPhases(matching(instanceOf(PBXSourcesBuildPhase.class), asSources(action))); + } + + protected static BiFunction shellScriptBuildPhases(BiFunction action) { + return buildPhases(matching(instanceOf(PBXShellScriptBuildPhase.class), asShellScript(action))); + } + + protected static BiFunction, List> shuffleOrdering() { + return (self, values) -> { + assert values.size() > 1; + val result = ImmutableList.builder().add(values.get(values.size() - 1)).addAll(values.subList(0, values.size() - 1)).build(); + assert result.size() == values.size(); + return result; + }; + } + @BeforeEach - final void setup(GradleRunner runner) throws IOException { + void setup(GradleRunner runner) throws IOException { new UpToDateCheck().writeToProject(testDirectory); - setup(testDirectory.resolve("UpToDateCheck.xcodeproj")); plugins(it -> it.id("dev.nokee.xcode-build-adapter")).writeTo(testDirectory.resolve("settings.gradle")); - executer = configure(runner).withArgument("-Dsdk=macosx"); - executer.build(); - assertThat(executer.build().getTasks(), everyItem(skipped())); + executer = runner.withTasks(targetUnderTestName() + "Debug").withArgument("-Dsdk=macosx"); } - void setup(Path location) throws IOException {} - GradleRunner configure(GradleRunner runner) { - return runner.withTasks("AppDebug"); + protected String targetUnderTestName() { + return "ComponentUnderTest"; + } + + protected final BuildTask targetUnderTestExecution() { + return executer.build().task(":UpToDateCheck:" + targetUnderTestName() + "Debug"); } static void appendMeaningfulChangeToCFile(Path location) throws IOException { + assert location.getFileName().toString().endsWith(".c"); // Need to make a meaningful change so the final binary changes (this change will add a .data entry) Files.write(location, Arrays.asList("int value = 42;"), StandardOpenOption.WRITE, StandardOpenOption.APPEND); } static void appendChangeToCHeader(Path location) throws IOException { + assert location.getFileName().toString().endsWith(".h"); Files.write(location, Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.APPEND); } static void appendChangeToSwiftFile(Path location) throws IOException { + assert location.getFileName().toString().endsWith(".swift"); Files.write(location, Arrays.asList("// Some additional line"), StandardOpenOption.WRITE, StandardOpenOption.APPEND); } @@ -83,6 +197,11 @@ static void writeColorSet(Path location) throws IOException { "}"), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW); } + static void ensureUpToDate(GradleRunner executer) { + executer.build(); + assertThat(executer.build().getTasks(), everyItem(skipped())); + } + Path appDebugProductsDirectory() { return buildDirectory().resolve("derivedData/App/Build/Products/Debug"); } @@ -90,4 +209,49 @@ Path appDebugProductsDirectory() { Path buildDirectory() { return testDirectory.resolve("build/subprojects/UpToDateCheck-1jnf0zhg14ui3"); } + + protected static Function run(Executable executable) { + return it -> { + try { + executable.execute(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + return it; + }; + } + + protected void xcodeproj(Function action) { + mutateProject(action).accept(testDirectory.resolve("UpToDateCheck.xcodeproj")); + } + + protected UnaryOperator targetUnderTest(BiFunction action) { + return targets(matching(targetName(targetUnderTestName()), action)); + } + + protected UnaryOperator groupUnderTest(BiFunction action) { + return mainGroup(children(matching(childNameOrPath(targetUnderTestName()), asGroup(action)))); + } + + protected Function buildFileTo(String name) { + return self -> { + val appGroup = (PBXGroup) self.getMainGroup().getChildren().stream().filter(childNameOrPath(targetUnderTestName())).collect(onlyElement()); + val fileRef = (PBXFileReference) appGroup.getChildren().stream().filter(childNameOrPath(name)).collect(onlyElement()); + return PBXBuildFile.builder().fileRef(fileRef).build(); + }; + } + + protected Function buildFileTo(String name, Consumer action) { + return self -> { + val appGroup = (PBXGroup) self.getMainGroup().getChildren().stream().filter(childNameOrPath(targetUnderTestName())).collect(onlyElement()); + val fileRef = (PBXFileReference) appGroup.getChildren().stream().filter(childNameOrPath(name)).collect(onlyElement()); + val builder = PBXBuildFile.builder(); + action.accept(builder); + return builder.fileRef(fileRef).build(); + }; + } + + protected final Path file(String path) { + return testDirectory.resolve(path); + } } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputObjectSpecEncoder.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtInputEncoder.java similarity index 58% rename from subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputObjectSpecEncoder.java rename to subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtInputEncoder.java index 1b24bb43ab..bf7a34b74c 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputObjectSpecEncoder.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtInputEncoder.java @@ -17,17 +17,42 @@ import dev.nokee.xcode.project.ValueEncoder; import lombok.EqualsAndHashCode; +import org.gradle.api.tasks.Input; @EqualsAndHashCode -public final class InputObjectSpecEncoder implements ValueEncoder { +public final class AtInputEncoder implements ValueEncoder { private final ValueEncoder delegate; - public InputObjectSpecEncoder(ValueEncoder delegate) { + public AtInputEncoder(ValueEncoder delegate) { this.delegate = delegate; } @Override public XCBuildSpec encode(IN value, Context context) { - return new InputObjectSpec(delegate.encode(value, context)); + return new Spec(delegate.encode(value, context)); + } + + @EqualsAndHashCode + public static final class Spec implements XCBuildSpec, XCBuildPlan { + private final Object value; + + public Spec(Object value) { + this.value = value; + } + + @Input + public Object getValue() { + return value; + } + + @Override + public XCBuildPlan resolve(ResolveContext context) { + return this; // already resolved + } + + @Override + public void visit(Visitor visitor) { + visitor.visitValue(value); + } } } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/MapSpecEncoder.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtInputFilesEncoder.java similarity index 56% rename from subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/MapSpecEncoder.java rename to subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtInputFilesEncoder.java index 5b02e91871..3c5c0353cb 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/MapSpecEncoder.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtInputFilesEncoder.java @@ -15,23 +15,37 @@ */ package dev.nokee.buildadapter.xcode.internal.plugins.specs; -import dev.nokee.xcode.project.Encodeable; import dev.nokee.xcode.project.ValueEncoder; import lombok.EqualsAndHashCode; - -import java.util.Map; +import org.gradle.api.tasks.InputFiles; @EqualsAndHashCode -public final class MapSpecEncoder implements ValueEncoder { - private final ValueEncoder delegate; +public final class AtInputFilesEncoder implements ValueEncoder { + private final ValueEncoder delegate; - public MapSpecEncoder(ValueEncoder delegate) { + public AtInputFilesEncoder(ValueEncoder delegate) { this.delegate = delegate; } @Override - @SuppressWarnings("unchecked") public XCBuildSpec encode(IN value, Context context) { - return new NestedMapSpec((Map) context.encodeBycopyObject(delegate.encode(value, context)).asMap()); + final XCBuildSpec references = delegate.encode(value, context); + return new XCBuildSpec() { + @Override + public XCBuildPlan resolve(ResolveContext context) { + final XCBuildPlan result = references.resolve(context); + return new XCBuildPlan() { + @InputFiles + public Object getValue() { + return result; + } + + @Override + public String toString() { + return result.toString(); + } + }; + } + }; } } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoder.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoder.java new file mode 100644 index 0000000000..cbfc6b9e15 --- /dev/null +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoder.java @@ -0,0 +1,77 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dev.nokee.buildadapter.xcode.internal.plugins.specs; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import dev.nokee.xcode.project.ValueEncoder; +import lombok.EqualsAndHashCode; +import lombok.val; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collector; + +@EqualsAndHashCode +public final class AtNestedCollectionEncoder implements ValueEncoder { + private final Collector> collector; + private final ValueEncoder, IN> delegate; + + public AtNestedCollectionEncoder(Collector> collector, ValueEncoder, IN> delegate) { + this.collector = collector; + this.delegate = delegate; + } + + @Override + public XCBuildSpec encode(IN value, Context context) { + return new Spec(collector, delegate.encode(value, context)); + } + + public static AtNestedCollectionEncoder atNestedSet(ValueEncoder, IN> encoder) { + return new AtNestedCollectionEncoder<>(ImmutableSet.toImmutableSet(), encoder); + } + + public static AtNestedCollectionEncoder atNestedList(ValueEncoder, IN> encoder) { + return new AtNestedCollectionEncoder<>(ImmutableList.toImmutableList(), encoder); + } + + @EqualsAndHashCode + public static class Spec implements XCBuildSpec { + private final Collector> collector; + private final List specs; + + public Spec(Collector> collector, List specs) { + this.collector = collector; + this.specs = specs; + } + + @Override + public XCBuildPlan resolve(ResolveContext context) { + val result = specs.stream().map(it -> it.resolve(context)).collect(collector); + return new CompositeXCBuildPlan<>(result); + } + + @Override + public void visit(Visitor visitor) { + for (int i = 0; i < specs.size(); i++) { + XCBuildSpec it = specs.get(i); + visitor.enterContext(String.valueOf(i)); + it.visit(visitor); + visitor.exitContext(); + } + } + } +} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoder.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoder.java new file mode 100644 index 0000000000..eaa186b5d4 --- /dev/null +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoder.java @@ -0,0 +1,137 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dev.nokee.buildadapter.xcode.internal.plugins.specs; + +import dev.nokee.xcode.project.Encodeable; +import dev.nokee.xcode.project.ValueEncoder; +import lombok.EqualsAndHashCode; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@EqualsAndHashCode +public final class AtNestedMapEncoder implements ValueEncoder { + private final ValueEncoder delegate; + + public AtNestedMapEncoder(ValueEncoder delegate) { + this.delegate = delegate; + } + + @Override + @SuppressWarnings("unchecked") + public XCBuildSpec encode(IN value, Context context) { + return new Spec((Map) context.encodeBycopyObject(delegate.encode(value, context)).asMap()); + } + + @EqualsAndHashCode + public static final class Spec implements XCBuildSpec { + private final Map values; + + public Spec(Map values) { + this.values = values; + } + + @Override + public XCBuildPlan resolve(ResolveContext context) { + final Map values = new HashMap<>(this.values.size()); + for (Map.Entry entry : this.values.entrySet()) { + values.put(entry.getKey(), entry.getValue().resolve(context)); + } + return new MapXCBuildPlan(values); + } + + @Override + public void visit(Visitor visitor) { + values.forEach((k, v) -> { + visitor.enterContext(k); + v.visit(visitor); + visitor.exitContext(); + }); + } + + // We implement a Map so Gradle can present the change in a much nicer way + @EqualsAndHashCode + private static final class MapXCBuildPlan implements XCBuildPlan, Map { + private final Map values; + + public MapXCBuildPlan(Map values) { + this.values = values; + } + + @Override + public int size() { + return values.size(); + } + + @Override + public boolean isEmpty() { + return values.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return values.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return values.containsValue(value); + } + + @Override + public XCBuildPlan get(Object key) { + return values.get(key); + } + + @Override + public XCBuildPlan put(String key, XCBuildPlan value) { + throw new UnsupportedOperationException(); + } + + @Override + public XCBuildPlan remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Set keySet() { + return values.keySet(); + } + + @Override + public Collection values() { + return values.values(); + } + + @Override + public Set> entrySet() { + return values.entrySet(); + } + } + } +} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputObjectSpec.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/CompositeXCBuildPlan.java similarity index 65% rename from subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputObjectSpec.java rename to subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/CompositeXCBuildPlan.java index acd6866767..0e8ffff9f7 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputObjectSpec.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/CompositeXCBuildPlan.java @@ -16,28 +16,24 @@ package dev.nokee.buildadapter.xcode.internal.plugins.specs; import lombok.EqualsAndHashCode; -import org.gradle.api.tasks.Input; -@EqualsAndHashCode -public final class InputObjectSpec implements XCBuildSpec, XCBuildPlan { - private final Object value; +import java.util.Iterator; - InputObjectSpec(Object value) { - this.value = value; - } +@EqualsAndHashCode +public final class CompositeXCBuildPlan implements XCBuildPlan, Iterable { + private final Iterable values; - @Input - public Object getValue() { - return value; + public CompositeXCBuildPlan(Iterable values) { + this.values = values; } @Override - public XCBuildPlan resolve(ResolveContext context) { - return this; // already resolved + public Iterator iterator() { + return values.iterator(); } @Override - public void visit(Visitor visitor) { - visitor.visitValue(value); + public String toString() { + return values.toString(); } } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpecEncoder.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/FileSystemLocationEncoder.java similarity index 56% rename from subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpecEncoder.java rename to subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/FileSystemLocationEncoder.java index ba1dcae317..b067a3c12c 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpecEncoder.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/FileSystemLocationEncoder.java @@ -18,17 +18,38 @@ import dev.nokee.xcode.objects.files.PBXReference; import dev.nokee.xcode.project.ValueEncoder; import lombok.EqualsAndHashCode; +import org.gradle.api.file.FileCollection; @EqualsAndHashCode -public final class InputLocationSpecEncoder implements ValueEncoder { +public final class FileSystemLocationEncoder implements ValueEncoder { private final ValueEncoder delegate; - public InputLocationSpecEncoder(ValueEncoder delegate) { + public FileSystemLocationEncoder(ValueEncoder delegate) { this.delegate = delegate; } @Override public XCBuildSpec encode(IN value, Context context) { - return new InputLocationSpec(delegate.encode(value, context)); + return new Spec(delegate.encode(value, context)); + } + + @EqualsAndHashCode + public static final class Spec implements XCBuildSpec { + private final PBXReference reference; + + public Spec(PBXReference reference) { + this.reference = reference; + } + + @Override + public XCBuildPlan resolve(ResolveContext context) { + final FileCollection locations = context.inputs(reference); + return new CompositeXCBuildPlan<>(locations); + } + + @Override + public void visit(Visitor visitor) { + visitor.visitValue(reference.toString()); // TODO: Proper tostring + } } } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpec.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpec.java deleted file mode 100644 index b5fb1fc99e..0000000000 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpec.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.nokee.buildadapter.xcode.internal.plugins.specs; - -import dev.nokee.xcode.objects.files.PBXReference; -import lombok.EqualsAndHashCode; -import org.gradle.api.file.FileCollection; -import org.gradle.api.tasks.InputFiles; - -@EqualsAndHashCode -public final class InputLocationSpec implements XCBuildSpec { - private final PBXReference reference; - - InputLocationSpec(PBXReference reference) { - this.reference = reference; - } - - @Override - public XCBuildPlan resolve(ResolveContext context) { - final FileCollection locations = context.inputs(reference); - return new XCBuildPlan() { - @InputFiles - public FileCollection getInputFiles() { - return locations; - } - }; - } - - @Override - public void visit(Visitor visitor) { - visitor.visitValue(reference.toString()); // TODO: Proper tostring - } -} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoder.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoder.java deleted file mode 100644 index 6ed752c721..0000000000 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoder.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.nokee.buildadapter.xcode.internal.plugins.specs; - -import dev.nokee.xcode.project.ValueEncoder; -import lombok.EqualsAndHashCode; - -import java.util.List; - -@EqualsAndHashCode -public final class ListSpecEncoder implements ValueEncoder { - private final ValueEncoder, IN> delegate; - - public ListSpecEncoder(ValueEncoder, IN> delegate) { - this.delegate = delegate; - } - - @Override - public XCBuildSpec encode(IN value, Context context) { - return new NestedListSpec(delegate.encode(value, context)); - } -} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedListSpec.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedListSpec.java deleted file mode 100644 index 41090ddd49..0000000000 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedListSpec.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.nokee.buildadapter.xcode.internal.plugins.specs; - -import lombok.EqualsAndHashCode; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -@EqualsAndHashCode -public final class NestedListSpec implements XCBuildSpec { - private final List specs; - - NestedListSpec(List specs) { - this.specs = specs; - } - - @Override - public XCBuildPlan resolve(ResolveContext context) { - final List values = new ArrayList<>(specs.size()); - for (XCBuildSpec spec : specs) { - values.add(spec.resolve(context)); - } - return new CompositeXCBuildPlan(values); - } - - @Override - public void visit(Visitor visitor) { - for (int i = 0; i < specs.size(); i++) { - XCBuildSpec it = specs.get(i); - visitor.enterContext(String.valueOf(i)); - it.visit(visitor); - visitor.exitContext(); - } - } - - private static final class CompositeXCBuildPlan implements XCBuildPlan, Iterable { - private final List values; - - public CompositeXCBuildPlan(List values) { - this.values = values; - } - - @Override - public Iterator iterator() { - return values.iterator(); - } - } -} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedMapSpec.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedMapSpec.java deleted file mode 100644 index 244c2fa6af..0000000000 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/NestedMapSpec.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.nokee.buildadapter.xcode.internal.plugins.specs; - -import lombok.EqualsAndHashCode; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -@EqualsAndHashCode -public final class NestedMapSpec implements XCBuildSpec { - private final Map values; - - public NestedMapSpec(Map values) { - this.values = values; - } - - @Override - public XCBuildPlan resolve(ResolveContext context) { - final Map values = new HashMap<>(this.values.size()); - for (Map.Entry entry : this.values.entrySet()) { - values.put(entry.getKey(), entry.getValue().resolve(context)); - } - return new MapXCBuildPlan(values); - } - - @Override - public void visit(Visitor visitor) { - values.forEach((k, v) -> { - visitor.enterContext(k); - v.visit(visitor); - visitor.exitContext(); - }); - } - - // We implement a Map so Gradle can present the change in a much nicer way - private static final class MapXCBuildPlan implements XCBuildPlan, Map { - private final Map values; - - public MapXCBuildPlan(Map values) { - this.values = values; - } - - @Override - public int size() { - return values.size(); - } - - @Override - public boolean isEmpty() { - return values.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return values.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return values.containsValue(value); - } - - @Override - public XCBuildPlan get(Object key) { - return values.get(key); - } - - @Override - public XCBuildPlan put(String key, XCBuildPlan value) { - throw new UnsupportedOperationException(); - } - - @Override - public XCBuildPlan remove(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public void putAll(Map m) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } - - @Override - public Set keySet() { - return values.keySet(); - } - - @Override - public Collection values() { - return values.values(); - } - - @Override - public Set> entrySet() { - return values.entrySet(); - } - } -} diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCoders.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCoders.java index b105bbb331..c093ac6240 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCoders.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCoders.java @@ -65,7 +65,7 @@ public final class XCBuildSpecCodingKeyCoders implements CodingKeyCoders { private static final Map> coders = Collections.unmodifiableMap(new HashMap>() {{ - put(ISA, forKey("isa", ofInputString())); + put(ISA, forKey("isa", atInput(ofString()))); // PBXAggregateTarget put(CodeablePBXAggregateTarget.CodingKeys.name, null); @@ -77,7 +77,7 @@ public final class XCBuildSpecCodingKeyCoders implements CodingKeyCoders { put(CodeablePBXAggregateTarget.CodingKeys.dependencies, null); // PBXBuildFile - put(CodeablePBXBuildFile.CodingKeys.fileRef, forKey("fileRef", ofInputLocation())); + put(CodeablePBXBuildFile.CodingKeys.fileRef, forKey("fileRef", atInputFiles(ofLocation()))); put(CodeablePBXBuildFile.CodingKeys.settings, null); put(CodeablePBXBuildFile.CodingKeys.productRef, null); @@ -112,8 +112,8 @@ public final class XCBuildSpecCodingKeyCoders implements CodingKeyCoders { put(CodeablePBXLegacyTarget.CodingKeys.dependencies, null); put(CodeablePBXLegacyTarget.CodingKeys.buildConfigurationList, null); put(CodeablePBXLegacyTarget.CodingKeys.buildPhases, null); // legacy target are not allowed to have build phases - put(CodeablePBXLegacyTarget.CodingKeys.buildArgumentsString, forKey("buildArgumentsString", ofInputString())); - put(CodeablePBXLegacyTarget.CodingKeys.buildToolPath, forKey("buildToolPath", ofInputString())); + put(CodeablePBXLegacyTarget.CodingKeys.buildArgumentsString, forKey("buildArgumentsString", atInput(ofString()))); + put(CodeablePBXLegacyTarget.CodingKeys.buildToolPath, forKey("buildToolPath", atInput(ofString()))); put(CodeablePBXLegacyTarget.CodingKeys.buildWorkingDirectory, null); put(CodeablePBXLegacyTarget.CodingKeys.passBuildSettingsInEnvironment, null); @@ -148,9 +148,9 @@ public final class XCBuildSpecCodingKeyCoders implements CodingKeyCoders { // PBXShellScriptBuildPhase put(CodeablePBXShellScriptBuildPhase.CodingKeys.name, null); put(CodeablePBXShellScriptBuildPhase.CodingKeys.files, null); // shell script uses input*/output* to check up-to-date - put(CodeablePBXShellScriptBuildPhase.CodingKeys.shellPath, forKey("shellPath", ofInputString())); - put(CodeablePBXShellScriptBuildPhase.CodingKeys.shellScript, forKey("shellScript", ofInputString())); - put(CodeablePBXShellScriptBuildPhase.CodingKeys.inputPaths, forKey("inputPaths", list(ofInputLocation()))); + put(CodeablePBXShellScriptBuildPhase.CodingKeys.shellPath, forKey("shellPath", atInput(ofString()))); + put(CodeablePBXShellScriptBuildPhase.CodingKeys.shellScript, forKey("shellScript", atInput(ofString()))); + put(CodeablePBXShellScriptBuildPhase.CodingKeys.inputPaths, forKey("inputPaths", atInputFiles(set(ofLocation())))); put(CodeablePBXShellScriptBuildPhase.CodingKeys.inputFileListPaths, null); put(CodeablePBXShellScriptBuildPhase.CodingKeys.outputPaths, null); put(CodeablePBXShellScriptBuildPhase.CodingKeys.outputFileListPaths, null); @@ -235,18 +235,30 @@ private static FieldCoder forKey(String key, ValueEncoder valueCode } private static ValueEncoder of(Class type) { - return new MapSpecEncoder<>(new NoOpEncoder<>()); + return new AtNestedMapEncoder<>(new NoOpEncoder<>()); } - private static ValueEncoder ofInputLocation() { - return new InputLocationSpecEncoder<>(new NormalizeStringAsPBXReferenceEncoder(new NormalizePBXBuildFileFileReferenceAsPBXReferenceEncoder(new ThrowingValueEncoder<>()))); + private static ValueEncoder ofLocation() { + return new FileSystemLocationEncoder<>(new NormalizeStringAsPBXReferenceEncoder(new NormalizePBXBuildFileFileReferenceAsPBXReferenceEncoder(new ThrowingValueEncoder<>()))); } private static ValueEncoder> list(ValueEncoder elementEncoder) { - return new ListSpecEncoder<>(new ListEncoder<>(elementEncoder)); + return AtNestedCollectionEncoder.atNestedList(new ListEncoder<>(elementEncoder)); } - private static ValueEncoder ofInputString() { - return new InputObjectSpecEncoder<>(new StringEncoder<>(new NoOpEncoder<>())); + private static ValueEncoder atInputFiles(ValueEncoder encoder) { + return new AtInputFilesEncoder<>(encoder); + } + + private static ValueEncoder atInput(ValueEncoder encoder) { + return new AtInputEncoder<>(encoder); + } + + private static ValueEncoder ofString() { + return new StringEncoder<>(new NoOpEncoder<>()); + } + + private static ValueEncoder> set(ValueEncoder elementEncoder) { + return AtNestedCollectionEncoder.atNestedSet(new ListEncoder<>(elementEncoder)); } } diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCBuildSpecLoader.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCBuildSpecLoader.java index b0dc62da6b..e46c675004 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCBuildSpecLoader.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCBuildSpecLoader.java @@ -15,7 +15,7 @@ */ package dev.nokee.xcode; -import dev.nokee.buildadapter.xcode.internal.plugins.specs.NestedMapSpec; +import dev.nokee.buildadapter.xcode.internal.plugins.specs.AtNestedMapEncoder; import dev.nokee.buildadapter.xcode.internal.plugins.specs.XCBuildSpec; import dev.nokee.buildadapter.xcode.internal.plugins.specs.XCBuildSpecCodingKeyCoders; import dev.nokee.xcode.objects.targets.PBXTarget; @@ -57,7 +57,7 @@ private static final class MyEncodeContext implements Encodeable.EncodeContext { private final Map map = new LinkedHashMap<>(); public XCBuildSpec value() { - return new NestedMapSpec(map); + return new AtNestedMapEncoder.Spec(map); } @Override diff --git a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCFileReferencesLoader.java b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCFileReferencesLoader.java index 7cf98253f0..4ea6754eab 100644 --- a/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCFileReferencesLoader.java +++ b/subprojects/build-adapter-xcode/src/main/java/dev/nokee/xcode/XCFileReferencesLoader.java @@ -135,7 +135,7 @@ public XCFileReference get(PBXReference fileRef) { return XCFileReference.fromBuildSetting(fileRef.getSourceTree().toString(), pathOf(fileRef)); } } - return Objects.requireNonNull(fileRefs.get(fileRef)); + return Objects.requireNonNull(fileRefs.get(fileRef), () -> "no reference for '" + fileRef + "'"); } public static Builder builder() { diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/App/FileToRemove.swift b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/App/FileToRemove.swift new file mode 100644 index 0000000000..ea412062d4 --- /dev/null +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/App/FileToRemove.swift @@ -0,0 +1,8 @@ +// +// FileToRemove.swift +// App +// +// Created by Daniel Lacasse on 2023-03-18. +// + +import Foundation diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.h b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.h new file mode 100644 index 0000000000..4b1e7158ba --- /dev/null +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.h @@ -0,0 +1,18 @@ +// +// Bar.h +// Bar +// +// Created by Daniel Lacasse on 2023-03-16. +// + +#import + +//! Project version number for Bar. +FOUNDATION_EXPORT double BarVersionNumber; + +//! Project version string for Bar. +FOUNDATION_EXPORT const unsigned char BarVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.m b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.m new file mode 100644 index 0000000000..22c7c240b3 --- /dev/null +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Bar/Bar.m @@ -0,0 +1,8 @@ +// +// Bar.m +// Bar +// +// Created by Daniel Lacasse on 2023-03-16. +// + +#import diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.c b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.c deleted file mode 100644 index 60e163d2a2..0000000000 --- a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.c +++ /dev/null @@ -1,8 +0,0 @@ -// -// Common.c -// Common -// -// Created by Daniel Lacasse on 2023-03-06. -// - -#include diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.docc/Common.md b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.docc/Common.md deleted file mode 100755 index fe40262f8d..0000000000 --- a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.docc/Common.md +++ /dev/null @@ -1,13 +0,0 @@ -# ``Common`` - -Summary - -## Overview - -Text - -## Topics - -### Group - -- ``Symbol`` \ No newline at end of file diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.h b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.h deleted file mode 100644 index c769dc687d..0000000000 --- a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Common/Common.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Common.h -// Common -// -// Created by Daniel Lacasse on 2023-03-06. -// - -#import - -//! Project version number for Common. -FOUNDATION_EXPORT double CommonVersionNumber; - -//! Project version string for Common. -FOUNDATION_EXPORT const unsigned char CommonVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/CommonTests/CommonTests.swift b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/CommonTests/CommonTests.swift deleted file mode 100644 index d4fdbee552..0000000000 --- a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/CommonTests/CommonTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// CommonTests.swift -// CommonTests -// -// Created by Daniel Lacasse on 2023-03-06. -// - -import XCTest -@testable import Common - -final class CommonTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.h b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.h new file mode 100644 index 0000000000..547fbdb630 --- /dev/null +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.h @@ -0,0 +1,18 @@ +// +// Foo.h +// Foo +// +// Created by Daniel Lacasse on 2023-03-16. +// + +#import + +//! Project version number for Foo. +FOUNDATION_EXPORT double FooVersionNumber; + +//! Project version string for Foo. +FOUNDATION_EXPORT const unsigned char FooVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.swift b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.swift new file mode 100644 index 0000000000..e7eb17c63e --- /dev/null +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/Foo/Foo.swift @@ -0,0 +1,8 @@ +// +// Foo.swift +// Foo +// +// Created by Daniel Lacasse on 2023-03-16. +// + +import Foundation diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/project.pbxproj b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/project.pbxproj index 6063662e77..4110e4acf9 100644 --- a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/project.pbxproj +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/project.pbxproj @@ -7,25 +7,19 @@ objects = { /* Begin PBXAggregateTarget section */ - 65FF4C9D29BF0402000D5657 /* Aggregate */ = { + 65FF4D2829C31A99000D5657 /* AppAggregate */ = { isa = PBXAggregateTarget; - buildConfigurationList = 65FF4C9E29BF0402000D5657 /* Build configuration list for PBXAggregateTarget "Aggregate" */; + buildConfigurationList = 65FF4D2929C31A99000D5657 /* Build configuration list for PBXAggregateTarget "AppAggregate" */; buildPhases = ( - 65FF4CA529BF0783000D5657 /* Empty Copy Files Phase */, ); dependencies = ( ); - name = Aggregate; - productName = Aggregate; + name = AppAggregate; + productName = AppAggregate; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 6550D1F229B644710026F169 /* Common.docc in Sources */ = {isa = PBXBuildFile; fileRef = 6550D1F129B644710026F169 /* Common.docc */; }; - 6550D1F829B644710026F169 /* Common.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6550D1EE29B644710026F169 /* Common.framework */; }; - 6550D1FF29B644710026F169 /* CommonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6550D1FE29B644710026F169 /* CommonTests.swift */; }; - 6550D20029B644710026F169 /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 6550D1F029B644710026F169 /* Common.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 65FF4C6829B6664B000D5657 /* Common.c in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4C6729B6664B000D5657 /* Common.c */; }; 65FF4C7329B74B8A000D5657 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4C7229B74B8A000D5657 /* AppDelegate.swift */; }; 65FF4C7529B74B8A000D5657 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4C7429B74B8A000D5657 /* ViewController.swift */; }; 65FF4C7729B74B8B000D5657 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65FF4C7629B74B8B000D5657 /* Assets.xcassets */; }; @@ -33,16 +27,14 @@ 65FF4C8529B74B8C000D5657 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4C8429B74B8C000D5657 /* AppTests.swift */; }; 65FF4C8F29B74B8C000D5657 /* AppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4C8E29B74B8C000D5657 /* AppUITests.swift */; }; 65FF4C9129B74B8C000D5657 /* AppUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4C9029B74B8C000D5657 /* AppUITestsLaunchTests.swift */; }; + 65FF4D0B29C31A25000D5657 /* Foo.h in Headers */ = {isa = PBXBuildFile; fileRef = 65FF4D0A29C31A25000D5657 /* Foo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 65FF4D1C29C31A2F000D5657 /* Bar.h in Headers */ = {isa = PBXBuildFile; fileRef = 65FF4D1B29C31A2F000D5657 /* Bar.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 65FF4D2529C31A48000D5657 /* Foo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4D2429C31A48000D5657 /* Foo.swift */; }; + 65FF4D2729C31A5F000D5657 /* Bar.m in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4D2629C31A5F000D5657 /* Bar.m */; }; + 65FF4D3829C5DD49000D5657 /* FileToRemove.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF4D3729C5DD49000D5657 /* FileToRemove.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 6550D1F929B644710026F169 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6550D18029B641900026F169 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 6550D1ED29B644710026F169; - remoteInfo = Common; - }; 65FF4C8129B74B8C000D5657 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 6550D18029B641900026F169 /* Project object */; @@ -60,35 +52,19 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 65FF4C9C29BF0373000D5657 /* Empty Copy Files Phase */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 7; - files = ( - ); - name = "Empty Copy Files Phase"; - runOnlyForDeploymentPostprocessing = 0; - }; - 65FF4CA529BF0783000D5657 /* Empty Copy Files Phase */ = { + 65FF4D3329C32D27000D5657 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; - dstSubfolderSpec = 7; + dstSubfolderSpec = 10; files = ( ); - name = "Empty Copy Files Phase"; + name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 6550D1EE29B644710026F169 /* Common.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Common.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6550D1F029B644710026F169 /* Common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = ""; }; - 6550D1F129B644710026F169 /* Common.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Common.docc; sourceTree = ""; }; - 6550D1F729B644710026F169 /* CommonTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CommonTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 6550D1FE29B644710026F169 /* CommonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonTests.swift; sourceTree = ""; }; - 65FF4C6729B6664B000D5657 /* Common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = Common.c; sourceTree = ""; }; 65FF4C7029B74B8A000D5657 /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; }; 65FF4C7229B74B8A000D5657 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 65FF4C7429B74B8A000D5657 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -100,39 +76,46 @@ 65FF4C8A29B74B8C000D5657 /* AppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 65FF4C8E29B74B8C000D5657 /* AppUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUITests.swift; sourceTree = ""; }; 65FF4C9029B74B8C000D5657 /* AppUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUITestsLaunchTests.swift; sourceTree = ""; }; + 65FF4D0829C31A25000D5657 /* Foo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Foo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 65FF4D0A29C31A25000D5657 /* Foo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Foo.h; sourceTree = ""; }; + 65FF4D1929C31A2F000D5657 /* Bar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Bar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 65FF4D1B29C31A2F000D5657 /* Bar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Bar.h; sourceTree = ""; }; + 65FF4D2429C31A48000D5657 /* Foo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Foo.swift; sourceTree = ""; }; + 65FF4D2629C31A5F000D5657 /* Bar.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Bar.m; sourceTree = ""; }; + 65FF4D3229C31ADC000D5657 /* makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = makefile; sourceTree = ""; }; + 65FF4D3729C5DD49000D5657 /* FileToRemove.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileToRemove.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 6550D1EB29B644710026F169 /* Frameworks */ = { + 65FF4C6D29B74B8A000D5657 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 6550D1F429B644710026F169 /* Frameworks */ = { + 65FF4C7D29B74B8B000D5657 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6550D1F829B644710026F169 /* Common.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C6D29B74B8A000D5657 /* Frameworks */ = { + 65FF4C8729B74B8C000D5657 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C7D29B74B8B000D5657 /* Frameworks */ = { + 65FF4D0529C31A25000D5657 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C8729B74B8C000D5657 /* Frameworks */ = { + 65FF4D1629C31A2F000D5657 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -145,11 +128,12 @@ 6550D17F29B641900026F169 = { isa = PBXGroup; children = ( + 65FF4D3229C31ADC000D5657 /* makefile */, 65FF4C7129B74B8A000D5657 /* App */, 65FF4C8329B74B8C000D5657 /* AppTests */, 65FF4C8D29B74B8C000D5657 /* AppUITests */, - 6550D1EF29B644710026F169 /* Common */, - 6550D1FD29B644710026F169 /* CommonTests */, + 65FF4D0929C31A25000D5657 /* Foo */, + 65FF4D1A29C31A2F000D5657 /* Bar */, 6550D18B29B644320026F169 /* Products */, 6550D20C29B644BC0026F169 /* Frameworks */, ); @@ -158,33 +142,15 @@ 6550D18B29B644320026F169 /* Products */ = { isa = PBXGroup; children = ( - 6550D1EE29B644710026F169 /* Common.framework */, - 6550D1F729B644710026F169 /* CommonTests.xctest */, 65FF4C7029B74B8A000D5657 /* App.app */, 65FF4C8029B74B8B000D5657 /* AppTests.xctest */, 65FF4C8A29B74B8C000D5657 /* AppUITests.xctest */, + 65FF4D0829C31A25000D5657 /* Foo.framework */, + 65FF4D1929C31A2F000D5657 /* Bar.framework */, ); name = Products; sourceTree = ""; }; - 6550D1EF29B644710026F169 /* Common */ = { - isa = PBXGroup; - children = ( - 6550D1F029B644710026F169 /* Common.h */, - 6550D1F129B644710026F169 /* Common.docc */, - 65FF4C6729B6664B000D5657 /* Common.c */, - ); - path = Common; - sourceTree = ""; - }; - 6550D1FD29B644710026F169 /* CommonTests */ = { - isa = PBXGroup; - children = ( - 6550D1FE29B644710026F169 /* CommonTests.swift */, - ); - path = CommonTests; - sourceTree = ""; - }; 6550D20C29B644BC0026F169 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -200,6 +166,7 @@ 65FF4C7629B74B8B000D5657 /* Assets.xcassets */, 65FF4C7829B74B8B000D5657 /* Main.storyboard */, 65FF4C7B29B74B8B000D5657 /* App.entitlements */, + 65FF4D3729C5DD49000D5657 /* FileToRemove.swift */, ); path = App; sourceTree = ""; @@ -221,72 +188,62 @@ path = AppUITests; sourceTree = ""; }; + 65FF4D0929C31A25000D5657 /* Foo */ = { + isa = PBXGroup; + children = ( + 65FF4D0A29C31A25000D5657 /* Foo.h */, + 65FF4D2429C31A48000D5657 /* Foo.swift */, + ); + path = Foo; + sourceTree = ""; + }; + 65FF4D1A29C31A2F000D5657 /* Bar */ = { + isa = PBXGroup; + children = ( + 65FF4D1B29C31A2F000D5657 /* Bar.h */, + 65FF4D2629C31A5F000D5657 /* Bar.m */, + ); + path = Bar; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 6550D1E929B644710026F169 /* Headers */ = { + 65FF4D0329C31A25000D5657 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 6550D20029B644710026F169 /* Common.h in Headers */, + 65FF4D0B29C31A25000D5657 /* Foo.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 65FF4D1429C31A2F000D5657 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 65FF4D1C29C31A2F000D5657 /* Bar.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXLegacyTarget section */ - 65FF4CA129BF05DE000D5657 /* Legacy */ = { + 65FF4D2C29C31AA6000D5657 /* AppLegacy */ = { isa = PBXLegacyTarget; buildArgumentsString = "$(ACTION)"; - buildConfigurationList = 65FF4CA229BF05DE000D5657 /* Build configuration list for PBXLegacyTarget "Legacy" */; + buildConfigurationList = 65FF4D2D29C31AA7000D5657 /* Build configuration list for PBXLegacyTarget "AppLegacy" */; buildPhases = ( ); buildToolPath = /usr/bin/make; dependencies = ( ); - name = Legacy; + name = AppLegacy; passBuildSettingsInEnvironment = 1; - productName = Legacy; + productName = AppLegacy; }; /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 6550D1ED29B644710026F169 /* Common */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6550D20529B644710026F169 /* Build configuration list for PBXNativeTarget "Common" */; - buildPhases = ( - 6550D1E929B644710026F169 /* Headers */, - 6550D1EA29B644710026F169 /* Sources */, - 6550D1EB29B644710026F169 /* Frameworks */, - 6550D1EC29B644710026F169 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Common; - productName = Common; - productReference = 6550D1EE29B644710026F169 /* Common.framework */; - productType = "com.apple.product-type.framework"; - }; - 6550D1F629B644710026F169 /* CommonTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6550D20929B644710026F169 /* Build configuration list for PBXNativeTarget "CommonTests" */; - buildPhases = ( - 6550D1F329B644710026F169 /* Sources */, - 6550D1F429B644710026F169 /* Frameworks */, - 6550D1F529B644710026F169 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 6550D1FA29B644710026F169 /* PBXTargetDependency */, - ); - name = CommonTests; - productName = CommonTests; - productReference = 6550D1F729B644710026F169 /* CommonTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; 65FF4C6F29B74B8A000D5657 /* App */ = { isa = PBXNativeTarget; buildConfigurationList = 65FF4C9829B74B8C000D5657 /* Build configuration list for PBXNativeTarget "App" */; @@ -294,7 +251,7 @@ 65FF4C6C29B74B8A000D5657 /* Sources */, 65FF4C6D29B74B8A000D5657 /* Frameworks */, 65FF4C6E29B74B8A000D5657 /* Resources */, - 65FF4C9C29BF0373000D5657 /* Empty Copy Files Phase */, + 65FF4D3329C32D27000D5657 /* Embed Frameworks */, ); buildRules = ( ); @@ -341,6 +298,42 @@ productReference = 65FF4C8A29B74B8C000D5657 /* AppUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; + 65FF4D0729C31A25000D5657 /* Foo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 65FF4D1129C31A25000D5657 /* Build configuration list for PBXNativeTarget "Foo" */; + buildPhases = ( + 65FF4D0329C31A25000D5657 /* Headers */, + 65FF4D0429C31A25000D5657 /* Sources */, + 65FF4D0529C31A25000D5657 /* Frameworks */, + 65FF4D0629C31A25000D5657 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Foo; + productName = Foo; + productReference = 65FF4D0829C31A25000D5657 /* Foo.framework */; + productType = "com.apple.product-type.framework"; + }; + 65FF4D1829C31A2F000D5657 /* Bar */ = { + isa = PBXNativeTarget; + buildConfigurationList = 65FF4D2129C31A30000D5657 /* Build configuration list for PBXNativeTarget "Bar" */; + buildPhases = ( + 65FF4D1429C31A2F000D5657 /* Headers */, + 65FF4D1529C31A2F000D5657 /* Sources */, + 65FF4D1629C31A2F000D5657 /* Frameworks */, + 65FF4D1729C31A2F000D5657 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Bar; + productName = Bar; + productReference = 65FF4D1929C31A2F000D5657 /* Bar.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -351,13 +344,6 @@ LastSwiftUpdateCheck = 1420; LastUpgradeCheck = 1420; TargetAttributes = { - 6550D1ED29B644710026F169 = { - CreatedOnToolsVersion = 14.2; - }; - 6550D1F629B644710026F169 = { - CreatedOnToolsVersion = 14.2; - TestTargetID = 6550D18929B644320026F169; - }; 65FF4C6F29B74B8A000D5657 = { CreatedOnToolsVersion = 14.2; }; @@ -369,10 +355,17 @@ CreatedOnToolsVersion = 14.2; TestTargetID = 65FF4C6F29B74B8A000D5657; }; - 65FF4C9D29BF0402000D5657 = { + 65FF4D0729C31A25000D5657 = { + CreatedOnToolsVersion = 14.2; + LastSwiftMigration = 1420; + }; + 65FF4D1829C31A2F000D5657 = { + CreatedOnToolsVersion = 14.2; + }; + 65FF4D2829C31A99000D5657 = { CreatedOnToolsVersion = 14.2; }; - 65FF4CA129BF05DE000D5657 = { + 65FF4D2C29C31AA6000D5657 = { CreatedOnToolsVersion = 14.2; }; }; @@ -393,46 +386,46 @@ 65FF4C6F29B74B8A000D5657 /* App */, 65FF4C7F29B74B8B000D5657 /* AppTests */, 65FF4C8929B74B8C000D5657 /* AppUITests */, - 6550D1ED29B644710026F169 /* Common */, - 6550D1F629B644710026F169 /* CommonTests */, - 65FF4C9D29BF0402000D5657 /* Aggregate */, - 65FF4CA129BF05DE000D5657 /* Legacy */, + 65FF4D0729C31A25000D5657 /* Foo */, + 65FF4D1829C31A2F000D5657 /* Bar */, + 65FF4D2829C31A99000D5657 /* AppAggregate */, + 65FF4D2C29C31AA6000D5657 /* AppLegacy */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 6550D1EC29B644710026F169 /* Resources */ = { + 65FF4C6E29B74B8A000D5657 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 65FF4C7729B74B8B000D5657 /* Assets.xcassets in Resources */, + 65FF4C7A29B74B8B000D5657 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 6550D1F529B644710026F169 /* Resources */ = { + 65FF4C7E29B74B8B000D5657 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C6E29B74B8A000D5657 /* Resources */ = { + 65FF4C8829B74B8C000D5657 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65FF4C7729B74B8B000D5657 /* Assets.xcassets in Resources */, - 65FF4C7A29B74B8B000D5657 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C7E29B74B8B000D5657 /* Resources */ = { + 65FF4D0629C31A25000D5657 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C8829B74B8C000D5657 /* Resources */ = { + 65FF4D1729C31A2F000D5657 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -442,57 +435,52 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 6550D1EA29B644710026F169 /* Sources */ = { + 65FF4C6C29B74B8A000D5657 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65FF4C6829B6664B000D5657 /* Common.c in Sources */, - 6550D1F229B644710026F169 /* Common.docc in Sources */, + 65FF4C7529B74B8A000D5657 /* ViewController.swift in Sources */, + 65FF4D3829C5DD49000D5657 /* FileToRemove.swift in Sources */, + 65FF4C7329B74B8A000D5657 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 6550D1F329B644710026F169 /* Sources */ = { + 65FF4C7C29B74B8B000D5657 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6550D1FF29B644710026F169 /* CommonTests.swift in Sources */, + 65FF4C8529B74B8C000D5657 /* AppTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C6C29B74B8A000D5657 /* Sources */ = { + 65FF4C8629B74B8C000D5657 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65FF4C7529B74B8A000D5657 /* ViewController.swift in Sources */, - 65FF4C7329B74B8A000D5657 /* AppDelegate.swift in Sources */, + 65FF4C9129B74B8C000D5657 /* AppUITestsLaunchTests.swift in Sources */, + 65FF4C8F29B74B8C000D5657 /* AppUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C7C29B74B8B000D5657 /* Sources */ = { + 65FF4D0429C31A25000D5657 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65FF4C8529B74B8C000D5657 /* AppTests.swift in Sources */, + 65FF4D2529C31A48000D5657 /* Foo.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 65FF4C8629B74B8C000D5657 /* Sources */ = { + 65FF4D1529C31A2F000D5657 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65FF4C9129B74B8C000D5657 /* AppUITestsLaunchTests.swift in Sources */, - 65FF4C8F29B74B8C000D5657 /* AppUITests.swift in Sources */, + 65FF4D2729C31A5F000D5657 /* Bar.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 6550D1FA29B644710026F169 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 6550D1ED29B644710026F169 /* Common */; - targetProxy = 6550D1F929B644710026F169 /* PBXContainerItemProxy */; - }; 65FF4C8229B74B8C000D5657 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 65FF4C6F29B74B8A000D5657 /* App */; @@ -529,10 +517,13 @@ }; name = Release; }; - 6550D20629B644710026F169 /* Debug */ = { + 65FF4C9229B74B8C000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -561,15 +552,12 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -588,34 +576,34 @@ GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", - "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.Common; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.App; + PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 6550D20729B644710026F169 /* Release */ = { + 65FF4C9329B74B8C000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -644,15 +632,12 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -665,34 +650,32 @@ GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", - "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.Common; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.App; + PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; }; name = Release; }; - 6550D20A29B644710026F169 /* Debug */ = { + 65FF4C9429B74B8C000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -747,7 +730,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.CommonTests; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -758,11 +741,12 @@ }; name = Debug; }; - 6550D20B29B644710026F169 /* Release */ = { + 65FF4C9529B74B8C000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -810,7 +794,7 @@ MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.CommonTests; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -821,12 +805,11 @@ }; name = Release; }; - 65FF4C9229B74B8C000D5657 /* Debug */ = { + 65FF4C9629B74B8C000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -855,9 +838,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; @@ -878,34 +859,27 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INFOPLIST_KEY_NSMainStoryboardFile = Main; - INFOPLIST_KEY_NSPrincipalClass = NSApplication; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.App; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; + TEST_TARGET_NAME = App; }; name = Debug; }; - 65FF4C9329B74B8C000D5657 /* Release */ = { + 65FF4C9729B74B8C000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -934,9 +908,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -951,33 +923,25 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INFOPLIST_KEY_NSMainStoryboardFile = Main; - INFOPLIST_KEY_NSPrincipalClass = NSApplication; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.App; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; + TEST_TARGET_NAME = App; }; name = Release; }; - 65FF4C9429B74B8C000D5657 /* Debug */ = { + 65FF4D1229C31A25000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -1007,9 +971,14 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1027,28 +996,35 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppTests; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.Foo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = macosx; + SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/App"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 65FF4C9529B74B8C000D5657 /* Release */ = { + 65FF4D1329C31A25000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; - BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -1078,9 +1054,14 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1092,25 +1073,33 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppTests; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.Foo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = macosx; + SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/App"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Release; }; - 65FF4C9629B74B8C000D5657 /* Debug */ = { + 65FF4D2229C31A30000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -1141,9 +1130,14 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1161,26 +1155,31 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppUITests; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.Bar; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TEST_TARGET_NAME = App; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 65FF4C9729B74B8C000D5657 /* Release */ = { + 65FF4D2329C31A30000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -1211,9 +1210,14 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1225,22 +1229,28 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 12.5; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.AppUITests; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.nokee.samples.xcode.Bar; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; - TEST_TARGET_NAME = App; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Release; }; - 65FF4C9F29BF0402000D5657 /* Debug */ = { + 65FF4D2A29C31A99000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; @@ -1248,7 +1258,7 @@ }; name = Debug; }; - 65FF4CA029BF0402000D5657 /* Release */ = { + 65FF4D2B29C31A99000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; @@ -1256,7 +1266,7 @@ }; name = Release; }; - 65FF4CA329BF05DE000D5657 /* Debug */ = { + 65FF4D2E29C31AA7000D5657 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1318,7 +1328,7 @@ }; name = Debug; }; - 65FF4CA429BF05DE000D5657 /* Release */ = { + 65FF4D2F29C31AA7000D5657 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1383,65 +1393,65 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6550D20529B644710026F169 /* Build configuration list for PBXNativeTarget "Common" */ = { + 65FF4C9829B74B8C000D5657 /* Build configuration list for PBXNativeTarget "App" */ = { isa = XCConfigurationList; buildConfigurations = ( - 6550D20629B644710026F169 /* Debug */, - 6550D20729B644710026F169 /* Release */, + 65FF4C9229B74B8C000D5657 /* Debug */, + 65FF4C9329B74B8C000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6550D20929B644710026F169 /* Build configuration list for PBXNativeTarget "CommonTests" */ = { + 65FF4C9929B74B8C000D5657 /* Build configuration list for PBXNativeTarget "AppTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 6550D20A29B644710026F169 /* Debug */, - 6550D20B29B644710026F169 /* Release */, + 65FF4C9429B74B8C000D5657 /* Debug */, + 65FF4C9529B74B8C000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65FF4C9829B74B8C000D5657 /* Build configuration list for PBXNativeTarget "App" */ = { + 65FF4C9A29B74B8C000D5657 /* Build configuration list for PBXNativeTarget "AppUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 65FF4C9229B74B8C000D5657 /* Debug */, - 65FF4C9329B74B8C000D5657 /* Release */, + 65FF4C9629B74B8C000D5657 /* Debug */, + 65FF4C9729B74B8C000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65FF4C9929B74B8C000D5657 /* Build configuration list for PBXNativeTarget "AppTests" */ = { + 65FF4D1129C31A25000D5657 /* Build configuration list for PBXNativeTarget "Foo" */ = { isa = XCConfigurationList; buildConfigurations = ( - 65FF4C9429B74B8C000D5657 /* Debug */, - 65FF4C9529B74B8C000D5657 /* Release */, + 65FF4D1229C31A25000D5657 /* Debug */, + 65FF4D1329C31A25000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65FF4C9A29B74B8C000D5657 /* Build configuration list for PBXNativeTarget "AppUITests" */ = { + 65FF4D2129C31A30000D5657 /* Build configuration list for PBXNativeTarget "Bar" */ = { isa = XCConfigurationList; buildConfigurations = ( - 65FF4C9629B74B8C000D5657 /* Debug */, - 65FF4C9729B74B8C000D5657 /* Release */, + 65FF4D2229C31A30000D5657 /* Debug */, + 65FF4D2329C31A30000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65FF4C9E29BF0402000D5657 /* Build configuration list for PBXAggregateTarget "Aggregate" */ = { + 65FF4D2929C31A99000D5657 /* Build configuration list for PBXAggregateTarget "AppAggregate" */ = { isa = XCConfigurationList; buildConfigurations = ( - 65FF4C9F29BF0402000D5657 /* Debug */, - 65FF4CA029BF0402000D5657 /* Release */, + 65FF4D2A29C31A99000D5657 /* Debug */, + 65FF4D2B29C31A99000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65FF4CA229BF05DE000D5657 /* Build configuration list for PBXLegacyTarget "Legacy" */ = { + 65FF4D2D29C31AA7000D5657 /* Build configuration list for PBXLegacyTarget "AppLegacy" */ = { isa = XCConfigurationList; buildConfigurations = ( - 65FF4CA329BF05DE000D5657 /* Debug */, - 65FF4CA429BF05DE000D5657 /* Release */, + 65FF4D2E29C31AA7000D5657 /* Debug */, + 65FF4D2F29C31AA7000D5657 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/xcshareddata/xcschemes/App.xcscheme index 435788593f..36e60ab290 100644 --- a/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/xcshareddata/xcschemes/App.xcscheme +++ b/subprojects/build-adapter-xcode/src/templates/up-to-date-check/UpToDateCheck.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -50,6 +50,17 @@ ReferencedContainer = "container:UpToDateCheck.xcodeproj"> + + + + > delegate = newMock(ValueEncoder.class) .when(any(callTo(method(ValueEncoder::encode))).then(doReturn((it, args) -> args.getArgument(0)))); Object objectToEncode = new Object(); - InputObjectSpecEncoder subject = new InputObjectSpecEncoder<>(delegate.instance()); + AtInputEncoder subject = new AtInputEncoder<>(delegate.instance()); XCBuildSpec result = subject.encode(objectToEncode, context); @Test void canEncodeObjectToBuildSpec() { - assertThat(result, equalTo(new InputObjectSpec(objectToEncode))); + assertThat(result, equalTo(new AtInputEncoder.Spec(objectToEncode))); } @Test diff --git a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoderTests.java b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoderTests.java similarity index 85% rename from subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoderTests.java rename to subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoderTests.java index 987aac75bd..190f646582 100644 --- a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/ListSpecEncoderTests.java +++ b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedCollectionEncoderTests.java @@ -33,21 +33,21 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -class ListSpecEncoderTests { +class AtNestedCollectionEncoderTests { ValueEncoder.Context context = newMock(ValueEncoder.Context.class).alwaysThrows().instance(); TestDouble, List>> delegate = newMock(ValueEncoder.class) .when(any(callTo(method(ValueEncoder, List>::encode))).then(doReturn((it, args) -> { List values = args.getArgument(0); - return values.stream().map(Object::toString).map(ListSpecEncoderTests::spec).collect(Collectors.toList()); + return values.stream().map(Object::toString).map(AtNestedCollectionEncoderTests::spec).collect(Collectors.toList()); }))); List objectToEncode = ImmutableList.of("a", "b", "c"); - ListSpecEncoder> subject = new ListSpecEncoder<>(delegate.instance()); + AtNestedCollectionEncoder> subject = new AtNestedCollectionEncoder<>(ImmutableList.toImmutableList(), delegate.instance()); XCBuildSpec result = subject.encode(objectToEncode, context); @Test void canEncodeObjectToBuildSpec() { - assertThat(result, equalTo(new NestedListSpec(ImmutableList.of(spec("a"), spec("b"), spec("c"))))); + assertThat(result, equalTo(new AtNestedCollectionEncoder.Spec(ImmutableList.toImmutableList(), ImmutableList.of(spec("a"), spec("b"), spec("c"))))); } @Test diff --git a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/MapSpecEncoderTests.java b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoderTests.java similarity index 94% rename from subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/MapSpecEncoderTests.java rename to subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoderTests.java index a295d0ffad..fd788eb7c2 100644 --- a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/MapSpecEncoderTests.java +++ b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/AtNestedMapEncoderTests.java @@ -38,20 +38,20 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -class MapSpecEncoderTests { +class AtNestedMapEncoderTests { ValueEncoder.Context context = newMock(ValueEncoder.Context.class) .when(any(callTo(method(ValueEncoder.Context::encodeBycopyObject))).then(doReturn((it, args) -> new TestBycopyObject(args.getArgument(0))))) .alwaysThrows().instance(); TestDouble> delegate = newMock(ValueEncoder.class) .when(any(callTo(method(ValueEncoder::encode))).then(doReturn((it, args) -> args.getArgument(0)))); - MapSpecEncoder subject = new MapSpecEncoder<>(delegate.instance()); + AtNestedMapEncoder subject = new AtNestedMapEncoder<>(delegate.instance()); KeyedObject objectToEncode = DefaultKeyedObject.builder().put(key("a"), "A").put(key("b"), "B").build(); XCBuildSpec result = subject.encode(objectToEncode, context); @Test void canEncodeObjectToBuildSpec() { - assertThat(result, equalTo(new NestedMapSpec(ImmutableMap.of("a", spec("A"), "b", spec("B"))))); + assertThat(result, equalTo(new AtNestedMapEncoder.Spec(ImmutableMap.of("a", spec("A"), "b", spec("B"))))); } @Test diff --git a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpecEncoderTests.java b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/FileSystemLocationEncoderTests.java similarity index 90% rename from subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpecEncoderTests.java rename to subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/FileSystemLocationEncoderTests.java index b01185597b..250131ee91 100644 --- a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/InputLocationSpecEncoderTests.java +++ b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/FileSystemLocationEncoderTests.java @@ -30,18 +30,18 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -class InputLocationSpecEncoderTests { +class FileSystemLocationEncoderTests { ValueEncoder.Context context = newMock(ValueEncoder.Context.class).alwaysThrows().instance(); TestDouble> delegate = newMock(ValueEncoder.class) .when(any(callTo(method(ValueEncoder::encode))).then(doReturn((it, args) -> args.getArgument(0)))); PBXFileReference objectToEncode = PBXFileReference.ofSourceRoot("foo.c"); - InputLocationSpecEncoder subject = new InputLocationSpecEncoder<>(delegate.instance()); + FileSystemLocationEncoder subject = new FileSystemLocationEncoder<>(delegate.instance()); XCBuildSpec result = subject.encode(objectToEncode, context); @Test void canEncodeObjectToBuildSpec() { - assertThat(result, equalTo(new InputLocationSpec(objectToEncode))); + assertThat(result, equalTo(new FileSystemLocationEncoder.Spec(objectToEncode))); } @Test diff --git a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCodersTests.java b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCodersTests.java index 474f31b2e3..395c67c692 100644 --- a/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCodersTests.java +++ b/subprojects/build-adapter-xcode/src/test/java/dev/nokee/buildadapter/xcode/internal/plugins/specs/XCBuildSpecCodingKeyCodersTests.java @@ -15,6 +15,8 @@ */ package dev.nokee.buildadapter.xcode.internal.plugins.specs; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import dev.nokee.xcode.objects.files.PBXReference; import dev.nokee.xcode.project.CodeablePBXAggregateTarget; import dev.nokee.xcode.project.CodeablePBXBuildFile; @@ -68,6 +70,7 @@ import static com.spotify.hamcrest.optional.OptionalMatchers.emptyOptional; import static com.spotify.hamcrest.optional.OptionalMatchers.optionalWithValue; +import static dev.gradleplugins.buildscript.syntax.Syntax.setOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.params.provider.Arguments.arguments; @@ -161,7 +164,7 @@ private static final class CodingKeysProvider implements ArgumentsProvider { add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.name, ignore())); add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.shellPath, keyOf("shellPath", inputOf(string())))); add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.shellScript, keyOf("shellScript", inputOf(string())))); - add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.inputPaths, keyOf("inputPaths", listOf(inputLocation(resolvablePaths()))))); + add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.inputPaths, keyOf("inputPaths", inputLocation(setOf(resolvablePaths()))))); add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.inputFileListPaths, ignore())); // TODO: implement support add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.outputPaths, ignore())); add(arguments(CodeablePBXShellScriptBuildPhase.CodingKeys.outputFileListPaths, ignore())); // TODO: implement support @@ -239,24 +242,28 @@ private static Matcher>> ignore() { return emptyOptional(); } - private static ValueEncoder resolvablePaths() { - return new NormalizeStringAsPBXReferenceEncoder(new NormalizePBXBuildFileFileReferenceAsPBXReferenceEncoder(new ThrowingValueEncoder<>())); + private static ValueEncoder resolvablePaths() { + return new FileSystemLocationEncoder<>(new NormalizeStringAsPBXReferenceEncoder(new NormalizePBXBuildFileFileReferenceAsPBXReferenceEncoder(new ThrowingValueEncoder<>()))); } - private static ValueEncoder inputLocation(ValueEncoder encoder) { - return new InputLocationSpecEncoder<>(encoder); + private static ValueEncoder inputLocation(ValueEncoder encoder) { + return new AtInputFilesEncoder<>(encoder); } private static ValueEncoder object() { - return new MapSpecEncoder<>(new NoOpEncoder<>()); + return new AtNestedMapEncoder<>(new NoOpEncoder<>()); } public static ValueEncoder> listOf(ValueEncoder elementEncoder) { - return new ListSpecEncoder<>(new ListEncoder<>(elementEncoder)); + return new AtNestedCollectionEncoder<>(ImmutableList.toImmutableList(), new ListEncoder<>(elementEncoder)); + } + + public static ValueEncoder> setOf(ValueEncoder elementEncoder) { + return new AtNestedCollectionEncoder<>(ImmutableSet.toImmutableSet(), new ListEncoder<>(elementEncoder)); } public static ValueEncoder inputOf(ValueEncoder encoder) { - return new InputObjectSpecEncoder<>(encoder); + return new AtInputEncoder<>(encoder); } public static ValueEncoder string() {