Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for Binding Projects Incremental Build #8706

Merged
merged 3 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,31 @@ It is shared between "legacy" binding projects and .NET 5 projects.
/>
</Target>

<Target Name="_CollectLibrariesToBind" DependsOnTargets="_CategorizeAndroidLibraries">
<ItemGroup>
<_LibrariesToBind Include="@(EmbeddedJar)" />
<_LibrariesToBind Include="@(InputJar)" />
<_LibrariesToBind Include="@(LibraryProjectZip)" />
<_LibrariesToBind Include="@(_JavaBindingSource)" Condition=" '%(_JavaBindingSource.Bind)' == 'true' "/>
</ItemGroup>
</Target>

<Target Name="_SetAndroidGenerateManagedBindings"
Condition=" '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' Or '@(LibraryProjectZip->Count())' != '0' Or '@(_JavaBindingSource->Count())' != '0' ">
Condition=" '@(_LibrariesToBind->Count())' != '0' ">
<PropertyGroup>
<!-- Used throughout to determine if C# binding-related targets should skip -->
<_AndroidGenerateManagedBindings>true</_AndroidGenerateManagedBindings>
</PropertyGroup>
</Target>

<Target Name="_CollectGeneratedManagedBindingFiles">
<Target Name="_CollectGeneratedManagedBindingFiles" AfterTargets="GenerateBindings">
<ItemGroup>
<_GeneratedManagedBindingFiles Include="$(GeneratedOutputPath)**\*.cs" />
</ItemGroup>
</Target>

<Target Name="_ClearGeneratedManagedBindings"
Condition=" '@(InputJar->Count())' == '0' And '@(EmbeddedJar->Count())' == '0' And '@(LibraryProjectZip->Count())' == '0' And '@(_JavaBindingSource->Count())' == '0' "
DependsOnTargets="_CollectGeneratedManagedBindingFiles"
Condition=" '@(_LibrariesToBind->Count())' == '0' And '$(DesignTimeBuild)' != 'True' "
>
<Delete Files="@(_GeneratedManagedBindingFiles)" />
</Target>
Expand All @@ -75,7 +83,6 @@ It is shared between "legacy" binding projects and .NET 5 projects.

<Target Name="GenerateBindings"
Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' "
DependsOnTargets="ExportJarToXml;_ResolveMonoAndroidSdks"
Inputs="$(ApiOutputFile);@(TransformFile);@(ReferencePath);@(ReferenceDependencyPaths);@(_AndroidMSBuildAllProjects)"
Outputs="$(_GeneratorStampFile)">

Expand Down Expand Up @@ -135,14 +142,17 @@ It is shared between "legacy" binding projects and .NET 5 projects.

<ItemGroup>
<FileWrites Include="$(GeneratedOutputPath)**\*.cs" />
<FileWrites Include="$(GeneratedOutputPath)src\$(AssemblyName).projitems" />
<FileWrites Include="$(_GeneratorStampFile)" />
</ItemGroup>

<!-- Read the file list. -->

</Target>

<Target Name="AddBindingsToCompile"
Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' Or '@(_GeneratedManagedBindingFiles->Count())' != '0' "
DependsOnTargets="GenerateBindings;_CollectGeneratedManagedBindingFiles">
>
<!-- bindings need AllowUnsafeBlocks -->
<PropertyGroup>
<AllowUnsafeBlocks Condition=" '$(AllowUnsafeBlocks)' != 'true' ">true</AllowUnsafeBlocks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ It is shared between "legacy" binding projects and .NET 7+ projects.
<_AndroidIntermediateBindingClassesZip>$(IntermediateOutputPath)binding\bin\$(MSBuildProjectName).jar</_AndroidIntermediateBindingClassesZip>
<_AndroidIntermediateBindingClassesDocs>$(IntermediateOutputPath)binding\bin\$(MSBuildProjectName)-docs.xml</_AndroidIntermediateBindingClassesDocs>
<_AndroidCompileJavaStampFile>$(_AndroidStampDirectory)_CompileJava.stamp</_AndroidCompileJavaStampFile>
<_AndroidCompileJavaFileList>$(IntermediateOutputPath)_CompileJava.FileList.txt</_AndroidCompileJavaFileList>
<_AndroidCompileBindingJavaStampFile>$(_AndroidStampDirectory)_CompileBindingJava.stamp</_AndroidCompileBindingJavaStampFile>
<_AndroidCompileBindingJavaFileList>$(IntermediateOutputPath)_CompileBindingJava.FileList.txt</_AndroidCompileBindingJavaFileList>
</PropertyGroup>

