Use 'cp -a' when packaging on unix to preserve symlinks

This commit is contained in:
Caelan Sayler
2024-03-07 14:31:54 +00:00
parent 8b74e0fc74
commit e497a3d5ae
4 changed files with 60 additions and 44 deletions

View File

@@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Packaging.Abstractions;
@@ -6,6 +7,7 @@ using Velopack.Packaging.Exceptions;
namespace Velopack.Packaging.Unix.Commands;
[SupportedOSPlatform("osx")]
public class OsxBundleCommandRunner : ICommand<OsxBundleOptions>
{
private readonly ILogger _logger;
@@ -85,7 +87,7 @@ public class OsxBundleCommandRunner : ICommand<OsxBundleOptions>
File.Copy(icon, Path.Combine(builder.ResourcesDirectory, Path.GetFileName(icon)));
_logger.Debug("Copying application files into new '.app' bundle");
Utility.CopyFiles(new DirectoryInfo(packDirectory), new DirectoryInfo(builder.MacosDirectory));
new OsxBuildTools(_logger).CopyPreserveSymlinks(packDirectory, builder.MacosDirectory);
_logger.Debug("Bundle created successfully: " + builder.AppDirectory);

View File

@@ -70,6 +70,15 @@ public class OsxBuildTools
Log.Info(Exe.InvokeAndThrowIfNonZero("spctl", args2, null));
}
public void CopyPreserveSymlinks(string source, string dest)
{
if (!Directory.Exists(source)) {
throw new ArgumentException("Source directory does not exist: " + source);
}
Log.Debug($"Copying '{source}' to '{dest}' (preserving symlinks)");
Log.Debug(Exe.InvokeAndThrowIfNonZero("cp", new[] { "-a", source, dest }, null));
}
public void CreateInstallerPkg(string appBundlePath, string appTitle, string appId, IEnumerable<KeyValuePair<string, string>> extraContent,
string pkgOutputPath, string signIdentity, Action<int> progress)
{
@@ -88,7 +97,7 @@ public class OsxBuildTools
// copy .app to tmp folder
var bundleName = Path.GetFileName(appBundlePath);
var tmpBundlePath = Path.Combine(tmpPayload1, bundleName);
Utility.CopyFiles(new DirectoryInfo(appBundlePath), new DirectoryInfo(tmpBundlePath));
CopyPreserveSymlinks(appBundlePath, tmpBundlePath);
progress(10);
// create postinstall scripts to open app after install

View File

@@ -290,30 +290,55 @@ public abstract class PackageBuilder<T> : ICommand<T>
protected virtual void CopyFiles(DirectoryInfo source, DirectoryInfo target, Action<int> progress, bool excludeAnnoyances = false)
{
var excludes = Options.IncludePdb ? REGEX_EXCLUDES : REGEX_EXCLUDES_NO_PDB;
var numFiles = source.EnumerateFiles("*", SearchOption.AllDirectories).Count();
int currentFile = 0;
// On Windows, we can use our custom copy method to avoid annoying files.
// On OSX, it's a bit tricker because it's common practice to have internal symlinks which this will recursively copy as directories.
// We need to preserve the internal symlinks, so we will use 'cp -a' and then manually delete annoying files.
void CopyFilesInternal(DirectoryInfo source, DirectoryInfo target)
{
foreach (var fileInfo in source.GetFiles()) {
var path = Path.Combine(target.FullName, fileInfo.Name);
currentFile++;
progress((int) ((double) currentFile / numFiles * 100));
if (excludeAnnoyances && excludes.IsMatch(path)) {
Log.Debug("Skipping because matched exclude pattern: " + path);
continue;
}
fileInfo.CopyTo(path, true);
}
foreach (var sourceSubDir in source.GetDirectories()) {
var targetSubDir = target.CreateSubdirectory(sourceSubDir.Name);
CopyFilesInternal(sourceSubDir, targetSubDir);
}
if (!source.Exists) {
throw new ArgumentException("Source directory does not exist: " + source.FullName);
}
CopyFilesInternal(source, target);
if (VelopackRuntimeInfo.IsWindows) {
Log.Debug($"Copying '{source}' to '{target}' (built-in recursive)");
var excludes = Options.IncludePdb ? REGEX_EXCLUDES : REGEX_EXCLUDES_NO_PDB;
var numFiles = source.EnumerateFiles("*", SearchOption.AllDirectories).Count();
int currentFile = 0;
void CopyFilesInternal(DirectoryInfo source, DirectoryInfo target)
{
foreach (var fileInfo in source.GetFiles()) {
var path = Path.Combine(target.FullName, fileInfo.Name);
currentFile++;
progress((int) ((double) currentFile / numFiles * 100));
if (excludeAnnoyances && excludes.IsMatch(path)) {
Log.Debug("Skipping because matched exclude pattern: " + path);
continue;
}
fileInfo.CopyTo(path, true);
}
foreach (var sourceSubDir in source.GetDirectories()) {
var targetSubDir = target.CreateSubdirectory(sourceSubDir.Name);
CopyFilesInternal(sourceSubDir, targetSubDir);
}
}
CopyFilesInternal(source, target);
} else {
Log.Debug($"Copying '{source}' to '{target}' (preserving symlinks)");
Log.Debug(Exe.InvokeAndThrowIfNonZero("cp", new[] { "-a", source.FullName, target.FullName }, null));
if (excludeAnnoyances) {
foreach (var f in target.EnumerateFiles("*", SearchOption.AllDirectories)) {
if (REGEX_EXCLUDES.IsMatch(f.FullName)) {
Log.Debug("Deleting because matched exclude pattern: " + f.FullName);
f.Delete();
}
}
}
progress(100);
}
}
protected virtual void AddContentTypesAndRel(string nuspecPath)

View File

@@ -635,26 +635,6 @@ namespace Velopack
guid[right] = temp;
}
public static void CopyFiles(string source, string target)
{
CopyFiles(new DirectoryInfo(source), new DirectoryInfo(target));
}
public static void CopyFiles(DirectoryInfo source, DirectoryInfo target)
{
Directory.CreateDirectory(target.FullName);
foreach (var fileInfo in source.GetFiles()) {
var path = Path.Combine(target.FullName, fileInfo.Name);
fileInfo.CopyTo(path, true);
}
foreach (var sourceSubDir in source.GetDirectories()) {
var targetSubDir = target.CreateSubdirectory(sourceSubDir.Name);
CopyFiles(sourceSubDir, targetSubDir);
}
}
public static void MoveFile(string source, string dest, bool overwrite)
{
#if NET6_0_OR_GREATER