Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# hepctl

`hepctl` is a terminal app to install HEP packages from one place.

Current scope:
- macOS: ROOT install
- Ubuntu: planned
`hepctl` is a terminal app to install HEP (High Energy Physics) packages from one place.

## Quick start

Expand All @@ -13,11 +9,22 @@ go run ./cmd/hepctl
```

```bash
go run ./cmd/hepctl install root
go run ./cmd/hepct
```

## Commands

- `install root`
- `install packagename`
- `help`
- `quit`

## Package checklist

| Package | Ubuntu | macOS |
| ------- | ------ | ----- |
| ROOT | [ ] | [x] |
| PYTHIA | [ ] | [ ] |
| AMPT | [ ] | [ ] |
| HIJING | [ ] | [ ] |
| RIVET | [ ] | [ ] |
| EPOS4 | [ ] | [ ] |
67 changes: 53 additions & 14 deletions internal/install/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"os/exec"
"runtime"
"strings"

"hepctl/internal/platform"
)

const homebrewInstallCommand = `$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)`
Expand Down Expand Up @@ -97,15 +99,62 @@ func (i *RootInstaller) Install(ctx context.Context) error {
case "darwin":
return i.installOnMacOS(ctx)
case "linux":
if isUbuntu() {
return errors.New("ubuntu support is planned but not implemented yet")
}
return errors.New("linux detected, but only ubuntu is in scope for the next step")
return i.installOnLinux(ctx)
default:
return fmt.Errorf("unsupported OS: %s", runtime.GOOS)
}
}

// linuxManagerInfo maps a package manager binary to the install arguments for ROOT.
type linuxManagerInfo struct {
bin string // binary name (e.g. "pacman")
args []string // arguments after "sudo <bin>" (e.g. ["-S", "root"])
pkgName string // human-friendly label for logging
}

// ErrNeedsVersionSelection signals the caller (the TUI) that this distro
// requires the user to pick a ROOT version before installation can proceed.
var ErrNeedsVersionSelection = errors.New("version selection required")

// distrosNeedingVersionSelect lists distros where ROOT is not in the system repos.
var distrosNeedingVersionSelect = []string{"ubuntu", "debian", "linuxmint"}

// DistrosNeedingVersionSelect returns the list of distros that require
// manual ROOT version selection.
func DistrosNeedingVersionSelect() []string {
return distrosNeedingVersionSelect
}

var linuxManagers = []linuxManagerInfo{
{bin: "pacman", args: []string{"-S", "--noconfirm", "root"}, pkgName: "pacman"},
{bin: "dnf", args: []string{"install", "-y", "root"}, pkgName: "dnf"},
{bin: "yum", args: []string{"install", "-y", "root"}, pkgName: "yum"},
{bin: "zypper", args: []string{"install", "-y", "root"}, pkgName: "zypper"},
{bin: "eopkg", args: []string{"install", "-y", "root"}, pkgName: "eopkg"},
}

func (i *RootInstaller) installOnLinux(ctx context.Context) error {
// Check if this distro needs manual version selection (ROOT not in repos).
for _, d := range distrosNeedingVersionSelect {
if platform.IsDistro(d) {
return ErrNeedsVersionSelection
}
}

mgr := platform.PackageManager()

for _, m := range linuxManagers {
if m.bin == mgr {
cmdArgs := append([]string{m.bin}, m.args...)
fmt.Fprintf(i.out, "Detected %s. Installing ROOT with: sudo %s\n", m.pkgName, strings.Join(cmdArgs, " "))
return i.runner.Run(ctx, "sudo", cmdArgs...)
}
}

distro := platform.DistroName()
return fmt.Errorf("no supported package manager found on %s; detected manager: %s", distro, mgr)
}

func (i *RootInstaller) installOnMacOS(ctx context.Context) error {
detected := i.DetectMacManagers()
brewExists := detected.BrewExists
Expand Down Expand Up @@ -192,13 +241,3 @@ func (i *RootInstaller) resolveBrewPath() (string, error) {

return "", errors.New("homebrew installed but `brew` was not found in PATH; rerun your shell and try again")
}

func isUbuntu() bool {
data, err := os.ReadFile("/etc/os-release")
if err != nil {
return false
}

lower := strings.ToLower(string(data))
return strings.Contains(lower, "id=ubuntu") || strings.Contains(lower, "id_like=ubuntu")
}
Loading