Skip to content

Commit 0255249

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 1a8116a commit 0255249

File tree

8 files changed

+417
-8
lines changed

8 files changed

+417
-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>
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Reflection.Emit;
5+
using System.Security.Cryptography;
6+
using System.Text;
7+
using System.Xml;
8+
using Microsoft.Build.Framework;
9+
using Microsoft.Build.Utilities;
10+
11+
namespace Xamarin.Android.Tools.BootstrapTasks
12+
{
13+
/// <summary>
14+
/// Generates a .wix file for the contents of ~/android-toolchain/dotnet/packs
15+
/// The .wix file can be used to generate the .msi installer for Windows.
16+
/// </summary>
17+
public class GenerateWixFile : Task
18+
{
19+
[Required]
20+
public string Template { get; set; }
21+
22+
[Required]
23+
public string DestinationFile { get; set; }
24+
25+
[Required]
26+
public string DotNetPath { get; set; }
27+
28+
[Required]
29+
public string DotNetVersion { get; set; }
30+
31+
[Required]
32+
public string MSIVersion { get; set; }
33+
34+
public override bool Execute ()
35+
{
36+
var settings = new XmlWriterSettings {
37+
OmitXmlDeclaration = true,
38+
Indent = true,
39+
};
40+
41+
var directories = new StringBuilder ();
42+
var components = new StringBuilder ();
43+
using (var packWriter = XmlWriter.Create (directories, settings))
44+
using (var componentWriter = XmlWriter.Create (components, settings)) {
45+
46+
// Components
47+
componentWriter.WriteStartElement ("ComponentGroup");
48+
componentWriter.WriteAttributeString ("Id", "ProductComponents");
49+
componentWriter.WriteStartElement ("ComponentRef");
50+
componentWriter.WriteAttributeString ("Id", "EnableWorkloadResolver");
51+
componentWriter.WriteEndElement (); // </ComponentRef>
52+
53+
// dotnet
54+
packWriter.WriteStartElement ("Directory");
55+
packWriter.WriteAttributeString ("Id", "dotnet");
56+
packWriter.WriteAttributeString ("Name", "dotnet");
57+
58+
// sdk
59+
packWriter.WriteStartElement ("Directory");
60+
packWriter.WriteAttributeString ("Id", "sdk");
61+
packWriter.WriteAttributeString ("Name", "sdk");
62+
63+
// DOTNETVERSION
64+
packWriter.WriteStartElement ("Directory");
65+
packWriter.WriteAttributeString ("Id", "DOTNETVERSION");
66+
packWriter.WriteAttributeString ("Name", DotNetVersion);
67+
packWriter.WriteAttributeString ("FileSource", Path.Combine (DotNetPath, "sdk", DotNetVersion));
68+
69+
// EnableWorkloadResolver
70+
packWriter.WriteStartElement ("Component");
71+
packWriter.WriteAttributeString ("Id", "EnableWorkloadResolver");
72+
packWriter.WriteStartElement ("File");
73+
packWriter.WriteAttributeString ("Id", "EnableWorkloadResolver");
74+
packWriter.WriteAttributeString ("Name", "EnableWorkloadResolver.sentinel");
75+
packWriter.WriteAttributeString ("KeyPath", "yes");
76+
packWriter.WriteEndElement (); // </File>
77+
packWriter.WriteEndElement (); // </Component>
78+
packWriter.WriteEndElement (); // </Directory> DOTNETVERSION
79+
packWriter.WriteEndElement (); // </Directory> sdk
80+
81+
// sdk-manifests
82+
var sdk_manifests_root = Path.Combine (DotNetPath, "sdk-manifests");
83+
packWriter.WriteStartElement ("Directory");
84+
packWriter.WriteAttributeString ("Id", "sdk_manifests");
85+
packWriter.WriteAttributeString ("Name", "sdk-manifests");
86+
87+
// 5.0.100
88+
var sdk_manifests = Directory.EnumerateDirectories (sdk_manifests_root).FirstOrDefault ();
89+
if (string.IsNullOrEmpty (sdk_manifests)) {
90+
Log.LogError ($"Cannot find child directory of: {sdk_manifests_root}");
91+
return false;
92+
}
93+
var version_band = Path.GetFileName (sdk_manifests);
94+
packWriter.WriteStartElement ("Directory");
95+
packWriter.WriteAttributeString ("Id", "DOTNETVERSIONBAND");
96+
packWriter.WriteAttributeString ("Name", version_band);
97+
packWriter.WriteAttributeString ("FileSource", sdk_manifests);
98+
var workload = Path.Combine (sdk_manifests, "Microsoft.Android.Workload");
99+
if (Directory.Exists (workload)) {
100+
RecurseDirectory (sdk_manifests, packWriter, componentWriter, workload);
101+
} else {
102+
Log.LogError ($"Cannot find directory: {workload}");
103+
return false;
104+
}
105+
packWriter.WriteEndElement (); // </Directory> version_band
106+
packWriter.WriteEndElement (); // </Directory> sdk-manifests
107+
108+
// packs
109+
var packs_dir = Path.Combine (DotNetPath, "packs");
110+
packWriter.WriteStartElement ("Directory");
111+
packWriter.WriteAttributeString ("Id", "packs");
112+
packWriter.WriteAttributeString ("Name", "packs");
113+
foreach (var directory in Directory.EnumerateDirectories (packs_dir, "Microsoft.Android.*")) {
114+
RecurseDirectory (packs_dir, packWriter, componentWriter, directory);
115+
}
116+
117+
packWriter.WriteEndDocument (); // </Directory>
118+
componentWriter.WriteEndDocument (); // </ComponentGroup>
119+
}
120+
121+
var template = File.ReadAllText (Template);
122+
var contents = template
123+
.Replace ("@MSIVERSION@", MSIVersion)
124+
.Replace ("@DIRECTORIES@", directories.ToString ())
125+
.Replace ("@COMPONENTS@", components.ToString ());
126+
127+
File.WriteAllText (DestinationFile, contents);
128+
129+
return !Log.HasLoggedErrors;
130+
}
131+
132+
static void RecurseDirectory (string top_dir, XmlWriter packWriter, XmlWriter componentWriter, string directory)
133+
{
134+
var directoryId = GetId (top_dir, directory);
135+
packWriter.WriteStartElement ("Directory");
136+
packWriter.WriteAttributeString ("Id", directoryId);
137+
packWriter.WriteAttributeString ("Name", Path.GetFileName (directory));
138+
packWriter.WriteAttributeString ("FileSource", directory);
139+
foreach (var child in Directory.EnumerateDirectories (directory)) {
140+
var directoryName = Path.GetFileName (child);
141+
if (directoryName.StartsWith (".") || directoryName.StartsWith ("_"))
142+
continue;
143+
RecurseDirectory (top_dir, packWriter, componentWriter, child);
144+
}
145+
foreach (var file in Directory.EnumerateFiles (directory)) {
146+
var fileName = Path.GetFileName (file);
147+
if (fileName.StartsWith (".") || fileName.StartsWith ("_"))
148+
continue;
149+
var componentId = GetId (top_dir, file);
150+
packWriter.WriteStartElement ("Component");
151+
packWriter.WriteAttributeString ("Id", componentId);
152+
packWriter.WriteStartElement ("File");
153+
packWriter.WriteAttributeString ("Id", componentId);
154+
packWriter.WriteAttributeString ("Name", Path.GetFileName (file));
155+
packWriter.WriteAttributeString ("KeyPath", "yes");
156+
packWriter.WriteEndElement (); // </File>
157+
packWriter.WriteEndElement (); // </Component>
158+
componentWriter.WriteStartElement ("ComponentRef");
159+
componentWriter.WriteAttributeString ("Id", componentId);
160+
componentWriter.WriteEndElement (); // </ComponentRef>
161+
}
162+
packWriter.WriteEndElement (); // </Directory>
163+
}
164+
165+
static string GetId (string top_dir, string path)
166+
{
167+
if (string.IsNullOrEmpty (path))
168+
return path;
169+
if (path.Length > top_dir.Length + 1) {
170+
path = path.Substring (top_dir.Length + 1);
171+
}
172+
return GetHashString (path);
173+
}
174+
175+
static byte [] GetHash (string inputString)
176+
{
177+
using (var algorithm = SHA256.Create ())
178+
return algorithm.ComputeHash (Encoding.UTF8.GetBytes (inputString));
179+
}
180+
181+
static string GetHashString (string inputString)
182+
{
183+
var sb = new StringBuilder ("S", 65);
184+
foreach (byte b in GetHash (inputString))
185+
sb.Append (b.ToString ("X2"));
186+
return sb.ToString ();
187+
}
188+
}
189+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3+
4+
<Product Name="Microsoft.Android.Workload"
5+
Id="*"
6+
Language="1033"
7+
Version="@MSIVERSION@"
8+
Manufacturer="Microsoft"
9+
UpgradeCode="86a83cc9-6b75-489f-be10-27988df907c6">
10+
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Platform="x64" />
11+
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
12+
<MediaTemplate EmbedCab="yes" />
13+
<Feature Id="ProductFeature" Title="Microsoft.Android.Sdk">
14+
<ComponentGroupRef Id="ProductComponents" />
15+
</Feature>
16+
</Product>
17+
18+
<Fragment>
19+
<Directory Id="TARGETDIR" Name="SourceDir">
20+
<Directory Id="ProgramFiles64Folder">
21+
@DIRECTORIES@
22+
</Directory>
23+
</Directory>
24+
</Fragment>
25+
26+
<Fragment>
27+
@COMPONENTS@
28+
</Fragment>
29+
30+
</Wix>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<Project Sdk="Microsoft.Build.NoTargets">
2+
<PropertyGroup>
3+
<TargetFramework>netstandard2.0</TargetFramework>
4+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
5+
<OutputPath>..\..\bin\Build$(Configuration)</OutputPath>
6+
<_WixTemplate>Microsoft.Android.Workload.wix.in</_WixTemplate>
7+
</PropertyGroup>
8+
9+
<Import Project="..\..\Configuration.props" />
10+
<Import Project="..\scripts\XAVersionInfo.targets" />
11+
12+
<ItemGroup>
13+
<None Remove="**" />
14+
<None Include="$(_WixTemplate)" />
15+
</ItemGroup>
16+
17+
<UsingTask AssemblyFile="$(PrepTasksAssembly)" TaskName="Xamarin.Android.BuildTools.PrepTasks.DownloadUri" />
18+
<UsingTask AssemblyFile="$(BootstrapTasksAssembly)" TaskName="Xamarin.Android.Tools.BootstrapTasks.GenerateWixFile" />
19+
<UsingTask AssemblyFile="$(BootstrapTasksAssembly)" TaskName="Xamarin.Android.Tools.BootstrapTasks.UnzipDirectoryChildren" />
20+
21+
<Target Name="_DownloadWix">
22+
<DownloadUri
23+
SourceUris="https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip"
24+
DestinationFiles="$(AndroidToolchainCacheDirectory)\wix311-binaries.zip"
25+
/>
26+
</Target>
27+
28+
<Target Name="_UnzipWix"
29+
Inputs="$(AndroidToolchainCacheDirectory)\wix311-binaries.zip"
30+
Outputs="$(WixToolPath)candle.exe;$(WixToolPath)light.exe">
31+
<UnzipDirectoryChildren
32+
NoSubdirectory="True"
33+
SourceFiles="$(AndroidToolchainCacheDirectory)\wix311-binaries.zip"
34+
DestinationFolder="$(WixToolPath)"
35+
/>
36+
</Target>
37+
38+
<Target Name="_Properties">
39+
<PropertyGroup>
40+
<_WixFile>$(IntermediateOutputPath)Microsoft.Android.Workload.wix</_WixFile>
41+
<_WixObj>$(IntermediateOutputPath)Microsoft.Android.Workload.wixobj</_WixObj>
42+
<_WixMsi>$(IntermediateOutputPath)Microsoft.Android.Workload.msi</_WixMsi>
43+
</PropertyGroup>
44+
</Target>
45+
46+
<Target Name="_Generate"
47+
DependsOnTargets="GetXAVersionInfo;_Properties"
48+
Inputs="$(MSBuildThisFile);$(BootstrapTasksAssembly);$(_WixTemplate)"
49+
Outputs="$(_WixFile)">
50+
<GenerateWixFile
51+
Template="$(_WixTemplate)"
52+
DestinationFile="$(_WixFile)"
53+
DotNetPath="$(DotNetPreviewPath)"
54+
DotNetVersion="$(DotNetPreviewVersionFull)"
55+
MSIVersion="$(AndroidMSIVersion)"
56+
/>
57+
<ItemGroup>
58+
<FileWrites Include="$(_WixFile)" />
59+
</ItemGroup>
60+
</Target>
61+
62+
<Target Name="_Candle"
63+
DependsOnTargets="_DownloadWix;_Generate"
64+
Inputs="$(_WixFile)"
65+
Outputs="$(_WixObj)">
66+
<Exec Command="&quot;$(WixToolPath)candle.exe&quot; -arch x64 Microsoft.Android.Workload.wix" WorkingDirectory="$(IntermediateOutputPath)" />
67+
<ItemGroup>
68+
<FileWrites Include="$(_WixObj)" />
69+
</ItemGroup>
70+
</Target>
71+
72+
<Target Name="_Light"
73+
BeforeTargets="AssignTargetPaths"
74+
DependsOnTargets="_Candle"
75+
Inputs="$(_WixObj)"
76+
Outputs="$(_WixMsi)">
77+
<Exec Command="&quot;$(WixToolPath)light.exe&quot; Microsoft.Android.Workload.wixobj" WorkingDirectory="$(IntermediateOutputPath)" />
78+
<ItemGroup>
79+
<FileWrites Include="$(_WixMsi)" />
80+
<None Include="$(_WixMsi)" CopyToOutputDirectory="PreserveNewest" Link="Microsoft.Android.Workload.$(AndroidMSIVersion).msi" />
81+
</ItemGroup>
82+
</Target>
83+
84+
</Project>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<Project Sdk="Microsoft.Build.NoTargets">
2+
<PropertyGroup>
3+
<TargetFramework>netstandard2.0</TargetFramework>
4+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
5+
<OutputPath>..\..\bin\Build$(Configuration)</OutputPath>
6+
</PropertyGroup>
7+
8+
<Import Project="..\..\Configuration.props" />
9+
<Import Project="..\scripts\XAVersionInfo.targets" />
10+
11+
<PropertyGroup>
12+
<PkgInstallDir>/</PkgInstallDir>
13+
<PayloadDir>$(OutputPath)\pkg\archive</PayloadDir>
14+
<PkgOutputPath>$(OutputPath)\pkg\packages</PkgOutputPath>
15+
<PkgResourcesPath>$(OutputPath)\pkg\resources</PkgResourcesPath>
16+
<PkgDistributionDestination>$(OutputPath)\pkg\distribution.xml</PkgDistributionDestination>
17+
<PkgLicenseSrcEn Condition="'$(PkgLicenseSrcEn)' == ''">$(XamarinAndroidSourcePath)\LICENSE</PkgLicenseSrcEn>
18+
<PkgLicenseDestinationEn>$(PkgResourcesPath)\en.lproj</PkgLicenseDestinationEn>
19+
</PropertyGroup>
20+
21+
<ItemGroup>
22+
<None Remove="**" />
23+
<None Include="distribution.xml.in" />
24+
</ItemGroup>
25+
26+
<UsingTask AssemblyFile="$(PrepTasksAssembly)" TaskName="Xamarin.Android.BuildTools.PrepTasks.ReplaceFileContents" />
27+
28+
<Target Name="_FinalizePayload"
29+
DependsOnTargets="GetXAVersionInfo">
30+
<PropertyGroup>
31+
<DotNetPayloadDir>$(PayloadDir)\usr\local\share\dotnet\</DotNetPayloadDir>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<_FilesToCopy Include="$(DotNetPreviewPath)\sdk\$(DotNetPreviewVersionFull)\EnableWorkloadResolver.sentinel" />
35+
<_FilesToCopy Include="$(DotNetPreviewPath)\sdk-manifests\$(DotNetPreviewVersionBand)\Microsoft.Android.Workload\**\*" />
36+
<_FilesToCopy Include="$(DotNetPreviewPath)\packs\Microsoft.Android.Ref\**\*" />
37+
<_FilesToCopy Include="$(DotNetPreviewPath)\packs\Microsoft.Android.Sdk\**\*" />
38+
</ItemGroup>
39+
<MakeDir Directories="$(PkgOutputPath);$(PayloadDir);$(PkgResourcesPath);$(PkgLicenseDestinationEn)"/>
40+
<ReplaceFileContents
41+
SourceFile="distribution.xml.in"
42+
DestinationFile="$(PkgDistributionDestination)"
43+
Replacements="@PACKAGE_TITLE@=Microsoft.Android.Workload $(AndroidPackVersionLong)"
44+
/>
45+
<Copy
46+
SourceFiles="@(_FilesToCopy)"
47+
DestinationFiles="@(_FilesToCopy->'$([System.String]::Copy('%(Identity)').Replace($(DotNetPreviewPath),$(DotNetPayloadDir)))')"
48+
/>
49+
<Copy
50+
SourceFiles="$(PkgLicenseSrcEn)"
51+
DestinationFiles="$(PkgLicenseDestinationEn)\License"
52+
/>
53+
</Target>
54+
<Target Name="_CreatePkg"
55+
BeforeTargets="AssignTargetPaths"
56+
DependsOnTargets="_FinalizePayload">
57+
<PropertyGroup>
58+
<PkgProductOutputPath>$(IntermediateOutputPath)Microsoft.Android.Workload.pkg</PkgProductOutputPath>
59+
</PropertyGroup>
60+
<ItemGroup>
61+
<PkgBuildArgs Include="--root &quot;$(PayloadDir)&quot;" />
62+
<PkgBuildArgs Include="--identifier com.microsoft.android.workload.pkg" />
63+
<PkgBuildArgs Include="--version $(AndroidPackVersionLong)"/>
64+
<PkgBuildArgs Include="--install-location &quot;$(PkgInstallDir)&quot; "/>
65+
<PkgBuildArgs Include="&quot;$(PkgOutputPath)/microsoft.android.workload.pkg&quot; "/>
66+
</ItemGroup>
67+
<Exec Command="pkgbuild @(PkgBuildArgs, ' ')" />
68+
<ItemGroup>
69+
<ProductBuildArgs Include="--resources &quot;$(PkgResourcesPath)&quot;" />
70+
<ProductBuildArgs Include="--distribution &quot;$(PkgDistributionDestination)&quot;" />
71+
<ProductBuildArgs Include="--package-path &quot;$(PkgOutputPath)&quot;" />
72+
<ProductBuildArgs Include="&quot;$(PkgProductOutputPath)&quot;" />
73+
</ItemGroup>
74+
<Exec Command="productbuild @(ProductBuildArgs, ' ')" />
75+
<RemoveDir Directories="$(OutputPath)\pkg"/>
76+
<ItemGroup>
77+
<FileWrites Include="$(PkgProductOutputPath)" />
78+
<None Include="$(PkgProductOutputPath)" CopyToOutputDirectory="PreserveNewest" Link="Microsoft.Android.Workload-$(AndroidPackVersionLong).pkg" />
79+
</ItemGroup>
80+
</Target>
81+
82+
</Project>

0 commit comments

Comments
 (0)