Skip to content
Draft
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
125 changes: 120 additions & 5 deletions cmd/init/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ package init
import (
"fmt"
"os"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/jedib0t/go-pretty/v6/progress"
"github.com/spf13/cobra"

bsfv1 "github.com/buildsafedev/bsf-apis/go/buildsafe/v1"
"github.com/buildsafedev/bsf/cmd/configure"
"github.com/buildsafedev/bsf/cmd/precheck"
"github.com/buildsafedev/bsf/cmd/styles"
"github.com/buildsafedev/bsf/pkg/clients/search"
"github.com/buildsafedev/bsf/pkg/generate"
bgit "github.com/buildsafedev/bsf/pkg/git"
"github.com/buildsafedev/bsf/pkg/hcl2nix"
"github.com/buildsafedev/bsf/pkg/langdetect"
"github.com/buildsafedev/bsf/pkg/nix/cmd"
)

// InitCmd represents the init command
Expand All @@ -35,17 +40,103 @@ var InitCmd = &cobra.Command{

sc, err := search.NewClientWithAddr(conf.BuildSafeAPI, conf.BuildSafeAPITLS)
if err != nil {
fmt.Println(styles.ErrorStyle.Render("error:", err.Error()))
os.Exit(1)
}

m := model{sc: sc}
m.resetSpinner()
if _, err := tea.NewProgram(m).Run(); err != nil {
err = initializeProject(sc)
if err != nil {
errorMessage := err.Error()
fmt.Println(styles.ErrorStyle.Render("Error:", errorMessage))
if errorMessage != "project already initialised. bsf.hcl found" {
cleanUp()
}
os.Exit(1)
}

fmt.Println(styles.SucessStyle.Render("Initialized successfully!"))
},
}

func initializeProject(sc bsfv1.SearchServiceClient) error {
// Set up the progress writer
pw, steps := setupProgressTracker()

trackers := make([]*progress.Tracker, len(steps))
for i, step := range steps {
trackers[i] = &progress.Tracker{Message: step, Total: 100}
pw.AppendTracker(trackers[i])
}

go pw.Render()

// Initialize progress tracking
updateProgress := func(tracker *progress.Tracker, progress int64) {
tracker.SetValue(progress)
if progress >= 100 {
tracker.MarkAsDone()
}
}

// Detect project language
pt, pd, err := langdetect.FindProjectType()
if err != nil {
return err
}
updateProgress(trackers[0], 100)

// Resolve dependencies
fh, err := hcl2nix.NewFileHandlers(false)
if err != nil {
return err
}
defer fh.ModFile.Close()
defer fh.LockFile.Close()
defer fh.FlakeFile.Close()
defer fh.DefFlakeFile.Close()
updateProgress(trackers[1], 100)

// Write configuration
conf, err := generatehcl2NixConf(pt, pd)
if err != nil {
return err
}
err = hcl2nix.WriteConfig(conf, fh.ModFile)
if err != nil {
return err
}
updateProgress(trackers[2], 100)

// Generate files
err = generate.Generate(fh, sc)
if err != nil {
return err
}
updateProgress(trackers[3], 100)

// Lock dependencies
err = cmd.Lock(func(progress int) {
updateProgress(trackers[4], int64(progress))
})
if err != nil {
return err
}

// Add to git
err = bgit.Add("bsf/")
if err != nil {
return err
}

// Set up git ignore
err = bgit.Ignore("bsf-result/")
if err != nil {
return err
}

return nil
}

// GetBSFInitializers generates the nix files
func GetBSFInitializers() (bsfv1.SearchServiceClient, *hcl2nix.FileHandlers, error) {
if _, err := os.Stat("bsf.hcl"); err != nil {
Expand All @@ -72,10 +163,34 @@ func GetBSFInitializers() (bsfv1.SearchServiceClient, *hcl2nix.FileHandlers, err
}

// CleanUp removes the bsf config if any error occurs in init process (ctrl+c or any init process stage)
func cleanUp(){
func cleanUp() {
configs := []string{"bsf", "bsf.hcl", "bsf.lock"}

for _, f := range configs {
os.RemoveAll(f)
}
}

func setupProgressTracker() (progress.Writer, []string) {
pw := progress.NewWriter()
pw.SetAutoStop(true)
pw.SetTrackerLength(25)
pw.SetMessageLength(50)
pw.SetUpdateFrequency(time.Millisecond * 100)
pw.Style().Colors = progress.StyleColorsExample
pw.Style().Options.PercentFormat = "%4.1f%%"
pw.Style().Visibility.ETA = true
pw.Style().Visibility.Percentage = true
pw.Style().Visibility.Time = true

// Define the steps and create trackers for each
steps := []string{
"Detecting project language...",
"Resolving dependencies...",
"Writing configuration...",
"Generating files...",
"Locking dependencies...",
}

return pw, steps
}
159 changes: 0 additions & 159 deletions cmd/init/model.go

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/hcl2nix/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func NewFileHandlers(expectInit bool) (*FileHandlers, error) {
}

if exists != expectInit {
return nil, fmt.Errorf("Project already initialised. bsf.hcl found")
return nil, fmt.Errorf("project already initialised. bsf.hcl found")
}

lockFile, err := os.Create("bsf.lock")
Expand Down
1 change: 0 additions & 1 deletion pkg/nix/cmd/closure.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ func addNarHashToGraph(graph *gographviz.Graph) {
}

wg.Wait()
return
}

// GetNarHashFromPath returns the sha256 hash of the nar
Expand Down
9 changes: 8 additions & 1 deletion pkg/nix/cmd/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"fmt"
"os"
"os/exec"
"time"
)

// Lock generates the Nix flake lock file
func Lock() error {
func Lock(reportProgress func(int)) error {
dir, err := os.Getwd()
if err != nil {
return err
Expand All @@ -24,6 +25,12 @@ func Lock() error {
return fmt.Errorf("failed with %s", err)
}

// Simulate incremental progress
for i := 0; i <= 100; i += 10 {
time.Sleep(100 * time.Millisecond)
reportProgress(i)
}

err = cmd.Wait()
if err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
Expand Down