зеркало из https://github.com/golang/dep.git
Respect dry-run flag during dep ensure
This commit is contained in:
Родитель
1c50c3ad88
Коммит
e43a3b839e
|
@ -147,25 +147,26 @@ func (cmd *ensureCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
return errors.Wrap(err, "ensure Solve()")
|
||||
}
|
||||
|
||||
sw := dep.SafeWriter{
|
||||
Root: p.AbsRoot,
|
||||
Lock: p.Lock,
|
||||
NewLock: solution,
|
||||
SourceManager: sm,
|
||||
}
|
||||
if !cmd.update {
|
||||
sw.Manifest = p.Manifest
|
||||
}
|
||||
|
||||
// check if vendor exists, because if the locks are the same but
|
||||
// vendor does not exist we should write vendor
|
||||
vendorExists, err := dep.IsNonEmptyDir(filepath.Join(sw.Root, "vendor"))
|
||||
vendorExists, err := dep.IsNonEmptyDir(filepath.Join(p.AbsRoot, "vendor"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ensure vendor is a directory")
|
||||
}
|
||||
writeV := !vendorExists && solution != nil
|
||||
|
||||
return errors.Wrap(sw.WriteAllSafe(writeV), "grouped write of manifest, lock and vendor")
|
||||
var sw dep.SafeWriter
|
||||
var manifest *dep.Manifest
|
||||
if !cmd.update {
|
||||
manifest = p.Manifest
|
||||
}
|
||||
|
||||
sw.Prepare(manifest, p.Lock, solution, writeV)
|
||||
if cmd.dryRun {
|
||||
return sw.PrintPreparedActions()
|
||||
}
|
||||
|
||||
return errors.Wrap(sw.Write(p.AbsRoot, sm), "grouped write of manifest, lock and vendor")
|
||||
}
|
||||
|
||||
func applyUpdateArgs(args []string, params *gps.SolveParameters) {
|
||||
|
|
|
@ -106,13 +106,13 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m := dep.Manifest{
|
||||
m := &dep.Manifest{
|
||||
Dependencies: pd.constraints,
|
||||
}
|
||||
|
||||
// Make an initial lock from what knowledge we've collected about the
|
||||
// versions on disk
|
||||
l := dep.Lock{
|
||||
l := &dep.Lock{
|
||||
P: make([]gps.LockedProject, 0, len(pd.ondisk)),
|
||||
}
|
||||
|
||||
|
@ -134,19 +134,13 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
)
|
||||
}
|
||||
|
||||
sw := dep.SafeWriter{
|
||||
Root: root,
|
||||
SourceManager: sm,
|
||||
Manifest: &m,
|
||||
}
|
||||
|
||||
if len(pd.notondisk) > 0 {
|
||||
vlogf("Solving...")
|
||||
params := gps.SolveParameters{
|
||||
RootDir: root,
|
||||
RootPackageTree: pkgT,
|
||||
Manifest: &m,
|
||||
Lock: &l,
|
||||
Manifest: m,
|
||||
Lock: l,
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
|
@ -163,14 +157,14 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
handleAllTheFailuresOfTheWorld(err)
|
||||
return err
|
||||
}
|
||||
sw.Lock = dep.LockFromInterface(soln)
|
||||
} else {
|
||||
sw.Lock = &l
|
||||
l = dep.LockFromInterface(soln)
|
||||
}
|
||||
|
||||
vlogf("Writing manifest and lock files.")
|
||||
|
||||
if err := sw.WriteAllSafe(true); err != nil {
|
||||
var sw dep.SafeWriter
|
||||
sw.Prepare(m, l, nil, true)
|
||||
if err := sw.Write(root, sm); err != nil {
|
||||
return errors.Wrap(err, "safe write of manifest and lock")
|
||||
}
|
||||
|
||||
|
|
|
@ -179,15 +179,9 @@ func (cmd *removeCommand) Run(ctx *dep.Ctx, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
sw := dep.SafeWriter{
|
||||
Root: p.AbsRoot,
|
||||
Manifest: p.Manifest,
|
||||
Lock: p.Lock,
|
||||
NewLock: soln,
|
||||
SourceManager: sm,
|
||||
}
|
||||
|
||||
if err := sw.WriteAllSafe(false); err != nil {
|
||||
var sw dep.SafeWriter
|
||||
sw.Prepare(p.Manifest, p.Lock, soln, false)
|
||||
if err := sw.Write(p.AbsRoot, sm); err != nil {
|
||||
return errors.Wrap(err, "grouped write of manifest, lock and vendor")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"memo": "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5",
|
||||
"projects": [
|
||||
{
|
||||
"name": "github.com/sdboyer/deptest",
|
||||
"version": "v0.8.0",
|
||||
"revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf",
|
||||
"packages": [
|
||||
"."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "github.com/sdboyer/deptestdos",
|
||||
"version": "v2.0.0",
|
||||
"revision": "5c607206be5decd28e6263ffffdcee067266015e",
|
||||
"packages": [
|
||||
"."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"github.com/sdboyer/deptest": {
|
||||
"version": "~0.8.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"memo": "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5",
|
||||
"projects": [
|
||||
{
|
||||
"name": "github.com/sdboyer/deptest",
|
||||
"version": "v0.8.0",
|
||||
"revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf",
|
||||
"packages": [
|
||||
"."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "github.com/sdboyer/deptestdos",
|
||||
"version": "v2.0.0",
|
||||
"revision": "5c607206be5decd28e6263ffffdcee067266015e",
|
||||
"packages": [
|
||||
"."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/sdboyer/deptest"
|
||||
"github.com/sdboyer/deptestdos"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := nil
|
||||
if err != nil {
|
||||
deptest.Map["yo yo!"]
|
||||
}
|
||||
deptestdos.diMeLo("whatev")
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"github.com/sdboyer/deptest": {
|
||||
"version": "~0.8.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"commands": [
|
||||
["init"],
|
||||
["ensure", "-n", "-update", "github.com/sdboyer/deptest"]
|
||||
]
|
||||
}
|
25
lock.go
25
lock.go
|
@ -102,16 +102,7 @@ func (l *Lock) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
v := lp.Version()
|
||||
// Figure out how to get the underlying revision
|
||||
switch tv := v.(type) {
|
||||
case gps.UnpairedVersion:
|
||||
// TODO we could error here, if we want to be very defensive about not
|
||||
// allowing a lock to be written if without an immmutable revision
|
||||
case gps.Revision:
|
||||
ld.Revision = tv.String()
|
||||
case gps.PairedVersion:
|
||||
ld.Revision = tv.Underlying().String()
|
||||
}
|
||||
ld.Revision = GetRevisionFromVersion(v)
|
||||
|
||||
switch v.Type() {
|
||||
case gps.IsBranch:
|
||||
|
@ -134,6 +125,20 @@ func (l *Lock) MarshalJSON() ([]byte, error) {
|
|||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func GetRevisionFromVersion(v gps.Version) string {
|
||||
// Figure out how to get the underlying revision
|
||||
switch tv := v.(type) {
|
||||
case gps.UnpairedVersion:
|
||||
// TODO we could error here, if we want to be very defensive about not
|
||||
// allowing a lock to be written if without an immmutable revision
|
||||
case gps.Revision:
|
||||
return tv.String()
|
||||
case gps.PairedVersion:
|
||||
return tv.Underlying().String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// LockFromInterface converts an arbitrary gps.Lock to dep's representation of a
|
||||
// lock. If the input is already dep's *lock, the input is returned directly.
|
||||
//
|
||||
|
|
26
test/test.go
26
test/test.go
|
@ -513,11 +513,20 @@ func (h *Helper) Path(name string) string {
|
|||
|
||||
// MustExist fails if path does not exist.
|
||||
func (h *Helper) MustExist(path string) {
|
||||
if !h.Exist(path) {
|
||||
h.t.Fatalf("%+v", errors.Errorf("%s does not exist but should", path))
|
||||
if err := h.ShouldExist(path); err != nil {
|
||||
h.t.Fatalf("%+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldExist returns an error if path does not exist.
|
||||
func (h *Helper) ShouldExist(path string) error {
|
||||
if !h.Exist(path) {
|
||||
return errors.Errorf("%s does not exist but should", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exist returns whether or not a path exists
|
||||
func (h *Helper) Exist(path string) bool {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
|
@ -532,11 +541,20 @@ func (h *Helper) Exist(path string) bool {
|
|||
|
||||
// MustNotExist fails if path exists.
|
||||
func (h *Helper) MustNotExist(path string) {
|
||||
if h.Exist(path) {
|
||||
h.t.Fatalf("%+v", errors.Errorf("%s exists but should not", path))
|
||||
if err := h.ShouldNotExist(path); err != nil {
|
||||
h.t.Fatalf("%+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldNotExist returns an error if path exists.
|
||||
func (h *Helper) ShouldNotExist(path string) error {
|
||||
if h.Exist(path) {
|
||||
return errors.Errorf("%s exists but should not", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cleanup cleans up a test that runs testgo.
|
||||
func (h *Helper) Cleanup() {
|
||||
if h.wd != "" {
|
||||
|
|
235
txn_writer.go
235
txn_writer.go
|
@ -21,85 +21,132 @@ import (
|
|||
// It is not impervious to errors (writing to disk is hard), but it should
|
||||
// guard against non-arcane failure conditions.
|
||||
type SafeWriter struct {
|
||||
Root string // absolute path of root dir in which to write
|
||||
Manifest *Manifest // the manifest to write, if any
|
||||
Lock *Lock // the old lock, if any
|
||||
NewLock gps.Lock // the new lock, if any
|
||||
SourceManager gps.SourceManager
|
||||
Payload *SafeWriterPayload
|
||||
}
|
||||
|
||||
// WriteAllSafe writes out some combination of config yaml, lock, and a vendor
|
||||
// tree, to a temp dir, then moves them into place if and only if all the write
|
||||
// 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.
|
||||
//
|
||||
// - If a sw.Manifest is provided, it will be written to the standard manifest file
|
||||
// name beneath sw.Root
|
||||
// - If sw.Lock is provided without an sw.NewLock, it will be written to the standard
|
||||
// lock file name in the root dir, but vendor will NOT be written
|
||||
// - If sw.Lock and sw.NewLock are both provided and are equivalent, then neither lock
|
||||
// nor vendor will be written
|
||||
// - If sw.Lock and sw.NewLock are both provided and are not equivalent,
|
||||
// the nl will be written to the same location as above, and a vendor
|
||||
// tree will be written to sw.Root/vendor
|
||||
// - If sw.NewLock is provided and sw.Lockock is not, it will write both a lock
|
||||
// and vendor dir in the same way
|
||||
// - If the forceVendor param is true, then vendor will be unconditionally
|
||||
// written out based on sw.NewLock if present, else sw.Lock, else error.
|
||||
//
|
||||
// Any of m, l, or nl can be omitted; the grouped write operation will continue
|
||||
// for whichever inputs are present. A SourceManager is only required if vendor
|
||||
// is being written.
|
||||
func (sw SafeWriter) WriteAllSafe(forceVendor bool) error {
|
||||
// Decide which writes we need to do
|
||||
var writeM, writeL, writeV bool
|
||||
writeV = forceVendor
|
||||
// SafeWriterPayload represents the actions SafeWriter will execute when SafeWriter.Write is called.
|
||||
type SafeWriterPayload struct {
|
||||
Manifest *Manifest
|
||||
Lock *Lock
|
||||
LockDiff *LockDiff
|
||||
ForceWriteVendor bool
|
||||
}
|
||||
|
||||
if sw.Manifest != nil {
|
||||
writeM = true
|
||||
func (payload *SafeWriterPayload) HasLock() bool {
|
||||
return payload.Lock != nil
|
||||
}
|
||||
|
||||
func (payload *SafeWriterPayload) HasManifest() bool {
|
||||
return payload.Manifest != nil
|
||||
}
|
||||
|
||||
func (payload *SafeWriterPayload) HasVendor() bool {
|
||||
// TODO(carolynvs) this can be calculated based on if we are writing the lock
|
||||
// init -> switch to newlock
|
||||
// ensure checks existence, why not move that into the prep?
|
||||
return payload.ForceWriteVendor
|
||||
}
|
||||
|
||||
// LockDiff is the set of differences between an existing lock file and an updated lock file.
|
||||
// TODO(carolynvs) this should be moved to gps
|
||||
type LockDiff struct {
|
||||
Add []gps.LockedProject
|
||||
Remove []gps.LockedProject
|
||||
Modify []LockedProjectDiff
|
||||
}
|
||||
|
||||
// LockedProjectDiff contains the before and after snapshot of a project reference.
|
||||
// TODO(carolynvs) this should be moved to gps
|
||||
type LockedProjectDiff struct {
|
||||
Current gps.LockedProject // Current represents the project reference as defined in the existing lock file.
|
||||
Updated gps.LockedProject // Updated represents the desired project reference.
|
||||
}
|
||||
|
||||
// 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 lock is provided it will be written to the standard
|
||||
// lock file name in the root dir, but vendor will NOT be written
|
||||
// - If lock and newLock are both provided and are equivalent, then neither lock
|
||||
// nor vendor will be written
|
||||
// - If lock and newLock are both provided and are not equivalent,
|
||||
// the newLock will be written to the same location as above, and a vendor
|
||||
// tree will be written to the vendor directory
|
||||
// - If newLock is provided and lock is not, it will write both a lock
|
||||
// and the vendor directory in the same way
|
||||
// - If the forceVendor param is true, then vendor/ will be unconditionally
|
||||
// written out based on newLock if present, else lock, else error.
|
||||
func (sw *SafeWriter) Prepare(manifest *Manifest, lock *Lock, newLock gps.Lock, forceVendor bool) {
|
||||
sw.Payload = &SafeWriterPayload{
|
||||
Manifest: manifest,
|
||||
ForceWriteVendor: forceVendor,
|
||||
}
|
||||
|
||||
if sw.NewLock != nil {
|
||||
if sw.Lock == nil {
|
||||
writeL, writeV = true, true
|
||||
if newLock != nil {
|
||||
rlf := LockFromInterface(newLock)
|
||||
if lock == nil {
|
||||
sw.Payload.Lock = rlf
|
||||
sw.Payload.ForceWriteVendor = true
|
||||
} else {
|
||||
rlf := LockFromInterface(sw.NewLock)
|
||||
if !locksAreEquivalent(rlf, sw.Lock) {
|
||||
writeL, writeV = true, true
|
||||
if !locksAreEquivalent(rlf, lock) {
|
||||
sw.Payload.Lock = rlf
|
||||
sw.Payload.ForceWriteVendor = true
|
||||
}
|
||||
}
|
||||
} else if sw.Lock != nil {
|
||||
writeL = true
|
||||
} else if lock != nil {
|
||||
sw.Payload.Lock = lock
|
||||
}
|
||||
}
|
||||
|
||||
if sw.Root == "" {
|
||||
func (payload SafeWriterPayload) validate(root string, sm gps.SourceManager) error {
|
||||
if root == "" {
|
||||
return errors.New("root path must be non-empty")
|
||||
}
|
||||
if is, err := IsDir(sw.Root); !is {
|
||||
if is, err := IsDir(root); !is {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("root path %q does not exist", sw.Root)
|
||||
return fmt.Errorf("root path %q does not exist", root)
|
||||
}
|
||||
|
||||
if !writeM && !writeL && !writeV {
|
||||
if payload.HasVendor() && sm == nil {
|
||||
return errors.New("must provide a SourceManager if writing out a vendor dir")
|
||||
}
|
||||
|
||||
if payload.HasVendor() && payload.Lock == nil {
|
||||
return errors.New("must provide a lock in order to write out vendor")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write saves some combination of config yaml, lock, and a vendor tree.
|
||||
// root is the absolute path of root dir in which to write.
|
||||
// sm is only required if vendor is being written.
|
||||
//
|
||||
// It first writes to a temp dir, then moves them in place if and only if all the write
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !sw.Payload.HasManifest() && !sw.Payload.HasLock() && !sw.Payload.HasVendor() {
|
||||
// nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
if writeV && sw.SourceManager == nil {
|
||||
return errors.New("must provide a SourceManager if writing out a vendor dir")
|
||||
}
|
||||
|
||||
if writeV && sw.Lock == nil && sw.NewLock == nil {
|
||||
return errors.New("must provide a lock in order to write out vendor")
|
||||
}
|
||||
|
||||
mpath := filepath.Join(sw.Root, ManifestName)
|
||||
lpath := filepath.Join(sw.Root, LockName)
|
||||
vpath := filepath.Join(sw.Root, "vendor")
|
||||
mpath := filepath.Join(root, ManifestName)
|
||||
lpath := filepath.Join(root, LockName)
|
||||
vpath := filepath.Join(root, "vendor")
|
||||
|
||||
td, err := ioutil.TempDir(os.TempDir(), "dep")
|
||||
if err != nil {
|
||||
|
@ -107,35 +154,20 @@ func (sw SafeWriter) WriteAllSafe(forceVendor bool) error {
|
|||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
if writeM {
|
||||
if err := writeFile(filepath.Join(td, ManifestName), sw.Manifest); err != nil {
|
||||
if sw.Payload.HasManifest() {
|
||||
if err := writeFile(filepath.Join(td, ManifestName), sw.Payload.Manifest); err != nil {
|
||||
return errors.Wrap(err, "failed to write manifest file to temp dir")
|
||||
}
|
||||
}
|
||||
|
||||
if writeL {
|
||||
if sw.NewLock == nil {
|
||||
// the new lock is nil but the flag is on, so we must be writing
|
||||
// the other one
|
||||
if err := writeFile(filepath.Join(td, LockName), sw.Lock); err != nil {
|
||||
return errors.Wrap(err, "failed to write lock file to temp dir")
|
||||
}
|
||||
} else {
|
||||
rlf := LockFromInterface(sw.NewLock)
|
||||
if err := writeFile(filepath.Join(td, LockName), rlf); err != nil {
|
||||
return errors.Wrap(err, "failed to write lock file to temp dir")
|
||||
}
|
||||
if sw.Payload.HasLock() {
|
||||
if err := writeFile(filepath.Join(td, LockName), sw.Payload.Lock); err != nil {
|
||||
return errors.Wrap(err, "failed to write lock file to temp dir")
|
||||
}
|
||||
}
|
||||
|
||||
if writeV {
|
||||
// Prefer the nl, but take the l if only that's available, as could be the
|
||||
// case if true was passed for forceVendor.
|
||||
l := sw.NewLock
|
||||
if l == nil {
|
||||
l = sw.Lock
|
||||
}
|
||||
err = gps.WriteDepTree(filepath.Join(td, "vendor"), l, sw.SourceManager, true)
|
||||
if sw.Payload.HasVendor() {
|
||||
err = gps.WriteDepTree(filepath.Join(td, "vendor"), sw.Payload.Lock, sm, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while writing out vendor tree")
|
||||
}
|
||||
|
@ -150,7 +182,7 @@ func (sw SafeWriter) WriteAllSafe(forceVendor bool) error {
|
|||
var failerr error
|
||||
var vendorbak string
|
||||
|
||||
if writeM {
|
||||
if sw.Payload.HasManifest() {
|
||||
if _, err := os.Stat(mpath); err == nil {
|
||||
// Move out the old one.
|
||||
tmploc := filepath.Join(td, ManifestName+".orig")
|
||||
|
@ -168,7 +200,7 @@ func (sw SafeWriter) WriteAllSafe(forceVendor bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
if writeL {
|
||||
if sw.Payload.HasLock() {
|
||||
if _, err := os.Stat(lpath); err == nil {
|
||||
// Move out the old one.
|
||||
tmploc := filepath.Join(td, LockName+".orig")
|
||||
|
@ -187,7 +219,7 @@ func (sw SafeWriter) WriteAllSafe(forceVendor bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
if writeV {
|
||||
if sw.Payload.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
|
||||
|
@ -215,7 +247,7 @@ func (sw SafeWriter) WriteAllSafe(forceVendor bool) 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 writeV {
|
||||
if sw.Payload.HasVendor() {
|
||||
// Nothing we can really do about an error at this point, so ignore it
|
||||
os.RemoveAll(vendorbak)
|
||||
}
|
||||
|
@ -230,3 +262,38 @@ fail:
|
|||
}
|
||||
return failerr
|
||||
}
|
||||
|
||||
func (sw *SafeWriter) PrintPreparedActions() error {
|
||||
if sw.Payload.HasManifest() {
|
||||
fmt.Println("Would have written the following manifest.json:")
|
||||
m, err := sw.Payload.Manifest.MarshalJSON()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ensure DryRun cannot read manifest")
|
||||
}
|
||||
fmt.Println(string(m))
|
||||
}
|
||||
|
||||
if sw.Payload.HasLock() {
|
||||
fmt.Println("Would have written the following lock.json:")
|
||||
m, err := sw.Payload.Lock.MarshalJSON()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ensure DryRun cannot read lock")
|
||||
}
|
||||
fmt.Println(string(m))
|
||||
}
|
||||
|
||||
if sw.Payload.HasVendor() {
|
||||
fmt.Println("Would have written the following projects to the vendor directory:")
|
||||
for _, project := range sw.Payload.Lock.Projects() {
|
||||
prj := project.Ident()
|
||||
rev := GetRevisionFromVersion(project.Version())
|
||||
if prj.Source == "" {
|
||||
fmt.Printf("%s@%s\n", prj.ProjectRoot, rev)
|
||||
} else {
|
||||
fmt.Printf("%s -> %s@%s\n", prj.ProjectRoot, prj.Source, rev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ package dep
|
|||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/dep/test"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestTxnWriterBadInputs(t *testing.T) {
|
||||
|
@ -18,190 +18,327 @@ func TestTxnWriterBadInputs(t *testing.T) {
|
|||
defer h.Cleanup()
|
||||
|
||||
h.TempDir("txnwriter")
|
||||
td := h.Path(".")
|
||||
root := h.Path(".")
|
||||
|
||||
var sw SafeWriter
|
||||
pc, err := NewContext()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm, err := pc.SourceManager()
|
||||
defer sm.Release()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sw.Prepare(nil, nil, nil, false)
|
||||
|
||||
// no root
|
||||
if err := sw.WriteAllSafe(false); err == nil {
|
||||
t.Errorf("should have errored without a root path, but did not")
|
||||
}
|
||||
sw.Root = td
|
||||
|
||||
if err := sw.WriteAllSafe(false); err != nil {
|
||||
t.Errorf("write with only root should be fine, just a no-op, but got err %q", err)
|
||||
}
|
||||
if err := sw.WriteAllSafe(true); err == nil {
|
||||
t.Errorf("should fail because no source manager was provided for writing vendor")
|
||||
if err := sw.Write("", nil); err == nil {
|
||||
t.Fatalf("should have errored without a root path, but did not")
|
||||
}
|
||||
|
||||
if err := sw.WriteAllSafe(true); err == nil {
|
||||
t.Errorf("should fail because no lock was provided from which to write vendor")
|
||||
// noop
|
||||
if err := sw.Write(root, nil); err != nil {
|
||||
t.Fatalf("write with only root should be fine, just a no-op, but got err %q", err)
|
||||
}
|
||||
|
||||
// force vendor with missing source manager
|
||||
sw.Prepare(nil, nil, nil, true)
|
||||
if !sw.Payload.HasVendor() {
|
||||
t.Fatalf("writeV not propogated")
|
||||
}
|
||||
if err := sw.Write(root, nil); err == nil {
|
||||
t.Fatalf("should fail because no source manager was provided for writing vendor")
|
||||
}
|
||||
|
||||
// force vendor with missing lock
|
||||
if err := sw.Write(root, sm); err == nil {
|
||||
t.Fatalf("should fail because no lock was provided from which to write vendor")
|
||||
}
|
||||
|
||||
// now check dir validation
|
||||
sw.Root = filepath.Join(td, "nonexistent")
|
||||
if err := sw.WriteAllSafe(false); err == nil {
|
||||
t.Errorf("should have errored with nonexistent dir for root path, but did not")
|
||||
sw.Prepare(nil, nil, nil, false)
|
||||
missingroot := filepath.Join(root, "nonexistent")
|
||||
if err := sw.Write(missingroot, sm); err == nil {
|
||||
t.Fatalf("should have errored with nonexistent dir for root path, but did not")
|
||||
}
|
||||
|
||||
sw.Root = filepath.Join(td, "myfile")
|
||||
srcf, err := os.Create(sw.Root)
|
||||
fileroot := filepath.Join(root, "myfile")
|
||||
srcf, err := os.Create(fileroot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srcf.Close()
|
||||
if err := sw.WriteAllSafe(false); err == nil {
|
||||
t.Errorf("should have errored when root path is a file, but did not")
|
||||
if err := sw.Write(fileroot, sm); err == nil {
|
||||
t.Fatalf("should have errored when root path is a file, but did not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxnWriter(t *testing.T) {
|
||||
const safeWriterProject = "safewritertest"
|
||||
const safeWriterGoldenManifest = "txn_writer/expected_manifest.json"
|
||||
const safeWriterGoldenLock = "txn_writer/expected_lock.json"
|
||||
|
||||
func TestSafeWriter_ManifestOnly(t *testing.T) {
|
||||
test.NeedsExternalNetwork(t)
|
||||
test.NeedsGit(t)
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
h.TempDir("")
|
||||
defer h.Cleanup()
|
||||
|
||||
c := &Ctx{
|
||||
GOPATH: h.Path("."),
|
||||
}
|
||||
sm, err := c.SourceManager()
|
||||
defer sm.Release()
|
||||
h.Must(err)
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
pc.CopyFile(ManifestName, safeWriterGoldenManifest)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
var mpath, lpath, vpath string
|
||||
var count int
|
||||
reset := func() {
|
||||
pr := filepath.Join("src", "txnwriter"+strconv.Itoa(count))
|
||||
h.TempDir(pr)
|
||||
sw.Prepare(pc.Project.Manifest, nil, nil, false)
|
||||
|
||||
sw = SafeWriter{
|
||||
Root: h.Path(pr),
|
||||
SourceManager: sm,
|
||||
}
|
||||
h.Cd(sw.Root)
|
||||
|
||||
mpath = filepath.Join(sw.Root, ManifestName)
|
||||
lpath = filepath.Join(sw.Root, LockName)
|
||||
vpath = filepath.Join(sw.Root, "vendor")
|
||||
|
||||
count++
|
||||
// Verify prepared actions
|
||||
if !sw.Payload.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
reset()
|
||||
|
||||
// super basic manifest and lock
|
||||
goldenm := "txn_writer/expected_manifest.json"
|
||||
goldenl := "txn_writer/expected_lock.json"
|
||||
wantm := h.GetTestFileString(goldenm)
|
||||
wantl := h.GetTestFileString(goldenl)
|
||||
|
||||
m, err := readManifest(h.GetTestFile(goldenm))
|
||||
h.Must(err)
|
||||
l, err := readLock(h.GetTestFile(goldenl))
|
||||
h.Must(err)
|
||||
|
||||
// Just write manifest
|
||||
sw.Manifest = m
|
||||
h.Must(sw.WriteAllSafe(false))
|
||||
h.MustExist(mpath)
|
||||
h.MustNotExist(lpath)
|
||||
h.MustNotExist(vpath)
|
||||
|
||||
gotm := h.ReadManifest()
|
||||
if wantm != gotm {
|
||||
if *test.UpdateGolden {
|
||||
wantm = gotm
|
||||
if err = h.WriteTestFile(goldenm, gotm); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("expected %s, got %s", wantm, gotm)
|
||||
}
|
||||
if sw.Payload.HasLock() {
|
||||
t.Fatal("Did not expect the payload to contain the lock")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Manifest and lock, but no vendor
|
||||
sw.Lock = l
|
||||
h.Must(sw.WriteAllSafe(false))
|
||||
h.MustExist(mpath)
|
||||
h.MustExist(lpath)
|
||||
h.MustNotExist(vpath)
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
gotm = h.ReadManifest()
|
||||
if wantm != gotm {
|
||||
t.Fatalf("expected %s, got %s", wantm, gotm)
|
||||
// Verify file system changes
|
||||
if err := pc.ManifestShouldMatchGolden(safeWriterGoldenManifest); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gotl := h.ReadLock()
|
||||
if wantl != gotl {
|
||||
if *test.UpdateGolden {
|
||||
wantl = gotl
|
||||
if err = h.WriteTestFile(goldenl, gotl); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("expected %s, got %s", wantl, gotl)
|
||||
}
|
||||
if err := pc.LockShouldNotExist(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h.Must(sw.WriteAllSafe(true))
|
||||
h.MustExist(mpath)
|
||||
h.MustExist(lpath)
|
||||
h.MustExist(vpath)
|
||||
h.MustExist(filepath.Join(vpath, "github.com", "sdboyer", "dep-test"))
|
||||
|
||||
gotm = h.ReadManifest()
|
||||
if wantm != gotm {
|
||||
t.Fatalf("expected %s, got %s", wantm, gotm)
|
||||
if err := pc.VendorShouldNotExist(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWriter_ManifestAndUnmodifiedLock(t *testing.T) {
|
||||
test.NeedsExternalNetwork(t)
|
||||
test.NeedsGit(t)
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
pc.CopyFile(ManifestName, safeWriterGoldenManifest)
|
||||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(pc.Project.Manifest, pc.Project.Lock, nil, false)
|
||||
|
||||
// Verify prepared actions
|
||||
if !sw.Payload.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
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.VendorShouldNotExist(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWriter_ManifestAndUnmodifiedLockWithForceVendor(t *testing.T) {
|
||||
test.NeedsExternalNetwork(t)
|
||||
test.NeedsGit(t)
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
pc.CopyFile(ManifestName, safeWriterGoldenManifest)
|
||||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(pc.Project.Manifest, pc.Project.Lock, nil, true)
|
||||
|
||||
// Verify prepared actions
|
||||
if !sw.Payload.HasManifest() {
|
||||
t.Fatal("Expected the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
t.Fatal("Expected the payload to the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWriter_UnmodifiedLock(t *testing.T) {
|
||||
test.NeedsExternalNetwork(t)
|
||||
test.NeedsGit(t)
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
sw.Prepare(nil, pc.Project.Lock, pc.Project.Lock, false)
|
||||
|
||||
// Verify prepared actions
|
||||
if sw.Payload.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if sw.Payload.HasLock() {
|
||||
t.Fatal("Did not expect the payload to contain the lock")
|
||||
}
|
||||
if sw.Payload.HasVendor() {
|
||||
t.Fatal("Did not expect the payload to contain the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
// locks are equivalent, so nothing gets written
|
||||
if err := pc.ManifestShouldNotExist(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := pc.VendorShouldNotExist(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWriter_ModifiedLockForceVendor(t *testing.T) {
|
||||
test.NeedsExternalNetwork(t)
|
||||
test.NeedsGit(t)
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
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, true)
|
||||
|
||||
// Verify prepared actions
|
||||
if sw.Payload.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
t.Fatal("Expected the payload to the vendor directory")
|
||||
}
|
||||
|
||||
// Write changes
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
if err := pc.ManifestShouldNotExist(); 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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeWriter_ForceVendorWhenVendorAlreadyExists(t *testing.T) {
|
||||
test.NeedsExternalNetwork(t)
|
||||
test.NeedsGit(t)
|
||||
|
||||
h := test.NewHelper(t)
|
||||
defer h.Cleanup()
|
||||
|
||||
pc := NewTestProjectContext(h, safeWriterProject)
|
||||
defer pc.Release()
|
||||
pc.CopyFile(LockName, safeWriterGoldenLock)
|
||||
pc.Load()
|
||||
|
||||
var sw SafeWriter
|
||||
// Populate vendor
|
||||
sw.Prepare(nil, pc.Project.Lock, nil, true)
|
||||
err := sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify prepared actions
|
||||
sw.Prepare(nil, nil, pc.Project.Lock, true)
|
||||
if sw.Payload.HasManifest() {
|
||||
t.Fatal("Did not expect the payload to contain the manifest")
|
||||
}
|
||||
if !sw.Payload.HasLock() {
|
||||
t.Fatal("Expected the payload to contain the lock")
|
||||
}
|
||||
if !sw.Payload.HasVendor() {
|
||||
t.Fatal("Expected the payload to the vendor directory")
|
||||
}
|
||||
|
||||
err = sw.Write(pc.Project.AbsRoot, pc.SourceManager)
|
||||
h.Must(errors.Wrap(err, "SafeWriter.Write failed"))
|
||||
|
||||
// Verify file system changes
|
||||
if err := pc.ManifestShouldNotExist(); 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)
|
||||
}
|
||||
|
||||
gotl = h.ReadLock()
|
||||
if wantl != gotl {
|
||||
t.Fatalf("expected %s, got %s", wantl, gotl)
|
||||
}
|
||||
|
||||
// start fresh, ignoring the manifest now
|
||||
reset()
|
||||
sw.Lock = l
|
||||
sw.NewLock = l
|
||||
|
||||
h.Must(sw.WriteAllSafe(false))
|
||||
// locks are equivalent, so nothing gets written
|
||||
h.MustNotExist(mpath)
|
||||
h.MustNotExist(lpath)
|
||||
h.MustNotExist(vpath)
|
||||
|
||||
l2 := new(Lock)
|
||||
*l2 = *l
|
||||
// zero out the input hash to ensure non-equivalency
|
||||
l2.Memo = []byte{}
|
||||
sw.Lock = l2
|
||||
h.Must(sw.WriteAllSafe(true))
|
||||
h.MustNotExist(mpath)
|
||||
h.MustExist(lpath)
|
||||
h.MustExist(vpath)
|
||||
h.MustExist(filepath.Join(vpath, "github.com", "sdboyer", "dep-test"))
|
||||
|
||||
gotl = h.ReadLock()
|
||||
if wantl != gotl {
|
||||
t.Fatalf("expected %s, got %s", wantl, gotl)
|
||||
}
|
||||
|
||||
// repeat op to ensure good behavior when vendor dir already exists
|
||||
sw.Lock = nil
|
||||
h.Must(sw.WriteAllSafe(true))
|
||||
h.MustNotExist(mpath)
|
||||
h.MustExist(lpath)
|
||||
h.MustExist(vpath)
|
||||
h.MustExist(filepath.Join(vpath, "github.com", "sdboyer", "dep-test"))
|
||||
|
||||
gotl = h.ReadLock()
|
||||
if wantl != gotl {
|
||||
t.Fatalf("expected %s, got %s", wantl, gotl)
|
||||
}
|
||||
|
||||
// TODO test txn rollback cases. maybe we can force errors with chmodding?
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче