Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

[WIP] Feature to disable file locking when DEPNOLOCK set #1206

Merged
merged 7 commits into from
Sep 29, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions cmd/dep/main.go
Original file line number Diff line number Diff line change
@@ -147,9 +147,10 @@ func (c *Config) Run() (exitCode int) {

// Set up dep context.
ctx := &dep.Ctx{
Out: outLogger,
Err: errLogger,
Verbose: *verbose,
Out: outLogger,
Err: errLogger,
Verbose: *verbose,
DisableLocking: getEnv(c.Env, "DEPNOLOCK") != "",
}

GOPATHS := filepath.SplitList(getEnv(c.Env, "GOPATH"))
16 changes: 9 additions & 7 deletions context.go
Original file line number Diff line number Diff line change
@@ -34,11 +34,12 @@ import (
// }
//
type Ctx struct {
WorkingDir string // Where to execute.
GOPATH string // Selected Go path, containing WorkingDir.
GOPATHs []string // Other Go paths.
Out, Err *log.Logger // Required loggers.
Verbose bool // Enables more verbose logging.
WorkingDir string // Where to execute.
GOPATH string // Selected Go path, containing WorkingDir.
GOPATHs []string // Other Go paths.
Out, Err *log.Logger // Required loggers.
Verbose bool // Enables more verbose logging.
DisableLocking bool // When set, no lock file will be created to protect against simultaneous dep processes.
}

// SetPaths sets the WorkingDir and GOPATHs fields. If GOPATHs is empty, then
@@ -87,8 +88,9 @@ func defaultGOPATH() string {
// initialized to log to the receiver's logger.
func (c *Ctx) SourceManager() (*gps.SourceMgr, error) {
return gps.NewSourceManager(gps.SourceManagerConfig{
Cachedir: filepath.Join(c.GOPATH, "pkg", "dep"),
Logger: c.Out,
Cachedir: filepath.Join(c.GOPATH, "pkg", "dep"),
Logger: c.Out,
DisableLocking: c.DisableLocking,
})
}

53 changes: 48 additions & 5 deletions internal/gps/source_manager.go
Original file line number Diff line number Diff line change
@@ -28,6 +28,41 @@ import (
// Used to compute a friendly filepath from a URL-shaped input.
var sanitizer = strings.NewReplacer("-", "--", ":", "-", "/", "-", "+", "-")

// A locker is responsible for preventing multiple instances of dep from
// interfering with one-another.
//
// Currently, anything that can either TryLock(), Unlock(), or GetOwner()
// satifies that need.
type locker interface {
TryLock() error
Unlock() error
GetOwner() (*os.Process, error)
}

// A falselocker adheres to the locker interface and its purpose is to quietly
// fail to lock when the DEPNOLOCK environment variable is set.
//
// This allows dep to run on systems where file locking doesn't work --
// particularly those that use union mount type filesystems that don't
// implement hard links or fnctl() style locking.
type falseLocker struct{}

// Always returns an error to indicate there's no current ower PID for our
// lock.
func (fl falseLocker) GetOwner() (*os.Process, error) {
return nil, fmt.Errorf("falseLocker always fails")
}

// Does nothing and returns a nil error so caller beleives locking succeeded.
func (fl falseLocker) TryLock() error {
return nil
}

// Does nothing and returns a nil error so caller beleives unlocking succeeded.
func (fl falseLocker) Unlock() error {
return nil
}

// A SourceManager is responsible for retrieving, managing, and interrogating
// source repositories. Its primary purpose is to serve the needs of a Solver,
// but it is handy for other purposes, as well.
@@ -121,7 +156,7 @@ func (p ProjectAnalyzerInfo) String() string {
// tools; control via dependency injection is intended to be sufficient.
type SourceMgr struct {
cachedir string // path to root of cache dir
lf *lockfile.Lockfile // handle for the sm lock file on disk
lf locker // handle for the sm lock file on disk
suprvsr *supervisor // subsystem that supervises running calls/io
cancelAll context.CancelFunc // cancel func to kill all running work
deduceCoord *deductionCoordinator // subsystem that manages import path deduction
@@ -142,8 +177,9 @@ var _ SourceManager = &SourceMgr{}

// SourceManagerConfig holds configuration information for creating SourceMgrs.
type SourceManagerConfig struct {
Cachedir string // Where to store local instances of upstream sources.
Logger *log.Logger // Optional info/warn logger. Discards if nil.
Cachedir string // Where to store local instances of upstream sources.
Logger *log.Logger // Optional info/warn logger. Discards if nil.
DisableLocking bool // True if the SourceManager should NOT use a lock file to protect the Cachedir from multiple processes.
}

// NewSourceManager produces an instance of gps's built-in SourceManager.
@@ -175,7 +211,14 @@ func NewSourceManager(c SourceManagerConfig) (*SourceMgr, error) {
// we can spin on.

glpath := filepath.Join(c.Cachedir, "sm.lock")
lockfile, err := lockfile.New(glpath)

lockfile, err := func() (locker, error) {
if c.DisableLocking {
return falseLocker{}, nil
}
return lockfile.New(glpath)
}()

if err != nil {
return nil, CouldNotCreateLockError{
Path: glpath,
@@ -238,7 +281,7 @@ func NewSourceManager(c SourceManagerConfig) (*SourceMgr, error) {

sm := &SourceMgr{
cachedir: c.Cachedir,
lf: &lockfile,
lf: lockfile,
suprvsr: superv,
cancelAll: cf,
deduceCoord: deducer,