diff --git a/packaging/windows/Dotnet.Cli.Msi.Tests/InstallFixture.cs b/packaging/windows/Dotnet.Cli.Msi.Tests/InstallFixture.cs
index 96b599ca2..0feb379f5 100644
--- a/packaging/windows/Dotnet.Cli.Msi.Tests/InstallFixture.cs
+++ b/packaging/windows/Dotnet.Cli.Msi.Tests/InstallFixture.cs
@@ -14,6 +14,10 @@ namespace Dotnet.Cli.Msi.Tests
public InstallFixture()
{
string msiFile = Environment.GetEnvironmentVariable("CLI_MSI");
+ if(string.IsNullOrEmpty(msiFile))
+ {
+ throw new InvalidOperationException("%CLI_MSI% must point to the msi that is to be tested");
+ }
_msiMgr = new MsiManager(msiFile);
diff --git a/packaging/windows/Dotnet.Cli.Msi.Tests/InstallationTests.cs b/packaging/windows/Dotnet.Cli.Msi.Tests/InstallationTests.cs
index 893ee1fc3..d19c2b07c 100644
--- a/packaging/windows/Dotnet.Cli.Msi.Tests/InstallationTests.cs
+++ b/packaging/windows/Dotnet.Cli.Msi.Tests/InstallationTests.cs
@@ -10,22 +10,20 @@ namespace Dotnet.Cli.Msi.Tests
{
public class InstallationTests : IDisposable
{
- private string _msiFile;
private MsiManager _msiMgr;
public InstallationTests()
{
// all the tests assume that the msi to be tested is available via environment variable %CLI_MSI%
- _msiFile = Environment.GetEnvironmentVariable("CLI_MSI");
- if(string.IsNullOrEmpty(_msiFile))
+ var msiFile = Environment.GetEnvironmentVariable("CLI_MSI");
+ if(string.IsNullOrEmpty(msiFile))
{
throw new InvalidOperationException("%CLI_MSI% must point to the msi that is to be tested");
}
- _msiMgr = new MsiManager(_msiFile);
+ _msiMgr = new MsiManager(msiFile);
}
-
[Theory]
[InlineData("")]
[InlineData(@"%SystemDrive%\dotnet")]
@@ -34,14 +32,14 @@ namespace Dotnet.Cli.Msi.Tests
installLocation = Environment.ExpandEnvironmentVariables(installLocation);
string expectedInstallLocation = string.IsNullOrEmpty(installLocation) ?
Environment.ExpandEnvironmentVariables(@"%ProgramFiles%\dotnet") :
- installLocation;
+ installLocation;
// make sure that the msi is not already installed, if so the machine is in a bad state
Assert.False(_msiMgr.IsInstalled, "The dotnet CLI msi is already installed");
Assert.False(Directory.Exists(expectedInstallLocation));
_msiMgr.Install(installLocation);
- Assert.True(_msiMgr.IsInstalled);
+ Assert.True(_msiMgr.IsInstalled);
Assert.True(Directory.Exists(expectedInstallLocation));
_msiMgr.UnInstall();
diff --git a/packaging/windows/Dotnet.Cli.Msi.Tests/MsiManager.cs b/packaging/windows/Dotnet.Cli.Msi.Tests/MsiManager.cs
index cd56d6f08..a944a2a44 100644
--- a/packaging/windows/Dotnet.Cli.Msi.Tests/MsiManager.cs
+++ b/packaging/windows/Dotnet.Cli.Msi.Tests/MsiManager.cs
@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Package;
-
namespace Dotnet.Cli.Msi.Tests
{
public class MsiManager
{
+ private string _bundleFile;
private string _msiFile;
private string _productCode;
private InstallPackage _installPackage;
@@ -48,6 +50,7 @@ namespace Dotnet.Cli.Msi.Tests
public MsiManager(string msiFile)
{
+ _bundleFile = Path.ChangeExtension(msiFile, "exe");
_msiFile = msiFile;
var ispackage = Installer.VerifyPackage(msiFile);
@@ -67,8 +70,8 @@ namespace Dotnet.Cli.Msi.Tests
{
dotnetHome = $"DOTNETHOME={customLocation}";
}
- Installer.SetInternalUI(InstallUIOptions.Silent);
- Installer.InstallProduct(_msiFile, $"ACTION=INSTALL ALLUSERS=2 ACCEPTEULA=1 {dotnetHome}");
+
+ RunBundle(dotnetHome);
return IsInstalled;
}
@@ -80,10 +83,25 @@ namespace Dotnet.Cli.Msi.Tests
throw new InvalidOperationException($"UnInstall Error: Msi at {_msiFile} is not installed.");
}
- Installer.SetInternalUI(InstallUIOptions.Silent);
- Installer.InstallProduct(_msiFile, "REMOVE=ALL");
+ RunBundle("/uninstall");
return !IsInstalled;
}
+
+ private void RunBundle(string additionalArguments)
+ {
+ var arguments = $"/q /norestart {additionalArguments}";
+ var process = Process.Start(_bundleFile, arguments);
+
+ if (!process.WaitForExit(5 * 60 * 1000))
+ {
+ throw new InvalidOperationException($"Failed to wait for the installation operation to complete. Check to see if the installation process is still running. Command line: {_bundleFile} {arguments}");
+ }
+
+ else if (0 != process.ExitCode)
+ {
+ throw new InvalidOperationException($"The installation operation failed with exit code: {process.ExitCode}. Command line: {_bundleFile} {arguments}");
+ }
+ }
}
}
diff --git a/packaging/windows/bundle.thm b/packaging/windows/bundle.thm
new file mode 100644
index 000000000..16839fa68
--- /dev/null
+++ b/packaging/windows/bundle.thm
@@ -0,0 +1,107 @@
+
+
+ #(loc.Caption)
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+
+ #(loc.Title)
+
+
+
+
+ #(loc.HelpHeader)
+ #(loc.HelpText)
+
+
+
+
+
+
+
+ v[DisplayVersion]
+ [ReleaseSuffix] [BuildType]
+ #(loc.Motto)
+
+
+
+ #(loc.InstallAcceptCheckbox)
+
+
+
+
+
+
+
+
+ #(loc.OptionsHeader)
+ #(loc.OptionsLocationLabel)
+
+
+
+
+
+
+
+
+ #(loc.FilesInUseHeader)
+ #(loc.FilesInUseLabel)
+ A
+
+
+
+
+
+
+
+
+
+
+
+
+ #(loc.ProgressHeader)
+ #(loc.ProgressLabel)
+ #(loc.OverallProgressPackageText)
+
+
+
+
+
+
+
+ #(loc.ModifyHeader)
+
+
+
+
+
+
+
+
+ #(loc.SuccessHeader)
+ #(loc.SuccessInstallHeader)
+ #(loc.SuccessRepairHeader)
+ #(loc.SuccessUninstallHeader)
+
+ #(loc.SuccessRestartText)
+
+
+
+
+
+
+
+ #(loc.FailureHeader)
+ #(loc.FailureInstallHeader)
+ #(loc.FailureUninstallHeader)
+ #(loc.FailureRepairHeader)
+ #(loc.FailureHyperlinkLogText)
+
+ #(loc.FailureRestartText)
+
+
+
+
\ No newline at end of file
diff --git a/packaging/windows/bundle.wxl b/packaging/windows/bundle.wxl
new file mode 100644
index 000000000..deb315ee4
--- /dev/null
+++ b/packaging/windows/bundle.wxl
@@ -0,0 +1,59 @@
+
+
+ [WixBundleName] Setup
+ Microsoft Dotnet CLI for Windows
+ You just need a shell, a text editor and 10 minutes of your time.
+
+Ready? Set? Let's go!
+ Are you sure you want to cancel?
+ Previous version
+
+ /install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
+ creates a complete local copy of the bundle in directory. Install is the default.
+
+/passive | /quiet - displays minimal UI with no prompts or displays no UI and
+ no prompts. By default UI and all prompts are displayed.
+
+/norestart - suppress any attempts to restart. By default UI will prompt before restart.
+/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.
+ &Close
+ I &agree to the license terms and conditions
+ &Options
+ &Install
+ &Close
+
+ Install location:
+ &Browse
+ &OK
+ &Cancel
+
+ Processing:
+ Initializing...
+ &Cancel
+
+ &Repair
+ &Uninstall
+ &Close
+
+
+
+
+ &Launch
+ You must restart your computer before you can use the software.
+ &Restart
+ &Close
+
+
+
+
+ One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>.
+ You must restart your computer to complete the rollback of the software.
+ &Restart
+ &Close
+
+ The following applications are using files that need to be updated:
+ Close the &applications and attempt to restart them.
+ &Do not close applications. A reboot will be required.
+ &OK
+ &Cancel
+
diff --git a/packaging/windows/bundle.wxs b/packaging/windows/bundle.wxs
new file mode 100644
index 000000000..6999e8a3c
--- /dev/null
+++ b/packaging/windows/bundle.wxs
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ eula.rtf
+
+
+
+
+
diff --git a/packaging/windows/dotnet.wxs b/packaging/windows/dotnet.wxs
index f978de721..561a469ab 100644
--- a/packaging/windows/dotnet.wxs
+++ b/packaging/windows/dotnet.wxs
@@ -6,7 +6,7 @@
-
+
diff --git a/packaging/windows/generatemsi.ps1 b/packaging/windows/generatemsi.ps1
index 6310cd370..ce1c09d46 100644
--- a/packaging/windows/generatemsi.ps1
+++ b/packaging/windows/generatemsi.ps1
@@ -8,6 +8,7 @@ param(
. "$PSScriptRoot\..\..\scripts\common\_common.ps1"
$DotnetMSIOutput = ""
+$DotnetBundleOutput = ""
$WixRoot = ""
$InstallFileswsx = "install-files.wxs"
$InstallFilesWixobj = "install-files.wixobj"
@@ -19,7 +20,7 @@ function AcquireWixTools
Write-Host Restoring Wixtools..
$result = $env:TEMP
-
+
.\dotnet restore $RepoRoot\packaging\windows\WiXTools --packages $result | Out-Null
if($LastExitCode -ne 0)
@@ -32,14 +33,14 @@ function AcquireWixTools
$result = Join-Path $result WiX\3.10.0.2103-pre1\tools
}
- popd
+ popd
return $result
}
function RunHeat
{
- $result = $true
- pushd "$WixRoot"
+ $result = $true
+ pushd "$WixRoot"
Write-Host Running heat..
@@ -63,7 +64,8 @@ function RunCandle
Write-Host Running candle..
$AuthWsxRoot = Join-Path $RepoRoot "packaging\windows"
- .\candle.exe -dDotnetSrc="$inputDir" `
+ .\candle.exe -nologo `
+ -dDotnetSrc="$inputDir" `
-dMicrosoftEula="$RepoRoot\packaging\osx\resources\en.lproj\eula.rtf" `
-dBuildVersion="$env:DOTNET_MSI_VERSION" `
-dDisplayVersion="$env:DOTNET_CLI_VERSION" `
@@ -92,14 +94,20 @@ function RunLight
pushd "$WixRoot"
Write-Host Running light..
+ $CabCache = Join-Path $WixRoot "cabcache"
+ $AuthWsxRoot = Join-Path $RepoRoot "packaging\windows"
- .\light -ext WixUIExtension -ext WixDependencyExtension -ext WixUtilExtension `
+ .\light.exe -nologo -ext WixUIExtension -ext WixDependencyExtension -ext WixUtilExtension `
-cultures:en-us `
dotnet.wixobj `
provider.wixobj `
registrykeys.wixobj `
checkbuildtype.wixobj `
$InstallFilesWixobj `
+ -b "$inputDir" `
+ -b "$AuthWsxRoot" `
+ -reusecab `
+ -cc "$CabCache" `
-out $DotnetMSIOutput | Out-Host
if($LastExitCode -ne 0)
@@ -112,19 +120,80 @@ function RunLight
return $result
}
+function RunCandleForBundle
+{
+ $result = $true
+ pushd "$WixRoot"
+
+ Write-Host Running candle for bundle..
+ $AuthWsxRoot = Join-Path $RepoRoot "packaging\windows"
+
+ .\candle.exe -nologo `
+ -dDotnetSrc="$inputDir" `
+ -dMicrosoftEula="$RepoRoot\packaging\osx\resources\en.lproj\eula.rtf" `
+ -dBuildVersion="$env:DOTNET_MSI_VERSION" `
+ -dDisplayVersion="$env:DOTNET_CLI_VERSION" `
+ -dReleaseSuffix="$env:ReleaseSuffix" `
+ -dMsiSourcePath="$DotnetMSIOutput" `
+ -arch x64 `
+ -ext WixBalExtension.dll `
+ -ext WixUtilExtension.dll `
+ -ext WixTagExtension.dll `
+ "$AuthWsxRoot\bundle.wxs" | Out-Host
+
+ if($LastExitCode -ne 0)
+ {
+ $result = $false
+ Write-Host "Candle failed with exit code $LastExitCode."
+ }
+
+ popd
+ return $result
+}
+
+function RunLightForBundle
+{
+ $result = $true
+ pushd "$WixRoot"
+
+ Write-Host Running light for bundle..
+ $AuthWsxRoot = Join-Path $RepoRoot "packaging\windows"
+
+ .\light.exe -nologo `
+ -cultures:en-us `
+ bundle.wixobj `
+ -ext WixBalExtension.dll `
+ -ext WixUtilExtension.dll `
+ -ext WixTagExtension.dll `
+ -b "$AuthWsxRoot" `
+ -out $DotnetBundleOutput | Out-Host
+
+ if($LastExitCode -ne 0)
+ {
+ $result = $false
+ Write-Host "Light failed with exit code $LastExitCode."
+ }
+
+ popd
+ return $result
+}
+
+
if(!(Test-Path $inputDir))
{
throw "$inputDir not found"
}
-if(!(Test-Path $PackageDir))
+if(!(Test-Path $PackageDir))
{
mkdir $PackageDir | Out-Null
}
$DotnetMSIOutput = Join-Path $PackageDir "dotnet-win-x64.$env:DOTNET_CLI_VERSION.msi"
+$DotnetBundleOutput = Join-Path $PackageDir "dotnet-win-x64.$env:DOTNET_CLI_VERSION.exe"
Write-Host "Creating dotnet MSI at $DotnetMSIOutput"
+Write-Host "Creating dotnet Bundle at $DotnetBundleOutput"
$WixRoot = AcquireWixTools
@@ -135,7 +204,7 @@ if([string]::IsNullOrEmpty($WixRoot))
}
if(-Not (RunHeat))
-{
+{
Exit -1
}
@@ -144,18 +213,35 @@ if(-Not (RunCandle))
Exit -1
}
+if(-Not (RunCandleForBundle))
+{
+ Exit -1
+}
+
if(-Not (RunLight))
{
Exit -1
}
+if(-Not (RunLightForBundle))
+{
+ Exit -1
+}
+
if(!(Test-Path $DotnetMSIOutput))
{
throw "Unable to create the dotnet msi."
Exit -1
}
+if(!(Test-Path $DotnetBundleOutput))
+{
+ throw "Unable to create the dotnet bundle."
+ Exit -1
+}
+
Write-Host -ForegroundColor Green "Successfully created dotnet MSI - $DotnetMSIOutput"
+Write-Host -ForegroundColor Green "Successfully created dotnet bundle - $DotnetBundleOutput"
_ $PSScriptRoot\testmsi.ps1 @("$DotnetMSIOutput")