Add SharedFramework MSI Authoring

This commit is contained in:
Matt Ellis 2016-03-08 19:32:31 -08:00
parent 04d21e6693
commit e6bcfee4a4
12 changed files with 413 additions and 3 deletions

View file

@ -0,0 +1,151 @@
# Copyright (c) .NET Foundation and contributors. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
param(
[Parameter(Mandatory=$true)][string]$SharedFrameworkPublishRoot,
[Parameter(Mandatory=$true)][string]$SharedFrameworkMSIOutput,
[Parameter(Mandatory=$true)][string]$WixRoot,
[Parameter(Mandatory=$true)][string]$DotnetMSIVersion,
[Parameter(Mandatory=$true)][string]$SharedFrameworkNugetName,
[Parameter(Mandatory=$true)][string]$SharedFrameworkNugetVersion,
[Parameter(Mandatory=$true)][string]$SharedFrameworkUpgradeCode,
[Parameter(Mandatory=$true)][string]$Architecture,
[Parameter(Mandatory=$true)][string]$WixObjRoot
)
. "$PSScriptRoot\..\..\..\scripts\common\_common.ps1"
$RepoRoot = Convert-Path "$PSScriptRoot\..\..\.."
$InstallFileswsx = "$WixObjRoot\install-files.wxs"
$InstallFilesWixobj = "$WixObjRoot\install-files.wixobj"
function RunHeat
{
$result = $true
pushd "$WixRoot"
Write-Host Running heat..
.\heat.exe dir `"$SharedFrameworkPublishRoot`" `
-nologo `
-template fragment `
-sreg -gg `
-var var.SharedFrameworkSource `
-cg InstallFiles `
-srd `
-dr DOTNETHOME `
-out $InstallFileswsx | Out-Host
if($LastExitCode -ne 0)
{
$result = $false
Write-Host "Heat failed with exit code $LastExitCode."
}
popd
return $result
}
function RunCandle
{
$result = $true
pushd "$WixRoot"
Write-Host Running candle..
$AuthWsxRoot = Join-Path $RepoRoot "packaging\sharedframework\windows"
$SharedFrameworkComponentVersion = $SharedFrameworkNugetVersion.Replace('-', '_');
.\candle.exe -nologo `
-out "$WixObjRoot\" `
-dSharedFrameworkSource="$SharedFrameworkPublishRoot" `
-dMicrosoftEula="$RepoRoot\packaging\osx\resources\en.lproj\eula.rtf" `
-dFrameworkName="$SharedFrameworkNugetName" `
-dFrameworkDisplayVersion="$SharedFrameworkNugetVersion" `
-dFrameworkComponentVersion="$SharedFrameworkComponentVersion" `
-dFrameworkUpgradeCode="$SharedFrameworkUpgradeCode" `
-dBuildVersion="$DotnetMSIVersion" `
-arch $Architecture `
-ext WixDependencyExtension.dll `
"$AuthWsxRoot\sharedframework.wxs" `
"$AuthWsxRoot\provider.wxs" `
"$AuthWsxRoot\registrykeys.wxs" `
$InstallFileswsx | Out-Host
if($LastExitCode -ne 0)
{
$result = $false
Write-Host "Candle failed with exit code $LastExitCode."
}
popd
return $result
}
function RunLight
{
$result = $true
pushd "$WixRoot"
Write-Host Running light..
$CabCache = Join-Path $WixRoot "cabcache"
.\light.exe -nologo -ext WixUIExtension -ext WixDependencyExtension -ext WixUtilExtension `
-cultures:en-us `
"$WixObjRoot\sharedframework.wixobj" `
"$WixObjRoot\provider.wixobj" `
"$WixObjRoot\registrykeys.wixobj" `
"$InstallFilesWixobj" `
-out $SharedFrameworkMSIOutput | Out-Host
if($LastExitCode -ne 0)
{
$result = $false
Write-Host "Light failed with exit code $LastExitCode."
}
popd
return $result
}
if(!(Test-Path $SharedFrameworkPublishRoot))
{
throw "$SharedHostPublishRoot not found"
}
if(!(Test-Path $WixObjRoot))
{
throw "$WixObjRoot not found"
}
Write-Host "Creating dotnet shared framework MSI at $SharedFrameworkMSIOutput"
if([string]::IsNullOrEmpty($WixRoot))
{
Exit -1
}
if(-Not (RunHeat))
{
Exit -1
}
if(-Not (RunCandle))
{
Exit -1
}
if(-Not (RunLight))
{
Exit -1
}
if(!(Test-Path $SharedFrameworkMSIOutput))
{
throw "Unable to create the dotnet shared framework msi."
Exit -1
}
Write-Host -ForegroundColor Green "Successfully created shared framework MSI - $SharedFrameworkMSIOutput"
exit $LastExitCode

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension">
<?include "Variables.wxi" ?>
<Fragment>
<Component Id="DotNet_CLI_SharedFramework_$(var.FrameworkName)_$(var.FrameworkComponentVersion)" Directory="TARGETDIR" Win64="no" Guid="F47B3A4D-7CEB-4F18-8464-0F6C5978E08E">
<dep:Provides Key="DotNet.CLI.SharedFramework.$(var.FrameworkName)_$(var.FrameworkComponentVersion)" />
</Component>
</Fragment>
</Wix>

