Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unpack/Repack Pkg Tooling and Tests #15205

Merged
merged 15 commits into from
Nov 21, 2024
Merged
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
30 changes: 30 additions & 0 deletions Arcade.sln
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Internal.S
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.ArcadeAzureIntegration", "src\Microsoft.DotNet.ArcadeAzureIntegration\Microsoft.DotNet.ArcadeAzureIntegration.csproj", "{CA159C84-CD7D-4364-9121-3842F97D4B60}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DotNet.MacOsPkg", "src\Microsoft.DotNet.MacOsPkg\Microsoft.DotNet.MacOsPkg.csproj", "{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DotNet.MacOsPkg.Tests", "src\Microsoft.DotNet.MacOsPkg.Tests\Microsoft.DotNet.MacOsPkg.Tests.csproj", "{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -949,6 +953,30 @@ Global
{CA159C84-CD7D-4364-9121-3842F97D4B60}.Release|x64.Build.0 = Release|Any CPU
{CA159C84-CD7D-4364-9121-3842F97D4B60}.Release|x86.ActiveCfg = Release|Any CPU
{CA159C84-CD7D-4364-9121-3842F97D4B60}.Release|x86.Build.0 = Release|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Debug|x64.ActiveCfg = Debug|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Debug|x64.Build.0 = Debug|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Debug|x86.ActiveCfg = Debug|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Debug|x86.Build.0 = Debug|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Release|Any CPU.Build.0 = Release|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Release|x64.ActiveCfg = Release|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Release|x64.Build.0 = Release|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Release|x86.ActiveCfg = Release|Any CPU
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0}.Release|x86.Build.0 = Release|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Debug|x64.ActiveCfg = Debug|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Debug|x64.Build.0 = Debug|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Debug|x86.ActiveCfg = Debug|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Debug|x86.Build.0 = Debug|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Release|Any CPU.Build.0 = Release|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Release|x64.ActiveCfg = Release|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Release|x64.Build.0 = Release|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Release|x86.ActiveCfg = Release|Any CPU
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -986,6 +1014,8 @@ Global
{14462553-E4E1-4F67-B954-4BF24B1DAAFE} = {3C542789-2576-48C8-9772-C9D7575F7E42}
{650B7526-7B8A-45B5-B14E-C16D828891B2} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{6BA81447-C61D-4F91-BF0F-5B17AF4CFFAC} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{CE0FAEB2-4B8A-4A37-840D-7FF88ECB42A0} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE}
{1F5118A8-A5C5-4D18-AF34-FFB60FECCD45} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {32B9C883-432E-4FC8-A1BF-090EB033DD5B}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<MicrosoftDotnetNuGetRepackTasksVersion Condition="'$(MicrosoftDotnetNuGetRepackTasksVersion)' == ''">$(ArcadeSdkVersion)</MicrosoftDotnetNuGetRepackTasksVersion>
<MicrosoftDotNetSignToolVersion Condition="'$(MicrosoftDotNetSignToolVersion)' == ''">$(ArcadeSdkVersion)</MicrosoftDotNetSignToolVersion>
<MicrosoftDotNetTarVersion Condition="'$(MicrosoftDotNetTarVersion)' == ''">$(ArcadeSdkVersion)</MicrosoftDotNetTarVersion>
<MicrosoftDotNetMacOsPkgVersion Condition="'$(MicrosoftDotNetMacOsPkgVersion)' == ''">$(ArcadeSdkVersion)</MicrosoftDotNetMacOsPkgVersion>
<MicrosoftTestPlatformVersion Condition="'$(MicrosoftTestPlatformVersion)' == ''">16.5.0</MicrosoftTestPlatformVersion>

<!-- Follow the instructions on how to update any of the below xunit versions: https://github.com/dotnet/arcade/blob/main/Documentation/update-xunit.md. -->
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<PackageReference Include="Microsoft.Signed.Wix" Version="$(MicrosoftSignedWixVersion)" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.DotNet.SignTool" Version="$(MicrosoftDotNetSignToolVersion)" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.DotNet.Tar" Version="$(MicrosoftDotNetTarVersion)" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.DotNet.MacOsPkg" Version="$(MicrosoftDotNetMacOsPkgVersion)" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.SymbolUploader.Build.Task" Version="$(MicrosoftSymbolUploaderBuildTaskVersion)" Condition="'$(PublishToSymbolServer)' == 'true'" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.DotNet.Build.Tasks.VisualStudio" Version="$(MicrosoftDotNetBuildTasksVisualStudioVersion)" Condition="'$(UsingToolVSSDK)' == 'true'" IsImplicitlyDefined="true" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetToolCurrent)</TargetFrameworks>
ellahathaway marked this conversation as resolved.
Show resolved Hide resolved
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.Build.Utilities.Core" />
<PackageReference Include="Microsoft.Build.Framework" />
</ItemGroup>

