cli: consolidate and improve cli

This commit is contained in:
Daylin Morgan 2024-07-15 16:24:46 -05:00
parent 6baa412e09
commit e7ec17916b
Signed by: daylin
GPG key ID: 950D13E9719334AD
16 changed files with 317 additions and 119 deletions

View file

@ -52,15 +52,14 @@ Usage:
oizys [command] oizys [command]
Available Commands: Available Commands:
boot nixos rebuild boot
build nix build build nix build
cache build and push to cachix cache build and push to cachix
checks nix build checks checks nix build checks
ci offload build to GHA ci offload build to GHA
dry poor man's nix flake check dry poor man's nix flake check
help Help about any command help Help about any command
os nixos-rebuild wrapper
output show nixosConfiguration attr output show nixosConfiguration attr
switch nixos rebuild switch
update update and run nixos rebuild update update and run nixos rebuild
Flags: Flags:
@ -84,3 +83,4 @@ Oizys was birthed by the goddess Nyx/Nix and embodies suffering and misery. Whic
> I don't use home-manager to manager my shell/user configs. You can find those in my separate `chezmoi`-managed [`dotfiles`](https://git.dayl.in/daylin/dotfiles) repository. > I don't use home-manager to manager my shell/user configs. You can find those in my separate `chezmoi`-managed [`dotfiles`](https://git.dayl.in/daylin/dotfiles) repository.

View file

@ -1,19 +0,0 @@
package cmd
import (
"oizys/internal/oizys"
"github.com/spf13/cobra"
)
var bootCmd = &cobra.Command{
Use: "boot",
Short: "nixos rebuild boot",
Run: func(cmd *cobra.Command, args []string) {
oizys.NixosRebuild("boot", args...)
},
}
func init() {
rootCmd.AddCommand(bootCmd)
}

View file

@ -10,12 +10,11 @@ var buildCmd = &cobra.Command{
Use: "build", Use: "build",
Short: "nix build", Short: "nix build",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
oizys.NixBuild(nom, minimal, args...) oizys.NixBuild(minimal, args...)
}, },
} }
func init() { func init() {
rootCmd.AddCommand(buildCmd) rootCmd.AddCommand(buildCmd)
buildCmd.Flags().BoolVar(&nom, "nom", false, "display result with nom")
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")
} }

View file

@ -10,11 +10,10 @@ var checksCmd = &cobra.Command{
Use: "checks", Use: "checks",
Short: "nix build checks", Short: "nix build checks",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
oizys.Checks(nom, args...) oizys.Checks(args...)
}, },
} }
func init() { func init() {
rootCmd.AddCommand(checksCmd) rootCmd.AddCommand(checksCmd)
checksCmd.Flags().BoolVar(&nom, "nom", false, "display result with nom")
} }

38
pkgs/oizys/cmd/os.go Normal file
View file

@ -0,0 +1,38 @@
package cmd
import (
"fmt"
"oizys/internal/oizys"
"slices"
"strings"
"github.com/spf13/cobra"
)
var validArgs = []string{
"switch", "boot", "test", "build", "dry-build", "dry-activate", "edit", "repl",
"build-vm", "build-vm-with-bootloader",
"list-generations",
}
var osCmd = &cobra.Command{
Use: "os [subcmd]",
Short: "nixos-rebuild wrapper",
Args: func(cmd *cobra.Command, args []string) error {
if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
return err
}
// Run the custom validation logic
if slices.Contains(validArgs, args[0]) {
return nil
}
return fmt.Errorf("unexpected arg: %s\nexpected one of:\n %s", args[0], strings.Join(validArgs, ", "))
},
Run: func(cmd *cobra.Command, args []string) {
subcmd := args[0]
oizys.NixosRebuild(subcmd, args[1:]...)
},
}
func init() {
rootCmd.AddCommand(osCmd)
}

View file