View file

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include "Variables.wxi" ?>
<Fragment>
<ComponentGroup Id="AuthoredRegistryKeys">
<?if $(var.Platform) = x64?>
<Component Id="SetupRegistry_x64" Directory="TARGETDIR" Win64="yes">
<RegistryKey Root="HKLM" Key="SOFTWARE\dotnet\sharedframework\$(var.FrameworkName) $(var.FrameworkDisplayVersion)\Setup">
<RegistryValue Action="write" Name="Install" Type="integer" Value="1" KeyPath="yes"/>
<RegistryValue Action="write" Name="InstallDir" Type="string" Value="[SHAREDFRAMEWORKHOME]" />
<RegistryValue Action="write" Name="Version" Type="string" Value="$(var.FrameworkDisplayVersion)" />
</RegistryKey>
</Component>
<?endif?>
<?if $(var.Platform) = x86?>
<Component Id="SetupRegistry_x86" Directory="TARGETDIR" Win64="no">
<RegistryKey Root="HKLM" Key="SOFTWARE\dotnet\sharedframework\$(var.FrameworkName) $(var.FrameworkDisplayVersion)\Setup">
<RegistryValue Action="write" Name="Install" Type="integer" Value="1" KeyPath="yes"/>
<RegistryValue Action="write" Name="InstallDir" Type="string" Value="[SHAREDFRAMEWORKHOME]" />
<RegistryValue Action="write" Name="Version" Type="string" Value="$(var.FrameworkDisplayVersion)" />
</RegistryKey>
</Component>
<?endif?>
</ComponentGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include "Variables.wxi" ?>
<Product Id="*" Name="$(var.ProductName)" Language="$(var.ProductLanguage)" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package Compressed="yes" InstallScope="perMachine" InstallerVersion="200" />
<MajorUpgrade DowngradeErrorMessage="$(var.DowngradeErrorMessage)" Schedule="afterInstallInitialize"/>
<MediaTemplate CompressionLevel="high" EmbedCab="yes"/>
<Feature Id="MainFeature" Title="Main Feature" Level="1">
<ComponentGroupRef Id="InstallFiles" />
<ComponentGroupRef Id="AuthoredRegistryKeys"/>
</Feature>
<Feature Id="Provider" Absent="disallow" AllowAdvertise="no" Description="Used for Ref Counting" Display="hidden" Level="1" InstallDefault="local" Title="RefCounting" TypicalDefault="install">
<ComponentRef Id="DotNet_CLI_SharedFramework_$(var.FrameworkName)_$(var.FrameworkComponentVersion)" />
</Feature>
<Property Id="MSIFASTINSTALL" Value="7" />
<WixVariable Id="WixUILicenseRtf" Value="$(var.MicrosoftEula)" />
<Property Id="WIXUI_INSTALLDIR" Value="DOTNETHOME"/>
<UIRef Id="WixUI_InstallDir" />
<CustomActionRef Id="WixBroadcastEnvironmentChange" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.Program_Files)">
<Directory Id="DOTNETHOME" Name="dotnet" />
</Directory>
</Directory>
</Fragment>
</Wix>

