Skip to content

Commit 9920b9b

Browse files
committed
feat(system): add emerge support to install resolvers for Gentoo
Mirrors the openSUSE/zypper pattern from PR #1946. Without this, the detection work in 0853d11 marks Gentoo as Supported=true but every component resolver in internal/installcmd/resolver.go falls through to the 'unsupported package manager' default error, leaving the Gentoo user with a worse experience than the clean rejection they got before detection was added. Changes: - internal/installcmd/resolver.go: add 'emerge' case to uvInstallHint (sudo emerge --ask=n --quiet uv) and ResolveDependencyInstall (sudo emerge --ask=n --quiet <dep>); add 'emerge' to the combined apt/pacman/dnf case in resolveOpenCodeInstall and resolveGGAInstall (Linux flows are npm/git-based, so the PM grouping is sufficient). resolveEngramInstall is intentionally untouched (engram uses direct binary download on non-brew, same as zypper). - internal/system/install_deps.go: add 'emerge' case to installHintGit, installHintCurl, installHintNode, installHintGo, installCommandsGit, installCommandsCurl, installCommandsNode, and installCommandsGo. Portage package names match the simple unqualified form used by zypper (git, curl, nodejs, dev-lang/go) and emerge flags use --ask=n --quiet for non-interactive behavior matching zypper's --non-interactive. - internal/installcmd/resolver_test.go: add gentoo test cases for ResolveDependencyInstall, resolveOpenCodeInstall (opencode), and resolveGGAInstall (gga), mirroring the existing fedora/arch/opensuse matrix entries. - internal/components/gga/install_test.go: add gentoo test case for InstallCommand, mirroring the fedora entry with the current 6-step install flow (mkdir + git init + git fetch + git checkout + bash). Addresses review feedback from @Alan-TheGentleman on #1857 (Gentoo cannot be marked Supported=true until install paths exist for emerge) and @dnlrsls (restore the required Automated Checks section in the PR body).
1 parent 257a1d4 commit 9920b9b

4 files changed

Lines changed: 59 additions & 2 deletions

File tree

