Skip to content

Commit a2a222c

Browse files
committed
feat: implement Homebrew package manager and related process handling
1 parent df0146c commit a2a222c

5 files changed

Lines changed: 141 additions & 0 deletions

File tree

Directory.Packages.props

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
</PropertyGroup>
5+
6+
<ItemGroup>
7+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
8+
<PackageVersion Include="ProcessX" Version="1.5.6" />
9+
<PackageVersion Include="R3" Version="1.3.0" />
10+
<PackageVersion Include="Spectre.Console" Version="0.54.0" />
11+
<PackageVersion Include="System.CommandLine" Version="2.0.0" />
12+
<PackageVersion Include="Tomlyn" Version="0.19.0" />
13+
14+
<PackageVersion Include="AwesomeAssertions" Version="9.3.0" />
15+
<PackageVersion Include="AwesomeAssertions.Analyzers" Version="9.0.8" />
16+
<PackageVersion Include="Microsoft.Testing.Platform" Version="2.0.2" />
17+
<PackageVersion Include="Verify.MSTest" Version="31.7.1" />
18+
</ItemGroup>
19+
</Project>

src/DevEnv.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@
88
<InvariantGlobalization>true</InvariantGlobalization>
99
</PropertyGroup>
1010

11+
<ItemGroup>
12+
<PackageReference Include="R3" />
13+
</ItemGroup>
14+
1115
</Project>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace DevEnv;
6+
7+
public sealed class HomebrewPackageManager : IPackageManager
8+
{
9+
public string Name { get; } = "Homebrew";
10+
11+
public Task InstallPackageAsync(string packageName, CancellationToken cancellationToken)
12+
{
13+
Process process = new("brew", "install", packageName);
14+
15+
return process.ExecuteAsync(cancellationToken);
16+
}
17+
18+
public Task UpdateAsync(CancellationToken cancellationToken)
19+
{
20+
Process process = new("brew", "update");
21+
22+
return process.ExecuteAsync(cancellationToken);
23+
}
24+
public async Task<bool> CheckIfPackageIsInstalledAsync(string packageName,CancellationToken cancellationToken)
25+
{
26+
Process processService = new("brew", "list", "--versions", packageName);
27+
28+
int exitCode = await processService.ExecuteAsync(cancellationToken).ConfigureAwait(false);
29+
30+
return exitCode == 0;
31+
}
32+
33+
public Task UpdatePackageAsync(string packageName, CancellationToken cancellationToken)
34+
{
35+
throw new NotImplementedException();
36+
}
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
4+
namespace DevEnv;
5+
6+
public interface IPackageManager
7+
{
8+
public string Name { get; }
9+
10+
public Task UpdateAsync(CancellationToken cancellationToken);
11+
12+
public Task UpdatePackageAsync(string packageName, CancellationToken cancellationToken);
13+
14+
public Task InstallPackageAsync(string packageName, CancellationToken cancellationToken);
15+
16+
public Task<bool> CheckIfPackageIsInstalledAsync(string packageName, CancellationToken cancellationToken);
17+
}

src/Process.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Diagnostics;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using R3;
5+
6+
namespace DevEnv;
7+
8+
public sealed class Process(string command, params string[] args)
9+
{
10+
private readonly ReplaySubject<string> stdOut = new();
11+
12+
private readonly ReplaySubject<string> stdErr = new();
13+
14+
private readonly string command = command;
15+
16+
private readonly string[] args = args;
17+
18+
public Observable<string> StdOut => stdOut;
19+
20+
public Observable<string> StdErr => stdErr;
21+
22+
public async Task<int> ExecuteAsync(CancellationToken cancellationToken)
23+
{
24+
ProcessStartInfo processStartInfo = new()
25+
{
26+
FileName = command,
27+
Arguments = string.Join(' ', args),
28+
RedirectStandardOutput = true,
29+
RedirectStandardError = true,
30+
UseShellExecute = false,
31+
CreateNoWindow = true,
32+
};
33+
34+
using System.Diagnostics.Process process = new()
35+
{
36+
StartInfo = processStartInfo,
37+
};
38+
39+
process.OutputDataReceived += (sender, e) =>
40+
{
41+
if (e.Data != null)
42+
{
43+
stdOut.OnNext(e.Data);
44+
}
45+
};
46+
47+
process.ErrorDataReceived += (sender, e) =>
48+
{
49+
if (e.Data != null)
50+
{
51+
stdErr.OnNext(e.Data);
52+
}
53+
};
54+
55+
process.Start();
56+
57+
process.BeginOutputReadLine();
58+
process.BeginErrorReadLine();
59+
60+
await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
61+
62+
return process.ExitCode;
63+
}
64+
}

0 commit comments

Comments
 (0)