diff --git a/gode/packages.go b/gode/packages.go index 7ae14f1ab2..73bd6bab56 100644 --- a/gode/packages.go +++ b/gode/packages.go @@ -52,22 +52,20 @@ func RemovePackage(name string) error { return nil } -// UpdatePackages updates all packages. -func UpdatePackages() (string, error) { - stdout, stderr, err := execNpm("update") +// OutdatedPackages returns a map of packages and their latest version +func OutdatedPackages(names ...string) (map[string]string, error) { + args := append([]string{"outdated", "--json"}, names...) + stdout, stderr, err := execNpm(args...) if err != nil { - return stdout, errors.New(stderr) + return nil, errors.New(stderr) } - return stdout, nil -} - -// UpdatePackage updates a package. -func UpdatePackage(name string) (string, error) { - stdout, stderr, err := execNpm("update", name) - if err != nil { - return stdout, errors.New(stderr) + var outdated map[string]struct{ Latest string } + json.Unmarshal([]byte(stdout), &outdated) + packages := make(map[string]string, len(outdated)) + for name, versions := range outdated { + packages[name] = versions.Latest } - return stdout, nil + return packages, nil } func npmCmd(args ...string) (*exec.Cmd, error) { diff --git a/gode/packages_test.go b/gode/packages_test.go index 4757a9e1d1..cebb5a55b5 100644 --- a/gode/packages_test.go +++ b/gode/packages_test.go @@ -37,11 +37,14 @@ func TestRemovePackage(t *testing.T) { } } -func TestUpdatePackages(t *testing.T) { +func TestOutdatedPackages(t *testing.T) { setup() - must(InstallPackage("request")) - _, err := UpdatePackages() + must(InstallPackage("heroku-cli-util@1.0.0")) + packages, err := OutdatedPackages("heroku-cli-util") must(err) + if packages["heroku-cli-util"] == "" { + t.Fatal("heroku-cli-util not found") + } } func TestPackagesGithubPackage(t *testing.T) { diff --git a/io.go b/io.go index 587744d58f..d328cf2aed 100644 --- a/io.go +++ b/io.go @@ -213,3 +213,10 @@ func supportsColor() bool { } return os.Getenv("COLOR") != "false" } + +func plural(word string, count int) string { + if count == 1 { + return word + } + return word + "s" +} diff --git a/plugin_cache.go b/plugin_cache.go index 9fc8ac538a..1bae90ee40 100644 --- a/plugin_cache.go +++ b/plugin_cache.go @@ -8,15 +8,6 @@ import ( var pluginCachePath = filepath.Join(AppDir(), "plugin-cache.json") -// UpdatePluginCache updates all the plugins in ~/.heroku/plugin-cache.json -func UpdatePluginCache() { - cache := FetchPluginCache() - for name := range cache { - cache[name] = getPlugin(name, true) - } - savePluginCache(cache) -} - // AddPluginsToCache adds/updates a set of plugins to ~/.heroku/plugin-cache.json func AddPluginsToCache(plugins ...*Plugin) { cache := FetchPluginCache() diff --git a/update.go b/update.go index 075adf80dd..06dba07e0b 100644 --- a/update.go +++ b/update.go @@ -60,7 +60,7 @@ func Update(channel string, t string) { touchAutoupdateFile() updateCLI(channel) updateNode() - updatePlugins(t) + updatePlugins() done <- true }() select { @@ -70,38 +70,34 @@ func Update(channel string, t string) { } } -func updatePlugins(t string) { - updated := false +func updatePlugins() { plugins := PluginNamesNotSymlinked() if len(plugins) == 0 { return } Err("Updating plugins... ") - if t == "foreground" || t == "block" { - b, _ := gode.UpdatePackages() - if len(b) > 0 { - updated = true - } - } else { - for _, name := range plugins { + packages, err := gode.OutdatedPackages(plugins...) + PrintError(err) + if len(packages) > 0 { + for name, version := range packages { lockfile := updateLockPath + "." + name LogIfError(golock.Lock(lockfile)) - b, _ := gode.UpdatePackage(name) + err := gode.InstallPackage(name + "@" + version) + PrintError(err) + AddPluginsToCache(getPlugin(name, true)) LogIfError(golock.Unlock(lockfile)) - if len(b) > 0 { - updated = true - } } - } - Errln("done") - if updated { - Err("rebuilding plugins cache... ") - UpdatePluginCache() - Errln("done") + Errf("done. Updated %d %s.\n", len(packages), plural("package", len(packages))) + } else { + Errln("no plugins to update.") } } func updateCLI(channel string) { + if channel == "?" { + // do not update dev version + return + } manifest, err := getUpdateManifest(channel) if err != nil { Warn("Error updating CLI") @@ -136,9 +132,6 @@ func updateCLI(channel string) { // IsUpdateNeeded checks if an update is available func IsUpdateNeeded(t string) bool { - if Channel == "?" { - return false - } f, err := os.Stat(autoupdateFile) if err != nil { return true