<ItemGroup>
<Content Include="Resources\**"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Common\Microsoft.Arcade.Test.Common\Microsoft.Arcade.Test.Common.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.XUnitExtensions\src\Microsoft.DotNet.XUnitExtensions.csproj" />

<ProjectReference Condition="$([MSBuild]::IsOSPlatform('osx'))"
Include="..\Microsoft.DotNet.MacOsPkg\Microsoft.DotNet.MacOsPkg.csproj"
ReferenceOutputAssembly="false"
SetTargetFramework="TargetFramework=$(NetToolCurrent)"
SkipGetTargetFrameworkProperties="true"
Private="false"
OutputItemType="_MacOsPkgToolPath" />
</ItemGroup>

<Target Name="_CopyMacOsPkgTool" AfterTargets="ResolveProjectReferences" Condition="$([MSBuild]::IsOSPlatform('osx'))">
<PropertyGroup>
<_MacOSPkgToolPattern>@(_MacOsPkgToolPath->'%(RootDir)%(Directory)')**\*.*</_MacOSPkgToolPattern>
</PropertyGroup>
<ItemGroup>
<_MacOSPkgToolFiles Include="$(_MacOsPkgToolPattern)"/>
</ItemGroup>
<ItemGroup>
<Content Include="@(_MacOsPkgToolFiles)" CopyToOutputDirectory="PreserveNewest" Link="tools\macospkg\%(RecursiveDir)%(Filename)%(Extension)"/>
</ItemGroup>
</Target>

