Skip to content

Commit 1c9c8c9

Browse files
authored
[Java.Interop.Tools.Maven] Initial commit. (#1179)
Context: dotnet/android#8649 Add a new `Java.Interop.Tools.Maven.dll` assembly that contains functionality for: - Retrieving artifacts from Maven - Parsing and understanding POM files This assembly is used by dotnet/android#8649 and replaces our previous usage of [`MavenNet.dll`][0]. `Java.Interop.Tools.Maven.dll` contains a binding of [`maven-4.0.0.xsd`][1], generated via [dotnet-xscgen][2]. To update the binding: # Install the binding utility % dotnet tool install -g dotnet-xscgen # Grab the version of `maven*.xsd` you want to bind/update to % curl -o maven-4.0.0.xsd https://maven.apache.org/xsd/maven-4.0.0.xsd # `dotnet tool install` installs into e.g. `$HOME/.dotnet/tools`, which might not be in `$PATH`… # Run the `UpdateProjectSchema` target % PATH=$HOME/.dotnet/tools:$PATH dotnet build -t:UpdateProjectSchema \ src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.csproj \ -p:MavenXsd=`pwd`/maven-4.0.0.xsd [0]: https://www.nuget.org/packages/MavenNet [1]: https://maven.apache.org/xsd/maven-4.0.0.xsd [2]: https://www.nuget.org/packages/dotnet-xscgen
1 parent 3436a30 commit 1c9c8c9

27 files changed

+7578
-0
lines changed

Java.Interop.sln

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.Expressi
113113
EndProject
114114
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.Expressions-Tests", "tests\Java.Interop.Tools.Expressions-Tests\Java.Interop.Tools.Expressions-Tests.csproj", "{211BAA88-66B1-41B2-88B2-530DBD8DF702}"
115115
EndProject
116+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Maven", "src\Java.Interop.Tools.Maven\Java.Interop.Tools.Maven.csproj", "{DA458F90-218B-4FE3-995F-AF4B27895FA2}"
117+
EndProject
118+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Maven-Tests", "tests\Java.Interop.Tools.Maven-Tests\Java.Interop.Tools.Maven-Tests.csproj", "{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}"
116119
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hello-NativeAOTFromJNI", "samples\Hello-NativeAOTFromJNI\Hello-NativeAOTFromJNI.csproj", "{8DB3842B-73D7-491C-96F9-EBC863E2C917}"
117120
EndProject
118121
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{40B3CE2F-B8DE-45CD-A43A-0F1A89BDB803}"
@@ -326,6 +329,14 @@ Global
326329
{211BAA88-66B1-41B2-88B2-530DBD8DF702}.Debug|Any CPU.Build.0 = Debug|Any CPU
327330
{211BAA88-66B1-41B2-88B2-530DBD8DF702}.Release|Any CPU.ActiveCfg = Release|Any CPU
328331
{211BAA88-66B1-41B2-88B2-530DBD8DF702}.Release|Any CPU.Build.0 = Release|Any CPU
332+
{DA458F90-218B-4FE3-995F-AF4B27895FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
333+
{DA458F90-218B-4FE3-995F-AF4B27895FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
334+
{DA458F90-218B-4FE3-995F-AF4B27895FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
335+
{DA458F90-218B-4FE3-995F-AF4B27895FA2}.Release|Any CPU.Build.0 = Release|Any CPU
336+
{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
337+
{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Debug|Any CPU.Build.0 = Debug|Any CPU
338+
{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Release|Any CPU.ActiveCfg = Release|Any CPU
339+
{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Release|Any CPU.Build.0 = Release|Any CPU
329340
{8DB3842B-73D7-491C-96F9-EBC863E2C917}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
330341
{8DB3842B-73D7-491C-96F9-EBC863E2C917}.Debug|Any CPU.Build.0 = Debug|Any CPU
331342
{8DB3842B-73D7-491C-96F9-EBC863E2C917}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -388,6 +399,8 @@ Global
388399
{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC} = {271C9F30-F679-4793-942B-0D9527CB3E2F}
389400
{1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A} = {0998E45F-8BCE-4791-A944-962CD54E2D80}
390401
{211BAA88-66B1-41B2-88B2-530DBD8DF702} = {271C9F30-F679-4793-942B-0D9527CB3E2F}
402+
{DA458F90-218B-4FE3-995F-AF4B27895FA2} = {0998E45F-8BCE-4791-A944-962CD54E2D80}
403+
{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D} = {271C9F30-F679-4793-942B-0D9527CB3E2F}
391404
{8DB3842B-73D7-491C-96F9-EBC863E2C917} = {D5A93398-AEB1-49F3-89DC-3904A47DB0C7}
392405
{C2AF6ACF-04F6-4B41-95EA-97A372C075F9} = {40B3CE2F-B8DE-45CD-A43A-0F1A89BDB803}
393406
EndGlobalSection

build-tools/automation/templates/core-tests.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ steps:
7777
arguments: bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Xamarin.SourceWriter-Tests.dll
7878
continueOnError: true
7979

80+
- task: DotNetCoreCLI@2
81+
displayName: 'Tests: Java.Interop.Tools.Maven'
82+
inputs:
83+
command: test
84+
testRunTitle: Java.Interop.Tools.Maven (${{ parameters.platformName }})
85+
arguments: bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Java.Interop.Tools.Maven-Tests.dll
86+
continueOnError: true
87+
8088
- task: DotNetCoreCLI@2
8189
displayName: 'Tests: Java.Interop'
8290
condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true'))
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Java.Interop.Tools.Maven.Models;
4+
5+
namespace Java.Interop.Tools.Maven;
6+
7+
public class DefaultProjectResolver : IProjectResolver
8+
{
9+
readonly Dictionary<string, Project> poms = new ();
10+
11+
public void Register (Project project)
12+
{
13+
poms.Add (project.VersionedArtifactString, project);
14+
}
15+
16+
public virtual Project Resolve (Artifact artifact)
17+
{
18+
if (poms.TryGetValue (artifact.VersionedArtifactString, out var project))
19+
return project;
20+
21+
throw new InvalidOperationException ($"No POM registered for {artifact}");
22+
}
23+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
using System.Collections.ObjectModel;
3+
using System.Xml.Linq;
4+
using Java.Interop.Tools.Maven.Models;
5+
6+
namespace Java.Interop.Tools.Maven.Extensions;
7+
8+
class PropertyStack
9+
{
10+
// Why go to this trouble?
11+
// A property can be specified in both a child POM and its parent POM.
12+
// Even if the property is being consumed in the parent POM, the property in
13+
// the child POM takes precedence.
14+
readonly List<List<KeyValuePair<string, string>>> stack = new ();
15+
16+
public void Push (ModelProperties? properties)
17+
{
18+
// We add a new list to the stack, even if it's empty, so that the Pop works later
19+
var list = new List<KeyValuePair<string, string>> ();
20+
21+
if (properties?.Any is Collection<XElement> props)
22+
foreach (var prop in props)
23+
list.Add (new KeyValuePair<string, string> (prop.Name.LocalName, prop.Value));
24+
25+
stack.Add (list);
26+
}
27+
28+
public void Pop ()
29+
{
30+
stack.RemoveAt (stack.Count - 1);
31+
}
32+
33+
public string Apply (string value)
34+
{
35+
if (stack.Count == 0 || !value.Contains ("${"))
36+
return value;
37+
38+
foreach (var property_set in stack) {
39+
foreach (var prop in property_set)
40+
value = value.Replace ($"${{{prop.Key}}}", prop.Value);
41+
}
42+
43+
return value;
44+
}
45+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
3+
namespace Java.Interop.Tools.Maven.Extensions;
4+
5+
static class StringExtensions
6+
{
7+
/// <summary>
8+
/// Shortcut for !string.IsNullOrWhiteSpace (s)
9+
/// </summary>
10+
public static bool HasValue ([NotNullWhen (true)] this string? s) => !string.IsNullOrWhiteSpace (s);
11+
12+
/// <summary>
13+
/// Shortcut for s ?? string.Empty
14+
/// </summary>
15+
public static string OrEmpty (this string? str) => str ?? string.Empty;
16+
17+
/// <summary>
18+
/// Removes the first subset of a delimited string. ("127.0.0.1" -> "0.0.1")
19+
/// </summary>
20+
[return: NotNullIfNotNull (nameof (s))]
21+
public static string? ChompFirst (this string? s, char separator)
22+
{
23+
if (!s.HasValue ())
24+
return s;
25+
26+
var index = s.IndexOf (separator);
27+
28+
if (index < 0)
29+
return string.Empty;
30+
31+
return s.Substring (index + 1);
32+
}
33+
34+
/// <summary>
35+
/// Removes the final subset of a delimited string. ("127.0.0.1" -> "127.0.0")
36+
/// </summary>
37+
[return: NotNullIfNotNull (nameof (s))]
38+
public static string? ChompLast (this string? s, char separator)
39+
{
40+
if (!s.HasValue ())
41+
return s;
42+
43+
var index = s.LastIndexOf (separator);
44+
45+
if (index < 0)
46+
return string.Empty;
47+
48+
return s.Substring (0, index);
49+
}
50+
51+
/// <summary>
52+
/// Returns the first subset of a delimited string. ("127.0.0.1" -> "127")
53+
/// </summary>
54+
[return: NotNullIfNotNull (nameof (s))]
55+
public static string? FirstSubset (this string? s, char separator)
56+
{
57+
if (!s.HasValue ())
58+
return s;
59+
60+
var index = s.IndexOf (separator);
61+
62+
if (index < 0)
63+
return s;
64+
65+
return s.Substring (0, index);
66+
}
67+
68+
/// <summary>
69+
/// Returns the final subset of a delimited string. ("127.0.0.1" -> "1")
70+
/// </summary>
71+
[return: NotNullIfNotNull (nameof (s))]
72+
public static string? LastSubset (this string? s, char separator)
73+
{
74+
if (!s.HasValue ())
75+
return s;
76+
77+
var index = s.LastIndexOf (separator);
78+
79+
if (index < 0)
80+
return s;
81+
82+
return s.Substring (index + 1);
83+
}
84+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using Java.Interop.Tools.Maven.Models;
2+
3+
namespace Java.Interop.Tools.Maven;
4+
5+
public interface IProjectResolver
6+
{
7+
Project Resolve (Artifact artifact);
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>11.0</LangVersion>
6+
<Nullable>enable</Nullable>
7+
<DefineConstants>INTERNAL_NULLABLE_ATTRIBUTES</DefineConstants>
8+
<Nullable>enable</Nullable>
9+
<SignAssembly>true</SignAssembly>
10+
<AssemblyOriginatorKeyFile>..\..\product.snk</AssemblyOriginatorKeyFile>
11+
</PropertyGroup>
12+
13+
<Import Project="..\..\TargetFrameworkDependentValues.props" />
14+
15+
<PropertyGroup>
16+
<OutputPath>$(UtilityOutputFullPath)</OutputPath>
17+
</PropertyGroup>
18+
19+
<ItemGroup>
20+
<Compile Include="..\utils\NullableAttributes.cs" />
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
25+
</ItemGroup>
26+
27+
<Import Project="Java.Interop.Tools.Maven.targets" />
28+
</Project>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<Project>
2+
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Java.Interop.BootstrapTasks.dll" TaskName="Java.Interop.BootstrapTasks.ReplaceFileContents" />
3+
4+
<!-- This target generates the Project model from the Maven POM schema.
5+
Prerequisites:
6+
- Install dotnet tool: 'dotnet tool install -g dotnet-xscgen'
7+
- Download new schema to this directory (eg: https://maven.apache.org/xsd/maven-4.0.0.xsd)
8+
Run 'dotnet build -t:UpdateProjectSchema -p:MavenXsd=maven-4.0.0.xsd' -->
9+
<Target Name="UpdateProjectSchema">
10+
11+
<PropertyGroup>
12+
<MavenXsd Condition=" '$(MavenXsd)' == '' ">maven-4.0.0.xsd</MavenXsd>
13+
</PropertyGroup>
14+
15+
<ItemGroup>
16+
<_XscgenOpt Include="$(MavenXsd)" />
17+
<_XscgenOpt Include="--namespace http://maven.apache.org/POM/4.0.0=Java.Interop.Tools.Maven.Models" />
18+
<_XscgenOpt Include="--typeNameSubstitute T:Model=Project" />
19+
<_XscgenOpt Include="--nullable" />
20+
<_XscgenOpt Include="--pcl" />
21+
<_XscgenOpt Include="--netCore" />
22+
<_XscgenOpt Include="--nullableReferenceAttributes" />
23+
<_XscgenOpt Include="-o &quot;Models&quot;" />
24+
</ItemGroup>
25+
26+
<Exec Command="xscgen @(_XscgenOpt, ' ')" />
27+
28+
<!-- Remove the Namespace from eg: [System.Xml.Serialization.XmlRootAttribute("project", Namespace="http://maven.apache.org/POM/4.0.0")]
29+
This allows us to import POM files that do not specify an XML namespace (xmlns). -->
30+
<ItemGroup>
31+
<Replacements Include=', Namespace="http://maven.apache.org/POM/4.0.0"' Replacement="" />
32+
</ItemGroup>
33+
34+
<ReplaceFileContents
35+
TemplateFile="Models/Java.Interop.Tools.Maven.Models.cs"
36+
OutputFile="Models/Project.cs"
37+
Replacements="@(Replacements)"
38+
/>
39+
40+
<Delete Files="Models/Java.Interop.Tools.Maven.Models.cs" />
41+
</Target>
42+
</Project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
4+
namespace Java.Interop.Tools.Maven.Models;
5+
6+
public class Artifact
7+
{
8+
public string GroupId { get; }
9+
10+
public string Id { get; }
11+
12+
public string Version { get; }
13+
14+
public string ArtifactString => $"{GroupId}:{Id}";
15+
16+
// Format should match Project.ArtifactString for comparisons.
17+
public string VersionedArtifactString => $"{GroupId}:{Id}:{Version}";
18+
19+
public Artifact (string groupId, string artifactId, string version)
20+
{
21+
Id = artifactId;
22+
GroupId = groupId;
23+
Version = version;
24+
}
25+
26+
public static Artifact Parse (string value)
27+
{
28+
if (TryParse (value, out var artifact))
29+
return artifact;
30+
31+
throw new ArgumentException ($"Invalid artifact format: {value}");
32+
}
33+
34+
public static bool TryParse (string value, [NotNullWhen (true)]out Artifact? artifact)
35+
{
36+
artifact = null;
37+
38+
var parts = value.Split (':');
39+
40+
if (parts.Length != 3)
41+
return false;
42+
43+
artifact = new Artifact (parts [0], parts [1], parts [2]);
44+
45+
return true;
46+
}
47+
48+
public override string ToString () => VersionedArtifactString;
49+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Java.Interop.Tools.Maven.Extensions;
2+
3+
namespace Java.Interop.Tools.Maven.Models;
4+
5+
public partial class Dependency
6+
{
7+
public Artifact ToArtifact ()
8+
=> new Artifact (GroupId.OrEmpty (), ArtifactId.OrEmpty (), Version.OrEmpty ());
9+
}

0 commit comments

Comments
 (0)