Skip to content

Commit 27de15b

Browse files
[One .NET] temporary Windows & macOS installers for .NET 6
Depends on: dotnet#5195 For .NET 6 Preview 1, we will need to provide our own installers for the Android workload. This will also unblock the Xamarin.Forms / MAUI team as they build on top of the iOS and Android workloads for .NET 6. We will eventually do some kind of "insertion" process to provide our `.nupkg` files to the dotnet/installer repo, so these installers will go away completely at some point. For now, this creates two new installers: * Microsoft.Android.Workload.msi - installs to `C:\Program Files\dotnet\` * Microsoft.Android.Workload.pkg - installs to `/usr/local/share/dotnet/` Both installers have the following file structure underneath the root directory: * sdk\5.0.100-rtm.20509.5\EnableWorkloadResolver.sentinel * sdk-manifests\5.0.100\Microsoft.Android.Workload\** * packs\Microsoft.Android.Ref\** * packs\Microsoft.Android.Sdk\** The installers will have a hard dependency on .NET 5.0.100-rtm.20509.5, so we will need to have clear instructions for installing the correct version of .NET for the Android workload. The Windows installer is made using WIX, to mirror what dotnet/installer is using: * https://wixtoolset.org/ * https://github.com/dotnet/installer/blob/861a1dd12cb80bd834d0e51442d46ee7d1a4023f/src/redist/targets/GenerateMSIs.targets For now, the `.msi` will need to be built on Windows and the `.pkg` will need to be built on macOS. `create-dotnet-msi.csproj` will download the WIX toolset to `~\android-toolchain\wix` and call `candle.exe` and `light.exe` appropriately. `create-dotnet-pkg.csproj` is based on `create-pkg.csproj`, and no additional tooling is needed.
1 parent 1600835 commit 27de15b

File tree

10 files changed

+617
-8
lines changed

10 files changed

+617
-8
lines changed

