feat(golang-rewrite): refactor completion code and move all packages except cmd into internal

* Refactor and move `completion` package to `internal/completions`
* Move `cli` and `repotest` packages to `internal/cli`
* Use passed version information for `--version` flag
* Add simple test for completions package
This commit is contained in:
DeedleFake 2024-12-18 15:31:36 -05:00 committed by Trevor Brown
parent 9c12b79969
commit 518a0fa442
20 changed files with 95 additions and 52 deletions

View File

@ -1,7 +1,7 @@
// Main entrypoint for the CLI app // Main entrypoint for the CLI app
package main package main
import "github.com/asdf-vm/asdf/cli" import "github.com/asdf-vm/asdf/internal/cli"
// Replaced with the real version during a typical build // Replaced with the real version during a typical build
var version = "v-dev" var version = "v-dev"

View File

@ -2,7 +2,6 @@
package cli package cli
import ( import (
_ "embed"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -14,6 +13,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/asdf-vm/asdf/internal/completions"
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/exec" "github.com/asdf-vm/asdf/internal/exec"
"github.com/asdf-vm/asdf/internal/execenv" "github.com/asdf-vm/asdf/internal/execenv"
@ -52,7 +52,7 @@ func Execute(version string) {
app := &cli.App{ app := &cli.App{
Name: "asdf", Name: "asdf",
Version: "0.1.0", Version: version,
// Not really sure what I should put here, but all the new Golang code will // Not really sure what I should put here, but all the new Golang code will
// likely be written by me. // likely be written by me.
Copyright: "(c) 2024 Trevor Brown", Copyright: "(c) 2024 Trevor Brown",
@ -315,45 +315,18 @@ func Execute(version string) {
} }
} }
//go:embed completions/asdf.bash
var bashCompletions string
//go:embed completions/asdf.zsh
var zshCompletions string
//go:embed completions/asdf.fish
var fishCompletions string
//go:embed completions/asdf.nu
var nuCompletions string
//go:embed completions/asdf.elv
var elvishCompletions string
func completionCommand(l *log.Logger, shell string) error { func completionCommand(l *log.Logger, shell string) error {
switch shell { file, ok := completions.Get(shell)
case "bash": if !ok {
fmt.Print(bashCompletions) l.Printf(`No completions available for shell with name %q
return nil Completions are available for: %v`, shell, strings.Join(completions.Names(), ", "))
case "zsh": return errors.New("bad shell name")
fmt.Print(zshCompletions)
return nil
case "fish":
fmt.Print(fishCompletions)
return nil
case "nushell":
fmt.Print(nuCompletions)
return nil
case "elvish":
fmt.Print(elvishCompletions)
return nil
default:
fmtString := `No completions available for shell with name %s
Completions are available for: bash, zsh, fish, nushell, elvish`
msg := fmt.Sprintf(fmtString, shell)
l.Print(msg)
return errors.New(msg)
} }
defer file.Close()
io.Copy(os.Stdout, file)
return nil
} }
// This function is a whole mess and needs to be refactored // This function is a whole mess and needs to be refactored

View File

@ -0,0 +1,40 @@
// Package completions handles shell completion files.
//
// To add completion support for a shell, simply add a file named
// "asdf.<shell>" to this directory, replacing "<shell>" with the name
// of the shell.
package completions
import (
"embed"
"errors"
"io/fs"
"slices"
"strings"
)
//go:embed asdf.*
var completions embed.FS
// Get returns a file containing completion code for the given shell if it is
// found.
func Get(name string) (fs.File, bool) {
file, err := completions.Open("asdf." + name)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil, false
}
panic(err) // This should never happen.
}
return file, true
}
// Names returns a slice of shell names that completion is available for.
func Names() []string {
files, _ := fs.Glob(completions, "asdf.*")
for i, file := range files {
files[i] = strings.TrimPrefix(file, "asdf.")
}
slices.Sort(files)
return files
}

View File

@ -0,0 +1,30 @@
package completions
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGet(t *testing.T) {
t.Run("returns file when completion file found with matching name", func(t *testing.T) {
file, found := Get("bash")
info, err := file.Stat()
assert.Nil(t, err)
assert.Equal(t, "asdf.bash", info.Name())
assert.True(t, found)
})
t.Run("returns false when completion file not found", func(t *testing.T) {
_, found := Get("non-existent")
assert.False(t, found)
})
}
func TestNames(t *testing.T) {
t.Run("returns slice of shell names for which completion is available", func(t *testing.T) {
assert.Equal(t, []string{"bash", "elvish", "fish", "nushell", "zsh"}, Names())
})
}

View File

@ -5,7 +5,7 @@ import (
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/plugins" "github.com/asdf-vm/asdf/internal/plugins"
"github.com/asdf-vm/asdf/repotest" "github.com/asdf-vm/asdf/internal/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -5,7 +5,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/asdf-vm/asdf/repotest" "github.com/asdf-vm/asdf/internal/repotest"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@ -9,7 +9,7 @@ import (
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/plugins" "github.com/asdf-vm/asdf/internal/plugins"
"github.com/asdf-vm/asdf/repotest" "github.com/asdf-vm/asdf/internal/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -8,8 +8,8 @@ import (
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/installtest" "github.com/asdf-vm/asdf/internal/installtest"
"github.com/asdf-vm/asdf/internal/plugins" "github.com/asdf-vm/asdf/internal/plugins"
"github.com/asdf-vm/asdf/internal/repotest"
"github.com/asdf-vm/asdf/internal/toolversions" "github.com/asdf-vm/asdf/internal/toolversions"
"github.com/asdf-vm/asdf/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/asdf-vm/asdf/internal/git" "github.com/asdf-vm/asdf/internal/git"
"github.com/asdf-vm/asdf/repotest" "github.com/asdf-vm/asdf/internal/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -9,7 +9,7 @@ import (
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/data" "github.com/asdf-vm/asdf/internal/data"
"github.com/asdf-vm/asdf/repotest" "github.com/asdf-vm/asdf/internal/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -8,7 +8,7 @@ import (
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/plugins" "github.com/asdf-vm/asdf/internal/plugins"
"github.com/asdf-vm/asdf/repotest" "github.com/asdf-vm/asdf/internal/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -12,8 +12,8 @@ import (
"github.com/asdf-vm/asdf/internal/installs" "github.com/asdf-vm/asdf/internal/installs"
"github.com/asdf-vm/asdf/internal/installtest" "github.com/asdf-vm/asdf/internal/installtest"
"github.com/asdf-vm/asdf/internal/plugins" "github.com/asdf-vm/asdf/internal/plugins"
"github.com/asdf-vm/asdf/internal/repotest"
"github.com/asdf-vm/asdf/internal/toolversions" "github.com/asdf-vm/asdf/internal/toolversions"
"github.com/asdf-vm/asdf/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )

View File

@ -9,8 +9,8 @@ import (
"github.com/asdf-vm/asdf/internal/config" "github.com/asdf-vm/asdf/internal/config"
"github.com/asdf-vm/asdf/internal/plugins" "github.com/asdf-vm/asdf/internal/plugins"
"github.com/asdf-vm/asdf/internal/repotest"
"github.com/asdf-vm/asdf/internal/toolversions" "github.com/asdf-vm/asdf/internal/toolversions"
"github.com/asdf-vm/asdf/repotest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -31,7 +31,7 @@ run_shfmt_stylecheck() {
print.info "Checking .bash with shfmt" print.info "Checking .bash with shfmt"
shfmt --language-dialect bash --indent 2 "${shfmt_flag}" \ shfmt --language-dialect bash --indent 2 "${shfmt_flag}" \
cli/completions/*.bash \ internal/completions/*.bash \
bin/asdf \ bin/asdf \
bin/private/asdf-exec \ bin/private/asdf-exec \
lib/utils.bash \ lib/utils.bash \
@ -55,7 +55,7 @@ run_shellcheck_linter() {
print.info "Checking .bash files with Shellcheck" print.info "Checking .bash files with Shellcheck"
shellcheck --shell bash --external-sources \ shellcheck --shell bash --external-sources \
cli/completions/*.bash \ internal/completions/*.bash \
bin/asdf \ bin/asdf \
bin/private/asdf-exec \ bin/private/asdf-exec \
lib/utils.bash \ lib/utils.bash \
@ -123,7 +123,7 @@ run_fish_linter() {
printf "%s\n" "[WARNING] fish_indent not found. Skipping .fish files." printf "%s\n" "[WARNING] fish_indent not found. Skipping .fish files."
else else
print.info "Checking .fish files with fish_indent" print.info "Checking .fish files with fish_indent"
fish_indent "${flag}" ./cli/completions/asdf.fish fish_indent "${flag}" ./completions/asdf.fish
fi fi
} }