Skip to content

Commit

Permalink
ZeroInstall.Client: Map exit codes to exception types
Browse files Browse the repository at this point in the history
  • Loading branch information
bastianeicher committed Jan 17, 2022
1 parent 803202d commit 660a11f
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 92 deletions.
30 changes: 0 additions & 30 deletions src/Client/IProcessLauncher.cs

This file was deleted.

23 changes: 0 additions & 23 deletions src/Client/ProcessLauncher.cs

This file was deleted.

33 changes: 13 additions & 20 deletions src/Client/ZeroInstallClient.cs
Expand Up @@ -15,20 +15,17 @@ namespace ZeroInstall.Client;
public class ZeroInstallClient : IZeroInstallClient
{
private readonly ISubProcess _subProcess;
private readonly IProcessLauncher _launcher;
private readonly IProcessLauncher? _guiLauncher;
private readonly ISubProcess? _guiSubProcess;

/// <summary>
/// Creates a new Zero Install client.
/// </summary>
/// <param name="subProcess">Used to launch <c>0install</c>, captures its output and waits until it has terminated.</param>
/// <param name="launcher">Used to launch <c>0install</c> as ane external process.</param>
/// <param name="guiLauncher">Used to launch <c>0install-win</c> as ane external process.</param>
internal ZeroInstallClient(ISubProcess subProcess, IProcessLauncher launcher, IProcessLauncher? guiLauncher = null)
/// <param name="subProcess">Used to launch <c>0install</c> as a child process.</param>
/// <param name="guiSubProcess">Used to launch <c>0install-win</c> as a child process.</param>
internal ZeroInstallClient(ISubProcess subProcess, ISubProcess? guiSubProcess = null)
{
_subProcess = subProcess;
_launcher = launcher;
_guiLauncher = guiLauncher;
_guiSubProcess = guiSubProcess;
}

/// <summary>
Expand All @@ -38,9 +35,8 @@ internal ZeroInstallClient(ISubProcess subProcess, IProcessLauncher launcher, IP
/// <param name="guiCommandLine">The optional command-line used to launch <c>0install-win</c>. Whitespace must be properly escaped.</param>
public ZeroInstallClient(string commandLine, string? guiCommandLine = null)
: this(
subProcess: new SubProcess(ProcessUtils.FromCommandLine(commandLine)),
launcher: new ProcessLauncher(commandLine),
guiLauncher: guiCommandLine?.To(x=> new ProcessLauncher(x)))
subProcess: new ZeroInstallProcess(commandLine),
guiSubProcess: guiCommandLine?.To(x=> new ZeroInstallProcess(x)))
{}

/// <summary>
Expand Down Expand Up @@ -81,7 +77,7 @@ public async Task<Selections> DownloadAsync(Requirements requirements, bool refr
if (refresh) args.Add("--refresh");
args.AddRange(requirements.ToCommandLineArgs());

if (_guiLauncher == null)
if (_guiSubProcess == null)
{
args.Add("--xml");
string output = await Task.Run(() => _subProcess.RunAndCapture(args.ToArray()));
Expand All @@ -90,7 +86,7 @@ public async Task<Selections> DownloadAsync(Requirements requirements, bool refr
else
{
args.Add("--background");
await Task.Run(() => _guiLauncher.Run(args.ToArray()));
await Task.Run(() => _guiSubProcess.Run(args.ToArray()));
return await SelectAsync(requirements, offline: true);
}
}
Expand All @@ -104,10 +100,8 @@ public void Run(Requirements requirements, bool refresh = false, bool needsTermi
args.AddRange(requirements.ToCommandLineArgs());
args.AddRange(arguments);

if (needsTerminal || _guiLauncher == null)
_launcher.Start(args.ToArray());
else
_guiLauncher.Start(args.ToArray());
var launcher = needsTerminal ? _subProcess : _guiSubProcess ?? _subProcess;
launcher.Start(args.ToArray());
}

/// <inheritdoc/>
Expand All @@ -118,9 +112,8 @@ public Process RunWithProcess(Requirements requirements, bool refresh = false, b
args.AddRange(requirements.ToCommandLineArgs());
args.AddRange(arguments);

return needsTerminal || _guiLauncher == null
? _launcher.Start(args.ToArray())
: _guiLauncher.Start(args.ToArray());
var launcher = needsTerminal ? _subProcess : _guiSubProcess ?? _subProcess;
return launcher.Start(args.ToArray());
}

/// <inheritdoc/>
Expand Down
36 changes: 36 additions & 0 deletions src/Client/ZeroInstallProcess.cs
@@ -0,0 +1,36 @@
// Copyright Bastian Eicher et al.
// Licensed under the GNU Lesser Public License

using NanoByte.Common.Streams;

namespace ZeroInstall.Client;

/// <summary>
/// Runs Zero Install as a sub/child process.
/// </summary>
internal class ZeroInstallProcess : SubProcess
{
public ZeroInstallProcess(string commandLine)
: base(ProcessUtils.FromCommandLine(commandLine))
{}

protected override void HandleExitCode(int exitCode)
{
switch (exitCode)
{
case 1: // No changes
break;
case 10: // Web error
throw new WebException();
case 11: // Access denied
throw new UnauthorizedAccessException();
case 12: // IO error
throw new IOException();
case 100: // User canceled
throw new OperationCanceledException();
default:
base.HandleExitCode(exitCode);
return;
}
}
}
20 changes: 9 additions & 11 deletions src/UnitTests/Client/ZeroInstallClientGuiTest.cs
Expand Up @@ -12,24 +12,22 @@ namespace ZeroInstall.Client;
/// </summary>
public class ZeroInstallClientGuiTest : TestWithMocks
{
private readonly Mock<ISubProcess> _subProcessMock;
private readonly Mock<IProcessLauncher> _guiLauncherMock;
private readonly Mock<ISubProcess> _subProcessMock, _guiSubProcessMock;
private readonly ZeroInstallClient _client;

public ZeroInstallClientGuiTest()
{
_subProcessMock = CreateMock<ISubProcess>();
_guiLauncherMock = CreateMock<IProcessLauncher>();
_client = new(_subProcessMock.Object, CreateMock<IProcessLauncher>().Object, _guiLauncherMock.Object);
_guiSubProcessMock = CreateMock<ISubProcess>();
_client = new(_subProcessMock.Object, _guiSubProcessMock.Object);
}

[Fact]
public async Task Download()
{
var selections = SelectionsTest.CreateTestSelections();

_guiLauncherMock.Setup(x => x.Run("download", "--batch", "--refresh", FeedTest.Test1Uri.ToStringRfc(), "--background"))
.Returns(0);
_guiSubProcessMock.Setup(x => x.Run("download", "--batch", "--refresh", FeedTest.Test1Uri.ToStringRfc(), "--background"));

_subProcessMock.Setup(x => x.RunAndCapture(null, "select", "--batch", "--xml", "--offline", FeedTest.Test1Uri.ToStringRfc()))
.Returns(selections.ToXmlString());
Expand All @@ -41,18 +39,18 @@ public async Task Download()
[Fact]
public void Run()
{
_guiLauncherMock.Setup(x => x.Start("run", "--no-wait", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(new Process());
_guiSubProcessMock.Setup(x => x.Start("run", "--no-wait", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(new Process());

_client.Run(FeedTest.Test1Uri, arguments: "--arg");
}

[Fact]
public void RunAndWait()
public void RunWithProcess()
{
var process = new Process();
_guiLauncherMock.Setup(x => x.Start("run", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(process);
_guiSubProcessMock.Setup(x => x.Start("run", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(process);

_client.RunWithProcess(FeedTest.Test1Uri, arguments: "--arg")
.Should().BeSameAs(process);
Expand Down
14 changes: 6 additions & 8 deletions src/UnitTests/Client/ZeroInstallClientTest.cs
Expand Up @@ -14,14 +14,12 @@ namespace ZeroInstall.Client;
public class ZeroInstallClientTest : TestWithMocks
{
private readonly Mock<ISubProcess> _subProcessMock;
private readonly Mock<IProcessLauncher> _launcherMock;
private readonly ZeroInstallClient _client;

public ZeroInstallClientTest()
{
_subProcessMock = CreateMock<ISubProcess>();
_launcherMock = CreateMock<IProcessLauncher>();
_client = new(_subProcessMock.Object, _launcherMock.Object);
_client = new(_subProcessMock.Object);
}

[Fact]
Expand Down Expand Up @@ -51,18 +49,18 @@ public async Task Download()
[Fact]
public void Run()
{
_launcherMock.Setup(x => x.Start("run", "--no-wait", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(new Process());
_subProcessMock.Setup(x => x.Start("run", "--no-wait", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(new Process());

_client.Run(FeedTest.Test1Uri, arguments: "--arg");
}

[Fact]
public void RunAndWait()
public void RunWithProcess()
{
var process = new Process();
_launcherMock.Setup(x => x.Start("run", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(process);
_subProcessMock.Setup(x => x.Start("run", FeedTest.Test1Uri.ToStringRfc(), "--arg"))
.Returns(process);

_client.RunWithProcess(FeedTest.Test1Uri, arguments: "--arg")
.Should().BeSameAs(process);
Expand Down

0 comments on commit 660a11f

Please sign in to comment.