Configuration.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
<!-- Version number from: https://github.com/dotnet/installer#installers-and-binaries -->
7373
<DotNetPreviewVersionBand Condition=" '$(DotNetPreviewVersionBand)' == '' ">5.0.100</DotNetPreviewVersionBand>
7474
<DotNetPreviewVersionFull Condition=" '$(DotNetPreviewVersionFull)' == '' ">$(DotNetPreviewVersionBand)-rtm.20509.5</DotNetPreviewVersionFull>
75+
<WixToolPath Condition=" '$(WixToolPath)' == '' ">$(AndroidToolchainDirectory)\wix\</WixToolPath>
7576
<AndroidCmakeVersion Condition=" '$(AndroidCmakeVersion)' == '' ">3.10.2</AndroidCmakeVersion>
7677
<AndroidCmakeVersionPath Condition=" '$(AndroidCmakeVersionPath)' == '' ">$(AndroidCmakeVersion).4988404</AndroidCmakeVersionPath>
7778
<AndroidSdkCmakeDirectory>$(AndroidSdkDirectory)\cmake\$(AndroidCmakeVersionPath)</AndroidSdkCmakeDirectory>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.IO;
3+
using Microsoft.Build.Framework;
4+
using Microsoft.Build.Utilities;
5+
6+
namespace Xamarin.Android.Tools.BootstrapTasks
7+
{
8+
/// <summary>
9+
/// Used for converting plain text license files to .rtf format.
10+
/// Assumes the file is line wrapped with Environment.NewLine:
11+
/// * Double new lines are preserved.
12+
/// * Single new lines are replaced with spaces.
13+
/// </summary>
14+
public class ConvertToRichText : Task
15+
{
16+
[Required]
17+
public string SourceFile { get; set; }
18+
19+
[Required]
20+
public string DestinationFile { get; set; }
21+
22+
public override bool Execute ()
23+
{
24+
var text = File.ReadAllText (SourceFile);
25+
26+
text = text
27+
.Replace (@"\", @"\\")
28+
.Replace ("{", @"\{")
29+
.Replace ("}", @"\}")
30+
// Only want to keep "double" new lines
31+
.Replace (Environment.NewLine + Environment.NewLine, $@"\par{Environment.NewLine} \par{Environment.NewLine} ")
32+
.Replace (Environment.NewLine, " ");
33+
34+
Directory.CreateDirectory (Path.GetDirectoryName (DestinationFile));
35+
using (var writer = File.CreateText (DestinationFile)) {
36+
writer.Write (@"{\rtf1\ansi\ansicpg1250\deff0{\fonttbl\f0\fcharset0 Courier New;}\f0\pard ");
37+
writer.Write (text);
38+
writer.Write (" } ");
39+
}
40+
41+
return !Log.HasLoggedErrors;
42+
}
43+
}
44+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System.IO;
2+
using System.Linq;
3+
using System.Security.Cryptography;
4+
using System.Text;
5+
using System.Xml;
6+
using Microsoft.Build.Framework;
7+
using Microsoft.Build.Utilities;
8+
9+
namespace Xamarin.Android.Tools.BootstrapTasks
10+
{
11+
/// <summary>
12+
/// Generates a .wix file for the contents of ~/android-toolchain/dotnet/packs
13+
/// The .wix file can be used to generate the .msi installer for Windows.
14+
/// </summary>
15+
public class GenerateWixFile : Task
16+
{
17+
[Required]
18+
public string Template { get; set; }
19+
20+
[Required]
21+
public string DestinationFile { get; set; }
22+
23+
[Required]
24+
public string DotNetPath { get; set; }
25+
26+
[Required]
27+
public string DotNetVersion { get; set; }
28+
29+
[Required]
30+
public string MSIVersion { get; set; }
31+
32+
public override bool Execute ()
33+
{
34+
var settings = new XmlWriterSettings {
35+
OmitXmlDeclaration = true,
36+
Indent = true,
37+
};
38+
39+
var directories = new StringBuilder ();
40+
var components = new StringBuilder ();
41+
using (var packWriter = XmlWriter.Create (directories, settings))
42+
using (var componentWriter = XmlWriter.Create (components, settings)) {
43+
44+
// Components
45+
componentWriter.WriteStartElement ("ComponentGroup");
46+
componentWriter.WriteAttributeString ("Id", "ProductComponents");
47+
componentWriter.WriteStartElement ("ComponentRef");
48+
componentWriter.WriteAttributeString ("Id", "EnableWorkloadResolver");
49+
componentWriter.WriteEndElement (); // </ComponentRef>
50+
51+
// dotnet
52+
packWriter.WriteStartElement ("Directory");
53+
packWriter.WriteAttributeString ("Id", "dotnet");
54+
packWriter.WriteAttributeString ("Name", "dotnet");
55+
56+
// sdk
57+
packWriter.WriteStartElement ("Directory");
58+
packWriter.WriteAttributeString ("Id", "sdk");
59+
packWriter.WriteAttributeString ("Name", "sdk");
60+
61+
// DOTNETVERSION
62+
packWriter.WriteStartElement ("Directory");
63+
packWriter.WriteAttributeString ("Id", "DOTNETVERSION");
64+
packWriter.WriteAttributeString ("Name", DotNetVersion);
65+
packWriter.WriteAttributeString ("FileSource", Path.Combine (DotNetPath, "sdk", DotNetVersion));
66+
67+
// EnableWorkloadResolver
68+
packWriter.WriteStartElement ("Component");
69+
packWriter.WriteAttributeString ("Id", "EnableWorkloadResolver");
70+
packWriter.WriteStartElement ("File");
71+
packWriter.WriteAttributeString ("Id", "EnableWorkloadResolver");
72+
packWriter.WriteAttributeString ("Name", "EnableWorkloadResolver.sentinel");
73+
packWriter.WriteAttributeString ("KeyPath", "yes");
74+
packWriter.WriteEndElement (); // </File>
75+
packWriter.WriteEndElement (); // </Component>
76+
packWriter.WriteEndElement (); // </Directory> DOTNETVERSION
77+
packWriter.WriteEndElement (); // </Directory> sdk
78+
79+
// sdk-manifests
80+
var sdk_manifests_root = Path.Combine (DotNetPath, "sdk-manifests");
81+
packWriter.WriteStartElement ("Directory");
82+
packWriter.WriteAttributeString ("Id", "sdk_manifests");
83+
packWriter.WriteAttributeString ("Name", "sdk-manifests");
84+
85+
// 5.0.100
86+
var sdk_manifests = Directory.EnumerateDirectories (sdk_manifests_root).FirstOrDefault ();
87+
if (string.IsNullOrEmpty (sdk_manifests)) {
88+
Log.LogError ($"Cannot find child directory of: {sdk_manifests_root}");
89+
return false;
90+
}
91+
var version_band = Path.GetFileName (sdk_manifests);
92+
packWriter.WriteStartElement ("Directory");
93+
packWriter.WriteAttributeString ("Id", "DOTNETVERSIONBAND");
94+
packWriter.WriteAttributeString ("Name", version_band);
95+
packWriter.WriteAttributeString ("FileSource", sdk_manifests);
96+
var workload = Path.Combine (sdk_manifests, "Microsoft.NET.Workload.Android");
97+
if (Directory.Exists (workload)) {
98+
RecurseDirectory (sdk_manifests, packWriter, componentWriter, workload);
99+
} else {
100+
Log.LogError ($"Cannot find directory: {workload}");
101+
return false;
102+
}
103+
packWriter.WriteEndElement (); // </Directory> version_band
104+
packWriter.WriteEndElement (); // </Directory> sdk-manifests
105+
106+
// packs
107+
var packs_dir = Path.Combine (DotNetPath, "packs");
108+
packWriter.WriteStartElement ("Directory");
109+
packWriter.WriteAttributeString ("Id", "packs");
110+
packWriter.WriteAttributeString ("Name", "packs");
111+
foreach (var directory in Directory.EnumerateDirectories (packs_dir, "Microsoft.Android.*")) {
112+
RecurseDirectory (packs_dir, packWriter, componentWriter, directory);
113+
}
114+
115+
packWriter.WriteEndDocument (); // </Directory>
116+
componentWriter.WriteEndDocument (); // </ComponentGroup>
117+
}
118+
119+
var template = File.ReadAllText (Template);
120+
var contents = template
121+
.Replace ("@MSIVERSION@", MSIVersion)
122+
.Replace ("@DIRECTORIES@", directories.ToString ())
123+
.Replace ("@COMPONENTS@", components.ToString ());
124+
125+
Log.LogMessage (MessageImportance.Low, "Writing XML to {0}: {1}", DestinationFile, contents);
126+
File.WriteAllText (DestinationFile, contents);
127+
128+
return !Log.HasLoggedErrors;
129+
}
130+
131+
static void RecurseDirectory (string top_dir, XmlWriter packWriter, XmlWriter componentWriter, string directory)
132+
{
133+
var directoryId = GetId (top_dir, directory);
134+
packWriter.WriteStartElement ("Directory");
135+
packWriter.WriteAttributeString ("Id", directoryId);
136+
packWriter.WriteAttributeString ("Name", Path.GetFileName (directory));
137+
packWriter.WriteAttributeString ("FileSource", directory);
138+
foreach (var child in Directory.EnumerateDirectories (directory)) {
139+
var directoryName = Path.GetFileName (child);
140+
if (directoryName.StartsWith (".") || directoryName.StartsWith ("_"))
141+
continue;
142+
RecurseDirectory (top_dir, packWriter, componentWriter, child);
143+
}
144+
foreach (var file in Directory.EnumerateFiles (directory)) {
145+
var fileName = Path.GetFileName (file);
146+
if (fileName.StartsWith (".") || fileName.StartsWith ("_"))
147+
continue;
148+
var componentId = GetId (top_dir, file);
149+
packWriter.WriteStartElement ("Component");
150+
packWriter.WriteAttributeString ("Id", componentId);
151+
packWriter.WriteStartElement ("File");
152+
packWriter.WriteAttributeString ("Id", componentId);
153+
packWriter.WriteAttributeString ("Name", Path.GetFileName (file));
154+
packWriter.WriteAttributeString ("KeyPath", "yes");
155+
packWriter.WriteEndElement (); // </File>
156+
packWriter.WriteEndElement (); // </Component>
157+
componentWriter.WriteStartElement ("ComponentRef");
158+
componentWriter.WriteAttributeString ("Id", componentId);
159+
componentWriter.WriteEndElement (); // </ComponentRef>
160+
}
161+
packWriter.WriteEndElement (); // </Directory>
162+
}
163+
164+
static string GetId (string top_dir, string path)
165+
{
166+
if (string.IsNullOrEmpty (path))
167+
return path;
168+
if (path.Length > top_dir.Length + 1) {
169+
path = path.Substring (top_dir.Length + 1);
170+
}
171+
return GetHashString (path);
172+
}
173+
174+
static byte [] GetHash (string inputString)
175+
{
176+
using (var algorithm = SHA256.Create ())
177+
return algorithm.ComputeHash (Encoding.UTF8.GetBytes (inputString));
178+
}
179+
180+
static string GetHashString (string inputString)
181+
{
182+
var sb = new StringBuilder ("S", 65);
183+
foreach (byte b in GetHash (inputString))
184+
sb.Append (b.ToString ("X2"));
185+
return sb.ToString ();
186+
}
187+
}
188+
}

build-tools/automation/azure-pipelines.yaml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,125 @@ stages:
11151115

11161116
- template: yaml-templates/fail-on-issue.yaml
11171117

1118+
- stage: dotnet_installers
1119+
displayName: .NET 6 Preview
1120+
dependsOn: mac_build
1121+
jobs:
1122+
# Check - "Xamarin.Android (.NET 6 Preview .pkg Installer)"
1123+
- job: dotnet_pkg_installer
1124+
displayName: .pkg Installer
1125+
pool: $(MacMojaveBuildPool)
1126+
workspace:
1127+
clean: all
1128+
steps:
1129+
- checkout: self
1130+
submodules: recursive
1131+
1132+
# Clone monodroid without submodules, we only need tools/scripts/License.txt
1133+
- checkout: monodroid
1134+
clean: true
1135+
path: s/xamarin-android/external/monodroid
1136+
persistCredentials: true
1137+
1138+
- task: DownloadPipelineArtifact@2
1139+
inputs:
1140+
artifactName: $(NuGetArtifactName)
1141+
downloadPath: $(System.DefaultWorkingDirectory)/storage-artifacts
1142+
1143+
- task: UseDotNet@2
1144+
displayName: install .NET Core $(DotNetCoreVersion)
1145+
inputs:
1146+
version: $(DotNetCoreVersion)
1147+
1148+
- script: >
1149+
mkdir -p $(System.DefaultWorkingDirectory)/xamarin-android/bin/Build$(XA.Build.Configuration)/nupkgs &&
1150+
cp $(System.DefaultWorkingDirectory)/storage-artifacts/*.nupkg $(System.DefaultWorkingDirectory)/xamarin-android/bin/Build$(XA.Build.Configuration)/nupkgs
1151+
displayName: copy .nupkgs
1152+
1153+
- task: MSBuild@1
1154+
displayName: msbuild Xamarin.Android.BootstrapTasks
1155+
inputs:
1156+
solution: xamarin-android/Xamarin.Android.BootstrapTasks.sln
1157+
configuration: $(XA.Build.Configuration)
1158+
msbuildArguments: /restore /bl:$(System.DefaultWorkingDirectory)/xamarin-android/bin/Build$(XA.Build.Configuration)/msbuild-bootstraptasks.binlog
1159+
1160+
- task: MSBuild@1
1161+
displayName: msbuild /t:CreateWorkloadInstallers
1162+
inputs:
1163+
solution: xamarin-android/Xamarin.Android.sln
1164+
configuration: $(XA.Build.Configuration)
1165+
msbuildArguments: /t:CreateWorkloadInstallers /p:License=$(System.DefaultWorkingDirectory)/xamarin-android/external/monodroid/tools/scripts/License.txt /bl:$(System.DefaultWorkingDirectory)/xamarin-android/bin/Build$(XA.Build.Configuration)/msbuild-workload.binlog
1166+
1167+
- script: cp $(System.DefaultWorkingDirectory)/xamarin-android/bin/Build$(XA.Build.Configuration)/*.pkg $(Build.ArtifactStagingDirectory)
1168+
displayName: copy pkg
1169+
1170+
- template: upload-to-storage.yml@yaml
1171+
parameters:
1172+
BuildPackages: $(Build.ArtifactStagingDirectory)
1173+
AzureContainerName: $(Azure.Container.Name)
1174+
AzureUploadLocation: $(Build.DefinitionName)/public/$(Build.BuildId)/$(Build.SourceBranchName)/$(Build.SourceVersion)
1175+
SourceDirectory: $(System.DefaultWorkingDirectory)/xamarin-android
1176+
1177+
- template: yaml-templates/upload-results.yaml
1178+
parameters:
1179+
solution: xamarin-android/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj
1180+
artifactName: dotnet-preview-pkg
1181+
1182+
# Check - "Xamarin.Android (.NET 6 Preview .msi Installer)"
1183+
- job: dotnet_msi_installer
1184+
displayName: .msi Installer
1185+
pool: $(VSEngWinVS2019)
1186+
workspace:
1187+
clean: all
1188+
steps:
1189+
- checkout: self
1190+
submodules: recursive
1191+
1192+
# Clone monodroid without submodules, we only need tools/scripts/License.txt
1193+
- checkout: monodroid
1194+
clean: true
1195+
path: s/xamarin-android/external/monodroid
1196+
persistCredentials: true
1197+
1198+
- task: DownloadPipelineArtifact@2
1199+
inputs:
1200+
artifactName: $(NuGetArtifactName)
1201+
downloadPath: $(System.DefaultWorkingDirectory)\storage-artifacts
1202+
1203+
- script: >
1204+
mkdir $(System.DefaultWorkingDirectory)\xamarin-android\bin\Build$(XA.Build.Configuration)\nupkgs &&
1205+
copy /Y $(System.DefaultWorkingDirectory)\storage-artifacts\*.nupkg $(System.DefaultWorkingDirectory)\xamarin-android\bin\Build$(XA.Build.Configuration)\nupkgs
1206+
displayName: copy .nupkgs
1207+
1208+
- task: MSBuild@1
1209+
displayName: msbuild Xamarin.Android.BootstrapTasks
1210+
inputs:
1211+
solution: xamarin-android\Xamarin.Android.BootstrapTasks.sln
1212+
configuration: $(XA.Build.Configuration)
1213+
msbuildArguments: /restore /bl:$(System.DefaultWorkingDirectory)\xamarin-android\bin\Build$(XA.Build.Configuration)\msbuild-bootstraptasks.binlog
1214+
1215+
- task: MSBuild@1
1216+
displayName: msbuild /t:CreateWorkloadInstallers
1217+
inputs:
1218+
solution: xamarin-android\Xamarin.Android.sln
1219+
configuration: $(XA.Build.Configuration)
1220+
msbuildArguments: /t:CreateWorkloadInstallers /p:License=$(System.DefaultWorkingDirectory)\xamarin-android\external\monodroid\tools\scripts\License.txt /bl:$(System.DefaultWorkingDirectory)\bin\Build$(XA.Build.Configuration)\msbuild-workload.binlog
1221+
1222+
- script: copy /Y $(System.DefaultWorkingDirectory)\xamarin-android\bin\Build$(XA.Build.Configuration)\*.msi $(Build.ArtifactStagingDirectory)
1223+
displayName: copy msi
1224+
1225+
- template: upload-to-storage.yml@yaml
1226+
parameters:
1227+
BuildPackages: $(Build.ArtifactStagingDirectory)
1228+
AzureContainerName: $(Azure.Container.Name)
1229+
AzureUploadLocation: $(Build.DefinitionName)/public/$(Build.BuildId)/$(Build.SourceBranchName)/$(Build.SourceVersion)
1230+
SourceDirectory: $(System.DefaultWorkingDirectory)\xamarin-android
1231+
1232+
- template: yaml-templates/upload-results.yaml
1233+
parameters:
1234+
solution: xamarin-android\build-tools\Xamarin.Android.Tools.BootstrapTasks\Xamarin.Android.Tools.BootstrapTasks.csproj
1235+
artifactName: dotnet-preview-msi
1236+
11181237
- stage: finalize_installers
11191238
displayName: Finalize Installers
11201239
dependsOn: mac_build

0 commit comments

Comments
 (0)