Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,7 @@ public async Task ExtractManifestAsync(string nupkgPath, string targetPath)
}
}

var manifestsFolder = Path.Combine(msiExtractionPath, "dotnet", "sdk-manifests");

string? manifestFolder = null;
string? manifestsFeatureBandFolder = Directory.GetDirectories(manifestsFolder).SingleOrDefault();
if (manifestsFeatureBandFolder != null)
{
manifestFolder = Directory.GetDirectories(manifestsFeatureBandFolder).SingleOrDefault();
}
string? manifestFolder = FindExtractedManifestFolder(msiExtractionPath);

if (manifestFolder == null)
{
Expand All @@ -155,6 +148,42 @@ public async Task ExtractManifestAsync(string nupkgPath, string targetPath)
}
}

/// <summary>
/// Locates the extracted manifest directory in the layout produced by the administrative install of a
/// manifest or workload set MSI.
///
/// <para>
/// The MSI lays its content down under <c>&lt;Program Files&gt;\dotnet\sdk-manifests\&lt;feature band&gt;\...</c>,
/// but the name of the Program Files directory in the administrative image depends on the WiX version that
/// built the MSI: WiX v3 collapsed it into the target directory (<c>&lt;target&gt;\dotnet\sdk-manifests</c>),
/// while WiX v4+ emits a named directory for it (for example <c>&lt;target&gt;\PFiles64\dotnet\sdk-manifests</c>).
/// Search for the <c>sdk-manifests</c> directory instead of assuming a fixed depth so that both layouts work.
/// </para>
/// </summary>
/// <param name="msiExtractionPath">The directory the MSI was administratively installed to.</param>
/// <returns>The extracted manifest directory, or <see langword="null"/> if it could not be located.</returns>
internal static string? FindExtractedManifestFolder(string msiExtractionPath)
{
if (!Directory.Exists(msiExtractionPath))
{
return null;
}

string? manifestsFolder = Directory.EnumerateDirectories(msiExtractionPath, "sdk-manifests", SearchOption.AllDirectories).FirstOrDefault();
if (manifestsFolder == null)
{
return null;
}
Comment on lines +172 to +176

string? manifestsFeatureBandFolder = Directory.GetDirectories(manifestsFolder).SingleOrDefault();
if (manifestsFeatureBandFolder == null)
{
return null;
}

return Directory.GetDirectories(manifestsFeatureBandFolder).SingleOrDefault();
}

/// <summary>
/// Equivalent to <see cref="MsiInstallerBase.GetMsiLogNameForAdminInstall(string)"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,36 @@ public void GetManifestPackageIdReturnsTheArchitectureQualifiedManifestPackageId
packageId.ToString().Should().Be(
$"{manifestId}.Manifest-{featureBand}.Msi.{RuntimeInformation.ProcessArchitecture}".ToLowerInvariant());
}

// MSIs built with WiX v3 collapse the Program Files directory into the administrative install target.
[TestMethod]
public void FindExtractedManifestFolderLocatesTheManifestInTheWiXV3AdminInstallLayout()
{
var testDirectory = TestAssetsManager.CreateTestDirectory().Path;
var expected = Path.Combine(testDirectory, "dotnet", "sdk-manifests", "6.0.100", "test.manifest");
Directory.CreateDirectory(expected);

WindowsMsiManifestInstaller.FindExtractedManifestFolder(testDirectory).Should().Be(expected);
}

// MSIs built with WiX v4 and newer emit a named directory for Program Files in the administrative image.
[TestMethod]
public void FindExtractedManifestFolderLocatesTheManifestInTheWiXV4AdminInstallLayout()
{
var testDirectory = TestAssetsManager.CreateTestDirectory().Path;
var expected = Path.Combine(testDirectory, "PFiles64", "dotnet", "sdk-manifests", "6.0.100", "workloadsets");
Directory.CreateDirectory(expected);

WindowsMsiManifestInstaller.FindExtractedManifestFolder(testDirectory).Should().Be(expected);
}

[TestMethod]
public void FindExtractedManifestFolderReturnsNullWhenThereIsNoManifest()
{
var testDirectory = TestAssetsManager.CreateTestDirectory().Path;
Directory.CreateDirectory(Path.Combine(testDirectory, "PFiles64", "dotnet"));

WindowsMsiManifestInstaller.FindExtractedManifestFolder(testDirectory).Should().BeNull();
WindowsMsiManifestInstaller.FindExtractedManifestFolder(Path.Combine(testDirectory, "does-not-exist")).Should().BeNull();
}
}