View file

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define Servicing_Key_SP = "0" ?>
<?define Servicing_Key_SPIndex = "0" ?>
<?define Servicing_Key_SPName = "Beta" ?>
<?define Manufacturer = "Microsoft Corporation" ?>
<?define ProductName = "Microsoft .NET Core Shared Framework ($(var.FrameworkName) $(var.FrameworkDisplayVersion))" ?>
<?define ProductLanguage = "1033" ?>
<?define ProductVersion = "$(var.BuildVersion)" ?>
<?define LCID = "$(var.ProductLanguage)"?>
<?define DowngradeErrorMessage = "A newer version is already installed; please uninstall it and re-run setup."?>
<?define Platform = "$(sys.BUILDARCH)" ?>
<!--
The provided upgrade code already between x86 and x64
(since it is a GUID based on a string which includes the architecture)
-->
<?define UpgradeCode="$(var.FrameworkUpgradeCode)"?>
<?if $(var.Platform)=x86?>
<?define Program_Files="ProgramFilesFolder"?>
<?define Win64AttributeValue=no?>
<?elseif $(var.Platform)=x64?>
<?define Program_Files="ProgramFiles64Folder"?>
<?define Win64AttributeValue=yes?>
<?else?>
<?error Invalid Platform ($(var.Platform))?>
<?endif?>
</Include>

View file

@ -28,6 +28,8 @@ namespace Microsoft.DotNet.Cli.Build
private static string SharedHostMsi { get; set; }
private static string SharedFrameworkMsi { get; set; }
private static string Engine { get; set; }
private static string MsiVersion { get; set; }
@ -67,6 +69,7 @@ namespace Microsoft.DotNet.Cli.Build
Engine = Path.Combine(Path.GetDirectoryName(SdkBundle), ENGINE);
SharedHostMsi = Path.ChangeExtension(c.BuildContext.Get<string>("SharedHostInstallerFile"), "msi");
SharedFrameworkMsi = Path.ChangeExtension(c.BuildContext.Get<string>("SharedFrameworkInstallerFile"), "msi");
var buildVersion = c.BuildContext.Get<BuildVersion>("BuildVersion");
MsiVersion = buildVersion.GenerateMsiVersion();
@ -79,7 +82,7 @@ namespace Microsoft.DotNet.Cli.Build
[Target(nameof(MsiTargets.InitMsi),
nameof(GenerateDotnetSharedHostMsi),
nameof(GenerateDotnetSharedFxMsi),
nameof(GenerateDotnetSharedFrameworkMsi),
nameof(GenerateCliSdkMsi))]
[BuildPlatforms(BuildPlatform.Windows)]
public static BuildTargetResult GenerateMsis(BuildTargetContext c)
@ -121,10 +124,28 @@ namespace Microsoft.DotNet.Cli.Build
return c.Success();
}
[Target]
[Target(nameof(SharedFrameworkTargets.PublishSharedFramework))]
[BuildPlatforms(BuildPlatform.Windows)]
public static BuildTargetResult GenerateDotnetSharedFxMsi(BuildTargetContext c)
public static BuildTargetResult GenerateDotnetSharedFrameworkMsi(BuildTargetContext c)
{
var inputDir = c.BuildContext.Get<string>("SharedFrameworkPublishRoot");
var sharedFrameworkNuGetName = SharedFrameworkTargets.SharedFrameworkName;
var sharedFrameworkNuGetVersion = c.BuildContext.Get<string>("SharedFrameworkNugetVersion");
var upgradeCode = Utils.GenerateGuidFromName($"{sharedFrameworkNuGetName}-{sharedFrameworkNuGetVersion}-{Arch}").ToString().ToUpper();
var wixObjRoot = Path.Combine(Dirs.Output, "obj", "wix", "sharedframework");
if (Directory.Exists(wixObjRoot))
{
Directory.Delete(wixObjRoot, true);
}
Directory.CreateDirectory(wixObjRoot);
Cmd("powershell", "-NoProfile", "-NoLogo",
Path.Combine(Dirs.RepoRoot, "packaging", "sharedframework", "windows", "generatemsi.ps1"),
inputDir, SharedFrameworkMsi, WixRoot, MsiVersion, sharedFrameworkNuGetName, sharedFrameworkNuGetVersion, upgradeCode, Arch, wixObjRoot)
.Execute()
.EnsureSuccessful();
return c.Success();
}

View file

