-
Notifications
You must be signed in to change notification settings - Fork 533
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
[Xamarin.Android.Build.Tasks] Add GetAndroidDependencies Target #1290
Changes from all commits
d536c72
fce561c
4e751da
ac1ac27
f719361
fe3fda9
2ecff08
4312f6d
8785f1f
5d1770c
6df41a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
using System; | ||
using System.IO; | ||
using System.Collections.Generic; | ||
using Microsoft.Build.Framework; | ||
using Microsoft.Build.Utilities; | ||
using Xamarin.Android.Tools; | ||
|
||
namespace Xamarin.Android.Tasks | ||
{ | ||
public class CalculateProjectDependencies : Task | ||
{ | ||
const int DefaultMinSDKVersion = 11; | ||
|
||
[Required] | ||
public string TargetFrameworkVersion { get; set; } | ||
|
||
[Required] | ||
public ITaskItem ManifestFile { get; set; } | ||
|
||
[Required] | ||
public string BuildToolsVersion { get; set; } | ||
|
||
public string PlatformToolsVersion { get; set; } | ||
|
||
public string ToolsVersion { get; set; } | ||
|
||
public string NdkVersion { get; set; } | ||
|
||
[Output] | ||
public ITaskItem [] Dependencies { get; set; } | ||
|
||
ITaskItem CreateAndroidDependency (string include, string version) | ||
{ | ||
if (string.IsNullOrEmpty (version)) | ||
return new TaskItem (include); | ||
|
||
return new TaskItem (include, new Dictionary<string, string> { | ||
{ "Version", version } | ||
}); | ||
} | ||
|
||
public override bool Execute () | ||
{ | ||
var dependencies = new List<ITaskItem> (); | ||
var targetApiLevel = MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion (TargetFrameworkVersion); | ||
var manifestApiLevel = DefaultMinSDKVersion; | ||
if (File.Exists (ManifestFile.ItemSpec)) { | ||
var manifest = AndroidAppManifest.Load (ManifestFile.ItemSpec, MonoAndroidHelper.SupportedVersions); | ||
manifestApiLevel = manifest.TargetSdkVersion ?? manifest.MinSdkVersion ?? DefaultMinSDKVersion; | ||
} | ||
var sdkVersion = Math.Max (targetApiLevel.Value, manifestApiLevel); | ||
dependencies.Add (CreateAndroidDependency ($"platforms;android-{sdkVersion}", $"")); | ||
dependencies.Add (CreateAndroidDependency ($"build-tools;{BuildToolsVersion}", BuildToolsVersion)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is the version duplicated here? Why not |
||
if (!string.IsNullOrEmpty (PlatformToolsVersion)) { | ||
dependencies.Add (CreateAndroidDependency ("platform-tools", PlatformToolsVersion)); | ||
} | ||
if (!string.IsNullOrEmpty (ToolsVersion)) { | ||
dependencies.Add (CreateAndroidDependency ("tools", ToolsVersion)); | ||
} | ||
if (!string.IsNullOrEmpty (NdkVersion)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should only be returned if the project actually depends on the NDK. Also, why not just use an ItemGroup in the target for this one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, using an var task = new CalculateProjectDependencies {
BuildEngine = engine,
}; By constructing it that way, you can invoke all the properties and methods "normally," without the overhead of an entire MSBuild process+context: task.PlatformToolsVersion = "26.0.3";
task.ToolsVersion = "26.0.1";
task.NdkVersion = "12.1";
task.BuildToolsVersion = "26.0.1";
task.TargetFrameworkVersion = "v8.0";
task.ManifestFile = new TaskItem (Path.Combine (path, "AndroidManifest.xml"));
Assert.IsTrue (task.Execute ());
... I find this hugely easier to interpret (what are the output items? What value do the metadata properties contain?) and is much faster to execute. |
||
dependencies.Add (CreateAndroidDependency ("ndk-bundle", NdkVersion)); | ||
} | ||
Dependencies = dependencies.ToArray (); | ||
return !Log.HasLoggedErrors; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
using System; | ||
using NUnit.Framework; | ||
using Xamarin.ProjectTools; | ||
using System.IO; | ||
using System.Linq; | ||
using Microsoft.Build.Framework; | ||
using System.Text; | ||
using Xamarin.Android.Tasks; | ||
using Microsoft.Build.Utilities; | ||
|
||
namespace Xamarin.Android.Build.Tests { | ||
|
||
[TestFixture] | ||
[Parallelizable (ParallelScope.Children)] | ||
public class GetDependenciesTest : BaseTest { | ||
|
||
[Test] | ||
public void ManifestFileDoesNotExist () | ||
{ | ||
var path = Path.Combine ("temp", TestName); | ||
var referencePath = CreateFauxReferencesDirectory (Path.Combine (path, "references"), new ApiInfo[] { | ||
new ApiInfo () { Id = 26, Level = 26, Name = "Oreo", FrameworkVersion = "v8.0", Stable = true }, | ||
} ); | ||
MonoAndroidHelper.RefreshSupportedVersions (new string [] { referencePath }); | ||
IBuildEngine engine = new MockBuildEngine (TestContext.Out); | ||
var task = new CalculateProjectDependencies { | ||
BuildEngine = engine | ||
}; | ||
|
||
task.PlatformToolsVersion = "26.0.3"; | ||
task.ToolsVersion = "26.0.1"; | ||
task.NdkVersion = "12.1"; | ||
task.BuildToolsVersion = "26.0.1"; | ||
task.TargetFrameworkVersion = "v8.0"; | ||
task.ManifestFile = new TaskItem (Path.Combine (path, "AndroidManifest.xml")); | ||
Assert.IsTrue (task.Execute ()); | ||
Assert.IsNotNull (task.Dependencies); | ||
Assert.AreEqual (5, task.Dependencies.Length); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools;26.0.1" && x.GetMetadata ("Version") == "26.0.1"), | ||
"Dependencies should contains a build-tools version 26.0.1"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "tools" && x.GetMetadata ("Version") == "26.0.1"), | ||
"Dependencies should contains a tools version 26.0.1"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms;android-26" && x.GetMetadata ("Version") == ""), | ||
"Dependencies should contains a platform version android-26"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), | ||
"Dependencies should contains a platform-tools version 26.0.3"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), | ||
"Dependencies should contains a ndk-bundle version 12.1"); | ||
} | ||
|
||
[Test] | ||
public void ManifestFileExists () | ||
{ | ||
var path = Path.Combine (Root, "temp", TestName); | ||
var referencePath = CreateFauxReferencesDirectory (Path.Combine (path, "references"), new ApiInfo[] { | ||
new ApiInfo () { Id = 26, Level = 26, Name = "Oreo", FrameworkVersion = "v8.0", Stable = true }, | ||
} ); | ||
MonoAndroidHelper.RefreshSupportedVersions (new string [] { referencePath }); | ||
IBuildEngine engine = new MockBuildEngine (TestContext.Out); | ||
var task = new CalculateProjectDependencies { | ||
BuildEngine = engine | ||
}; | ||
|
||
|
||
Directory.CreateDirectory (path); | ||
var manifestFile = Path.Combine (path, "AndroidManifest.xml"); | ||
File.WriteAllText (manifestFile, @"<?xml version='1.0' ?> | ||
<manifest xmlns:android='http://schemas.android.com/apk/res/android' android:versionCode='1' android:versionName='1.0' package='Mono.Android_Tests'> | ||
<uses-sdk android:minSdkVersion='10' /> | ||
</manifest>"); | ||
|
||
task.PlatformToolsVersion = "26.0.3"; | ||
task.ToolsVersion = "26.0.1"; | ||
task.NdkVersion = "12.1"; | ||
task.BuildToolsVersion = "26.0.1"; | ||
task.TargetFrameworkVersion = "v8.0"; | ||
task.ManifestFile = new TaskItem (manifestFile); | ||
Assert.IsTrue(task.Execute ()); | ||
Assert.IsNotNull (task.Dependencies); | ||
Assert.AreEqual (5, task.Dependencies.Length); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools;26.0.1" && x.GetMetadata ("Version") == "26.0.1"), | ||
"Dependencies should contains a build-tools version 26.0.1"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "tools" && x.GetMetadata ("Version") == "26.0.1"), | ||
"Dependencies should contains a tools version 26.0.1"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms;android-26" && x.GetMetadata ("Version") == ""), | ||
"Dependencies should contains a platform version android-26"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), | ||
"Dependencies should contains a platform-tools version 26.0.3"); | ||
Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), | ||
"Dependencies should contains a ndk-bundle version 12.1"); | ||
|
||
Directory.Delete (path, recursive: true); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Microsoft.Build.Framework; | ||
|
||
namespace Xamarin.Android.Build.Tests { | ||
public class MockBuildEngine : IBuildEngine, IBuildEngine2, IBuildEngine3, IBuildEngine4 { | ||
public MockBuildEngine (TextWriter output) | ||
{ | ||
this.Output = output; | ||
} | ||
|
||
private TextWriter Output { get; } | ||
|
||
int IBuildEngine.ColumnNumberOfTaskNode => -1; | ||
|
||
bool IBuildEngine.ContinueOnError => false; | ||
|
||
int IBuildEngine.LineNumberOfTaskNode => -1; | ||
|
||
string IBuildEngine.ProjectFileOfTaskNode => "this.xml"; | ||
|
||
bool IBuildEngine2.IsRunningMultipleNodes => false; | ||
|
||
bool IBuildEngine.BuildProjectFile (string projectFileName, string [] targetNames, IDictionary globalProperties, IDictionary targetOutputs) => true; | ||
|
||
void IBuildEngine.LogCustomEvent (CustomBuildEventArgs e) | ||
{ | ||
this.Output.WriteLine ($"Custom: {e.Message}"); | ||
} | ||
|
||
void IBuildEngine.LogErrorEvent (BuildErrorEventArgs e) | ||
{ | ||
this.Output.WriteLine ($"Error: {e.Message}"); | ||
} | ||
|
||
void IBuildEngine.LogMessageEvent (BuildMessageEventArgs e) | ||
{ | ||
this.Output.WriteLine ($"Message: {e.Message}"); | ||
} | ||
|
||
void IBuildEngine.LogWarningEvent (BuildWarningEventArgs e) | ||
{ | ||
this.Output.WriteLine ($"Warning: {e.Message}"); | ||
} | ||
|
||
private Dictionary<object, object> Tasks = new Dictionary<object, object> (); | ||
|
||
void IBuildEngine4.RegisterTaskObject (object key, object obj, RegisteredTaskObjectLifetime lifetime, bool allowEarlyCollection) | ||
{ | ||
Tasks.Add (key, obj); | ||
} | ||
|
||
object IBuildEngine4.GetRegisteredTaskObject (object key, RegisteredTaskObjectLifetime lifetime) | ||
{ | ||
return null; | ||
} | ||
|
||
object IBuildEngine4.UnregisterTaskObject (object key, RegisteredTaskObjectLifetime lifetime) | ||
{ | ||
var obj = Tasks [key]; | ||
Tasks.Remove (key); | ||
return obj; | ||
} | ||
|
||
BuildEngineResult IBuildEngine3.BuildProjectFilesInParallel (string [] projectFileNames, string [] targetNames, IDictionary [] globalProperties, IList<string> [] removeGlobalProperties, string [] toolsVersion, bool returnTargetOutputs) | ||
{ | ||
throw new NotImplementedException (); | ||
} | ||
|
||
void IBuildEngine3.Yield () { } | ||
|
||
void IBuildEngine3.Reacquire () { } | ||
|
||
bool IBuildEngine2.BuildProjectFile (string projectFileName, string [] targetNames, IDictionary globalProperties, IDictionary targetOutputs, string toolsVersion) => true; | ||
|
||
bool IBuildEngine2.BuildProjectFilesInParallel (string [] projectFileNames, string [] targetNames, IDictionary [] globalProperties, IDictionary [] targetOutputsPerProject, string [] toolsVersion, bool useResultsCache, bool unloadProjectsOnCompletion) => true; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Semicolon is a really bad choice for a separator... it has meaning in MSBuild. How about
platform-android-{sdkVersion}
?