Skip to content

Commit 7263e09

Browse files
authored
feat: Enable truly self-contained single binary builds (#24)
* build: enable truly self-contained single binary - Add IncludeNativeLibrariesForSelfExtract to embed LibGit2Sharp native libraries - Remove Scrutor dependency, replace with explicit command registration - Refactor command registration into AddCommands() method for better organization - Add linux-arm64 to release matrix for ARM Linux support Now hypr builds as a single ~15MB binary that runs without .NET runtime installed on target machines. * feat: add scrutor back for terminal providers
1 parent e0a276b commit 7263e09

File tree

4 files changed

+76
-65
lines changed

4 files changed

+76
-65
lines changed

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ jobs:
1919
- os: ubuntu-latest
2020
rid: linux-x64
2121
name: linux-x64
22+
- os: ubuntu-latest
23+
rid: linux-arm64
24+
name: linux-arm64
2225
- os: windows-latest
2326
rid: win-x64
2427
name: windows-x64

src/Module.cs

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.CommandLine;
2+
using Hypr.Commands;
13
using Hypr.Configuration;
24
using Hypr.Hooks;
35
using Hypr.Services;
@@ -10,64 +12,74 @@ namespace Hypr;
1012

1113
internal static class Module
1214
{
13-
internal static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration) => services
14-
.Configure<TerminalConfig>(configuration.GetSection("terminal"))
15-
.Configure<WorktreeConfig>(configuration.GetSection("worktree"))
16-
.Configure<CleanupConfig>(configuration.GetSection("cleanup"))
17-
.Configure<ScriptsConfig>(configuration.GetSection("scripts"))
18-
.Configure<ConfirmationsConfig>(configuration.GetSection("confirmations"))
19-
.AddSingleton<StateService>()
20-
.AddSingleton<GitService>()
21-
.AddSingleton<GitHubService>()
22-
.AddSingleton<TerminalService>()
23-
.AddSingleton<VersionCheckService>()
24-
.AddSingleton<HookRunner>()
25-
.AddTerminalProviders();
15+
internal static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration) => services
16+
// Configuration sections
17+
.Configure<TerminalConfig>(configuration.GetSection("terminal"))
18+
.Configure<WorktreeConfig>(configuration.GetSection("worktree"))
19+
.Configure<CleanupConfig>(configuration.GetSection("cleanup"))
20+
.Configure<ScriptsConfig>(configuration.GetSection("scripts"))
21+
.Configure<ConfirmationsConfig>(configuration.GetSection("confirmations"))
22+
// Services
23+
.AddSingleton<StateService>()
24+
.AddSingleton<GitService>()
25+
.AddSingleton<GitHubService>()
26+
.AddSingleton<TerminalService>()
27+
.AddSingleton<VersionCheckService>()
28+
.AddSingleton<HookRunner>()
29+
// Commands and terminal providers (explicit registration for commands, Scrutor for terminal providers)
30+
.AddCommands()
31+
.AddTerminalProviders();
2632

27-
private static IServiceCollection AddTerminalProviders(this IServiceCollection services)
28-
{
29-
var currentPlatform = GetCurrentPlatform();
33+
internal static IServiceCollection AddCommands(this IServiceCollection services) => services
34+
.AddSingleton<Command, ListCommand>()
35+
.AddSingleton<Command, SwitchCommand>()
36+
.AddSingleton<Command, ConfigCommand>()
37+
.AddSingleton<Command, CleanupCommand>();
3038

31-
// Use Scrutor to scan and register all terminal providers that support the current platform
32-
services.Scan(scan => scan
33-
.FromAssemblyOf<ITerminalProvider>()
34-
.AddClasses(classes => classes
35-
.AssignableTo<ITerminalProvider>()
36-
.Where(type => SupportsCurrentPlatform(type, currentPlatform)))
37-
.AsImplementedInterfaces()
38-
.WithSingletonLifetime());
39+
private static IServiceCollection AddTerminalProviders(this IServiceCollection services)
40+
{
41+
var currentPlatform = GetCurrentPlatform();
3942

40-
return services;
41-
}
43+
// Use Scrutor to scan and register all terminal providers that support current platform
44+
services.Scan(scan => scan
45+
.FromAssemblyOf<ITerminalProvider>()
46+
.AddClasses(classes => classes
47+
.AssignableTo<ITerminalProvider>()
48+
.Where(type => SupportsCurrentPlatform(type, currentPlatform)))
49+
.AsImplementedInterfaces()
50+
.WithSingletonLifetime());
4251

43-
private static Platform GetCurrentPlatform()
44-
{
45-
if (PlatformUtils.IsWindows) return Platform.Windows;
46-
if (PlatformUtils.IsMacOS) return Platform.MacOS;
47-
if (PlatformUtils.IsLinux) return Platform.Linux;
48-
return Platform.None;
49-
}
52+
return services;
53+
}
5054

