diff --git a/Makefile b/Makefile index c59e8a8..451331a 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ install: build test: @echo ">> running all unit tests" - @go test $(PKGS) + go test -v $(PKGS) test-integration: @echo ">> running all integration tests" diff --git a/README.md b/README.md index f47ce80..196d1dd 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Commands: init Initialize a new empty jsonnetfile - install [...] + install [...] Install all dependencies or install specific ones update diff --git a/cmd/jb/install.go b/cmd/jb/install.go index db2c42b..78b5d64 100644 --- a/cmd/jb/install.go +++ b/cmd/jb/install.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "io/ioutil" - "net/url" "os" "path/filepath" @@ -28,7 +27,7 @@ import ( "gopkg.in/alecthomas/kingpin.v2" ) -func installCommand(dir, jsonnetHome string, urls ...*url.URL) int { +func installCommand(dir, jsonnetHome string, uris ...string) int { if dir == "" { dir = "." } @@ -45,19 +44,11 @@ func installCommand(dir, jsonnetHome string, urls ...*url.URL) int { return 1 } - if len(urls) > 0 { - for _, url := range urls { - // install package specified in command - // $ jsonnetpkg install ksonnet git@github.com:ksonnet/ksonnet-lib - // $ jsonnetpkg install grafonnet git@github.com:grafana/grafonnet-lib grafonnet - // $ jsonnetpkg install github.com/grafana/grafonnet-lib/grafonnet - // - // github.com/(slug)/(dir) - - urlString := url.String() - newDep := parseDepedency(urlString) + if len(uris) > 0 { + for _, uri := range uris { + newDep := parseDependency(dir, uri) if newDep == nil { - kingpin.Errorf("ignoring unrecognized url: %s", url) + kingpin.Errorf("ignoring unrecognized uri: %s", uri) continue } diff --git a/cmd/jb/install_test.go b/cmd/jb/install_test.go index 9de6b69..ae3a78b 100644 --- a/cmd/jb/install_test.go +++ b/cmd/jb/install_test.go @@ -18,7 +18,6 @@ package main import ( "io/ioutil" - "net/url" "os" "path/filepath" "testing" @@ -30,7 +29,7 @@ import ( func TestInstallCommand(t *testing.T) { testcases := []struct { Name string - URLs []*url.URL + URIs []string ExpectedCode int ExpectedJsonnetFile []byte ExpectedJsonnetLockFile []byte @@ -41,26 +40,28 @@ func TestInstallCommand(t *testing.T) { ExpectedJsonnetFile: []byte(`{"dependencies":null}`), ExpectedJsonnetLockFile: []byte(`{"dependencies":null}`), }, { - Name: "OneURL", - URLs: []*url.URL{ - { - Scheme: "https", - Host: "github.com", - Path: "jsonnet-bundler/jsonnet-bundler@v0.1.0", - }, - }, + Name: "OneURL", + URIs: []string{"github.com/jsonnet-bundler/jsonnet-bundler@v0.1.0"}, ExpectedCode: 0, ExpectedJsonnetFile: []byte(`{"dependencies": [{"name": "jsonnet-bundler", "source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "v0.1.0"}]}`), ExpectedJsonnetLockFile: []byte(`{"dependencies": [{"name": "jsonnet-bundler", "source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "080f157c7fb85ad0281ea78f6c641eaa570a582f"}]}`), + }, { + Name: "Relative", + URIs: []string{"test/jsonnet/foobar"}, + ExpectedCode: 0, + ExpectedJsonnetFile: []byte(`{"dependencies": [{"name": "foobar", "source": {"local": {"directory": "test/jsonnet/foobar"}}, "version": ""}]}`), + ExpectedJsonnetLockFile: []byte(`{"dependencies": [{"name": "foobar", "source": {"local": {"directory": "test/jsonnet/foobar"}}, "version": ""}]}`), }, } for _, tc := range testcases { - t.Run(tc.Name, func(t *testing.T) { + _ = t.Run(tc.Name, func(t *testing.T) { tempDir, err := ioutil.TempDir("", "jb-install") assert.NoError(t, err) + err = os.MkdirAll(filepath.Join(tempDir, "test/jsonnet/foobar"), os.ModePerm) + assert.NoError(t, err) defer os.Remove(tempDir) - defer os.RemoveAll("vendor") // delete test vendor folder + defer os.RemoveAll("vendor") // cloning jsonnet-bundler will create this folder jsonnetFile := filepath.Join(tempDir, jsonnetfile.File) jsonnetLockFile := filepath.Join(tempDir, jsonnetfile.LockFile) @@ -70,7 +71,7 @@ func TestInstallCommand(t *testing.T) { jsonnetFileContent(t, jsonnetFile, []byte(`{}`)) - code = installCommand(tempDir, "vendor", tc.URLs...) + code = installCommand(tempDir, "vendor", tc.URIs...) assert.Equal(t, tc.ExpectedCode, code) jsonnetFileContent(t, jsonnetFile, tc.ExpectedJsonnetFile) @@ -80,6 +81,8 @@ func TestInstallCommand(t *testing.T) { } func jsonnetFileContent(t *testing.T, filename string, content []byte) { + t.Helper() + bytes, err := ioutil.ReadFile(filename) assert.NoError(t, err) if eq := assert.JSONEq(t, string(content), string(bytes)); !eq { diff --git a/cmd/jb/main.go b/cmd/jb/main.go index 4fc0646..221a56e 100644 --- a/cmd/jb/main.go +++ b/cmd/jb/main.go @@ -15,17 +15,13 @@ package main import ( - "context" - "encoding/json" "fmt" - "io/ioutil" - "net/url" "os" "path" "path/filepath" "regexp" + "strings" - "github.com/jsonnet-bundler/jsonnet-bundler/pkg" "github.com/jsonnet-bundler/jsonnet-bundler/spec" "github.com/pkg/errors" "gopkg.in/alecthomas/kingpin.v2" @@ -35,15 +31,9 @@ const ( installActionName = "install" updateActionName = "update" initActionName = "init" - basePath = ".jsonnetpkg" - srcDirName = "src" ) var ( - availableSubcommands = []string{ - initActionName, - installActionName, - } gitSSHRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git") gitSSHWithVersionRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git@(.*)") gitSSHWithPathRegex = regexp.MustCompile("git\\+ssh://git@([^:]+):([^/]+)/([^/]+).git/(.*)") @@ -73,7 +63,7 @@ func Main() int { initCmd := a.Command(initActionName, "Initialize a new empty jsonnetfile") installCmd := a.Command(installActionName, "Install all dependencies or install specific ones") - installCmdURLs := installCmd.Arg("packages", "URLs to package to install").URLList() + installCmdURIs := installCmd.Arg("uris", "URIs to packages to install, URLs or file paths").Strings() updateCmd := a.Command(updateActionName, "Update all dependencies.") @@ -93,7 +83,7 @@ func Main() int { case initCmd.FullCommand(): return initCommand(workdir) case installCmd.FullCommand(): - return installCommand(workdir, cfg.JsonnetHome, *installCmdURLs...) + return installCommand(workdir, cfg.JsonnetHome, *installCmdURIs...) case updateCmd.FullCommand(): return updateCommand(cfg.JsonnetHome) default: @@ -103,20 +93,24 @@ func Main() int { return 0 } -func parseDepedency(urlString string) *spec.Dependency { - if spec := parseGitSSHDependency(urlString); spec != nil { - return spec +func parseDependency(dir, uri string) *spec.Dependency { + if d := parseGitSSHDependency(uri); d != nil { + return d } - if spec := parseGithubDependency(urlString); spec != nil { - return spec + if d := parseGithubDependency(uri); d != nil { + return d + } + + if d := parseLocalDependency(dir, uri); d != nil { + return d } return nil } -func parseGitSSHDependency(urlString string) *spec.Dependency { - if !gitSSHRegex.MatchString(urlString) { +func parseGitSSHDependency(p string) *spec.Dependency { + if !gitSSHRegex.MatchString(p) { return nil } @@ -126,27 +120,27 @@ func parseGitSSHDependency(urlString string) *spec.Dependency { repo := "" version := "master" - if gitSSHWithPathAndVersionRegex.MatchString(urlString) { - matches := gitSSHWithPathAndVersionRegex.FindStringSubmatch(urlString) + if gitSSHWithPathAndVersionRegex.MatchString(p) { + matches := gitSSHWithPathAndVersionRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] subdir = matches[4] version = matches[5] - } else if gitSSHWithPathRegex.MatchString(urlString) { - matches := gitSSHWithPathRegex.FindStringSubmatch(urlString) + } else if gitSSHWithPathRegex.MatchString(p) { + matches := gitSSHWithPathRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] subdir = matches[4] - } else if gitSSHWithVersionRegex.MatchString(urlString) { - matches := gitSSHWithVersionRegex.FindStringSubmatch(urlString) + } else if gitSSHWithVersionRegex.MatchString(p) { + matches := gitSSHWithVersionRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] version = matches[4] } else { - matches := gitSSHRegex.FindStringSubmatch(urlString) + matches := gitSSHRegex.FindStringSubmatch(p) host = matches[1] org = matches[2] repo = matches[3] @@ -164,8 +158,8 @@ func parseGitSSHDependency(urlString string) *spec.Dependency { } } -func parseGithubDependency(urlString string) *spec.Dependency { - if !githubSlugRegex.MatchString(urlString) { +func parseGithubDependency(p string) *spec.Dependency { + if !githubSlugRegex.MatchString(p) { return nil } @@ -175,30 +169,30 @@ func parseGithubDependency(urlString string) *spec.Dependency { subdir := "" version := "master" - if githubSlugWithPathRegex.MatchString(urlString) { - if githubSlugWithPathAndVersionRegex.MatchString(urlString) { - matches := githubSlugWithPathAndVersionRegex.FindStringSubmatch(urlString) + if githubSlugWithPathRegex.MatchString(p) { + if githubSlugWithPathAndVersionRegex.MatchString(p) { + matches := githubSlugWithPathAndVersionRegex.FindStringSubmatch(p) user = matches[1] repo = matches[2] subdir = matches[3] version = matches[4] name = path.Base(subdir) } else { - matches := githubSlugWithPathRegex.FindStringSubmatch(urlString) + matches := githubSlugWithPathRegex.FindStringSubmatch(p) user = matches[1] repo = matches[2] subdir = matches[3] name = path.Base(subdir) } } else { - if githubSlugWithVersionRegex.MatchString(urlString) { - matches := githubSlugWithVersionRegex.FindStringSubmatch(urlString) + if githubSlugWithVersionRegex.MatchString(p) { + matches := githubSlugWithVersionRegex.FindStringSubmatch(p) user = matches[1] repo = matches[2] name = repo version = matches[3] } else { - matches := githubSlugRegex.FindStringSubmatch(urlString) + matches := githubSlugRegex.FindStringSubmatch(p) user = matches[1] repo = matches[2] name = repo @@ -217,41 +211,36 @@ func parseGithubDependency(urlString string) *spec.Dependency { } } -func updateCommand(jsonnetHome string, urls ...*url.URL) int { - jsonnetfile := pkg.JsonnetFile - - m, err := pkg.LoadJsonnetfile(jsonnetfile) - if err != nil { - kingpin.Fatalf("failed to load jsonnetfile: %v", err) - return 1 +func parseLocalDependency(dir, p string) *spec.Dependency { + if p == "" { + return nil + } + if strings.HasPrefix(p, "github.com") { + return nil + } + if strings.HasPrefix(p, "git+ssh") { + return nil } - err = os.MkdirAll(jsonnetHome, os.ModePerm) + clean := filepath.Clean(p) + abs := filepath.Join(dir, clean) + + info, err := os.Stat(abs) if err != nil { - kingpin.Fatalf("failed to create jsonnet home path: %v", err) - return 3 + return nil } - // When updating, the lockfile is explicitly ignored. - isLock := false - lock, err := pkg.Install(context.TODO(), isLock, jsonnetfile, m, jsonnetHome) - if err != nil { - kingpin.Fatalf("failed to install: %v", err) - return 3 + if !info.IsDir() { + return nil } - b, err := json.MarshalIndent(lock, "", " ") - if err != nil { - kingpin.Fatalf("failed to encode jsonnet file: %v", err) - return 3 + return &spec.Dependency{ + Name: info.Name(), + Source: spec.Source{ + LocalSource: &spec.LocalSource{ + Directory: clean, + }, + }, + Version: "", } - b = append(b, []byte("\n")...) - - err = ioutil.WriteFile(pkg.JsonnetLockFile, b, 0644) - if err != nil { - kingpin.Fatalf("failed to write lock file: %v", err) - return 3 - } - - return 0 } diff --git a/cmd/jb/main_test.go b/cmd/jb/main_test.go new file mode 100644 index 0000000..3a4007e --- /dev/null +++ b/cmd/jb/main_test.go @@ -0,0 +1,101 @@ +// 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. + +package main + +import ( + "os" + "testing" + + "github.com/jsonnet-bundler/jsonnet-bundler/spec" + "github.com/stretchr/testify/assert" +) + +func TestParseDependency(t *testing.T) { + const testFolder = "test/jsonnet/foobar" + err := os.MkdirAll(testFolder, os.ModePerm) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll("test") + + tests := []struct { + name string + path string + want *spec.Dependency + }{ + { + name: "Empty", + path: "", + want: nil, + }, + { + name: "Invalid", + path: "github.com/foo", + want: nil, + }, + { + name: "GitHub", + path: "github.com/jsonnet-bundler/jsonnet-bundler", + want: &spec.Dependency{ + Name: "jsonnet-bundler", + Source: spec.Source{ + GitSource: &spec.GitSource{ + Remote: "https://github.com/jsonnet-bundler/jsonnet-bundler", + Subdir: "", + }, + }, + Version: "master", + }, + }, + { + name: "SSH", + path: "git+ssh://git@github.com:jsonnet-bundler/jsonnet-bundler.git", + want: &spec.Dependency{ + Name: "jsonnet-bundler", + Source: spec.Source{ + GitSource: &spec.GitSource{ + Remote: "git@github.com:jsonnet-bundler/jsonnet-bundler", + Subdir: "", + }, + }, + Version: "master", + }, + }, + { + name: "local", + path: testFolder, + want: &spec.Dependency{ + Name: "foobar", + Source: spec.Source{ + LocalSource: &spec.LocalSource{ + Directory: "test/jsonnet/foobar", + }, + }, + Version: "", + }, + }, + } + for _, tt := range tests { + _ = t.Run(tt.name, func(t *testing.T) { + dependency := parseDependency("", tt.path) + + if tt.path == "" { + assert.Nil(t, dependency) + } else { + assert.Equal(t, tt.want, dependency) + } + }) + } +} diff --git a/cmd/jb/update.go b/cmd/jb/update.go new file mode 100644 index 0000000..9496d31 --- /dev/null +++ b/cmd/jb/update.go @@ -0,0 +1,64 @@ +// 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. + +package main + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/url" + "os" + + "github.com/jsonnet-bundler/jsonnet-bundler/pkg" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" + "gopkg.in/alecthomas/kingpin.v2" +) + +func updateCommand(jsonnetHome string, urls ...*url.URL) int { + m, err := pkg.LoadJsonnetfile(jsonnetfile.File) + if err != nil { + kingpin.Fatalf("failed to load jsonnetfile: %v", err) + return 1 + } + + err = os.MkdirAll(jsonnetHome, os.ModePerm) + if err != nil { + kingpin.Fatalf("failed to create jsonnet home path: %v", err) + return 3 + } + + // When updating, the lockfile is explicitly ignored. + isLock := false + lock, err := pkg.Install(context.TODO(), isLock, jsonnetfile.File, m, jsonnetHome) + if err != nil { + kingpin.Fatalf("failed to install: %v", err) + return 3 + } + + b, err := json.MarshalIndent(lock, "", " ") + if err != nil { + kingpin.Fatalf("failed to encode jsonnet file: %v", err) + return 3 + } + b = append(b, []byte("\n")...) + + err = ioutil.WriteFile(jsonnetfile.LockFile, b, 0644) + if err != nil { + kingpin.Fatalf("failed to write lock file: %v", err) + return 3 + } + + return 0 +} diff --git a/pkg/git.go b/pkg/git.go index d2cd6f3..8af4a00 100644 --- a/pkg/git.go +++ b/pkg/git.go @@ -17,12 +17,16 @@ package pkg import ( "bytes" "context" + "fmt" + "io/ioutil" "os" "os/exec" "path" + "path/filepath" "strings" "github.com/jsonnet-bundler/jsonnet-bundler/spec" + "github.com/pkg/errors" ) type GitPackage struct { @@ -35,8 +39,16 @@ func NewGitPackage(source *spec.GitSource) Interface { } } -func (p *GitPackage) Install(ctx context.Context, dir, version string) (lockVersion string, err error) { - cmd := exec.CommandContext(ctx, "git", "clone", p.Source.Remote, dir) +func (p *GitPackage) Install(ctx context.Context, name, dir, version string) (string, error) { + destPath := path.Join(dir, name) + + tmpDir, err := ioutil.TempDir(filepath.Join(dir, ".tmp"), fmt.Sprintf("jsonnetpkg-%s-%s", name, version)) + if err != nil { + return "", errors.Wrap(err, "failed to create tmp dir") + } + defer os.RemoveAll(tmpDir) + + cmd := exec.CommandContext(ctx, "git", "clone", p.Source.Remote, tmpDir) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -49,7 +61,7 @@ func (p *GitPackage) Install(ctx context.Context, dir, version string) (lockVers cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - cmd.Dir = dir + cmd.Dir = tmpDir err = cmd.Run() if err != nil { return "", err @@ -58,7 +70,7 @@ func (p *GitPackage) Install(ctx context.Context, dir, version string) (lockVers b := bytes.NewBuffer(nil) cmd = exec.CommandContext(ctx, "git", "rev-parse", "HEAD") cmd.Stdout = b - cmd.Dir = dir + cmd.Dir = tmpDir err = cmd.Run() if err != nil { return "", err @@ -66,10 +78,25 @@ func (p *GitPackage) Install(ctx context.Context, dir, version string) (lockVers commitHash := strings.TrimSpace(b.String()) - err = os.RemoveAll(path.Join(dir, ".git")) + err = os.RemoveAll(path.Join(tmpDir, ".git")) if err != nil { return "", err } + err = os.MkdirAll(path.Dir(destPath), os.ModePerm) + if err != nil { + return "", errors.Wrap(err, "failed to create parent path") + } + + err = os.RemoveAll(destPath) + if err != nil { + return "", errors.Wrap(err, "failed to clean previous destination path") + } + + err = os.Rename(path.Join(tmpDir, p.Source.Subdir), destPath) + if err != nil { + return "", errors.Wrap(err, "failed to move package") + } + return commitHash, nil } diff --git a/pkg/interface.go b/pkg/interface.go index 79384af..a93911c 100644 --- a/pkg/interface.go +++ b/pkg/interface.go @@ -19,5 +19,5 @@ import ( ) type Interface interface { - Install(ctx context.Context, dir, version string) (lockVersion string, err error) + Install(ctx context.Context, name, dir, version string) (lockVersion string, err error) } diff --git a/pkg/local.go b/pkg/local.go new file mode 100644 index 0000000..6406012 --- /dev/null +++ b/pkg/local.go @@ -0,0 +1,56 @@ +// 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. + +package pkg + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "github.com/jsonnet-bundler/jsonnet-bundler/spec" + "github.com/pkg/errors" +) + +type LocalPackage struct { + Source *spec.LocalSource +} + +func NewLocalPackage(source *spec.LocalSource) Interface { + return &LocalPackage{ + Source: source, + } +} + +func (p *LocalPackage) Install(ctx context.Context, name, dir, version string) (lockVersion string, err error) { + wd, err := os.Getwd() + if err != nil { + return "", fmt.Errorf("failed to get current working directory: %v", err) + } + + destPath := filepath.Join(dir, name) + + err = os.RemoveAll(destPath) + if err != nil { + return "", errors.Wrap(err, "failed to clean previous destination path") + } + + err = os.Symlink(filepath.Join(wd, p.Source.Directory), filepath.Join(wd, destPath)) + if err != nil { + return "", fmt.Errorf("failed to create symlink for local dependency: %v", err) + } + + return "", nil +} diff --git a/pkg/packages.go b/pkg/packages.go index a847298..a5b1494 100644 --- a/pkg/packages.go +++ b/pkg/packages.go @@ -18,19 +18,17 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "os" "path" "path/filepath" "github.com/fatih/color" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" "github.com/jsonnet-bundler/jsonnet-bundler/spec" "github.com/pkg/errors" ) var ( - JsonnetFile = "jsonnetfile.json" - JsonnetLockFile = "jsonnetfile.lock.json" VersionMismatch = errors.New("multiple colliding versions specified") ) @@ -43,20 +41,16 @@ func Install(ctx context.Context, isLock bool, dependencySourceIdentifier string if err != nil { return nil, errors.Wrap(err, "failed to create general tmp dir") } - tmpDir, err := ioutil.TempDir(tmp, fmt.Sprintf("jsonnetpkg-%s-%s", dep.Name, dep.Version)) - if err != nil { - return nil, errors.Wrap(err, "failed to create tmp dir") - } - defer os.RemoveAll(tmpDir) - subdir := "" var p Interface if dep.Source.GitSource != nil { p = NewGitPackage(dep.Source.GitSource) - subdir = dep.Source.GitSource.Subdir + } + if dep.Source.LocalSource != nil { + p = NewLocalPackage(dep.Source.LocalSource) } - lockVersion, err := p.Install(ctx, tmpDir, dep.Version) + lockVersion, err := p.Install(ctx, dep.Name, dir, dep.Version) if err != nil { return nil, errors.Wrap(err, "failed to install package") } @@ -65,20 +59,6 @@ func Install(ctx context.Context, isLock bool, dependencySourceIdentifier string destPath := path.Join(dir, dep.Name) - err = os.MkdirAll(path.Dir(destPath), os.ModePerm) - if err != nil { - return nil, errors.Wrap(err, "failed to create parent path") - } - - err = os.RemoveAll(destPath) - if err != nil { - return nil, errors.Wrap(err, "failed to clean previous destination path") - } - err = os.Rename(path.Join(tmpDir, subdir), destPath) - if err != nil { - return nil, errors.Wrap(err, "failed to move package") - } - lockfile.Dependencies, err = insertDependency(lockfile.Dependencies, spec.Dependency{ Name: dep.Name, Source: dep.Source, @@ -101,7 +81,7 @@ func Install(ctx context.Context, isLock bool, dependencySourceIdentifier string return nil, err } depsDeps, err := LoadJsonnetfile(filepath) - // It is ok for depedencies not to have a JsonnetFile, it just means + // It is ok for dependencies not to have a JsonnetFile, it just means // they do not have transitive dependencies of their own. if err != nil && !os.IsNotExist(err) { return nil, err @@ -161,18 +141,18 @@ func FileExists(path string) (bool, error) { } func ChooseJsonnetFile(dir string) (string, bool, error) { - lockfile := path.Join(dir, JsonnetLockFile) - jsonnetfile := path.Join(dir, JsonnetFile) - filename := lockfile + lockfilePath := path.Join(dir, jsonnetfile.LockFile) + jsonnetfilePath := path.Join(dir, jsonnetfile.File) + filename := lockfilePath isLock := true - lockExists, err := FileExists(filepath.Join(dir, JsonnetLockFile)) + lockExists, err := FileExists(filepath.Join(dir, jsonnetfile.LockFile)) if err != nil { return "", false, err } if !lockExists { - filename = jsonnetfile + filename = jsonnetfilePath isLock = false } diff --git a/pkg/packages_test.go b/pkg/packages_test.go index 729ab73..3316c02 100644 --- a/pkg/packages_test.go +++ b/pkg/packages_test.go @@ -20,6 +20,7 @@ import ( "path/filepath" "testing" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" "github.com/jsonnet-bundler/jsonnet-bundler/spec" "github.com/stretchr/testify/assert" ) @@ -110,7 +111,7 @@ func TestLoadJsonnetfile(t *testing.T) { assert.Nil(t, err) }() - tempFile := filepath.Join(tempDir, JsonnetFile) + tempFile := filepath.Join(tempDir, jsonnetfile.File) err = ioutil.WriteFile(tempFile, []byte(`{}`), os.ModePerm) assert.Nil(t, err) @@ -128,7 +129,7 @@ func TestLoadJsonnetfile(t *testing.T) { assert.Nil(t, err) }() - tempFile := filepath.Join(tempDir, JsonnetFile) + tempFile := filepath.Join(tempDir, jsonnetfile.File) err = ioutil.WriteFile(tempFile, []byte(jsonnetfileContent), os.ModePerm) assert.Nil(t, err) diff --git a/spec/spec.go b/spec/spec.go index 5f10ea8..0eafee9 100644 --- a/spec/spec.go +++ b/spec/spec.go @@ -18,8 +18,16 @@ type JsonnetFile struct { Dependencies []Dependency `json:"dependencies"` } +type Dependency struct { + Name string `json:"name"` + Source Source `json:"source"` + Version string `json:"version"` + DepSource string `json:"-"` +} + type Source struct { - GitSource *GitSource `json:"git"` + GitSource *GitSource `json:"git,omitempty"` + LocalSource *LocalSource `json:"local,omitempty"` } type GitSource struct { @@ -27,9 +35,6 @@ type GitSource struct { Subdir string `json:"subdir"` } -type Dependency struct { - Name string `json:"name"` - Source Source `json:"source"` - Version string `json:"version"` - DepSource string `json:"-"` +type LocalSource struct { + Directory string `json:"directory"` }