</Project>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
242 changes: 242 additions & 0 deletions src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.DotNet.MacOsPkg.Tests
{
public class UnpackPackTests
{
private readonly ITestOutputHelper output;
private static readonly string simplePkg = GetResourceFilePath("Simple.pkg");
private static readonly string withAppPkg = GetResourceFilePath("WithApp.pkg");
private static readonly string simpleInstallerPkg = GetResourceFilePath("SimpleInstaller.pkg");
private static readonly string withAppInstallerPkg = GetResourceFilePath("WithAppInstaller.pkg");

private static readonly string pkgToolPath = Path.Combine(
Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location)!,
"tools",
"macospkg",
"Microsoft.Dotnet.MacOsPkg.dll");

private static readonly string[] simplePkgFiles =
[
"Bom",
"PackageInfo",
Path.Combine("Payload", "Sample.txt")
];

private static readonly string[] withAppPkgFiles =
[
"Bom",
"PackageInfo",
Path.Combine("Payload", "test.app")
];

private static readonly string[] appFiles =
[
Path.Combine("Contents", "Info.plist"),
Path.Combine("Contents", "MacOS", "main"),
Path.Combine("Contents", "Resources", "libexample.dylib")
];

private static readonly string[] simpleInstallerFiles =
[
"Distribution",
"Simple.pkg"
];

private static readonly string[] withAppInstallerFiles =
[
"Distribution",
"WithApp.pkg"
];

public UnpackPackTests(ITestOutputHelper output) => this.output = output;

[MacOSOnlyFact]
public void UnpackPackSimplePkg()
{
string unpackPath = Path.GetTempFileName();
string packPath = GetTempPkgPath();

ExecuteWithCleanup(() =>
{
Unpack(simplePkg, unpackPath, simplePkgFiles);
Pack(unpackPath, packPath, simplePkgFiles);
}, [ unpackPath, packPath ]);
}

[MacOSOnlyFact]
public void UnpackPackWithAppPkg()
{
string unpackPath = Path.GetTempFileName();
string packPath = GetTempPkgPath();

ExecuteWithCleanup(() =>
{
Unpack(withAppPkg, unpackPath, withAppPkgFiles);
Pack(unpackPath, packPath, withAppPkgFiles);
}, [ unpackPath, packPath ]);
}

[MacOSOnlyFact]
public void UnpackPackAppBundle()
{
string unpackPkgPath = Path.GetTempFileName();
string unpackAppPath = Path.GetTempFileName();
string packAppPath = GetTempAppPath();

ExecuteWithCleanup(() =>
{
Unpack(withAppPkg, unpackPkgPath, withAppPkgFiles);
Unpack(Path.Combine(unpackPkgPath, "Payload", "test.app"), unpackAppPath, appFiles);
Pack(unpackAppPath, packAppPath, appFiles);
}, [ unpackPkgPath, unpackAppPath ]);
}

[MacOSOnlyFact]
public void UnpackPackSimpleInstallerPkg()
{
string unpackPath = Path.GetTempFileName();
string packPath = GetTempPkgPath();

ExecuteWithCleanup(() =>
{
Unpack(simpleInstallerPkg, unpackPath, simpleInstallerFiles);
Pack(unpackPath, packPath, simpleInstallerFiles);
}, [ unpackPath, packPath ]);
}

[MacOSOnlyFact]
public void UnpackPackSimplePkgInSimpleInstallerPkg()
{
string unpackInstallerPath = Path.GetTempFileName();
string unpackComponentPath = Path.GetTempFileName();
string packInstallerPath = GetTempPkgPath();

string componentPkgPath = Path.Combine(unpackInstallerPath, "Simple.pkg");

ExecuteWithCleanup(() =>
{
Unpack(simpleInstallerPkg, unpackInstallerPath, simpleInstallerFiles);
Unpack(componentPkgPath, unpackComponentPath, simplePkgFiles);
Pack(unpackComponentPath, componentPkgPath, simplePkgFiles);
Pack(unpackInstallerPath, packInstallerPath, simpleInstallerFiles);
}, [ unpackInstallerPath, unpackComponentPath, packInstallerPath ]);
}

[MacOSOnlyFact]
public void UnpackPackAppBundleAndWithAppPkgInWithAppInstallerPkg()
{
string unpackInstallerPath = Path.GetTempFileName();
string unpackComponentPath = Path.GetTempFileName();
string unpackAppPath = Path.GetTempFileName();
string packInstallerPath = GetTempPkgPath();

string componentPkgPath = Path.Combine(unpackInstallerPath, "WithApp.pkg");
string appPath = Path.Combine(unpackComponentPath, "Payload", "test.app");

ExecuteWithCleanup(() =>
{
Unpack(withAppInstallerPkg, unpackInstallerPath, withAppInstallerFiles);
Unpack(componentPkgPath, unpackComponentPath, withAppPkgFiles);
Unpack(appPath, unpackAppPath, appFiles);
Pack(unpackAppPath, appPath, appFiles);
Pack(unpackComponentPath, componentPkgPath, withAppPkgFiles);
Pack(unpackInstallerPath, packInstallerPath, withAppInstallerFiles);
}, [ unpackInstallerPath, unpackComponentPath, unpackAppPath, packInstallerPath ]);
}

private static void ExecuteWithCleanup(Action action, List<string> cleanupPaths)
{
try
{
action();
}
finally
{
foreach (string path in cleanupPaths)
{
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
else if (File.Exists(path))
{
File.Delete(path);
}
}
}
}

private void Unpack(string srcPath, string dstPath, string[] expectedFiles)
{
RunPkgProcess(srcPath, dstPath, "unpack").Should().BeTrue();

Directory.Exists(dstPath).Should().BeTrue();

CompareContent(dstPath, expectedFiles);
}

private void Pack(string srcPath, string dstPath, string[] expectedFiles)
{
RunPkgProcess(srcPath, dstPath, "pack").Should().BeTrue();

File.Exists(dstPath).Should().BeTrue();

// Unpack the packed pkg and verify the content
string unpackPath = Path.GetTempFileName();
ExecuteWithCleanup(() =>
{
Unpack(dstPath, unpackPath, expectedFiles);
}, [ unpackPath ]);
}

private bool RunPkgProcess(string inputPath, string outputPath, string action)
{
var process = Process.Start(new ProcessStartInfo()
{
FileName = "dotnet",
Arguments = $@"exec ""{pkgToolPath}"" ""{inputPath}"" ""{outputPath}"" {action}",
UseShellExecute = false,
RedirectStandardError = true,
});

process!.WaitForExit(60000); // 60 seconds
bool success = process.ExitCode == 0;
if (!success)
{
output.WriteLine($"Error: {process.StandardError.ReadToEnd()}");
}
return success;
}

private static string GetResourceFilePath(string resourceName)
{
return Path.Combine(
Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location)!,
"Resources",
resourceName);
}

private static string GetTempPkgPath() => $"{Path.GetTempFileName()}.pkg";

private static string GetTempAppPath() => $"{Path.GetTempFileName()}.app";

private static void CompareContent(string basePath, string[] expectedFiles)
{
string[] actualFiles = Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories)
.Select(f => f.Substring(basePath.Length + 1))
.ToArray();
actualFiles.Should().BeEquivalentTo(expectedFiles);
mmitche marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
20 changes: 20 additions & 0 deletions src/Microsoft.DotNet.MacOsPkg/AppBundle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.DotNet.MacOsPkg
{
internal static class AppBundle
{
internal static void Unpack(string inputPath, string outputPath)
{
string args = $"-V -xk {inputPath} {outputPath}";
ExecuteHelper.Run("ditto", args);
}

internal static void Pack(string inputPath, string outputPath)
{
string args = $"-c -k --sequesterRsrc {inputPath} {outputPath}";
ExecuteHelper.Run("ditto", args);
}
}
}
Loading
Loading