зеркало из https://github.com/golang/dep.git
Merge branch 'master' into add-gps
This commit is contained in:
Коммит
4d5c597e0f
|
@ -0,0 +1,10 @@
|
|||
engines:
|
||||
gofmt:
|
||||
enabled: true
|
||||
govet:
|
||||
enabled: true
|
||||
ratings:
|
||||
paths:
|
||||
- "**.go"
|
||||
exclude_paths:
|
||||
- vendor/
|
12
.travis.yml
12
.travis.yml
|
@ -16,8 +16,13 @@ matrix:
|
|||
install:
|
||||
- echo "This is an override of the default install deps step in travis."
|
||||
before_script:
|
||||
# OSX as of El Capitan sets an exit trap that interacts poorly with our
|
||||
# set -e below. So, unset the trap.
|
||||
# Related: https://superuser.com/questions/1044130/why-am-i-having-how-can-i-fix-this-error-shell-session-update-command-not-f
|
||||
- if [[ "$(go env GOHOSTOS)" == "darwin" ]]; then trap EXIT; fi
|
||||
- PKGS=$(go list ./... | grep -v /vendor/)
|
||||
- go get -v honnef.co/go/tools/cmd/{gosimple,staticcheck}
|
||||
- npm install -g codeclimate-test-reporter
|
||||
script:
|
||||
- go build -v ./cmd/dep
|
||||
- go vet $PKGS
|
||||
|
@ -26,5 +31,10 @@ script:
|
|||
- ./hack/validate-gofmt.bash
|
||||
- ./hack/validate-vendor.bash
|
||||
- gosimple $PKGS
|
||||
- go test -race $PKGS
|
||||
#- go test -race $PKGS
|
||||
- go build ./hack/licenseok
|
||||
- set -e; for pkg in $PKGS; do go test -race -coverprofile=profile.out -covermode=atomic $pkg; if [[ -f profile.out ]]; then cat profile.out >> coverage.txt; rm profile.out; fi; done
|
||||
- find . -path ./vendor -prune -o -type f -name "*.go" -printf '%P\n' | xargs ./licenseok
|
||||
- ./hack/validate-vendor.bash
|
||||
after_success:
|
||||
- codeclimate-test-reporter < coverage.txt
|
||||
|
|
14
FAQ.md
14
FAQ.md
|
@ -17,16 +17,22 @@ Summarize the question and quote the reply, linking back to the original comment
|
|||
* [Why did dep use a different revision for package X instead of the revision in the lock file?](#why-did-dep-use-a-different-revision-for-package-x-instead-of-the-revision-in-the-lock-file)
|
||||
|
||||
## What is a direct or transitive dependency?
|
||||
* Direct dependencies appear in at least one import statement from your project - are dependencies that are imported by your project.
|
||||
* Direct dependencies are dependencies that are imported directly by your project: they appear in at least one import statement from your project.
|
||||
* Transitive dependencies are the dependencies of your dependencies. Necessary to compile but are not directly used by your code.
|
||||
|
||||
## Should I commit my vendor directory?
|
||||
|
||||
Committing the vendor directory is totally up to you. There is no general advice that applies in all cases.
|
||||
It's up to you:
|
||||
|
||||
**Pros**: it's the only way to get truly reproducible builds, as it guards against upstream renames and deletes; and you don't need an extra `dep ensure` step on fresh clones to build your repo.
|
||||
**Pros**
|
||||
|
||||
**Cons**: your repo will be bigger, potentially a lot bigger; and PR diffs are more annoying.
|
||||
- it's the only way to get truly reproducible builds, as it guards against upstream renames and deletes
|
||||
- you don't need an extra `dep ensure` step (to fetch dependencies) on fresh clones to build your repo
|
||||
|
||||
**Cons**
|
||||
|
||||
- your repo will be bigger, potentially a lot bigger
|
||||
- PR diffs are more annoying
|
||||
|
||||
## Why is it `dep ensure` instead of `dep install`?
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
memo = "099c73630ad2c4f0894ed8646e2e4b5a9f635c85661a77fbf3b9f9dd78c77e87"
|
||||
memo = "71329a18f735441776be73d92d064f26a67fa30e616bbdfbb47e8dc68bda8c5c"
|
||||
|
||||
[[projects]]
|
||||
branch = "2.x"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# Temporarily, until gps moves in and this becomes a direct dep again
|
||||
required = ["github.com/Masterminds/semver"]
|
||||
|
||||
[[dependencies]]
|
||||
branch = "2.x"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Dep
|
||||
|
||||
Linux: [![Build Status](https://travis-ci.org/golang/dep.svg?branch=master)](https://travis-ci.org/golang/dep) | Windows: [![Build status](https://ci.appveyor.com/api/projects/status/4pu2xnnrikol2gsf/branch/master?svg=true)](https://ci.appveyor.com/project/golang/dep/branch/master)
|
||||
Linux: [![Build Status](https://travis-ci.org/golang/dep.svg?branch=master)](https://travis-ci.org/golang/dep) | Windows: [![Build status](https://ci.appveyor.com/api/projects/status/4pu2xnnrikol2gsf/branch/master?svg=true)](https://ci.appveyor.com/project/golang/dep/branch/master) | [![Code Climate](https://codeclimate.com/github/golang/dep/badges/gpa.svg)](https://codeclimate.com/github/golang/dep)
|
||||
|
||||
Dep is a prototype dependency management tool. It requires Go 1.7 or newer to compile.
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ func (a Analyzer) DeriveManifestAndLock(path string, n gps.ProjectRoot) (gps.Man
|
|||
}
|
||||
f, err := os.Open(mf)
|
||||
if err != nil {
|
||||
return nil, nil, nil
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
package dep
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/dep/test"
|
||||
)
|
||||
|
||||
func TestDeriveManifestAndLock(t *testing.T) {
|
||||
func TestAnalyzerDeriveManifestAndLock(t *testing.T) {
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
|
@ -49,17 +49,75 @@ func TestDeriveManifestAndLock(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDeriveManifestAndLockDoesNotExist(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "dep")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
func TestAnalyzerDeriveManifestAndLockDoesNotExist(t *testing.T) {
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
h.TempDir("dep")
|
||||
|
||||
a := Analyzer{}
|
||||
|
||||
m, l, err := a.DeriveManifestAndLock(dir, "my/fake/project")
|
||||
m, l, err := a.DeriveManifestAndLock(h.Path("dep"), "my/fake/project")
|
||||
if m != nil || l != nil || err != nil {
|
||||
t.Fatalf("expected manifest & lock & err to be nil: m -> %#v l -> %#v err-> %#v", m, l, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyzerDeriveManifestAndLockCannotOpen(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// TODO: find an implementation that works on Microsoft
|
||||
// Windows. Setting permissions works differently there.
|
||||
// os.Chmod(..., 0222) below is not enough for the file
|
||||
// to be write-only (unreadable), and os.Chmod(...,
|
||||
// 0000) returns an invalid argument error.
|
||||
t.Skip("skipping on windows")
|
||||
}
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
h.TempDir("dep")
|
||||
|
||||
// Create an empty manifest file
|
||||
h.TempFile(filepath.Join("dep", ManifestName), "")
|
||||
|
||||
// Change its mode so that it cannot be read
|
||||
err := os.Chmod(filepath.Join(h.Path("dep"), ManifestName), 0222)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := Analyzer{}
|
||||
|
||||
m, l, err := a.DeriveManifestAndLock(h.Path("dep"), "my/fake/project")
|
||||
if m != nil || l != nil || err == nil {
|
||||
t.Fatalf("expected manifest & lock to be nil, err to be not nil: m -> %#v l -> %#v err -> %#v", m, l, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyzerDeriveManifestAndLockInvalidManifest(t *testing.T) {
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
h.TempDir("dep")
|
||||
|
||||
// Create a manifest with invalid contents
|
||||
h.TempFile(filepath.Join("dep", ManifestName), "invalid manifest")
|
||||
|
||||
a := Analyzer{}
|
||||
|
||||
m, l, err := a.DeriveManifestAndLock(h.Path("dep"), "my/fake/project")
|
||||
if m != nil || l != nil || err == nil {
|
||||
t.Fatalf("expected manifest & lock & err to be nil: m -> %#v l -> %#v err-> %#v", m, l, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyzerInfo(t *testing.T) {
|
||||
a := Analyzer{}
|
||||
|
||||
name, vers := a.Info()
|
||||
|
||||
if name != "dep" || vers != 1 {
|
||||
t.Fatalf("expected name to be 'dep' and version to be 1: name -> %q vers -> %d", name, vers)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -27,7 +28,7 @@ const ensureLongHelp = `
|
|||
Ensure is used to fetch project dependencies into the vendor folder, as well as
|
||||
to set version constraints for specific dependencies. It takes user input,
|
||||
solves the updated dependency graph of the project, writes any changes to the
|
||||
manifest and lock file, and places dependencies in the vendor folder.
|
||||
lock file, and places dependencies in the vendor folder.
|
||||
|
||||
Package spec:
|
||||
|
||||
|
@ -130,6 +131,10 @@ func (cmd *ensureCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
return errors.Wrap(err, "ensure ListPackage for project")
|
||||
}
|
||||
|
||||
if err := checkErrors(params.RootPackageTree.Packages); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cmd.update {
|
||||
applyUpdateArgs(args, ¶ms)
|
||||
} else {
|
||||
|
@ -160,19 +165,16 @@ func (cmd *ensureCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
writeV = dep.VendorAlways
|
||||
}
|
||||
|
||||
var sw dep.SafeWriter
|
||||
var manifest *dep.Manifest
|
||||
if !cmd.update {
|
||||
manifest = p.Manifest
|
||||
}
|
||||
|
||||
newLock := dep.LockFromInterface(solution)
|
||||
sw.Prepare(manifest, p.Lock, newLock, writeV)
|
||||
sw, err := dep.NewSafeWriter(nil, p.Lock, newLock, writeV)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.dryRun {
|
||||
return sw.PrintPreparedActions()
|
||||
}
|
||||
|
||||
return errors.Wrap(sw.Write(p.AbsRoot, sm), "grouped write of manifest, lock and vendor")
|
||||
return errors.Wrap(sw.Write(p.AbsRoot, sm, true), "grouped write of manifest, lock and vendor")
|
||||
}
|
||||
|
||||
func applyUpdateArgs(args []string, params *gps.SolveParameters) {
|
||||
|
@ -366,3 +368,30 @@ func deduceConstraint(s string) gps.Constraint {
|
|||
// TODO: if there is amgibuity here, then prompt the user?
|
||||
return gps.NewVersion(s)
|
||||
}
|
||||
|
||||
func checkErrors(m map[string]pkgtree.PackageOrErr) error {
|
||||
noGoErrors, pkgErrors := 0, 0
|
||||
for _, poe := range m {
|
||||
if poe.Err != nil {
|
||||
switch poe.Err.(type) {
|
||||
case *build.NoGoError:
|
||||
noGoErrors++
|
||||
default:
|
||||
pkgErrors++
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(m) == 0 || len(m) == noGoErrors {
|
||||
return errors.New("all dirs lacked any go code")
|
||||
}
|
||||
|
||||
if len(m) == pkgErrors {
|
||||
return errors.New("all dirs had go code with errors")
|
||||
}
|
||||
|
||||
if len(m) == pkgErrors+noGoErrors {
|
||||
return errors.Errorf("%d dirs had errors and %d had no go code", pkgErrors, noGoErrors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
144
cmd/dep/init.go
144
cmd/dep/init.go
|
@ -21,16 +21,21 @@ import (
|
|||
|
||||
const initShortHelp = `Initialize a new project with manifest and lock files`
|
||||
const initLongHelp = `
|
||||
Initialize the project at filepath root by parsing its dependencies and writing
|
||||
manifest and lock files. If root isn't specified, use the current directory.
|
||||
Initialize the project at filepath root by parsing its dependencies, writing
|
||||
manifest and lock files, and vendoring the dependencies. If root isn't
|
||||
specified, use the current directory.
|
||||
|
||||
The version of each dependency will reflect the current state of the GOPATH. If
|
||||
a dependency doesn't exist in the GOPATH, it won't be written to the manifest,
|
||||
but it will be solved-for, and will appear in the lock.
|
||||
a dependency doesn't exist in the GOPATH, a version will be selected from the
|
||||
versions available from the upstream source per the following algorithm:
|
||||
|
||||
Note: init may use the network to solve the dependency graph.
|
||||
- Tags conforming to semver (sorted by semver rules)
|
||||
- Default branch(es) (sorted lexicographically)
|
||||
- Non-semver tags (sorted lexicographically)
|
||||
|
||||
Note: init does NOT vendor dependencies at the moment. See dep ensure.
|
||||
A Gopkg.toml file will be written with inferred version constraints for all
|
||||
direct dependencies. Gopkg.lock will be written with precise versions, and
|
||||
vendor/ will be populated with the precise versions written to Gopkg.lock.
|
||||
`
|
||||
|
||||
func (cmd *initCommand) Name() string { return "init" }
|
||||
|
@ -39,9 +44,13 @@ func (cmd *initCommand) ShortHelp() string { return initShortHelp }
|
|||
func (cmd *initCommand) LongHelp() string { return initLongHelp }
|
||||
func (cmd *initCommand) Hidden() bool { return false }
|
||||
|
||||
func (cmd *initCommand) Register(fs *flag.FlagSet) {}
|
||||
func (cmd *initCommand) Register(fs *flag.FlagSet) {
|
||||
fs.BoolVar(&cmd.noExamples, "no-examples", false, "don't include example in Gopkg.toml")
|
||||
}
|
||||
|
||||
type initCommand struct{}
|
||||
type initCommand struct {
|
||||
noExamples bool
|
||||
}
|
||||
|
||||
func trimPathPrefix(p1, p2 string) string {
|
||||
if internal.HasFilepathPrefix(p1, p2) {
|
||||
|
@ -74,7 +83,7 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
return err
|
||||
}
|
||||
if mok {
|
||||
return errors.Errorf("manifest file %q already exists", mf)
|
||||
return errors.Errorf("manifest already exists: %s", mf)
|
||||
}
|
||||
// Manifest file does not exist.
|
||||
|
||||
|
@ -135,38 +144,59 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
)
|
||||
}
|
||||
|
||||
if len(pd.notondisk) > 0 {
|
||||
internal.Vlogf("Solving...")
|
||||
params := gps.SolveParameters{
|
||||
RootDir: root,
|
||||
RootPackageTree: pkgT,
|
||||
Manifest: m,
|
||||
Lock: l,
|
||||
ProjectAnalyzer: dep.Analyzer{},
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
params.Trace = true
|
||||
params.TraceLogger = log.New(os.Stderr, "", 0)
|
||||
}
|
||||
s, err := gps.Prepare(params, sm)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "prepare solver")
|
||||
}
|
||||
|
||||
soln, err := s.Solve()
|
||||
if err != nil {
|
||||
handleAllTheFailuresOfTheWorld(err)
|
||||
return err
|
||||
}
|
||||
l = dep.LockFromInterface(soln)
|
||||
// Run solver with project versions found on disk
|
||||
internal.Vlogf("Solving...")
|
||||
params := gps.SolveParameters{
|
||||
RootDir: root,
|
||||
RootPackageTree: pkgT,
|
||||
Manifest: m,
|
||||
Lock: l,
|
||||
ProjectAnalyzer: dep.Analyzer{},
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
params.Trace = true
|
||||
params.TraceLogger = log.New(os.Stderr, "", 0)
|
||||
}
|
||||
s, err := gps.Prepare(params, sm)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "prepare solver")
|
||||
}
|
||||
|
||||
soln, err := s.Solve()
|
||||
if err != nil {
|
||||
handleAllTheFailuresOfTheWorld(err)
|
||||
return err
|
||||
}
|
||||
l = dep.LockFromInterface(soln)
|
||||
|
||||
// Pick notondisk project constraints from solution and add to manifest
|
||||
for k, _ := range pd.notondisk {
|
||||
for _, x := range l.Projects() {
|
||||
if k == x.Ident().ProjectRoot {
|
||||
m.Dependencies[k] = getProjectPropertiesFromVersion(x.Version())
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run gps.Prepare with appropriate constraint solutions from solve run
|
||||
// to generate the final lock memo.
|
||||
s, err = gps.Prepare(params, sm)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "prepare solver")
|
||||
}
|
||||
|
||||
l.Memo = s.HashInputs()
|
||||
|
||||
internal.Vlogf("Writing manifest and lock files.")
|
||||
|
||||
var sw dep.SafeWriter
|
||||
sw.Prepare(m, nil, l, dep.VendorAlways)
|
||||
if err := sw.Write(root, sm); err != nil {
|
||||
sw, err := dep.NewSafeWriter(m, nil, l, dep.VendorAlways)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sw.Write(root, sm, cmd.noExamples); err != nil {
|
||||
return errors.Wrap(err, "safe write of manifest and lock")
|
||||
}
|
||||
|
||||
|
@ -200,7 +230,6 @@ func isStdLib(path string) bool {
|
|||
// TODO solve failures can be really creative - we need to be similarly creative
|
||||
// in handling them and informing the user appropriately
|
||||
func handleAllTheFailuresOfTheWorld(err error) {
|
||||
fmt.Printf("solve error: %s\n", err)
|
||||
}
|
||||
|
||||
func hasImportPathPrefix(s, prefix string) bool {
|
||||
|
@ -210,6 +239,34 @@ func hasImportPathPrefix(s, prefix string) bool {
|
|||
return strings.HasPrefix(s, prefix+"/")
|
||||
}
|
||||
|
||||
// getProjectPropertiesFromVersion takes a gps.Version and returns a proper
|
||||
// gps.ProjectProperties with Constraint value based on the provided version.
|
||||
func getProjectPropertiesFromVersion(v gps.Version) gps.ProjectProperties {
|
||||
pp := gps.ProjectProperties{}
|
||||
|
||||
// extract version and ignore if it's revision only
|
||||
switch tv := v.(type) {
|
||||
case gps.PairedVersion:
|
||||
v = tv.Unpair()
|
||||
case gps.Revision:
|
||||
return pp
|
||||
}
|
||||
|
||||
switch v.Type() {
|
||||
case gps.IsBranch, gps.IsVersion:
|
||||
pp.Constraint = v
|
||||
case gps.IsSemver:
|
||||
// TODO: remove "^" when https://github.com/golang/dep/issues/225 is ready.
|
||||
c, err := gps.NewSemverConstraint("^" + v.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pp.Constraint = c
|
||||
}
|
||||
|
||||
return pp
|
||||
}
|
||||
|
||||
type projectData struct {
|
||||
constraints gps.ProjectConstraints // constraints that could be found
|
||||
dependencies map[gps.ProjectRoot][]string // all dependencies (imports) found by project root
|
||||
|
@ -264,16 +321,7 @@ func getProjectData(ctx *dep.Ctx, pkgT pkgtree.PackageTree, cpr string, sm *gps.
|
|||
}
|
||||
|
||||
ondisk[pr] = v
|
||||
pp := gps.ProjectProperties{}
|
||||
switch v.Type() {
|
||||
case gps.IsBranch, gps.IsVersion, gps.IsRevision:
|
||||
pp.Constraint = v
|
||||
case gps.IsSemver:
|
||||
c, _ := gps.NewSemverConstraint("^" + v.String())
|
||||
pp.Constraint = c
|
||||
}
|
||||
|
||||
constraints[pr] = pp
|
||||
constraints[pr] = getProjectPropertiesFromVersion(v)
|
||||
}
|
||||
|
||||
internal.Vlogf("Analyzing transitive imports...")
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/sdboyer/gps"
|
||||
)
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
a := []string{"a", "b", "abcd"}
|
||||
|
@ -33,3 +38,46 @@ func TestIsStdLib(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProjectPropertiesFromVersion(t *testing.T) {
|
||||
wantSemver, _ := gps.NewSemverConstraint("^v1.0.0")
|
||||
cases := []struct {
|
||||
version, want gps.Constraint
|
||||
}{
|
||||
{
|
||||
version: gps.NewBranch("foo-branch"),
|
||||
want: gps.NewBranch("foo-branch"),
|
||||
},
|
||||
{
|
||||
version: gps.NewVersion("foo-version"),
|
||||
want: gps.NewVersion("foo-version"),
|
||||
},
|
||||
{
|
||||
version: gps.NewVersion("v1.0.0"),
|
||||
want: wantSemver,
|
||||
},
|
||||
{
|
||||
version: gps.NewBranch("foo-branch").Is("some-revision"),
|
||||
want: gps.NewBranch("foo-branch"),
|
||||
},
|
||||
{
|
||||
version: gps.NewVersion("foo-version").Is("some-revision"),
|
||||
want: gps.NewVersion("foo-version"),
|
||||
},
|
||||
{
|
||||
version: gps.Revision("some-revision"),
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
version: gps.NewVersion("v1.0.0").Is("some-revision"),
|
||||
want: wantSemver,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
actualProp := getProjectPropertiesFromVersion(c.version.(gps.Version))
|
||||
if !reflect.DeepEqual(c.want, actualProp.Constraint) {
|
||||
t.Fatalf("Constraints are not as expected: \n\t(GOT) %v\n\t(WNT) %v", actualProp.Constraint, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ func TestIntegration(t *testing.T) {
|
|||
test.NeedsGit(t)
|
||||
|
||||
filepath.Walk(filepath.Join("testdata", "harness_tests"), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
t.Fatal("error walking filepath")
|
||||
}
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -51,13 +55,18 @@ func TestIntegration(t *testing.T) {
|
|||
|
||||
// Run commands
|
||||
testProj.RecordImportPaths()
|
||||
for _, args := range testCase.Commands {
|
||||
|
||||
var err error
|
||||
for i, args := range testCase.Commands {
|
||||
err = testProj.DoRun(args)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
if err != nil && i < len(testCase.Commands)-1 {
|
||||
t.Fatalf("cmd %s raised an unexpected error: %s", args[0], err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Check error raised in final command
|
||||
testCase.CompareError(err, testProj.GetStderr())
|
||||
|
||||
// Check final manifest and lock
|
||||
testCase.CompareFile(dep.ManifestName, testProj.ProjPath(dep.ManifestName))
|
||||
testCase.CompareFile(dep.LockName, testProj.ProjPath(dep.LockName))
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
|
||||
const removeShortHelp = `Remove a dependency from the project`
|
||||
const removeLongHelp = `
|
||||
Remove a dependency from the project's manifest file, lock file, and vendor
|
||||
Remove a dependency from the project's lock file, and vendor
|
||||
folder. If the project includes that dependency in its import graph, remove will
|
||||
fail unless -force is specified.
|
||||
`
|
||||
|
@ -180,10 +180,13 @@ func (cmd *removeCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var sw dep.SafeWriter
|
||||
newLock := dep.LockFromInterface(soln)
|
||||
sw.Prepare(p.Manifest, p.Lock, newLock, dep.VendorOnChanged)
|
||||
if err := sw.Write(p.AbsRoot, sm); err != nil {
|
||||
|
||||
sw, err := dep.NewSafeWriter(nil, p.Lock, newLock, dep.VendorOnChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sw.Write(p.AbsRoot, sm, true); err != nil {
|
||||
return errors.Wrap(err, "grouped write of manifest, lock and vendor")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -28,7 +28,7 @@ desired. The test name will consist of the directory path from `testdata` to
|
|||
the test case directory itself. In the above example, the test name would be
|
||||
`category1/subcategory1/case1`, and could be singled out with the `-run` option
|
||||
of `go test` (i.e.
|
||||
`go test github.com/golang/dep/cmp/dep -run Integration/category1/subcategory1/case1`).
|
||||
`go test github.com/golang/dep/cmd/dep -run Integration/category1/subcategory1/case1`).
|
||||
New tests can be added simply by adding a new directory with the json file to
|
||||
the `testdata` tree. There is no need for code modification - the new test
|
||||
will be included automatically.
|
||||
|
@ -58,7 +58,8 @@ The `testcase.json` file has the following format:
|
|||
"github.com/sdboyer/deptestdos",
|
||||
"github.com/sdboyer/deptesttres",
|
||||
"github.com/sdboyer/deptestquatro"
|
||||
]
|
||||
],
|
||||
"error-expected": "something went wrong"
|
||||
}
|
||||
|
||||
All of the categories are optional - if the `imports` list for a test is empty,
|
||||
|
@ -72,9 +73,10 @@ The test procedure is as follows:
|
|||
4. Fetch the repos and versions in `gopath-initial` into `$TMPDIR/src` directory
|
||||
5. Fetch the repos and versions in `vendor-initial` to the project's `vendor` directory
|
||||
6. Run `commands` on the project, in declaration order
|
||||
7. Check the resulting files against those in the `final` input directory
|
||||
8. Check the `vendor` directory for the projects listed under `vendor-final`
|
||||
9. Check that there were no changes to `src` listings
|
||||
10. Clean up
|
||||
7. Ensure that, if any errors are raised, it is only by the final command and their string output matches `error-expected`
|
||||
8. Check the resulting files against those in the `final` input directory
|
||||
9. Check the `vendor` directory for the projects listed under `vendor-final`
|
||||
10. Check that there were no changes to `src` listings
|
||||
11. Clean up
|
||||
|
||||
Note that for the remote fetches, only git repos are currently supported.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
memo = "4b36ae008ef4be09dee7e2ae00606d44fd75f4310fd0d0ef6e744690290569de"
|
||||
memo = "14b07b05e0f01051b03887ab2bf80b516bc5510ea92f75f76c894b1745d8850c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
|
|
|
@ -1,9 +1,56 @@
|
|||
|
||||
# Example:
|
||||
## Gopkg.toml example (these lines may be deleted)
|
||||
|
||||
## "required" lists a set of packages (not projects) that must be included in
|
||||
## Gopkg.lock. This list is merged with the set of packages imported by the current
|
||||
## project. Use it when your project needs a package it doesn't explicitly import -
|
||||
## including "main" packages.
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
|
||||
## "ignored" lists a set of packages (not projects) that are ignored when
|
||||
## dep statically analyzes source code. Ignored packages can be in this project,
|
||||
## or in a dependency.
|
||||
# ignored = ["github.com/user/project/badpkg"]
|
||||
|
||||
## Dependencies define constraints on dependent projects. They are respected by
|
||||
## dep whether coming from the Gopkg.toml of the current project or a dependency.
|
||||
# [[dependencies]]
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
# branch = "master"
|
||||
# name = "github.com/vendor/package"
|
||||
# Note: revision will depend on your repository type, i.e git, svc, bzr etc...
|
||||
# revision = "abc123"
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Recommended: the version constraint to enforce for the project.
|
||||
## Only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: an alternate location (URL or import path) for the project's source.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
## Overrides have the same structure as [[dependencies]], but supercede all
|
||||
## [[dependencies]] declarations from all projects. Only the current project's
|
||||
## [[overrides]] are applied.
|
||||
##
|
||||
## Overrides are a sledgehammer. Use them only as a last resort.
|
||||
# [[overrides]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Optional: specifying a version constraint override will cause all other
|
||||
## constraints on this project to be ignored; only the overriden constraint
|
||||
## need be satisfied.
|
||||
## Again, only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: specifying an alternate source location as an override will
|
||||
## enforce that the alternate location is used for that project, regardless of
|
||||
## what source location any dependent projects specify.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = "^1.0.0"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = "^0.8.0"
|
||||
version = "~0.8.0"
|
|
@ -1,4 +1,56 @@
|
|||
|
||||
[[overrides]]
|
||||
## Gopkg.toml example (these lines may be deleted)
|
||||
|
||||
## "required" lists a set of packages (not projects) that must be included in
|
||||
## Gopkg.lock. This list is merged with the set of packages imported by the current
|
||||
## project. Use it when your project needs a package it doesn't explicitly import -
|
||||
## including "main" packages.
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
|
||||
## "ignored" lists a set of packages (not projects) that are ignored when
|
||||
## dep statically analyzes source code. Ignored packages can be in this project,
|
||||
## or in a dependency.
|
||||
# ignored = ["github.com/user/project/badpkg"]
|
||||
|
||||
## Dependencies define constraints on dependent projects. They are respected by
|
||||
## dep whether coming from the Gopkg.toml of the current project or a dependency.
|
||||
# [[dependencies]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Recommended: the version constraint to enforce for the project.
|
||||
## Only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: an alternate location (URL or import path) for the project's source.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
## Overrides have the same structure as [[dependencies]], but supercede all
|
||||
## [[dependencies]] declarations from all projects. Only the current project's
|
||||
## [[overrides]] are applied.
|
||||
##
|
||||
## Overrides are a sledgehammer. Use them only as a last resort.
|
||||
# [[overrides]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Optional: specifying a version constraint override will cause all other
|
||||
## constraints on this project to be ignored; only the overriden constraint
|
||||
## need be satisfied.
|
||||
## Again, only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: specifying an alternate source location as an override will
|
||||
## enforce that the alternate location is used for that project, regardless of
|
||||
## what source location any dependent projects specify.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = "1.0.0"
|
||||
version = "^1.0.0"
|
||||
|
|
1
cmd/dep/testdata/harness_tests/ensure/pkg-errors/case1/final/Gopkg.lock
сгенерированный
поставляемый
Normal file
1
cmd/dep/testdata/harness_tests/ensure/pkg-errors/case1/final/Gopkg.lock
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1 @@
|
|||
memo = "ab4fef131ee828e96ba67d31a7d690bd5f2f42040c6766b1b12fe856f87e0ff7"
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"commands": [
|
||||
["init", "-no-examples"],
|
||||
["ensure", "-update"]
|
||||
],
|
||||
"error-expected" : "all dirs lacked any go code"
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
memo = ""
|
||||
memo = "88d2718cda70cce45158f953d2c6ead79c1db38e67e9704aff72be8fddb096e7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
|
|
|
@ -5,4 +5,3 @@
|
|||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"commands": [
|
||||
["init"]
|
||||
["init", "-no-examples"]
|
||||
],
|
||||
"gopath-initial": {
|
||||
"github.com/sdboyer/deptest": "v0.8.0",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
memo = "88d2718cda70cce45158f953d2c6ead79c1db38e67e9704aff72be8fddb096e7"
|
||||
memo = "b4fe6e8bceac924197838b6ea47989abbdd3a8d31035d20ee0a1dabc0994c368"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
|
|
|
@ -2,3 +2,7 @@
|
|||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = ">=0.8.0, <1.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
version = "^2.0.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"commands": [
|
||||
["init"]
|
||||
["init", "-no-examples"]
|
||||
],
|
||||
"gopath-initial": {
|
||||
"github.com/sdboyer/deptest": "v0.8.0"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
memo = ""
|
||||
memo = "af9a783a5430dabcaaf44683c09e2b729e1c0d61f13bfdf6677c4fd0b41387ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
|
@ -5,4 +5,3 @@
|
|||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"commands": [
|
||||
["init"]
|
||||
["init", "-no-examples"]
|
||||
],
|
||||
"gopath-initial": {
|
||||
"github.com/sdboyer/deptestdos": "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"commands": [
|
||||
["init"]
|
||||
],
|
||||
"error-expected" : "manifest already exists:"
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
memo = "4b36ae008ef4be09dee7e2ae00606d44fd75f4310fd0d0ef6e744690290569de"
|
||||
memo = "14b07b05e0f01051b03887ab2bf80b516bc5510ea92f75f76c894b1745d8850c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
|
||||
# Example:
|
||||
# [[dependencies]]
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
# branch = "master"
|
||||
# name = "github.com/vendor/package"
|
||||
# Note: revision will depend on your repository type, i.e git, svc, bzr etc...
|
||||
# revision = "abc123"
|
||||
# version = "1.0.0"
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = "^1.0.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"commands": [
|
||||
["init"]
|
||||
["init", "-no-examples"]
|
||||
],
|
||||
"vendor-final": [
|
||||
"github.com/sdboyer/deptest"
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
[[dependencies]]
|
||||
name = "github.com/not/used"
|
||||
version = "2.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = ">=0.8.0, <1.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
[[dependencies]]
|
||||
name = "github.com/not/used"
|
||||
version = "2.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = ">=0.8.0, <1.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
|
@ -1,3 +1,6 @@
|
|||
[[dependencies]]
|
||||
name = "github.com/not/used"
|
||||
version = "2.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
|
@ -5,4 +8,4 @@
|
|||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
|
@ -1,3 +1,6 @@
|
|||
[[dependencies]]
|
||||
name = "github.com/not/used"
|
||||
version = "2.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
|
@ -5,4 +8,4 @@
|
|||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptestdos"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
||||
revision = "a0196baa11ea047dd65037287451d36b861b00ea"
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/deptest"
|
||||
version = ">=0.8.0, <1.0.0"
|
||||
version = "^0.8.0"
|
||||
|
|
101
context_test.go
101
context_test.go
|
@ -352,22 +352,15 @@ func TestResolveProjectRoot(t *testing.T) {
|
|||
tg := test.NewHelper(t)
|
||||
defer tg.Cleanup()
|
||||
|
||||
tg.TempDir("go")
|
||||
tg.TempDir("go/src")
|
||||
tg.TempDir("go/src/real")
|
||||
tg.TempDir("go/src/real/path")
|
||||
tg.TempDir("go/src/sym")
|
||||
|
||||
tg.TempDir("gotwo") // Another directory used as a GOPATH
|
||||
tg.TempDir("gotwo/src")
|
||||
tg.TempDir("gotwo/src/real")
|
||||
// Another directory used as a GOPATH
|
||||
tg.TempDir("gotwo/src/real/path")
|
||||
tg.TempDir("gotwo/src/sym")
|
||||
|
||||
tg.TempDir("sym") // Directory for symlinks
|
||||
|
||||
tg.Setenv("GOPATH", tg.Path(filepath.Join(".", "go")))
|
||||
|
||||
ctx := &Ctx{
|
||||
GOPATH: tg.Path(filepath.Join(".", "go")),
|
||||
GOPATHS: []string{
|
||||
|
@ -376,45 +369,65 @@ func TestResolveProjectRoot(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
realPath := filepath.Join(ctx.GOPATH, "src", "real", "path")
|
||||
realPathTwo := filepath.Join(ctx.GOPATHS[1], "src", "real", "path")
|
||||
symlinkedPath := filepath.Join(tg.Path("."), "sym", "symlink")
|
||||
symlinkedInGoPath := filepath.Join(ctx.GOPATH, "src/sym/path")
|
||||
symlinkedInOtherGoPath := filepath.Join(tg.Path("."), "sym", "symtwo")
|
||||
os.Symlink(realPath, symlinkedPath)
|
||||
os.Symlink(realPath, symlinkedInGoPath)
|
||||
os.Symlink(realPathTwo, symlinkedInOtherGoPath)
|
||||
|
||||
// Real path should be returned, no symlinks to deal with
|
||||
p, err := ctx.resolveProjectRoot(realPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Error resolving project root: %s", err)
|
||||
}
|
||||
if p != realPath {
|
||||
t.Fatalf("Want path to be %s, got %s", realPath, p)
|
||||
testcases := []struct {
|
||||
name string
|
||||
path string
|
||||
resolvedPath string
|
||||
symlink bool
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "no-symlinks",
|
||||
path: filepath.Join(ctx.GOPATH, "src/real/path"),
|
||||
resolvedPath: filepath.Join(ctx.GOPATH, "src/real/path"),
|
||||
},
|
||||
{
|
||||
name: "symlink-outside-gopath",
|
||||
path: filepath.Join(tg.Path("."), "sym/symlink"),
|
||||
resolvedPath: filepath.Join(ctx.GOPATH, "src/real/path"),
|
||||
symlink: true,
|
||||
},
|
||||
{
|
||||
name: "symlink-in-another-gopath",
|
||||
path: filepath.Join(tg.Path("."), "sym/symtwo"),
|
||||
resolvedPath: filepath.Join(ctx.GOPATHS[1], "src/real/path"),
|
||||
symlink: true,
|
||||
},
|
||||
{
|
||||
name: "symlink-in-gopath",
|
||||
path: filepath.Join(ctx.GOPATH, "src/sym/path"),
|
||||
resolvedPath: filepath.Join(ctx.GOPATH, "src/real/path"),
|
||||
symlink: true,
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
// Real path should be returned, symlink is outside GOPATH
|
||||
p, err = ctx.resolveProjectRoot(symlinkedPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Error resolving project root: %s", err)
|
||||
}
|
||||
if p != realPath {
|
||||
t.Fatalf("Want path to be %s, got %s", realPath, p)
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if tc.symlink {
|
||||
if err := os.Symlink(tc.resolvedPath, tc.path); err != nil {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("Not testing Windows symlinks because: %s", err)
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Real path should be returned, symlink is in another GOPATH
|
||||
p, err = ctx.resolveProjectRoot(symlinkedInOtherGoPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Error resolving project root: %s", err)
|
||||
}
|
||||
if p != realPathTwo {
|
||||
t.Fatalf("Want path to be %s, got %s", realPathTwo, p)
|
||||
}
|
||||
p, err := ctx.resolveProjectRoot(tc.path)
|
||||
if err != nil {
|
||||
if !tc.expectErr {
|
||||
t.Fatalf("Error resolving project root: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err == nil && tc.expectErr {
|
||||
t.Fatal("Wanted an error")
|
||||
}
|
||||
|
||||
// Symlinked path is inside GOPATH, should return error
|
||||
_, err = ctx.resolveProjectRoot(symlinkedInGoPath)
|
||||
if err == nil {
|
||||
t.Fatalf("Wanted an error")
|
||||
if p != tc.resolvedPath {
|
||||
t.Errorf("Want path to be %s, got %s", tc.resolvedPath, p)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,6 +190,8 @@ func TestIsEmpty(t *testing.T) {
|
|||
}
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
h.TempDir("empty")
|
||||
tests := map[string]string{
|
||||
wd: "true",
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -27,6 +28,7 @@ type IntegrationTestCase struct {
|
|||
initialPath string
|
||||
finalPath string
|
||||
Commands [][]string `json:"commands"`
|
||||
ErrorExpected string `json:"error-expected"`
|
||||
GopathInitial map[string]string `json:"gopath-initial"`
|
||||
VendorInitial map[string]string `json:"vendor-initial"`
|
||||
VendorFinal []string `json:"vendor-final"`
|
||||
|
@ -126,6 +128,22 @@ func (tc *IntegrationTestCase) CompareFile(goldenPath, working string) {
|
|||
}
|
||||
}
|
||||
|
||||
// CompareError compares exected and actual error
|
||||
func (tc *IntegrationTestCase) CompareError(err error, stderr string) {
|
||||
wantExists, want := tc.ErrorExpected != "", tc.ErrorExpected
|
||||
gotExists, got := stderr != "" && err != nil, stderr
|
||||
|
||||
if wantExists && gotExists {
|
||||
if !strings.Contains(got, want) {
|
||||
tc.t.Errorf("expected error containing %s, got error %s", want, got)
|
||||
}
|
||||
} else if !wantExists && gotExists {
|
||||
tc.t.Fatal("error raised where none was expected")
|
||||
} else if wantExists && !gotExists {
|
||||
tc.t.Error("error not raised where one was expected")
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *IntegrationTestCase) CompareVendorPaths(gotVendorPaths []string) {
|
||||
if *UpdateGolden {
|
||||
tc.VendorFinal = gotVendorPaths
|
||||
|
|
|
@ -139,6 +139,11 @@ func (p *IntegrationTestProject) RunGit(dir string, args ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetStderr gets the Stderr output from test run
|
||||
func (p *IntegrationTestProject) GetStderr() string {
|
||||
return p.stderr.String()
|
||||
}
|
||||
|
||||
func (p *IntegrationTestProject) GetVendorGit(ip string) {
|
||||
parse := strings.Split(ip, "/")
|
||||
gitDir := strings.Join(parse[:len(parse)-1], string(filepath.Separator))
|
||||
|
|
|
@ -1,4 +1,56 @@
|
|||
|
||||
## Gopkg.toml example (these lines may be deleted)
|
||||
|
||||
## "required" lists a set of packages (not projects) that must be included in
|
||||
## Gopkg.lock. This list is merged with the set of packages imported by the current
|
||||
## project. Use it when your project needs a package it doesn't explicitly import -
|
||||
## including "main" packages.
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
|
||||
## "ignored" lists a set of packages (not projects) that are ignored when
|
||||
## dep statically analyzes source code. Ignored packages can be in this project,
|
||||
## or in a dependency.
|
||||
# ignored = ["github.com/user/project/badpkg"]
|
||||
|
||||
## Dependencies define constraints on dependent projects. They are respected by
|
||||
## dep whether coming from the Gopkg.toml of the current project or a dependency.
|
||||
# [[dependencies]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Recommended: the version constraint to enforce for the project.
|
||||
## Only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: an alternate location (URL or import path) for the project's source.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
## Overrides have the same structure as [[dependencies]], but supercede all
|
||||
## [[dependencies]] declarations from all projects. Only the current project's
|
||||
## [[overrides]] are applied.
|
||||
##
|
||||
## Overrides are a sledgehammer. Use them only as a last resort.
|
||||
# [[overrides]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Optional: specifying a version constraint override will cause all other
|
||||
## constraints on this project to be ignored; only the overriden constraint
|
||||
## need be satisfied.
|
||||
## Again, only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: specifying an alternate source location as an override will
|
||||
## enforce that the alternate location is used for that project, regardless of
|
||||
## what source location any dependent projects specify.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
|
||||
|
||||
[[dependencies]]
|
||||
name = "github.com/sdboyer/dep-test"
|
||||
version = "1.0.0"
|
||||
|
|
241
txn_writer.go
241
txn_writer.go
|
@ -21,15 +21,58 @@ import (
|
|||
// Example string to be written to the manifest file
|
||||
// if no dependencies are found in the project
|
||||
// during `dep init`
|
||||
const exampleToml = `
|
||||
# Example:
|
||||
const exampleTOML = `
|
||||
## Gopkg.toml example (these lines may be deleted)
|
||||
|
||||
## "required" lists a set of packages (not projects) that must be included in
|
||||
## Gopkg.lock. This list is merged with the set of packages imported by the current
|
||||
## project. Use it when your project needs a package it doesn't explicitly import -
|
||||
## including "main" packages.
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
|
||||
## "ignored" lists a set of packages (not projects) that are ignored when
|
||||
## dep statically analyzes source code. Ignored packages can be in this project,
|
||||
## or in a dependency.
|
||||
# ignored = ["github.com/user/project/badpkg"]
|
||||
|
||||
## Dependencies define constraints on dependent projects. They are respected by
|
||||
## dep whether coming from the Gopkg.toml of the current project or a dependency.
|
||||
# [[dependencies]]
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
# branch = "master"
|
||||
# name = "github.com/vendor/package"
|
||||
# Note: revision will depend on your repository type, i.e git, svc, bzr etc...
|
||||
# revision = "abc123"
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Recommended: the version constraint to enforce for the project.
|
||||
## Only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: an alternate location (URL or import path) for the project's source.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
## Overrides have the same structure as [[dependencies]], but supercede all
|
||||
## [[dependencies]] declarations from all projects. Only the current project's
|
||||
## [[overrides]] are applied.
|
||||
##
|
||||
## Overrides are a sledgehammer. Use them only as a last resort.
|
||||
# [[overrides]]
|
||||
## Required: the root import path of the project being constrained.
|
||||
# name = "github.com/user/project"
|
||||
#
|
||||
## Optional: specifying a version constraint override will cause all other
|
||||
## constraints on this project to be ignored; only the overriden constraint
|
||||
## need be satisfied.
|
||||
## Again, only one of "branch", "version" or "revision" can be specified.
|
||||
# version = "1.0.0"
|
||||
# branch = "master"
|
||||
# revision = "abc123"
|
||||
#
|
||||
## Optional: specifying an alternate source location as an override will
|
||||
## enforce that the alternate location is used for that project, regardless of
|
||||
## what source location any dependent projects specify.
|
||||
# source = "https://github.com/myfork/package.git"
|
||||
|
||||
|
||||
`
|
||||
|
||||
// SafeWriter transactionalizes writes of manifest, lock, and vendor dir, both
|
||||
|
@ -39,27 +82,63 @@ const exampleToml = `
|
|||
// It is not impervious to errors (writing to disk is hard), but it should
|
||||
// guard against non-arcane failure conditions.
|
||||
type SafeWriter struct {
|
||||
Payload *SafeWriterPayload
|
||||
}
|
||||
|
||||
// SafeWriterPayload represents the actions SafeWriter will execute when SafeWriter.Write is called.
|
||||
type SafeWriterPayload struct {
|
||||
Manifest *Manifest
|
||||
Lock *Lock
|
||||
LockDiff *gps.LockDiff
|
||||
WriteVendor bool
|
||||
}
|
||||
|
||||
func (payload *SafeWriterPayload) HasLock() bool {
|
||||
return payload.Lock != nil
|
||||
// NewSafeWriter sets up a SafeWriter to write a set of config yaml, lock and vendor tree.
|
||||
//
|
||||
// - If manifest is provided, it will be written to the standard manifest file
|
||||
// name beneath root.
|
||||
// - If newLock is provided, it will be written to the standard lock file
|
||||
// name beneath root.
|
||||
// - If vendor is VendorAlways, or is VendorOnChanged and the locks are different,
|
||||
// the vendor directory will be written beneath root based on newLock.
|
||||
// - If oldLock is provided without newLock, error.
|
||||
// - If vendor is VendorAlways without a newLock, error.
|
||||
func NewSafeWriter(manifest *Manifest, oldLock, newLock *Lock, vendor VendorBehavior) (*SafeWriter, error) {
|
||||
sw := &SafeWriter{
|
||||
Manifest: manifest,
|
||||
Lock: newLock,
|
||||
}
|
||||
if oldLock != nil {
|
||||
if newLock == nil {
|
||||
return nil, errors.New("must provide newLock when oldLock is specified")
|
||||
}
|
||||
sw.LockDiff = gps.DiffLocks(oldLock, newLock)
|
||||
}
|
||||
|
||||
switch vendor {
|
||||
case VendorAlways:
|
||||
sw.WriteVendor = true
|
||||
case VendorOnChanged:
|
||||
if sw.LockDiff != nil || (newLock != nil && oldLock == nil) {
|
||||
sw.WriteVendor = true
|
||||
}
|
||||
}
|
||||
|
||||
if sw.WriteVendor && newLock == nil {
|
||||
return nil, errors.New("must provide newLock in order to write out vendor")
|
||||
}
|
||||
|
||||
return sw, nil
|
||||
}
|
||||
|
||||
func (payload *SafeWriterPayload) HasManifest() bool {
|
||||
return payload.Manifest != nil
|
||||
// HasLock checks if a Lock is present in the SafeWriter
|
||||
func (sw *SafeWriter) HasLock() bool {
|
||||
return sw.Lock != nil
|
||||
}
|
||||
|
||||
func (payload *SafeWriterPayload) HasVendor() bool {
|
||||
return payload.WriteVendor
|
||||
// HasManifest checks if a Manifest is present in the SafeWriter
|
||||
func (sw *SafeWriter) HasManifest() bool {
|
||||
return sw.Manifest != nil
|
||||
}
|
||||
|
||||
// HasVendor returns the if SafeWriter should write to vendor
|
||||
func (sw *SafeWriter) HasVendor() bool {
|
||||
return sw.WriteVendor
|
||||
}
|
||||
|
||||
type rawStringDiff struct {
|
||||
|
@ -178,47 +257,7 @@ const (
|
|||
VendorNever
|
||||
)
|
||||
|
||||
// Prepare to write a set of config yaml, lock and vendor tree.
|
||||
//
|
||||
// - If manifest is provided, it will be written to the standard manifest file
|
||||
// name beneath root.
|
||||
// - If newLock is provided, it will be written to the standard lock file
|
||||
// name beneath root.
|
||||
// - If vendor is VendorAlways, or is VendorOnChanged and the locks are different,
|
||||
// the vendor directory will be written beneath root based on newLock.
|
||||
// - If oldLock is provided without newLock, error.
|
||||
// - If vendor is VendorAlways without a newLock, error.
|
||||
func (sw *SafeWriter) Prepare(manifest *Manifest, oldLock, newLock *Lock, vendor VendorBehavior) error {
|
||||
|
||||
sw.Payload = &SafeWriterPayload{
|
||||
Manifest: manifest,
|
||||
Lock: newLock,
|
||||
}
|
||||
|
||||
if oldLock != nil {
|
||||
if newLock == nil {
|
||||
return errors.New("must provide newLock when oldLock is specified")
|
||||
}
|
||||
sw.Payload.LockDiff = gps.DiffLocks(oldLock, newLock)
|
||||
}
|
||||
|
||||
switch vendor {
|
||||
case VendorAlways:
|
||||
sw.Payload.WriteVendor = true
|
||||
case VendorOnChanged:
|
||||
if sw.Payload.LockDiff != nil || (newLock != nil && oldLock == nil) {
|
||||
sw.Payload.WriteVendor = true
|
||||
}
|
||||
}
|
||||
|
||||
if sw.Payload.WriteVendor && newLock == nil {
|
||||
return errors.New("must provide newLock in order to write out vendor")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (payload SafeWriterPayload) validate(root string, sm gps.SourceManager) error {
|
||||
func (sw SafeWriter) validate(root string, sm gps.SourceManager) error {
|
||||
if root == "" {
|
||||
return errors.New("root path must be non-empty")
|
||||
}
|
||||
|
@ -229,7 +268,7 @@ func (payload SafeWriterPayload) validate(root string, sm gps.SourceManager) err
|
|||
return errors.Errorf("root path %q does not exist", root)
|
||||
}
|
||||
|
||||
if payload.HasVendor() && sm == nil {
|
||||
if sw.HasVendor() && sm == nil {
|
||||
return errors.New("must provide a SourceManager if writing out a vendor dir")
|
||||
}
|
||||
|
||||
|
@ -244,18 +283,13 @@ func (payload SafeWriterPayload) validate(root string, sm gps.SourceManager) err
|
|||
// operations succeeded. It also does its best to roll back if any moves fail.
|
||||
// This mostly guarantees that dep cannot exit with a partial write that would
|
||||
// leave an undefined state on disk.
|
||||
func (sw *SafeWriter) Write(root string, sm gps.SourceManager) error {
|
||||
|
||||
if sw.Payload == nil {
|
||||
return errors.New("Cannot call SafeWriter.Write before SafeWriter.Prepare")
|
||||
}
|
||||
|
||||
err := sw.Payload.validate(root, sm)
|
||||
func (sw *SafeWriter) Write(root string, sm gps.SourceManager, noExamples bool) error {
|
||||
err := sw.validate(root, sm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !sw.Payload.HasManifest() && !sw.Payload.HasLock() && !sw.Payload.HasVendor() {
|
||||
if !sw.HasManifest() && !sw.HasLock() && !sw.HasVendor() {
|
||||
// nothing to do
|
||||
return nil
|
||||
}
|
||||
|
@ -270,30 +304,48 @@ func (sw *SafeWriter) Write(root string, sm gps.SourceManager) error {
|
|||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.Payload.Manifest.IsEmpty() {
|
||||
err := modifyWithString(filepath.Join(td, ManifestName), exampleToml)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate example text")
|
||||
}
|
||||
} else if err := writeFile(filepath.Join(td, ManifestName), sw.Payload.Manifest); err != nil {
|
||||
if sw.HasManifest() {
|
||||
// Always write the example text to the bottom of the TOML file.
|
||||
tb, err := sw.Manifest.MarshalTOML()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal manifest to TOML")
|
||||
}
|
||||
|
||||
var initOutput string
|
||||
|
||||
// If examples are NOT disabled, use the example text
|
||||
if !noExamples {
|
||||
initOutput = exampleTOML
|
||||
}
|
||||
|
||||
// 0666 is before umask; mirrors behavior of os.Create (used by
|
||||
// writeFile())
|
||||
if err = ioutil.WriteFile(filepath.Join(td, ManifestName), append([]byte(initOutput), tb...), 0666); err != nil {
|
||||
return errors.Wrap(err, "failed to write manifest file to temp dir")
|
||||
}
|
||||
}
|
||||
|
||||
if sw.Payload.HasLock() {
|
||||
if err := writeFile(filepath.Join(td, LockName), sw.Payload.Lock); err != nil {
|
||||
if sw.HasLock() {
|
||||
if err := writeFile(filepath.Join(td, LockName), sw.Lock); err != nil {
|
||||
return errors.Wrap(err, "failed to write lock file to temp dir")
|
||||
}
|
||||
}
|
||||
|
||||
if sw.Payload.HasVendor() {
|
||||
err = gps.WriteDepTree(filepath.Join(td, "vendor"), sw.Payload.Lock, sm, true)
|
||||
if sw.HasVendor() {
|
||||
err = gps.WriteDepTree(filepath.Join(td, "vendor"), sw.Lock, sm, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while writing out vendor tree")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure vendor/.git is preserved if present
|
||||
if hasDotGit(vpath) {
|
||||
err = renameWithFallback(filepath.Join(vpath, ".git"), filepath.Join(td, "vendor/.git"))
|
||||
if _, ok := err.(*os.LinkError); ok {
|
||||
return errors.Wrap(err, "failed to preserve vendor/.git")
|
||||
}
|
||||
}
|
||||
|
||||
// Move the existing files and dirs to the temp dir while we put the new
|
||||
// ones in, to provide insurance against errors for as long as possible.
|
||||
type pathpair struct {
|
||||
|
@ -303,7 +355,7 @@ func (sw *SafeWriter) Write(root string, sm gps.SourceManager) error {
|
|||
var failerr error
|
||||
var vendorbak string
|
||||
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.HasManifest() {
|
||||
if _, err := os.Stat(mpath); err == nil {
|
||||
// Move out the old one.
|
||||
tmploc := filepath.Join(td, ManifestName+".orig")
|
||||
|
@ -321,7 +373,7 @@ func (sw *SafeWriter) Write(root string, sm gps.SourceManager) error {
|
|||
}
|
||||
}
|
||||
|
||||
if sw.Payload.HasLock() {
|
||||
if sw.HasLock() {
|
||||
if _, err := os.Stat(lpath); err == nil {
|
||||
// Move out the old one.
|
||||
tmploc := filepath.Join(td, LockName+".orig")
|
||||
|
@ -340,7 +392,7 @@ func (sw *SafeWriter) Write(root string, sm gps.SourceManager) error {
|
|||
}
|
||||
}
|
||||
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
if _, err := os.Stat(vpath); err == nil {
|
||||
// Move out the old vendor dir. just do it into an adjacent dir, to
|
||||
// try to mitigate the possibility of a pointless cross-filesystem
|
||||
|
@ -368,7 +420,7 @@ func (sw *SafeWriter) Write(root string, sm gps.SourceManager) error {
|
|||
|
||||
// Renames all went smoothly. The deferred os.RemoveAll will get the temp
|
||||
// dir, but if we wrote vendor, we have to clean that up directly
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
// Nothing we can really do about an error at this point, so ignore it
|
||||
os.RemoveAll(vendorbak)
|
||||
}
|
||||
|
@ -385,26 +437,26 @@ fail:
|
|||
}
|
||||
|
||||
func (sw *SafeWriter) PrintPreparedActions() error {
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.HasManifest() {
|
||||
fmt.Printf("Would have written the following %s:\n", ManifestName)
|
||||
m, err := sw.Payload.Manifest.MarshalTOML()
|
||||
m, err := sw.Manifest.MarshalTOML()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ensure DryRun cannot serialize manifest")
|
||||
}
|
||||
fmt.Println(string(m))
|
||||
}
|
||||
|
||||
if sw.Payload.HasLock() {
|
||||
if sw.Payload.LockDiff == nil {
|
||||
if sw.HasLock() {
|
||||
if sw.LockDiff == nil {
|
||||
fmt.Printf("Would have written the following %s:\n", LockName)
|
||||
l, err := sw.Payload.Lock.MarshalTOML()
|
||||
l, err := sw.Lock.MarshalTOML()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ensure DryRun cannot serialize lock")
|
||||
}
|
||||
fmt.Println(string(l))
|
||||
} else {
|
||||
fmt.Printf("Would have written the following changes to %s:\n", LockName)
|
||||
diff, err := formatLockDiff(*sw.Payload.LockDiff)
|
||||
diff, err := formatLockDiff(*sw.LockDiff)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ensure DryRun cannot serialize the lock diff")
|
||||
}
|
||||
|
@ -412,9 +464,9 @@ func (sw *SafeWriter) PrintPreparedActions() error {
|
|||
}
|
||||
}
|
||||
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
fmt.Println("Would have written the following projects to the vendor directory:")
|
||||
for _, project := range sw.Payload.Lock.Projects() {
|
||||
for _, project := range sw.Lock.Projects() {
|
||||
prj := project.Ident()
|
||||
rev, _, _ := gps.VersionComponentStrings(project.Version())
|
||||
if prj.Source == "" {
|
||||
|
@ -526,6 +578,13 @@ func deleteDirs(toDelete []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// hasDotGit checks if a given path has .git file or directory in it.
|
||||
func hasDotGit(path string) bool {
|
||||
gitfilepath := filepath.Join(path, ".git")
|
||||
_, err := os.Stat(gitfilepath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
type byLen []string
|
||||
|
||||
func (a byLen) Len() int { return len(a) }
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
package dep
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -23,10 +25,8 @@ func TestSafeWriter_BadInput_MissingRoot(t *testing.T) {
|
|||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(nil, nil, nil, VendorOnChanged)
|
||||
|
||||
err := sw.Write("", pc.SourceManager)
|
||||
sw, _ := NewSafeWriter(nil, nil, nil, VendorOnChanged)
|
||||
err := sw.Write("", pc.SourceManager, false)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("should have errored without a root path, but did not")
|
||||
|
@ -43,10 +43,8 @@ func TestSafeWriter_BadInput_MissingSourceManager(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(nil, nil, pc.Project.Lock, VendorAlways)
|
||||
|
||||
err := sw.Write(pc.Project.AbsRoot, nil)
|
||||
sw, _ := NewSafeWriter(nil, nil, pc.Project.Lock, VendorAlways)
|
||||
err := sw.Write(pc.Project.AbsRoot, nil, false)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("should have errored without a source manager when forceVendor is true, but did not")
|
||||
|
@ -61,9 +59,7 @@ func TestSafeWriter_BadInput_ForceVendorMissingLock(t *testing.T) {
|
|||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
|
||||
var sw SafeWriter
|
||||
err := sw.Prepare(nil, nil, nil, VendorAlways)
|
||||
|
||||
_, err := NewSafeWriter(nil, nil, nil, VendorAlways)
|
||||
if err == nil {
|
||||
t.Fatal("should have errored without a lock when forceVendor is true, but did not")
|
||||
} else if !strings.Contains(err.Error(), "newLock") {
|
||||
|
@ -79,9 +75,7 @@ func TestSafeWriter_BadInput_OldLockOnly(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
err := sw.Prepare(nil, pc.Project.Lock, nil, VendorAlways)
|
||||
|
||||
_, err := NewSafeWriter(nil, pc.Project.Lock, nil, VendorAlways)
|
||||
if err == nil {
|
||||
t.Fatal("should have errored with only an old lock, but did not")
|
||||
} else if !strings.Contains(err.Error(), "oldLock") {
|
||||
|
@ -95,11 +89,10 @@ func TestSafeWriter_BadInput_NonexistentRoot(t *testing.T) {
|
|||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(nil, nil, nil, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(nil, nil, nil, VendorOnChanged)
|
||||
|
||||
missingroot := filepath.Join(pc.Project.AbsRoot, "nonexistent")
|
||||
err := sw.Write(missingroot, pc.SourceManager)
|
||||
err := sw.Write(missingroot, pc.SourceManager, false)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("should have errored with nonexistent dir for root path, but did not")
|
||||
|
@ -114,11 +107,10 @@ func TestSafeWriter_BadInput_RootIsFile(t *testing.T) {
|
|||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(nil, nil, nil, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(nil, nil, nil, VendorOnChanged)
|
||||
|
||||
fileroot := pc.CopyFile("fileroot", "txn_writer/badinput_fileroot")
|
||||
err := sw.Write(fileroot, pc.SourceManager)
|
||||
err := sw.Write(fileroot, pc.SourceManager, false)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("should have errored when root path is a file, but did not")
|
||||
|
@ -139,22 +131,21 @@ func TestSafeWriter_Manifest(t *testing.T) {
|
|||
pc.CopyFile(ManifestName, safeWriterGoldenManifest)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(pc.Project.Manifest, nil, nil, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(pc.Project.Manifest, nil, nil, VendorOnChanged)
|
||||
|
||||
// Verify prepared actions
|
||||
if !sw.Payload.HasManifest() {
|
||||
if !sw.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
if sw.Payload.HasLock() {
|
||||
if sw.HasLock() {
|
||||
t.Fatal("Did not expect the payload to contain the lock")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -182,22 +173,21 @@ func TestSafeWriter_ManifestAndUnmodifiedLock(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(pc.Project.Manifest, pc.Project.Lock, pc.Project.Lock, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(pc.Project.Manifest, pc.Project.Lock, pc.Project.Lock, VendorOnChanged)
|
||||
|
||||
// Verify prepared actions
|
||||
if !sw.Payload.HasManifest() {
|
||||
if !sw.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock.")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -225,22 +215,21 @@ func TestSafeWriter_ManifestAndUnmodifiedLockWithForceVendor(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(pc.Project.Manifest, pc.Project.Lock, pc.Project.Lock, VendorAlways)
|
||||
sw, _ := NewSafeWriter(pc.Project.Manifest, pc.Project.Lock, pc.Project.Lock, VendorAlways)
|
||||
|
||||
// Verify prepared actions
|
||||
if !sw.Payload.HasManifest() {
|
||||
if !sw.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
if !sw.HasVendor() {
|
||||
t.Fatal("Expected the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -270,25 +259,24 @@ func TestSafeWriter_ModifiedLock(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
originalLock := new(Lock)
|
||||
*originalLock = *pc.Project.Lock
|
||||
originalLock.Memo = []byte{} // zero out the input hash to ensure non-equivalency
|
||||
sw.Prepare(nil, originalLock, pc.Project.Lock, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(nil, originalLock, pc.Project.Lock, VendorOnChanged)
|
||||
|
||||
// Verify prepared actions
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
if !sw.HasVendor() {
|
||||
t.Fatal("Expected the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -318,25 +306,24 @@ func TestSafeWriter_ModifiedLockSkipVendor(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
originalLock := new(Lock)
|
||||
*originalLock = *pc.Project.Lock
|
||||
originalLock.Memo = []byte{} // zero out the input hash to ensure non-equivalency
|
||||
sw.Prepare(nil, originalLock, pc.Project.Lock, VendorNever)
|
||||
sw, _ := NewSafeWriter(nil, originalLock, pc.Project.Lock, VendorNever)
|
||||
|
||||
// Verify prepared actions
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -363,25 +350,23 @@ func TestSafeWriter_ForceVendorWhenVendorAlreadyExists(t *testing.T) {
|
|||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
// Populate vendor
|
||||
sw.Prepare(nil, pc.Project.Lock, pc.Project.Lock, VendorAlways)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
sw, _ := NewSafeWriter(nil, pc.Project.Lock, pc.Project.Lock, VendorAlways)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify prepared actions
|
||||
sw.Prepare(nil, nil, pc.Project.Lock, VendorAlways)
|
||||
if sw.Payload.HasManifest() {
|
||||
sw, _ = NewSafeWriter(nil, nil, pc.Project.Lock, VendorAlways)
|
||||
if sw.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
if !sw.HasVendor() {
|
||||
t.Fatal("Expected the payload to contain the vendor directory ")
|
||||
}
|
||||
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -410,26 +395,25 @@ func TestSafeWriter_NewLock(t *testing.T) {
|
|||
defer pc.Release()
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
lf := h.GetTestFile(safeWriterGoldenLock)
|
||||
defer lf.Close()
|
||||
newLock, err := readLock(lf)
|
||||
h.Must(err)
|
||||
sw.Prepare(nil, nil, newLock, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(nil, nil, newLock, VendorOnChanged)
|
||||
|
||||
// Verify prepared actions
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
if !sw.HasVendor() {
|
||||
t.Fatal("Expected the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -455,26 +439,25 @@ func TestSafeWriter_NewLockSkipVendor(t *testing.T) {
|
|||
defer pc.Release()
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
lf := h.GetTestFile(safeWriterGoldenLock)
|
||||
defer lf.Close()
|
||||
newLock, err := readLock(lf)
|
||||
h.Must(err)
|
||||
sw.Prepare(nil, nil, newLock, VendorNever)
|
||||
sw, _ := NewSafeWriter(nil, nil, newLock, VendorNever)
|
||||
|
||||
// Verify prepared actions
|
||||
if sw.Payload.HasManifest() {
|
||||
if sw.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
if sw.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
|
@ -506,11 +489,10 @@ func TestSafeWriter_DiffLocks(t *testing.T) {
|
|||
updatedLock, err := readLock(ulf)
|
||||
h.Must(err)
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(nil, pc.Project.Lock, updatedLock, VendorOnChanged)
|
||||
sw, _ := NewSafeWriter(nil, pc.Project.Lock, updatedLock, VendorOnChanged)
|
||||
|
||||
// Verify lock diff
|
||||
diff := sw.Payload.LockDiff
|
||||
diff := sw.LockDiff
|
||||
if diff == nil {
|
||||
t.Fatal("Expected the payload to contain a diff of the lock files")
|
||||
}
|
||||
|
@ -522,3 +504,66 @@ func TestSafeWriter_DiffLocks(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasDotGit(t *testing.T) {
|
||||
// Create a tempdir with .git file
|
||||
td, err := ioutil.TempDir(os.TempDir(), "dotGitFile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
os.OpenFile(td+string(filepath.Separator)+".git", os.O_CREATE, 0777)
|
||||
if !hasDotGit(td) {
|
||||
t.Fatal("Expected hasDotGit to find .git")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWriter_VendorDotGitPreservedWithForceVendor(t *testing.T) {
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
|
||||
gitDirPath := filepath.Join(pc.Project.AbsRoot, "vendor", ".git")
|
||||
os.MkdirAll(gitDirPath, 0777)
|
||||
dummyFile := filepath.Join("vendor", ".git", "badinput_fileroot")
|
||||
pc.CopyFile(dummyFile, "txn_writer/badinput_fileroot")
|
||||
pc.CopyFile(ManifestName, safeWriterGoldenManifest)
|
||||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
sw, _ := NewSafeWriter(pc.Project.Manifest, pc.Project.Lock, pc.Project.Lock, VendorAlways)
|
||||
|
||||
// Verify prepared actions
|
||||
if !sw.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
if !sw.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.HasVendor() {
|
||||
t.Fatal("Expected the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager, false)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
if err := pc.ManifestShouldMatchGolden(safeWriterGoldenManifest); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := pc.LockShouldMatchGolden(safeWriterGoldenLock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := pc.VendorShouldExist(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := pc.VendorFileShouldExist("github.com/sdboyer/dep-test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := pc.VendorFileShouldExist(".git/badinput_fileroot"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче