Moved script running to a helper method

This commit is contained in:
Carl Johnsen
2026-02-23 21:04:46 +01:00
parent db7252b66f
commit 3b3aafc123
@@ -64,55 +64,13 @@ namespace Duplicati.UnitTest.DiskImage
// Create a raw disk image using hdiutil
// Use UDIF format with "Free Space" filesystem (unformatted)
var psi = new ProcessStartInfo
{
FileName = "hdiutil",
Arguments = $"create -size {sizeB} -type UDIF -layout NONE -o \"{imagePath}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
RunProcess("hdiutil", $"create -size {sizeB} -type UDIF -layout NONE -o \"{imagePath}\"");
using (var process = new Process { StartInfo = psi })
{
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
var output = RunProcess("hdiutil", $"attach -nomount \"{imagePath}\"");
if (process.ExitCode != 0)
throw new InvalidOperationException($"Failed to create disk image '{imagePath}': {error}");
}
// Attach the disk image without mounting
psi = new ProcessStartInfo
{
FileName = "hdiutil",
Arguments = $"attach -nomount \"{imagePath}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
string diskDevice;
using (var process = new Process { StartInfo = psi })
{
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"Failed to attach disk image: {error}");
// Parse the disk device from output (e.g., "/dev/disk4")
diskDevice = output.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault()?.Trim()
?? throw new InvalidOperationException("Failed to get disk device from hdiutil attach output");
_lastDiskDevice = diskDevice;
}
// Parse the disk device from output (e.g., "/dev/disk4")
var diskDevice = output.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault()?.Trim()
?? throw new InvalidOperationException("Failed to get disk device from hdiutil attach output");
// Return the raw device path for direct I/O
return diskDevice.Replace("/dev/disk", "/dev/rdisk");
@@ -120,20 +78,7 @@ namespace Duplicati.UnitTest.DiskImage
private string[] GetPartitionNames(string diskIdentifier)
{
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"list {diskIdentifier}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
var output = RunProcess("diskutil", $"list {diskIdentifier}");
// Very hardcoded to disks with < 10 partitions and no identifiers with spaces. Should be sufficient for test purposes.
return output
@@ -154,20 +99,7 @@ namespace Duplicati.UnitTest.DiskImage
foreach (var partition in partitions)
{
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"info /dev/{partition}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
var output = RunProcess("diskutil", $"info /dev/{partition}");
var mountLine = output
.Split('\n')
@@ -208,24 +140,7 @@ namespace Duplicati.UnitTest.DiskImage
: ["Free Space \"\" 0"];
var partitionArgs = string.Join(" ", partitionStrings);
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"partitionDisk {diskIdentifier} {tableType.ToString().ToUpperInvariant()} {partitionArgs}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"Failed to initialize disk: {error}");
RunProcess("diskutil", $"partitionDisk {diskIdentifier} {tableType.ToString().ToUpperInvariant()} {partitionArgs}");
if (partitions.Length == 0)
return [];
@@ -242,24 +157,7 @@ namespace Duplicati.UnitTest.DiskImage
return mountPoints;
// Mount all volumes on the disk
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"mountDisk {diskIdentifier}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"Failed to mount disk: {error}");
RunProcess("diskutil", $"mountDisk {diskIdentifier}");
// Find the mount points for the mounted partitions
return GetMountPoints(diskIdentifier);
@@ -268,42 +166,14 @@ namespace Duplicati.UnitTest.DiskImage
public void Unmount(string diskIdentifier)
{
// Unmount all volumes on the disk
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"unmountDisk {diskIdentifier}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"Failed to mount disk: {error}");
RunProcess("diskutil", $"unmountDisk {diskIdentifier}");
}
/// <inheritdoc />
public void FlushDisk(string diskIdentifier)
{
// On macOS, use sync to flush all filesystem buffers
var psi = new ProcessStartInfo
{
FileName = "sync",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
process.WaitForExit();
RunProcess("sync", "");
}
/// <inheritdoc />
@@ -311,25 +181,7 @@ namespace Duplicati.UnitTest.DiskImage
{
if (diskIdentifier is null)
{
var psi = new ProcessStartInfo
{
FileName = "hdiutil",
Arguments = $"info",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
{
throw new InvalidOperationException($"Failed to get hdiutil info: {process.StandardError.ReadToEnd()}");
}
var output = RunProcess("hdiutil", $"info");
diskIdentifier = output
.Split("================================================")
@@ -367,23 +219,7 @@ namespace Duplicati.UnitTest.DiskImage
try
{
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"eject {diskIdentifier}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
TestContext.Progress.WriteLine($"Warning: Failed to eject disk {diskIdentifier}: {error}");
RunProcess("diskutil", $"eject {diskIdentifier}");
}
catch (Exception ex)
{
@@ -407,20 +243,7 @@ namespace Duplicati.UnitTest.DiskImage
// On macOS, check if running as root (UID 0)
try
{
var psi = new ProcessStartInfo
{
FileName = "id",
Arguments = "-u",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd().Trim();
process.WaitForExit();
var output = RunProcess("id", "-u");
if (int.TryParse(output, out int uid))
{
@@ -438,24 +261,7 @@ namespace Duplicati.UnitTest.DiskImage
/// <inheritdoc />
public Proprietary.DiskImage.PartitionTableGeometry GetPartitionTable(string diskIdentifier)
{
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"info {diskIdentifier}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"Process diskutil exited with code {process.ExitCode}: {error}");
var output = RunProcess("diskutil", $"info {diskIdentifier}");
var lines = output
.Split('\n')
@@ -516,24 +322,7 @@ namespace Duplicati.UnitTest.DiskImage
var partitions = new List<PartitionGeometry>();
foreach (var name in names)
{
var psi = new ProcessStartInfo
{
FileName = "diskutil",
Arguments = $"info /dev/{name}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
throw new InvalidOperationException($"Process diskutil exited with code {process.ExitCode}: {error}");
var output = RunProcess("diskutil", $"info /dev/{name}");
var lines = output
.Split('\n')
@@ -601,6 +390,35 @@ namespace Duplicati.UnitTest.DiskImage
return partitions.ToArray();
}
private string RunProcess(string fileName, string arguments)
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi };
process.Start();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
{
Console.WriteLine($"Error running process {fileName} {arguments}");
Console.WriteLine($"Error: {error}");
Console.WriteLine($"Output: {output}");
throw new InvalidOperationException($"Process {fileName} exited with code {process.ExitCode}: {error}");
}
return output;
}
/// <inheritdoc />
public void Dispose()
{