@ -33,7 +33,6 @@ var (
host string host string
debug bool debug bool
verbose bool verbose bool
nom bool
systemPath bool systemPath bool
resetCache bool resetCache bool
minimal bool minimal bool

View file

@ -1,19 +0,0 @@
package cmd
import (
"oizys/internal/oizys"
"github.com/spf13/cobra"
)
var switchCmd = &cobra.Command{
Use: "switch",
Short: "nixos rebuild switch",
Run: func(cmd *cobra.Command, args []string) {
oizys.NixosRebuild("switch", args...)
},
}
func init() {
rootCmd.AddCommand(switchCmd)
}

View file

@ -1,8 +1,13 @@
package cmd package cmd
import ( import (
"fmt"
"oizys/internal/github"
"oizys/internal/oizys" "oizys/internal/oizys"
"oizys/internal/ui"
"os"
"github.com/charmbracelet/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -10,14 +15,25 @@ var updateCmd = &cobra.Command{
Use: "update", Use: "update",
Short: "update and run nixos rebuild", Short: "update and run nixos rebuild",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
oizys.GitPull() run := github.GetLastUpdateRun()
oizys.NixosRebuild("switch", args...) if preview {
md, err := github.GetUpateSummary(run.GetID())
if err != nil {
log.Fatal(err)
}
fmt.Println(md)
if !ui.Confirm("proceed with system update?") {
os.Exit(0)
}
}
oizys.UpdateRepo()
oizys.NixosRebuild("switch")
}, },
} }
var boot bool var preview bool
func init() { func init() {
rootCmd.AddCommand(updateCmd) rootCmd.AddCommand(updateCmd)
updateCmd.Flags().BoolVarP(&boot, "boot", "b", false, "run nixos-rebuild boot") updateCmd.Flags().BoolVar(&preview, "preview", false, "confirm nix store diff")
} }

View file

