Skip to content

Commit

Permalink
feat: add the --all flag to the install command (#216)
Browse files Browse the repository at this point in the history
* feat: Add the `--all` flag to the `install` command

* update docs
  • Loading branch information
Chance-fyi authored Apr 22, 2024
1 parent d19e12b commit 8ca4448
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 17 deletions.
168 changes: 163 additions & 5 deletions cmd/commands/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,36 @@
package commands

import (
"strings"

"errors"
"fmt"
"github.com/pterm/pterm"
"github.com/urfave/cli/v2"
"github.com/version-fox/vfox/internal"
"github.com/version-fox/vfox/internal/toolset"
"os"
"strings"
)

var Install = &cli.Command{
Name: "install",
Aliases: []string{"i"},
Usage: "Install a version of the target SDK",
Name: "install",
Aliases: []string{"i"},
Usage: "Install a version of the target SDK",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "all",
Aliases: []string{"a"},
Usage: "Install all SDK versions recorded in .tool-versions",
},
},
Action: installCmd,
Category: CategorySDK,
}

func installCmd(ctx *cli.Context) error {
if ctx.Bool("all") {
return installAll()
}

sdkArg := ctx.Args().First()
if sdkArg == "" {
return cli.Exit("sdk name is required", 1)
Expand Down Expand Up @@ -59,3 +74,146 @@ func installCmd(ctx *cli.Context) error {
return source.Install(version)
}
}

func installAll() error {
manager := internal.NewSdkManager()
defer manager.Close()

plugins, sdks, err := notInstalled(manager)
if err != nil {
return err
}
if len(plugins) == 0 && len(sdks) == 0 {
fmt.Println("All plugins and SDKs are already installed")
return nil
}

fmt.Println("Install the following plugins and SDKs:")
printPlugin(plugins, nil)
printSdk(sdks, nil)
if result, _ := pterm.DefaultInteractiveConfirm.
WithDefaultValue(true).
Show("Do you want to install these plugins and SDKs?"); !result {
return nil
}

var (
count = len(plugins) + len(sdks)
index = 0
errorStr string
stdout = os.Stdout
stderr = os.Stderr
pluginsResult = make(map[string]bool)
sdksResult = make(map[string]bool)
)
os.Stdout = nil
os.Stderr = nil
pterm.SetDefaultOutput(os.Stdout)

spinnerInfo, _ := pterm.DefaultSpinner.
WithSequence([]string{"⣾ ", "⣽ ", "⣻ ", "⢿ ", "⡿ ", "⣟ ", "⣯ ", "⣷ "}...).
WithText("Installing...").
WithWriter(stdout).
Start()
for _, plugin := range plugins {
index++
spinnerInfo.UpdateText(fmt.Sprintf("[%v/%v] %s: %s installing...\033[K", index, count, "Plugin", plugin))
pluginsResult[plugin] = false
if err := manager.Add(plugin, "", ""); err != nil {
if errors.Is(err, internal.ManifestNotFound) {
errorStr = fmt.Sprintf("%s\n[%s] not found in remote registry, please check the name", errorStr, plugin)
} else {
errorStr = fmt.Sprintf("%s\n%s", errorStr, err)
}
continue
}
pluginsResult[plugin] = true
}
for sdk, version := range sdks {
index++
spinnerInfo.UpdateText(fmt.Sprintf("[%v/%v] %s: %s@%s installing...\033[K", index, count, "SDK", sdk, version))
sdkVersion := fmt.Sprintf("%s@%s", sdk, version)
sdksResult[sdkVersion] = false
lookupSdk, err := manager.LookupSdk(sdk)
if err != nil {
errorStr = fmt.Sprintf("%s\n%s", errorStr, err)
continue
}
err = lookupSdk.Install(internal.Version(version))
if err != nil {
errorStr = fmt.Sprintf("%s\n%s", errorStr, err)
continue
}
sdksResult[sdkVersion] = true
}
spinnerInfo.UpdateText(fmt.Sprintf("[%v/%v] Installation completed.\033[K", count, count))
_ = spinnerInfo.Stop()
os.Stdout = stdout
os.Stderr = stderr
pterm.SetDefaultOutput(os.Stdout)

fmt.Printf("%s indicates successful installation, while %s indicates installation failure.\n", pterm.Green("Green"), pterm.Red("red"))
printPlugin(plugins, pluginsResult)
printSdk(sdks, sdksResult)

if len(errorStr) > 0 {
fmt.Println(errorStr)
}
return nil
}

func notInstalled(manager *internal.Manager) (plugins []string, sdks map[string]string, err error) {
tvs, err := toolset.NewMultiToolVersions([]string{
manager.PathMeta.WorkingDirectory,
manager.PathMeta.CurTmpPath,
manager.PathMeta.HomePath,
})
if err != nil {
return
}
sdks = tvs.FilterTools(func(name, version string) bool {
lookupSdk, err := manager.LookupSdk(name)
if err != nil {
plugins = append(plugins, name)
return true
}
if !lookupSdk.CheckExists(internal.Version(version)) {
return true
}
return false
})
return
}

func printPlugin(plugins []string, result map[string]bool) {
if len(plugins) > 0 {
fmt.Println("Plugin:")
for _, plugin := range plugins {
if result != nil {
if result[plugin] {
plugin = pterm.Green(plugin)
} else {
plugin = pterm.Red(plugin)
}
}

fmt.Printf(" %s\n", plugin)
}
}
}

func printSdk(sdks map[string]string, result map[string]bool) {
fmt.Println("SDK:")
for sdk, version := range sdks {
sdkVersion := fmt.Sprintf("%s@%s", sdk, version)
if result != nil {
if result[sdkVersion] {
sdkVersion = pterm.Green(sdkVersion)
} else {
sdkVersion = pterm.Red(sdkVersion)
}
}

fmt.Printf(" %s\n", sdkVersion)
}
}
4 changes: 4 additions & 0 deletions docs/usage/core-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ vfox i <sdk-name>@<version>

`version`: The version to install

**Options**

- `-a, --all`: Install all SDK versions recorded in .tool-versions

::: tip
`search` command will retrieve the plugin from the remote repository and add it locally if it is not installed locally.
:::
Expand Down
6 changes: 5 additions & 1 deletion docs/zh-hans/usage/core-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ vfox i <sdk-name>@<version>

`version`: 需要安装的版本号

**选项**

- `-a, --all`: 安装 .tool-versions 中记录的所有 SDK 版本

::: tip 自动安装
如果本地没有安装 SDK,`install`命令会从远端仓库检索插件并安装到本地。
:::
Expand Down Expand Up @@ -120,7 +124,7 @@ vfox c
vfox cd [options] [<sdk-name>]
```

`sdk-name`: SDK 名称, 不传默认为 `VFOX_HOME`.
`sdk-name`: SDK 名称, 不传默认为 `VFOX_HOME`

**选项**

Expand Down
8 changes: 4 additions & 4 deletions internal/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const (
)

var (
manifestNotFound = errors.New("manifest not found")
ManifestNotFound = errors.New("manifest not found")
)

type NotFoundError struct {
Expand Down Expand Up @@ -131,7 +131,7 @@ func (m *Manager) LookupSdkWithInstall(name string) (*Sdk, error) {
Show(); result {

manifest, err := m.fetchPluginManifest(m.GetRegistryAddress(name + ".json"))
if errors.Is(err, manifestNotFound) {
if errors.Is(err, ManifestNotFound) {
return nil, fmt.Errorf("[%s] not found in remote registry, please check the name", pterm.LightRed(name))
}

Expand Down Expand Up @@ -236,7 +236,7 @@ func (m *Manager) Update(pluginName string) error {
logger.Debugf("Fetching plugin %s from %s...\n", pluginName, address)
registryManifest, err := m.fetchPluginManifest(address)
if err != nil {
if errors.Is(err, manifestNotFound) {
if errors.Is(err, ManifestNotFound) {
if sdk.Plugin.ManifestUrl != "" {
logger.Debugf("Fetching plugin %s from %s...\n", pluginName, sdk.Plugin.ManifestUrl)
du, err := m.fetchPluginManifest(sdk.Plugin.ManifestUrl)
Expand Down Expand Up @@ -324,7 +324,7 @@ func (m *Manager) fetchPluginManifest(url string) (*RegistryPluginManifest, erro
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
return nil, manifestNotFound
return nil, ManifestNotFound
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("fetch manifest error, status code: %d", resp.StatusCode)
Expand Down
14 changes: 7 additions & 7 deletions internal/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type Sdk struct {

func (b *Sdk) Install(version Version) error {
label := b.label(version)
if b.checkExists(version) {
if b.CheckExists(version) {
return fmt.Errorf("%s is already installed", label)
}
installInfo, err := b.Plugin.PreInstall(version)
Expand All @@ -65,7 +65,7 @@ func (b *Sdk) Install(version Version) error {
// A second check is required because the plug-in may change the version number,
// for example, latest is resolved to a specific version number.
label = b.label(mainSdk.Version)
if b.checkExists(mainSdk.Version) {
if b.CheckExists(mainSdk.Version) {
return fmt.Errorf("%s is already installed", label)
}
success := false
Expand Down Expand Up @@ -194,7 +194,7 @@ func (b *Sdk) preInstallSdk(info *Info, sdkDestPath string) (string, error) {

func (b *Sdk) Uninstall(version Version) error {
label := b.label(version)
if !b.checkExists(version) {
if !b.CheckExists(version) {
return fmt.Errorf("%s is not installed", pterm.Red(label))
}
if b.Current() == version {
Expand All @@ -215,7 +215,7 @@ func (b *Sdk) Available(args []string) ([]*Package, error) {

func (b *Sdk) EnvKeys(version Version) (*env.Envs, error) {
label := b.label(version)
if !b.checkExists(version) {
if !b.CheckExists(version) {
return nil, fmt.Errorf("%s is not installed", label)
}
sdkPackage, err := b.GetLocalSdkPackage(version)
Expand Down Expand Up @@ -266,7 +266,7 @@ func (b *Sdk) Use(version Version, scope UseScope) error {
}

label := b.label(version)
if !b.checkExists(version) {
if !b.CheckExists(version) {
return fmt.Errorf("%s is not installed", label)
}

Expand Down Expand Up @@ -411,7 +411,7 @@ func (b *Sdk) Current() Version {
return ""
}
current := toolVersion.FilterTools(func(name, version string) bool {
return name == b.Plugin.SdkName && b.checkExists(Version(version))
return name == b.Plugin.SdkName && b.CheckExists(Version(version))
})
if len(current) == 0 {
return ""
Expand Down Expand Up @@ -524,7 +524,7 @@ func (b *Sdk) GetLocalSdkPackage(version Version) (*Package, error) {
}, nil
}

func (b *Sdk) checkExists(version Version) bool {
func (b *Sdk) CheckExists(version Version) bool {
return util.FileExists(b.VersionPath(version))
}

Expand Down

0 comments on commit 8ca4448

Please sign in to comment.