Skip to content

Commit

Permalink
feat(pkg/godot/version): add GDENV_DEFAULT_MONO to simplify Mono us…
Browse files Browse the repository at this point in the history
…age; improve `gdenv` version resolution logic (#120)

* refactor: don't log in touchStore, log in command handlers

* chore: simplify env var variable names

* feat: add support for defaulting to mono versions

* chore: update documentation to use new variable name

* fix: call function for modified variable

* chore: add .godot-version to gitignore

* fix: improve version resolution logic; update commands docs to reflect this

* fix: match docs to cli usage text; use active voice

* fix: documentation grammar and style
  • Loading branch information
coffeebeats authored Oct 31, 2023
1 parent dcb23fa commit 5b4c90a
Show file tree
Hide file tree
Showing 15 changed files with 245 additions and 140 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ dist

# gdenv-related ignores
.gdenv
.godot-version
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ By default `gdenv` will install _Godot_ executables for the host platform (i.e.

However, to simplify use of `gdenv` when _Mono_ builds are desired, the following environment variable can be set to have `gdenv` default to using _Mono_ builds _when the version label is omitted_. A non-_Mono_ build can then be specified by passing a version label of `stable` without the `_mono` suffix.

- **`GDENV_MONO_DEFAULT`** - set to something truthy (e.g. `1`) to have `gdenv` interpret missing version labels as `stable_mono` instead of `stable`
- **`GDENV_DEFAULT_MONO`** - set to `1` to have `gdenv` interpret missing version labels as `stable_mono` instead of `stable`

## **Development**

Expand Down
4 changes: 2 additions & 2 deletions cmd/gdenv/completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ func NewCompletions() *cli.Command {
Name: "completions",
Category: "Utilities",

Usage: "print shell completions for the gdenv CLI application",
Usage: "print shell completions for the 'gdenv' CLI application",
UsageText: "gdenv completions [OPTIONS] <SHELL>",

Flags: []cli.Flag{
&cli.StringFlag{
Name: "output",
Aliases: []string{"p"},
Usage: "Write the completions to `OUT_FILE`",
Usage: "write the completions to 'OUT_FILE'",
},
},

Expand Down
67 changes: 44 additions & 23 deletions cmd/gdenv/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"os"
"path/filepath"

"github.com/charmbracelet/log"
Expand All @@ -31,7 +30,8 @@ func NewInstall() *cli.Command { //nolint:funlen

Aliases: []string{"i"},

Usage: "download and cache a specific version of Godot",
Usage: "download and cache a specific version of Godot; " +
"if 'VERSION' is omitted then the version is resolved using '-g', '-p', or '$PWD'",
UsageText: "gdenv install [OPTIONS] [VERSION]",

Flags: []cli.Flag{
Expand All @@ -43,12 +43,12 @@ func NewInstall() *cli.Command { //nolint:funlen
&cli.BoolFlag{
Name: "global",
Aliases: []string{"g"},
Usage: "pin the system version",
Usage: "update the global pin (if 'VERSION' is specified) or resolve 'VERSION' from the global pin",
},
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "determine the version from the pinned `PATH` (cannot be used with '-g')",
Usage: "resolve the pinned 'VERSION' at 'PATH'",
},
&cli.BoolFlag{
Name: "source",
Expand All @@ -66,7 +66,7 @@ func NewInstall() *cli.Command { //nolint:funlen
return UsageError{ctx: c, err: ErrInstallUsageGlobalAndSource}
}

v, err := resolveVersionFromArgOrPath(c)
v, err := resolveVersionFromInput(c)
if err != nil {
return err
}
Expand All @@ -76,6 +76,8 @@ func NewInstall() *cli.Command { //nolint:funlen
return err
}

log.Debugf("using store at path: %s", storePath)

if c.Bool("source") {
return installSource(c.Context, storePath, v, c.Bool("force"))
}
Expand Down Expand Up @@ -178,11 +180,25 @@ func installSource(
return nil
}

/* ------------------ Function: resolveVersionFromArgOrPath ----------------- */

// Parses command arguments and reads pin files to determine the correct version
// of Godot to use.
func resolveVersionFromArgOrPath(c *cli.Context) (version.Version, error) {
/* -------------------- Function: resolveVersionFromInput ------------------- */

// Parses command arguments and environment variables and reads pin files to
// determine the correct version of Godot to use.
//
// There are four distinct situations which need to be handled. These are listed
// below along with their desired resolution:
// 1. An explicit version is passed in (e.g. `install <version>`)
// > The explicitly specified version is returned.
// 2. No version is passed, but the '-g' flag is used (e.g. `install -g`)
// > The globally pinned version is returned.
// 3. No version is passed, but the '-p' flag is used (e.g. `install --path <path>`)
// > The pinned version is resolved _at the provided path_.
// 4. No version is passed and no other flag is passed (e.g. `install`)
// > The pinned version is resolved _in the current working directory_.
//
// For 3. and 4., both of which require pin resolution, the standard resolution
// strategy of checking for a local pin and then a global is used.
func resolveVersionFromInput(c *cli.Context) (version.Version, error) {
versionArg := c.Args().First()

v, err := version.Parse(versionArg)
Expand All @@ -194,20 +210,27 @@ func resolveVersionFromArgOrPath(c *cli.Context) (version.Version, error) {
return v, nil
}

path := filepath.Clean(c.String("path"))
if path == "" {
path, err = os.Getwd() // Update 'path' value.
if err != nil {
return version.Version{}, err
}
storePath, err := store.Path()
if err != nil {
return version.Version{}, err
}

// If '-g' is passed then _only_ the globally-pinned version should be
// returned. Prior validation should have already ensured '-p' was not
// simultaneously set.
if c.IsSet("global") && c.Bool("global") {
return pin.Read(storePath)
}

// NOTE: Omit store path to avoid resolving the global pin version.
v, err = pin.VersionAt(c.Context, "", path) // Update 'v' value.
// NOTE: 'filepath.Clean' will replace '' with '.', handling cases 3. and 4.
// simultaneously.
path := filepath.Clean(c.String("path"))

v, err = pin.VersionAt(c.Context, storePath, path) // Update 'v' value.
if err != nil {
// Return an error that communicates the root problem and hides the
// storePath="" hack from above.
if errors.Is(err, pin.ErrMissingPath) {
// Return an error that communicates the root problem and hides any
// attempted global pin resolution.
if errors.Is(err, pin.ErrMissingPath) || errors.Is(err, pin.ErrMissingPin) {
return version.Version{}, fmt.Errorf("%w: %s", pin.ErrMissingPin, path)
}

Expand All @@ -227,8 +250,6 @@ func touchStore() (string, error) {
return "", err
}

log.Debugf("using store at path: %s", storePath)

// Ensure the store exists.
if err := store.Touch(storePath); err != nil {
return "", err
Expand Down
2 changes: 2 additions & 0 deletions cmd/gdenv/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func NewLs() *cli.Command {
return err
}

log.Debugf("using store at path: %s", storePath)

src, all := c.Bool("source"), c.Bool("all")

if !src {
Expand Down
4 changes: 3 additions & 1 deletion cmd/gdenv/pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func NewPin() *cli.Command { //nolint:funlen
&cli.BoolFlag{
Name: "install",
Aliases: []string{"i"},
Usage: "installs the specified version of Godot if missing",
Usage: "install the specified version of Godot if missing",
},
&cli.BoolFlag{
Name: "force",
Expand Down Expand Up @@ -71,6 +71,8 @@ func NewPin() *cli.Command { //nolint:funlen
return err
}

log.Debugf("using store at path: %s", storePath)

// Determine 'path' option
pinPath, err := resolvePath(c)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion cmd/gdenv/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func NewUninstall() *cli.Command {
Name: "uninstall",
Category: "Install",

Usage: "remove the specified version of Godot from the gdenv download cache",
Usage: "Remove the specified version of Godot from the 'gdenv' download cache",
UsageText: "gdenv uninstall [OPTIONS] [VERSION]",

Flags: []cli.Flag{
Expand All @@ -40,6 +40,8 @@ func NewUninstall() *cli.Command {
return err
}

log.Debugf("using store at path: %s", storePath)

src, all := c.Bool("source"), c.Bool("all")

// Uninstall all versions.
Expand Down
2 changes: 1 addition & 1 deletion cmd/gdenv/unpin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewUnpin() *cli.Command {
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "unpin the specified `PATH` (cannot be used with '-g')",
Usage: "unpin the specified 'PATH' (cannot be used with '-g')",
},
},

Expand Down
8 changes: 5 additions & 3 deletions cmd/gdenv/vendor.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ func NewVendor() *cli.Command {
&cli.StringFlag{
Name: "out",
Aliases: []string{"o"},
Usage: "download the source code into `OUT` (will overwrite conflicting files)",
Usage: "extract the source code into 'OUT' (overwrites conflicting files)",
},
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "determine the version from the pinned `PATH` (ignores the global pin)",
Usage: "resolve the pinned 'VERSION' at 'PATH'",
},
},

Action: func(c *cli.Context) error {
v, err := resolveVersionFromArgOrPath(c)
v, err := resolveVersionFromInput(c)
if err != nil {
return err
}
Expand All @@ -57,6 +57,8 @@ func NewVendor() *cli.Command {
return err
}

log.Debugf("using store at path: %s", storePath)

if err := installSource(c.Context, storePath, v, c.Bool("force")); err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/gdenv/which.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func NewWhich() *cli.Command {
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "Check the specified `PATH`",
Usage: "check at the specified `PATH`",
},
},

Expand All @@ -37,6 +37,8 @@ func NewWhich() *cli.Command {
return err
}

log.Debugf("using store at path: %s", storePath)

// Define the host 'Platform'.
p, err := platform.Detect()
if err != nil {
Expand Down
Loading

0 comments on commit 5b4c90a

Please sign in to comment.