@ -3,19 +3,17 @@
installShellFiles, installShellFiles,
buildGoModule, buildGoModule,
makeWrapper, makeWrapper,
gh,
nix-output-monitor,
... ...
}: }:
let let
inherit (lib) cleanSource makeBinPath; inherit (lib) cleanSource;
in in
buildGoModule { buildGoModule {
pname = "oizys"; pname = "oizys";
version = "unstable"; version = "unstable";
src = cleanSource ./.; src = cleanSource ./.;
vendorHash = "sha256-/JVXhXrU2np/ty7AGFy+LPZCo1NaLYl9NAyD9+FJYBI="; vendorHash = "sha256-+4OtpcKHfomBAXRrJOvkhQdCSwU0W6+5OJuS4o12r5E=";
nativeBuildInputs = [ nativeBuildInputs = [
installShellFiles installShellFiles
@ -27,13 +25,4 @@ buildGoModule {
--zsh <(OIZYS_SKIP_CHECK=true $out/bin/oizys completion zsh) --zsh <(OIZYS_SKIP_CHECK=true $out/bin/oizys completion zsh)
''; '';
postFixup = '' }
wrapProgram $out/bin/oizys \
--prefix PATH ':' ${
makeBinPath [
gh
nix-output-monitor
]
}
'';
}

View file

@ -6,6 +6,7 @@ require (
github.com/briandowns/spinner v1.23.0 github.com/briandowns/spinner v1.23.0
github.com/charmbracelet/lipgloss v0.11.0 github.com/charmbracelet/lipgloss v0.11.0
github.com/charmbracelet/log v0.4.0 github.com/charmbracelet/log v0.4.0
github.com/google/go-github/v63 v63.0.0
github.com/ivanpirog/coloredcobra v1.0.1 github.com/ivanpirog/coloredcobra v1.0.1
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.8.0
golang.org/x/term v0.21.0 golang.org/x/term v0.21.0
@ -16,6 +17,7 @@ require (
github.com/charmbracelet/x/ansi v0.1.2 // indirect github.com/charmbracelet/x/ansi v0.1.2 // indirect
github.com/fatih/color v1.17.0 // indirect github.com/fatih/color v1.17.0 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect

View file

@ -17,6 +17,13 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE=
github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
@ -60,6 +67,7 @@ golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View file

@ -1,18 +1,24 @@
package oizys package git
import ( import (
"fmt" "fmt"
"oizys/internal/ui"
"os" "os"
"os/exec" "os/exec"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
"oizys/internal/ui"
) )
type GitRepo struct { type GitRepo struct {
path string path string
} }
func NewRepo(path string) *GitRepo {
repo := new(GitRepo)
repo.path = path
return repo
}
func (g *GitRepo) git(rest ...string) *exec.Cmd { func (g *GitRepo) git(rest ...string) *exec.Cmd {
args := []string{"-C", g.path} args := []string{"-C", g.path}
args = append(args, rest...) args = append(args, rest...)
@ -21,8 +27,22 @@ func (g *GitRepo) git(rest ...string) *exec.Cmd {
return cmd return cmd
} }
func GitPull(workDir string) { func (g *GitRepo) Fetch() {
g := GitRepo{workDir} err := g.git("fetch").Run()
if err != nil {
log.Fatal(err)
}
}
func (g *GitRepo) Rebase(ref string) {
g.Status()
err := g.git("rebase", ref).Run()
if err != nil {
log.Fatal(err)
}
}
func (g *GitRepo) Status() {
cmdOutput, err := g.git("status", "--porcelain").Output() cmdOutput, err := g.git("status", "--porcelain").Output()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -33,8 +53,11 @@ func GitPull(workDir string) {
ui.ShowFailedOutput(cmdOutput) ui.ShowFailedOutput(cmdOutput)
os.Exit(1) os.Exit(1)
} }
}
cmdOutput, err = g.git("pull").CombinedOutput() func (g *GitRepo) Pull() {
g.Status()
cmdOutput, err := g.git("pull").CombinedOutput()
if err != nil { if err != nil {
ui.ShowFailedOutput(cmdOutput) ui.ShowFailedOutput(cmdOutput)
log.Fatal(err) log.Fatal(err)

View file

@ -0,0 +1,154 @@
package github
import (
"archive/zip"
"bytes"
"context"
"fmt"
"io"
"net/http"
"net/url"
"oizys/internal/oizys"
"github.com/charmbracelet/log"
"github.com/google/go-github/v63/github"
)
var client *github.Client
func init() {
client = github.NewClient(nil).WithAuthToken(oizys.GithubToken())
}
func ListWorkflows() {
workflowRuns, resp, err := client.Actions.ListWorkflowRunsByFileName(
context.Background(),
"daylinmorgan",
"oizys",
"update.yml",
nil,
)
if err != nil {
log.Fatal("Failed to get a list of workflows", "err", err, "resp", resp)
}
for _, w := range workflowRuns.WorkflowRuns {
fmt.Println(w.GetID())
fmt.Println(w.GetConclusion())
}
}
func ListUpdateRuns() (*github.WorkflowRuns, *github.Response) {
workflowRuns, resp, err := client.Actions.ListWorkflowRunsByFileName(
context.Background(),
"daylinmorgan",
"oizys",
"update.yml",
nil,
)
if err != nil {
log.Fatal("failed to get last update run", "resp", resp, "err", err)
}
return workflowRuns, resp
}
func GetArtifacts(runID int64) (*github.ArtifactList, *github.Response) {
artifactList, resp, err := client.Actions.ListWorkflowRunArtifacts(context.Background(), "daylinmorgan", "oizys", runID, nil)
if err != nil {
log.Fatal("failed to get artifacts for run", "id", runID, "err", err)
}
return artifactList, resp
}
func GetUpdateSummaryArtifact(runID int64) *github.Artifact {
artifactList, _ := GetArtifacts(runID)
for _, artifact := range artifactList.Artifacts {
if artifact.GetName() == "summary" {
return artifact
}
}
log.Fatal("failed to find summary for run", "id", runID)
return nil
}
func GetUpdateSummaryUrl(runID int64) *url.URL {
artifact := GetUpdateSummaryArtifact(runID)
url, resp, err := client.Actions.DownloadArtifact(context.Background(), "daylinmorgan", "oizys", artifact.GetID(), 4)
if err != nil {
log.Fatal("failed to get update summary URL", "artifact", artifact.GetID(), "resp", resp)
}
return url
}
func GetUpdateSummaryFromUrl(url *url.URL) []byte {
log.Debug(url.String())
res, err := http.Get(url.String())
if err != nil {
log.Fatal("failed to get update summary zip", "err", err)
}
body, err := io.ReadAll(res.Body)
res.Body.Close()
if res.StatusCode > 299 {
log.Fatalf("Response failed with status code: %d and\nbody: %s\n", res.StatusCode, body)
}
if err != nil {
log.Fatal(err)
}
return body
}
func GetLastUpdateRun() *github.WorkflowRun {
workflowRuns, _ := ListUpdateRuns()
run := workflowRuns.WorkflowRuns[0]
if run.GetConclusion() == "failure" {
log.Fatal("Most recent run was not successful", "runId", run.GetID(), "conclusion", run.GetConclusion())
}
if run.GetStatus() == "in_progress" {
log.Fatalf("Most recent run is not finished\nview workflow run at: %s", run.GetHTMLURL())
}
return run
}
func GetUpateSummary(runID int64) (string, error) {
url := GetUpdateSummaryUrl(runID)
bytes := GetUpdateSummaryFromUrl(url)
md, err := ReadMarkdownFromZip(bytes, "summary.md")
return md, err
}
func ReadMarkdownFromZip(zipData []byte, fileName string) (string, error) {
// Open the zip reader from the in-memory byte slice
reader, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData)))
if err != nil {
return "", err
}
// Search for the target file
var markdownFile *zip.File
for _, f := range reader.File {
if f.Name == fileName {
markdownFile = f
break
}
}
if markdownFile == nil {
return "", fmt.Errorf("file %s not found in zip archive", fileName)
}
// Open the markdown file reader
fileReader, err := markdownFile.Open()
if err != nil {
return "", err
}
defer fileReader.Close()
// Read the markdown content
content, err := io.ReadAll(fileReader)
if err != nil {
return "", err
}
// Return the markdown content as string
return string(content), nil
}

View file

@ -5,6 +5,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
"oizys/internal/git"
"oizys/internal/ui"
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
@ -13,7 +15,6 @@ import (
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
e "oizys/internal/exec" e "oizys/internal/exec"
"oizys/internal/ui"
) )
var o *Oizys var o *Oizys
@ -24,10 +25,13 @@ func init() {
// verbose vs debug? // verbose vs debug?
type Oizys struct { type Oizys struct {
repo *git.GitRepo
flake string flake string
host string host string
cache string cache string
githubSummary string githubSummary string
githubToken string
local bool
inCI bool inCI bool
verbose bool verbose bool
systemPath bool systemPath bool
@ -52,21 +56,29 @@ func New() *Oizys {
} }
o.githubSummary = os.Getenv("GITHUB_STEP_SUMMARY") o.githubSummary = os.Getenv("GITHUB_STEP_SUMMARY")
o.inCI = o.githubSummary != "" o.inCI = o.githubSummary != ""
o.githubToken = os.Getenv("GITHUB_TOKEN")
o.repo = git.NewRepo(o.flake)
return o return o
} }
func GithubToken() string {
return o.githubToken
}
func SetFlake(path string) { func SetFlake(path string) {
// Check path exists // Check path exists
if path != "" { if path != "" {
o.flake = path o.flake = path
} }
// check local path exists
// check if path is local and exists
if !strings.HasPrefix(o.flake, "github") && !strings.HasPrefix(o.flake, "git+") { if !strings.HasPrefix(o.flake, "github") && !strings.HasPrefix(o.flake, "git+") {
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.Warnf("path to flake %s does not exist, using remote as fallback", o.flake) log.Warnf("path to flake %s does not exist, using remote as fallback", o.flake)
o.flake = "github:daylinmorgan/oizys" o.flake = "github:daylinmorgan/oizys"
} else {
o.local = true
} }
} }
} }
@ -127,33 +139,6 @@ func Output() {
} }
} }
func git(rest ...string) *exec.Cmd {
args := []string{"-C", o.flake}
args = append(args, rest...)
cmd := exec.Command("git", args...)
e.LogCmd(cmd)
return cmd
}
func GitPull() {
cmdOutput, err := git("status", "--porcelain").Output()
if err != nil {
log.Fatal(err)
}
if len(cmdOutput) > 0 {
fmt.Println("unstaged commits, cowardly exiting...")
ui.ShowFailedOutput(cmdOutput)
os.Exit(1)
}
cmdOutput, err = git("pull").CombinedOutput()
if err != nil {
ui.ShowFailedOutput(cmdOutput)
log.Fatal(err)
}
}
func parseDryRun(buf string) (*ui.Packages, *ui.Packages) { func parseDryRun(buf string) (*ui.Packages, *ui.Packages) {
lines := strings.Split(strings.TrimSpace(buf), "\n") lines := strings.Split(strings.TrimSpace(buf), "\n")
var parts [2][]string var parts [2][]string
@ -260,14 +245,8 @@ func NixosRebuild(subcmd string, rest ...string) {
e.ExitWithCommand(cmd) e.ExitWithCommand(cmd)
} }
func NixBuild(nom bool, minimal bool, rest ...string) { func NixBuild(minimal bool, rest ...string) {
var cmdName string cmd := exec.Command("nix", "build")
if nom {
cmdName = "nom"
} else {
cmdName = "nix"
}
cmd := exec.Command(cmdName, "build")
if o.resetCache { if o.resetCache {
cmd.Args = append(cmd.Args, "--narinfo-cache-negative-ttl", "0") cmd.Args = append(cmd.Args, "--narinfo-cache-negative-ttl", "0")
} }
@ -318,10 +297,10 @@ 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 Checks(nom bool, rest ...string) { func Checks(rest ...string) {
checks := o.getChecks() checks := o.getChecks()
for _, check := range checks { for _, check := range checks {
NixBuild(nom, false, o.checkPath(check)) NixBuild(false, o.checkPath(check))
} }
} }
@ -338,8 +317,17 @@ func CacheBuild(rest ...string) {
} }
func 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...)
e.ExitWithCommand(cmd) e.ExitWithCommand(cmd)
} }
func UpdateRepo() {
log.Info("rebasing HEAD on origin/flake-lock")
o.repo.Fetch()
o.repo.Rebase("origin/flake-lock")
}

