| package cache |
| |
| import ( |
| "encoding/json" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "time" |
| |
| "github.com/Masterminds/glide/msg" |
| gpath "github.com/Masterminds/glide/path" |
| ) |
| |
| var isStarted bool |
| |
| // SystemLock starts a system rather than application lock. This way multiple |
| // app instances don't cause race conditions when working in the cache. |
| func SystemLock() error { |
| if isStarted { |
| return nil |
| } |
| err := waitOnLock() |
| if err != nil { |
| return err |
| } |
| err = startLock() |
| isStarted = true |
| return err |
| } |
| |
| // SystemUnlock removes the system wide Glide cache lock. |
| func SystemUnlock() { |
| lockdone <- struct{}{} |
| os.Remove(lockFileName) |
| } |
| |
| var lockdone = make(chan struct{}, 1) |
| |
| type lockdata struct { |
| Comment string `json:"comment"` |
| Pid int `json:"pid"` |
| Time string `json:"time"` |
| } |
| |
| var lockFileName = filepath.Join(gpath.Home(), "lock.json") |
| |
| // Write a lock for now. |
| func writeLock() error { |
| ld := &lockdata{ |
| Comment: "File managed by Glide (https://glide.sh)", |
| Pid: os.Getpid(), |
| Time: time.Now().Format(time.RFC3339Nano), |
| } |
| |
| out, err := json.Marshal(ld) |
| if err != nil { |
| return err |
| } |
| err = ioutil.WriteFile(lockFileName, out, 0755) |
| return err |
| } |
| |
| func startLock() error { |
| err := writeLock() |
| if err != nil { |
| return err |
| } |
| |
| go func() { |
| for { |
| select { |
| case <-lockdone: |
| return |
| default: |
| time.Sleep(10 * time.Second) |
| err := writeLock() |
| if err != nil { |
| msg.Die("Error using Glide lock: %s", err) |
| } |
| } |
| } |
| }() |
| |
| return nil |
| } |
| |
| func waitOnLock() error { |
| var announced bool |
| for { |
| fi, err := os.Stat(lockFileName) |
| if err != nil && os.IsNotExist(err) { |
| return nil |
| } else if err != nil { |
| return err |
| } |
| |
| diff := time.Now().Sub(fi.ModTime()) |
| if diff.Seconds() > 15 { |
| return nil |
| } |
| |
| if !announced { |
| announced = true |
| msg.Info("Waiting on Glide global cache access") |
| } |
| |
| // Check on the lock file every 15 seconds. |
| // TODO(mattfarina): should this be a different length? |
| time.Sleep(time.Second) |
| } |
| } |