From 185fea46c01d1f2fec83fe72bf4512dd73a269a0 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Thu, 17 Aug 2017 20:26:58 +0100 Subject: [PATCH] Add Net Standard Support This commit adds Net Standard Support for msbuild tests. It also adds support for `PackageReference` for standard xamarin.android projects. Note We have to inject the PackageReference bits into a standard project using xml. This is because the Project api we are using does NOT support PackageReference items. At least the version we have on mono doesn't. --- .../PackagingTest.cs | 221 ++++++++++++++++++ .../Android/KnownPackages.cs | 67 +++++- .../Android/XamarinAndroidProject.cs | 2 +- .../Common/BuildActions.cs | 1 + .../Xamarin.ProjectTools/Common/BuildItem.cs | 14 +- .../Xamarin.ProjectTools/Common/Builder.cs | 3 +- .../Common/DotNetStandard.cs | 83 +++++++ .../Common/DotNetXamarinProject.cs | 148 ++++++++++++ .../Common/ProjectBuilder.cs | 2 +- .../Common/XamarinPCLProject.cs | 2 +- .../Common/XamarinProject.cs | 180 +++----------- .../Xamarin.ProjectTools.csproj | 2 + 12 files changed, 566 insertions(+), 159 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index 039f96a2feb..bb3ad05b176 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -201,5 +201,226 @@ public void ExplicitPackageNamingPolicy () Assert.IsTrue (text.Contains ("package unnamedproject;"), "expected package not found in the source."); } } + + [Test] + public void NetStandardReferenceTest () + { + var netStandardProject = new DotNetStandard () { + Language = XamarinAndroidProjectLanguage.CSharp, + ProjectName = "XamFormsSample", + ProjectGuid = Guid.NewGuid ().ToString (), + Sdk = "Microsoft.NET.Sdk", + TargetFramework = "netstandard1.4", + IsRelease = true, + PackageTargetFallback = "portable-net45+win8+wpa81+wp8", + PackageReferences = { + KnownPackages.XamarinFormsPCL_2_3_4_231, + new Package () { + Id = "System.IO.Packaging", + Version = "4.4.0", + }, +// Uncomment when https://bugzilla.xamarin.com/show_bug.cgi?id=59313 gets fixed +// new Package () { +// Id = "Newtonsoft.Json", +// Version = "10.0.3" +// }, + }, + OtherBuildItems = { + new BuildItem ("None") { + Remove = () => "**\\*.xaml", + }, + new BuildItem ("Compile") { + Update = () => "**\\*.xaml.cs", + DependentUpon = () => "%(Filename)" + }, + new BuildItem ("EmbeddedResource") { + Include = () => "**\\*.xaml", + SubType = () => "Designer", + Generator = () => "MSBuild:UpdateDesignTimeXaml", + }, + }, + Sources = { + new BuildItem.Source ("App.xaml.cs") { + TextContent = () => @"using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +//using Newtonsoft.Json; + +using Xamarin.Forms; + +namespace XamFormsSample +{ + public partial class App : Application + { + public App() + { +// Uncomment when https://bugzilla.xamarin.com/show_bug.cgi?id=59313 gets fixed +// JsonConvert.DeserializeObject(""test""); + InitializeComponent(); + } + + protected override void OnStart() + { + // Handle when your app starts + } + + protected override void OnSleep() + { + // Handle when your app sleeps + } + + protected override void OnResume() + { + // Handle when your app resumes + } + } +}", + }, + new BuildItem.Source ("App.xaml") { + TextContent = () => @" + + + + +", + }, + }, + }; + + var app = new XamarinAndroidApplicationProject () { + ProjectName = "App1", + IsRelease = true, + UseLatestPlatformSdk = true, + References = { + new BuildItem.Reference ("Mono.Android.Export"), + new BuildItem.ProjectReference ($"..\\{netStandardProject.ProjectName}\\{netStandardProject.ProjectName}.csproj", + netStandardProject.ProjectName, netStandardProject.ProjectGuid), + }, + PackageReferences = { + KnownPackages.SupportDesign_25_4_0_1, + KnownPackages.SupportV7CardView_24_2_1, + KnownPackages.AndroidSupportV4_25_4_0_1, + KnownPackages.SupportCoreUtils_25_4_0_1, + KnownPackages.SupportMediaCompat_25_4_0_1, + KnownPackages.SupportFragment_25_4_0_1, + KnownPackages.SupportCoreUI_25_4_0_1, + KnownPackages.SupportCompat_25_4_0_1, + KnownPackages.SupportV7AppCompat_25_4_0_1, + KnownPackages.XamarinForms_2_3_4_231, + } + }; + app.SetProperty (KnownProperties.AndroidSupportedAbis, "x86;armeabi-v7a"); + var expectedFiles = new string [] { + "Java.Interop.dll", + "Mono.Android.dll", + "mscorlib.dll", + "mscorlib.dll.mdb", + "System.Collections.Concurrent.dll", + "System.Collections.dll", + "System.Core.dll", + "System.Diagnostics.Debug.dll", + "System.dll", + "System.Linq.dll", + "System.Reflection.dll", + "System.Reflection.Extensions.dll", + "System.Runtime.dll", + "System.Runtime.Extensions.dll", + "System.Runtime.InteropServices.dll", + "System.Runtime.Serialization.dll", + "System.Threading.dll", + "System.IO.Packaging.dll", + "System.IO.Compression.dll", + "System.IO.Compression.pdb", + "Mono.Android.Export.dll", + "Mono.Android.Export.pdb", + "App1.dll", + "App1.pdb", + "FormsViewGroup.dll", + "FormsViewGroup.dll.mdb", + "Xamarin.Android.Support.Compat.dll", + "Xamarin.Android.Support.Core.UI.dll", + "Xamarin.Android.Support.Core.Utils.dll", + "Xamarin.Android.Support.Design.dll", + "Xamarin.Android.Support.Fragment.dll", + "Xamarin.Android.Support.Media.Compat.dll", + "Xamarin.Android.Support.v4.dll", + "Xamarin.Android.Support.v7.AppCompat.dll", + "Xamarin.Android.Support.Animated.Vector.Drawable.dll", + "Xamarin.Android.Support.Vector.Drawable.dll", + "Xamarin.Android.Support.Transition.dll", + "Xamarin.Android.Support.v7.MediaRouter.dll", + "Xamarin.Android.Support.v7.RecyclerView.dll", + "Xamarin.Android.Support.Annotations.dll", + "Xamarin.Android.Support.v7.CardView.dll", + "Xamarin.Forms.Core.dll", + "Xamarin.Forms.Core.dll.mdb", + "Xamarin.Forms.Platform.Android.dll", + "Xamarin.Forms.Platform.Android.dll.mdb", + "Xamarin.Forms.Platform.dll", + "Xamarin.Forms.Xaml.dll", + "Xamarin.Forms.Xaml.dll.mdb", + "XamFormsSample.dll", + "XamFormsSample.pdb", + "Mono.Android.pdb", + "System.Core.pdb", + "System.pdb", + "Mono.Security.dll", + "Mono.Security.pdb", + "System.Xml.dll", + "System.Xml.pdb", + "System.ComponentModel.Composition.dll", + "System.ComponentModel.Composition.pdb", + "System.Net.Http.dll", + "System.Net.Http.pdb", + "System.Runtime.Serialization.pdb", + "System.ServiceModel.Internals.dll", + "System.ServiceModel.Internals.pdb", + "System.Threading.Tasks.dll", + "System.ObjectModel.dll", + "System.Globalization.dll", + "System.ComponentModel.dll", + "System.Xml.ReaderWriter.dll", + "System.Linq.Expressions.dll", + "System.IO.dll", + "System.Dynamic.Runtime.dll", + "System.Text.RegularExpressions.dll", + "System.Diagnostics.Tools.dll", + }; + var path = Path.Combine ("temp", TestContext.CurrentContext.Test.Name); + using (var builder = CreateDllBuilder (Path.Combine (path, netStandardProject.ProjectName))) { + builder.RequiresMSBuild = true; + builder.Target = "Restore"; + Assert.IsTrue (builder.Build (netStandardProject), "XamFormsSample Nuget packages should have been restored."); + builder.Target = "Build"; + Assert.IsTrue (builder.Build (netStandardProject), "XamFormsSample should have built."); + using (var ab = CreateApkBuilder (Path.Combine (path, app.ProjectName))) { + ab.RequiresMSBuild = true; + ab.Target = "Restore"; + Assert.IsTrue (ab.Build (app), "App should have built."); + ab.Target = "SignAndroidPackage"; + Assert.IsTrue (ab.Build (app), "App should have built."); + var apk = Path.Combine (Root, ab.ProjectDirectory, + app.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"); + using (var zip = ZipHelper.OpenZip (apk)) { + var existingFiles = zip.Where (a => a.FullName.StartsWith ("assemblies/", StringComparison.InvariantCultureIgnoreCase)); + var missingFiles = expectedFiles.Where (x => !zip.ContainsEntry ("assmelbies/" + Path.GetFileName (x))); + Assert.IsTrue (missingFiles.Any (), + string.Format ("The following Expected files are missing. {0}", + string.Join (Environment.NewLine, missingFiles))); + var additionalFiles = existingFiles.Where (x => !expectedFiles.Contains (Path.GetFileName (x.FullName))); + Assert.IsTrue (!additionalFiles.Any (), + string.Format ("Unexpected Files found! {0}", + string.Join (Environment.NewLine, additionalFiles.Select (x => x.FullName)))); + } + if (!HasDevices) + Assert.Ignore ("Skipping Installation. No devices available."); + ab.Target = "Install"; + Assert.IsTrue (ab.Build (app), "App should have installed."); + } + } + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs index 02d5b86ce7f..344deea46e9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs @@ -66,7 +66,7 @@ public static class KnownPackages new BuildItem.Reference ("Xamarin.Android.Support.v13") { MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.v13.20.0.0.4\\lib\\MonoAndroid32\\Xamarin.Android.Support.v13.dll" } } - }; + }; public static Package AndroidSupportV13Beta = new Package () { Id = "Xamarin.Android.Support.v13", Version = "21.0.0.0-beta1", @@ -93,20 +93,20 @@ public static class KnownPackages new BuildItem.Reference ("Xamarin.Android.Wearable") { MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Wear.1.0.0-preview7\\lib\\MonoAndroid10\\Xamarin.Android.Wearable.dll" } } - }; + }; public static Package SupportV7RecyclerView = new Package { Id = "Xamarin.Android.Support.v7.RecyclerView", - Version="21.0.0.0-beta1", - TargetFramework="MonoAndroid523", + Version = "21.0.0.0-beta1", + TargetFramework = "MonoAndroid523", References = { new BuildItem.Reference ("Xamarin.Android.Support.V7.RecyclerView") { MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.v7.RecyclerView.21.0.0.0-beta1\\lib\\MonoAndroid\\Xamarin.Android.Support.v7.RecyclerView.dll" } } - }; + }; public static Package SupportV7CardView = new Package { Id = "Xamarin.Android.Support.v7.Cardview", - Version="21.0.3.0", - TargetFramework="MonoAndroid523", + Version = "21.0.3.0", + TargetFramework = "MonoAndroid523", References = { new BuildItem.Reference ("Xamarin.Android.Support.v7.CardView") { MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.v7.CardView.21.0.3.0\\lib\\MonoAndroid403\\Xamarin.Android.Support.v7.CardView.dll" } @@ -121,6 +121,15 @@ public static class KnownPackages MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.v7.CardView.24.2.1\\lib\\MonoAndroid70\\Xamarin.Android.Support.v7.CardView.dll" } } }; + public static Package SupportV7CardView_25_4_0_1 = new Package { + Id = "Xamarin.Android.Support.v7.Cardview", + Version = "25.4.0.1", + TargetFramework = "MonoAndroid70", + References = { + new BuildItem.Reference ("Xamarin.Android.Support.v7.CardView") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.v7.CardView.25.4.0.1\\lib\\MonoAndroid70\\Xamarin.Android.Support.v7.CardView.dll" } + } + }; public static Package SupportV7AppCompat_21_0_3_0 = new Package { Id = "Xamarin.Android.Support.v7.AppCompat", Version = "21.0.3.0", @@ -220,6 +229,15 @@ public static class KnownPackages MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.v7.Palette.22.1.1.1\\lib\\MonoAndroid403\\Xamarin.Android.Support.v7.Palette.dll" } } }; + public static Package SupportDesign_25_4_0_1 = new Package { + Id = "Xamarin.Android.Support.Design", + Version = "25.4.0.1", + TargetFramework = "MonoAndroid70", + References = { + new BuildItem.Reference ("Xamarin.Android.Support.Design") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Support.Design.25.4.0.1\\lib\\MonoAndroid70\\Xamarin.Android.Support.Design.dll" } + } + }; public static Package GooglePlayServices_22_0_0_2 = new Package { Id = "Xamarin.GooglePlayServices", Version = "22.0.0.2", @@ -265,6 +283,41 @@ public static class KnownPackages }, } }; + public static Package XamarinFormsPCL_2_3_4_231 = new Package { + Id = "Xamarin.Forms", + Version = "2.3.4.231", + TargetFramework = "portable-net45+win+wp80+MonoAndroid10+xamarinios10+MonoTouch10", + References = { + new BuildItem.Reference ("Xamarin.Forms.Core") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\\Xamarin.Forms.Core.dll" + }, + new BuildItem.Reference ("Xamarin.Forms.Xaml") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\\Xamarin.Forms.Xaml.dll" + }, + } + }; + public static Package XamarinForms_2_3_4_231 = new Package { + Id = "Xamarin.Forms", + Version = "2.3.4.231", + TargetFramework = "MonoAndroid44", + References = { + new BuildItem.Reference ("Xamarin.Forms.Platform.Android") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\MonoAndroid10\\Xamarin.Forms.Platform.Android.dll" + }, + new BuildItem.Reference ("FormsViewGroup") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\MonoAndroid10\\FormsViewGroup.dll" + }, + new BuildItem.Reference ("Xamarin.Forms.Core") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\MonoAndroid10\\Xamarin.Forms.Core.dll" + }, + new BuildItem.Reference ("Xamarin.Forms.Xaml") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\MonoAndroid10\\Xamarin.Forms.Xaml.dll" + }, + new BuildItem.Reference ("Xamarin.Forms.Platform") { + MetadataValues = "HintPath=..\\packages\\Xamarin.Forms.2.3.4.231\\lib\\MonoAndroid10\\Xamarin.Forms.Platform.dll" + }, + } + }; public static Package CocosSharp_PCL_Shared_1_5_0_0 = new Package { Id = "CocosSharp.PCL.Shared", Version = "1.5.0.0", diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs index 7db82452a91..7776a255dcc 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs @@ -7,7 +7,7 @@ namespace Xamarin.ProjectTools { - public abstract class XamarinAndroidProject : XamarinProject + public abstract class XamarinAndroidProject : DotNetXamarinProject { protected XamarinAndroidProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") : base (debugConfigurationName, releaseConfigurationName) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs index 668f90adf32..36b6d8fc73c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs @@ -11,6 +11,7 @@ public static class BuildActions { public const string None = "None"; public const string ProjectReference = "ProjectReference"; + public const string PackageReference = "PackageReference"; public const string Reference = "Reference"; public const string Compile = "Compile"; public const string EmbeddedResource = "EmbeddedResource"; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs index ba5ec269195..2a61a827aed 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs @@ -78,7 +78,7 @@ public BuildItem (string buildAction, string include) { } - public BuildItem (string buildAction, Func include) + public BuildItem (string buildAction, Func include = null) { BuildAction = buildAction; Include = include; @@ -86,11 +86,23 @@ public BuildItem (string buildAction, Func include) Timestamp = DateTimeOffset.UtcNow; Encoding = Encoding.UTF8; Attributes = FileAttributes.Normal; + Generator = null; + Remove = null; + SubType = null; + Update = null; + DependentUpon = null; + Version = null; } public DateTimeOffset? Timestamp { get; set; } public string BuildAction { get; set; } public Func Include { get; set; } + public Func Remove { get; set; } + public Func Update { get; set; } + public Func SubType { get; set; } + public Func Generator { get; set; } + public Func DependentUpon { get; set; } + public Func Version { get; set; } public IDictionary Metadata { get; private set; } public Func TextContent { get; set; } public Func BinaryContent { get; set; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs index 1ec86a7e4df..5ff7ab177f3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs @@ -22,13 +22,14 @@ public class Builder : IDisposable public TimeSpan LastBuildTime { get; protected set; } public string BuildLogFile { get; set; } public bool ThrowOnBuildFailure { get; set; } + public bool RequiresMSBuild { get; set; } string GetUnixBuildExe () { RunningMSBuild = false; var tooldir = Directory.Exists (fixed_osx_xbuild_path) ? fixed_osx_xbuild_path : fixed_linux_xbuild_path; string path = Path.Combine (tooldir, xbuildapp); - if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("USE_MSBUILD"))) { + if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("USE_MSBUILD")) || RequiresMSBuild) { path = Path.Combine (tooldir, msbuildapp); RunningMSBuild = true; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs new file mode 100644 index 00000000000..f9efd35a92b --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Xamarin.ProjectTools +{ + public class DotNetStandard : XamarinProject + { + + public override string ProjectTypeGuid { + get { + return string.Empty; + } + } + + public DotNetStandard () + { + Sources = new List (); + OtherBuildItems = new List (); + SetProperty (CommonProperties, "DebugType", "full"); + ItemGroupList.Add (Sources); + } + public string PackageTargetFallback { + get { return GetProperty ("PackageTargetFallback"); } + set { SetProperty ("PackageTargetFallback", value); } + } + public string TargetFramework { + get { return GetProperty ("TargetFramework"); } + set { SetProperty ("TargetFramework", value); } + } + public string Sdk { get; set; } + + public IList OtherBuildItems { get; private set; } + public IList Sources { get; private set; } + + public override string SaveProject () + { + var sb = new StringBuilder (); + sb.AppendLine ("\t"); + foreach (var pg in PropertyGroups) { + if (!pg.Properties.Any ()) + continue; + foreach (var p in pg.Properties) { + var conditon = string.IsNullOrEmpty (p.Condition) ? "" : $" Conditon=\"{p.Condition}\""; + sb.AppendLine ($"\t\t<{p.Name}{conditon}>{p.Value ()}"); + } + } + sb.AppendLine ("\t"); + sb.AppendLine ("\t"); + foreach (var pr in PackageReferences) { + sb.AppendLine ($"\t\t"); + } + sb.AppendLine ("\t"); + sb.AppendLine ("\t"); + foreach (var bi in OtherBuildItems) { + sb.Append ($"\t\t<{bi.BuildAction} "); + if (bi.Include != null) sb.Append ($"Include=\"{bi.Include ()}\" "); + if (bi.Update != null) sb.Append ($"Update=\"{bi.Update ()}\" "); + if (bi.Remove != null) sb.Append ($"Remove=\"{bi.Remove ()}\" "); + if (bi.Generator != null) sb.Append ($"Generator=\"{bi.Generator ()}\" "); + if (bi.DependentUpon != null) sb.Append ($"DependentUpon=\"{bi.DependentUpon ()}\" "); + if (bi.Version != null) sb.Append ($"Version=\"{bi.Version ()}\" "); + if (bi.SubType != null) sb.Append ($"SubType=\"{bi.SubType ()}\" "); + if (bi.Metadata.Any ()) { + sb.AppendLine ($"\t\t/>"); + } else { + sb.AppendLine ($">"); + foreach (var kvp in bi.Metadata) { + sb.AppendLine ($"\t\t\t<{kvp.Key}>{kvp.Value}"); + } + sb.AppendLine ($"\t\t"); + } + } + sb.AppendLine ("\t"); + return $"\r\n{sb.ToString ()}\r\n"; + } + + public override void NuGetRestore (string directory, string packagesDirectory = null) + { + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs new file mode 100644 index 00000000000..7e24a89e82b --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Microsoft.Build.Construction; + +namespace Xamarin.ProjectTools +{ + public abstract class DotNetXamarinProject : XamarinProject + { + protected DotNetXamarinProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) + { + ProjectName = "UnnamedProject"; + + Sources = new List (); + OtherBuildItems = new List (); + + ItemGroupList.Add (References); + ItemGroupList.Add (OtherBuildItems); + ItemGroupList.Add (Sources); + + AddReferences ("System"); // default + + SetProperty (KnownProperties.Configuration, debugConfigurationName, "'$(Configuration)' == ''"); + SetProperty ("Platform", "AnyCPU", "'$(Platform)' == ''"); + SetProperty ("ErrorReport", "prompt"); + SetProperty ("WarningLevel", "4"); + SetProperty ("ConsolePause", "false"); + SetProperty ("RootNamespace", () => RootNamespace ?? ProjectName); + SetProperty ("AssemblyName", () => AssemblyName ?? ProjectName); + SetProperty ("BuildingInsideVisualStudio", "True"); + SetProperty ("BaseIntermediateOutputPath", "obj\\", " '$(BaseIntermediateOutputPath)' == '' "); + + SetProperty (DebugProperties, "DebugSymbols", "true"); + SetProperty (DebugProperties, "DebugType", "full"); + SetProperty (DebugProperties, "Optimize", "false"); + SetProperty (DebugProperties, KnownProperties.OutputPath, Path.Combine ("bin", debugConfigurationName)); + SetProperty (DebugProperties, "DefineConstants", "DEBUG;"); + SetProperty (DebugProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", debugConfigurationName)); + + SetProperty (ReleaseProperties, "Optimize", "true"); + SetProperty (ReleaseProperties, "ErrorReport", "prompt"); + SetProperty (ReleaseProperties, "WarningLevel", "4"); + SetProperty (ReleaseProperties, "ConsolePause", "false"); + SetProperty (ReleaseProperties, KnownProperties.OutputPath, Path.Combine ("bin", releaseConfigurationName)); + SetProperty (ReleaseProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", releaseConfigurationName)); + + Sources.Add (new BuildItem.Source (() => "Properties\\AssemblyInfo" + Language.DefaultExtension) { TextContent = () => ProcessSourceTemplate (AssemblyInfo ?? Language.DefaultAssemblyInfo) }); + } + + void AddProperties (IList list, string condition, KeyValuePair [] props) + { + foreach (var p in props) + list.Add (new Property (condition, p.Key, p.Value)); + } + + public IList OtherBuildItems { get; private set; } + public IList Sources { get; private set; } + + public IList ActiveConfigurationProperties { + get { return IsRelease ? ReleaseProperties : DebugProperties; } + } + + public string OutputPath { + get { return GetProperty (ActiveConfigurationProperties, KnownProperties.OutputPath); } + set { SetProperty (ActiveConfigurationProperties, KnownProperties.OutputPath, value); } + } + + public string IntermediateOutputPath { + get { return GetProperty (ActiveConfigurationProperties, KnownProperties.IntermediateOutputPath); } + set { SetProperty (ActiveConfigurationProperties, KnownProperties.IntermediateOutputPath, value); } + } + + public BuildItem GetItem (string include) + { + return ItemGroupList.SelectMany (g => g).First (i => i.Include ().Equals (include, StringComparison.OrdinalIgnoreCase)); + } + + public void AddReferences (params string [] references) + { + foreach (var s in references) + References.Add (new BuildItem.Reference (s)); + } + + public void AddSources (params string [] sources) + { + foreach (var s in sources) + Sources.Add (new BuildItem.Source (s)); + } + + public void Touch (params string [] itemPaths) + { + foreach (var item in itemPaths) + GetItem (item).Timestamp = DateTimeOffset.Now; + } + + public virtual ProjectRootElement Construct () + { + var root = ProjectRootElement.Create (); + if (Packages.Any ()) + root.AddItemGroup ().AddItem (BuildActions.None, "packages.config"); + foreach (var pkg in Packages.Where (p => p.AutoAddReferences)) + foreach (var reference in pkg.References) + if (!References.Any (r => r.Include == reference.Include)) + References.Add (reference); + + foreach (var pg in PropertyGroups) + pg.AddElement (root); + + foreach (var ig in ItemGroupList) { + var ige = root.AddItemGroup (); + foreach (var i in ig) { + if (i.Deleted) + continue; + ige.AddItem (i.BuildAction, i.Include (), i.Metadata); + } + } + + root.FullPath = ProjectName + Language.DefaultProjectExtension; + + return root; + } + + public override string SaveProject () + { + var root = Construct (); + var sw = new StringWriter (); + root.Save (sw); + var document = XDocument.Parse (sw.ToString ()); + var pn = XName.Get ("Project", "http://schemas.microsoft.com/developer/msbuild/2003"); + var p = document.Element (pn); + if (p != null) { + var referenceGroup = p.Elements ().FirstOrDefault (x => x.Name.LocalName == "ItemGroup" && x.HasElements && x.Elements ().Any (e => e.Name.LocalName == "Reference")); + if (referenceGroup != null) { + foreach (var pr in PackageReferences) { + var e = XElement.Parse ($""); + referenceGroup.Add (e); + } + sw = new StringWriter (); + document.Save (sw); + } + } + return sw.ToString (); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs index 9566758d051..9ffdf86fdcb 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs @@ -60,7 +60,7 @@ public bool Build (XamarinProject project, bool doNotCleanupOnUpdate = false, st Output = project.CreateBuildOutput (this); - project.NuGetRestore (ProjectDirectory, PackagesDirectory); + project.NuGetRestore (Path.Combine (Root, ProjectDirectory), PackagesDirectory); bool result = BuildInternal (Path.Combine (ProjectDirectory, project.ProjectFilePath), Target, parameters, environmentVariables); built_before = true; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinPCLProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinPCLProject.cs index 6236210277b..2aa7176ca3f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinPCLProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinPCLProject.cs @@ -2,7 +2,7 @@ namespace Xamarin.ProjectTools { - public class XamarinPCLProject : XamarinProject + public class XamarinPCLProject : DotNetXamarinProject { public XamarinPCLProject () { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs index 97e915db0a0..425c8d75c6c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs @@ -9,37 +9,43 @@ namespace Xamarin.ProjectTools { - - // no need to be Xamarin specific, but I want to not name Project to avoid local name conflict :/ - public abstract class XamarinProject + public abstract class XamarinProject { + string debugConfigurationName; + string releaseConfigurationName; + + public virtual ProjectLanguage Language { get; set; } + public string ProjectName { get; set; } public string ProjectGuid { get; set; } public string AssemblyName { get; set; } + public abstract string ProjectTypeGuid { get; } - public virtual ProjectLanguage Language { get; set; } + public IList DebugProperties { get; private set; } + public IList ReleaseProperties { get; private set; } + public IList CommonProperties { get; private set; } + public IList> ItemGroupList { get; private set; } + public IList PropertyGroups { get; private set; } + public IList Packages { get; private set; } + public IList References { get; private set; } + public IList PackageReferences { get; private set; } + public IList Imports { get; private set; } + PropertyGroup common, debug, release; - string debugConfigurationName; - string releaseConfigurationName; + public bool IsRelease { + get { return GetProperty (KnownProperties.Configuration) == releaseConfigurationName; } + set { SetProperty ("Configuration", value ? releaseConfigurationName : debugConfigurationName); } + } - protected XamarinProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + public XamarinProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") { - ProjectName = "UnnamedProject"; - this.debugConfigurationName = debugConfigurationName; this.releaseConfigurationName = releaseConfigurationName; - Sources = new List (); References = new List (); - OtherBuildItems = new List (); - + PackageReferences = new List (); ItemGroupList = new List> (); - ItemGroupList.Add (References); - ItemGroupList.Add (OtherBuildItems); - ItemGroupList.Add (Sources); - - AddReferences ("System"); // default - + PropertyGroups = new List (); CommonProperties = new List (); common = new PropertyGroup (null, CommonProperties); DebugProperties = new List (); @@ -47,89 +53,13 @@ protected XamarinProject (string debugConfigurationName = "Debug", string releas ReleaseProperties = new List (); release = new PropertyGroup ($"'$(Configuration)|$(Platform)' == '{releaseConfigurationName}|AnyCPU'", ReleaseProperties); - PropertyGroups = new List (); PropertyGroups.Add (common); PropertyGroups.Add (debug); PropertyGroups.Add (release); Packages = new List (); - - SetProperty (KnownProperties.Configuration, debugConfigurationName, "'$(Configuration)' == ''"); - SetProperty ("Platform", "AnyCPU", "'$(Platform)' == ''"); - SetProperty ("ErrorReport", "prompt"); - SetProperty ("WarningLevel", "4"); - SetProperty ("ConsolePause", "false"); - SetProperty ("RootNamespace", () => RootNamespace ?? ProjectName); - SetProperty ("AssemblyName", () => AssemblyName ?? ProjectName); - SetProperty ("BuildingInsideVisualStudio", "True"); - SetProperty ("BaseIntermediateOutputPath", "obj\\", " '$(BaseIntermediateOutputPath)' == '' "); - - SetProperty (DebugProperties, "DebugSymbols", "true"); - SetProperty (DebugProperties, "DebugType", "full"); - SetProperty (DebugProperties, "Optimize", "false"); - SetProperty (DebugProperties, KnownProperties.OutputPath, Path.Combine ("bin", debugConfigurationName)); - SetProperty (DebugProperties, "DefineConstants", "DEBUG;"); - SetProperty (DebugProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", debugConfigurationName)); - - SetProperty (ReleaseProperties, "Optimize", "true"); - SetProperty (ReleaseProperties, "ErrorReport", "prompt"); - SetProperty (ReleaseProperties, "WarningLevel", "4"); - SetProperty (ReleaseProperties, "ConsolePause", "false"); - SetProperty (ReleaseProperties, KnownProperties.OutputPath, Path.Combine ("bin", releaseConfigurationName)); - SetProperty (ReleaseProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", releaseConfigurationName)); - - Sources.Add (new BuildItem.Source (() => "Properties\\AssemblyInfo" + Language.DefaultExtension) { TextContent = () => ProcessSourceTemplate (AssemblyInfo ?? Language.DefaultAssemblyInfo) }); - Imports = new List (); - } - - public virtual BuildOutput CreateBuildOutput (ProjectBuilder builder) - { - return new BuildOutput (this) { Builder = builder }; - } - - void AddProperties (IList list, string condition, KeyValuePair [] props) - { - foreach (var p in props) - list.Add (new Property (condition, p.Key, p.Value)); - } - - PropertyGroup common, debug, release; - public IList> ItemGroupList { get; private set; } - public IList PropertyGroups { get; private set; } - public IList CommonProperties { get; private set; } - public IList DebugProperties { get; private set; } - public IList ReleaseProperties { get; private set; } - public IList OtherBuildItems { get; private set; } - public IList Sources { get; private set; } - public IList References { get; private set; } - public IList Packages { get; private set; } - public IList Imports { get; private set; } - - public abstract string ProjectTypeGuid { get; } - - public bool IsRelease { - get { return GetProperty (KnownProperties.Configuration) == releaseConfigurationName; } - set { SetProperty ("Configuration", value ? releaseConfigurationName : debugConfigurationName); } - } - - public IList ActiveConfigurationProperties { - get { return IsRelease ? ReleaseProperties : DebugProperties; } - } - - public string OutputPath { - get { return GetProperty (ActiveConfigurationProperties, KnownProperties.OutputPath); } - set { SetProperty (ActiveConfigurationProperties, KnownProperties.OutputPath, value); } - } - public string IntermediateOutputPath { - get { return GetProperty (ActiveConfigurationProperties, KnownProperties.IntermediateOutputPath); } - set { SetProperty (ActiveConfigurationProperties, KnownProperties.IntermediateOutputPath, value); } - } - - public BuildItem GetItem (string include) - { - return ItemGroupList.SelectMany (g => g).First (i => i.Include ().Equals (include, StringComparison.OrdinalIgnoreCase)); } public string GetProperty (string name) @@ -188,50 +118,6 @@ public void SetProperty (IList group, string name, Func value, } } - public void AddReferences (params string [] references) - { - foreach (var s in references) - References.Add (new BuildItem.Reference (s)); - } - - public void AddSources (params string [] sources) - { - foreach (var s in sources) - Sources.Add (new BuildItem.Source (s)); - } - - public void Touch (params string [] itemPaths) - { - foreach (var item in itemPaths) - GetItem (item).Timestamp = DateTimeOffset.Now; - } - - public virtual ProjectRootElement Construct () - { - var root = ProjectRootElement.Create (); - if (Packages.Any ()) - root.AddItemGroup ().AddItem (BuildActions.None, "packages.config"); - foreach (var pkg in Packages.Where (p => p.AutoAddReferences)) - foreach (var reference in pkg.References) - if (!References.Any (r => r.Include == reference.Include)) - References.Add (reference); - foreach (var pg in PropertyGroups) - pg.AddElement (root); - - foreach (var ig in ItemGroupList) { - var ige = root.AddItemGroup (); - foreach (var i in ig) { - if (i.Deleted) - continue; - ige.AddItem (i.BuildAction, i.Include (), i.Metadata); - } - } - - root.FullPath = ProjectName + Language.DefaultProjectExtension; - - return root; - } - string project_file_path; public string ProjectFilePath { get { return project_file_path ?? ProjectName + Language.DefaultProjectExtension; } @@ -241,12 +127,14 @@ public string ProjectFilePath { public string AssemblyInfo { get; set; } public string RootNamespace { get; set; } - public string SaveProject () + public virtual string SaveProject () { - var root = Construct (); - var sw = new StringWriter (); - root.Save (sw); - return sw.ToString (); + return string.Empty; + } + + public virtual BuildOutput CreateBuildOutput (ProjectBuilder builder) + { + return new BuildOutput (this) { Builder = builder }; } public virtual List Save (bool saveProject = true) @@ -357,8 +245,7 @@ public void UpdateProjectFiles (string directory, IEnumerable p File.SetLastWriteTimeUtc (path, p.Timestamp != null ? p.Timestamp.Value.UtcDateTime : DateTime.UtcNow); File.SetAttributes (path, p.Attributes); p.Timestamp = new DateTimeOffset (new FileInfo (path).LastWriteTimeUtc); - } - else if (p.BinaryContent != null && needsUpdate) { + } else if (p.BinaryContent != null && needsUpdate) { using (var f = File.Create (path)) f.Write (p.BinaryContent, 0, p.BinaryContent.Length); File.SetLastWriteTimeUtc (path, p.Timestamp != null ? p.Timestamp.Value.UtcDateTime : DateTime.UtcNow); @@ -382,7 +269,7 @@ public void UpdateProjectFiles (string directory, IEnumerable p } - public void NuGetRestore (string directory, string packagesDirectory = null) + public virtual void NuGetRestore (string directory, string packagesDirectory = null) { if (!Packages.Any ()) return; @@ -402,6 +289,5 @@ public string ProcessSourceTemplate (string source) { return source.Replace ("${ROOT_NAMESPACE}", RootNamespace ?? ProjectName).Replace ("${PROJECT_NAME}", ProjectName); } - } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj index 090239390f6..9b421f1457d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj @@ -77,6 +77,8 @@ + +