From fd7b5605964e35a307ee7e7deae01ab370129ecf Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Tue, 29 Oct 2024 15:59:07 +0000 Subject: [PATCH 01/14] Unpack/Repack Pkg Tooling and Tests --- Arcade.sln | 30 ++ .../tools/DefaultVersions.props | 1 + .../tools/Tools.proj | 1 + .../Microsoft.DotNet.Pkg.Tests.csproj | 43 ++ .../Resources/Simple.pkg | Bin 0 -> 1667 bytes .../Resources/SimpleInstaller.pkg | Bin 0 -> 2218 bytes .../Resources/WithApp.pkg | Bin 0 -> 4301 bytes .../Resources/WithAppInstaller.pkg | Bin 0 -> 4910 bytes .../UnpackRepackTests.cs | 407 ++++++++++++++++++ src/Microsoft.DotNet.Pkg/AppBundle.cs | 31 ++ src/Microsoft.DotNet.Pkg/ExecuteHelper.cs | 41 ++ .../Microsoft.DotNet.Pkg.csproj | 18 + src/Microsoft.DotNet.Pkg/Package.cs | 156 +++++++ src/Microsoft.DotNet.Pkg/PackageBundle.cs | 177 ++++++++ src/Microsoft.DotNet.Pkg/Processor.cs | 114 +++++ src/Microsoft.DotNet.Pkg/Program.cs | 52 +++ .../Microsoft.DotNet.SignTool.Tests.csproj | 20 + 17 files changed, 1091 insertions(+) create mode 100644 src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj create mode 100644 src/Microsoft.DotNet.Pkg.Tests/Resources/Simple.pkg create mode 100644 src/Microsoft.DotNet.Pkg.Tests/Resources/SimpleInstaller.pkg create mode 100644 src/Microsoft.DotNet.Pkg.Tests/Resources/WithApp.pkg create mode 100644 src/Microsoft.DotNet.Pkg.Tests/Resources/WithAppInstaller.pkg create mode 100644 src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs create mode 100644 src/Microsoft.DotNet.Pkg/AppBundle.cs create mode 100644 src/Microsoft.DotNet.Pkg/ExecuteHelper.cs create mode 100644 src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj create mode 100644 src/Microsoft.DotNet.Pkg/Package.cs create mode 100644 src/Microsoft.DotNet.Pkg/PackageBundle.cs create mode 100644 src/Microsoft.DotNet.Pkg/Processor.cs create mode 100644 src/Microsoft.DotNet.Pkg/Program.cs diff --git a/Arcade.sln b/Arcade.sln index 3e355769f02..bbfd972403f 100644 --- a/Arcade.sln +++ b/Arcade.sln @@ -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.Pkg", "src\Microsoft.DotNet.Pkg\Microsoft.DotNet.Pkg.csproj", "{F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DotNet.Pkg.Tests", "src\Microsoft.DotNet.Pkg.Tests\Microsoft.DotNet.Pkg.Tests.csproj", "{0917B9D9-90C0-4DE4-9C85-D248FB9F826C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -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 + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x64.ActiveCfg = Debug|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x64.Build.0 = Debug|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x86.ActiveCfg = Debug|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x86.Build.0 = Debug|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|Any CPU.Build.0 = Release|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x64.ActiveCfg = Release|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x64.Build.0 = Release|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x86.ActiveCfg = Release|Any CPU + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x86.Build.0 = Release|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x64.ActiveCfg = Debug|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x64.Build.0 = Debug|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x86.ActiveCfg = Debug|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x86.Build.0 = Debug|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|Any CPU.Build.0 = Release|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x64.ActiveCfg = Release|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x64.Build.0 = Release|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x86.ActiveCfg = Release|Any CPU + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -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} + {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE} + {0917B9D9-90C0-4DE4-9C85-D248FB9F826C} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {32B9C883-432E-4FC8-A1BF-090EB033DD5B} diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props b/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props index 737e0bd375f..075dbcd672f 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props @@ -80,6 +80,7 @@ $(ArcadeSdkVersion) $(ArcadeSdkVersion) $(ArcadeSdkVersion) + $(ArcadeSdkVersion) 16.5.0 diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj b/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj index d7cc34a6f50..93c3c3e2cdc 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj @@ -56,6 +56,7 @@ + diff --git a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj b/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj new file mode 100644 index 00000000000..a9be32a8622 --- /dev/null +++ b/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj @@ -0,0 +1,43 @@ + + + + $(NetToolCurrent);$(NetFrameworkToolCurrent) + + + + + + + + + + + + + + + + + + + + + + <_PkgToolPattern>@(_PkgToolPath->'%(RootDir)%(Directory)')**\*.* + + + <_PkgToolFiles Include="$(_PkgToolPattern)"/> + + + + + + + diff --git a/src/Microsoft.DotNet.Pkg.Tests/Resources/Simple.pkg b/src/Microsoft.DotNet.Pkg.Tests/Resources/Simple.pkg new file mode 100644 index 0000000000000000000000000000000000000000..349d3a6cc074bba9101b3918974cb13ed7c95827 GIT binary patch literal 1667 zcmV-}27LK=VR9h=8~_0T0000000O4~0000000^W20004a+U!7M5YRQ8*lC0@+yGL7yWTPnP#~<>L@s#@-l0#B&TkvgHUF=#N$R#T+2h2NAQALMvMC!&lT$k9oNF=fS?zY)Qu~9&$7uan z?!tJ69{X159!zxppoVY_2CU)23Y8Tcu~ZnU(#&WM0%r;nfen-K+elLi)#^=oxR@am zLRbXcl7b*gIm1>PB21AnOnH(B&XaI$qn!PFI)I>FX$v)|=iudFM} zI2iq<@z=ue_l|uBZEl*rc70;tAY<j6t~#u3MEb{xMem4|Jk%ypUIi!$LPJAZi*bgt>S+c)}Kw^xx+i@3E~ zCk0j+L8-t6Ge{Mhxh@u1QA?2h1BDP?AWjVjLK1g!O$)9IrBfsdTv(-?Qdojj@-G!a zkZZ~X`LB>)RS5o|LOwUu8Fe_=@X(O4e|G!?009600|1QglDWm=SL52_VP19TnaBD; z#f+cU=bU)j?c7aER8bfJ;CF61mT8uK5<)QUg>Z7!qFiO)B(@BN#tKqXXCXmU1VPZk zP0OI7Rllk~(5{w6=gyfKC))%Sl|2uf``+{3b3f+JtX|HX=_{9Jn=5OLh^VA?EaKUh zh`G&(@mlJi4tBcodmm`+EibOL`(=yfTBGy3=#SW6riyZNU_IrEo+}KeHWYcth!+X~ z0028fPi0_Nw=&R^+@0E^?&yhVr}y4$Y-}qX97^qAv{P^v*!$XyaAD^st zFY%KVgr0KCXliGE^+k_tT{IVL4o7!h$Tzo{&tdT0R;qq2ZN}1rP37~7say~$#&Umj zwcRfV52yZxoUgr!*7TCvYVMEU$m1qcj1y^Gd9P}Ui_w~jGWj6I@ihKvwEmw`d(qCn z&*x9R${(WkGR3}hzmqxEPqmMK%E#;H+xg2m0ssI2000000000000000000000RMsh zh@xDpv=UK!o#W_owANrPhTE}RAa&^bQ?17e0000000000000000000000000{8Oqw zz8-5m<>xj#Cw>JBWK=dEiwFP!0000012Zr;06}D6Vqk7+YJd)mA(Wwsxq+Ffftj&6 zM2QiS5Vvc~NqlDKkQ*xsJDYnedg66O1UJAdM0e+piGA}2?&gw6U66vmpY zi){(LG&+ZUwJN%gR=e1cqQU#cPEdEq!KJY-l_1h_CeZ(&;(ar1OVd z-E4P{_q+Ud$T8nBC7irjpEw(jK1)Z#m|2pD0?PDqEP;sxs+Ag6(V4R+V^!?K0r|ao zaURo@VQ%~Obe559Ae&1LeY75zWDD)PmW@SyQLoe*`3r}K1y}2TwIu9n(bvCSgn0s^ NvB;L8Ro}a9qL7&c7})>- literal 0 HcmV?d00001 diff --git a/src/Microsoft.DotNet.Pkg.Tests/Resources/SimpleInstaller.pkg b/src/Microsoft.DotNet.Pkg.Tests/Resources/SimpleInstaller.pkg new file mode 100644 index 0000000000000000000000000000000000000000..47a9ba9513f4b5522174dfc803a13d67f799453a GIT binary patch literal 2218 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 Jdv6TD^M58Emy!Sg literal 0 HcmV?d00001 diff --git a/src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs b/src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs new file mode 100644 index 00000000000..a0f39af4c70 --- /dev/null +++ b/src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs @@ -0,0 +1,407 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; +using System.Diagnostics; +using Xunit; +using Xunit.Abstractions; +using FluentAssertions; + +namespace Microsoft.DotNet.Pkg.Tests +{ + public class UnpackRepackTests + { + private static string pkgToolPath = Path.Combine( + Path.GetDirectoryName(typeof(UnpackRepackTests).Assembly.Location), + "tools", + "pkg", + "Microsoft.Dotnet.Pkg.dll"); + + private static string[] simplePkgFiles = new[] + { + Path.Combine("Bom"), + Path.Combine("PackageInfo"), + Path.Combine("Payload", "Sample.txt") + }; + + private static string[] withAppPkgFiles = new[] + { + Path.Combine("Bom"), + Path.Combine("PackageInfo"), + Path.Combine("Payload", "test.app") + }; + + private static string[] appFiles = new[] + { + Path.Combine("Contents", "Info.plist"), + Path.Combine("Contents", "MacOS", "main"), + Path.Combine("Contents", "Resources", "libexample.dylib"), + }; + + private static string[] simpleInstallerFiles = new[] + { + Path.Combine("Distribution"), + Path.Combine("Simple.pkg"), + }; + + private static string[] withAppInstallerFiles = new[] + { + Path.Combine("Distribution"), + Path.Combine("WithApp.pkg"), + }; + + [MacOSOnlyFact] + public void UnpackSimplePkg() + { + string srcPath = GetResourceFilePath("Simple.pkg"); + string dstPath = GetTempFilePath("SimplePkg"); + try + { + Unpack(srcPath, dstPath, simplePkgFiles); + } + finally + { + Directory.Delete(dstPath, true); + } + } + + [MacOSOnlyFact] + public void RepackSimplePkg() + { + string srcPath = GetResourceFilePath("Simple.pkg"); + string dstPath = GetTempFilePath("SimplePkg"); + string repackPath = GetTempFilePath("RepackSimple.pkg"); + try + { + // Unpack the package + Unpack(srcPath, dstPath); + + // Repack the package + Repack(dstPath, repackPath, simplePkgFiles); + } + finally + { + Directory.Delete(dstPath, true); + File.Delete(repackPath); + } + } + + [MacOSOnlyFact] + public void UnpackPkgWithApp() + { + string srcPath = GetResourceFilePath("WithApp.pkg"); + string dstPath = GetTempFilePath("WithAppPkg"); + try + { + Unpack(srcPath, dstPath, withAppPkgFiles); + } + finally + { + Directory.Delete(dstPath, true); + } + } + + [MacOSOnlyFact] + public void RepackPkgWithApp() + { + string srcPath = GetResourceFilePath("WithApp.pkg"); + string dstPath = GetTempFilePath("WithAppPkg"); + string repackPath = GetTempFilePath("RepackWithApp.pkg"); + try + { + // Unpack the package + Unpack(srcPath, dstPath); + + // Repack the package + Repack(dstPath, repackPath, withAppPkgFiles); + } + finally + { + Directory.Delete(dstPath, true); + File.Delete(repackPath); + } + } + + [MacOSOnlyFact] + public void UnpackAppBundle() + { + string srcPath = GetResourceFilePath("WithApp.pkg"); + string dstPath = GetTempFilePath("WithAppPkg"); + string appPath = Path.Combine(dstPath, "Payload", "test.app"); + string appDstPath = GetTempFilePath("TestApp"); + try + { + // Unpack the package + Unpack(srcPath, dstPath); + + // Unpack the app bundle + Unpack(appPath, appDstPath, appFiles); + } + finally + { + Directory.Delete(dstPath, true); + Directory.Delete(appDstPath, true); + } + } + + [MacOSOnlyFact] + public void RepackAppBundle() + { + string srcPath = GetResourceFilePath("WithApp.pkg"); + string dstPath = GetTempFilePath("WithAppPkg"); + string appPath = Path.Combine(dstPath, "Payload", "test.app"); + string appDstPath = GetTempFilePath("TestApp"); + try + { + // Unpack the package + Unpack(srcPath, dstPath); + + // Unpack the app bundle + Unpack(appPath, appDstPath); + + // Repack the app bundle + Repack(appDstPath, appPath, appFiles); + } + finally + { + Directory.Delete(dstPath, true); + Directory.Delete(appDstPath, true); + } + } + + [MacOSOnlyFact] + public void UnpackSimpleInstaller() + { + string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); + string dstPath = GetTempFilePath("SimpleInstallerPkg"); + try + { + Unpack(srcPath, dstPath, simpleInstallerFiles); + } + finally + { + Directory.Delete(dstPath, true); + } + } + + [MacOSOnlyFact] + public void RepackSimpleInstaller() + { + string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); + string dstPath = GetTempFilePath("SimpleInstallerPkg"); + string repackPath = GetTempFilePath("RepackSimpleInstaller.pkg"); + try + { + // Unpack the installer + Unpack(srcPath, dstPath); + + // Repack the installer + Repack(dstPath, repackPath, simpleInstallerFiles); + } + finally + { + Directory.Delete(dstPath, true); + File.Delete(repackPath); + } + } + + [MacOSOnlyFact] + public void UnpackNestedInstaller() + { + string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); + string dstPath = GetTempFilePath("SimpleInstallerPkg"); + string simplePkgPath = Path.Combine(dstPath, "Simple.pkg"); + string simplePkgDstPath = GetTempFilePath("SimplePkg"); + try + { + // Unpack the installer + Unpack(srcPath, dstPath, simpleInstallerFiles); + + // Unpack the simple package inside the installer + Unpack(simplePkgPath, simplePkgDstPath, simplePkgFiles); + } + finally + { + Directory.Delete(dstPath, true); + Directory.Delete(simplePkgDstPath, true); + } + } + + [MacOSOnlyFact] + public void RepackNestedInstaller() + { + string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); + string dstPath = GetTempFilePath("SimpleInstallerPkg"); + string simplePkgPath = Path.Combine(dstPath, "Simple.pkg"); + string simplePkgDstPath = GetTempFilePath("SimplePkg"); + string repackPath = GetTempFilePath("RepackSimpleInstaller.pkg"); + string unpackRepackPath = GetTempFilePath("UnpackRepackSimpleInstallerPkg"); + string unpackRepackSimplePkgPath = Path.Combine(unpackRepackPath, "Simple.pkg"); + string unpackRepackSimplePkgDstPath = GetTempFilePath("UnpackRepackSimplePkg"); + try + { + // Unpack the installer + Unpack(srcPath, dstPath); + + // Unpack and repack the simple package + Unpack(simplePkgPath, simplePkgDstPath); + Repack(simplePkgDstPath, simplePkgPath); + + // Repack the installer + Repack(dstPath, repackPath, simpleInstallerFiles); + + // Unpack the repacked simple pkg inside to compare the content + Unpack(repackPath, unpackRepackPath); + Unpack(unpackRepackSimplePkgPath, unpackRepackSimplePkgDstPath, simplePkgFiles); + } + finally + { + File.Delete(repackPath); + File.Delete(simplePkgPath); + + Directory.Delete(dstPath, true); + Directory.Delete(simplePkgDstPath, true); + Directory.Delete(unpackRepackPath, true); + Directory.Delete(unpackRepackSimplePkgDstPath, true); + } + } + + [MacOSOnlyFact] + public void UnpackNestedInstallerWithApp() + { + string srcPath = GetResourceFilePath("WithAppInstaller.pkg"); + string dstPath = GetTempFilePath("WithAppInstallerPkg"); + string withAppPkgPath = Path.Combine(dstPath, "WithApp.pkg"); + string withAppPkgDstPath = GetTempFilePath("WithAppPkg"); + try + { + // Unpack the installer + Unpack(srcPath, dstPath, withAppInstallerFiles); + + // Unpack the app package inside the installer + Unpack(withAppPkgPath, withAppPkgDstPath, withAppPkgFiles); + } + finally + { + Directory.Delete(dstPath, true); + Directory.Delete(withAppPkgDstPath, true); + } + } + + [MacOSOnlyFact] + public void RepackNestedInstallerWithApp() + { + string srcPath = GetResourceFilePath("WithAppInstaller.pkg"); + string dstPath = GetTempFilePath("WithAppInstallerPkg"); + string withAppPkgPath = Path.Combine(dstPath, "WithApp.pkg"); + string withAppPkgDstPath = GetTempFilePath("WithAppPkg"); + string repackPath = GetTempFilePath("RepackWithAppInstaller.pkg"); + string unpackRepackPath = GetTempFilePath("UnpackRepackWithAppInstallerPkg"); + string unpackRepackWithAppPkgPath = Path.Combine(unpackRepackPath, "WithApp.pkg"); + string unpackRepackWithAppPkgDstPath = GetTempFilePath("UnpackRepackWithAppPkg"); + try + { + // Unpack the installer + Unpack(srcPath, dstPath); + + // Unpack and repack the app package + Unpack(withAppPkgPath, withAppPkgDstPath); + Repack(withAppPkgDstPath, withAppPkgPath); + + // Repack the installer + Repack(dstPath, repackPath, withAppInstallerFiles); + + // Unpack the repacked app pkg inside to compare the content + Unpack(repackPath, unpackRepackPath); + Unpack(unpackRepackWithAppPkgPath, unpackRepackWithAppPkgDstPath, withAppPkgFiles); + } + finally + { + File.Delete(repackPath); + File.Delete(withAppPkgPath); + + Directory.Delete(dstPath, true); + Directory.Delete(withAppPkgDstPath, true); + Directory.Delete(unpackRepackPath, true); + Directory.Delete(unpackRepackWithAppPkgDstPath, true); + } + } + + private static void Unpack(string inputPath, string outputPath, string[] expectedFiles = null) + { + bool success = RunPkgProcess(inputPath, outputPath, "unpack"); + success.Should().BeTrue(); + + Directory.Exists(outputPath).Should().BeTrue(); + + if (expectedFiles != null) + { + CompareContent(outputPath, expectedFiles); + } + } + + private static void Repack(string inputPath, string outputPath, string[] expectedFiles = null) + { + bool success = RunPkgProcess(inputPath, outputPath, "repack"); + success.Should().BeTrue(); + + File.Exists(outputPath).Should().BeTrue(); + + if (expectedFiles != null) + { + string tempPath = GetTempFilePath($"UnpackRepack{Path.GetFileNameWithoutExtension(inputPath)}"); + RunPkgProcess(outputPath, tempPath, "unpack").Should().BeTrue(); + Directory.Exists(tempPath).Should().BeTrue(); + + CompareContent(tempPath, expectedFiles); + + Directory.Delete(tempPath, true); + } + } + + private static 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(); + bool success = process.ExitCode == 0; + if (!success) + { + Console.WriteLine($"Error: {process.StandardError.ReadToEnd()}"); + } + return success; + } + + private static string GetResourceFilePath(string resourceName) + { + return Path.Combine( + Path.GetDirectoryName(typeof(UnpackRepackTests).Assembly.Location), + "Resources", + resourceName); + } + + private static string GetTempFilePath(string fileName) + { + return Path.Combine( + Path.GetTempPath(), + fileName); + } + + 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); + } + } +} diff --git a/src/Microsoft.DotNet.Pkg/AppBundle.cs b/src/Microsoft.DotNet.Pkg/AppBundle.cs new file mode 100644 index 00000000000..6500cb18ada --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/AppBundle.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +#nullable enable + +namespace Microsoft.DotNet.Pkg +{ + 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 Repack(string inputPath, string outputPath) + { + string args = $"-c -k --sequesterRsrc {inputPath} {outputPath}"; + ExecuteHelper.Run("ditto", args); + } + } +} diff --git a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs b/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs new file mode 100644 index 00000000000..aa18f5a0f3f --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; + +namespace Microsoft.DotNet.Pkg +{ + public static class ExecuteHelper + { + public static string Run(string command, string arguments = "") + { + if (string.IsNullOrEmpty(command)) + { + throw new ArgumentNullException(nameof(command)); + } + + string output = string.Empty; + + ProcessStartInfo processStartInfo = CreateProcessStartInfo(command, arguments); + using (Process process = new Process { StartInfo = processStartInfo }) + { + process.Start(); + output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + } + return output; + } + + private static ProcessStartInfo CreateProcessStartInfo(string command, string arguments) => + new ProcessStartInfo + { + FileName = command, + Arguments = arguments, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + } +} diff --git a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj b/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj new file mode 100644 index 00000000000..add01a1dbd8 --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj @@ -0,0 +1,18 @@ + + + + $(NetToolCurrent);$(NetFrameworkToolCurrent) + Exe + true + true + Pkg + Arcade Build Tool Pkg + false + + + + true + dotnet-pkg + + + diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.Pkg/Package.cs new file mode 100644 index 00000000000..7509f3c3c86 --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/Package.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +#nullable enable + +namespace Microsoft.DotNet.Pkg +{ + internal static class Package + { + private static string NameWithExtension = string.Empty; + private static string LocalExtractionPath = string.Empty; + private static string? Identifier = null; + private static string? Resources = null; + private static string? Distribution = null; + private static string? Scripts = null; + private static List Bundles = new List(); + + internal static void Unpack() => + ProcessPackage(repacking: false); + + internal static void Repack() => + ProcessPackage(repacking: true); + + private static void ProcessPackage(bool repacking) + { + NameWithExtension = repacking ? Path.GetFileName(Processor.OutputPath) : Path.GetFileName(Processor.InputPath); + LocalExtractionPath = repacking ? Processor.InputPath : Processor.OutputPath; + + if (!Processor.IsPkg(NameWithExtension)) + { + throw new Exception($"Package '{NameWithExtension}' is not a .pkg file"); + } + + if (!repacking) + { + ExpandPkg(); + } + + Resources = Processor.FindInPath("Resources", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Distribution = Processor.FindInPath("Distribution", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + Scripts = Processor.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + string? packageInfo = Processor.FindInPath("PackageInfo", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + + if (!string.IsNullOrEmpty(Distribution)) + { + var xml = XElement.Load(Distribution); + List pkgBundles = xml.Elements("pkg-ref").Where(e => e.Value.Trim() != "").ToList(); + if (!pkgBundles.Any()) + { + throw new Exception("No pkg-ref elements found in Distribution file"); + } + Identifier = GetId(pkgBundles[0]); + foreach (var pkgBundle in pkgBundles) + { + ProcessBundle(pkgBundle, isNested: true, repacking: repacking); + } + + if (repacking) + { + RepackPkg(); + } + } + else if (!string.IsNullOrEmpty(packageInfo)) + { + // This is a single bundle package + XElement pkgBundle = XElement.Load(packageInfo); + ProcessBundle(pkgBundle, isNested: false, repacking: repacking); + } + else if (repacking) + { + throw new Exception("Cannot unpack: no Distribution or PackageInfo file found in package"); + } + } + + private static void ExpandPkg() + { + if (Directory.Exists(LocalExtractionPath)) + { + Directory.Delete(LocalExtractionPath, true); + } + + ExecuteHelper.Run("pkgutil", $"--expand {Processor.InputPath} {LocalExtractionPath}"); + } + + private static void RepackPkg() + { + string args = string.Empty; + args += $"--distribution {Distribution}"; + if (Bundles.Any()) + { + args += $" --package-path {LocalExtractionPath}"; + } + if (!string.IsNullOrEmpty(Resources)) + { + args += $" --resources {Resources}"; + } + if (!string.IsNullOrEmpty(Scripts)) + { + args += $" --scripts {Scripts}"; + } + if (args.Length == 0) + { + args += $" --root {LocalExtractionPath}"; + } + + if (File.Exists(Processor.OutputPath)) + { + File.Delete(Processor.OutputPath); + } + args += $" {Processor.OutputPath}"; + + ExecuteHelper.Run("productbuild", args); + } + + private static void ProcessBundle(XElement bundleInfo, bool isNested, bool repacking) + { + string extractionPath = isNested ? Path.Combine(LocalExtractionPath, bundleInfo.Value.Substring(1)) : LocalExtractionPath; + string version = bundleInfo.Attribute("version")?.Value ?? throw new Exception($"No version found in bundle file {NameWithExtension}"); + string id = GetId(bundleInfo); + PackageBundle bundle = new PackageBundle(extractionPath, id, version, NameWithExtension, isNested); + + if (!repacking) + { + bundle.Unpack(); + } + else + { + bundle.Repack(); + } + + if (isNested) + { + Bundles.Add(bundle); + } + } + + private static string GetId(XElement element) + { + string id = element.Attribute("packageIdentifier")?.Value + ?? element.Attribute("id")?.Value + ?? element.Attribute("identifier")?.Value + ?? throw new Exception("No packageIdentifier or id found in XElement."); + + return id; + } + } +} diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs new file mode 100644 index 00000000000..47ca0056edc --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/PackageBundle.cs @@ -0,0 +1,177 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +#nullable enable + +namespace Microsoft.DotNet.Pkg +{ + internal class PackageBundle + { + private bool IsNested; + private string NameWithExtension; + private string LocalExtractionPath; + private string Identifier; + private string Version; + private string? Scripts; + private string? Payload; + + internal PackageBundle(string localExtractionPath, string identifier, string version, string rootPkgName, bool isNested) + { + IsNested = isNested; + Identifier = identifier; + Version = version; + NameWithExtension = rootPkgName; + LocalExtractionPath = localExtractionPath; + if (isNested) + { + NameWithExtension = Path.GetFileName(localExtractionPath); + LocalExtractionPath = Path.Combine(Path.GetDirectoryName(localExtractionPath) ?? string.Empty, Path.GetFileNameWithoutExtension(NameWithExtension)); + } + + if (!Processor.IsPkg(NameWithExtension)) + { + throw new Exception($"Bundle '{NameWithExtension}' is not a .pkg file"); + } + } + + internal void Unpack() + { + if (IsNested) + { + // The nested bundles get unpacked into a directory with a .pkg extension by `pkgutil --expand`, + // so we remove this extension when unpacking the bundle. + // Otherwise, there will be problems when repacking the bundle due to the naming conflict + Directory.Move(LocalExtractionPath + ".pkg", LocalExtractionPath); + } + + Scripts = Processor.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Payload = Processor.FindInPath("Payload", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + + if (!string.IsNullOrEmpty(Payload)) + { + UnpackPayloadFile(Path.GetFullPath(Payload)); + } + + if (!IsNested) + { + // Zip the nested app bundles + IEnumerable nestedApps = Processor.GetDirectories(LocalExtractionPath, "*.app", SearchOption.AllDirectories); + foreach (string app in nestedApps) + { + string tempDest = $"{app}.zip"; + AppBundle.Repack(app, tempDest); + Directory.Delete(app, true); + + // Rename the zipped file to .app + // This is needed so that the signtool + // can properly identity and sign app bundles + File.Move(tempDest, app); + } + } + + if (IsNested) + { + // We now need to repack the nested bundle and remove the unpacked directory + PkgBuild(); + Directory.Delete(LocalExtractionPath, true); + } + } + + internal void Repack() + { + if (!IsNested) + { + Scripts = Processor.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Payload = Processor.FindInPath("Payload", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + + IEnumerable zippedNestedApps = Processor.GetFiles(LocalExtractionPath, "*.app", SearchOption.AllDirectories); + foreach (string appZip in zippedNestedApps) + { + // Unzip the .app directory + string tempDest = appZip + ".unzipped"; + AppBundle.Unpack(appZip, tempDest); + File.Delete(appZip); + + // Rename the unzipped directory back to .app + // so that it can be repacked properly + Directory.Move(tempDest, appZip); + } + + PkgBuild(); + } + } + + private void PkgBuild() + { + string info = GenerateInfoPlist(); + string root = string.IsNullOrEmpty(Payload) ? $"{LocalExtractionPath}" : $"{Payload}"; + string args = $"--root {root} --component-plist {info} --identifier {Identifier} --version {Version} --keychain login.keychain --install-location /usr/local/share/dotnet"; + if (!string.IsNullOrEmpty(Scripts)) + { + args += $" --scripts {Scripts}"; + } + + string outputPath = $"{LocalExtractionPath}.pkg"; + if (!IsNested) + { + outputPath = Processor.OutputPath; + if (File.Exists(outputPath)) + { + File.Delete(outputPath); + } + } + args += $" {outputPath}"; + + ExecuteHelper.Run("pkgbuild", args); + + File.Delete(info); + } + + private string GenerateInfoPlist() + { + string root = string.IsNullOrEmpty(Payload) ? $"{LocalExtractionPath}" : $"{Payload}"; + string info = Path.Combine(Processor.WorkingDirectory, "Info.plist"); + ExecuteHelper.Run("pkgbuild", $"--analyze --root {root} {info}"); + return info; + } + + private void UnpackPayloadFile(string payloadFilePath) + { + if (!File.Exists(payloadFilePath) || !Path.GetFileName(payloadFilePath).Equals("Payload")) + { + throw new Exception($"Cannot unpack invalid 'Payload' file in {NameWithExtension}"); + } + + string tempDir = Path.Combine(Processor.WorkingDirectory, "tempPayloadUnpackingDir"); + Directory.CreateDirectory(tempDir); + try + { + Directory.SetCurrentDirectory(tempDir); + + // While we're shelling out to an executable named 'tar', the "Payload" file from pkgs is not actually + // a tar file. It's secretly a 'pbzx' file that tar on OSX has been taught to unpack. + // As such, while there is actually untarring / re-tarring in this file using Python libraries, we have to + // shell out to the host machine to do this. + ExecuteHelper.Run("tar", $"-xf {payloadFilePath}"); + } + finally + { + Directory.SetCurrentDirectory(Processor.WorkingDirectory); + + // Remove the payload file and replace it with + // a directory of the same name containing the unpacked contents + File.Delete(payloadFilePath); + Directory.Move(tempDir, payloadFilePath); + } + } + } +} diff --git a/src/Microsoft.DotNet.Pkg/Processor.cs b/src/Microsoft.DotNet.Pkg/Processor.cs new file mode 100644 index 00000000000..9b1653218a4 --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/Processor.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +#nullable enable + +namespace Microsoft.DotNet.Pkg +{ + public static class Processor + { + internal static string WorkingDirectory = Directory.GetCurrentDirectory(); + internal static string InputPath = string.Empty; + internal static string OutputPath = string.Empty; + + public static void Initialize(string inputPath, string outputPath = "") + { + InputPath = inputPath; + OutputPath = outputPath; + } + + public static void Unpack() + { + if (!File.Exists(InputPath)) + { + throw new Exception("Input path must be a valid file"); + } + + if (!IsPkg(InputPath) && !IsAppBundle(InputPath)) + { + throw new Exception("Input path must be a .pkg or .app (zipped) file"); + } + + if (!Directory.Exists(OutputPath)) + { + Directory.CreateDirectory(OutputPath); + } + + if (IsPkg(InputPath)) + { + Package.Unpack(); + } + else if (IsAppBundle(InputPath)) + { + AppBundle.Unpack(InputPath, OutputPath); + } + } + + public static void Repack() + { + if (!Directory.Exists(InputPath)) + { + throw new Exception("Input path must be a valid directory"); + } + + if (!IsPkg(OutputPath) && !IsAppBundle(OutputPath)) + { + throw new Exception("Output path must be a .pkg or .app (zipped) file"); + } + + if (IsPkg(OutputPath)) + { + Package.Repack(); + } + else if (IsAppBundle(OutputPath)) + { + AppBundle.Repack(InputPath, OutputPath); + } + } + + internal static bool IsPkg(string path) => + Path.GetExtension(path).Equals(".pkg"); + + internal static bool IsAppBundle(string path) => + Path.GetExtension(path).Equals(".app"); + + internal static string? FindInPath(string name, string path, bool isDirectory, SearchOption searchOption = SearchOption.AllDirectories) + { + try + { + List results = isDirectory ? GetDirectories(path, name, searchOption).ToList() : GetFiles(path, name, searchOption).ToList(); + if (results.Count == 1) + { + return results[0]; + } + else if (results.Count > 1) + { + throw new Exception($"Multiple files found with name '{name}'"); + } + else + { + return null; + } + } + catch (Exception e) + { + throw new Exception($"Error finding file '{name}' in '{path}': {e.Message}"); + } + } + + internal static IEnumerable GetDirectories(string path, string pathFilter = "*", SearchOption searchOption = SearchOption.AllDirectories) => + Directory.EnumerateDirectories(path, pathFilter, searchOption); + + internal static IEnumerable GetFiles(string path, string pathFilter = "*", SearchOption searchOption = SearchOption.AllDirectories) => + Directory.EnumerateFiles(path, pathFilter, searchOption); + } +} diff --git a/src/Microsoft.DotNet.Pkg/Program.cs b/src/Microsoft.DotNet.Pkg/Program.cs new file mode 100644 index 00000000000..af34894f90f --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/Program.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.DotNet.Pkg; + +if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) +{ + Console.Error.WriteLine("This tool is only supported on macOS."); + return 1; +} + +if (args.Length != 3) +{ + Console.Error.WriteLine("Usage: "); + return 1; +} + +string srcPath = args[0]; +string dstPath = args[1]; +string op = args[2]; + +try +{ + Processor.Initialize(srcPath, dstPath); + + if (op == "unpack") + { + Processor.Unpack(); + } + else if(op == "repack") + { + Processor.Repack(); + } + else + { + Console.Error.WriteLine($"Invalid operation {op}."); + return 1; + } +} +catch (Exception e) +{ + Console.Error.Write(e.Message); + return 1; +} + +return 0; diff --git a/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj b/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj index f1601325a25..b106537a080 100644 --- a/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj +++ b/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj @@ -21,6 +21,14 @@ SkipGetTargetFrameworkProperties="true" Private="false" OutputItemType="_TarToolPath" /> + + @@ -47,4 +55,16 @@ + + + <_PkgToolPattern>@(_PkgToolPath->'%(RootDir)%(Directory)')**\*.* + + + <_PkgToolFiles Include="$(_PkgToolPattern)"/> + + + + + + From 3e8107689e1bf1167ac55e1d1be58be74de61fa8 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Thu, 31 Oct 2024 18:36:28 +0000 Subject: [PATCH 02/14] Remove tool from SignTool tests - will be added in https://github.com/dotnet/arcade/pull/15206 --- .../Microsoft.DotNet.SignTool.Tests.csproj | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj b/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj index b106537a080..f1601325a25 100644 --- a/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj +++ b/src/Microsoft.DotNet.SignTool.Tests/Microsoft.DotNet.SignTool.Tests.csproj @@ -21,14 +21,6 @@ SkipGetTargetFrameworkProperties="true" Private="false" OutputItemType="_TarToolPath" /> - - @@ -55,16 +47,4 @@ - - - <_PkgToolPattern>@(_PkgToolPath->'%(RootDir)%(Directory)')**\*.* - - - <_PkgToolFiles Include="$(_PkgToolPattern)"/> - - - - - - From 5d93e1fbdaa74900bb257be3a99f44ae1115e3b3 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 19:03:46 +0000 Subject: [PATCH 03/14] Rename repack to pack --- ...npackRepackTests.cs => UnpackPackTests.cs} | 108 +++++++++--------- src/Microsoft.DotNet.Pkg/AppBundle.cs | 2 +- src/Microsoft.DotNet.Pkg/Package.cs | 32 +++--- src/Microsoft.DotNet.Pkg/PackageBundle.cs | 6 +- src/Microsoft.DotNet.Pkg/Processor.cs | 6 +- src/Microsoft.DotNet.Pkg/Program.cs | 6 +- 6 files changed, 80 insertions(+), 80 deletions(-) rename src/Microsoft.DotNet.Pkg.Tests/{UnpackRepackTests.cs => UnpackPackTests.cs} (76%) diff --git a/src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs b/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs similarity index 76% rename from src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs rename to src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs index a0f39af4c70..ff783a77376 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/UnpackRepackTests.cs +++ b/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs @@ -12,10 +12,10 @@ namespace Microsoft.DotNet.Pkg.Tests { - public class UnpackRepackTests + public class UnpackPackTests { private static string pkgToolPath = Path.Combine( - Path.GetDirectoryName(typeof(UnpackRepackTests).Assembly.Location), + Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location), "tools", "pkg", "Microsoft.Dotnet.Pkg.dll"); @@ -69,23 +69,23 @@ public void UnpackSimplePkg() } [MacOSOnlyFact] - public void RepackSimplePkg() + public void PackSimplePkg() { string srcPath = GetResourceFilePath("Simple.pkg"); string dstPath = GetTempFilePath("SimplePkg"); - string repackPath = GetTempFilePath("RepackSimple.pkg"); + string packPath = GetTempFilePath("PackSimple.pkg"); try { // Unpack the package Unpack(srcPath, dstPath); - // Repack the package - Repack(dstPath, repackPath, simplePkgFiles); + // Pack the package + Pack(dstPath, packPath, simplePkgFiles); } finally { Directory.Delete(dstPath, true); - File.Delete(repackPath); + File.Delete(packPath); } } @@ -105,23 +105,23 @@ public void UnpackPkgWithApp() } [MacOSOnlyFact] - public void RepackPkgWithApp() + public void PackPkgWithApp() { string srcPath = GetResourceFilePath("WithApp.pkg"); string dstPath = GetTempFilePath("WithAppPkg"); - string repackPath = GetTempFilePath("RepackWithApp.pkg"); + string packPath = GetTempFilePath("PackWithApp.pkg"); try { // Unpack the package Unpack(srcPath, dstPath); - // Repack the package - Repack(dstPath, repackPath, withAppPkgFiles); + // Pack the package + Pack(dstPath, packPath, withAppPkgFiles); } finally { Directory.Delete(dstPath, true); - File.Delete(repackPath); + File.Delete(packPath); } } @@ -148,7 +148,7 @@ public void UnpackAppBundle() } [MacOSOnlyFact] - public void RepackAppBundle() + public void PackAppBundle() { string srcPath = GetResourceFilePath("WithApp.pkg"); string dstPath = GetTempFilePath("WithAppPkg"); @@ -162,8 +162,8 @@ public void RepackAppBundle() // Unpack the app bundle Unpack(appPath, appDstPath); - // Repack the app bundle - Repack(appDstPath, appPath, appFiles); + // Pack the app bundle + Pack(appDstPath, appPath, appFiles); } finally { @@ -188,23 +188,23 @@ public void UnpackSimpleInstaller() } [MacOSOnlyFact] - public void RepackSimpleInstaller() + public void PackSimpleInstaller() { string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); string dstPath = GetTempFilePath("SimpleInstallerPkg"); - string repackPath = GetTempFilePath("RepackSimpleInstaller.pkg"); + string packPath = GetTempFilePath("PackSimpleInstaller.pkg"); try { // Unpack the installer Unpack(srcPath, dstPath); - // Repack the installer - Repack(dstPath, repackPath, simpleInstallerFiles); + // Pack the installer + Pack(dstPath, packPath, simpleInstallerFiles); } finally { Directory.Delete(dstPath, true); - File.Delete(repackPath); + File.Delete(packPath); } } @@ -231,41 +231,41 @@ public void UnpackNestedInstaller() } [MacOSOnlyFact] - public void RepackNestedInstaller() + public void PackNestedInstaller() { string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); string dstPath = GetTempFilePath("SimpleInstallerPkg"); string simplePkgPath = Path.Combine(dstPath, "Simple.pkg"); string simplePkgDstPath = GetTempFilePath("SimplePkg"); - string repackPath = GetTempFilePath("RepackSimpleInstaller.pkg"); - string unpackRepackPath = GetTempFilePath("UnpackRepackSimpleInstallerPkg"); - string unpackRepackSimplePkgPath = Path.Combine(unpackRepackPath, "Simple.pkg"); - string unpackRepackSimplePkgDstPath = GetTempFilePath("UnpackRepackSimplePkg"); + string packPath = GetTempFilePath("PackSimpleInstaller.pkg"); + string unpackPackPath = GetTempFilePath("UnpackPackSimpleInstallerPkg"); + string unpackPackSimplePkgPath = Path.Combine(unpackPackPath, "Simple.pkg"); + string unpackPackSimplePkgDstPath = GetTempFilePath("UnpackPackSimplePkg"); try { // Unpack the installer Unpack(srcPath, dstPath); - // Unpack and repack the simple package + // Unpack and pack the simple package Unpack(simplePkgPath, simplePkgDstPath); - Repack(simplePkgDstPath, simplePkgPath); + Pack(simplePkgDstPath, simplePkgPath); - // Repack the installer - Repack(dstPath, repackPath, simpleInstallerFiles); + // Pack the installer + Pack(dstPath, packPath, simpleInstallerFiles); - // Unpack the repacked simple pkg inside to compare the content - Unpack(repackPath, unpackRepackPath); - Unpack(unpackRepackSimplePkgPath, unpackRepackSimplePkgDstPath, simplePkgFiles); + // Unpack the packed simple pkg inside to compare the content + Unpack(packPath, unpackPackPath); + Unpack(unpackPackSimplePkgPath, unpackPackSimplePkgDstPath, simplePkgFiles); } finally { - File.Delete(repackPath); + File.Delete(packPath); File.Delete(simplePkgPath); Directory.Delete(dstPath, true); Directory.Delete(simplePkgDstPath, true); - Directory.Delete(unpackRepackPath, true); - Directory.Delete(unpackRepackSimplePkgDstPath, true); + Directory.Delete(unpackPackPath, true); + Directory.Delete(unpackPackSimplePkgDstPath, true); } } @@ -292,41 +292,41 @@ public void UnpackNestedInstallerWithApp() } [MacOSOnlyFact] - public void RepackNestedInstallerWithApp() + public void PackNestedInstallerWithApp() { string srcPath = GetResourceFilePath("WithAppInstaller.pkg"); string dstPath = GetTempFilePath("WithAppInstallerPkg"); string withAppPkgPath = Path.Combine(dstPath, "WithApp.pkg"); string withAppPkgDstPath = GetTempFilePath("WithAppPkg"); - string repackPath = GetTempFilePath("RepackWithAppInstaller.pkg"); - string unpackRepackPath = GetTempFilePath("UnpackRepackWithAppInstallerPkg"); - string unpackRepackWithAppPkgPath = Path.Combine(unpackRepackPath, "WithApp.pkg"); - string unpackRepackWithAppPkgDstPath = GetTempFilePath("UnpackRepackWithAppPkg"); + string packPath = GetTempFilePath("PackWithAppInstaller.pkg"); + string unpackPackPath = GetTempFilePath("UnpackPackWithAppInstallerPkg"); + string unpackPackWithAppPkgPath = Path.Combine(unpackPackPath, "WithApp.pkg"); + string unpackPackWithAppPkgDstPath = GetTempFilePath("UnpackPackWithAppPkg"); try { // Unpack the installer Unpack(srcPath, dstPath); - // Unpack and repack the app package + // Unpack and pack the app package Unpack(withAppPkgPath, withAppPkgDstPath); - Repack(withAppPkgDstPath, withAppPkgPath); + Pack(withAppPkgDstPath, withAppPkgPath); - // Repack the installer - Repack(dstPath, repackPath, withAppInstallerFiles); + // Pack the installer + Pack(dstPath, packPath, withAppInstallerFiles); - // Unpack the repacked app pkg inside to compare the content - Unpack(repackPath, unpackRepackPath); - Unpack(unpackRepackWithAppPkgPath, unpackRepackWithAppPkgDstPath, withAppPkgFiles); + // Unpack the packed app pkg inside to compare the content + Unpack(packPath, unpackPackPath); + Unpack(unpackPackWithAppPkgPath, unpackPackWithAppPkgDstPath, withAppPkgFiles); } finally { - File.Delete(repackPath); + File.Delete(packPath); File.Delete(withAppPkgPath); Directory.Delete(dstPath, true); Directory.Delete(withAppPkgDstPath, true); - Directory.Delete(unpackRepackPath, true); - Directory.Delete(unpackRepackWithAppPkgDstPath, true); + Directory.Delete(unpackPackPath, true); + Directory.Delete(unpackPackWithAppPkgDstPath, true); } } @@ -343,16 +343,16 @@ private static void Unpack(string inputPath, string outputPath, string[] expecte } } - private static void Repack(string inputPath, string outputPath, string[] expectedFiles = null) + private static void Pack(string inputPath, string outputPath, string[] expectedFiles = null) { - bool success = RunPkgProcess(inputPath, outputPath, "repack"); + bool success = RunPkgProcess(inputPath, outputPath, "pack"); success.Should().BeTrue(); File.Exists(outputPath).Should().BeTrue(); if (expectedFiles != null) { - string tempPath = GetTempFilePath($"UnpackRepack{Path.GetFileNameWithoutExtension(inputPath)}"); + string tempPath = GetTempFilePath($"UnpackPack{Path.GetFileNameWithoutExtension(inputPath)}"); RunPkgProcess(outputPath, tempPath, "unpack").Should().BeTrue(); Directory.Exists(tempPath).Should().BeTrue(); @@ -384,7 +384,7 @@ private static bool RunPkgProcess(string inputPath, string outputPath, string ac private static string GetResourceFilePath(string resourceName) { return Path.Combine( - Path.GetDirectoryName(typeof(UnpackRepackTests).Assembly.Location), + Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location), "Resources", resourceName); } diff --git a/src/Microsoft.DotNet.Pkg/AppBundle.cs b/src/Microsoft.DotNet.Pkg/AppBundle.cs index 6500cb18ada..de7f25ddde8 100644 --- a/src/Microsoft.DotNet.Pkg/AppBundle.cs +++ b/src/Microsoft.DotNet.Pkg/AppBundle.cs @@ -22,7 +22,7 @@ internal static void Unpack(string inputPath, string outputPath) ExecuteHelper.Run("ditto", args); } - internal static void Repack(string inputPath, string outputPath) + internal static void Pack(string inputPath, string outputPath) { string args = $"-c -k --sequesterRsrc {inputPath} {outputPath}"; ExecuteHelper.Run("ditto", args); diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.Pkg/Package.cs index 7509f3c3c86..b67fd05e6e3 100644 --- a/src/Microsoft.DotNet.Pkg/Package.cs +++ b/src/Microsoft.DotNet.Pkg/Package.cs @@ -25,22 +25,22 @@ internal static class Package private static List Bundles = new List(); internal static void Unpack() => - ProcessPackage(repacking: false); + ProcessPackage(packing: false); - internal static void Repack() => - ProcessPackage(repacking: true); + internal static void Pack() => + ProcessPackage(packing: true); - private static void ProcessPackage(bool repacking) + private static void ProcessPackage(bool packing) { - NameWithExtension = repacking ? Path.GetFileName(Processor.OutputPath) : Path.GetFileName(Processor.InputPath); - LocalExtractionPath = repacking ? Processor.InputPath : Processor.OutputPath; + NameWithExtension = packing ? Path.GetFileName(Processor.OutputPath) : Path.GetFileName(Processor.InputPath); + LocalExtractionPath = packing ? Processor.InputPath : Processor.OutputPath; if (!Processor.IsPkg(NameWithExtension)) { throw new Exception($"Package '{NameWithExtension}' is not a .pkg file"); } - if (!repacking) + if (!packing) { ExpandPkg(); } @@ -61,21 +61,21 @@ private static void ProcessPackage(bool repacking) Identifier = GetId(pkgBundles[0]); foreach (var pkgBundle in pkgBundles) { - ProcessBundle(pkgBundle, isNested: true, repacking: repacking); + ProcessBundle(pkgBundle, isNested: true, packing: packing); } - if (repacking) + if (packing) { - RepackPkg(); + PackPkg(); } } else if (!string.IsNullOrEmpty(packageInfo)) { // This is a single bundle package XElement pkgBundle = XElement.Load(packageInfo); - ProcessBundle(pkgBundle, isNested: false, repacking: repacking); + ProcessBundle(pkgBundle, isNested: false, packing: packing); } - else if (repacking) + else if (packing) { throw new Exception("Cannot unpack: no Distribution or PackageInfo file found in package"); } @@ -91,7 +91,7 @@ private static void ExpandPkg() ExecuteHelper.Run("pkgutil", $"--expand {Processor.InputPath} {LocalExtractionPath}"); } - private static void RepackPkg() + private static void PackPkg() { string args = string.Empty; args += $"--distribution {Distribution}"; @@ -121,20 +121,20 @@ private static void RepackPkg() ExecuteHelper.Run("productbuild", args); } - private static void ProcessBundle(XElement bundleInfo, bool isNested, bool repacking) + private static void ProcessBundle(XElement bundleInfo, bool isNested, bool packing) { string extractionPath = isNested ? Path.Combine(LocalExtractionPath, bundleInfo.Value.Substring(1)) : LocalExtractionPath; string version = bundleInfo.Attribute("version")?.Value ?? throw new Exception($"No version found in bundle file {NameWithExtension}"); string id = GetId(bundleInfo); PackageBundle bundle = new PackageBundle(extractionPath, id, version, NameWithExtension, isNested); - if (!repacking) + if (!packing) { bundle.Unpack(); } else { - bundle.Repack(); + bundle.Pack(); } if (isNested) diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs index 47ca0056edc..056952b04ac 100644 --- a/src/Microsoft.DotNet.Pkg/PackageBundle.cs +++ b/src/Microsoft.DotNet.Pkg/PackageBundle.cs @@ -49,7 +49,7 @@ internal void Unpack() { // The nested bundles get unpacked into a directory with a .pkg extension by `pkgutil --expand`, // so we remove this extension when unpacking the bundle. - // Otherwise, there will be problems when repacking the bundle due to the naming conflict + // Otherwise, there will be problems when packing the bundle due to the naming conflict Directory.Move(LocalExtractionPath + ".pkg", LocalExtractionPath); } @@ -68,7 +68,7 @@ internal void Unpack() foreach (string app in nestedApps) { string tempDest = $"{app}.zip"; - AppBundle.Repack(app, tempDest); + AppBundle.Pack(app, tempDest); Directory.Delete(app, true); // Rename the zipped file to .app @@ -86,7 +86,7 @@ internal void Unpack() } } - internal void Repack() + internal void Pack() { if (!IsNested) { diff --git a/src/Microsoft.DotNet.Pkg/Processor.cs b/src/Microsoft.DotNet.Pkg/Processor.cs index 9b1653218a4..8d86e460aed 100644 --- a/src/Microsoft.DotNet.Pkg/Processor.cs +++ b/src/Microsoft.DotNet.Pkg/Processor.cs @@ -53,7 +53,7 @@ public static void Unpack() } } - public static void Repack() + public static void Pack() { if (!Directory.Exists(InputPath)) { @@ -67,11 +67,11 @@ public static void Repack() if (IsPkg(OutputPath)) { - Package.Repack(); + Package.Pack(); } else if (IsAppBundle(OutputPath)) { - AppBundle.Repack(InputPath, OutputPath); + AppBundle.Pack(InputPath, OutputPath); } } diff --git a/src/Microsoft.DotNet.Pkg/Program.cs b/src/Microsoft.DotNet.Pkg/Program.cs index af34894f90f..5cd245436fd 100644 --- a/src/Microsoft.DotNet.Pkg/Program.cs +++ b/src/Microsoft.DotNet.Pkg/Program.cs @@ -17,7 +17,7 @@ if (args.Length != 3) { - Console.Error.WriteLine("Usage: "); + Console.Error.WriteLine("Usage: "); return 1; } @@ -33,9 +33,9 @@ { Processor.Unpack(); } - else if(op == "repack") + else if(op == "pack") { - Processor.Repack(); + Processor.Pack(); } else { From 38aba811942fb9205488453deef227c444e44299 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 18:48:15 +0000 Subject: [PATCH 04/14] Move nullable to csproj and remove unnecessary usings --- .../Microsoft.DotNet.Pkg.Tests.csproj | 1 + src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs | 2 -- src/Microsoft.DotNet.Pkg/AppBundle.cs | 11 ----------- src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj | 1 + src/Microsoft.DotNet.Pkg/Package.cs | 7 ------- src/Microsoft.DotNet.Pkg/PackageBundle.cs | 7 ------- src/Microsoft.DotNet.Pkg/Processor.cs | 6 ------ src/Microsoft.DotNet.Pkg/Program.cs | 3 --- 8 files changed, 2 insertions(+), 36 deletions(-) diff --git a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj b/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj index a9be32a8622..1ea0bc20752 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj +++ b/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj @@ -2,6 +2,7 @@ $(NetToolCurrent);$(NetFrameworkToolCurrent) + enable diff --git a/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs b/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs index ff783a77376..6a95adb4b42 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs +++ b/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs @@ -4,10 +4,8 @@ using System; using System.IO; using System.Linq; -using System.Collections.Generic; using System.Diagnostics; using Xunit; -using Xunit.Abstractions; using FluentAssertions; namespace Microsoft.DotNet.Pkg.Tests diff --git a/src/Microsoft.DotNet.Pkg/AppBundle.cs b/src/Microsoft.DotNet.Pkg/AppBundle.cs index de7f25ddde8..f46ce9e6288 100644 --- a/src/Microsoft.DotNet.Pkg/AppBundle.cs +++ b/src/Microsoft.DotNet.Pkg/AppBundle.cs @@ -1,17 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using System.Xml.Linq; - -#nullable enable - namespace Microsoft.DotNet.Pkg { internal static class AppBundle diff --git a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj b/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj index add01a1dbd8..1ce09bd3a04 100644 --- a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj +++ b/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj @@ -4,6 +4,7 @@ $(NetToolCurrent);$(NetFrameworkToolCurrent) Exe true + enable true Pkg Arcade Build Tool Pkg diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.Pkg/Package.cs index b67fd05e6e3..983d74bcee7 100644 --- a/src/Microsoft.DotNet.Pkg/Package.cs +++ b/src/Microsoft.DotNet.Pkg/Package.cs @@ -2,23 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Collections.Generic; using System.Linq; -using System.Xml; using System.Xml.Linq; -#nullable enable - namespace Microsoft.DotNet.Pkg { internal static class Package { private static string NameWithExtension = string.Empty; private static string LocalExtractionPath = string.Empty; - private static string? Identifier = null; private static string? Resources = null; private static string? Distribution = null; private static string? Scripts = null; @@ -58,7 +52,6 @@ private static void ProcessPackage(bool packing) { throw new Exception("No pkg-ref elements found in Distribution file"); } - Identifier = GetId(pkgBundles[0]); foreach (var pkgBundle in pkgBundles) { ProcessBundle(pkgBundle, isNested: true, packing: packing); diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs index 056952b04ac..2d1a749e1f3 100644 --- a/src/Microsoft.DotNet.Pkg/PackageBundle.cs +++ b/src/Microsoft.DotNet.Pkg/PackageBundle.cs @@ -2,15 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Collections.Generic; -using System.Linq; -using System.Xml; -using System.Xml.Linq; - -#nullable enable namespace Microsoft.DotNet.Pkg { diff --git a/src/Microsoft.DotNet.Pkg/Processor.cs b/src/Microsoft.DotNet.Pkg/Processor.cs index 8d86e460aed..efebf2c0f16 100644 --- a/src/Microsoft.DotNet.Pkg/Processor.cs +++ b/src/Microsoft.DotNet.Pkg/Processor.cs @@ -2,15 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Collections.Generic; using System.Linq; -using System.Xml; -using System.Xml.Linq; - -#nullable enable namespace Microsoft.DotNet.Pkg { diff --git a/src/Microsoft.DotNet.Pkg/Program.cs b/src/Microsoft.DotNet.Pkg/Program.cs index 5cd245436fd..583fea33a6c 100644 --- a/src/Microsoft.DotNet.Pkg/Program.cs +++ b/src/Microsoft.DotNet.Pkg/Program.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.IO; -using System.IO.Compression; -using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.DotNet.Pkg; From 1715646ab5a2851c5798f4741b8ef68fb26ea39c Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 18:48:15 +0000 Subject: [PATCH 05/14] Fixup execute helper --- src/Microsoft.DotNet.Pkg/ExecuteHelper.cs | 24 +++++++++++++++++------ src/Microsoft.DotNet.Pkg/PackageBundle.cs | 6 +----- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs b/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs index aa18f5a0f3f..6aba009199f 100644 --- a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs +++ b/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs @@ -3,39 +3,51 @@ using System; using System.Diagnostics; +using System.IO; namespace Microsoft.DotNet.Pkg { public static class ExecuteHelper { - public static string Run(string command, string arguments = "") + public static string Run(string command, string arguments = "", string? workingDirectory = null) { if (string.IsNullOrEmpty(command)) { throw new ArgumentNullException(nameof(command)); } + if (string.IsNullOrEmpty(workingDirectory)) + { + workingDirectory = Processor.WorkingDirectory; + } + string output = string.Empty; + string escapedArgs = $"-c \"{command} {arguments}\""; - ProcessStartInfo processStartInfo = CreateProcessStartInfo(command, arguments); + ProcessStartInfo processStartInfo = CreateProcessStartInfo("sh", escapedArgs, workingDirectory); using (Process process = new Process { StartInfo = processStartInfo }) { process.Start(); output = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); + process.WaitForExit(60000); // 60 seconds + if (process.ExitCode != 0) + { + throw new Exception($"Command '{command} {arguments}' failed with exit code {process.ExitCode}: {process.StandardError.ReadToEnd()}"); + } } return output; } - private static ProcessStartInfo CreateProcessStartInfo(string command, string arguments) => + private static ProcessStartInfo CreateProcessStartInfo(string command, string arguments, string? workingDirectory) => new ProcessStartInfo { FileName = command, - Arguments = arguments, + Arguments = $@"{arguments}", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, - CreateNoWindow = true + CreateNoWindow = true, + WorkingDirectory = workingDirectory }; } } diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs index 2d1a749e1f3..a37c85ff852 100644 --- a/src/Microsoft.DotNet.Pkg/PackageBundle.cs +++ b/src/Microsoft.DotNet.Pkg/PackageBundle.cs @@ -148,18 +148,14 @@ private void UnpackPayloadFile(string payloadFilePath) Directory.CreateDirectory(tempDir); try { - Directory.SetCurrentDirectory(tempDir); - // While we're shelling out to an executable named 'tar', the "Payload" file from pkgs is not actually // a tar file. It's secretly a 'pbzx' file that tar on OSX has been taught to unpack. // As such, while there is actually untarring / re-tarring in this file using Python libraries, we have to // shell out to the host machine to do this. - ExecuteHelper.Run("tar", $"-xf {payloadFilePath}"); + ExecuteHelper.Run("tar", $"-xf {payloadFilePath}", tempDir); } finally { - Directory.SetCurrentDirectory(Processor.WorkingDirectory); - // Remove the payload file and replace it with // a directory of the same name containing the unpacked contents File.Delete(payloadFilePath); From 694c8cee51b9f19e7946be57aff08b367436eedf Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 19:41:56 +0000 Subject: [PATCH 06/14] Remove processor and create utilities --- src/Microsoft.DotNet.Pkg/ExecuteHelper.cs | 2 +- src/Microsoft.DotNet.Pkg/Package.cs | 44 ++++----- src/Microsoft.DotNet.Pkg/PackageBundle.cs | 26 +++--- src/Microsoft.DotNet.Pkg/Processor.cs | 108 ---------------------- src/Microsoft.DotNet.Pkg/Program.cs | 46 ++++++++- src/Microsoft.DotNet.Pkg/Utilities.cs | 44 +++++++++ 6 files changed, 122 insertions(+), 148 deletions(-) delete mode 100644 src/Microsoft.DotNet.Pkg/Processor.cs create mode 100644 src/Microsoft.DotNet.Pkg/Utilities.cs diff --git a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs b/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs index 6aba009199f..67f1e1ea93b 100644 --- a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs +++ b/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs @@ -18,7 +18,7 @@ public static string Run(string command, string arguments = "", string? workingD if (string.IsNullOrEmpty(workingDirectory)) { - workingDirectory = Processor.WorkingDirectory; + workingDirectory = Directory.GetCurrentDirectory(); } string output = string.Empty; diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.Pkg/Package.cs index 983d74bcee7..e24b4e70344 100644 --- a/src/Microsoft.DotNet.Pkg/Package.cs +++ b/src/Microsoft.DotNet.Pkg/Package.cs @@ -18,31 +18,31 @@ internal static class Package private static string? Scripts = null; private static List Bundles = new List(); - internal static void Unpack() => - ProcessPackage(packing: false); + internal static void Unpack(string srcPath, string dstPath) => + ProcessPackage(string srcPath, string dstPath, packing: false); - internal static void Pack() => - ProcessPackage(packing: true); + internal static void Pack(string srcPath, string dstPath) => + ProcessPackage(srcPath, dstPath, packing: true); - private static void ProcessPackage(bool packing) + private static void ProcessPackage(string srcPath, string dstPath, bool packing) { - NameWithExtension = packing ? Path.GetFileName(Processor.OutputPath) : Path.GetFileName(Processor.InputPath); - LocalExtractionPath = packing ? Processor.InputPath : Processor.OutputPath; + NameWithExtension = packing ? Path.GetFileName(dstPath) : Path.GetFileName(srcPath); + LocalExtractionPath = packing ? srcPath : dstPath; - if (!Processor.IsPkg(NameWithExtension)) + if (!Utilities.IsPkg(NameWithExtension)) { throw new Exception($"Package '{NameWithExtension}' is not a .pkg file"); } if (!packing) { - ExpandPkg(); + ExpandPkg(srcPath); } - Resources = Processor.FindInPath("Resources", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - Distribution = Processor.FindInPath("Distribution", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); - Scripts = Processor.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - string? packageInfo = Processor.FindInPath("PackageInfo", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + Resources = Utilities.FindInPath("Resources", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Distribution = Utilities.FindInPath("Distribution", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + Scripts = Utilities.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + string? packageInfo = Utilities.FindInPath("PackageInfo", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); if (!string.IsNullOrEmpty(Distribution)) { @@ -59,14 +59,14 @@ private static void ProcessPackage(bool packing) if (packing) { - PackPkg(); + PackPkg(dstPath); } } else if (!string.IsNullOrEmpty(packageInfo)) { // This is a single bundle package XElement pkgBundle = XElement.Load(packageInfo); - ProcessBundle(pkgBundle, isNested: false, packing: packing); + ProcessBundle(pkgBundle, isNested: false, packing: packing, dstPath); } else if (packing) { @@ -74,17 +74,17 @@ private static void ProcessPackage(bool packing) } } - private static void ExpandPkg() + private static void ExpandPkg(string srcPath) { if (Directory.Exists(LocalExtractionPath)) { Directory.Delete(LocalExtractionPath, true); } - ExecuteHelper.Run("pkgutil", $"--expand {Processor.InputPath} {LocalExtractionPath}"); + ExecuteHelper.Run("pkgutil", $"--expand {srcPath} {LocalExtractionPath}"); } - private static void PackPkg() + private static void PackPkg(string dstPath) { string args = string.Empty; args += $"--distribution {Distribution}"; @@ -105,11 +105,11 @@ private static void PackPkg() args += $" --root {LocalExtractionPath}"; } - if (File.Exists(Processor.OutputPath)) + if (File.Exists(dstPath)) { - File.Delete(Processor.OutputPath); + File.Delete(dstPath); } - args += $" {Processor.OutputPath}"; + args += $" {dstPath}"; ExecuteHelper.Run("productbuild", args); } @@ -127,7 +127,7 @@ private static void ProcessBundle(XElement bundleInfo, bool isNested, bool packi } else { - bundle.Pack(); + bundle.Pack(dstPath); } if (isNested) diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs index a37c85ff852..b5f177c464c 100644 --- a/src/Microsoft.DotNet.Pkg/PackageBundle.cs +++ b/src/Microsoft.DotNet.Pkg/PackageBundle.cs @@ -30,7 +30,7 @@ internal PackageBundle(string localExtractionPath, string identifier, string ver LocalExtractionPath = Path.Combine(Path.GetDirectoryName(localExtractionPath) ?? string.Empty, Path.GetFileNameWithoutExtension(NameWithExtension)); } - if (!Processor.IsPkg(NameWithExtension)) + if (!Utilities.IsPkg(NameWithExtension)) { throw new Exception($"Bundle '{NameWithExtension}' is not a .pkg file"); } @@ -46,8 +46,8 @@ internal void Unpack() Directory.Move(LocalExtractionPath + ".pkg", LocalExtractionPath); } - Scripts = Processor.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - Payload = Processor.FindInPath("Payload", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + Scripts = Utilities.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Payload = Utilities.FindInPath("Payload", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); if (!string.IsNullOrEmpty(Payload)) { @@ -57,7 +57,7 @@ internal void Unpack() if (!IsNested) { // Zip the nested app bundles - IEnumerable nestedApps = Processor.GetDirectories(LocalExtractionPath, "*.app", SearchOption.AllDirectories); + IEnumerable nestedApps = Utilities.GetDirectories(LocalExtractionPath, "*.app", SearchOption.AllDirectories); foreach (string app in nestedApps) { string tempDest = $"{app}.zip"; @@ -79,14 +79,14 @@ internal void Unpack() } } - internal void Pack() + internal void Pack(string dstPath) { if (!IsNested) { - Scripts = Processor.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - Payload = Processor.FindInPath("Payload", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Scripts = Utilities.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + Payload = Utilities.FindInPath("Payload", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - IEnumerable zippedNestedApps = Processor.GetFiles(LocalExtractionPath, "*.app", SearchOption.AllDirectories); + IEnumerable zippedNestedApps = Directory.GetFiles(LocalExtractionPath, "*.app", SearchOption.AllDirectories); foreach (string appZip in zippedNestedApps) { // Unzip the .app directory @@ -99,11 +99,11 @@ internal void Pack() Directory.Move(tempDest, appZip); } - PkgBuild(); + PkgBuild(dstPath); } } - private void PkgBuild() + private void PkgBuild(string dstPath = "") { string info = GenerateInfoPlist(); string root = string.IsNullOrEmpty(Payload) ? $"{LocalExtractionPath}" : $"{Payload}"; @@ -116,7 +116,7 @@ private void PkgBuild() string outputPath = $"{LocalExtractionPath}.pkg"; if (!IsNested) { - outputPath = Processor.OutputPath; + outputPath = dstPath; if (File.Exists(outputPath)) { File.Delete(outputPath); @@ -132,7 +132,7 @@ private void PkgBuild() private string GenerateInfoPlist() { string root = string.IsNullOrEmpty(Payload) ? $"{LocalExtractionPath}" : $"{Payload}"; - string info = Path.Combine(Processor.WorkingDirectory, "Info.plist"); + string info = Path.Combine(Directory.GetCurrentDirectory(), "Info.plist"); ExecuteHelper.Run("pkgbuild", $"--analyze --root {root} {info}"); return info; } @@ -144,7 +144,7 @@ private void UnpackPayloadFile(string payloadFilePath) throw new Exception($"Cannot unpack invalid 'Payload' file in {NameWithExtension}"); } - string tempDir = Path.Combine(Processor.WorkingDirectory, "tempPayloadUnpackingDir"); + string tempDir = Path.Combine(Directory.GetCurrentDirectory(), "tempPayloadUnpackingDir"); Directory.CreateDirectory(tempDir); try { diff --git a/src/Microsoft.DotNet.Pkg/Processor.cs b/src/Microsoft.DotNet.Pkg/Processor.cs deleted file mode 100644 index efebf2c0f16..00000000000 --- a/src/Microsoft.DotNet.Pkg/Processor.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.DotNet.Pkg -{ - public static class Processor - { - internal static string WorkingDirectory = Directory.GetCurrentDirectory(); - internal static string InputPath = string.Empty; - internal static string OutputPath = string.Empty; - - public static void Initialize(string inputPath, string outputPath = "") - { - InputPath = inputPath; - OutputPath = outputPath; - } - - public static void Unpack() - { - if (!File.Exists(InputPath)) - { - throw new Exception("Input path must be a valid file"); - } - - if (!IsPkg(InputPath) && !IsAppBundle(InputPath)) - { - throw new Exception("Input path must be a .pkg or .app (zipped) file"); - } - - if (!Directory.Exists(OutputPath)) - { - Directory.CreateDirectory(OutputPath); - } - - if (IsPkg(InputPath)) - { - Package.Unpack(); - } - else if (IsAppBundle(InputPath)) - { - AppBundle.Unpack(InputPath, OutputPath); - } - } - - public static void Pack() - { - if (!Directory.Exists(InputPath)) - { - throw new Exception("Input path must be a valid directory"); - } - - if (!IsPkg(OutputPath) && !IsAppBundle(OutputPath)) - { - throw new Exception("Output path must be a .pkg or .app (zipped) file"); - } - - if (IsPkg(OutputPath)) - { - Package.Pack(); - } - else if (IsAppBundle(OutputPath)) - { - AppBundle.Pack(InputPath, OutputPath); - } - } - - internal static bool IsPkg(string path) => - Path.GetExtension(path).Equals(".pkg"); - - internal static bool IsAppBundle(string path) => - Path.GetExtension(path).Equals(".app"); - - internal static string? FindInPath(string name, string path, bool isDirectory, SearchOption searchOption = SearchOption.AllDirectories) - { - try - { - List results = isDirectory ? GetDirectories(path, name, searchOption).ToList() : GetFiles(path, name, searchOption).ToList(); - if (results.Count == 1) - { - return results[0]; - } - else if (results.Count > 1) - { - throw new Exception($"Multiple files found with name '{name}'"); - } - else - { - return null; - } - } - catch (Exception e) - { - throw new Exception($"Error finding file '{name}' in '{path}': {e.Message}"); - } - } - - internal static IEnumerable GetDirectories(string path, string pathFilter = "*", SearchOption searchOption = SearchOption.AllDirectories) => - Directory.EnumerateDirectories(path, pathFilter, searchOption); - - internal static IEnumerable GetFiles(string path, string pathFilter = "*", SearchOption searchOption = SearchOption.AllDirectories) => - Directory.EnumerateFiles(path, pathFilter, searchOption); - } -} diff --git a/src/Microsoft.DotNet.Pkg/Program.cs b/src/Microsoft.DotNet.Pkg/Program.cs index 583fea33a6c..5b5c0f600b4 100644 --- a/src/Microsoft.DotNet.Pkg/Program.cs +++ b/src/Microsoft.DotNet.Pkg/Program.cs @@ -24,15 +24,53 @@ try { - Processor.Initialize(srcPath, dstPath); - if (op == "unpack") { - Processor.Unpack(); + if (!File.Exists(srcPath)) + { + throw new Exception("Input path must be a valid file"); + } + + if (!Utilities.IsPkg(srcPath) && !Utilities.IsAppBundle(srcPath)) + { + throw new Exception("Input path must be a .pkg or .app (zipped) file"); + } + + Utilities.CleanupPath(dstPath); + Utilities.CreateParentDirectory(dstPath); + + if (Utilities.IsPkg(srcPath)) + { + Package.Unpack(srcPath, dstPath); + } + else if (Utilities.IsAppBundle(srcPath)) + { + AppBundle.Unpack(srcPath, dstPath); + } } else if(op == "pack") { - Processor.Pack(); + if (!Directory.Exists(srcPath)) + { + throw new Exception("Input path must be a valid directory"); + } + + if (!Utilities.IsPkg(dstPath) && !Utilities.IsAppBundle(dstPath)) + { + throw new Exception("Output path must be a .pkg or .app (zipped) file"); + } + + Utilities.CleanupPath(dstPath); + Utilities.CreateParentDirectory(dstPath); + + if (Utilities.IsPkg(dstPath)) + { + Package.Pack(srcPath, dstPath); + } + else if (Utilities.IsAppBundle(dstPath)) + { + AppBundle.Pack(srcPath, dstPath); + } } else { diff --git a/src/Microsoft.DotNet.Pkg/Utilities.cs b/src/Microsoft.DotNet.Pkg/Utilities.cs new file mode 100644 index 00000000000..7897d220589 --- /dev/null +++ b/src/Microsoft.DotNet.Pkg/Utilities.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Linq; + +namespace Microsoft.DotNet.Pkg +{ + public static class Utilities + { + internal static bool IsPkg(string path) => + Path.GetExtension(path).Equals(".pkg"); + + internal static bool IsAppBundle(string path) => + Path.GetExtension(path).Equals(".app"); + + internal static string? FindInPath(string name, string path, bool isDirectory, SearchOption searchOption = SearchOption.AllDirectories) + { + string[] results = isDirectory ? Directory.GetDirectories(path, name, searchOption) : Directory.GetFiles(path, name, searchOption); + return results.FirstOrDefault(); + } + + internal static void CleanupPath(string path) + { + if (Directory.Exists(path)) + { + Directory.Delete(path, true); + } + else if (File.Exists(path)) + { + File.Delete(path); + } + } + + internal static void CreateParentDirectory(string path) + { + string? parent = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(parent)) + { + Directory.CreateDirectory(parent); + } + } + } +} From c439e47121edd9851cf7d334ed820ca56231459e Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 18:48:15 +0000 Subject: [PATCH 07/14] Remove fields --- src/Microsoft.DotNet.Pkg/Package.cs | 94 ++++++----------------- src/Microsoft.DotNet.Pkg/PackageBundle.cs | 81 ++++++------------- 2 files changed, 50 insertions(+), 125 deletions(-) diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.Pkg/Package.cs index e24b4e70344..0f391105a1c 100644 --- a/src/Microsoft.DotNet.Pkg/Package.cs +++ b/src/Microsoft.DotNet.Pkg/Package.cs @@ -11,13 +11,6 @@ namespace Microsoft.DotNet.Pkg { internal static class Package { - private static string NameWithExtension = string.Empty; - private static string LocalExtractionPath = string.Empty; - private static string? Resources = null; - private static string? Distribution = null; - private static string? Scripts = null; - private static List Bundles = new List(); - internal static void Unpack(string srcPath, string dstPath) => ProcessPackage(string srcPath, string dstPath, packing: false); @@ -26,27 +19,22 @@ internal static void Pack(string srcPath, string dstPath) => private static void ProcessPackage(string srcPath, string dstPath, bool packing) { - NameWithExtension = packing ? Path.GetFileName(dstPath) : Path.GetFileName(srcPath); - LocalExtractionPath = packing ? srcPath : dstPath; - - if (!Utilities.IsPkg(NameWithExtension)) - { - throw new Exception($"Package '{NameWithExtension}' is not a .pkg file"); - } + string nameWithExtension = packing ? Path.GetFileName(dstPath) : Path.GetFileName(srcPath); + string localExtractionPath = packing ? srcPath : dstPath; if (!packing) { - ExpandPkg(srcPath); + ExpandPkg(srcPath, dstPath); } - Resources = Utilities.FindInPath("Resources", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - Distribution = Utilities.FindInPath("Distribution", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); - Scripts = Utilities.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - string? packageInfo = Utilities.FindInPath("PackageInfo", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + string? resources = Utilities.FindInPath("Resources", localExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + string? distribution = Utilities.FindInPath("Distribution", localExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + string? scripts = Utilities.FindInPath("Scripts", localExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + string? packageInfo = Utilities.FindInPath("PackageInfo", localExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); - if (!string.IsNullOrEmpty(Distribution)) + if (!string.IsNullOrEmpty(distribution)) { - var xml = XElement.Load(Distribution); + var xml = XElement.Load(distribution); List pkgBundles = xml.Elements("pkg-ref").Where(e => e.Value.Trim() != "").ToList(); if (!pkgBundles.Any()) { @@ -59,7 +47,7 @@ private static void ProcessPackage(string srcPath, string dstPath, bool packing) if (packing) { - PackPkg(dstPath); + PackPkg(srcPath, dstPath, distribution, resources, scripts); } } else if (!string.IsNullOrEmpty(packageInfo)) @@ -74,35 +62,20 @@ private static void ProcessPackage(string srcPath, string dstPath, bool packing) } } - private static void ExpandPkg(string srcPath) - { - if (Directory.Exists(LocalExtractionPath)) - { - Directory.Delete(LocalExtractionPath, true); - } - - ExecuteHelper.Run("pkgutil", $"--expand {srcPath} {LocalExtractionPath}"); - } + private static void ExpandPkg(string srcPath, string dstPath) => + ExecuteHelper.Run("pkgutil", $"--expand {srcPath} {dstPath}"); - private static void PackPkg(string dstPath) + private static void PackPkg(string srcPath, string dstPath, string distribution, string? resources, string? scripts) { - string args = string.Empty; - args += $"--distribution {Distribution}"; - if (Bundles.Any()) - { - args += $" --package-path {LocalExtractionPath}"; - } - if (!string.IsNullOrEmpty(Resources)) - { - args += $" --resources {Resources}"; - } - if (!string.IsNullOrEmpty(Scripts)) + string args = $"--distribution {distribution} --package-path {srcPath}"; + + if (!string.IsNullOrEmpty(resources)) { - args += $" --scripts {Scripts}"; + args += $" --resources {resources}"; } - if (args.Length == 0) + if (!string.IsNullOrEmpty(scripts)) { - args += $" --root {LocalExtractionPath}"; + args += $" --scripts {scripts}"; } if (File.Exists(dstPath)) @@ -114,36 +87,19 @@ private static void PackPkg(string dstPath) ExecuteHelper.Run("productbuild", args); } - private static void ProcessBundle(XElement bundleInfo, bool isNested, bool packing) + private static void ProcessBundle(XElement bundleInfo, string localExtractionPath, string nameWithExtension, bool isNested, bool packing) { - string extractionPath = isNested ? Path.Combine(LocalExtractionPath, bundleInfo.Value.Substring(1)) : LocalExtractionPath; - string version = bundleInfo.Attribute("version")?.Value ?? throw new Exception($"No version found in bundle file {NameWithExtension}"); - string id = GetId(bundleInfo); - PackageBundle bundle = new PackageBundle(extractionPath, id, version, NameWithExtension, isNested); - + string extractionPath = isNested ? Path.Combine(localExtractionPath, bundleInfo.Value.Substring(1)) : localExtractionPath; if (!packing) { - bundle.Unpack(); + bundle.Unpack(extractionPath, isNested); } else { - bundle.Pack(dstPath); + string version = bundleInfo.Attribute("version")?.Value ?? throw new Exception($"No version found in bundle file {nameWithExtension}"); + string id = bundleInfo.Attribute("identifier")?.Value ?? throw new Exception($"No identifier found in bundle file {nameWithExtension}"); + bundle.Pack(extractionPath, dstPath, id, version, isNested) } - - if (isNested) - { - Bundles.Add(bundle); - } - } - - private static string GetId(XElement element) - { - string id = element.Attribute("packageIdentifier")?.Value - ?? element.Attribute("id")?.Value - ?? element.Attribute("identifier")?.Value - ?? throw new Exception("No packageIdentifier or id found in XElement."); - - return id; } } } diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs index b5f177c464c..94786a0d147 100644 --- a/src/Microsoft.DotNet.Pkg/PackageBundle.cs +++ b/src/Microsoft.DotNet.Pkg/PackageBundle.cs @@ -9,55 +9,26 @@ namespace Microsoft.DotNet.Pkg { internal class PackageBundle { - private bool IsNested; - private string NameWithExtension; - private string LocalExtractionPath; - private string Identifier; - private string Version; - private string? Scripts; - private string? Payload; - - internal PackageBundle(string localExtractionPath, string identifier, string version, string rootPkgName, bool isNested) + internal void Unpack(string srcPath, bool isNested) { - IsNested = isNested; - Identifier = identifier; - Version = version; - NameWithExtension = rootPkgName; - LocalExtractionPath = localExtractionPath; if (isNested) { - NameWithExtension = Path.GetFileName(localExtractionPath); - LocalExtractionPath = Path.Combine(Path.GetDirectoryName(localExtractionPath) ?? string.Empty, Path.GetFileNameWithoutExtension(NameWithExtension)); - } + string nameWithExtension = Path.GetFileName(srcPath); + srcPath = Path.Combine(Path.GetDirectoryName(srcPath) ?? string.Empty, Path.GetFileNameWithoutExtension(srcPath)); - if (!Utilities.IsPkg(NameWithExtension)) - { - throw new Exception($"Bundle '{NameWithExtension}' is not a .pkg file"); - } - } - - internal void Unpack() - { - if (IsNested) - { // The nested bundles get unpacked into a directory with a .pkg extension by `pkgutil --expand`, // so we remove this extension when unpacking the bundle. // Otherwise, there will be problems when packing the bundle due to the naming conflict - Directory.Move(LocalExtractionPath + ".pkg", LocalExtractionPath); + Directory.Move(srcPath + ".pkg", srcPath); } - Scripts = Utilities.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - Payload = Utilities.FindInPath("Payload", LocalExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + string? payload = Utilities.FindInPath("Payload", srcPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly) ?? throw new Exception("Payload not found"); + UnpackPayloadFile(Path.GetFullPath(payload)); - if (!string.IsNullOrEmpty(Payload)) - { - UnpackPayloadFile(Path.GetFullPath(Payload)); - } - - if (!IsNested) + if (!isNested) { // Zip the nested app bundles - IEnumerable nestedApps = Utilities.GetDirectories(LocalExtractionPath, "*.app", SearchOption.AllDirectories); + IEnumerable nestedApps = Utilities.GetDirectories(srcPath, "*.app", SearchOption.AllDirectories); foreach (string app in nestedApps) { string tempDest = $"{app}.zip"; @@ -71,22 +42,19 @@ internal void Unpack() } } - if (IsNested) + if (isNested) { // We now need to repack the nested bundle and remove the unpacked directory - PkgBuild(); - Directory.Delete(LocalExtractionPath, true); + PkgBuild(payload, isNested); + Directory.Delete(srcPath, true); } } - internal void Pack(string dstPath) + internal void Pack(string srcPath, string dstPath, string identifier, string version, bool isNested) { - if (!IsNested) + if (!isNested) { - Scripts = Utilities.FindInPath("Scripts", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - Payload = Utilities.FindInPath("Payload", LocalExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - - IEnumerable zippedNestedApps = Directory.GetFiles(LocalExtractionPath, "*.app", SearchOption.AllDirectories); + IEnumerable zippedNestedApps = Directory.GetFiles(srcPath, "*.app", SearchOption.AllDirectories); foreach (string appZip in zippedNestedApps) { // Unzip the .app directory @@ -99,22 +67,24 @@ internal void Pack(string dstPath) Directory.Move(tempDest, appZip); } - PkgBuild(dstPath); + PkgBuild(srcPath, identifier, version, isNested, dstPath); } } - private void PkgBuild(string dstPath = "") + private void PkgBuild(string srcPath, string identifier, string version, bool isNested, string dstPath = "") { + string? payload = Utilities.FindInPath("Payload", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly) ?? throw new Exception("Payload not found"); string info = GenerateInfoPlist(); - string root = string.IsNullOrEmpty(Payload) ? $"{LocalExtractionPath}" : $"{Payload}"; - string args = $"--root {root} --component-plist {info} --identifier {Identifier} --version {Version} --keychain login.keychain --install-location /usr/local/share/dotnet"; + string args = $"--root {payload} --component-plist {info} --identifier {identifier} --version {version} --keychain login.keychain --install-location /usr/local/share/dotnet"; + + string? scripts = Utilities.FindInPath("Scripts", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); if (!string.IsNullOrEmpty(Scripts)) { - args += $" --scripts {Scripts}"; + args += $" --scripts {scripts}"; } - string outputPath = $"{LocalExtractionPath}.pkg"; - if (!IsNested) + string outputPath = $"{srcPath}.pkg"; + if (!isNested) { outputPath = dstPath; if (File.Exists(outputPath)) @@ -129,11 +99,10 @@ private void PkgBuild(string dstPath = "") File.Delete(info); } - private string GenerateInfoPlist() + private string GenerateInfoPlist(string payload) { - string root = string.IsNullOrEmpty(Payload) ? $"{LocalExtractionPath}" : $"{Payload}"; string info = Path.Combine(Directory.GetCurrentDirectory(), "Info.plist"); - ExecuteHelper.Run("pkgbuild", $"--analyze --root {root} {info}"); + ExecuteHelper.Run("pkgbuild", $"--analyze --root {payload} {info}"); return info; } From 838dbedf9f17ef760e93611b7da300176ab2270b Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 18:48:15 +0000 Subject: [PATCH 08/14] Merge Package and PackageBundle into the same file --- src/Microsoft.DotNet.Pkg/Package.cs | 178 +++++++++++++++------- src/Microsoft.DotNet.Pkg/PackageBundle.cs | 135 ---------------- 2 files changed, 126 insertions(+), 187 deletions(-) delete mode 100644 src/Microsoft.DotNet.Pkg/PackageBundle.cs diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.Pkg/Package.cs index 0f391105a1c..4884da5d90f 100644 --- a/src/Microsoft.DotNet.Pkg/Package.cs +++ b/src/Microsoft.DotNet.Pkg/Package.cs @@ -11,95 +11,169 @@ namespace Microsoft.DotNet.Pkg { internal static class Package { - internal static void Unpack(string srcPath, string dstPath) => - ProcessPackage(string srcPath, string dstPath, packing: false); - - internal static void Pack(string srcPath, string dstPath) => - ProcessPackage(srcPath, dstPath, packing: true); - - private static void ProcessPackage(string srcPath, string dstPath, bool packing) + internal static void Unpack(string srcPath, string dstPath) { - string nameWithExtension = packing ? Path.GetFileName(dstPath) : Path.GetFileName(srcPath); - string localExtractionPath = packing ? srcPath : dstPath; + ExpandPackage(srcPath, dstPath); - if (!packing) + string? distribution = Utilities.FindInPath("Distribution", dstPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + if (!string.IsNullOrEmpty(distribution)) { - ExpandPkg(srcPath, dstPath); + UnpackInstallerPackage(dstPath, distribution!); + return; } - string? resources = Utilities.FindInPath("Resources", localExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - string? distribution = Utilities.FindInPath("Distribution", localExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); - string? scripts = Utilities.FindInPath("Scripts", localExtractionPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - string? packageInfo = Utilities.FindInPath("PackageInfo", localExtractionPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + string? packageInfo = Utilities.FindInPath("PackageInfo", dstPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + if (!string.IsNullOrEmpty(packageInfo)) + { + UnpackComponentPackage(dstPath); + return; + } + throw new Exception("Cannot unpack: no 'Distribution' or 'PackageInfo' file found in package"); + } + + internal static void Pack(string srcPath, string dstPath) + { + string? distribution = Utilities.FindInPath("Distribution", srcPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); if (!string.IsNullOrEmpty(distribution)) { - var xml = XElement.Load(distribution); - List pkgBundles = xml.Elements("pkg-ref").Where(e => e.Value.Trim() != "").ToList(); - if (!pkgBundles.Any()) - { - throw new Exception("No pkg-ref elements found in Distribution file"); - } - foreach (var pkgBundle in pkgBundles) - { - ProcessBundle(pkgBundle, isNested: true, packing: packing); - } - - if (packing) - { - PackPkg(srcPath, dstPath, distribution, resources, scripts); - } + PackInstallerPackage(srcPath, dstPath, distribution!); + return; } - else if (!string.IsNullOrEmpty(packageInfo)) + + string? packageInfo = Utilities.FindInPath("PackageInfo", srcPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly); + if (!string.IsNullOrEmpty(packageInfo)) { - // This is a single bundle package - XElement pkgBundle = XElement.Load(packageInfo); - ProcessBundle(pkgBundle, isNested: false, packing: packing, dstPath); + PackComponentPackage(srcPath, dstPath, packageInfo!); + return; } - else if (packing) + + throw new Exception("Cannot pack: no 'Distribution' or 'PackageInfo' file found in package"); + } + + private static void UnpackInstallerPackage(string dstPath, string distribution) + { + var xml = XElement.Load(distribution); + List componentPackages = xml.Elements("pkg-ref").Where(e => e.Value.Trim() != "").ToList(); + foreach (var package in componentPackages) { - throw new Exception("Cannot unpack: no Distribution or PackageInfo file found in package"); + // Expanding the installer will unpack the nested component packages to a directory with a .pkg extension + // so we repack the component packages to a temporary file and then rename the file with the .pkg extension. + // Repacking is needed so that the signtool can properly identify and sign the nested component packages. + string packageName = Path.Combine(dstPath, package.Value.Substring(1)); + string tempDest = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + FlattenComponentPackage(packageName, tempDest); + + Directory.Delete(packageName, true); + File.Move(tempDest, packageName); } } - private static void ExpandPkg(string srcPath, string dstPath) => - ExecuteHelper.Run("pkgutil", $"--expand {srcPath} {dstPath}"); + private static void UnpackComponentPackage(string dstPath) + { + UnpackPayload(dstPath); - private static void PackPkg(string srcPath, string dstPath, string distribution, string? resources, string? scripts) + // Zip the nested app bundles + IEnumerable nestedApps = Directory.GetDirectories(dstPath, "*.app", SearchOption.AllDirectories); + foreach (string app in nestedApps) + { + string tempDest = $"{app}.zip"; + AppBundle.Pack(app, tempDest); + Directory.Delete(app, true); + + // Rename the zipped file to .app + // This is needed so that the signtool + // can properly identify and sign app bundles + File.Move(tempDest, app); + } + } + + private static void PackInstallerPackage(string srcPath, string dstPath, string distribution) { - string args = $"--distribution {distribution} --package-path {srcPath}"; + string args = $"--distribution {distribution}"; + if (Directory.GetFiles(srcPath, "*.pkg", SearchOption.TopDirectoryOnly).Any()) + { + args += $" --package-path {srcPath}"; + } + + string? resources = Utilities.FindInPath("Resources", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); if (!string.IsNullOrEmpty(resources)) { args += $" --resources {resources}"; } + + string? scripts = Utilities.FindInPath("Scripts", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); if (!string.IsNullOrEmpty(scripts)) { args += $" --scripts {scripts}"; } - if (File.Exists(dstPath)) - { - File.Delete(dstPath); - } args += $" {dstPath}"; ExecuteHelper.Run("productbuild", args); } - private static void ProcessBundle(XElement bundleInfo, string localExtractionPath, string nameWithExtension, bool isNested, bool packing) + private static void PackComponentPackage(string srcPath, string dstPath, string packageInfo) { - string extractionPath = isNested ? Path.Combine(localExtractionPath, bundleInfo.Value.Substring(1)) : localExtractionPath; - if (!packing) + // Unzip the nested app bundles + IEnumerable zippedNestedApps = Directory.GetFiles(srcPath, "*.app", SearchOption.AllDirectories); + foreach (string appZip in zippedNestedApps) { - bundle.Unpack(extractionPath, isNested); + // Unzip the .app directory + string tempDest = appZip + ".unzipped"; + AppBundle.Unpack(appZip, tempDest); + File.Delete(appZip); + + // Rename the unzipped directory back to .app + // so that it can be packed properly + Directory.Move(tempDest, appZip); } - else + + XElement pkgInfo = XElement.Load(packageInfo); + + string payloadDirectoryPath = GetPayloadPath(srcPath, isDirectory: true); + string identifier = GetPackageInfoAttribute(pkgInfo, "identifier"); + string version = GetPackageInfoAttribute(pkgInfo, "version"); + string installLocation = GetPackageInfoAttribute(pkgInfo, "install-location"); + + string args = $"--root {payloadDirectoryPath} --identifier {identifier} --version {version} --install-location {installLocation}"; + string? script = Utilities.FindInPath("Scripts", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); + if (!string.IsNullOrEmpty(script)) { - string version = bundleInfo.Attribute("version")?.Value ?? throw new Exception($"No version found in bundle file {nameWithExtension}"); - string id = bundleInfo.Attribute("identifier")?.Value ?? throw new Exception($"No identifier found in bundle file {nameWithExtension}"); - bundle.Pack(extractionPath, dstPath, id, version, isNested) + args += $" --scripts {script}"; } + args += $" {dstPath}"; + + ExecuteHelper.Run("pkgbuild", args); } + + private static void FlattenComponentPackage(string sourcePath, string destinationPath) + => ExecuteHelper.Run("pkgutil", $"--flatten {sourcePath} {destinationPath}"); + + private static void UnpackPayload(string dstPath) + { + string payloadFilePath = GetPayloadPath(dstPath, isDirectory: false); + + string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(tempDir); + + ExecuteHelper.Run("cat", $"{payloadFilePath} | gzip -d | cpio -id", tempDir); + + // Remove the payload file and replace it with + // a directory of the same name containing the unpacked contents + File.Delete(payloadFilePath); + Directory.Move(tempDir, payloadFilePath); + } + + private static string GetPayloadPath(string searchPath, bool isDirectory) => + Path.GetFullPath(Utilities.FindInPath("Payload", searchPath, isDirectory, searchOption: SearchOption.TopDirectoryOnly) + ?? throw new Exception("Payload was not found")); + + private static void ExpandPackage(string srcPath, string dstPath) => + ExecuteHelper.Run("pkgutil", $"--expand {srcPath} {dstPath}"); + + private static string GetPackageInfoAttribute(XElement pkgInfo, string elementName) => + pkgInfo.Attribute(elementName)?.Value ?? throw new Exception($"{elementName} is required in PackageInfo"); } } diff --git a/src/Microsoft.DotNet.Pkg/PackageBundle.cs b/src/Microsoft.DotNet.Pkg/PackageBundle.cs deleted file mode 100644 index 94786a0d147..00000000000 --- a/src/Microsoft.DotNet.Pkg/PackageBundle.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Collections.Generic; - -namespace Microsoft.DotNet.Pkg -{ - internal class PackageBundle - { - internal void Unpack(string srcPath, bool isNested) - { - if (isNested) - { - string nameWithExtension = Path.GetFileName(srcPath); - srcPath = Path.Combine(Path.GetDirectoryName(srcPath) ?? string.Empty, Path.GetFileNameWithoutExtension(srcPath)); - - // The nested bundles get unpacked into a directory with a .pkg extension by `pkgutil --expand`, - // so we remove this extension when unpacking the bundle. - // Otherwise, there will be problems when packing the bundle due to the naming conflict - Directory.Move(srcPath + ".pkg", srcPath); - } - - string? payload = Utilities.FindInPath("Payload", srcPath, isDirectory: false, searchOption: SearchOption.TopDirectoryOnly) ?? throw new Exception("Payload not found"); - UnpackPayloadFile(Path.GetFullPath(payload)); - - if (!isNested) - { - // Zip the nested app bundles - IEnumerable nestedApps = Utilities.GetDirectories(srcPath, "*.app", SearchOption.AllDirectories); - foreach (string app in nestedApps) - { - string tempDest = $"{app}.zip"; - AppBundle.Pack(app, tempDest); - Directory.Delete(app, true); - - // Rename the zipped file to .app - // This is needed so that the signtool - // can properly identity and sign app bundles - File.Move(tempDest, app); - } - } - - if (isNested) - { - // We now need to repack the nested bundle and remove the unpacked directory - PkgBuild(payload, isNested); - Directory.Delete(srcPath, true); - } - } - - internal void Pack(string srcPath, string dstPath, string identifier, string version, bool isNested) - { - if (!isNested) - { - IEnumerable zippedNestedApps = Directory.GetFiles(srcPath, "*.app", SearchOption.AllDirectories); - foreach (string appZip in zippedNestedApps) - { - // Unzip the .app directory - string tempDest = appZip + ".unzipped"; - AppBundle.Unpack(appZip, tempDest); - File.Delete(appZip); - - // Rename the unzipped directory back to .app - // so that it can be repacked properly - Directory.Move(tempDest, appZip); - } - - PkgBuild(srcPath, identifier, version, isNested, dstPath); - } - } - - private void PkgBuild(string srcPath, string identifier, string version, bool isNested, string dstPath = "") - { - string? payload = Utilities.FindInPath("Payload", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly) ?? throw new Exception("Payload not found"); - string info = GenerateInfoPlist(); - string args = $"--root {payload} --component-plist {info} --identifier {identifier} --version {version} --keychain login.keychain --install-location /usr/local/share/dotnet"; - - string? scripts = Utilities.FindInPath("Scripts", srcPath, isDirectory: true, searchOption: SearchOption.TopDirectoryOnly); - if (!string.IsNullOrEmpty(Scripts)) - { - args += $" --scripts {scripts}"; - } - - string outputPath = $"{srcPath}.pkg"; - if (!isNested) - { - outputPath = dstPath; - if (File.Exists(outputPath)) - { - File.Delete(outputPath); - } - } - args += $" {outputPath}"; - - ExecuteHelper.Run("pkgbuild", args); - - File.Delete(info); - } - - private string GenerateInfoPlist(string payload) - { - string info = Path.Combine(Directory.GetCurrentDirectory(), "Info.plist"); - ExecuteHelper.Run("pkgbuild", $"--analyze --root {payload} {info}"); - return info; - } - - private void UnpackPayloadFile(string payloadFilePath) - { - if (!File.Exists(payloadFilePath) || !Path.GetFileName(payloadFilePath).Equals("Payload")) - { - throw new Exception($"Cannot unpack invalid 'Payload' file in {NameWithExtension}"); - } - - string tempDir = Path.Combine(Directory.GetCurrentDirectory(), "tempPayloadUnpackingDir"); - Directory.CreateDirectory(tempDir); - try - { - // While we're shelling out to an executable named 'tar', the "Payload" file from pkgs is not actually - // a tar file. It's secretly a 'pbzx' file that tar on OSX has been taught to unpack. - // As such, while there is actually untarring / re-tarring in this file using Python libraries, we have to - // shell out to the host machine to do this. - ExecuteHelper.Run("tar", $"-xf {payloadFilePath}", tempDir); - } - finally - { - // Remove the payload file and replace it with - // a directory of the same name containing the unpacked contents - File.Delete(payloadFilePath); - Directory.Move(tempDir, payloadFilePath); - } - } - } -} From c1722cb0093c450d91b23bc074264f8dda415a94 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 18:48:15 +0000 Subject: [PATCH 09/14] Cleanup tests --- .../Microsoft.DotNet.Pkg.Tests.csproj | 4 +- .../UnpackPackTests.cs | 418 ++++++------------ 2 files changed, 130 insertions(+), 292 deletions(-) diff --git a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj b/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj index 1ea0bc20752..587bb449534 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj +++ b/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj @@ -11,9 +11,9 @@ - + + CopyToOutputDirectory="PreserveNewest" /> diff --git a/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs b/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs index 6a95adb4b42..6c2a6b453cc 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs +++ b/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs @@ -1,366 +1,207 @@ // 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 System.Diagnostics; using Xunit; -using FluentAssertions; +using Xunit.Abstractions; namespace Microsoft.DotNet.Pkg.Tests { public class UnpackPackTests { - private static string pkgToolPath = Path.Combine( - Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location), + 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", "pkg", "Microsoft.Dotnet.Pkg.dll"); - private static string[] simplePkgFiles = new[] - { - Path.Combine("Bom"), - Path.Combine("PackageInfo"), + private static readonly string[] simplePkgFiles = + [ + "Bom", + "PackageInfo", Path.Combine("Payload", "Sample.txt") - }; + ]; - private static string[] withAppPkgFiles = new[] - { - Path.Combine("Bom"), - Path.Combine("PackageInfo"), + private static readonly string[] withAppPkgFiles = + [ + "Bom", + "PackageInfo", Path.Combine("Payload", "test.app") - }; + ]; - private static string[] appFiles = new[] - { + private static readonly string[] appFiles = + [ Path.Combine("Contents", "Info.plist"), Path.Combine("Contents", "MacOS", "main"), - Path.Combine("Contents", "Resources", "libexample.dylib"), - }; - - private static string[] simpleInstallerFiles = new[] - { - Path.Combine("Distribution"), - Path.Combine("Simple.pkg"), - }; - - private static string[] withAppInstallerFiles = new[] - { - Path.Combine("Distribution"), - Path.Combine("WithApp.pkg"), - }; - - [MacOSOnlyFact] - public void UnpackSimplePkg() - { - string srcPath = GetResourceFilePath("Simple.pkg"); - string dstPath = GetTempFilePath("SimplePkg"); - try - { - Unpack(srcPath, dstPath, simplePkgFiles); - } - finally - { - Directory.Delete(dstPath, true); - } - } - - [MacOSOnlyFact] - public void PackSimplePkg() - { - string srcPath = GetResourceFilePath("Simple.pkg"); - string dstPath = GetTempFilePath("SimplePkg"); - string packPath = GetTempFilePath("PackSimple.pkg"); - try - { - // Unpack the package - Unpack(srcPath, dstPath); - - // Pack the package - Pack(dstPath, packPath, simplePkgFiles); - } - finally - { - Directory.Delete(dstPath, true); - File.Delete(packPath); - } - } + Path.Combine("Contents", "Resources", "libexample.dylib") + ]; - [MacOSOnlyFact] - public void UnpackPkgWithApp() - { - string srcPath = GetResourceFilePath("WithApp.pkg"); - string dstPath = GetTempFilePath("WithAppPkg"); - try - { - Unpack(srcPath, dstPath, withAppPkgFiles); - } - finally - { - Directory.Delete(dstPath, true); - } - } + private static readonly string[] simpleInstallerFiles = + [ + "Distribution", + "Simple.pkg" + ]; - [MacOSOnlyFact] - public void PackPkgWithApp() - { - string srcPath = GetResourceFilePath("WithApp.pkg"); - string dstPath = GetTempFilePath("WithAppPkg"); - string packPath = GetTempFilePath("PackWithApp.pkg"); - try - { - // Unpack the package - Unpack(srcPath, dstPath); + private static readonly string[] withAppInstallerFiles = + [ + "Distribution", + "WithApp.pkg" + ]; - // Pack the package - Pack(dstPath, packPath, withAppPkgFiles); - } - finally - { - Directory.Delete(dstPath, true); - File.Delete(packPath); - } - } + public UnpackPackTests(ITestOutputHelper output) => this.output = output; [MacOSOnlyFact] - public void UnpackAppBundle() + public void UnpackPackSimplePkg() { - string srcPath = GetResourceFilePath("WithApp.pkg"); - string dstPath = GetTempFilePath("WithAppPkg"); - string appPath = Path.Combine(dstPath, "Payload", "test.app"); - string appDstPath = GetTempFilePath("TestApp"); - try - { - // Unpack the package - Unpack(srcPath, dstPath); + string unpackPath = Path.GetTempFileName(); + string packPath = GetTempPkgPath(); - // Unpack the app bundle - Unpack(appPath, appDstPath, appFiles); - } - finally + ExecuteWithCleanup(() => { - Directory.Delete(dstPath, true); - Directory.Delete(appDstPath, true); - } + Unpack(simplePkg, unpackPath, simplePkgFiles); + Pack(unpackPath, packPath, simplePkgFiles); + }, new List { unpackPath, packPath }); } [MacOSOnlyFact] - public void PackAppBundle() + public void UnpackPackWithAppPkg() { - string srcPath = GetResourceFilePath("WithApp.pkg"); - string dstPath = GetTempFilePath("WithAppPkg"); - string appPath = Path.Combine(dstPath, "Payload", "test.app"); - string appDstPath = GetTempFilePath("TestApp"); - try - { - // Unpack the package - Unpack(srcPath, dstPath); + string unpackPath = Path.GetTempFileName(); + string packPath = GetTempPkgPath(); - // Unpack the app bundle - Unpack(appPath, appDstPath); - - // Pack the app bundle - Pack(appDstPath, appPath, appFiles); - } - finally + ExecuteWithCleanup(() => { - Directory.Delete(dstPath, true); - Directory.Delete(appDstPath, true); - } + Unpack(withAppPkg, unpackPath, withAppPkgFiles); + Pack(unpackPath, packPath, withAppPkgFiles); + }, new List { unpackPath, packPath }); } [MacOSOnlyFact] - public void UnpackSimpleInstaller() + public void UnpackPackAppBundle() { - string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); - string dstPath = GetTempFilePath("SimpleInstallerPkg"); - try - { - Unpack(srcPath, dstPath, simpleInstallerFiles); - } - finally - { - Directory.Delete(dstPath, true); - } - } + string unpackPkgPath = Path.GetTempFileName(); + string unpackAppPath = Path.GetTempFileName(); + string packAppPath = GetTempAppPath(); - [MacOSOnlyFact] - public void PackSimpleInstaller() - { - string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); - string dstPath = GetTempFilePath("SimpleInstallerPkg"); - string packPath = GetTempFilePath("PackSimpleInstaller.pkg"); - try + ExecuteWithCleanup(() => { - // Unpack the installer - Unpack(srcPath, dstPath); - - // Pack the installer - Pack(dstPath, packPath, simpleInstallerFiles); - } - finally - { - Directory.Delete(dstPath, true); - File.Delete(packPath); - } + Unpack(withAppPkg, unpackPkgPath, withAppPkgFiles); + Unpack(Path.Combine(unpackPkgPath, "Payload", "test.app"), unpackAppPath, appFiles); + Pack(unpackAppPath, packAppPath, appFiles); + }, new List { unpackPkgPath, unpackAppPath }); } [MacOSOnlyFact] - public void UnpackNestedInstaller() + public void UnpackPackSimpleInstallerPkg() { - string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); - string dstPath = GetTempFilePath("SimpleInstallerPkg"); - string simplePkgPath = Path.Combine(dstPath, "Simple.pkg"); - string simplePkgDstPath = GetTempFilePath("SimplePkg"); - try - { - // Unpack the installer - Unpack(srcPath, dstPath, simpleInstallerFiles); + string unpackPath = Path.GetTempFileName(); + string packPath = GetTempPkgPath(); - // Unpack the simple package inside the installer - Unpack(simplePkgPath, simplePkgDstPath, simplePkgFiles); - } - finally + ExecuteWithCleanup(() => { - Directory.Delete(dstPath, true); - Directory.Delete(simplePkgDstPath, true); - } + Unpack(simpleInstallerPkg, unpackPath, simpleInstallerFiles); + Pack(unpackPath, packPath, simpleInstallerFiles); + }, new List { unpackPath, packPath }); } [MacOSOnlyFact] - public void PackNestedInstaller() + public void UnpackPackSimplePkgInSimpleInstallerPkg() { - string srcPath = GetResourceFilePath("SimpleInstaller.pkg"); - string dstPath = GetTempFilePath("SimpleInstallerPkg"); - string simplePkgPath = Path.Combine(dstPath, "Simple.pkg"); - string simplePkgDstPath = GetTempFilePath("SimplePkg"); - string packPath = GetTempFilePath("PackSimpleInstaller.pkg"); - string unpackPackPath = GetTempFilePath("UnpackPackSimpleInstallerPkg"); - string unpackPackSimplePkgPath = Path.Combine(unpackPackPath, "Simple.pkg"); - string unpackPackSimplePkgDstPath = GetTempFilePath("UnpackPackSimplePkg"); - try - { - // Unpack the installer - Unpack(srcPath, dstPath); - - // Unpack and pack the simple package - Unpack(simplePkgPath, simplePkgDstPath); - Pack(simplePkgDstPath, simplePkgPath); + string unpackInstallerPath = Path.GetTempFileName(); + string unpackComponentPath = Path.GetTempFileName(); + string packInstallerPath = GetTempPkgPath(); - // Pack the installer - Pack(dstPath, packPath, simpleInstallerFiles); + string componentPkgPath = Path.Combine(unpackInstallerPath, "Simple.pkg"); - // Unpack the packed simple pkg inside to compare the content - Unpack(packPath, unpackPackPath); - Unpack(unpackPackSimplePkgPath, unpackPackSimplePkgDstPath, simplePkgFiles); - } - finally + ExecuteWithCleanup(() => { - File.Delete(packPath); - File.Delete(simplePkgPath); - - Directory.Delete(dstPath, true); - Directory.Delete(simplePkgDstPath, true); - Directory.Delete(unpackPackPath, true); - Directory.Delete(unpackPackSimplePkgDstPath, true); - } + Unpack(simpleInstallerPkg, unpackInstallerPath, simpleInstallerFiles); + Unpack(componentPkgPath, unpackComponentPath, simplePkgFiles); + Pack(unpackComponentPath, componentPkgPath, simplePkgFiles); + Pack(unpackInstallerPath, packInstallerPath, simpleInstallerFiles); + }, new List { unpackInstallerPath, unpackComponentPath, packInstallerPath }); } [MacOSOnlyFact] - public void UnpackNestedInstallerWithApp() + public void UnpackPackAppBundleAndWithAppPkgInWithAppInstallerPkg() { - string srcPath = GetResourceFilePath("WithAppInstaller.pkg"); - string dstPath = GetTempFilePath("WithAppInstallerPkg"); - string withAppPkgPath = Path.Combine(dstPath, "WithApp.pkg"); - string withAppPkgDstPath = GetTempFilePath("WithAppPkg"); - try - { - // Unpack the installer - Unpack(srcPath, dstPath, withAppInstallerFiles); + 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"); - // Unpack the app package inside the installer - Unpack(withAppPkgPath, withAppPkgDstPath, withAppPkgFiles); - } - finally - { - Directory.Delete(dstPath, true); - Directory.Delete(withAppPkgDstPath, true); - } + 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); + }, + new List { unpackInstallerPath, unpackComponentPath, unpackAppPath, packInstallerPath }); } - [MacOSOnlyFact] - public void PackNestedInstallerWithApp() + private static void ExecuteWithCleanup(Action action, List cleanupPaths) { - string srcPath = GetResourceFilePath("WithAppInstaller.pkg"); - string dstPath = GetTempFilePath("WithAppInstallerPkg"); - string withAppPkgPath = Path.Combine(dstPath, "WithApp.pkg"); - string withAppPkgDstPath = GetTempFilePath("WithAppPkg"); - string packPath = GetTempFilePath("PackWithAppInstaller.pkg"); - string unpackPackPath = GetTempFilePath("UnpackPackWithAppInstallerPkg"); - string unpackPackWithAppPkgPath = Path.Combine(unpackPackPath, "WithApp.pkg"); - string unpackPackWithAppPkgDstPath = GetTempFilePath("UnpackPackWithAppPkg"); try { - // Unpack the installer - Unpack(srcPath, dstPath); - - // Unpack and pack the app package - Unpack(withAppPkgPath, withAppPkgDstPath); - Pack(withAppPkgDstPath, withAppPkgPath); - - // Pack the installer - Pack(dstPath, packPath, withAppInstallerFiles); - - // Unpack the packed app pkg inside to compare the content - Unpack(packPath, unpackPackPath); - Unpack(unpackPackWithAppPkgPath, unpackPackWithAppPkgDstPath, withAppPkgFiles); + action(); } finally { - File.Delete(packPath); - File.Delete(withAppPkgPath); - - Directory.Delete(dstPath, true); - Directory.Delete(withAppPkgDstPath, true); - Directory.Delete(unpackPackPath, true); - Directory.Delete(unpackPackWithAppPkgDstPath, true); + foreach (string path in cleanupPaths) + { + if (Directory.Exists(path)) + { + Directory.Delete(path, true); + } + else if (File.Exists(path)) + { + File.Delete(path); + } + } } } - private static void Unpack(string inputPath, string outputPath, string[] expectedFiles = null) + private void Unpack(string srcPath, string dstPath, string[] expectedFiles) { - bool success = RunPkgProcess(inputPath, outputPath, "unpack"); - success.Should().BeTrue(); + RunPkgProcess(srcPath, dstPath, "unpack").Should().BeTrue(); - Directory.Exists(outputPath).Should().BeTrue(); + Directory.Exists(dstPath).Should().BeTrue(); - if (expectedFiles != null) - { - CompareContent(outputPath, expectedFiles); - } + CompareContent(dstPath, expectedFiles); } - private static void Pack(string inputPath, string outputPath, string[] expectedFiles = null) + private void Pack(string srcPath, string dstPath, string[] expectedFiles) { - bool success = RunPkgProcess(inputPath, outputPath, "pack"); - success.Should().BeTrue(); + RunPkgProcess(srcPath, dstPath, "pack").Should().BeTrue(); - File.Exists(outputPath).Should().BeTrue(); + File.Exists(dstPath).Should().BeTrue(); - if (expectedFiles != null) + // Unpack the packed pkg and verify the content + string unpackPath = Path.GetTempFileName(); + ExecuteWithCleanup(() => { - string tempPath = GetTempFilePath($"UnpackPack{Path.GetFileNameWithoutExtension(inputPath)}"); - RunPkgProcess(outputPath, tempPath, "unpack").Should().BeTrue(); - Directory.Exists(tempPath).Should().BeTrue(); - - CompareContent(tempPath, expectedFiles); - - Directory.Delete(tempPath, true); - } + Unpack(dstPath, unpackPath, expectedFiles); + }, new List { unpackPath }); } - private static bool RunPkgProcess(string inputPath, string outputPath, string action) + private bool RunPkgProcess(string inputPath, string outputPath, string action) { var process = Process.Start(new ProcessStartInfo() { @@ -370,11 +211,11 @@ private static bool RunPkgProcess(string inputPath, string outputPath, string ac RedirectStandardError = true, }); - process.WaitForExit(); + process!.WaitForExit(60000); // 60 seconds bool success = process.ExitCode == 0; if (!success) { - Console.WriteLine($"Error: {process.StandardError.ReadToEnd()}"); + output.WriteLine($"Error: {process.StandardError.ReadToEnd()}"); } return success; } @@ -382,17 +223,14 @@ private static bool RunPkgProcess(string inputPath, string outputPath, string ac private static string GetResourceFilePath(string resourceName) { return Path.Combine( - Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location), + Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location)!, "Resources", resourceName); } - private static string GetTempFilePath(string fileName) - { - return Path.Combine( - Path.GetTempPath(), - fileName); - } + private static string GetTempPkgPath() => $"{Path.GetTempFileName()}.pkg"; + + private static string GetTempAppPath() => $"{Path.GetTempFileName()}.app"; private static void CompareContent(string basePath, string[] expectedFiles) { From c9e7a8ca3abe401d76635c2d19390fad5ff077a0 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 20:33:44 +0000 Subject: [PATCH 10/14] Remove unnecessary 'AllowUnsafeBlocks' --- src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj b/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj index 1ce09bd3a04..31768364ebc 100644 --- a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj +++ b/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj @@ -3,7 +3,6 @@ $(NetToolCurrent);$(NetFrameworkToolCurrent) Exe - true enable true Pkg From e6af49964a8f43571a1b14e73fb37b9f254cb672 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 22:11:09 +0000 Subject: [PATCH 11/14] Rename tool to 'MacOsPkg' --- Arcade.sln | 56 +++++++++--------- .../tools/DefaultVersions.props | 2 +- .../tools/Tools.proj | 2 +- .../Microsoft.DotNet.MacOsPkg.Tests.csproj} | 12 ++-- .../Resources/Simple.pkg | Bin .../Resources/SimpleInstaller.pkg | Bin .../Resources/WithApp.pkg | Bin .../Resources/WithAppInstaller.pkg | Bin .../UnpackPackTests.cs | 6 +- .../AppBundle.cs | 2 +- .../ExecuteHelper.cs | 2 +- .../Microsoft.DotNet.MacOsPkg.csproj} | 6 +- .../Package.cs | 2 +- .../Program.cs | 2 +- .../Utilities.cs | 2 +- 15 files changed, 47 insertions(+), 47 deletions(-) rename src/{Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj => Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj} (67%) rename src/{Microsoft.DotNet.Pkg.Tests => Microsoft.DotNet.MacOsPkg.Tests}/Resources/Simple.pkg (100%) rename src/{Microsoft.DotNet.Pkg.Tests => Microsoft.DotNet.MacOsPkg.Tests}/Resources/SimpleInstaller.pkg (100%) rename src/{Microsoft.DotNet.Pkg.Tests => Microsoft.DotNet.MacOsPkg.Tests}/Resources/WithApp.pkg (100%) rename src/{Microsoft.DotNet.Pkg.Tests => Microsoft.DotNet.MacOsPkg.Tests}/Resources/WithAppInstaller.pkg (100%) rename src/{Microsoft.DotNet.Pkg.Tests => Microsoft.DotNet.MacOsPkg.Tests}/UnpackPackTests.cs (98%) rename src/{Microsoft.DotNet.Pkg => Microsoft.DotNet.MacOsPkg}/AppBundle.cs (94%) rename src/{Microsoft.DotNet.Pkg => Microsoft.DotNet.MacOsPkg}/ExecuteHelper.cs (98%) rename src/{Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj => Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj} (74%) rename src/{Microsoft.DotNet.Pkg => Microsoft.DotNet.MacOsPkg}/Package.cs (99%) rename src/{Microsoft.DotNet.Pkg => Microsoft.DotNet.MacOsPkg}/Program.cs (98%) rename src/{Microsoft.DotNet.Pkg => Microsoft.DotNet.MacOsPkg}/Utilities.cs (97%) diff --git a/Arcade.sln b/Arcade.sln index bbfd972403f..3bd9171814a 100644 --- a/Arcade.sln +++ b/Arcade.sln @@ -151,9 +151,9 @@ 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.Pkg", "src\Microsoft.DotNet.Pkg\Microsoft.DotNet.Pkg.csproj", "{F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}" +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.Pkg.Tests", "src\Microsoft.DotNet.Pkg.Tests\Microsoft.DotNet.Pkg.Tests.csproj", "{0917B9D9-90C0-4DE4-9C85-D248FB9F826C}" +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 @@ -953,30 +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 - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x64.ActiveCfg = Debug|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x64.Build.0 = Debug|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x86.ActiveCfg = Debug|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Debug|x86.Build.0 = Debug|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|Any CPU.Build.0 = Release|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x64.ActiveCfg = Release|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x64.Build.0 = Release|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x86.ActiveCfg = Release|Any CPU - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C}.Release|x86.Build.0 = Release|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x64.ActiveCfg = Debug|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x64.Build.0 = Debug|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x86.ActiveCfg = Debug|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Debug|x86.Build.0 = Debug|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|Any CPU.Build.0 = Release|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x64.ActiveCfg = Release|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x64.Build.0 = Release|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.Release|x86.ActiveCfg = Release|Any CPU - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C}.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 @@ -1014,8 +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} - {F525F90D-F6CD-41DA-8E22-2DD7BB29B18C} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE} - {0917B9D9-90C0-4DE4-9C85-D248FB9F826C} = {6DA9F58A-34D5-45A6-998E-5D2B8037C3FE} + {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} diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props b/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props index 075dbcd672f..6646327a90e 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props @@ -80,7 +80,7 @@ $(ArcadeSdkVersion) $(ArcadeSdkVersion) $(ArcadeSdkVersion) - $(ArcadeSdkVersion) + $(ArcadeSdkVersion) 16.5.0 diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj b/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj index 93c3c3e2cdc..f7c3afdc6db 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj @@ -56,7 +56,7 @@ - + diff --git a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj b/src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj similarity index 67% rename from src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj rename to src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj index 587bb449534..bbd9e65c143 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/Microsoft.DotNet.Pkg.Tests.csproj +++ b/src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj @@ -21,23 +21,23 @@ + OutputItemType="_MacOsPkgToolPath" /> - + - <_PkgToolPattern>@(_PkgToolPath->'%(RootDir)%(Directory)')**\*.* + <_MacOSPkgToolPattern>@(_MacOsPkgToolPath->'%(RootDir)%(Directory)')**\*.* - <_PkgToolFiles Include="$(_PkgToolPattern)"/> + <_MacOSPkgToolFiles Include="$(_MacOsPkgToolPattern)"/> - + diff --git a/src/Microsoft.DotNet.Pkg.Tests/Resources/Simple.pkg b/src/Microsoft.DotNet.MacOsPkg.Tests/Resources/Simple.pkg similarity index 100% rename from src/Microsoft.DotNet.Pkg.Tests/Resources/Simple.pkg rename to src/Microsoft.DotNet.MacOsPkg.Tests/Resources/Simple.pkg diff --git a/src/Microsoft.DotNet.Pkg.Tests/Resources/SimpleInstaller.pkg b/src/Microsoft.DotNet.MacOsPkg.Tests/Resources/SimpleInstaller.pkg similarity index 100% rename from src/Microsoft.DotNet.Pkg.Tests/Resources/SimpleInstaller.pkg rename to src/Microsoft.DotNet.MacOsPkg.Tests/Resources/SimpleInstaller.pkg diff --git a/src/Microsoft.DotNet.Pkg.Tests/Resources/WithApp.pkg b/src/Microsoft.DotNet.MacOsPkg.Tests/Resources/WithApp.pkg similarity index 100% rename from src/Microsoft.DotNet.Pkg.Tests/Resources/WithApp.pkg rename to src/Microsoft.DotNet.MacOsPkg.Tests/Resources/WithApp.pkg diff --git a/src/Microsoft.DotNet.Pkg.Tests/Resources/WithAppInstaller.pkg b/src/Microsoft.DotNet.MacOsPkg.Tests/Resources/WithAppInstaller.pkg similarity index 100% rename from src/Microsoft.DotNet.Pkg.Tests/Resources/WithAppInstaller.pkg rename to src/Microsoft.DotNet.MacOsPkg.Tests/Resources/WithAppInstaller.pkg diff --git a/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs b/src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs similarity index 98% rename from src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs rename to src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs index 6c2a6b453cc..feed71890f1 100644 --- a/src/Microsoft.DotNet.Pkg.Tests/UnpackPackTests.cs +++ b/src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs @@ -10,7 +10,7 @@ using Xunit; using Xunit.Abstractions; -namespace Microsoft.DotNet.Pkg.Tests +namespace Microsoft.DotNet.MacOsPkg.Tests { public class UnpackPackTests { @@ -23,8 +23,8 @@ public class UnpackPackTests private static readonly string pkgToolPath = Path.Combine( Path.GetDirectoryName(typeof(UnpackPackTests).Assembly.Location)!, "tools", - "pkg", - "Microsoft.Dotnet.Pkg.dll"); + "macospkg", + "Microsoft.Dotnet.MacOsPkg.dll"); private static readonly string[] simplePkgFiles = [ diff --git a/src/Microsoft.DotNet.Pkg/AppBundle.cs b/src/Microsoft.DotNet.MacOsPkg/AppBundle.cs similarity index 94% rename from src/Microsoft.DotNet.Pkg/AppBundle.cs rename to src/Microsoft.DotNet.MacOsPkg/AppBundle.cs index f46ce9e6288..ceb0bdce1ef 100644 --- a/src/Microsoft.DotNet.Pkg/AppBundle.cs +++ b/src/Microsoft.DotNet.MacOsPkg/AppBundle.cs @@ -1,7 +1,7 @@ // 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.Pkg +namespace Microsoft.DotNet.MacOsPkg { internal static class AppBundle { diff --git a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs b/src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs similarity index 98% rename from src/Microsoft.DotNet.Pkg/ExecuteHelper.cs rename to src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs index 67f1e1ea93b..d62bca02f55 100644 --- a/src/Microsoft.DotNet.Pkg/ExecuteHelper.cs +++ b/src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using System.IO; -namespace Microsoft.DotNet.Pkg +namespace Microsoft.DotNet.MacOsPkg { public static class ExecuteHelper { diff --git a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj b/src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj similarity index 74% rename from src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj rename to src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj index 31768364ebc..d203ff40b72 100644 --- a/src/Microsoft.DotNet.Pkg/Microsoft.DotNet.Pkg.csproj +++ b/src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj @@ -5,14 +5,14 @@ Exe enable true - Pkg - Arcade Build Tool Pkg + MacOsPkg + Arcade Build Tool MacOS Pkg false true - dotnet-pkg + dotnet-macos-pkg diff --git a/src/Microsoft.DotNet.Pkg/Package.cs b/src/Microsoft.DotNet.MacOsPkg/Package.cs similarity index 99% rename from src/Microsoft.DotNet.Pkg/Package.cs rename to src/Microsoft.DotNet.MacOsPkg/Package.cs index 4884da5d90f..b1806edffc1 100644 --- a/src/Microsoft.DotNet.Pkg/Package.cs +++ b/src/Microsoft.DotNet.MacOsPkg/Package.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Xml.Linq; -namespace Microsoft.DotNet.Pkg +namespace Microsoft.DotNet.MacOsPkg { internal static class Package { diff --git a/src/Microsoft.DotNet.Pkg/Program.cs b/src/Microsoft.DotNet.MacOsPkg/Program.cs similarity index 98% rename from src/Microsoft.DotNet.Pkg/Program.cs rename to src/Microsoft.DotNet.MacOsPkg/Program.cs index 5b5c0f600b4..ebf208bc7ff 100644 --- a/src/Microsoft.DotNet.Pkg/Program.cs +++ b/src/Microsoft.DotNet.MacOsPkg/Program.cs @@ -4,7 +4,7 @@ using System; using System.IO; using System.Runtime.InteropServices; -using Microsoft.DotNet.Pkg; +using Microsoft.DotNet.MacOsPkg; if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { diff --git a/src/Microsoft.DotNet.Pkg/Utilities.cs b/src/Microsoft.DotNet.MacOsPkg/Utilities.cs similarity index 97% rename from src/Microsoft.DotNet.Pkg/Utilities.cs rename to src/Microsoft.DotNet.MacOsPkg/Utilities.cs index 7897d220589..5e2ba659533 100644 --- a/src/Microsoft.DotNet.Pkg/Utilities.cs +++ b/src/Microsoft.DotNet.MacOsPkg/Utilities.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; -namespace Microsoft.DotNet.Pkg +namespace Microsoft.DotNet.MacOsPkg { public static class Utilities { From 35fc325d77d1360bd44de49661a4c81265e95f08 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 15 Nov 2024 22:20:31 +0000 Subject: [PATCH 12/14] Small fixes --- .../UnpackPackTests.cs | 15 +++++++-------- src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs | 9 ++------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs b/src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs index feed71890f1..34755962731 100644 --- a/src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs +++ b/src/Microsoft.DotNet.MacOsPkg.Tests/UnpackPackTests.cs @@ -71,7 +71,7 @@ public void UnpackPackSimplePkg() { Unpack(simplePkg, unpackPath, simplePkgFiles); Pack(unpackPath, packPath, simplePkgFiles); - }, new List { unpackPath, packPath }); + }, [ unpackPath, packPath ]); } [MacOSOnlyFact] @@ -84,7 +84,7 @@ public void UnpackPackWithAppPkg() { Unpack(withAppPkg, unpackPath, withAppPkgFiles); Pack(unpackPath, packPath, withAppPkgFiles); - }, new List { unpackPath, packPath }); + }, [ unpackPath, packPath ]); } [MacOSOnlyFact] @@ -99,7 +99,7 @@ public void UnpackPackAppBundle() Unpack(withAppPkg, unpackPkgPath, withAppPkgFiles); Unpack(Path.Combine(unpackPkgPath, "Payload", "test.app"), unpackAppPath, appFiles); Pack(unpackAppPath, packAppPath, appFiles); - }, new List { unpackPkgPath, unpackAppPath }); + }, [ unpackPkgPath, unpackAppPath ]); } [MacOSOnlyFact] @@ -112,7 +112,7 @@ public void UnpackPackSimpleInstallerPkg() { Unpack(simpleInstallerPkg, unpackPath, simpleInstallerFiles); Pack(unpackPath, packPath, simpleInstallerFiles); - }, new List { unpackPath, packPath }); + }, [ unpackPath, packPath ]); } [MacOSOnlyFact] @@ -130,7 +130,7 @@ public void UnpackPackSimplePkgInSimpleInstallerPkg() Unpack(componentPkgPath, unpackComponentPath, simplePkgFiles); Pack(unpackComponentPath, componentPkgPath, simplePkgFiles); Pack(unpackInstallerPath, packInstallerPath, simpleInstallerFiles); - }, new List { unpackInstallerPath, unpackComponentPath, packInstallerPath }); + }, [ unpackInstallerPath, unpackComponentPath, packInstallerPath ]); } [MacOSOnlyFact] @@ -152,8 +152,7 @@ public void UnpackPackAppBundleAndWithAppPkgInWithAppInstallerPkg() Pack(unpackAppPath, appPath, appFiles); Pack(unpackComponentPath, componentPkgPath, withAppPkgFiles); Pack(unpackInstallerPath, packInstallerPath, withAppInstallerFiles); - }, - new List { unpackInstallerPath, unpackComponentPath, unpackAppPath, packInstallerPath }); + }, [ unpackInstallerPath, unpackComponentPath, unpackAppPath, packInstallerPath ]); } private static void ExecuteWithCleanup(Action action, List cleanupPaths) @@ -198,7 +197,7 @@ private void Pack(string srcPath, string dstPath, string[] expectedFiles) ExecuteWithCleanup(() => { Unpack(dstPath, unpackPath, expectedFiles); - }, new List { unpackPath }); + }, [ unpackPath ]); } private bool RunPkgProcess(string inputPath, string outputPath, string action) diff --git a/src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs b/src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs index d62bca02f55..123bbf8bc62 100644 --- a/src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs +++ b/src/Microsoft.DotNet.MacOsPkg/ExecuteHelper.cs @@ -9,18 +9,13 @@ namespace Microsoft.DotNet.MacOsPkg { public static class ExecuteHelper { - public static string Run(string command, string arguments = "", string? workingDirectory = null) + public static string Run(string command, string arguments = "", string workingDirectory = "") { if (string.IsNullOrEmpty(command)) { throw new ArgumentNullException(nameof(command)); } - if (string.IsNullOrEmpty(workingDirectory)) - { - workingDirectory = Directory.GetCurrentDirectory(); - } - string output = string.Empty; string escapedArgs = $"-c \"{command} {arguments}\""; @@ -38,7 +33,7 @@ public static string Run(string command, string arguments = "", string? workingD return output; } - private static ProcessStartInfo CreateProcessStartInfo(string command, string arguments, string? workingDirectory) => + private static ProcessStartInfo CreateProcessStartInfo(string command, string arguments, string workingDirectory = "") => new ProcessStartInfo { FileName = command, From 30f1d401f44fcc07eeca8618e10669d0b911146f Mon Sep 17 00:00:00 2001 From: "Matt Mitchell (.NET)" Date: Wed, 20 Nov 2024 12:19:04 -0800 Subject: [PATCH 13/14] Slight refactoring --- src/Microsoft.DotNet.MacOsPkg/Program.cs | 25 ++++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.DotNet.MacOsPkg/Program.cs b/src/Microsoft.DotNet.MacOsPkg/Program.cs index ebf208bc7ff..c3698745abc 100644 --- a/src/Microsoft.DotNet.MacOsPkg/Program.cs +++ b/src/Microsoft.DotNet.MacOsPkg/Program.cs @@ -22,22 +22,22 @@ string dstPath = args[1]; string op = args[2]; +var cleanTarget = () => +{ + Utilities.CleanupPath(dstPath); + Utilities.CreateParentDirectory(dstPath); +}; + try { if (op == "unpack") { - if (!File.Exists(srcPath)) - { - throw new Exception("Input path must be a valid file"); - } - - if (!Utilities.IsPkg(srcPath) && !Utilities.IsAppBundle(srcPath)) + if (!File.Exists(srcPath) || (!Utilities.IsPkg(srcPath) && !Utilities.IsAppBundle(srcPath))) { - throw new Exception("Input path must be a .pkg or .app (zipped) file"); + throw new Exception("Input path must be an existing .pkg or .app (zipped) file."); } - Utilities.CleanupPath(dstPath); - Utilities.CreateParentDirectory(dstPath); + cleanTarget(); if (Utilities.IsPkg(srcPath)) { @@ -52,16 +52,15 @@ { if (!Directory.Exists(srcPath)) { - throw new Exception("Input path must be a valid directory"); + throw new Exception("Input path must be a valid directory."); } if (!Utilities.IsPkg(dstPath) && !Utilities.IsAppBundle(dstPath)) { - throw new Exception("Output path must be a .pkg or .app (zipped) file"); + throw new Exception("Output path must be a .pkg or .app (zipped) file."); } - Utilities.CleanupPath(dstPath); - Utilities.CreateParentDirectory(dstPath); + cleanTarget(); if (Utilities.IsPkg(dstPath)) { From 0ae6d6f40b114785e3020fd76f2d57975b313774 Mon Sep 17 00:00:00 2001 From: "Matt Mitchell (.NET)" Date: Thu, 21 Nov 2024 07:11:40 -0800 Subject: [PATCH 14/14] Remove NetFrameworkToolCurrent --- .../Microsoft.DotNet.MacOsPkg.Tests.csproj | 2 +- .../Microsoft.DotNet.MacOsPkg.csproj | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj b/src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj index bbd9e65c143..4a9589913a0 100644 --- a/src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj +++ b/src/Microsoft.DotNet.MacOsPkg.Tests/Microsoft.DotNet.MacOsPkg.Tests.csproj @@ -1,7 +1,7 @@ - $(NetToolCurrent);$(NetFrameworkToolCurrent) + $(NetToolCurrent) enable diff --git a/src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj b/src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj index d203ff40b72..972c7594915 100644 --- a/src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj +++ b/src/Microsoft.DotNet.MacOsPkg/Microsoft.DotNet.MacOsPkg.csproj @@ -1,16 +1,13 @@ - $(NetToolCurrent);$(NetFrameworkToolCurrent) + $(NetToolCurrent) Exe enable true MacOsPkg Arcade Build Tool MacOS Pkg false - - - true dotnet-macos-pkg