<Target Name="_AdjustJavacVersionArguments">
Expand Down Expand Up @@ -74,18 +76,36 @@ It is shared between "legacy" binding projects and .NET 7+ projects.
<ItemGroup>
<_JavaBindingSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' == 'True' " />
</ItemGroup>
<WriteLinesToFile
File="$(_AndroidCompileBindingJavaFileList)"
Lines="@(_JavaBindingSource->ToLowerInvariant())"
Overwrite="true"
WriteOnlyWhenDifferent="true"
/>
<ItemGroup>
<FileWrites Include="$(_AndroidCompileBindingJavaFileList)" />
</ItemGroup>
</Target>

<Target Name="_CollectJavaSource">
<ItemGroup>
<_JavaSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' != 'True' " />
</ItemGroup>
<WriteLinesToFile
File="$(_AndroidCompileJavaFileList)"
Lines="@(_JavaSource->ToLowerInvariant())"
Overwrite="true"
WriteOnlyWhenDifferent="true"
/>
<ItemGroup>
<FileWrites Include="$(_AndroidCompileJavaFileList)" />
</ItemGroup>
</Target>

<Target Name="_CompileBindingJava"
Condition=" '@(_JavaBindingSource->Count())' != '0' "
DependsOnTargets="$(_CompileBindingJavaDependsOnTargets)"
Inputs="@(_AndroidMSBuildAllProjects);$(MonoPlatformJarPath);@(_JavaBindingSource)"
Inputs="@(_AndroidMSBuildAllProjects);$(_AndroidCompileBindingJavaFileList);$(MonoPlatformJarPath);@(_JavaBindingSource)"
Outputs="$(_AndroidCompileBindingJavaStampFile)">

<!-- remove existing <Javac /> outputs, since *.class files and classes.zip could contain old files -->
Expand Down Expand Up @@ -132,7 +152,7 @@ It is shared between "legacy" binding projects and .NET 7+ projects.

<Target Name="_CompileJava"
DependsOnTargets="$(_CompileJavaDependsOnTargets);_CollectJavaSource"
Inputs="@(_AndroidMSBuildAllProjects);$(MonoPlatformJarPath);@(_JavaStubFiles);@(_JavaSource)"
Inputs="@(_AndroidMSBuildAllProjects);$(_AndroidCompileJavaFileList);$(MonoPlatformJarPath);@(_JavaStubFiles);@(_JavaSource)"
Outputs="$(_AndroidCompileJavaStampFile)">

<!-- remove existing <Javac /> outputs, since *.class files and classes.zip could contain old files -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ properties that determine build ordering.
UpdateAndroidResources;
_BuildResourceDesigner;
UpdateAndroidInterfaceProxies;
_SetAndroidGenerateManagedBindings;
_ClearGeneratedManagedBindings;
AddBindingsToCompile;
_CheckForInvalidDesignerConfig;
</ResolveReferencesDependsOn>
<DesignTimeResolveAssemblyReferencesDependsOn>
Expand All @@ -144,6 +141,13 @@ properties that determine build ordering.
_AddAndroidDefines;
_IncludeLayoutBindingSources;
AddLibraryJarsToBind;
_CollectLibrariesToBind;
_SetAndroidGenerateManagedBindings;
ExportJarToXml;
GenerateBindings;
_CollectGeneratedManagedBindingFiles;
_ClearGeneratedManagedBindings;
AddBindingsToCompile;
_BuildResourceDesigner;
_AddResourceDesignerFiles;
$(CompileDependsOn);
Expand Down
2 changes: 2 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Android.Build.Tasks;

namespace Xamarin.Android.Tasks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void DotNetBuildBinding ()
proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javaclasses-sources.jar") {
BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar,
});
proj.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") {
proj.AndroidJavaSources.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") {
Encoding = Encoding.ASCII,
TextContent = () => ResourceData.JavaSourceTestExtension,
Metadata = { { "Bind", "True"} },
Expand Down Expand Up @@ -75,6 +75,7 @@ public void BindingLibraryIncremental (string classParser)
"_ResolveLibraryProjectImports",
"CoreCompile",
"_CreateAar",
"_ClearGeneratedManagedBindings",
};

var proj = new XamarinAndroidBindingProject () {
Expand Down Expand Up @@ -112,6 +113,23 @@ public void BindingLibraryIncremental (string classParser)
foreach (var target in targets) {
Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped on second build!");
}

Assert.IsTrue (b.DesignTimeBuild (proj, target: "UpdateGeneratedFiles"), "DTB should have succeeded.");
var cs_file = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "generated", "src", "Com.Larvalabs.Svgandroid.SVGParser.cs");
FileAssert.Exists (cs_file);
Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "third build should succeed");
foreach (var target in targets) {
Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped on second build!");
}
// Fast Update Check Build
Assert.IsTrue (b.DesignTimeBuild (proj, target: "PrepareResources;_GenerateCompileInputs"), "DTB should have succeeded.");
cs_file = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "generated", "src", "Com.Larvalabs.Svgandroid.SVGParser.cs");
FileAssert.Exists (cs_file);
Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "forth build should succeed");
foreach (var target in targets) {
Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped on second build!");
}

}
}