51-
private static bool SupportsCurrentPlatform(Type providerType, Platform currentPlatform)
52-
{
53-
return GetSupportedPlatformsForType(providerType).HasFlag(currentPlatform);
54-
}
55+
private static Platform GetCurrentPlatform()
56+
{
57+
if (PlatformUtils.IsWindows) return Platform.Windows;
58+
if (PlatformUtils.IsMacOS) return Platform.MacOS;
59+
if (PlatformUtils.IsLinux) return Platform.Linux;
60+
return Platform.None;
61+
}
62+
63+
private static bool SupportsCurrentPlatform(Type providerType, Platform currentPlatform)
64+
{
65+
return GetSupportedPlatformsForType(providerType).HasFlag(currentPlatform);
66+
}
5567

56-
private static Platform GetSupportedPlatformsForType(Type providerType)
68+
private static Platform GetSupportedPlatformsForType(Type providerType)
69+
{
70+
// Map known provider types to their supported platforms
71+
return providerType.Name switch
5772
{
58-
// Map known provider types to their supported platforms
59-
return providerType.Name switch
60-
{
61-
nameof(WindowsTerminalProvider) => Platform.Windows,
62-
nameof(ITerm2Provider) => Platform.MacOS,
63-
nameof(TerminalAppProvider) => Platform.MacOS,
64-
nameof(GnomeTerminalProvider) => Platform.Linux,
65-
nameof(TmuxProvider) => Platform.Linux | Platform.MacOS,
66-
nameof(VSCodeProvider) => Platform.All,
67-
nameof(CursorProvider) => Platform.All,
68-
nameof(EchoProvider) => Platform.All,
69-
nameof(InplaceProvider) => Platform.All,
70-
_ => Platform.None
71-
};
72-
}
73-
}
73+
nameof(WindowsTerminalProvider) => Platform.Windows,
74+
nameof(ITerm2Provider) => Platform.MacOS,
75+
nameof(TerminalAppProvider) => Platform.MacOS,
76+
nameof(GnomeTerminalProvider) => Platform.Linux,
77+
nameof(TmuxProvider) => Platform.Linux | Platform.MacOS,
78+
nameof(VSCodeProvider) => Platform.All,
79+
nameof(CursorProvider) => Platform.All,
80+
nameof(EchoProvider) => Platform.All,
81+
nameof(InplaceProvider) => Platform.All,
82+
_ => Platform.None
83+
};
84+
}
85+
}

src/Program.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.CommandLine;
2-
using Hypr.Commands;
32
using Hypr.Configuration;
43
using Hypr.Logging;
54
using Microsoft.Extensions.Configuration;
@@ -26,14 +25,9 @@
2625
// Register configuration
2726
builder.Services.AddSingleton<IConfiguration>(configuration);
2827

29-
// Register services and configuration sections
28+
// Register services, configuration sections, and commands
3029
builder.Services.AddServices(builder.Configuration);
3130

32-
// Automatically discover and register all commands
33-
builder.Services.Scan(s => s.FromAssemblyOf<ListCommand>()
34-
.AddClasses(c => c.AssignableTo<Command>())
35-
.As<Command>());
36-
3731
var host = builder.Build();
3832
var rootCommand = new RootCommand("hypr - Git worktree manager");
3933
rootCommand.Options.Add(new DebugOption());

src/hypr.csproj

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
<PublishTrimmed>true</PublishTrimmed>
3030
<TrimMode>link</TrimMode>
3131
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
32+
<!-- Embed native libraries (LibGit2Sharp) into single-file and auto-extract at runtime -->
33+
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
3234
</PropertyGroup>
3335

3436
<ItemGroup>
35-
<PackageReference Include="Scrutor" Version="6.1.0" />
37+
<PackageReference Include="Scrutor" Version="7.0.0" />
3638
<PackageReference Include="Serilog.Extensions.Hosting" Version="10.0.0" />
3739
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
3840
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
@@ -50,7 +52,7 @@
5052
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.0" />
5153
</ItemGroup>
5254

53-
<ItemGroup>
54-
<None Include="../README.md" Pack="true" PackagePath="README.md" />
55-
</ItemGroup>
55+
<ItemGroup>
56+
<None Include="../README.md" Pack="true" PackagePath="README.md" />
57+
</ItemGroup>
5658
</Project>

0 commit comments

Comments
 (0)