mirror of
https://github.com/daylinmorgan/oizys.git
synced 2025-01-03 02:30:45 -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
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,11 +14,8 @@ var buildCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var minimal bool
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(buildCmd)
|
rootCmd.AddCommand(buildCmd)
|
||||||
buildCmd.Flags().BoolVar(&nom, "nom", false, "display result with nom")
|
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")
|
buildCmd.Flags().BoolVar(&minimal, "minimal", false, "use system dry-run to make build args")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,10 +10,13 @@ var cacheCmd = &cobra.Command{
|
||||||
Use: "cache",
|
Use: "cache",
|
||||||
Short: "build and push to cachix",
|
Short: "build and push to cachix",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
oizys.SetCache(cacheName)
|
||||||
oizys.CacheBuild(args...)
|
oizys.CacheBuild(args...)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cacheName string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cacheCmd.Flags().StringVarP(
|
cacheCmd.Flags().StringVarP(
|
||||||
&cacheName,
|
&cacheName,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,11 +10,11 @@ var dryCmd = &cobra.Command{
|
||||||
Use: "dry",
|
Use: "dry",
|
||||||
Short: "poor man's nix flake check",
|
Short: "poor man's nix flake check",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
oizys.NixDryRun(verbose, args...)
|
oizys.Dry(verbose, minimal, args...)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(dryCmd)
|
rootCmd.AddCommand(dryCmd)
|
||||||
|
dryCmd.Flags().BoolVarP(&minimal, "minimal", "m", false, "use system dry-run to make build args")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"oizys/internal/oizys"
|
||||||
)
|
)
|
||||||
|
|
||||||
var outputCmd = &cobra.Command{
|
var outputCmd = &cobra.Command{
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
o "oizys/internal/oizys"
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
|
@ -31,15 +31,13 @@ func Execute() {
|
||||||
var (
|
var (
|
||||||
flake string
|
flake string
|
||||||
host string
|
host string
|
||||||
cacheName string
|
|
||||||
verbose bool
|
verbose bool
|
||||||
nom bool
|
nom bool
|
||||||
systemPath bool
|
systemPath bool
|
||||||
resetCache bool
|
resetCache bool
|
||||||
|
minimal bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var oizys = o.NewOizys()
|
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "oizys",
|
Use: "oizys",
|
||||||
Short: "nix begat oizys",
|
Short: "nix begat oizys",
|
||||||
|
@ -48,7 +46,12 @@ var rootCmd = &cobra.Command{
|
||||||
log.Info("running with verbose mode")
|
log.Info("running with verbose mode")
|
||||||
log.SetLevel(log.DebugLevel)
|
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()
|
oizys.CheckFlake()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"oizys/internal/oizys"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"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"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"golang.org/x/term"
|
|
||||||
|
|
||||||
"github.com/briandowns/spinner"
|
"github.com/briandowns/spinner"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var o *Oizys
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
o = New()
|
||||||
|
}
|
||||||
|
|
||||||
// verbose vs debug?
|
// verbose vs debug?
|
||||||
type Oizys struct {
|
type Oizys struct {
|
||||||
flake string
|
flake string
|
||||||
|
@ -30,12 +33,12 @@ type Oizys struct {
|
||||||
resetCache bool
|
resetCache bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOizys() *Oizys {
|
func New() *Oizys {
|
||||||
o := new(Oizys)
|
o := new(Oizys)
|
||||||
o.cache = "daylin"
|
o.cache = "daylin"
|
||||||
hostname, err := os.Hostname()
|
hostname, err := os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal("failed to determine hostname", "err", err)
|
||||||
}
|
}
|
||||||
o.host = hostname
|
o.host = hostname
|
||||||
oizysDir, ok := os.LookupEnv("OIZYS_DIR")
|
oizysDir, ok := os.LookupEnv("OIZYS_DIR")
|
||||||
|
@ -51,6 +54,32 @@ func NewOizys() *Oizys {
|
||||||
return o
|
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 {
|
type Derivation struct {
|
||||||
InputDrvs map[string]interface{}
|
InputDrvs map[string]interface{}
|
||||||
}
|
}
|
||||||
|
@ -68,12 +97,9 @@ func parseSystemPath(derivation map[string]Derivation) (string, error) {
|
||||||
|
|
||||||
// recreating this command
|
// recreating this command
|
||||||
// nix derivation show `oizys output` | jq -r '.[].inputDrvs | with_entries(select(.key|match("system-path";"i"))) | keys | .[]'
|
// 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())
|
cmd := exec.Command("nix", "derivation", "show", o.nixosConfigAttr())
|
||||||
logCmd(cmd)
|
out, err := cmdOutputWithSpinner(cmd, "running nix derivation show for full system", false)
|
||||||
s := nixSpinner(o.host)
|
|
||||||
out, err := cmd.Output()
|
|
||||||
s.Stop()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to evalute nixosConfiguration for system-path.drv", "err", err)
|
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 {
|
if o.systemPath {
|
||||||
return o.getSystemPath()
|
return getSystemPath()
|
||||||
} else {
|
} else {
|
||||||
return o.nixosConfigAttr()
|
return o.nixosConfigAttr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Oizys) Set(
|
// func (o *Oizys) Set(
|
||||||
flake, host, cache string,
|
// flake, host, cache string,
|
||||||
verbose, systemPath, resetCache bool,
|
// verbose, systemPath, resetCache bool,
|
||||||
) {
|
// ) {
|
||||||
if host != "" {
|
// if host != "" {
|
||||||
o.host = host
|
// o.host = host
|
||||||
}
|
// }
|
||||||
if flake != "" {
|
// if flake != "" {
|
||||||
o.flake = flake
|
// o.flake = flake
|
||||||
}
|
// }
|
||||||
if cache != "" {
|
// if cache != "" {
|
||||||
o.cache = cache
|
// o.cache = cache
|
||||||
}
|
// }
|
||||||
o.verbose = verbose
|
// o.verbose = verbose
|
||||||
o.systemPath = systemPath
|
// o.systemPath = systemPath
|
||||||
o.resetCache = resetCache
|
// o.resetCache = resetCache
|
||||||
}
|
// }
|
||||||
|
|
||||||
// TODO: seperate parsing and displaying of packages
|
func git(rest ...string) *exec.Cmd {
|
||||||
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 {
|
|
||||||
args := []string{"-C", o.flake}
|
args := []string{"-C", o.flake}
|
||||||
args = append(args, rest...)
|
args = append(args, rest...)
|
||||||
cmd := exec.Command("git", args...)
|
cmd := exec.Command("git", args...)
|
||||||
|
@ -215,19 +157,8 @@ func (o *Oizys) git(rest ...string) *exec.Cmd {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func showFailedOutput(buf []byte) {
|
func GitPull() {
|
||||||
arrow := lipgloss.
|
cmdOutput, err := git("status", "--porcelain").Output()
|
||||||
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()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -238,7 +169,7 @@ func (o *Oizys) GitPull() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdOutput, err = o.git("pull").CombinedOutput()
|
cmdOutput, err = git("pull").CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
showFailedOutput(cmdOutput)
|
showFailedOutput(cmdOutput)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -301,24 +232,38 @@ func showDryRunResult(nixOutput string, verbose bool) {
|
||||||
toFetch.show(verbose)
|
toFetch.show(verbose)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Oizys) NixDryRun(verbose bool, rest ...string) {
|
func Dry(verbose bool, minimal bool, rest ...string) {
|
||||||
args := []string{
|
cmd := exec.Command("nix", "build", "--dry-run")
|
||||||
"build", o.nixosConfigAttr(), "--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...)
|
result, err := cmdOutputWithSpinner(cmd, spinnerMsg, true)
|
||||||
cmd := exec.Command("nix", args...)
|
|
||||||
s := nixSpinner(o.host)
|
|
||||||
result, err := cmd.CombinedOutput()
|
|
||||||
s.Stop()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(result))
|
log.Fatal("failed to dry-run nix build", "err", err, "output", string(result))
|
||||||
log.Fatal(err)
|
}
|
||||||
|
if minimal {
|
||||||
|
fmt.Println(string(result))
|
||||||
|
} else {
|
||||||
|
showDryRunResult(string(result), verbose)
|
||||||
}
|
}
|
||||||
showDryRunResult(string(result), verbose)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// / Setup command completely differently here
|
// / Setup command completely differently here
|
||||||
func (o *Oizys) NixosRebuild(subcmd string, rest ...string) {
|
func NixosRebuild(subcmd string, rest ...string) {
|
||||||
cmd := exec.Command("sudo",
|
cmd := exec.Command("sudo",
|
||||||
"nixos-rebuild",
|
"nixos-rebuild",
|
||||||
subcmd,
|
subcmd,
|
||||||
|
@ -329,19 +274,10 @@ func (o *Oizys) NixosRebuild(subcmd string, rest ...string) {
|
||||||
if o.verbose {
|
if o.verbose {
|
||||||
cmd.Args = append(cmd.Args, "--print-build-logs")
|
cmd.Args = append(cmd.Args, "--print-build-logs")
|
||||||
}
|
}
|
||||||
runCommand(cmd)
|
exitWithCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCommand(cmd *exec.Cmd) {
|
func NixBuild(nom bool, minimal bool, rest ...string) {
|
||||||
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) {
|
|
||||||
var cmdName string
|
var cmdName string
|
||||||
if nom {
|
if nom {
|
||||||
cmdName = "nom"
|
cmdName = "nom"
|
||||||
|
@ -349,7 +285,6 @@ func (o *Oizys) NixBuild(nom bool, minimal bool, rest ...string) {
|
||||||
cmdName = "nix"
|
cmdName = "nix"
|
||||||
}
|
}
|
||||||
cmd := exec.Command(cmdName, "build")
|
cmd := exec.Command(cmdName, "build")
|
||||||
|
|
||||||
cmd.Args = append(cmd.Args, rest...)
|
cmd.Args = append(cmd.Args, rest...)
|
||||||
if o.resetCache {
|
if o.resetCache {
|
||||||
cmd.Args = append(cmd.Args, "--narinfo-cache-positive-ttl", "0")
|
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 {
|
if minimal {
|
||||||
log.Debug("populating args with derivations not already built")
|
log.Debug("populating args with derivations not already built")
|
||||||
drvs := o.systemPathDrvsToBuild()
|
drvs := systemPathDrvsToBuild()
|
||||||
if len(drvs) == 0 {
|
if len(drvs) == 0 {
|
||||||
log.Info("nothing to build. exiting...")
|
log.Info("nothing to build. exiting...")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
@ -367,7 +302,7 @@ func (o *Oizys) NixBuild(nom bool, minimal bool, rest ...string) {
|
||||||
cmd.Args = append(cmd.Args, drvs...)
|
cmd.Args = append(cmd.Args, drvs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
runCommand(cmd)
|
exitWithCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ignoredMap = stringSliceToMap(
|
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)
|
s := strings.SplitN(strings.Replace(drv, ".drv", "", 1), "-", 2)
|
||||||
_, ok := ignoredMap[s[len(s)-1]]
|
_, ok := ignoredMap[s[len(s)-1]]
|
||||||
return ok
|
return !ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringSliceToMap(slice []string) map[string]struct{} {
|
func stringSliceToMap(slice []string) map[string]struct{} {
|
||||||
|
@ -419,40 +354,71 @@ func drvsToInputs(derivation map[string]Derivation) []string {
|
||||||
return drvs
|
return drvs
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2
|
// compute the overlap between two slices of strings
|
||||||
func (o *Oizys) systemPathDrvsToBuild() []string {
|
func overlapStrings(a []string, b []string) []string {
|
||||||
log.Debug("getting system-path build-only deps")
|
var overlap []string
|
||||||
systemPathDrv := fmt.Sprintf("%s^*", o.getSystemPath())
|
set := stringSliceToMap(a)
|
||||||
derivationCmd := exec.Command("nix", "derivation", "show", systemPathDrv)
|
for _, s := range b {
|
||||||
logCmd(derivationCmd)
|
_, ok := set[s]
|
||||||
output, err := derivationCmd.Output()
|
if ok {
|
||||||
if err != nil {
|
overlap = append(overlap, s)
|
||||||
log.Fatal("failed to evaluate", "drv", systemPathDrv)
|
}
|
||||||
}
|
}
|
||||||
|
return overlap
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: abstract this?
|
func nixDerivationShowToInputs(output []byte) []string {
|
||||||
var derivation map[string]Derivation
|
var derivation map[string]Derivation
|
||||||
if err := json.Unmarshal(output, &derivation); err != nil {
|
if err := json.Unmarshal(output, &derivation); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
systemPathInputDrvs := stringSliceToMap(drvsToInputs(derivation))
|
return drvsToInputs(derivation)
|
||||||
|
}
|
||||||
|
|
||||||
// get to build packages for full system
|
func filter[T any](ss []T, test func(T) bool) (ret []T) {
|
||||||
systemCmd := exec.Command("nix", "build", o.nixosConfigAttr(), "--dry-run")
|
for _, s := range ss {
|
||||||
logCmd(systemCmd)
|
if test(s) {
|
||||||
result, err := systemCmd.CombinedOutput()
|
ret = append(ret, s)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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))
|
drvs := make([]string, len(toActuallyBuild))
|
||||||
for i, pkg := range toActuallyBuild {
|
for i, pkg := range toActuallyBuild {
|
||||||
|
@ -461,11 +427,6 @@ func (o *Oizys) systemPathDrvsToBuild() []string {
|
||||||
return drvs
|
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) {
|
func (o *Oizys) writeToGithubStepSummary(txt string) {
|
||||||
f, err := os.OpenFile(o.githubSummary, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
f, err := os.OpenFile(o.githubSummary, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
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)
|
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()
|
checks := o.getChecks()
|
||||||
for _, check := range checks {
|
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{
|
args := []string{
|
||||||
"watch-exec", o.cache, "--", "nix",
|
"watch-exec", o.cache, "--", "nix",
|
||||||
"build", o.nixosConfigAttr(), "--print-build-logs",
|
"build", o.nixosConfigAttr(), "--print-build-logs",
|
||||||
|
@ -528,10 +489,10 @@ func (o *Oizys) CacheBuild(rest ...string) {
|
||||||
}
|
}
|
||||||
args = append(args, rest...)
|
args = append(args, rest...)
|
||||||
cmd := exec.Command("cachix", args...)
|
cmd := exec.Command("cachix", args...)
|
||||||
runCommand(cmd)
|
exitWithCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Oizys) CheckFlake() {
|
func CheckFlake() {
|
||||||
if _, ok := os.LookupEnv("OIZYS_SKIP_CHECK"); !ok {
|
if _, ok := os.LookupEnv("OIZYS_SKIP_CHECK"); !ok {
|
||||||
if _, err := os.Stat(o.flake); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(o.flake); errors.Is(err, fs.ErrNotExist) {
|
||||||
log.Fatalf("path to flake: %s does not exist", o.flake)
|
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 := []string{"workflow", "run", "build.yml", "-F", fmt.Sprintf("hosts=%s", o.host)}
|
||||||
args = append(args, rest...)
|
args = append(args, rest...)
|
||||||
cmd := exec.Command("gh", args...)
|
cmd := exec.Command("gh", args...)
|
||||||
runCommand(cmd)
|
exitWithCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: deprecate
|
||||||
func nixSpinner(host string) *spinner.Spinner {
|
func nixSpinner(host string) *spinner.Spinner {
|
||||||
msg := fmt.Sprintf("%s %s", " evaluating derivation for:",
|
msg := fmt.Sprintf("%s %s", " evaluating derivation for:",
|
||||||
lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("6")).Render(host),
|
lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("6")).Render(host),
|
||||||
)
|
)
|
||||||
s := spinner.New(
|
return startSpinner(msg)
|
||||||
spinner.CharSets[14],
|
|
||||||
100*time.Millisecond,
|
|
||||||
spinner.WithSuffix(msg),
|
|
||||||
spinner.WithColor("fgHiMagenta"),
|
|
||||||
)
|
|
||||||
s.Start()
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue