mirror of
https://github.com/asdf-vm/asdf.git
synced 2024-12-19 09:55:01 -07:00
feat(golang-rewrite): create installs and installtest packages to avoid circular dependency
* Correct `go test` command in GitHub test workflow * Update execute tests to work on Github Actions * Check in `shims/testdata` directory * Create `installtest` helper package * Create `installs` package
This commit is contained in:
parent
05e0a4a57f
commit
be52d8f39c
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@ -52,7 +52,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: go get .
|
||||
- name: Run Go tests
|
||||
run: go test
|
||||
run: go test -coverprofile=/tmp/coverage.out -bench= -race ./...
|
||||
|
||||
# Because I changed the test helper code Bash tests now fail. I removed them
|
||||
# from here to get passing checks. They can be added back at a later time if
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/info"
|
||||
"asdf/internal/installs"
|
||||
"asdf/internal/plugins"
|
||||
"asdf/internal/shims"
|
||||
"asdf/internal/versions"
|
||||
@ -425,7 +426,7 @@ func latestForPlugin(conf config.Config, toolName, pattern string, showStatus bo
|
||||
}
|
||||
|
||||
if showStatus {
|
||||
installed := versions.IsInstalled(conf, plugin, latest)
|
||||
installed := installs.IsInstalled(conf, plugin, latest)
|
||||
fmt.Printf("%s\t%s\t%s\n", plugin.Name, latest, installedStatus(installed))
|
||||
} else {
|
||||
fmt.Printf("%s\n", latest)
|
||||
|
@ -33,7 +33,7 @@ func TestRun_Command(t *testing.T) {
|
||||
err := cmd.Run()
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "sh is /bin/sh\n", stdout.String())
|
||||
assert.Contains(t, stdout.String(), "sh is /")
|
||||
})
|
||||
|
||||
t.Run("positional arg is passed to command", func(t *testing.T) {
|
||||
@ -108,7 +108,7 @@ func TestRun_Expression(t *testing.T) {
|
||||
err := cmd.Run()
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "sh is /bin/sh\n", stdout.String())
|
||||
assert.Contains(t, stdout.String(), "sh is /")
|
||||
})
|
||||
|
||||
t.Run("positional arg is passed to expression", func(t *testing.T) {
|
||||
|
64
internal/installs/installs.go
Normal file
64
internal/installs/installs.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Package installs contains tool installation logic. It is "dumb" when it comes
|
||||
// to versions and treats versions as opaque strings. It cannot depend on the
|
||||
// versions package because the versions package relies on this page.
|
||||
package installs
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
dataDirInstalls = "installs"
|
||||
dataDirDownloads = "downloads"
|
||||
)
|
||||
|
||||
// Installed returns a slice of all installed versions for a given plugin
|
||||
func Installed(conf config.Config, plugin plugins.Plugin) (versions []string, err error) {
|
||||
installDirectory := pluginInstallPath(conf, plugin)
|
||||
files, err := os.ReadDir(installDirectory)
|
||||
if err != nil {
|
||||
if _, ok := err.(*fs.PathError); ok {
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
return versions, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
versions = append(versions, file.Name())
|
||||
}
|
||||
|
||||
return versions, err
|
||||
}
|
||||
|
||||
// InstallPath returns the path to a tool installation
|
||||
func InstallPath(conf config.Config, plugin plugins.Plugin, version string) string {
|
||||
return filepath.Join(pluginInstallPath(conf, plugin), version)
|
||||
}
|
||||
|
||||
// DownloadPath returns the download path for a particular plugin and version
|
||||
func DownloadPath(conf config.Config, plugin plugins.Plugin, version string) string {
|
||||
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, version)
|
||||
}
|
||||
|
||||
// IsInstalled checks if a specific version of a tool is installed
|
||||
func IsInstalled(conf config.Config, plugin plugins.Plugin, version string) bool {
|
||||
installDir := InstallPath(conf, plugin, version)
|
||||
|
||||
// Check if version already installed
|
||||
_, err := os.Stat(installDir)
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
|
||||
func pluginInstallPath(conf config.Config, plugin plugins.Plugin) string {
|
||||
return filepath.Join(conf.DataDir, dataDirInstalls, plugin.Name)
|
||||
}
|
72
internal/installs/installs_test.go
Normal file
72
internal/installs/installs_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
package installs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/installtest"
|
||||
"asdf/internal/plugins"
|
||||
"asdf/repotest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const testPluginName = "lua"
|
||||
|
||||
func TestInstalled(t *testing.T) {
|
||||
conf, plugin := generateConfig(t)
|
||||
|
||||
t.Run("returns empty slice for newly installed plugin", func(t *testing.T) {
|
||||
installedVersions, err := Installed(conf, plugin)
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, installedVersions)
|
||||
})
|
||||
|
||||
t.Run("returns slice of all installed versions for a tool", func(t *testing.T) {
|
||||
mockInstall(t, conf, plugin, "1.0.0")
|
||||
|
||||
installedVersions, err := Installed(conf, plugin)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, installedVersions, []string{"1.0.0"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsInstalled(t *testing.T) {
|
||||
conf, plugin := generateConfig(t)
|
||||
installVersion(t, conf, plugin, "1.0.0")
|
||||
|
||||
t.Run("returns false when not installed", func(t *testing.T) {
|
||||
assert.False(t, IsInstalled(conf, plugin, "4.0.0"))
|
||||
})
|
||||
t.Run("returns true when installed", func(t *testing.T) {
|
||||
assert.True(t, IsInstalled(conf, plugin, "1.0.0"))
|
||||
})
|
||||
}
|
||||
|
||||
// helper functions
|
||||
func generateConfig(t *testing.T) (config.Config, plugins.Plugin) {
|
||||
t.Helper()
|
||||
testDataDir := t.TempDir()
|
||||
conf, err := config.LoadConfig()
|
||||
assert.Nil(t, err)
|
||||
conf.DataDir = testDataDir
|
||||
|
||||
_, err = repotest.InstallPlugin("dummy_plugin", testDataDir, testPluginName)
|
||||
assert.Nil(t, err)
|
||||
|
||||
return conf, plugins.New(conf, testPluginName)
|
||||
}
|
||||
|
||||
func mockInstall(t *testing.T, conf config.Config, plugin plugins.Plugin, version string) {
|
||||
t.Helper()
|
||||
path := InstallPath(conf, plugin, version)
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func installVersion(t *testing.T, conf config.Config, plugin plugins.Plugin, version string) {
|
||||
t.Helper()
|
||||
err := installtest.InstallOneVersion(conf, plugin, "version", version)
|
||||
assert.Nil(t, err)
|
||||
}
|
78
internal/installtest/installtest.go
Normal file
78
internal/installtest/installtest.go
Normal file
@ -0,0 +1,78 @@
|
||||
// Package installtest provides functions used by various asdf tests for
|
||||
// installing versions of tools. It provides a simplified version of the
|
||||
// versions.InstallOneVersion function.
|
||||
package installtest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/plugins"
|
||||
)
|
||||
|
||||
const (
|
||||
dataDirInstalls = "installs"
|
||||
dataDirDownloads = "downloads"
|
||||
)
|
||||
|
||||
// InstallOneVersion is a simplified version of versions.InstallOneVersion
|
||||
// function for use in Go tests.
|
||||
func InstallOneVersion(conf config.Config, plugin plugins.Plugin, versionType, version string) error {
|
||||
var stdOut strings.Builder
|
||||
var stdErr strings.Builder
|
||||
|
||||
err := plugin.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
downloadDir := DownloadPath(conf, plugin, version)
|
||||
installDir := InstallPath(conf, plugin, version)
|
||||
|
||||
env := map[string]string{
|
||||
"ASDF_INSTALL_TYPE": versionType,
|
||||
"ASDF_INSTALL_VERSION": version,
|
||||
"ASDF_INSTALL_PATH": installDir,
|
||||
"ASDF_DOWNLOAD_PATH": downloadDir,
|
||||
"ASDF_CONCURRENCY": "1",
|
||||
}
|
||||
|
||||
err = os.MkdirAll(downloadDir, 0o777)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create download dir: %w", err)
|
||||
}
|
||||
|
||||
err = plugin.RunCallback("download", []string{}, env, &stdOut, &stdErr)
|
||||
if _, ok := err.(plugins.NoCallbackError); err != nil && !ok {
|
||||
return fmt.Errorf("failed to run download callback: %w", err)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(installDir, 0o777)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create install dir: %w", err)
|
||||
}
|
||||
|
||||
err = plugin.RunCallback("install", []string{}, env, &stdOut, &stdErr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run install callback: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallPath returns the path to a tool installation
|
||||
func InstallPath(conf config.Config, plugin plugins.Plugin, version string) string {
|
||||
return filepath.Join(pluginInstallPath(conf, plugin), version)
|
||||
}
|
||||
|
||||
// DownloadPath returns the download path for a particular plugin and version
|
||||
func DownloadPath(conf config.Config, plugin plugins.Plugin, version string) string {
|
||||
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, version)
|
||||
}
|
||||
|
||||
func pluginInstallPath(conf config.Config, plugin plugins.Plugin) string {
|
||||
return filepath.Join(conf.DataDir, dataDirInstalls, plugin.Name)
|
||||
}
|
@ -11,9 +11,9 @@ import (
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/hook"
|
||||
"asdf/internal/installs"
|
||||
"asdf/internal/plugins"
|
||||
"asdf/internal/toolversions"
|
||||
"asdf/internal/versions"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@ -56,7 +56,7 @@ func GenerateAll(conf config.Config, stdOut io.Writer, stdErr io.Writer) error {
|
||||
// GenerateForPluginVersions generates all shims for all installed versions of
|
||||
// a tool.
|
||||
func GenerateForPluginVersions(conf config.Config, plugin plugins.Plugin, stdOut io.Writer, stdErr io.Writer) error {
|
||||
installedVersions, err := versions.Installed(conf, plugin)
|
||||
installedVersions, err := installs.Installed(conf, plugin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -135,7 +135,7 @@ func ToolExecutables(conf config.Config, plugin plugins.Plugin, version string)
|
||||
return executables, err
|
||||
}
|
||||
|
||||
installPath := versions.InstallPath(conf, plugin, version)
|
||||
installPath := installs.InstallPath(conf, plugin, version)
|
||||
paths := dirsToPaths(dirs, installPath)
|
||||
|
||||
for _, path := range paths {
|
||||
|
@ -9,8 +9,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/installtest"
|
||||
"asdf/internal/plugins"
|
||||
"asdf/internal/versions"
|
||||
"asdf/repotest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -266,7 +266,6 @@ func installPlugin(t *testing.T, conf config.Config, fixture, pluginName string)
|
||||
|
||||
func installVersion(t *testing.T, conf config.Config, plugin plugins.Plugin, version string) {
|
||||
t.Helper()
|
||||
stdout, stderr := buildOutputs()
|
||||
err := versions.InstallOneVersion(conf, plugin, version, &stdout, &stderr)
|
||||
err := installtest.InstallOneVersion(conf, plugin, "version", version)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
2
internal/shims/testdata/asdfrc
vendored
Normal file
2
internal/shims/testdata/asdfrc
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
pre_asdf_reshim_lua = echo pre_reshim $@
|
||||
post_asdf_reshim_lua = echo post_reshim $@
|
@ -6,14 +6,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"asdf/internal/config"
|
||||
"asdf/internal/hook"
|
||||
"asdf/internal/installs"
|
||||
"asdf/internal/plugins"
|
||||
"asdf/internal/resolve"
|
||||
)
|
||||
@ -22,8 +21,6 @@ const (
|
||||
systemVersion = "system"
|
||||
latestVersion = "latest"
|
||||
uninstallableVersionMsg = "uninstallable version: system"
|
||||
dataDirDownloads = "downloads"
|
||||
dataDirInstalls = "installs"
|
||||
latestFilterRegex = "(?i)(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)"
|
||||
noLatestVersionErrMsg = "no latest version found"
|
||||
)
|
||||
@ -49,29 +46,6 @@ func (e NoVersionSetError) Error() string {
|
||||
return "no version set"
|
||||
}
|
||||
|
||||
// Installed returns a slice of all installed versions for a given plugin
|
||||
func Installed(conf config.Config, plugin plugins.Plugin) (versions []string, err error) {
|
||||
installDirectory := pluginInstallPath(conf, plugin)
|
||||
files, err := os.ReadDir(installDirectory)
|
||||
if err != nil {
|
||||
if _, ok := err.(*fs.PathError); ok {
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
return versions, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
versions = append(versions, file.Name())
|
||||
}
|
||||
|
||||
return versions, err
|
||||
}
|
||||
|
||||
// InstallAll installs all specified versions of every tool for the current
|
||||
// directory. Typically this will just be a single version, if not already
|
||||
// installed, but it may be multiple versions if multiple versions for the tool
|
||||
@ -154,11 +128,11 @@ func InstallOneVersion(conf config.Config, plugin plugins.Plugin, version string
|
||||
return UninstallableVersionError{}
|
||||
}
|
||||
|
||||
downloadDir := downloadPath(conf, plugin, version)
|
||||
installDir := InstallPath(conf, plugin, version)
|
||||
downloadDir := installs.DownloadPath(conf, plugin, version)
|
||||
installDir := installs.InstallPath(conf, plugin, version)
|
||||
versionType, version := ParseString(version)
|
||||
|
||||
if IsInstalled(conf, plugin, version) {
|
||||
if installs.IsInstalled(conf, plugin, version) {
|
||||
return fmt.Errorf("version %s of %s is already installed", version, plugin.Name)
|
||||
}
|
||||
|
||||
@ -222,15 +196,6 @@ func asdfConcurrency(conf config.Config) string {
|
||||
return val
|
||||
}
|
||||
|
||||
// IsInstalled checks if a specific version of a tool is installed
|
||||
func IsInstalled(conf config.Config, plugin plugins.Plugin, version string) bool {
|
||||
installDir := InstallPath(conf, plugin, version)
|
||||
|
||||
// Check if version already installed
|
||||
_, err := os.Stat(installDir)
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
|
||||
// Latest invokes the plugin's latest-stable callback if it exists and returns
|
||||
// the version it returns. If the callback is missing it invokes the list-all
|
||||
// callback and returns the last version matching the query, if a query is
|
||||
@ -338,16 +303,3 @@ func ParseString(version string) (string, string) {
|
||||
|
||||
return "version", version
|
||||
}
|
||||
|
||||
func downloadPath(conf config.Config, plugin plugins.Plugin, version string) string {
|
||||
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, version)
|
||||
}
|
||||
|
||||
// InstallPath returns the path to a tool installation
|
||||
func InstallPath(conf config.Config, plugin plugins.Plugin, version string) string {
|
||||
return filepath.Join(pluginInstallPath(conf, plugin), version)
|
||||
}
|
||||
|
||||
func pluginInstallPath(conf config.Config, plugin plugins.Plugin) string {
|
||||
return filepath.Join(conf.DataDir, dataDirInstalls, plugin.Name)
|
||||
}
|
||||
|
@ -16,30 +16,6 @@ import (
|
||||
|
||||
const testPluginName = "lua"
|
||||
|
||||
func TestInstalled(t *testing.T) {
|
||||
conf, plugin := generateConfig(t)
|
||||
//stdout, stderr := buildOutputs()
|
||||
//currentDir := t.TempDir()
|
||||
//secondPlugin := installPlugin(t, conf, "dummy_plugin", "another")
|
||||
//version := "1.0.0"
|
||||
|
||||
t.Run("returns empty slice for newly installed plugin", func(t *testing.T) {
|
||||
installedVersions, err := Installed(conf, plugin)
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, installedVersions)
|
||||
})
|
||||
|
||||
t.Run("returns slice of all installed versions for a tool", func(t *testing.T) {
|
||||
stdout, stderr := buildOutputs()
|
||||
err := InstallOneVersion(conf, plugin, "1.0.0", &stdout, &stderr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
installedVersions, err := Installed(conf, plugin)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, installedVersions, []string{"1.0.0"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestInstallAll(t *testing.T) {
|
||||
t.Run("installs multiple tools when multiple tool versions are specified", func(t *testing.T) {
|
||||
conf, plugin := generateConfig(t)
|
||||
@ -287,20 +263,6 @@ func TestInstallOneVersion(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsInstalled(t *testing.T) {
|
||||
conf, plugin := generateConfig(t)
|
||||
stdout, stderr := buildOutputs()
|
||||
err := InstallOneVersion(conf, plugin, "1.0.0", &stdout, &stderr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
t.Run("returns false when not installed", func(t *testing.T) {
|
||||
assert.False(t, IsInstalled(conf, plugin, "4.0.0"))
|
||||
})
|
||||
t.Run("returns true when installed", func(t *testing.T) {
|
||||
assert.True(t, IsInstalled(conf, plugin, "1.0.0"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestLatest(t *testing.T) {
|
||||
pluginName := "latest_test"
|
||||
conf, _ := generateConfig(t)
|
||||
|
Loading…
Reference in New Issue
Block a user