View file

@ -7,8 +7,9 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/charmbracelet/log"
e "oizys/internal/exec" e "oizys/internal/exec"
"github.com/charmbracelet/log"
) )
var ignoredMap = stringSliceToMap( var ignoredMap = stringSliceToMap(
@ -16,16 +17,12 @@ var ignoredMap = stringSliceToMap(
// nix // nix
"ld-library-path", "builder.pl", "profile", "system-path", "ld-library-path", "builder.pl", "profile", "system-path",
// nixos // nixos
"nixos-install",
"nixos-version",
"nixos-manual-html",
"nixos-configuration-reference-manpage",
"nixos-rebuild",
"nixos-help", "nixos-help",
"nixos-generate-config", "nixos-install", "nixos-version",
"nixos-enter", "nixos-manual-html", "nixos-rebuild",
"nixos-container", "nixos-configuration-reference-manpage",
"nixos-build-vms", "nixos-generate-config", "nixos-enter",
"nixos-container", "nixos-build-vms",
"nixos-wsl-version", "nixos-wsl-welcome-message", "nixos-wsl-welcome", "nixos-wsl-version", "nixos-wsl-welcome-message", "nixos-wsl-welcome",
// trivial packages // trivial packages
"restic-gdrive", "gitea", "lock", "code", "restic-gdrive", "gitea", "lock", "code",

View file

@ -1,6 +1,7 @@
package ui package ui
import ( import (
"bufio"
"fmt" "fmt"
"os" "os"
"sort" "sort"
@ -101,3 +102,26 @@ func (p *Packages) summary() {
Render(fmt.Sprint(len(p.names))), Render(fmt.Sprint(len(p.names))),
) )
} }
// Confirm asks the user for confirmation.
// valid inputs are: y/yes,n/no case insensitive.
func Confirm(s string) bool {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf("%s [y/n]: ", s)
response, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
response = strings.ToLower(strings.TrimSpace(response))
switch response {
case "y", "yes":
return true
case "n", "no":
return false
}
}
}