diff --git a/internal/build/build.go b/internal/build/build.go index ca24bbf..364f02d 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -121,6 +121,11 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string return nil, nil, err } + err = installOptDeps(ctx, vars, opts, installed) + if err != nil { + return nil, nil, err + } + builtPaths, builtNames, repoDeps, err := installDeps(ctx, opts, vars) if err != nil { return nil, nil, err @@ -316,6 +321,30 @@ func installBuildDeps(ctx context.Context, vars *types.BuildVars, opts types.Bui return buildDeps, nil } +func installOptDeps(ctx context.Context, vars *types.BuildVars, opts types.BuildOpts, installed map[string]string) error { + if len(vars.OptDepends) > 0 { + optDeps, err := cliutils.ChooseOptDepends(vars.OptDepends, "install", opts.Interactive) + if err != nil { + return err + } + + if len(optDeps) == 0 { + return nil + } + + found, notFound, err := repos.FindPkgs(optDeps) + if err != nil { + return err + } + + found = filterBuildDeps(found, installed) + flattened := cliutils.FlattenPkgs(found, "install", opts.Interactive) + optDeps = packageNames(flattened) + InstallPkgs(ctx, flattened, notFound, opts) + } + return nil +} + func installDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVars) (builtPaths, builtNames, repoDeps []string, err error) { if len(vars.Depends) > 0 { log.Info("Installing dependencies").Send() diff --git a/internal/cliutils/prompt.go b/internal/cliutils/prompt.go index 381927f..03905f0 100644 --- a/internal/cliutils/prompt.go +++ b/internal/cliutils/prompt.go @@ -20,6 +20,7 @@ package cliutils import ( "os" + "strings" "github.com/AlecAivazis/survey/v2" "go.elara.ws/lure/internal/config" @@ -116,7 +117,6 @@ func FlattenPkgs(found map[string][]db.Package, verb string, interactive bool) [ } // PkgPrompt asks the user to choose between multiple packages. -// The user may choose multiple packages. func PkgPrompt(options []db.Package, verb string, interactive bool) (db.Package, error) { if !interactive { return options[0], nil @@ -140,3 +140,29 @@ func PkgPrompt(options []db.Package, verb string, interactive bool) (db.Package, return options[choice], nil } + +// ChooseOptDepends asks the user to choose between multiple optional dependencies. +// The user may choose multiple items. +func ChooseOptDepends(options []string, verb string, interactive bool) ([]string, error) { + if !interactive { + return []string{}, nil + } + + prompt := &survey.MultiSelect{ + Options: options, + Message: translations.Translator().TranslateTo("Choose which optional package(s) to install", config.Language()), + } + + var choices []int + err := survey.AskOne(prompt, &choices) + if err != nil { + return nil, err + } + + out := make([]string, len(choices)) + for i, choiceIndex := range choices { + out[i], _, _ = strings.Cut(options[choiceIndex], ": ") + } + + return out, nil +} diff --git a/internal/db/db.go b/internal/db/db.go index 1b9921b..a19c0a6 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -24,7 +24,6 @@ import ( "encoding/json" "errors" "fmt" - "os" "github.com/jmoiron/sqlx" "go.elara.ws/lure/internal/config" @@ -33,7 +32,7 @@ import ( "modernc.org/sqlite" ) -const CurrentVersion = 1 +const CurrentVersion = 2 func init() { sqlite.MustRegisterScalarFunction("json_array_contains", 2, JsonArrayContains) @@ -55,6 +54,7 @@ type Package struct { Replaces JSON[[]string] `sh:"replaces" db:"replaces"` Depends JSON[map[string][]string] `db:"depends"` BuildDepends JSON[map[string][]string] `db:"builddepends"` + OptDepends JSON[map[string][]string] `db:"optdepends"` Repository string `db:"repository"` } @@ -124,6 +124,7 @@ func initDB(dsn string) error { replaces TEXT CHECK(replaces = 'null' OR (JSON_VALID(replaces) AND JSON_TYPE(replaces) = 'array')), depends TEXT CHECK(depends = 'null' OR (JSON_VALID(depends) AND JSON_TYPE(depends) = 'object')), builddepends TEXT CHECK(builddepends = 'null' OR (JSON_VALID(builddepends) AND JSON_TYPE(builddepends) = 'object')), + optdepends TEXT CHECK(optdepends = 'null' OR (JSON_VALID(optdepends) AND JSON_TYPE(optdepends) = 'object')), UNIQUE(name, repository) ); @@ -136,30 +137,27 @@ func initDB(dsn string) error { } ver, ok := GetVersion() - if !ok { + if ok && ver != CurrentVersion { + log.Warn("Database version mismatch; resetting").Int("version", ver).Int("expected", CurrentVersion).Send() + Reset() + return initDB(dsn) + } else if !ok { log.Warn("Database version does not exist. Run lure fix if something isn't working.").Send() return addVersion(CurrentVersion) } - if ver != CurrentVersion { - log.Warn("Database version mismatch; rebuilding").Int("version", ver).Int("expected", CurrentVersion).Send() - - conn.Close() - err = os.Remove(config.GetPaths().DBPath) - if err != nil { - return err - } - - tdb, err := Open(dsn) - if err != nil { - return err - } - conn = tdb - } - return nil } +func Reset() error { + _, err := DB().Exec("DROP TABLE IF EXISTS pkgs;") + if err != nil { + return err + } + _, err = DB().Exec("DROP TABLE IF EXISTS lure_db_version;") + return err +} + func IsEmpty() bool { var count int err := DB().Get(&count, "SELECT count(1) FROM pkgs;") @@ -201,7 +199,8 @@ func InsertPackage(pkg Package) error { conflicts, replaces, depends, - builddepends + builddepends, + optdepends ) VALUES ( :name, :repository, @@ -217,7 +216,8 @@ func InsertPackage(pkg Package) error { :conflicts, :replaces, :depends, - :builddepends + :builddepends, + :optdepends ); `, pkg) return err diff --git a/internal/overrides/overrides.go b/internal/overrides/overrides.go index 1992054..759324d 100644 --- a/internal/overrides/overrides.go +++ b/internal/overrides/overrides.go @@ -163,6 +163,7 @@ type ResolvedPackage struct { Replaces []string `sh:"replaces"` Depends []string `sh:"deps"` BuildDepends []string `sh:"build_deps"` + OptDepends []string `sh:"opt_deps"` } func ResolvePackage(pkg *db.Package, overrides []string) *ResolvedPackage { diff --git a/internal/repos/pull.go b/internal/repos/pull.go index b41e1f1..a06914d 100644 --- a/internal/repos/pull.go +++ b/internal/repos/pull.go @@ -98,12 +98,12 @@ func Pull(ctx context.Context, repos []types.Repo) error { // empty. In this case, we need to update the DB fully // rather than just incrementally. if db.IsEmpty() { - err = processRepoChanges(ctx, repo, r, w, old, new) + err = processRepoFull(ctx, repo, repoDir) if err != nil { return err } } else { - err = processRepoFull(ctx, repo, repoDir) + err = processRepoChanges(ctx, repo, r, w, old, new) if err != nil { return err } diff --git a/internal/types/build.go b/internal/types/build.go index d9f9865..82667dc 100644 --- a/internal/types/build.go +++ b/internal/types/build.go @@ -43,6 +43,7 @@ type BuildVars struct { Conflicts []string `sh:"conflicts"` Depends []string `sh:"deps"` BuildDepends []string `sh:"build_deps"` + OptDepends []string `sh:"opt_deps"` Replaces []string `sh:"replaces"` Sources []string `sh:"sources"` Checksums []string `sh:"checksums"`