This commit is contained in:
sam boyer 2017-01-03 21:16:07 -05:00 коммит произвёл Jess Frazelle
Родитель e955d434e4
Коммит 96ea714ac2
33 изменённых файлов: 603 добавлений и 651 удалений

Просмотреть файл

@ -1,5 +1,5 @@
{ {
"memo": "47c0ec3d677d1d5c01778bc81836801e009c641797708b8fcd773dce954c7714", "memo": "56093ed07896d0d5c47ee3472d6ad16e9a7e6826598364caf01ac30dc9c277c5",
"projects": [ "projects": [
{ {
"name": "github.com/Masterminds/semver", "name": "github.com/Masterminds/semver",
@ -35,16 +35,8 @@
}, },
{ {
"name": "github.com/sdboyer/gps", "name": "github.com/sdboyer/gps",
"version": "v0.13.1",
"revision": "e4435f58dfa1aee0c5324667f5b6cbad668db8fc",
"packages": [
"."
]
},
{
"name": "github.com/termie/go-shutil",
"branch": "master", "branch": "master",
"revision": "bcacb06fecaeec8dc42af03c87c6949f4a05c74c", "revision": "b27173f3bf78a69a70dba35122ce24eb1679a53a",
"packages": [ "packages": [
"." "."
] ]

Просмотреть файл

@ -4,13 +4,13 @@
"branch": "2.x" "branch": "2.x"
}, },
"github.com/Masterminds/vcs": { "github.com/Masterminds/vcs": {
"version": ">=1.8.0, <2.0.0" "version": "^1.8.0"
}, },
"github.com/pkg/errors": { "github.com/pkg/errors": {
"version": ">=0.8.0, <1.0.0" "version": ">=0.8.0, <1.0.0"
}, },
"github.com/sdboyer/gps": { "github.com/sdboyer/gps": {
"version": ">=0.13.0, <1.0.0" "branch": "master"
} }
} }
} }

4
vendor/github.com/sdboyer/gps/README.md сгенерированный поставляемый
Просмотреть файл

