Skip to content
This repository has been 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
Show file tree
Hide file tree
Changes from 2 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
Expand Up @@ -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"))
Expand Down
16 changes: 9 additions & 7 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, disables locking.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a little more on this comment here. it's in reference to a rather obscure feature that most people don't know about. with just this context, i would probably expect people to assume that it referred to, say, not writing out Gopkg.lock (which is not something we do at all). instead, maybe:

"When set, no lock file will be created to protect against multiple simultaneous dep processes."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. Frankly I wrote something similar originally and changed my mind (something about that comment being much longer than the others -- silly I know).

I'll fix immediately.

}

// SetPaths sets the WorkingDir and GOPATHs fields. If GOPATHs is empty, then
Expand Down Expand Up @@ -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,
})
}

Expand Down
53 changes: 48 additions & 5 deletions internal/gps/source_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 interfereing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/interfereing/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 inteface and it's 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.
Expand Down Expand Up @@ -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
Expand All @@ -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 dep SourceManager shoud NOT lock.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"shoud" typo here. also, let's rewrite this a bit, too:

"True if the SourceManager should NOT use a file lock to protect the Cachedir from multiple processes."

}

// NewSourceManager produces an instance of gps's built-in SourceManager.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down