Expand Down Expand Up @@ -671,6 +689,10 @@ public void BindingWithAndroidJavaSource ()
StringAssertEx.ContainsText (File.ReadAllLines (generatedIface), "string GreetWithQuestion (string name, global::Java.Util.Date date, string question);");
Assert.IsTrue (libBuilder.Build (lib), "Library build should have succeeded.");
Assert.IsTrue (libBuilder.Output.IsTargetSkipped ("_CompileBindingJava"), $"`_CompileBindingJava` should be skipped on second build!");
Assert.IsTrue (libBuilder.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings"), $"`_ClearGeneratedManagedBindings` should be skipped on second build!");
FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on second build.");
Assert.IsTrue (libBuilder.DesignTimeBuild (lib, target: "UpdateGeneratedFiles"), "DTB should have succeeded.");
FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on DTB build.");
Assert.IsTrue (appBuilder.Build (app), "App build should have succeeded.");
appBuilder.Target = "SignAndroidPackage";
Assert.IsTrue (appBuilder.Build (app), "App SignAndroidPackage should have succeeded.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo
proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javaclasses-sources.jar") {
BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar,
});
proj.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") {
proj.AndroidJavaSources.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") {
Encoding = Encoding.ASCII,
TextContent = () => ResourceData.JavaSourceTestExtension,
Metadata = { { "Bind", "True"} },
Expand Down Expand Up @@ -1511,7 +1511,7 @@ public void BuildApplicationWithJavaSourceUsingAndroidX ([Values(true, false)] b
{
var proj = new XamarinAndroidApplicationProject () {
IsRelease = isRelease,
OtherBuildItems = {
AndroidJavaSources = {
new BuildItem (AndroidBuildActions.AndroidJavaSource, "ToolbarEx.java") {
TextContent = () => @"package com.unnamedproject.unnamedproject;
import android.content.Context;
Expand Down Expand Up @@ -1556,11 +1556,11 @@ public void BuildApplicationCheckThatAddStaticResourcesTargetDoesNotRerun ()
public void CheckJavaError ()
{
var proj = new XamarinAndroidApplicationProject ();
proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe.java") {
proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe.java") {
TextContent = () => "public classo TestMe { }",
Encoding = Encoding.ASCII
});
proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe2.java") {
proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe2.java") {
TextContent = () => "public class TestMe2 {" +
"public vod Test ()" +
"}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1000,14 +1000,14 @@ public void BuildProguardEnabledProject (string rid)
XamarinAndroidApplicationProject CreateMultiDexRequiredApplication (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release")
{
var proj = new XamarinAndroidApplicationProject (debugConfigurationName, releaseConfigurationName);
proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods.java") {
proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods.java") {
TextContent = () => "public class ManyMethods { \n"
+ string.Join (Environment.NewLine, Enumerable.Range (0, 32768).Select (i => "public void method" + i + "() {}"))
+ "}",
Encoding = Encoding.ASCII,
Metadata = { { "Bind", "False "}},
});
proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods2.java") {
proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods2.java") {
TextContent = () => "public class ManyMethods2 { \n"
+ string.Join (Environment.NewLine, Enumerable.Range (0, 32768).Select (i => "public void method" + i + "() {}"))
+ "}",
Expand Down Expand Up @@ -1064,8 +1064,8 @@ public void BuildAfterMultiDexIsNotRequired ()
}

//Now build project again after it no longer requires multidex, remove the *HUGE* AndroidJavaSource build items
while (proj.OtherBuildItems.Count > 1)
proj.OtherBuildItems.RemoveAt (proj.OtherBuildItems.Count - 1);
while (proj.AndroidJavaSources.Count > 1)
proj.AndroidJavaSources.RemoveAt (proj.AndroidJavaSources.Count - 1);
proj.SetProperty ("AndroidEnableMultiDex", "False");

Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true), "Build should have succeeded.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ public List<string> GetAssemblyMapCache ()
return File.ReadLines (path).ToList ();
}

public bool IsTargetSkipped (string target) => IsTargetSkipped (Builder.LastBuildOutput, target);
public bool IsTargetSkipped (string target, bool defaultIfNotUsed = false) => IsTargetSkipped (Builder.LastBuildOutput, target, defaultIfNotUsed);

public static bool IsTargetSkipped (IEnumerable<string> output, string target)
public static bool IsTargetSkipped (IEnumerable<string> output, string target, bool defaultIfNotUsed = false)
{
bool found = false;
foreach (var line in output) {
Expand All @@ -69,7 +69,7 @@ public static bool IsTargetSkipped (IEnumerable<string> output, string target)
if (found)
return true;
}
return false;
return defaultIfNotUsed;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ protected DotNetXamarinProject (string debugConfigurationName = "Debug", string

Sources = new List<BuildItem> ();
OtherBuildItems = new List<BuildItem> ();
AndroidJavaSources = new List<BuildItem> ();

ItemGroupList.Add (References);
ItemGroupList.Add (OtherBuildItems);
ItemGroupList.Add (Sources);
ItemGroupList.Add (AndroidJavaSources);

SetProperty ("RootNamespace", () => RootNamespace ?? ProjectName);
SetProperty ("AssemblyName", () => AssemblyName ?? ProjectName);
Expand All @@ -40,6 +42,7 @@ protected DotNetXamarinProject (string debugConfigurationName = "Debug", string

public IList<BuildItem> OtherBuildItems { get; private set; }
public IList<BuildItem> Sources { get; private set; }
public IList<BuildItem> AndroidJavaSources { get; private set; }

public IList<Property> ActiveConfigurationProperties {
get { return IsRelease ? ReleaseProperties : DebugProperties; }
Expand Down
68 changes: 68 additions & 0 deletions tests/MSBuildDeviceIntegration/Tests/InstallTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,5 +611,73 @@ public void AdbTargetChangesAppBundle ()
var after = File.GetLastWriteTimeUtc (apkset);
Assert.AreNotEqual (before, after, $"{apkset} should change!");
}

[Test]
public void AppWithAndroidJavaSource ()
{
var path = Path.Combine ("temp", TestName);
var itemToDelete = new AndroidItem.AndroidJavaSource ("TestJavaClass2.java") {
Encoding = Encoding.ASCII,
TextContent = () => @"package com.test.java;

public class TestJavaClass2 {

public String test(){

return ""Java is called"";
}
}",
Metadata = {
{ "Bind", "True" },
},
};
var proj = new XamarinAndroidApplicationProject {
EnableDefaultItems = true,
AndroidJavaSources = {
new AndroidItem.AndroidJavaSource ("TestJavaClass.java") {
Encoding = Encoding.ASCII,
TextContent = () => @"package com.test.java;

public class TestJavaClass {

public String test(){

return ""Java is called"";
}
}",
Metadata = {
{ "Bind", "True" },
},
},
itemToDelete,
},
};
using (var b = CreateApkBuilder ()) {
b.ThrowOnBuildFailure = false;
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
b.AssertHasNoWarnings ();
var generatedCode = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath,
"generated", "src", "Com.Test.Java.TestJavaClass.cs");
var generatedCode2 = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath,
"generated", "src", "Com.Test.Java.TestJavaClass2.cs");
FileAssert.Exists (generatedCode, $"'{generatedCode}' should have been generated.");
FileAssert.Exists (generatedCode2, $"'{generatedCode2}' should have been generated.");
Assert.IsTrue (b.DesignTimeBuild (proj, target: "UpdateGeneratedFiles"), "DTB should have succeeded.");
Assert.IsTrue (b.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings", defaultIfNotUsed: true), $"`_ClearGeneratedManagedBindings` should be skipped on DTB build!");
FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on DTB build.");
FileAssert.Exists (generatedCode2, $"'{generatedCode2}' should have not be deleted on DTB build.");
proj.AndroidJavaSources.Remove (itemToDelete);
File.Delete (Path.Combine (Root, b.ProjectDirectory, itemToDelete.Include ()));
Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "Second build should have succeeded.");
FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on second build.");
FileAssert.DoesNotExist (generatedCode2, $"'{generatedCode2}' should have be deleted on second build.");
Assert.IsFalse (b.Output.IsTargetSkipped ("_CompileBindingJava"), $"`_CompileBindingJava` should run on second build!");
Assert.IsTrue (b.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings"), $"`_ClearGeneratedManagedBindings` should be skipped on second build!");
// Call Install directly so Build does not get called automatically
Assert.IsTrue (b.RunTarget (proj, "Install", doNotCleanupOnUpdate: true, saveProject: false), "Install build should have succeeded.");
FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on Install build.");
Assert.IsTrue (b.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings", defaultIfNotUsed: true), $"`_ClearGeneratedManagedBindings` should be skipped on Install build!");
}
}
}
}