mirror of
https://github.com/daylinmorgan/oizys.git
synced 2024-11-05 06:03:15 -06:00
refactor cli
This commit is contained in:
parent
1077cace3d
commit
91a720541f
13 changed files with 335 additions and 211 deletions
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -12,11 +14,8 @@ var buildCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var minimal bool
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(buildCmd)
|
||||
buildCmd.Flags().BoolVar(&nom, "nom", false, "display result with nom")
|
||||
// buildCmd.Flags().BoolVar(&systemPath, "system-path", false, "build system path derivation")
|
||||
buildCmd.Flags().BoolVar(&minimal, "minimal", false, "use system dry-run to make build args")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -8,10 +10,13 @@ var cacheCmd = &cobra.Command{
|
|||
Use: "cache",
|
||||
Short: "build and push to cachix",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
oizys.SetCache(cacheName)
|
||||
oizys.CacheBuild(args...)
|
||||
},
|
||||
}
|
||||
|
||||
var cacheName string
|
||||
|
||||
func init() {
|
||||
cacheCmd.Flags().StringVarP(
|
||||
&cacheName,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -8,11 +10,11 @@ var dryCmd = &cobra.Command{
|
|||
Use: "dry",
|
||||
Short: "poor man's nix flake check",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
oizys.NixDryRun(verbose, args...)
|
||||
oizys.Dry(verbose, minimal, args...)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(dryCmd)
|
||||
|
||||
dryCmd.Flags().BoolVarP(&minimal, "minimal", "m", false, "use system dry-run to make build args")
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"oizys/internal/oizys"
|
||||
)
|
||||
|
||||
var outputCmd = &cobra.Command{
|
||||
|
|
|
@ -3,7 +3,7 @@ package cmd
|
|||
import (
|
||||
"os"
|
||||
|
||||
o "oizys/internal/oizys"
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/log"
|
||||
|
@ -31,15 +31,13 @@ func Execute() {
|
|||
var (
|
||||
flake string
|
||||
host string
|
||||
cacheName string
|
||||
verbose bool
|
||||
nom bool
|
||||
systemPath bool
|
||||
resetCache bool
|
||||
minimal bool
|
||||
)
|
||||
|
||||
var oizys = o.NewOizys()
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "oizys",
|
||||
Short: "nix begat oizys",
|
||||
|
@ -48,7 +46,12 @@ var rootCmd = &cobra.Command{
|
|||
log.Info("running with verbose mode")
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
oizys.Set(flake, host, cacheName, verbose, systemPath, resetCache)
|
||||
oizys.SetFlake(flake)
|
||||
oizys.SetHost(host)
|
||||
oizys.SetCache(cacheName) // TODO: move
|
||||
oizys.SetVerbose(verbose)
|
||||
oizys.SetResetCache(resetCache)
|
||||
|
||||
oizys.CheckFlake()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"oizys/internal/oizys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
48
pkgs/oizys/oizys-go/internal/oizys/cmd.go
Normal file
48
pkgs/oizys/oizys-go/internal/oizys/cmd.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package oizys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/charmbracelet/log"
|
||||
)
|
||||
|
||||
func logCmd(cmd *exec.Cmd) {
|
||||
log.Debugf("CMD: %s", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
||||
func cmdOutputWithSpinner(cmd *exec.Cmd, msg string, stderr bool) (output []byte, err error) {
|
||||
logCmd(cmd)
|
||||
s := startSpinner(msg)
|
||||
if stderr {
|
||||
output, err = cmd.CombinedOutput()
|
||||
} else {
|
||||
output, err = cmd.Output()
|
||||
}
|
||||
s.Stop()
|
||||
return
|
||||
}
|
||||
|
||||
func startSpinner(msg string) *spinner.Spinner {
|
||||
s := spinner.New(
|
||||
spinner.CharSets[14],
|
||||
100*time.Millisecond,
|
||||
spinner.WithSuffix(fmt.Sprintf(" %s", msg)),
|
||||
spinner.WithColor("fgHiMagenta"),
|
||||
)
|
||||
s.Start()
|
||||
return s
|
||||
}
|
||||
|
||||
func exitWithCommand(cmd *exec.Cmd) {
|
||||
logCmd(cmd)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal("final command failed", "err", err)
|
||||
}
|
||||
}
|
101
pkgs/oizys/oizys-go/internal/oizys/display.go
Normal file
101
pkgs/oizys/oizys-go/internal/oizys/display.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
package oizys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/log"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// TODO: seperate parsing and displaying of packages
|
||||
func terminalSize() (int, int) {
|
||||
fd := os.Stdout.Fd()
|
||||
if !term.IsTerminal(int(fd)) {
|
||||
log.Error("failed to get terminal size")
|
||||
return 80, 0
|
||||
}
|
||||
w, h, err := term.GetSize(int(fd))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return w, h
|
||||
}
|
||||
|
||||
type packages struct {
|
||||
desc string
|
||||
names []string
|
||||
pad int
|
||||
}
|
||||
|
||||
func parsePackages(lines []string, desc string) *packages {
|
||||
w, _ := terminalSize()
|
||||
maxAcceptable := (w / 4) - 1
|
||||
maxLen := 0
|
||||
names := make([]string, len(lines))
|
||||
for i, pkg := range lines {
|
||||
s := strings.SplitN(pkg, "-", 2)
|
||||
if len(s) != 2 {
|
||||
log.Fatalf("failed to trim hash path from this line: %s\n ", pkg)
|
||||
}
|
||||
name := ellipsis(strings.Replace(s[1], ".drv", "", 1), maxAcceptable)
|
||||
if nameLen := len(name); nameLen > maxLen {
|
||||
maxLen = nameLen
|
||||
}
|
||||
names[i] = name
|
||||
}
|
||||
return &packages{names: names, pad: maxLen + 1, desc: desc}
|
||||
}
|
||||
|
||||
func ellipsis(s string, maxLen int) string {
|
||||
runes := []rune(s)
|
||||
if len(runes) <= maxLen {
|
||||
return s
|
||||
}
|
||||
if maxLen < 3 {
|
||||
maxLen = 3
|
||||
}
|
||||
return string(runes[0:maxLen-3]) + "..."
|
||||
}
|
||||
|
||||
func (p *packages) show(verbose bool) {
|
||||
p.summary()
|
||||
if !verbose || (len(p.names) == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
pkgs := p.names
|
||||
w, _ := terminalSize()
|
||||
nCols := w / p.pad
|
||||
fmt.Printf("%s\n", strings.Repeat("-", w))
|
||||
for i, pkg := range pkgs {
|
||||
fmt.Printf("%-*s", p.pad, pkg)
|
||||
if (i+1)%nCols == 0 {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func (p *packages) summary() {
|
||||
fmt.Printf("%s: %s\n",
|
||||
p.desc,
|
||||
lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("6")).
|
||||
Render(fmt.Sprint(len(p.names))),
|
||||
)
|
||||
}
|
||||
|
||||
func showFailedOutput(buf []byte) {
|
||||
arrow := lipgloss.
|
||||
NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("9")).
|
||||
Render("->")
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(buf)), "\n") {
|
||||
fmt.Println(arrow, line)
|
||||
}
|
||||
}
|
|
@ -7,17 +7,20 @@ import (
|
|||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"golang.org/x/term"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/charmbracelet/log"
|
||||
)
|
||||
|
||||
var o *Oizys
|
||||
|
||||
func init() {
|
||||
o = New()
|
||||
}
|
||||
|
||||
// verbose vs debug?
|
||||
type Oizys struct {
|
||||
flake string
|
||||
|
@ -30,12 +33,12 @@ type Oizys struct {
|
|||
resetCache bool
|
||||
}
|
||||
|
||||
func NewOizys() *Oizys {
|
||||
func New() *Oizys {
|
||||
o := new(Oizys)
|
||||
o.cache = "daylin"
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal("failed to determine hostname", "err", err)
|
||||
}
|
||||
o.host = hostname
|
||||
oizysDir, ok := os.LookupEnv("OIZYS_DIR")
|
||||
|
@ -51,6 +54,32 @@ func NewOizys() *Oizys {
|
|||
return o
|
||||
}
|
||||
|
||||
func SetFlake(path string) {
|
||||
if path != "" {
|
||||
o.flake = path
|
||||
}
|
||||
}
|
||||
|
||||
func SetCache(name string) {
|
||||
if name != "" {
|
||||
o.cache = name
|
||||
}
|
||||
}
|
||||
|
||||
func SetHost(name string) {
|
||||
if name != "" {
|
||||
o.host = name
|
||||
}
|
||||
}
|
||||
|
||||
func SetVerbose(v bool) {
|
||||
o.verbose = v
|
||||
}
|
||||
|
||||
func SetResetCache(reset bool) {
|
||||
o.resetCache = reset
|
||||
}
|
||||
|
||||
type Derivation struct {
|
||||
InputDrvs map[string]interface{}
|
||||
}
|
||||
|
@ -68,12 +97,9 @@ func parseSystemPath(derivation map[string]Derivation) (string, error) {
|
|||
|
||||
// recreating this command
|
||||
// nix derivation show `oizys output` | jq -r '.[].inputDrvs | with_entries(select(.key|match("system-path";"i"))) | keys | .[]'
|
||||
func (o *Oizys) getSystemPath() string {
|
||||
func getSystemPath() string {
|
||||
cmd := exec.Command("nix", "derivation", "show", o.nixosConfigAttr())
|
||||
logCmd(cmd)
|
||||
s := nixSpinner(o.host)
|
||||
out, err := cmd.Output()
|
||||
s.Stop()
|
||||
out, err := cmdOutputWithSpinner(cmd, "running nix derivation show for full system", false)
|
||||
if err != nil {
|
||||
log.Fatal("failed to evalute nixosConfiguration for system-path.drv", "err", err)
|
||||
}
|
||||
|
@ -97,117 +123,33 @@ func (o *Oizys) nixosConfigAttr() string {
|
|||
)
|
||||
}
|
||||
|
||||
func (o *Oizys) Output() string {
|
||||
func Output() string {
|
||||
if o.systemPath {
|
||||
return o.getSystemPath()
|
||||
return getSystemPath()
|
||||
} else {
|
||||
return o.nixosConfigAttr()
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Oizys) Set(
|
||||
flake, host, cache string,
|
||||
verbose, systemPath, resetCache bool,
|
||||
) {
|
||||
if host != "" {
|
||||
o.host = host
|
||||
}
|
||||
if flake != "" {
|
||||
o.flake = flake
|
||||
}
|
||||
if cache != "" {
|
||||
o.cache = cache
|
||||
}
|
||||
o.verbose = verbose
|
||||
o.systemPath = systemPath
|
||||
o.resetCache = resetCache
|
||||
}
|
||||
// func (o *Oizys) Set(
|
||||
// flake, host, cache string,
|
||||
// verbose, systemPath, resetCache bool,
|
||||
// ) {
|
||||
// if host != "" {
|
||||
// o.host = host
|
||||
// }
|
||||
// if flake != "" {
|
||||
// o.flake = flake
|
||||
// }
|
||||
// if cache != "" {
|
||||
// o.cache = cache
|
||||
// }
|
||||
// o.verbose = verbose
|
||||
// o.systemPath = systemPath
|
||||
// o.resetCache = resetCache
|
||||
// }
|
||||
|
||||
// TODO: seperate parsing and displaying of packages
|
||||
func terminalSize() (int, int) {
|
||||
fd := os.Stdout.Fd()
|
||||
if !term.IsTerminal(int(fd)) {
|
||||
log.Error("failed to get terminal size")
|
||||
return 80, 0
|
||||
// log.Fatal("failed to get terminal size")
|
||||
}
|
||||
w, h, err := term.GetSize(int(fd))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return w, h
|
||||
}
|
||||
|
||||
type packages struct {
|
||||
desc string
|
||||
names []string
|
||||
pad int
|
||||
}
|
||||
|
||||
func parsePackages(lines []string, desc string) *packages {
|
||||
w, _ := terminalSize()
|
||||
maxAcceptable := (w / 4) - 1
|
||||
maxLen := 0
|
||||
names := make([]string, len(lines))
|
||||
for i, pkg := range lines {
|
||||
s := strings.SplitN(pkg, "-", 2)
|
||||
if len(s) != 2 {
|
||||
log.Fatalf("failed to trim hash path from this line: %s\n ", pkg)
|
||||
}
|
||||
name := ellipsis(strings.Replace(s[1], ".drv", "", 1), maxAcceptable)
|
||||
if nameLen := len(name); nameLen > maxLen {
|
||||
maxLen = nameLen
|
||||
}
|
||||
names[i] = name
|
||||
}
|
||||
return &packages{names: names, pad: maxLen + 1, desc: desc}
|
||||
}
|
||||
|
||||
func ellipsis(s string, maxLen int) string {
|
||||
runes := []rune(s)
|
||||
if len(runes) <= maxLen {
|
||||
return s
|
||||
}
|
||||
if maxLen < 3 {
|
||||
maxLen = 3
|
||||
}
|
||||
return string(runes[0:maxLen-3]) + "..."
|
||||
}
|
||||
|
||||
func (p *packages) show(verbose bool) {
|
||||
p.summary()
|
||||
if !verbose || (len(p.names) == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
pkgs := p.names
|
||||
w, _ := terminalSize()
|
||||
nCols := w / p.pad
|
||||
fmt.Printf("%s\n", strings.Repeat("-", w))
|
||||
for i, pkg := range pkgs {
|
||||
fmt.Printf("%-*s", p.pad, pkg)
|
||||
if (i+1)%nCols == 0 {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func (p *packages) summary() {
|
||||
fmt.Printf("%s: %s\n",
|
||||
p.desc,
|
||||
lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("6")).
|
||||
Render(fmt.Sprint(len(p.names))),
|
||||
)
|
||||
}
|
||||
|
||||
func logCmd(cmd *exec.Cmd) {
|
||||
log.Debugf("CMD: %s", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
||||
func (o *Oizys) git(rest ...string) *exec.Cmd {
|
||||
func git(rest ...string) *exec.Cmd {
|
||||
args := []string{"-C", o.flake}
|
||||
args = append(args, rest...)
|
||||
cmd := exec.Command("git", args...)
|
||||
|
@ -215,19 +157,8 @@ func (o *Oizys) git(rest ...string) *exec.Cmd {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func showFailedOutput(buf []byte) {
|
||||
arrow := lipgloss.
|
||||
NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("9")).
|
||||
Render("->")
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(buf)), "\n") {
|
||||
fmt.Println(arrow, line)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Oizys) GitPull() {
|
||||
cmdOutput, err := o.git("status", "--porcelain").Output()
|
||||
func GitPull() {
|
||||
cmdOutput, err := git("status", "--porcelain").Output()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -238,7 +169,7 @@ func (o *Oizys) GitPull() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
cmdOutput, err = o.git("pull").CombinedOutput()
|
||||
cmdOutput, err = git("pull").CombinedOutput()
|
||||
if err != nil {
|
||||
showFailedOutput(cmdOutput)
|
||||
log.Fatal(err)
|
||||
|
@ -301,24 +232,38 @@ func showDryRunResult(nixOutput string, verbose bool) {
|
|||
toFetch.show(verbose)
|
||||
}
|
||||
|
||||
func (o *Oizys) NixDryRun(verbose bool, rest ...string) {
|
||||
args := []string{
|
||||
"build", o.nixosConfigAttr(), "--dry-run",
|
||||
func Dry(verbose bool, minimal bool, rest ...string) {
|
||||
cmd := exec.Command("nix", "build", "--dry-run")
|
||||
cmd.Args = append(cmd.Args, rest...)
|
||||
var spinnerMsg string
|
||||
if minimal {
|
||||
drvs := systemPathDrvsToBuild()
|
||||
if len(drvs) == 0 {
|
||||
log.Info("no packages in minimal set to build")
|
||||
os.Exit(0)
|
||||
}
|
||||
cmd.Args = append(cmd.Args, drvs...)
|
||||
spinnerMsg = "evaluting for minimal build needs"
|
||||
} else {
|
||||
log.Debug("evalutating full nixosConfiguration")
|
||||
cmd.Args = append(cmd.Args, o.nixosConfigAttr())
|
||||
spinnerMsg = fmt.Sprintf("%s %s", "evaluating derivation for:",
|
||||
lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("6")).Render(o.host),
|
||||
)
|
||||
}
|
||||
args = append(args, rest...)
|
||||
cmd := exec.Command("nix", args...)
|
||||
s := nixSpinner(o.host)
|
||||
result, err := cmd.CombinedOutput()
|
||||
s.Stop()
|
||||
result, err := cmdOutputWithSpinner(cmd, spinnerMsg, true)
|
||||
if err != nil {
|
||||
fmt.Println(string(result))
|
||||
log.Fatal(err)
|
||||
log.Fatal("failed to dry-run nix build", "err", err, "output", string(result))
|
||||
}
|
||||
if minimal {
|
||||
fmt.Println(string(result))
|
||||
} else {
|
||||
showDryRunResult(string(result), verbose)
|
||||
}
|
||||
showDryRunResult(string(result), verbose)
|
||||
}
|
||||
|
||||
// / Setup command completely differently here
|
||||
func (o *Oizys) NixosRebuild(subcmd string, rest ...string) {
|
||||
func NixosRebuild(subcmd string, rest ...string) {
|
||||
cmd := exec.Command("sudo",
|
||||
"nixos-rebuild",
|
||||
subcmd,
|
||||
|
@ -329,19 +274,10 @@ func (o *Oizys) NixosRebuild(subcmd string, rest ...string) {
|
|||
if o.verbose {
|
||||
cmd.Args = append(cmd.Args, "--print-build-logs")
|
||||
}
|
||||
runCommand(cmd)
|
||||
exitWithCommand(cmd)
|
||||
}
|
||||
|
||||
func runCommand(cmd *exec.Cmd) {
|
||||
logCmd(cmd)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Oizys) NixBuild(nom bool, minimal bool, rest ...string) {
|
||||
func NixBuild(nom bool, minimal bool, rest ...string) {
|
||||
var cmdName string
|
||||
if nom {
|
||||
cmdName = "nom"
|
||||
|
@ -349,7 +285,6 @@ func (o *Oizys) NixBuild(nom bool, minimal bool, rest ...string) {
|
|||
cmdName = "nix"
|
||||
}
|
||||
cmd := exec.Command(cmdName, "build")
|
||||
|
||||
cmd.Args = append(cmd.Args, rest...)
|
||||
if o.resetCache {
|
||||
cmd.Args = append(cmd.Args, "--narinfo-cache-positive-ttl", "0")
|
||||
|
@ -359,7 +294,7 @@ func (o *Oizys) NixBuild(nom bool, minimal bool, rest ...string) {
|
|||
// }
|
||||
if minimal {
|
||||
log.Debug("populating args with derivations not already built")
|
||||
drvs := o.systemPathDrvsToBuild()
|
||||
drvs := systemPathDrvsToBuild()
|
||||
if len(drvs) == 0 {
|
||||
log.Info("nothing to build. exiting...")
|
||||
os.Exit(0)
|
||||
|
@ -367,7 +302,7 @@ func (o *Oizys) NixBuild(nom bool, minimal bool, rest ...string) {
|
|||
cmd.Args = append(cmd.Args, drvs...)
|
||||
}
|
||||
|
||||
runCommand(cmd)
|
||||
exitWithCommand(cmd)
|
||||
}
|
||||
|
||||
var ignoredMap = stringSliceToMap(
|
||||
|
@ -395,10 +330,10 @@ var ignoredMap = stringSliceToMap(
|
|||
},
|
||||
)
|
||||
|
||||
func drvIsIgnored(drv string) bool {
|
||||
func drvNotIgnored(drv string) bool {
|
||||
s := strings.SplitN(strings.Replace(drv, ".drv", "", 1), "-", 2)
|
||||
_, ok := ignoredMap[s[len(s)-1]]
|
||||
return ok
|
||||
return !ok
|
||||
}
|
||||
|
||||
func stringSliceToMap(slice []string) map[string]struct{} {
|
||||
|
@ -419,40 +354,71 @@ func drvsToInputs(derivation map[string]Derivation) []string {
|
|||
return drvs
|
||||
}
|
||||
|
||||
// v2
|
||||
func (o *Oizys) systemPathDrvsToBuild() []string {
|
||||
log.Debug("getting system-path build-only deps")
|
||||
systemPathDrv := fmt.Sprintf("%s^*", o.getSystemPath())
|
||||
derivationCmd := exec.Command("nix", "derivation", "show", systemPathDrv)
|
||||
logCmd(derivationCmd)
|
||||
output, err := derivationCmd.Output()
|
||||
if err != nil {
|
||||
log.Fatal("failed to evaluate", "drv", systemPathDrv)
|
||||
// compute the overlap between two slices of strings
|
||||
func overlapStrings(a []string, b []string) []string {
|
||||
var overlap []string
|
||||
set := stringSliceToMap(a)
|
||||
for _, s := range b {
|
||||
_, ok := set[s]
|
||||
if ok {
|
||||
overlap = append(overlap, s)
|
||||
}
|
||||
}
|
||||
return overlap
|
||||
}
|
||||
|
||||
// TODO: abstract this?
|
||||
func nixDerivationShowToInputs(output []byte) []string {
|
||||
var derivation map[string]Derivation
|
||||
if err := json.Unmarshal(output, &derivation); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
systemPathInputDrvs := stringSliceToMap(drvsToInputs(derivation))
|
||||
return drvsToInputs(derivation)
|
||||
}
|
||||
|
||||
// get to build packages for full system
|
||||
systemCmd := exec.Command("nix", "build", o.nixosConfigAttr(), "--dry-run")
|
||||
logCmd(systemCmd)
|
||||
result, err := systemCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatal("failed to dry-run build full system", "err", err)
|
||||
}
|
||||
toBuild, _ := parseDryRun2(string(result))
|
||||
|
||||
var toActuallyBuild []string
|
||||
for _, drv := range toBuild {
|
||||
_, ok := systemPathInputDrvs[drv]
|
||||
if ok && !drvIsIgnored(drv) {
|
||||
toActuallyBuild = append(toActuallyBuild, drv)
|
||||
func filter[T any](ss []T, test func(T) bool) (ret []T) {
|
||||
for _, s := range ss {
|
||||
if test(s) {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func toBuildNixosConfiguration() []string {
|
||||
systemCmd := exec.Command("nix", "build", o.nixosConfigAttr(), "--dry-run")
|
||||
result, err := cmdOutputWithSpinner(
|
||||
systemCmd,
|
||||
fmt.Sprintf("running dry build for: %s", o.nixosConfigAttr()),
|
||||
true,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("failed to dry-run build system", "err", err)
|
||||
}
|
||||
toBuild, _ := parseDryRun2(string(result))
|
||||
return toBuild
|
||||
}
|
||||
|
||||
func systemPathDerivationShow() []string {
|
||||
systemPathDrv := fmt.Sprintf("%s^*", getSystemPath())
|
||||
derivationCmd := exec.Command("nix", "derivation", "show", systemPathDrv)
|
||||
output, err := cmdOutputWithSpinner(
|
||||
derivationCmd,
|
||||
fmt.Sprintf("evaluating system path: %s", systemPathDrv),
|
||||
false)
|
||||
if err != nil {
|
||||
log.Fatal("failed to evaluate", "drv", systemPathDrv)
|
||||
}
|
||||
return nixDerivationShowToInputs(output)
|
||||
}
|
||||
|
||||
func systemPathDrvsToBuild() []string {
|
||||
toBuild := toBuildNixosConfiguration()
|
||||
systemPathInputDrvs := systemPathDerivationShow()
|
||||
|
||||
toActuallyBuild := filter(
|
||||
overlapStrings(systemPathInputDrvs, toBuild),
|
||||
drvNotIgnored,
|
||||
)
|
||||
|
||||
drvs := make([]string, len(toActuallyBuild))
|
||||
for i, pkg := range toActuallyBuild {
|
||||
|
@ -461,11 +427,6 @@ func (o *Oizys) systemPathDrvsToBuild() []string {
|
|||
return drvs
|
||||
}
|
||||
|
||||
func contains(s []string, search string) bool {
|
||||
i := sort.SearchStrings(s, search)
|
||||
return i < len(s) && s[i] == search
|
||||
}
|
||||
|
||||
func (o *Oizys) writeToGithubStepSummary(txt string) {
|
||||
f, err := os.OpenFile(o.githubSummary, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
|
@ -513,14 +474,14 @@ func (o *Oizys) checkPath(name string) string {
|
|||
return fmt.Sprintf("%s#checks.x86_64-linux.%s", o.flake, name)
|
||||
}
|
||||
|
||||
func (o *Oizys) Checks(nom bool, rest ...string) {
|
||||
func Checks(nom bool, rest ...string) {
|
||||
checks := o.getChecks()
|
||||
for _, check := range checks {
|
||||
o.NixBuild(nom, false, o.checkPath(check))
|
||||
NixBuild(nom, false, o.checkPath(check))
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Oizys) CacheBuild(rest ...string) {
|
||||
func CacheBuild(rest ...string) {
|
||||
args := []string{
|
||||
"watch-exec", o.cache, "--", "nix",
|
||||
"build", o.nixosConfigAttr(), "--print-build-logs",
|
||||
|
@ -528,10 +489,10 @@ func (o *Oizys) CacheBuild(rest ...string) {
|
|||
}
|
||||
args = append(args, rest...)
|
||||
cmd := exec.Command("cachix", args...)
|
||||
runCommand(cmd)
|
||||
exitWithCommand(cmd)
|
||||
}
|
||||
|
||||
func (o *Oizys) CheckFlake() {
|
||||
func CheckFlake() {
|
||||
if _, ok := os.LookupEnv("OIZYS_SKIP_CHECK"); !ok {
|
||||
if _, err := os.Stat(o.flake); errors.Is(err, fs.ErrNotExist) {
|
||||
log.Fatalf("path to flake: %s does not exist", o.flake)
|
||||
|
@ -539,23 +500,17 @@ func (o *Oizys) CheckFlake() {
|
|||
}
|
||||
}
|
||||
|
||||
func (o *Oizys) CI(rest ...string) {
|
||||
func CI(rest ...string) {
|
||||
args := []string{"workflow", "run", "build.yml", "-F", fmt.Sprintf("hosts=%s", o.host)}
|
||||
args = append(args, rest...)
|
||||
cmd := exec.Command("gh", args...)
|
||||
runCommand(cmd)
|
||||
exitWithCommand(cmd)
|
||||
}
|
||||
|
||||
// TODO: deprecate
|
||||
func nixSpinner(host string) *spinner.Spinner {
|
||||
msg := fmt.Sprintf("%s %s", " evaluating derivation for:",
|
||||
lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("6")).Render(host),
|
||||
)
|
||||
s := spinner.New(
|
||||
spinner.CharSets[14],
|
||||
100*time.Millisecond,
|
||||
spinner.WithSuffix(msg),
|
||||
spinner.WithColor("fgHiMagenta"),
|
||||
)
|
||||
s.Start()
|
||||
return s
|
||||
return startSpinner(msg)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue