From eeea4677d2a4eeed5aee66263026186fc2de7c88 Mon Sep 17 00:00:00 2001 From: sh0rez Date: Tue, 17 Mar 2020 17:40:33 +0100 Subject: [PATCH 1/3] feat: update single dependencies The `update` command now takes dependency URI's like the `install` command. In contrast to `install`, `update` always pulls the latest version. --- cmd/jb/main.go | 7 ++++--- cmd/jb/update.go | 35 +++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/cmd/jb/main.go b/cmd/jb/main.go index df40a45..9fc82a4 100644 --- a/cmd/jb/main.go +++ b/cmd/jb/main.go @@ -52,10 +52,11 @@ func Main() int { initCmd := a.Command(initActionName, "Initialize a new empty jsonnetfile") - installCmd := a.Command(installActionName, "Install all dependencies or install specific ones") + installCmd := a.Command(installActionName, "Install new dependencies. Existing ones are silently skipped") installCmdURIs := installCmd.Arg("uris", "URIs to packages to install, URLs or file paths").Strings() - updateCmd := a.Command(updateActionName, "Update all dependencies.") + updateCmd := a.Command(updateActionName, "Update all or specific dependencies.") + updateCmdURIs := updateCmd.Arg("uris", "URIs to packages to update, URLs or file paths").Strings() rewriteCmd := a.Command(rewriteActionName, "Automatically rewrite legacy imports to absolute ones") @@ -79,7 +80,7 @@ func Main() int { case installCmd.FullCommand(): return installCommand(workdir, cfg.JsonnetHome, *installCmdURIs) case updateCmd.FullCommand(): - return updateCommand(workdir, cfg.JsonnetHome) + return updateCommand(workdir, cfg.JsonnetHome, *updateCmdURIs) case rewriteCmd.FullCommand(): return rewriteCommand(workdir, cfg.JsonnetHome) default: diff --git a/cmd/jb/update.go b/cmd/jb/update.go index f339782..f68bd89 100644 --- a/cmd/jb/update.go +++ b/cmd/jb/update.go @@ -15,7 +15,6 @@ package main import ( - "net/url" "os" "path/filepath" @@ -27,28 +26,44 @@ import ( "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) -func updateCommand(dir, jsonnetHome string, urls ...*url.URL) int { +func updateCommand(dir, jsonnetHome string, uris []string) int { if dir == "" { dir = "." } + // load jsonnetfiles jsonnetFile, err := jsonnetfile.Load(filepath.Join(dir, jsonnetfile.File)) kingpin.FatalIfError(err, "failed to load jsonnetfile") + lockFile, err := jsonnetfile.Load(filepath.Join(dir, jsonnetfile.LockFile)) + kingpin.FatalIfError(err, "failed to load lockfile") + kingpin.FatalIfError( os.MkdirAll(filepath.Join(dir, jsonnetHome, ".tmp"), os.ModePerm), "creating vendor folder") - // When updating, locks are ignored. - locks := map[string]deps.Dependency{} - locked, err := pkg.Ensure(jsonnetFile, jsonnetHome, locks) - kingpin.FatalIfError(err, "failed to install packages") + locks := lockFile.Dependencies + + for _, u := range uris { + d := deps.Parse(dir, u) + if d == nil { + kingpin.Fatalf("Unable to parse package URI `%s`", u) + } + + delete(locks, d.Name()) + } + + // no uris: update all + if len(uris) == 0 { + locks = make(map[string]deps.Dependency) + } + + newLocks, err := pkg.Ensure(jsonnetFile, jsonnetHome, locks) + kingpin.FatalIfError(err, "updating") kingpin.FatalIfError( - writeJSONFile(filepath.Join(dir, jsonnetfile.File), jsonnetFile), - "updating jsonnetfile.json") - kingpin.FatalIfError( - writeJSONFile(filepath.Join(dir, jsonnetfile.LockFile), v1.JsonnetFile{Dependencies: locked}), + writeJSONFile(filepath.Join(dir, jsonnetfile.LockFile), v1.JsonnetFile{Dependencies: newLocks}), "updating jsonnetfile.lock.json") + return 0 } From 25fcc6dda06bb6f2b7d5960bdc56378a927b906f Mon Sep 17 00:00:00 2001 From: sh0rez Date: Tue, 17 Mar 2020 17:42:08 +0100 Subject: [PATCH 2/3] doc: update README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3d01f7f..48a4e9b 100644 --- a/README.md +++ b/README.md @@ -101,10 +101,10 @@ Commands: Initialize a new empty jsonnetfile install [...] - Install all dependencies or install specific ones + Install new dependencies. Existing ones are silently skipped - update - Update all dependencies. + update [...] + Update all or specific dependencies. rewrite Automatically rewrite legacy imports to absolute ones From 5e141e10f912e85ca999cec32eabca5abcd591c1 Mon Sep 17 00:00:00 2001 From: sh0rez Date: Mon, 20 Apr 2020 18:24:56 +0200 Subject: [PATCH 3/3] test: update integration --- cmd/jb/install.go | 2 +- cmd/jb/update.go | 2 +- cmd/jb/update_test.go | 130 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 cmd/jb/update_test.go diff --git a/cmd/jb/install.go b/cmd/jb/install.go index 292b92d..c84515a 100644 --- a/cmd/jb/install.go +++ b/cmd/jb/install.go @@ -68,7 +68,7 @@ func installCommand(dir, jsonnetHome string, uris []string) int { } } - locked, err := pkg.Ensure(jsonnetFile, jsonnetHome, lockFile.Dependencies) + locked, err := pkg.Ensure(jsonnetFile, filepath.Join(dir, jsonnetHome), lockFile.Dependencies) kingpin.FatalIfError(err, "failed to install packages") pkg.CleanLegacyName(jsonnetFile.Dependencies) diff --git a/cmd/jb/update.go b/cmd/jb/update.go index f68bd89..e8ff2e7 100644 --- a/cmd/jb/update.go +++ b/cmd/jb/update.go @@ -58,7 +58,7 @@ func updateCommand(dir, jsonnetHome string, uris []string) int { locks = make(map[string]deps.Dependency) } - newLocks, err := pkg.Ensure(jsonnetFile, jsonnetHome, locks) + newLocks, err := pkg.Ensure(jsonnetFile, filepath.Join(dir, jsonnetHome), locks) kingpin.FatalIfError(err, "updating") kingpin.FatalIfError( diff --git a/cmd/jb/update_test.go b/cmd/jb/update_test.go new file mode 100644 index 0000000..3dd5e32 --- /dev/null +++ b/cmd/jb/update_test.go @@ -0,0 +1,130 @@ +// Copyright 2018 jsonnet-bundler authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build integration + +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// RepoState describes a point in time of a repository +type RepoState struct { + File string + Lock string +} + +// FilePath is the path to the jsonnetfile.json +func (rs RepoState) FilePath(dir string) string { + return filepath.Join(dir, jsonnetfile.File) +} + +// LockPath is the path to the jsonnetfile.lock.json +func (rs RepoState) LockPath(dir string) string { + return filepath.Join(dir, jsonnetfile.LockFile) +} + +// Write writes this state to dir +func (rs RepoState) Write(dir string) error { + if err := ioutil.WriteFile(rs.FilePath(dir), []byte(rs.File), 0644); err != nil { + return err + } + if err := ioutil.WriteFile(rs.LockPath(dir), []byte(rs.Lock), 0644); err != nil { + return err + } + if err := os.MkdirAll(filepath.Join(dir, "vendor/"), os.ModePerm); err != nil { + return err + } + return nil +} + +// Assert checks that dir matches this state +func (rs RepoState) Assert(t *testing.T, dir string) { + file, err := ioutil.ReadFile(rs.FilePath(dir)) + require.NoError(t, err) + assert.JSONEq(t, rs.File, string(file)) + + lock, err := ioutil.ReadFile(rs.LockPath(dir)) + require.NoError(t, err) + assert.JSONEq(t, rs.Lock, string(lock)) +} + +// UpdateCase is a testcase for jb update +type UpdateCase struct { + name string + uris []string + before *RepoState + after *RepoState +} + +func (u UpdateCase) Run(t *testing.T) { + dir, err := ioutil.TempDir("", u.name) + require.NoError(t, err) + defer os.RemoveAll(dir) + + if u.before == nil { + initCommand(dir) + } else { + err = u.before.Write(dir) + require.NoError(t, err) + } + + ret := updateCommand(dir, "vendor", u.uris) + assert.Equal(t, ret, 0) + + if u.after != nil { + u.after.Assert(t, dir) + } +} + +func TestUpdate(t *testing.T) { + cases := []UpdateCase{ + { + name: "simple", + uris: []string{}, // no uris + before: &RepoState{ + File: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"master"}],"legacyImports":true}`, + Lock: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"9f40207f668e382b706e1822f2d46ce2cd0a57cc","sum":"qUJDskVRtmkTms2udvFpLi1t5YKVbGmMSyiZnPjXsMo="}],"legacyImports":false}`, + }, + after: &RepoState{ + File: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"master"}],"legacyImports":true}`, + Lock: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"ed7c1aff9e10d3b42fb130446d495f1c769ecd7b","sum":"OraOcUvDIx9Eikaihi8XsRNRsVehO75Ek35im/jYoSA="}],"legacyImports":false}`, + }, + }, + { + name: "single", + uris: []string{"github.com/jsonnet-bundler/frozen-lib"}, + before: &RepoState{ + File: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/grafana/jsonnet-libs","subdir":"ksonnet-util"}},"version":"master"},{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"master"}],"legacyImports":true}`, + Lock: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/grafana/jsonnet-libs","subdir":"ksonnet-util"}},"version":"610b00d219d0a6f3d833dd44e4bb0deda2429da0","sum":"XdIrw3m7I8fJ3CL9eR8LtuYcanf2QK78n4H4OBBOADc="},{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"9f40207f668e382b706e1822f2d46ce2cd0a57cc","sum":"qUJDskVRtmkTms2udvFpLi1t5YKVbGmMSyiZnPjXsMo="}],"legacyImports":false}`, + }, + after: &RepoState{ + File: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/grafana/jsonnet-libs","subdir":"ksonnet-util"}},"version":"master"},{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"master"}],"legacyImports":true}`, + Lock: `{"version":1,"dependencies":[{"source":{"git":{"remote":"https://github.com/grafana/jsonnet-libs","subdir":"ksonnet-util"}},"version":"610b00d219d0a6f3d833dd44e4bb0deda2429da0","sum":"XdIrw3m7I8fJ3CL9eR8LtuYcanf2QK78n4H4OBBOADc="},{"source":{"git":{"remote":"https://github.com/jsonnet-bundler/frozen-lib","subdir":""}},"version":"ed7c1aff9e10d3b42fb130446d495f1c769ecd7b","sum":"OraOcUvDIx9Eikaihi8XsRNRsVehO75Ek35im/jYoSA="}],"legacyImports":false}`, + }, + }, + } + + for _, c := range cases { + t.Run(c.name, c.Run) + } +}