- post.go: export PNPM_HOME+PATH before pnpm add -g so global bins install correctly in the non-interactive shell. Applied to installNpmPackage and installPlaywright (incl. browser install). - system.go: treat token-less Obsidian AppImage as x86_64 (upstream publishes "Obsidian-X.Y.Z.AppImage" with no arch suffix). - pkgmgr.go: docker-ce-rootless-extras and vagrant are AUR-only on Arch → skipOverride; pipx → python-pipx on pacman. - repos.go: new setupLazygitCoprRepo enables copr.fedorainfracloud.org/ dejan/lazygit on Fedora; wired into repoGroups so lazygit installs. - Tests: PNPM_HOME export (Linux+macOS), token-less Obsidian asset, pacman pkg overrides, COPR repo setup, updated repoGroups count. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
247 lines
7.5 KiB
Go
247 lines
7.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// repoFileExists returns true if any of the given paths exists.
|
|
func repoFileExists(paths ...string) bool {
|
|
for _, p := range paths {
|
|
if _, err := osStat(p); err == nil {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func writeDNFRepo(name, displayName, baseurl, gpgkey string) {
|
|
content := fmt.Sprintf(
|
|
"[%s]\nname=%s\nbaseurl=%s\nenabled=1\ngpgcheck=1\ngpgkey=%s\n",
|
|
name, displayName, baseurl, gpgkey,
|
|
)
|
|
path := "/etc/yum.repos.d/" + name + ".repo"
|
|
runCmd([]string{"tee", path}, CmdOpts{AsSudo: true, Input: []byte(content), Capture: true})
|
|
}
|
|
|
|
func setupDockerRepo() {
|
|
switch pkgMgr {
|
|
case "dnf":
|
|
if repoFileExists("/etc/yum.repos.d/docker-ce.repo") {
|
|
return
|
|
}
|
|
runCmd([]string{"dnf", "config-manager", "addrepo", "--from-repofile",
|
|
"https://download.docker.com/linux/fedora/docker-ce.repo"}, CmdOpts{AsSudo: true})
|
|
case "apt-get":
|
|
if repoFileExists("/etc/apt/sources.list.d/docker.list") {
|
|
return
|
|
}
|
|
runCmd([]string{"apt-get", "update"}, CmdOpts{AsSudo: true})
|
|
runCmd([]string{"apt-get", "install", "-y", "ca-certificates", "curl", "gnupg"}, CmdOpts{AsSudo: true})
|
|
distroID := osReleaseField("ID")
|
|
dockerDistro := "ubuntu"
|
|
if distroID == "debian" || distroID == "ubuntu" {
|
|
dockerDistro = distroID
|
|
}
|
|
runShell(
|
|
"install -m 0755 -d /etc/apt/keyrings && "+
|
|
"curl -fsSL https://download.docker.com/linux/"+dockerDistro+"/gpg | "+
|
|
"sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && "+
|
|
"sudo chmod a+r /etc/apt/keyrings/docker.gpg",
|
|
CmdOpts{},
|
|
)
|
|
codenameRes := runShell(". /etc/os-release && echo $VERSION_CODENAME",
|
|
CmdOpts{Capture: true})
|
|
codename := strings.TrimSpace(string(codenameRes.Stdout))
|
|
debArch := archDeb[archName]
|
|
runCmd(
|
|
[]string{"tee", "/etc/apt/sources.list.d/docker.list"},
|
|
CmdOpts{
|
|
AsSudo: true,
|
|
Input: []byte(fmt.Sprintf("deb [arch=%s signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/%s %s stable\n", debArch, dockerDistro, codename)),
|
|
Capture: true,
|
|
},
|
|
)
|
|
runCmd([]string{"apt-get", "update"}, CmdOpts{AsSudo: true})
|
|
}
|
|
// pacman: docker is in official repos — no extra repo needed.
|
|
}
|
|
|
|
func setupGHRepo() {
|
|
switch pkgMgr {
|
|
case "dnf":
|
|
if repoFileExists("/etc/yum.repos.d/gh-cli.repo") {
|
|
return
|
|
}
|
|
runCmd([]string{"dnf", "config-manager", "addrepo", "--from-repofile",
|
|
"https://cli.github.com/packages/rpm/gh-cli.repo"}, CmdOpts{AsSudo: true})
|
|
case "apt-get":
|
|
if repoFileExists("/etc/apt/sources.list.d/github-cli.list") {
|
|
return
|
|
}
|
|
debArch := archDeb[archName]
|
|
runShell(
|
|
"curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | "+
|
|
"sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && "+
|
|
"sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && "+
|
|
fmt.Sprintf("echo 'deb [arch=%s signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main' | ", debArch)+
|
|
"sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null",
|
|
CmdOpts{},
|
|
)
|
|
runCmd([]string{"apt-get", "update"}, CmdOpts{AsSudo: true})
|
|
}
|
|
// pacman: github-cli is in community repo.
|
|
}
|
|
|
|
func setupChromeRepo() {
|
|
if archName != "x86_64" {
|
|
warn("Google Chrome has no Linux build for this arch — skipping repo")
|
|
return
|
|
}
|
|
switch pkgMgr {
|
|
case "dnf":
|
|
if repoFileExists("/etc/yum.repos.d/google-chrome.repo") {
|
|
return
|
|
}
|
|
writeDNFRepo(
|
|
"google-chrome", "Google Chrome",
|
|
"https://dl.google.com/linux/chrome/rpm/stable/x86_64",
|
|
"https://dl.google.com/linux/linux_signing_key.pub",
|
|
)
|
|
case "apt-get":
|
|
if repoFileExists("/etc/apt/sources.list.d/google-chrome.list") {
|
|
return
|
|
}
|
|
runShell(
|
|
"curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | "+
|
|
"sudo gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg && "+
|
|
"echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] "+
|
|
"https://dl.google.com/linux/chrome/deb/ stable main' | "+
|
|
"sudo tee /etc/apt/sources.list.d/google-chrome.list > /dev/null && "+
|
|
"sudo apt-get update",
|
|
CmdOpts{},
|
|
)
|
|
}
|
|
}
|
|
|
|
func setupVivaldiRepo() {
|
|
if archName != "x86_64" {
|
|
warn("Vivaldi repo on this arch is not supported by this script — skipping")
|
|
return
|
|
}
|
|
switch pkgMgr {
|
|
case "dnf":
|
|
if repoFileExists("/etc/yum.repos.d/vivaldi.repo") {
|
|
return
|
|
}
|
|
writeDNFRepo(
|
|
"vivaldi", "Vivaldi",
|
|
"https://repo.vivaldi.com/archive/rpm/x86_64",
|
|
"https://repo.vivaldi.com/archive/linux_signing_key.pub",
|
|
)
|
|
case "apt-get":
|
|
if repoFileExists("/etc/apt/sources.list.d/vivaldi.list") {
|
|
return
|
|
}
|
|
runShell(
|
|
"curl -fsSL https://repo.vivaldi.com/archive/linux_signing_key.pub | "+
|
|
"sudo gpg --dearmor -o /etc/apt/keyrings/vivaldi.gpg && "+
|
|
"echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/vivaldi.gpg] "+
|
|
"https://repo.vivaldi.com/archive/deb/ stable main' | "+
|
|
"sudo tee /etc/apt/sources.list.d/vivaldi.list > /dev/null && "+
|
|
"sudo apt-get update",
|
|
CmdOpts{},
|
|
)
|
|
}
|
|
}
|
|
|
|
func setupTemurinRepo() {
|
|
switch pkgMgr {
|
|
case "dnf":
|
|
if repoFileExists("/etc/yum.repos.d/adoptium.repo") {
|
|
return
|
|
}
|
|
writeDNFRepo(
|
|
"Adoptium", "Adoptium",
|
|
"https://packages.adoptium.net/artifactory/rpm/fedora/$releasever/$basearch",
|
|
"https://packages.adoptium.net/artifactory/api/gpg/key/public",
|
|
)
|
|
case "apt-get":
|
|
if repoFileExists("/etc/apt/sources.list.d/adoptium.list") {
|
|
return
|
|
}
|
|
runShell(
|
|
"wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | "+
|
|
"sudo gpg --dearmor | sudo tee /etc/apt/keyrings/adoptium.gpg > /dev/null && "+
|
|
`echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] `+
|
|
`https://packages.adoptium.net/artifactory/deb/ `+
|
|
`$(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | `+
|
|
"sudo tee /etc/apt/sources.list.d/adoptium.list > /dev/null && "+
|
|
"sudo apt-get update",
|
|
CmdOpts{},
|
|
)
|
|
}
|
|
}
|
|
|
|
func setupDotnetRepo() {
|
|
// .NET is in Fedora repos directly — no extra repo needed.
|
|
if pkgMgr != "apt-get" {
|
|
return
|
|
}
|
|
if repoFileExists(
|
|
"/etc/apt/sources.list.d/microsoft-prod.list",
|
|
"/etc/apt/sources.list.d/dotnet.list",
|
|
) {
|
|
return
|
|
}
|
|
distroID := strings.Trim(osReleaseField("ID"), `"`)
|
|
versionID := strings.Trim(osReleaseField("VERSION_ID"), `"`)
|
|
debURL := fmt.Sprintf(
|
|
"https://packages.microsoft.com/config/%s/%s/packages-microsoft-prod.deb",
|
|
distroID, versionID,
|
|
)
|
|
runShell(
|
|
fmt.Sprintf("curl -fsSL %s -o /tmp/packages-microsoft-prod.deb && "+
|
|
"sudo dpkg -i /tmp/packages-microsoft-prod.deb && "+
|
|
"sudo apt-get update", debURL),
|
|
CmdOpts{},
|
|
)
|
|
}
|
|
|
|
func setupLazygitCoprRepo() {
|
|
if pkgMgr != "dnf" {
|
|
return
|
|
}
|
|
if repoFileExists("/etc/yum.repos.d/_copr:copr.fedorainfracloud.org:dejan:lazygit.repo") {
|
|
return
|
|
}
|
|
// dnf-plugins-core provides the `copr` subcommand on dnf4; on dnf5 it's a no-op.
|
|
runCmd([]string{"dnf", "install", "-y", "dnf-plugins-core"}, CmdOpts{AsSudo: true})
|
|
runCmd([]string{"dnf", "copr", "enable", "-y", "dejan/lazygit"}, CmdOpts{AsSudo: true})
|
|
}
|
|
|
|
type repoGroup struct {
|
|
members map[string]bool
|
|
setup func()
|
|
}
|
|
|
|
func repoGroups() []repoGroup {
|
|
mk := func(names ...string) map[string]bool {
|
|
m := make(map[string]bool, len(names))
|
|
for _, n := range names {
|
|
m[n] = true
|
|
}
|
|
return m
|
|
}
|
|
return []repoGroup{
|
|
{mk("containerd.io", "docker-buildx-plugin", "docker-ce-cli",
|
|
"docker-ce-rootless-extras", "docker-ce", "docker-compose-plugin"), setupDockerRepo},
|
|
{mk("gh"), setupGHRepo},
|
|
{mk("google-chrome-stable"), setupChromeRepo},
|
|
{mk("vivaldi-stable"), setupVivaldiRepo},
|
|
{mk("temurin-25-jdk"), setupTemurinRepo},
|
|
{mk("dotnet-sdk-10.0"), setupDotnetRepo},
|
|
{mk("lazygit"), setupLazygitCoprRepo},
|
|
}
|
|
}
|