internal/components/gga/install_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ func TestInstallCommandByProfile(t *testing.T) {
109109
{"bash", "/tmp/gentleman-guardian-angel/install.sh"},
110110
},
111111
},
112+
{
113+
name: "gentoo uses git clone and install.sh",
114+
profile: system.PlatformProfile{OS: "linux", LinuxDistro: system.LinuxDistroGentoo, PackageManager: "emerge"},
115+
want: [][]string{
116+
{"rm", "-rf", "/tmp/gentleman-guardian-angel"},
117+
{"mkdir", "-p", "/tmp/gentleman-guardian-angel"},
118+
{"git", "init", "/tmp/gentleman-guardian-angel"},
119+
{"git", "-C", "/tmp/gentleman-guardian-angel", "fetch", "--depth=1", "https://github.com/Gentleman-Programming/gentleman-guardian-angel.git", "refs/tags/v" + versions.GGAVersion + ":refs/tags/v" + versions.GGAVersion},
120+
{"git", "-C", "/tmp/gentleman-guardian-angel", "checkout", "-f", "refs/tags/v" + versions.GGAVersion},
121+
{"bash", "/tmp/gentleman-guardian-angel/install.sh"},
122+
},
123+
},
112124
{
113125
name: "unsupported package manager returns error",
114126
profile: system.PlatformProfile{

internal/installcmd/resolver.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ func uvInstallHint(profile system.PlatformProfile) string {
179179
return "sudo pacman -S --noconfirm uv"
180180
case "dnf":
181181
return "sudo dnf install -y uv"
182+
case "emerge":
183+
return "sudo emerge --ask=n --quiet uv"
182184
case "winget":
183185
return "winget install --id astral-sh.uv -e --accept-source-agreements --accept-package-agreements"
184186
default:
@@ -211,6 +213,8 @@ func (profileResolver) ResolveDependencyInstall(profile system.PlatformProfile,
211213
return CommandSequence{{"sudo", "pacman", "-S", "--noconfirm", dependency}}, nil
212214
case "dnf":
213215
return CommandSequence{{"sudo", "dnf", "install", "-y", dependency}}, nil
216+
case "emerge":
217+
return CommandSequence{{"sudo", "emerge", "--ask=n", "--quiet", dependency}}, nil
214218
case "winget":
215219
return CommandSequence{{"winget", "install", "--id", dependency, "-e", "--accept-source-agreements", "--accept-package-agreements"}}, nil
216220
default:
@@ -233,7 +237,7 @@ func resolveOpenCodeInstall(profile system.PlatformProfile) (CommandSequence, er
233237
return CommandSequence{
234238
{"brew", "install", "anomalyco/tap/opencode"},
235239
}, nil
236-
case "apt", "pacman", "dnf":
240+
case "apt", "pacman", "dnf", "emerge":
237241
pkg := "opencode-ai@" + versions.OpenCode
238242
if profile.NpmWritable {
239243
return CommandSequence{{"npm", "install", "-g", "--ignore-scripts", pkg}}, nil
@@ -260,7 +264,7 @@ func resolveGGAInstall(profile system.PlatformProfile) (CommandSequence, error)
260264
{"brew", "tap", "Gentleman-Programming/homebrew-tap"},
261265
{"brew", "reinstall", "gga"},
262266
}, nil
263-
case "apt", "pacman", "dnf":
267+
case "apt", "pacman", "dnf", "emerge":
264268
const tmpDir = "/tmp/gentleman-guardian-angel"
265269
tagRef := "refs/tags/v" + versions.GGAVersion
266270
return CommandSequence{

internal/installcmd/resolver_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ func TestResolveDependencyInstall(t *testing.T) {
179179
dep: "somepkg",
180180
want: CommandSequence{{"sudo", "dnf", "install", "-y", "somepkg"}},
181181
},
182+
{
183+
name: "gentoo resolves emerge command",
184+
profile: system.PlatformProfile{OS: "linux", LinuxDistro: system.LinuxDistroGentoo, PackageManager: "emerge"},
185+
dep: "somepkg",
186+
want: CommandSequence{{"sudo", "emerge", "--ask=n", "--quiet", "somepkg"}},
187+
},
182188
{
183189
name: "windows resolves winget command",
184190
profile: system.PlatformProfile{OS: "windows", PackageManager: "winget"},
@@ -360,6 +366,12 @@ func TestResolveAgentInstall(t *testing.T) {
360366
agent: model.AgentOpenCode,
361367
want: CommandSequence{{"npm", "install", "-g", "--ignore-scripts", "opencode-ai@" + versions.OpenCode}},
362368
},
369+
{
370+
name: "opencode on gentoo system npm uses sudo",
371+
profile: system.PlatformProfile{OS: "linux", LinuxDistro: system.LinuxDistroGentoo, PackageManager: "emerge"},
372+
agent: model.AgentOpenCode,
373+
want: CommandSequence{{"sudo", "npm", "install", "-g", "--ignore-scripts", "opencode-ai@" + versions.OpenCode}},
374+
},
363375
{
364376
name: "claude-code on windows uses npm without sudo",
365377
profile: system.PlatformProfile{OS: "windows", PackageManager: "winget", NpmWritable: true},
@@ -658,6 +670,19 @@ func TestResolveComponentInstall(t *testing.T) {
658670
{"bash", "/tmp/gentleman-guardian-angel/install.sh"},
659671
},
660672
},
673+
{
674+
name: "gga on gentoo uses git clone and install.sh",
675+
profile: system.PlatformProfile{OS: "linux", LinuxDistro: system.LinuxDistroGentoo, PackageManager: "emerge"},
676+
component: model.ComponentGGA,
677+
want: CommandSequence{
678+
{"rm", "-rf", "/tmp/gentleman-guardian-angel"},
679+
{"mkdir", "-p", "/tmp/gentleman-guardian-angel"},
680+
{"git", "init", "/tmp/gentleman-guardian-angel"},
681+
{"git", "-C", "/tmp/gentleman-guardian-angel", "fetch", "--depth=1", "https://github.com/Gentleman-Programming/gentleman-guardian-angel.git", "refs/tags/v" + versions.GGAVersion + ":refs/tags/v" + versions.GGAVersion},
682+
{"git", "-C", "/tmp/gentleman-guardian-angel", "checkout", "-f", "refs/tags/v" + versions.GGAVersion},
683+
{"bash", "/tmp/gentleman-guardian-angel/install.sh"},
684+
},
685+
},
661686
{
662687
name: "engram on windows returns error (uses DownloadLatestBinary instead)",
663688
profile: system.PlatformProfile{OS: "windows", PackageManager: "winget"},

internal/system/install_deps.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ func installHintGit(profile PlatformProfile) string {
1515
return "sudo pacman -S --noconfirm git"
1616
case profile.PackageManager == "dnf":
1717
return "sudo dnf install -y git"
18+
case profile.PackageManager == "emerge":
19+
return "sudo emerge --ask=n --quiet git"
1820
default:
1921
return "install git from https://git-scm.com/"
2022
}
@@ -33,6 +35,8 @@ func installHintCurl(profile PlatformProfile) string {
3335
return "sudo pacman -S --noconfirm curl"
3436
case profile.PackageManager == "dnf":
3537
return "sudo dnf install -y curl"
38+
case profile.PackageManager == "emerge":
39+
return "sudo emerge --ask=n --quiet curl"
3640
default:
3741
return "install curl from https://curl.se/"
3842
}
@@ -51,6 +55,8 @@ func installHintNode(profile PlatformProfile) string {
5155
return "sudo pacman -S --noconfirm nodejs npm"
5256
case profile.PackageManager == "dnf":
5357
return "curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash - && sudo dnf install -y nodejs"
58+
case profile.PackageManager == "emerge":
59+
return "sudo emerge --ask=n --quiet nodejs"
5460
default:
5561
return "install node from https://nodejs.org/"
5662
}
@@ -80,6 +86,8 @@ func installHintGo(profile PlatformProfile) string {
8086
return "sudo pacman -S --noconfirm go"
8187
case profile.PackageManager == "dnf":
8288
return "sudo dnf install -y golang"
89+
case profile.PackageManager == "emerge":
90+
return "sudo emerge --ask=n --quiet dev-lang/go"
8391
default:
8492
return "install go from https://go.dev/dl/"
8593
}
@@ -140,6 +148,8 @@ func installCommandsGit(profile PlatformProfile) [][]string {
140148
return [][]string{{"sudo", "pacman", "-S", "--noconfirm", "git"}}
141149
case profile.PackageManager == "dnf":
142150
return [][]string{{"sudo", "dnf", "install", "-y", "git"}}
151+
case profile.PackageManager == "emerge":
152+
return [][]string{{"sudo", "emerge", "--ask=n", "--quiet", "git"}}
143153
default:
144154
return nil
145155
}
@@ -158,6 +168,8 @@ func installCommandsCurl(profile PlatformProfile) [][]string {
158168
return [][]string{{"sudo", "pacman", "-S", "--noconfirm", "curl"}}
159169
case profile.PackageManager == "dnf":
160170
return [][]string{{"sudo", "dnf", "install", "-y", "curl"}}
171+
case profile.PackageManager == "emerge":
172+
return [][]string{{"sudo", "emerge", "--ask=n", "--quiet", "curl"}}
161173
default:
162174
return nil
163175
}
@@ -183,6 +195,8 @@ func installCommandsNode(profile PlatformProfile) [][]string {
183195
{"bash", "-c", "curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -"},
184196
{"sudo", "dnf", "install", "-y", "nodejs"},
185197
}
198+
case profile.PackageManager == "emerge":
199+
return [][]string{{"sudo", "emerge", "--ask=n", "--quiet", "nodejs"}}
186200
default:
187201
return nil
188202
}
@@ -209,6 +223,8 @@ func installCommandsGo(profile PlatformProfile) [][]string {
209223
return [][]string{{"sudo", "pacman", "-S", "--noconfirm", "go"}}
210224
case profile.PackageManager == "dnf":
211225
return [][]string{{"sudo", "dnf", "install", "-y", "golang"}}
226+
case profile.PackageManager == "emerge":
227+
return [][]string{{"sudo", "emerge", "--ask=n", "--quiet", "dev-lang/go"}}
212228
default:
213229
return nil
214230
}

0 commit comments

Comments
 (0)