@ -114,6 +114,7 @@ namespace Microsoft.DotNet.Cli.Build
AddInstallerArtifactToContext(c, "dotnet", "Sdk");
AddInstallerArtifactToContext(c, "dotnet-host", "SharedHost");
AddInstallerArtifactToContext(c, "dotnet-sharedframework", "SharedFramework");
return c.Success();
}

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.Extensions.PlatformAbstractions;
@ -12,8 +13,47 @@ namespace Microsoft.DotNet.Cli.Build
{
public class SharedFrameworkTargets
{
public const string SharedFrameworkName = "NETStandard.Library";
private const string CoreHostBaseName = "corehost";
[Target]
public static BuildTargetResult PublishSharedFramework(BuildTargetContext c)
{
string SharedFrameworkPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedframework");
string SharedFrameworkSourceRoot = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework");
string SharedFrameworkNugetVersion = GetVersionFromProjectJson(Path.Combine(Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"), "project.json"));
if (Directory.Exists(SharedFrameworkPublishRoot))
{
Directory.Delete(SharedFrameworkPublishRoot, true);
}
// We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier.
string SharedFrameworkNameAndVersionRoot = Path.Combine(SharedFrameworkPublishRoot, "shared", SharedFrameworkName, SharedFrameworkNugetVersion);
DotNetCli.Stage0.Publish("--output", SharedFrameworkNameAndVersionRoot, SharedFrameworkSourceRoot).Execute().EnsureSuccessful();
c.BuildContext["SharedFrameworkPublishRoot"] = SharedFrameworkPublishRoot;
c.BuildContext["SharedFrameworkNugetVersion"] = SharedFrameworkNugetVersion;
// Clean up artifacts that dotnet-publish generates which we don't need
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, $"framework{Constants.ExeSuffix}"));
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.dll"));
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.pdb"));
// Rename the .deps file
File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps"));
// corehost will be renamed to dotnet at some point and then this can be removed.
File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}"));
// hostpolicy will be renamed to dotnet at some point and then this can be removed.
File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}dotnethostimpl{Constants.DynamicLibSuffix}"));
return c.Success();
}
[Target]
public static BuildTargetResult PublishSharedHost(BuildTargetContext c)
{
@ -42,5 +82,22 @@ namespace Microsoft.DotNet.Cli.Build
return c.Success();
}
private static string GetVersionFromProjectJson(string pathToProjectJson)
{
Regex r = new Regex($"\"{Regex.Escape(SharedFrameworkName)}\"\\s*:\\s*\"(?'version'[^\"]*)\"");
foreach(var line in File.ReadAllLines(pathToProjectJson))
{
var m = r.Match(line);
if (m.Success)
{
return m.Groups["version"].Value;
}
}
return null;
}
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace Microsoft.DotNet.Cli.Build
{
@ -34,5 +35,55 @@ namespace Microsoft.DotNet.Cli.Build
throw new PlatformNotSupportedException();
}
}
// Generate a Version 5 (SHA1 Name Based) Guid from a name.
public static Guid GenerateGuidFromName(string name)
{
// Any fixed GUID will do for a namespace.
Guid namespaceId = new Guid("28F1468D-672B-489A-8E0C-7C5B3030630C");
using (SHA1 hasher = SHA1.Create())
{
var nameBytes = System.Text.Encoding.UTF8.GetBytes(name ?? string.Empty);
var namespaceBytes = namespaceId.ToByteArray();
SwapGuidByteOrder(namespaceBytes);
var streamToHash = new byte[namespaceBytes.Length + nameBytes.Length];
Array.Copy(namespaceBytes, streamToHash, namespaceBytes.Length);
Array.Copy(nameBytes, 0, streamToHash, namespaceBytes.Length, nameBytes.Length);
var hashResult = hasher.ComputeHash(streamToHash);
var res = new byte[16];
Array.Copy(hashResult, res, res.Length);
unchecked { res[6] = (byte)(0x50 | (res[6] & 0x0F)); }
unchecked { res[8] = (byte)(0x40 | (res[8] & 0x3F)); }
SwapGuidByteOrder(res);
return new Guid(res);
}
}
// Do a byte order swap, .NET GUIDs store multi byte components in little
// endian.
private static void SwapGuidByteOrder(byte[] b)
{
Swap(b, 0, 3);
Swap(b, 1, 2);
Swap(b, 5, 6);
Swap(b, 7, 8);
}
private static void Swap(byte[] b, int x, int y)
{
byte t = b[x];
b[x] = b[y];
b[y] = t;
}
}
}

View file

@ -8,6 +8,7 @@
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23901",
"System.IO.Compression.ZipFile": "4.0.1-rc2-23901",
"System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901",
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537",
"Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*",
"WindowsAzure.Storage" : "6.2.2-preview"

View file

@ -0,0 +1,11 @@
using System;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
}
}
}

View file

@ -0,0 +1,14 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23811"
},
"frameworks": {
"dnxcore50": { }
}
}