@ -101,8 +101,8 @@ general library could know _a priori_.
* What dependency version constraints are declared by [all dependencies](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#the-projectanalyzer) * What dependency version constraints are declared by [all dependencies](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#the-projectanalyzer)
* Given a [previous solution](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#lock-data), [which versions to let change, and how](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#tochange-changeall-and-downgrade) * Given a [previous solution](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#lock-data), [which versions to let change, and how](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#tochange-changeall-and-downgrade)
* In the absence of a previous solution, whether or not to use [preferred versions](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#preferred-versions) * In the absence of a previous solution, whether or not to use [preferred versions](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#preferred-versions)
* Allowing, or not, the user to [swap in different network names](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#projectidentifier) for import paths (e.g. forks) * Allowing, or not, the user to [swap in different source locations](https://github.com/sdboyer/gps/wiki/gps-for-Implementors#projectidentifier) for import paths (e.g. forks)
* Specifying additional input/source packages not reachable from the root import graph ([not complete](https://github.com/sdboyer/gps/issues/42)) * Specifying additional input/source packages not reachable from the root import graph
This list may not be exhaustive - see the This list may not be exhaustive - see the
[implementor's guide](https://github.com/sdboyer/gps/wiki/gps-for-Implementors) [implementor's guide](https://github.com/sdboyer/gps/wiki/gps-for-Implementors)

8
vendor/github.com/sdboyer/gps/bridge.go сгенерированный поставляемый
Просмотреть файл

@ -361,10 +361,10 @@ func (b *bridge) SyncSourceFor(id ProjectIdentifier) error {
// operations attempt each member, and will take the most open/optimistic // operations attempt each member, and will take the most open/optimistic
// answer. // answer.
// //
// This technically does allow tags to match branches - something we // This technically does allow tags to match branches - something we otherwise
// otherwise try hard to avoid - but because the original input constraint never // try hard to avoid - but because the original input constraint never actually
// actually changes (and is never written out in the Result), there's no harmful // changes (and is never written out in the Solution), there's no harmful case
// case of a user suddenly riding a branch when they expected a fixed tag. // of a user suddenly riding a branch when they expected a fixed tag.
type versionTypeUnion []Version type versionTypeUnion []Version
// This should generally not be called, but is required for the interface. If it // This should generally not be called, but is required for the interface. If it

20
vendor/github.com/sdboyer/gps/constraints.go сгенерированный поставляемый
Просмотреть файл

@ -198,8 +198,8 @@ func pcSliceToMap(l []ProjectConstraint, r ...[]ProjectConstraint) ProjectConstr
for _, pc := range l { for _, pc := range l {
final[pc.Ident.ProjectRoot] = ProjectProperties{ final[pc.Ident.ProjectRoot] = ProjectProperties{
NetworkName: pc.Ident.NetworkName, Source: pc.Ident.Source,
Constraint: pc.Constraint, Constraint: pc.Constraint,
} }
} }
@ -213,8 +213,8 @@ func pcSliceToMap(l []ProjectConstraint, r ...[]ProjectConstraint) ProjectConstr
final[pc.Ident.ProjectRoot] = pp final[pc.Ident.ProjectRoot] = pp
} else { } else {
final[pc.Ident.ProjectRoot] = ProjectProperties{ final[pc.Ident.ProjectRoot] = ProjectProperties{
NetworkName: pc.Ident.NetworkName, Source: pc.Ident.Source,
Constraint: pc.Constraint, Constraint: pc.Constraint,
} }
} }
} }
@ -231,7 +231,7 @@ func (m ProjectConstraints) asSortedSlice() []ProjectConstraint {
pcs[k] = ProjectConstraint{ pcs[k] = ProjectConstraint{
Ident: ProjectIdentifier{ Ident: ProjectIdentifier{
ProjectRoot: pr, ProjectRoot: pr,
NetworkName: pp.NetworkName, Source: pp.Source,
}, },
Constraint: pp.Constraint, Constraint: pp.Constraint,
} }
@ -262,8 +262,8 @@ func (m ProjectConstraints) merge(other ...ProjectConstraints) (out ProjectConst
for pr, pp := range pcm { for pr, pp := range pcm {
if rpp, exists := out[pr]; exists { if rpp, exists := out[pr]; exists {
pp.Constraint = pp.Constraint.Intersect(rpp.Constraint) pp.Constraint = pp.Constraint.Intersect(rpp.Constraint)
if pp.NetworkName == "" { if pp.Source == "" {
pp.NetworkName = rpp.NetworkName pp.Source = rpp.Source
} }
} }
out[pr] = pp out[pr] = pp
@ -297,7 +297,7 @@ func (m ProjectConstraints) override(pr ProjectRoot, pp ProjectProperties) worki
wc := workingConstraint{ wc := workingConstraint{
Ident: ProjectIdentifier{ Ident: ProjectIdentifier{
ProjectRoot: pr, ProjectRoot: pr,
NetworkName: pp.NetworkName, Source: pp.Source,
}, },
Constraint: pp.Constraint, Constraint: pp.Constraint,
} }
@ -319,8 +319,8 @@ func (m ProjectConstraints) override(pr ProjectRoot, pp ProjectProperties) worki
// from. Such disagreement is exactly what overrides preclude, so // from. Such disagreement is exactly what overrides preclude, so
// there's no need to preserve the meaning of "" here - thus, we can // there's no need to preserve the meaning of "" here - thus, we can
// treat it as a zero value and ignore it, rather than applying it. // treat it as a zero value and ignore it, rather than applying it.
if opp.NetworkName != "" { if opp.Source != "" {
wc.Ident.NetworkName = opp.NetworkName wc.Ident.Source = opp.Source
wc.overrNet = true wc.overrNet = true
} }
} }

14
vendor/github.com/sdboyer/gps/hash.go сгенерированный поставляемый
Просмотреть файл

@ -26,7 +26,7 @@ func (s *solver) HashInputs() []byte {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
for _, pd := range p { for _, pd := range p {
buf.WriteString(string(pd.Ident.ProjectRoot)) buf.WriteString(string(pd.Ident.ProjectRoot))
buf.WriteString(pd.Ident.NetworkName) buf.WriteString(pd.Ident.Source)
// FIXME Constraint.String() is a surjective-only transformation - tags // FIXME Constraint.String() is a surjective-only transformation - tags
// and branches with the same name are written out as the same string. // and branches with the same name are written out as the same string.
// This could, albeit rarely, result in input collisions when a real // This could, albeit rarely, result in input collisions when a real
@ -50,10 +50,14 @@ func (s *solver) HashInputs() []byte {
buf.WriteString(perr.P.CommentPath) buf.WriteString(perr.P.CommentPath)
buf.WriteString(perr.P.ImportPath) buf.WriteString(perr.P.ImportPath)
for _, imp := range perr.P.Imports { for _, imp := range perr.P.Imports {
buf.WriteString(imp) if !isStdLib(imp) {
buf.WriteString(imp)
}
} }
for _, imp := range perr.P.TestImports { for _, imp := range perr.P.TestImports {
buf.WriteString(imp) if !isStdLib(imp) {
buf.WriteString(imp)
}
} }
} }
} }
@ -88,8 +92,8 @@ func (s *solver) HashInputs() []byte {
for _, pc := range s.ovr.asSortedSlice() { for _, pc := range s.ovr.asSortedSlice() {
buf.WriteString(string(pc.Ident.ProjectRoot)) buf.WriteString(string(pc.Ident.ProjectRoot))
if pc.Ident.NetworkName != "" { if pc.Ident.Source != "" {
buf.WriteString(pc.Ident.NetworkName) buf.WriteString(pc.Ident.Source)
} }
if pc.Constraint != nil { if pc.Constraint != nil {
buf.WriteString(pc.Constraint.String()) buf.WriteString(pc.Constraint.String())

12
vendor/github.com/sdboyer/gps/hash_test.go сгенерированный поставляемый
Просмотреть файл

@ -182,7 +182,7 @@ func TestHashInputsOverrides(t *testing.T) {
// First case - override something not in the root, just with network name // First case - override something not in the root, just with network name
rm.ovr = map[ProjectRoot]ProjectProperties{ rm.ovr = map[ProjectRoot]ProjectProperties{
"c": ProjectProperties{ "c": ProjectProperties{
NetworkName: "car", Source: "car",
}, },
} }
params := SolveParameters{ params := SolveParameters{
@ -259,8 +259,8 @@ func TestHashInputsOverrides(t *testing.T) {
// Override not in root, both constraint and network name // Override not in root, both constraint and network name
rm.ovr["e"] = ProjectProperties{ rm.ovr["e"] = ProjectProperties{
NetworkName: "groucho", Source: "groucho",
Constraint: NewBranch("plexiglass"), Constraint: NewBranch("plexiglass"),
} }
dig = s.HashInputs() dig = s.HashInputs()
h = sha256.New() h = sha256.New()
@ -334,7 +334,7 @@ func TestHashInputsOverrides(t *testing.T) {
// Override in root, only network name // Override in root, only network name
rm.ovr["a"] = ProjectProperties{ rm.ovr["a"] = ProjectProperties{
NetworkName: "nota", Source: "nota",
} }
dig = s.HashInputs() dig = s.HashInputs()
h = sha256.New() h = sha256.New()
@ -373,8 +373,8 @@ func TestHashInputsOverrides(t *testing.T) {
// Override in root, network name and constraint // Override in root, network name and constraint
rm.ovr["a"] = ProjectProperties{ rm.ovr["a"] = ProjectProperties{
NetworkName: "nota", Source: "nota",
Constraint: NewVersion("fluglehorn"), Constraint: NewVersion("fluglehorn"),
} }
dig = s.HashInputs() dig = s.HashInputs()
h = sha256.New() h = sha256.New()

69
vendor/github.com/sdboyer/gps/lock.go сгенерированный поставляемый
Просмотреть файл

@ -1,6 +1,9 @@
package gps package gps
import "sort" import (
"bytes"
"sort"
)
// Lock represents data from a lock file (or however the implementing tool // Lock represents data from a lock file (or however the implementing tool
// chooses to store it) at a particular version that is relevant to the // chooses to store it) at a particular version that is relevant to the
@ -20,6 +23,43 @@ type Lock interface {
Projects() []LockedProject Projects() []LockedProject
} }
// LocksAreEq checks if two locks are equivalent. This checks that
// all contained LockedProjects are equal, and optionally (if the third
// parameter is true) whether the locks' input hashes are equal.
func LocksAreEq(l1, l2 Lock, checkHash bool) bool {
// Cheapest ops first
if checkHash && !bytes.Equal(l1.InputHash(), l2.InputHash()) {
return false
}
p1, p2 := l1.Projects(), l2.Projects()
if len(p1) != len(p2) {
return false
}
// Check if the slices are sorted already. If they are, we can compare
// without copying. Otherwise, we have to copy to avoid altering the
// original input.
sp1, sp2 := lpsorter(p1), lpsorter(p2)
if len(p1) > 1 && !sort.IsSorted(sp1) {
p1 = make([]LockedProject, len(p1))
copy(p1, l1.Projects())
sort.Sort(lpsorter(p1))
}
if len(p2) > 1 && !sort.IsSorted(sp2) {
p2 = make([]LockedProject, len(p2))
copy(p2, l2.Projects())
sort.Sort(lpsorter(p2))
}
for k, lp := range p1 {
if !lp.Eq(p2[k]) {
return false
}
}
return true
}
// LockedProject is a single project entry from a lock file. It expresses the // LockedProject is a single project entry from a lock file. It expresses the
// project's name, one or both of version and underlying revision, the network // project's name, one or both of version and underlying revision, the network
// URI for accessing it, the path at which it should be placed within a vendor // URI for accessing it, the path at which it should be placed within a vendor
@ -107,6 +147,33 @@ func (lp LockedProject) Version() Version {
return lp.v.Is(lp.r) return lp.v.Is(lp.r)
} }
// Eq checks if two LockedProject instances are equal.
func (lp LockedProject) Eq(lp2 LockedProject) bool {
if lp.pi != lp2.pi {
return false
}
if lp.r != lp2.r {
return false
}
if len(lp.pkgs) != len(lp2.pkgs) {
return false
}
for k, v := range lp.pkgs {
if lp2.pkgs[k] != v {
return false
}
}
if !lp.v.Matches(lp2.v) {
return false
}
return true
}
// Packages returns the list of packages from within the LockedProject that are // Packages returns the list of packages from within the LockedProject that are
// actually used in the import graph. Some caveats: // actually used in the import graph. Some caveats:
// //

95
vendor/github.com/sdboyer/gps/lock_test.go сгенерированный поставляемый
Просмотреть файл

@ -24,3 +24,98 @@ func TestLockedProjectSorting(t *testing.T) {
t.Errorf("SortLockedProject did not sort as expected:\n\t(GOT) %s\n\t(WNT) %s", lps2, lps) t.Errorf("SortLockedProject did not sort as expected:\n\t(GOT) %s\n\t(WNT) %s", lps2, lps)
} }
} }
func TestLockedProjectsEq(t *testing.T) {
lps := []LockedProject{
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), []string{"gps"}),
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), nil),
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), []string{"gps", "flugle"}),
NewLockedProject(mkPI("foo"), NewVersion("nada"), []string{"foo"}),
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), []string{"flugle", "gps"}),
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0").Is("278a227dfc3d595a33a77ff3f841fd8ca1bc8cd0"), []string{"gps"}),
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.11.0"), []string{"gps"}),
}
fix := []struct {
l1, l2 int
shouldeq bool
err string
}{
{0, 0, true, "lp does not eq self"},
{0, 5, false, "should not eq with different rev"},
{0, 6, false, "should not eq with different version"},
{5, 5, true, "should eq with same rev"},
{0, 1, false, "should not eq when other pkg list is empty"},
{0, 2, false, "should not eq when other pkg list is longer"},
{2, 4, false, "should not eq when pkg lists are out of order"},
{0, 3, false, "should not eq totally different lp"},
}
for _, f := range fix {
if f.shouldeq {
if !lps[f.l1].Eq(lps[f.l2]) {
t.Error(f.err)
}
if !lps[f.l2].Eq(lps[f.l1]) {
t.Error(f.err + (" (reversed)"))
}
} else {
if lps[f.l1].Eq(lps[f.l2]) {
t.Error(f.err)
}
if lps[f.l2].Eq(lps[f.l1]) {
t.Error(f.err + (" (reversed)"))
}
}
}
}
func TestLocksAreEq(t *testing.T) {
gpl := NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0").Is("278a227dfc3d595a33a77ff3f841fd8ca1bc8cd0"), []string{"gps"})
svpl := NewLockedProject(mkPI("github.com/Masterminds/semver"), NewVersion("v2.0.0"), []string{"semver"})
bbbt := NewLockedProject(mkPI("github.com/beeblebrox/browntown"), NewBranch("master").Is("63fc17eb7966a6f4cc0b742bf42731c52c4ac740"), []string{"browntown", "smoochies"})
l1 := solution{
hd: []byte("foo"),
p: []LockedProject{
gpl,
bbbt,
svpl,
},
}
l2 := solution{
p: []LockedProject{
svpl,
gpl,
},
}
if LocksAreEq(l1, l2, true) {
t.Fatal("should have failed on hash check")
}
if LocksAreEq(l1, l2, false) {
t.Fatal("should have failed on length check")
}
l2.p = append(l2.p, bbbt)
if !LocksAreEq(l1, l2, false) {
t.Fatal("should be eq, must have failed on individual lp check")
}
// ensure original input sort order is maintained
if !l1.p[0].Eq(gpl) {
t.Error("checking equality resorted l1")
}
if !l2.p[0].Eq(svpl) {
t.Error("checking equality resorted l2")
}
l1.p[0] = NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.11.0"), []string{"gps"})
if LocksAreEq(l1, l2, false) {
t.Error("should fail when individual lp were not eq")
}
}

4
vendor/github.com/sdboyer/gps/manager_test.go сгенерированный поставляемый
Просмотреть файл

@ -358,7 +358,7 @@ func TestGetSources(t *testing.T) {
} }
// All of them _should_ select https, so this should work // All of them _should_ select https, so this should work
lpi.NetworkName = "https://" + lpi.NetworkName lpi.Source = "https://" + lpi.Source
src3, err := sm.getSourceFor(lpi) src3, err := sm.getSourceFor(lpi)
if err != nil { if err != nil {
t.Errorf("(src %q) unexpected error getting explicit https source: %s", nn, err) t.Errorf("(src %q) unexpected error getting explicit https source: %s", nn, err)
@ -367,7 +367,7 @@ func TestGetSources(t *testing.T) {
} }
// Now put in http, and they should differ // Now put in http, and they should differ
lpi.NetworkName = "http://" + string(lpi.ProjectRoot) lpi.Source = "http://" + string(lpi.ProjectRoot)
src4, err := sm.getSourceFor(lpi) src4, err := sm.getSourceFor(lpi)
if err != nil { if err != nil {
t.Errorf("(src %q) unexpected error getting explicit http source: %s", nn, err) t.Errorf("(src %q) unexpected error getting explicit http source: %s", nn, err)

4
vendor/github.com/sdboyer/gps/manifest.go сгенерированный поставляемый
Просмотреть файл

@ -158,7 +158,7 @@ func prepManifest(m Manifest) Manifest {
// normalize between these two by omitting such instances entirely, as // normalize between these two by omitting such instances entirely, as
// it negates some possibility for false mismatches in input hashing. // it negates some possibility for false mismatches in input hashing.
if d.Constraint == nil { if d.Constraint == nil {
if d.NetworkName == "" { if d.Source == "" {
continue continue
} }
d.Constraint = anyConstraint{} d.Constraint = anyConstraint{}
@ -169,7 +169,7 @@ func prepManifest(m Manifest) Manifest {
for k, d := range ddeps { for k, d := range ddeps {
if d.Constraint == nil { if d.Constraint == nil {
if d.NetworkName == "" { if d.Source == "" {
continue continue
} }
d.Constraint = anyConstraint{} d.Constraint = anyConstraint{}

4
vendor/github.com/sdboyer/gps/manifest_test.go сгенерированный поставляемый
Просмотреть файл

@ -8,13 +8,13 @@ func TestPrepManifest(t *testing.T) {
Deps: ProjectConstraints{ Deps: ProjectConstraints{
ProjectRoot("foo"): ProjectProperties{}, ProjectRoot("foo"): ProjectProperties{},
ProjectRoot("bar"): ProjectProperties{ ProjectRoot("bar"): ProjectProperties{
NetworkName: "whatever", Source: "whatever",
}, },
}, },
TestDeps: ProjectConstraints{ TestDeps: ProjectConstraints{
ProjectRoot("baz"): ProjectProperties{}, ProjectRoot("baz"): ProjectProperties{},
ProjectRoot("qux"): ProjectProperties{ ProjectRoot("qux"): ProjectProperties{
NetworkName: "whatever", Source: "whatever",
}, },
}, },
} }

18
vendor/github.com/sdboyer/gps/maybe_source.go сгенерированный поставляемый
Просмотреть файл

@ -82,10 +82,11 @@ func (m maybeGitSource) try(cachedir string, an ProjectAnalyzer) (source, string
} }
src.baseVCSSource.lvfunc = src.listVersions src.baseVCSSource.lvfunc = src.listVersions
if !r.CheckLocal() {
_, err = src.listVersions() _, err = src.listVersions()
if err != nil { if err != nil {
return nil, "", err return nil, "", err
}
} }
return src, ustr, nil return src, ustr, nil
@ -129,10 +130,11 @@ func (m maybeGopkginSource) try(cachedir string, an ProjectAnalyzer) (source, st
} }
src.baseVCSSource.lvfunc = src.listVersions src.baseVCSSource.lvfunc = src.listVersions
if !r.CheckLocal() {
_, err = src.listVersions() _, err = src.listVersions()
if err != nil { if err != nil {
return nil, "", err return nil, "", err
}
} }
return src, ustr, nil return src, ustr, nil

4
vendor/github.com/sdboyer/gps/satisfy.go сгенерированный поставляемый
Просмотреть файл

@ -195,8 +195,8 @@ func (s *solver) checkDepsDisallowsSelected(a atomWithPackages, cdep completeDep
} }
// checkIdentMatches ensures that the LocalName of a dep introduced by an atom, // checkIdentMatches ensures that the LocalName of a dep introduced by an atom,
// has the same NetworkName as what's already been selected (assuming anything's // has the same Source as what's already been selected (assuming anything's been
// been selected). // selected).
// //
// In other words, this ensures that the solver never simultaneously selects two // In other words, this ensures that the solver never simultaneously selects two
// identifiers with the same local name, but that disagree about where their // identifiers with the same local name, but that disagree about where their

12
vendor/github.com/sdboyer/gps/solve_basic_test.go сгенерированный поставляемый
Просмотреть файл

@ -19,7 +19,7 @@ func nvSplit(info string) (id ProjectIdentifier, version string) {
if strings.Contains(info, " from ") { if strings.Contains(info, " from ") {
parts := regfrom.FindStringSubmatch(info) parts := regfrom.FindStringSubmatch(info)
info = parts[1] + " " + parts[3] info = parts[1] + " " + parts[3]
id.NetworkName = parts[2] id.Source = parts[2]
} }
s := strings.SplitN(info, " ", 2) s := strings.SplitN(info, " ", 2)
@ -42,7 +42,7 @@ func nvrSplit(info string) (id ProjectIdentifier, version string, revision Revis
if strings.Contains(info, " from ") { if strings.Contains(info, " from ") {
parts := regfrom.FindStringSubmatch(info) parts := regfrom.FindStringSubmatch(info)
info = fmt.Sprintf("%s %s", parts[1], parts[3]) info = fmt.Sprintf("%s %s", parts[1], parts[3])
id.NetworkName = parts[2] id.Source = parts[2]
} }
s := strings.SplitN(info, " ", 3) s := strings.SplitN(info, " ", 3)
@ -205,7 +205,7 @@ type depspec struct {
// treated as a test-only dependency. // treated as a test-only dependency.
func mkDepspec(pi string, deps ...string) depspec { func mkDepspec(pi string, deps ...string) depspec {
pa := mkAtom(pi) pa := mkAtom(pi)
if string(pa.id.ProjectRoot) != pa.id.NetworkName && pa.id.NetworkName != "" { if string(pa.id.ProjectRoot) != pa.id.Source && pa.id.Source != "" {
panic("alternate source on self makes no sense") panic("alternate source on self makes no sense")
} }
@ -252,9 +252,9 @@ func mkADep(atom, pdep string, c Constraint, pl ...string) dependency {
} }
// mkPI creates a ProjectIdentifier with the ProjectRoot as the provided // mkPI creates a ProjectIdentifier with the ProjectRoot as the provided
// string, and the NetworkName unset. // string, and the Source unset.
// //
// Call normalize() on the returned value if you need the NetworkName to be be // Call normalize() on the returned value if you need the Source to be be
// equal to the ProjectRoot. // equal to the ProjectRoot.
func mkPI(root string) ProjectIdentifier { func mkPI(root string) ProjectIdentifier {
return ProjectIdentifier{ return ProjectIdentifier{
@ -1274,7 +1274,7 @@ var basicFixtures = map[string]basicFixture{
}, },
ovr: ProjectConstraints{ ovr: ProjectConstraints{
ProjectRoot("bar"): ProjectProperties{ ProjectRoot("bar"): ProjectProperties{
NetworkName: "bar", Source: "bar",
}, },
}, },
r: mksolution( r: mksolution(

6
vendor/github.com/sdboyer/gps/solve_bimodal_test.go сгенерированный поставляемый
Просмотреть файл

@ -640,7 +640,7 @@ var bimodalFixtures = map[string]bimodalFixture{
), ),
}, },
// When a given project is initially brought in using the default (i.e., // When a given project is initially brought in using the default (i.e.,
// empty) ProjectIdentifier.NetworkName, and a later, presumably // empty) ProjectIdentifier.Source, and a later, presumably
// as-yet-undiscovered dependency specifies an alternate net addr for it, we // as-yet-undiscovered dependency specifies an alternate net addr for it, we
// have to fail - even though, if the deps were visited in the opposite // have to fail - even though, if the deps were visited in the opposite
// order (deeper dep w/the alternate location first, default location // order (deeper dep w/the alternate location first, default location
@ -719,7 +719,7 @@ var bimodalFixtures = map[string]bimodalFixture{
}, },
ovr: ProjectConstraints{ ovr: ProjectConstraints{
ProjectRoot("bar"): ProjectProperties{ ProjectRoot("bar"): ProjectProperties{
NetworkName: "baz", Source: "baz",
}, },
}, },
r: mksolution( r: mksolution(
@ -740,7 +740,7 @@ var bimodalFixtures = map[string]bimodalFixture{
}, },
ovr: ProjectConstraints{ ovr: ProjectConstraints{
ProjectRoot("bar"): ProjectProperties{ ProjectRoot("bar"): ProjectProperties{
NetworkName: "baz", Source: "baz",
}, },
}, },
r: mksolution( r: mksolution(

6
vendor/github.com/sdboyer/gps/solve_test.go сгенерированный поставляемый
Просмотреть файл

@ -167,11 +167,11 @@ func solveBimodalAndCheck(fix bimodalFixture, t *testing.T) (res Solution, err e
func fixtureSolveSimpleChecks(fix specfix, soln Solution, err error, t *testing.T) (Solution, error) { func fixtureSolveSimpleChecks(fix specfix, soln Solution, err error, t *testing.T) (Solution, error) {
ppi := func(id ProjectIdentifier) string { ppi := func(id ProjectIdentifier) string {
// need this so we can clearly tell if there's a NetworkName or not // need this so we can clearly tell if there's a Source or not
if id.NetworkName == "" { if id.Source == "" {
return string(id.ProjectRoot) return string(id.ProjectRoot)
} }
return fmt.Sprintf("%s (from %s)", id.ProjectRoot, id.NetworkName) return fmt.Sprintf("%s (from %s)", id.ProjectRoot, id.Source)
} }
pv := func(v Version) string { pv := func(v Version) string {

35
vendor/github.com/sdboyer/gps/solver.go сгенерированный поставляемый
Просмотреть файл

@ -252,7 +252,7 @@ func Prepare(params SolveParameters, sm SourceManager) (Solver, error) {
// Validate no empties in the overrides map // Validate no empties in the overrides map
var eovr []string var eovr []string
for pr, pp := range s.ovr { for pr, pp := range s.ovr {
if pp.Constraint == nil && pp.NetworkName == "" { if pp.Constraint == nil && pp.Source == "" {
eovr = append(eovr, string(pr)) eovr = append(eovr, string(pr))
} }
} }
@ -537,7 +537,7 @@ func (s *solver) selectRoot() error {
// If we have no lock, or if this dep isn't in the lock, then prefetch // If we have no lock, or if this dep isn't in the lock, then prefetch
// it. See longer explanation in selectAtom() for how we benefit from // it. See longer explanation in selectAtom() for how we benefit from
// parallelism here. // parallelism here.
if _, has := s.rlm[dep.Ident.ProjectRoot]; !has { if s.needVersionsFor(dep.Ident.ProjectRoot) {
go s.b.SyncSourceFor(dep.Ident) go s.b.SyncSourceFor(dep.Ident)
} }
@ -696,8 +696,8 @@ func (s *solver) createVersionQueue(bmi bimodalIdentifier) (*versionQueue, error
return nil, err return nil, err
} }
if exists { if exists {
// Project exists only in vendor (and in some manifest somewhere) // Project exists only in vendor
// TODO(sdboyer) mark this for special handling, somehow? // FIXME(sdboyer) this just totally doesn't work at all right now
} else { } else {
return nil, fmt.Errorf("project '%s' could not be located", id) return nil, fmt.Errorf("project '%s' could not be located", id)
} }
@ -922,6 +922,29 @@ func (s *solver) getLockVersionIfValid(id ProjectIdentifier) (Version, error) {
return v, nil return v, nil
} }
// needVersionListFor indicates whether we need a version list for a given
// project root, based solely on general solver inputs (no constraint checking
// required). This will be true if:
//
// - ChangeAll is on
// - The project is not in the lock at all
// - The project is in the lock, but is also in the list of projects to change
func (s *solver) needVersionsFor(pr ProjectRoot) bool {
if s.params.ChangeAll {
return true
}
if _, has := s.rlm[pr]; !has {
// not in the lock
return true
} else if _, has := s.chng[pr]; has {
// in the lock, but marked for change
return true
}
// in the lock, not marked for change
return false
}
// backtrack works backwards from the current failed solution to find the next // backtrack works backwards from the current failed solution to find the next
// solution to try. // solution to try.
func (s *solver) backtrack() bool { func (s *solver) backtrack() bool {
@ -1144,13 +1167,13 @@ func (s *solver) selectAtom(a atomWithPackages, pkgonly bool) {
// few microseconds before blocking later. Best case, the dep doesn't // few microseconds before blocking later. Best case, the dep doesn't
// come up next, but some other dep comes up that wasn't prefetched, and // come up next, but some other dep comes up that wasn't prefetched, and
// both fetches proceed in parallel. // both fetches proceed in parallel.
if _, has := s.rlm[dep.Ident.ProjectRoot]; !has { if s.needVersionsFor(dep.Ident.ProjectRoot) {
go s.b.SyncSourceFor(dep.Ident) go s.b.SyncSourceFor(dep.Ident)
} }
s.sel.pushDep(dependency{depender: a.a, dep: dep}) s.sel.pushDep(dependency{depender: a.a, dep: dep})
// Go through all the packages introduced on this dep, selecting only // Go through all the packages introduced on this dep, selecting only
// the ones where the only depper on them is what the previous line just // the ones where the only depper on them is what the preceding line just
// pushed in. Then, put those into the unselected queue. // pushed in. Then, put those into the unselected queue.
rpm := s.sel.getRequiredPackagesIn(dep.Ident) rpm := s.sel.getRequiredPackagesIn(dep.Ident)
var newp []string var newp []string

35
vendor/github.com/sdboyer/gps/source.go сгенерированный поставляемый
Просмотреть файл

@ -97,23 +97,30 @@ func (bs *baseVCSSource) getManifestAndLock(r ProjectRoot, v Version) (Manifest,
} }
// Cache didn't help; ensure our local is fully up to date. // Cache didn't help; ensure our local is fully up to date.
err = bs.syncLocal() do := func() (err error) {
if err != nil { bs.crepo.mut.Lock()
return nil, nil, err // Always prefer a rev, if it's available
if pv, ok := v.(PairedVersion); ok {
err = bs.crepo.r.UpdateVersion(pv.Underlying().String())
} else {
err = bs.crepo.r.UpdateVersion(v.String())
}
bs.crepo.mut.Unlock()
return
} }
bs.crepo.mut.Lock() if err = do(); err != nil {
// Always prefer a rev, if it's available // minimize network activity: only force local syncing if we had an err
if pv, ok := v.(PairedVersion); ok { err = bs.syncLocal()
err = bs.crepo.r.UpdateVersion(pv.Underlying().String()) if err != nil {
} else { return nil, nil, err
err = bs.crepo.r.UpdateVersion(v.String()) }
}
bs.crepo.mut.Unlock()
if err != nil { if err = do(); err != nil {
// TODO(sdboyer) More-er proper-er error // TODO(sdboyer) More-er proper-er error
panic(fmt.Sprintf("canary - why is checkout/whatever failing: %s %s %s", bs.crepo.r.LocalPath(), v.String(), unwrapVcsErr(err))) panic(fmt.Sprintf("canary - why is checkout/whatever failing: %s %s %s", bs.crepo.r.LocalPath(), v.String(), unwrapVcsErr(err)))
}
} }
bs.crepo.mut.RLock() bs.crepo.mut.RLock()

1
vendor/github.com/sdboyer/gps/source_manager.go сгенерированный поставляемый
Просмотреть файл

@ -305,7 +305,6 @@ func (sm *SourceMgr) DeduceProjectRoot(ip string) (ProjectRoot, error) {
} }
func (sm *SourceMgr) getSourceFor(id ProjectIdentifier) (source, error) { func (sm *SourceMgr) getSourceFor(id ProjectIdentifier) (source, error) {
//pretty.Println(id.ProjectRoot)
nn := id.netName() nn := id.netName()
sm.srcmut.RLock() sm.srcmut.RLock()

46
vendor/github.com/sdboyer/gps/types.go сгенерированный поставляемый
Просмотреть файл

@ -44,10 +44,10 @@ type ProjectRoot string
// ProjectRoot. In gps' current design, this ProjectRoot almost always // ProjectRoot. In gps' current design, this ProjectRoot almost always
// corresponds to the root of a repository. // corresponds to the root of a repository.
// //
// Second, ProjectIdentifiers can optionally carry a NetworkName, which // Second, ProjectIdentifiers can optionally carry a Source, which
// identifies where the underlying source code can be located on the network. // identifies where the underlying source code can be located on the network.
// These can be either a full URL, including protocol, or plain import paths. // These can be either a full URL, including protocol, or plain import paths.
// So, these are all valid data for NetworkName: // So, these are all valid data for Source:
// //
// github.com/sdboyer/gps // github.com/sdboyer/gps
// github.com/fork/gps // github.com/fork/gps
@ -61,19 +61,19 @@ type ProjectRoot string
// //
// Note that gps makes no guarantees about the actual import paths contained in // Note that gps makes no guarantees about the actual import paths contained in
// a repository aligning with ImportRoot. If tools, or their users, specify an // a repository aligning with ImportRoot. If tools, or their users, specify an
// alternate NetworkName that contains a repository with incompatible internal // alternate Source that contains a repository with incompatible internal
// import paths, gps' solving operations will error. (gps does no import // import paths, gps' solving operations will error. (gps does no import
// rewriting.) // rewriting.)
// //
// Also note that if different projects' manifests report a different // Also note that if different projects' manifests report a different
// NetworkName for a given ImportRoot, it is a solve failure. Everyone has to // Source for a given ImportRoot, it is a solve failure. Everyone has to
// agree on where a given import path should be sourced from. // agree on where a given import path should be sourced from.
// //
// If NetworkName is not explicitly set, gps will derive the network address from // If Source is not explicitly set, gps will derive the network address from
// the ImportRoot using a similar algorithm to that utilized by `go get`. // the ImportRoot using a similar algorithm to that utilized by `go get`.
type ProjectIdentifier struct { type ProjectIdentifier struct {
ProjectRoot ProjectRoot ProjectRoot ProjectRoot
NetworkName string Source string
} }
func (i ProjectIdentifier) less(j ProjectIdentifier) bool { func (i ProjectIdentifier) less(j ProjectIdentifier) bool {
@ -91,12 +91,12 @@ func (i ProjectIdentifier) eq(j ProjectIdentifier) bool {
if i.ProjectRoot != j.ProjectRoot { if i.ProjectRoot != j.ProjectRoot {
return false return false
} }
if i.NetworkName == j.NetworkName { if i.Source == j.Source {
return true return true
} }
if (i.NetworkName == "" && j.NetworkName == string(j.ProjectRoot)) || if (i.Source == "" && j.Source == string(j.ProjectRoot)) ||
(j.NetworkName == "" && i.NetworkName == string(i.ProjectRoot)) { (j.Source == "" && i.Source == string(i.ProjectRoot)) {
return true return true
} }
@ -108,22 +108,22 @@ func (i ProjectIdentifier) eq(j ProjectIdentifier) bool {
// //
// Given that the ProjectRoots are equal (==), equivalency occurs if: // Given that the ProjectRoots are equal (==), equivalency occurs if:
// //
// 1. The NetworkNames are equal (==), OR // 1. The Sources are equal (==), OR
// 2. The LEFT (the receiver) NetworkName is non-empty, and the right // 2. The LEFT (the receiver) Source is non-empty, and the right
// NetworkName is empty. // Source is empty.
// //
// *This is asymmetry in this binary relation is intentional.* It facilitates // *This is asymmetry in this binary relation is intentional.* It facilitates
// the case where we allow for a ProjectIdentifier with an explicit NetworkName // the case where we allow for a ProjectIdentifier with an explicit Source
// to match one without. // to match one without.
func (i ProjectIdentifier) equiv(j ProjectIdentifier) bool { func (i ProjectIdentifier) equiv(j ProjectIdentifier) bool {
if i.ProjectRoot != j.ProjectRoot { if i.ProjectRoot != j.ProjectRoot {
return false return false
} }
if i.NetworkName == j.NetworkName { if i.Source == j.Source {
return true return true
} }
if i.NetworkName != "" && j.NetworkName == "" { if i.Source != "" && j.Source == "" {
return true return true
} }
@ -131,22 +131,22 @@ func (i ProjectIdentifier) equiv(j ProjectIdentifier) bool {
} }
func (i ProjectIdentifier) netName() string { func (i ProjectIdentifier) netName() string {
if i.NetworkName == "" { if i.Source == "" {
return string(i.ProjectRoot) return string(i.ProjectRoot)
} }
return i.NetworkName return i.Source
} }
func (i ProjectIdentifier) errString() string { func (i ProjectIdentifier) errString() string {
if i.NetworkName == "" || i.NetworkName == string(i.ProjectRoot) { if i.Source == "" || i.Source == string(i.ProjectRoot) {
return string(i.ProjectRoot) return string(i.ProjectRoot)
} }
return fmt.Sprintf("%s (from %s)", i.ProjectRoot, i.NetworkName) return fmt.Sprintf("%s (from %s)", i.ProjectRoot, i.Source)
} }
func (i ProjectIdentifier) normalize() ProjectIdentifier { func (i ProjectIdentifier) normalize() ProjectIdentifier {
if i.NetworkName == "" { if i.Source == "" {
i.NetworkName = string(i.ProjectRoot) i.Source = string(i.ProjectRoot)
} }
return i return i
@ -159,8 +159,8 @@ func (i ProjectIdentifier) normalize() ProjectIdentifier {
// ProjectProperties; they make little sense without their corresponding // ProjectProperties; they make little sense without their corresponding
// ProjectRoot. // ProjectRoot.
type ProjectProperties struct { type ProjectProperties struct {
NetworkName string Source string
Constraint Constraint Constraint Constraint
} }
// Package represents a Go package. It contains a subset of the information // Package represents a Go package. It contains a subset of the information

165
vendor/github.com/sdboyer/gps/util.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,165 @@
package gps
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"syscall"
)
// renameWithFallback attempts to rename a file or directory, but falls back to
// copying in the event of a cross-link device error. If the fallback copy
// succeeds, src is still removed, emulating normal rename behavior.
func renameWithFallback(src, dest string) error {
fi, err := os.Stat(src)
if err != nil {
return err
}
err = os.Rename(src, dest)
if err == nil {
return nil
}
terr, ok := err.(*os.LinkError)
if !ok {
return err
}
// Rename may fail if src and dest are on different devices; fall back to
// copy if we detect that case. syscall.EXDEV is the common name for the
// cross device link error which has varying output text across different
// operating systems.
var cerr error
if terr.Err == syscall.EXDEV {
if fi.IsDir() {
cerr = copyDir(src, dest)
} else {
cerr = copyFile(src, dest)
}
} else if runtime.GOOS == "windows" {
// In windows it can drop down to an operating system call that
// returns an operating system error with a different number and
// message. Checking for that as a fall back.
noerr, ok := terr.Err.(syscall.Errno)
// 0x11 (ERROR_NOT_SAME_DEVICE) is the windows error.
// See https://msdn.microsoft.com/en-us/library/cc231199.aspx
if ok && noerr == 0x11 {
if fi.IsDir() {
cerr = copyDir(src, dest)
} else {
cerr = copyFile(src, dest)
}
}
} else {
return terr
}
if cerr != nil {
return cerr
}
return os.RemoveAll(src)
}
// copyDir recursively copies a directory tree, attempting to preserve permissions.
// Source directory must exist, destination directory must *not* exist.
// Symlinks are ignored and skipped.
func copyDir(src string, dst string) (err error) {
src = filepath.Clean(src)
dst = filepath.Clean(dst)
si, err := os.Stat(src)
if err != nil {
return err
}
if !si.IsDir() {
return fmt.Errorf("source is not a directory")
}
_, err = os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
return
}
if err == nil {
return fmt.Errorf("destination already exists")
}
err = os.MkdirAll(dst, si.Mode())
if err != nil {
return
}
entries, err := ioutil.ReadDir(src)
if err != nil {
return
}
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
err = copyDir(srcPath, dstPath)
if err != nil {
return
}
} else {
// This will include symlinks, which is what we want in all cases
// where gps is copying things.
err = copyFile(srcPath, dstPath)
if err != nil {
return
}
}
}
return
}
// copyFile copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file. The file mode will be copied from the source and
// the copied data is synced/flushed to stable storage.
func copyFile(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
if e := out.Close(); e != nil {
err = e
}
}()
_, err = io.Copy(out, in)
if err != nil {
return
}
err = out.Sync()
if err != nil {
return
}
si, err := os.Stat(src)
if err != nil {
return
}
err = os.Chmod(dst, si.Mode())
if err != nil {
return
}
return
}

131
vendor/github.com/sdboyer/gps/util_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,131 @@
package gps
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func isDir(name string) (bool, error) {
fi, err := os.Stat(name)
if os.IsNotExist(err) {
return false, nil
}
if err != nil {
return false, err
}
if !fi.IsDir() {
return false, fmt.Errorf("%q is not a directory", name)
}
return true, nil
}
func TestCopyDir(t *testing.T) {
dir, err := ioutil.TempDir("", "gps")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
srcdir := filepath.Join(dir, "src")
if err := os.MkdirAll(srcdir, 0755); err != nil {
t.Fatal(err)
}
srcf, err := os.Create(filepath.Join(srcdir, "myfile"))
if err != nil {
t.Fatal(err)
}
contents := "hello world"
if _, err := srcf.Write([]byte(contents)); err != nil {
t.Fatal(err)
}
srcf.Close()
destdir := filepath.Join(dir, "dest")
if err := copyDir(srcdir, destdir); err != nil {
t.Fatal(err)
}
dirOK, err := isDir(destdir)
if err != nil {
t.Fatal(err)
}
if !dirOK {
t.Fatalf("expected %s to be a directory", destdir)
}
destf := filepath.Join(destdir, "myfile")
destcontents, err := ioutil.ReadFile(destf)
if err != nil {
t.Fatal(err)
}
if contents != string(destcontents) {
t.Fatalf("expected: %s, got: %s", contents, string(destcontents))
}
srcinfo, err := os.Stat(srcf.Name())
if err != nil {
t.Fatal(err)
}
destinfo, err := os.Stat(destf)
if err != nil {
t.Fatal(err)
}
if srcinfo.Mode() != destinfo.Mode() {
t.Fatalf("expected %s: %#v\n to be the same mode as %s: %#v", srcf.Name(), srcinfo.Mode(), destf, destinfo.Mode())
}
}
func TestCopyFile(t *testing.T) {
dir, err := ioutil.TempDir("", "gps")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
srcf, err := os.Create(filepath.Join(dir, "srcfile"))
if err != nil {
t.Fatal(err)
}
contents := "hello world"
if _, err := srcf.Write([]byte(contents)); err != nil {
t.Fatal(err)
}
srcf.Close()
destf := filepath.Join(dir, "destf")
if err := copyFile(srcf.Name(), destf); err != nil {
t.Fatal(err)
}
destcontents, err := ioutil.ReadFile(destf)
if err != nil {
t.Fatal(err)
}
if contents != string(destcontents) {
t.Fatalf("expected: %s, got: %s", contents, string(destcontents))
}
srcinfo, err := os.Stat(srcf.Name())
if err != nil {
t.Fatal(err)
}
destinfo, err := os.Stat(destf)
if err != nil {
t.Fatal(err)
}
if srcinfo.Mode() != destinfo.Mode() {
t.Fatalf("expected %s: %#v\n to be the same mode as %s: %#v", srcf.Name(), srcinfo.Mode(), destf, destinfo.Mode())
}
}

33
vendor/github.com/sdboyer/gps/vcs_source.go сгенерированный поставляемый
Просмотреть файл

@ -11,7 +11,6 @@ import (
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/Masterminds/vcs" "github.com/Masterminds/vcs"
"github.com/termie/go-shutil"
) )
// Kept here as a reference in case it does become important to implement a // Kept here as a reference in case it does become important to implement a
@ -47,13 +46,13 @@ func (s *gitSource) exportVersionTo(v Version, to string) error {
// Back up original index // Back up original index
idx, bak := filepath.Join(r.LocalPath(), ".git", "index"), filepath.Join(r.LocalPath(), ".git", "origindex") idx, bak := filepath.Join(r.LocalPath(), ".git", "index"), filepath.Join(r.LocalPath(), ".git", "origindex")
err := os.Rename(idx, bak) err := renameWithFallback(idx, bak)
if err != nil { if err != nil {
return err return err
} }
// could have an err here...but it's hard to imagine how? // could have an err here...but it's hard to imagine how?
defer os.Rename(bak, idx) defer renameWithFallback(bak, idx)
vstr := v.String() vstr := v.String()
if rv, ok := v.(PairedVersion); ok { if rv, ok := v.(PairedVersion); ok {
@ -635,30 +634,10 @@ func (r *repo) exportVersionTo(v Version, to string) error {
r.r.UpdateVersion(v.String()) r.r.UpdateVersion(v.String())
// TODO(sdboyer) This is a dumb, slow approach, but we're punting on making // TODO(sdboyer) this is a simplistic approach and relying on the tools
// these fast for now because git is the OVERWHELMING case (it's handled in // themselves might make it faster, but git's the overwhelming case (and has
// its own method) // its own method) so fine for now
return copyDir(r.rpath, to)
cfg := &shutil.CopyTreeOptions{
Symlinks: true,
CopyFunction: shutil.Copy,
Ignore: func(src string, contents []os.FileInfo) (ignore []string) {
for _, fi := range contents {
if !fi.IsDir() {
continue
}
n := fi.Name()
switch n {
case "vendor", ".bzr", ".svn", ".hg":
ignore = append(ignore, n)
}
}
return
},
}
return shutil.CopyTree(r.rpath, to, cfg)
} }
// This func copied from Masterminds/vcs so we can exec our own commands // This func copied from Masterminds/vcs so we can exec our own commands

1
vendor/github.com/termie/go-shutil/.gitignore сгенерированный поставляемый
Просмотреть файл

@ -1 +0,0 @@
test/testfile3

1
vendor/github.com/termie/go-shutil/LICENSE сгенерированный поставляемый
Просмотреть файл

@ -1 +0,0 @@
I guess Python's? If that doesn't apply then MIT. Have fun.

24
vendor/github.com/termie/go-shutil/README.rst сгенерированный поставляемый
Просмотреть файл

@ -1,24 +0,0 @@
=========================================
High-level Filesystem Operations (for Go)
=========================================
A direct port of a few of the functions from Python's shutil package for
high-level filesystem operations.
This project pretty much only exists so that other people don't have to keep
re-writing this code in their projects, at this time we have been unable to
find any helpful packages for this in the stdlib or elsewhere.
We don't expect it to be perfect, just better than whatever your first draft
would have been. Patches welcome.
See also: https://docs.python.org/3.5/library/shutil.html
================
Functions So Far
================
We support Copy, CopyFile, CopyMode, and CopyTree. CopyStat would be nice if
anybody wants to write that. Also the other functions that might be useful in
the python library :D

326
vendor/github.com/termie/go-shutil/shutil.go сгенерированный поставляемый
Просмотреть файл

@ -1,326 +0,0 @@
package shutil
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
)
type SameFileError struct {
Src string
Dst string
}
func (e SameFileError) Error() string {
return fmt.Sprintf("%s and %s are the same file", e.Src, e.Dst)
}
type SpecialFileError struct {
File string
FileInfo os.FileInfo
}
func (e SpecialFileError) Error() string {
return fmt.Sprintf("`%s` is a named pipe", e.File)
}
type NotADirectoryError struct {
Src string
}
func (e NotADirectoryError) Error() string {
return fmt.Sprintf("`%s` is not a directory", e.Src)
}
type AlreadyExistsError struct {
Dst string
}
func (e AlreadyExistsError) Error() string {
return fmt.Sprintf("`%s` already exists", e.Dst)
}
func samefile(src string, dst string) bool {
srcInfo, _ := os.Stat(src)
dstInfo, _ := os.Stat(dst)
return os.SameFile(srcInfo, dstInfo)
}
func specialfile(fi os.FileInfo) bool {
return (fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe
}
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
func IsSymlink(fi os.FileInfo) bool {
return (fi.Mode() & os.ModeSymlink) == os.ModeSymlink
}
// Copy data from src to dst
//
// If followSymlinks is not set and src is a symbolic link, a
// new symlink will be created instead of copying the file it points
// to.
func CopyFile(src, dst string, followSymlinks bool) (error) {
if samefile(src, dst) {
return &SameFileError{src, dst}
}
// Make sure src exists and neither are special files
srcStat, err := os.Lstat(src)
if err != nil {
return err
}
if specialfile(srcStat) {
return &SpecialFileError{src, srcStat}
}
dstStat, err := os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
return err
} else if err == nil {
if specialfile(dstStat) {
return &SpecialFileError{dst, dstStat}
}
}
// If we don't follow symlinks and it's a symlink, just link it and be done
if !followSymlinks && IsSymlink(srcStat) {
return os.Symlink(src, dst)
}
// If we are a symlink, follow it
if IsSymlink(srcStat) {
src, err = os.Readlink(src)
if err != nil {
return err
}
srcStat, err = os.Stat(src)
if err != nil {
return err
}
}
// Do the actual copy
fsrc, err := os.Open(src)
if err != nil {
return err
}
defer fsrc.Close()
fdst, err := os.Create(dst)
if err != nil {
return err
}
defer fdst.Close()
size, err := io.Copy(fdst, fsrc)
if err != nil {
return err
}
if size != srcStat.Size() {
return fmt.Errorf("%s: %d/%d copied", src, size, srcStat.Size())
}
return nil
}
// Copy mode bits from src to dst.
//
// If followSymlinks is false, symlinks aren't followed if and only
// if both `src` and `dst` are symlinks. If `lchmod` isn't available
// and both are symlinks this does nothing. (I don't think lchmod is
// available in Go)
func CopyMode(src, dst string, followSymlinks bool) error {
srcStat, err := os.Lstat(src)
if err != nil {
return err
}
dstStat, err := os.Lstat(dst)
if err != nil {
return err
}
// They are both symlinks and we can't change mode on symlinks.
if !followSymlinks && IsSymlink(srcStat) && IsSymlink(dstStat) {
return nil
}
// Atleast one is not a symlink, get the actual file stats
srcStat, _ = os.Stat(src)
err = os.Chmod(dst, srcStat.Mode())
return err
}
// Copy data and mode bits ("cp src dst"). Return the file's destination.
//
// The destination may be a directory.
//
// If followSymlinks is false, symlinks won't be followed. This
// resembles GNU's "cp -P src dst".
//
// If source and destination are the same file, a SameFileError will be
// rased.
func Copy(src, dst string, followSymlinks bool) (string, error){
dstInfo, err := os.Stat(dst)
if err == nil && dstInfo.Mode().IsDir() {
dst = filepath.Join(dst, filepath.Base(src))
}
if err != nil && !os.IsNotExist(err) {
return dst, err
}
err = CopyFile(src, dst, followSymlinks)
if err != nil {
return dst, err
}
err = CopyMode(src, dst, followSymlinks)
if err != nil {
return dst, err
}
return dst, nil
}
type CopyTreeOptions struct {
Symlinks bool
IgnoreDanglingSymlinks bool
CopyFunction func (string, string, bool) (string, error)
Ignore func (string, []os.FileInfo) []string
}
// Recursively copy a directory tree.
//
// The destination directory must not already exist.
//
// If the optional Symlinks flag is true, symbolic links in the
// source tree result in symbolic links in the destination tree; if
// it is false, the contents of the files pointed to by symbolic
// links are copied. If the file pointed by the symlink doesn't
// exist, an error will be returned.
//
// You can set the optional IgnoreDanglingSymlinks flag to true if you
// want to silence this error. Notice that this has no effect on
// platforms that don't support os.Symlink.
//
// The optional ignore argument is a callable. If given, it
// is called with the `src` parameter, which is the directory
// being visited by CopyTree(), and `names` which is the list of
// `src` contents, as returned by ioutil.ReadDir():
//
// callable(src, entries) -> ignoredNames
//
// Since CopyTree() is called recursively, the callable will be
// called once for each directory that is copied. It returns a
// list of names relative to the `src` directory that should
// not be copied.
//
// The optional copyFunction argument is a callable that will be used
// to copy each file. It will be called with the source path and the
// destination path as arguments. By default, Copy() is used, but any
// function that supports the same signature (like Copy2() when it
// exists) can be used.
func CopyTree(src, dst string, options *CopyTreeOptions) error {
if options == nil {
options = &CopyTreeOptions{Symlinks:false,
Ignore:nil,
CopyFunction:Copy,
IgnoreDanglingSymlinks:false}
}
srcFileInfo, err := os.Stat(src)
if err != nil {
return err
}
if !srcFileInfo.IsDir() {
return &NotADirectoryError{src}
}
_, err = os.Open(dst)
if !os.IsNotExist(err) {
return &AlreadyExistsError{dst}
}
entries, err := ioutil.ReadDir(src)
if err != nil {
return err
}
err = os.MkdirAll(dst, srcFileInfo.Mode())
if err != nil {
return err
}
ignoredNames := []string{}
if options.Ignore != nil {
ignoredNames = options.Ignore(src, entries)
}
for _, entry := range entries {
if stringInSlice(entry.Name(), ignoredNames) {
continue
}
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
entryFileInfo, err := os.Lstat(srcPath)
if err != nil {
return err
}
// Deal with symlinks
if IsSymlink(entryFileInfo) {
linkTo, err := os.Readlink(srcPath)
if err != nil {
return err
}
if options.Symlinks {
os.Symlink(linkTo, dstPath)
//CopyStat(srcPath, dstPath, false)
} else {
// ignore dangling symlink if flag is on
_, err = os.Stat(linkTo)
if os.IsNotExist(err) && options.IgnoreDanglingSymlinks {
continue
}
_, err = options.CopyFunction(srcPath, dstPath, false)
if err != nil {
return err
}
}
} else if entryFileInfo.IsDir() {
err = CopyTree(srcPath, dstPath, options)
if err != nil {
return err
}
} else {
_, err = options.CopyFunction(srcPath, dstPath, false)
if err != nil {
return err
}
}
}
return nil
}

156
vendor/github.com/termie/go-shutil/shutil_test.go сгенерированный поставляемый
Просмотреть файл

@ -1,156 +0,0 @@
package shutil
import (
"bytes"
"io/ioutil"
"os"
"testing"
)
func filesMatch(src, dst string) (bool, error) {
srcContents, err := ioutil.ReadFile(src)
if err != nil {
return false, err
}
dstContents, err := ioutil.ReadFile(dst)
if err != nil {
return false, err
}
if bytes.Compare(srcContents, dstContents) != 0 {
return false, nil
}
return true, nil
}
func TestSameFileError(t *testing.T) {
_, err := Copy("test/testfile", "test/testfile", false)
_, ok := err.(*SameFileError)
if !ok {
t.Error(err)
}
}
func TestCopyFile(t *testing.T) {
// clear out existing files if they exist
os.Remove("test/testfile3")
err := CopyFile("test/testfile", "test/testfile3", false)
if err != nil {
t.Error(err)
return
}
match, err := filesMatch("test/testfile", "test/testfile3")
if err != nil {
t.Error(err)
return
}
if !match {
t.Fail()
return
}
// And again without clearing the files
err = CopyFile("test/testfile2", "test/testfile3", false)
if err != nil {
t.Error(err)
return
}
match2, err := filesMatch("test/testfile2", "test/testfile3")
if err != nil {
t.Error(err)
return
}
if !match2 {
t.Fail()
return
}
}
func TestCopy(t *testing.T) {
// clear out existing files if they exist
os.Remove("test/testfile3")
_, err := Copy("test/testfile", "test/testfile3", false)
if err != nil {
t.Error(err)
return
}
match, err := filesMatch("test/testfile", "test/testfile3")
if err != nil {
t.Error(err)
return
}
if !match {
t.Fail()
return
}
// And again without clearing the files
_, err = Copy("test/testfile2", "test/testfile3", false)
if err != nil {
t.Error(err)
return
}
match2, err := filesMatch("test/testfile2", "test/testfile3")
if err != nil {
t.Error(err)
return
}
if !match2 {
t.Fail()
return
}
}
func TestCopyTree(t *testing.T) {
// clear out existing files if they exist
os.RemoveAll("test/testdir3")
err := CopyTree("test/testdir", "test/testdir3", nil)
if err != nil {
t.Error(err)
return
}
match, err := filesMatch("test/testdir/file1", "test/testdir3/file1")
if err != nil {
t.Error(err)
return
}
if !match {
t.Fail()
return
}
// // And again without clearing the files
// _, err = Copy("test/testfile2", "test/testfile3", false)
// if err != nil {
// t.Error(err)
// return
// }
// match2, err := filesMatch("test/testfile2", "test/testfile3")
// if err != nil {
// t.Error(err)
// return
// }
// if !match2 {
// t.Fail()
// return
// }
}

1
vendor/github.com/termie/go-shutil/test/testdir/file1 сгенерированный поставляемый
Просмотреть файл

@ -1 +0,0 @@
file1

1
vendor/github.com/termie/go-shutil/test/testdir/file2 сгенерированный поставляемый
Просмотреть файл

@ -1 +0,0 @@
file2

1
vendor/github.com/termie/go-shutil/test/testfile сгенерированный поставляемый
Просмотреть файл

@ -1 +0,0 @@
testfile

1
vendor/github.com/termie/go-shutil/test/testfile2 сгенерированный поставляемый
Просмотреть файл

@ -1 +0,0 @@
testfile2