github.com/mfycheng/glide@v0.11.2-0.20160818232903-be8a502f4bc4/cache/global_lock.go (about)

     1  package cache
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	"github.com/Masterminds/glide/msg"
    11  	gpath "github.com/Masterminds/glide/path"
    12  )
    13  
    14  var isStarted bool
    15  
    16  // SystemLock starts a system rather than application lock. This way multiple
    17  // app instances don't cause race conditions when working in the cache.
    18  func SystemLock() error {
    19  	if isStarted {
    20  		return nil
    21  	}
    22  	err := waitOnLock()
    23  	if err != nil {
    24  		return err
    25  	}
    26  	err = startLock()
    27  	isStarted = true
    28  	return err
    29  }
    30  
    31  // SystemUnlock removes the system wide Glide cache lock.
    32  func SystemUnlock() {
    33  	lockdone <- struct{}{}
    34  	os.Remove(lockFileName)
    35  }
    36  
    37  var lockdone = make(chan struct{}, 1)
    38  
    39  type lockdata struct {
    40  	Comment string `json:"comment"`
    41  	Pid     int    `json:"pid"`
    42  	Time    string `json:"time"`
    43  }
    44  
    45  var lockFileName = filepath.Join(gpath.Home(), "lock.json")
    46  
    47  // Write a lock for now.
    48  func writeLock() error {
    49  	ld := &lockdata{
    50  		Comment: "File managed by Glide (https://glide.sh)",
    51  		Pid:     os.Getpid(),
    52  		Time:    time.Now().Format(time.RFC3339Nano),
    53  	}
    54  
    55  	out, err := json.Marshal(ld)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	err = ioutil.WriteFile(lockFileName, out, 0755)
    60  	return err
    61  }
    62  
    63  func startLock() error {
    64  	err := writeLock()
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	go func() {
    70  		for {
    71  			select {
    72  			case <-lockdone:
    73  				return
    74  			default:
    75  				time.Sleep(10 * time.Second)
    76  				err := writeLock()
    77  				if err != nil {
    78  					msg.Die("Error using Glide lock: %s", err)
    79  				}
    80  			}
    81  		}
    82  	}()
    83  
    84  	return nil
    85  }
    86  
    87  func waitOnLock() error {
    88  	var announced bool
    89  	for {
    90  		fi, err := os.Stat(lockFileName)
    91  		if err != nil && os.IsNotExist(err) {
    92  			return nil
    93  		} else if err != nil {
    94  			return err
    95  		}
    96  
    97  		diff := time.Now().Sub(fi.ModTime())
    98  		if diff.Seconds() > 15 {
    99  			return nil
   100  		}
   101  
   102  		if !announced {
   103  			announced = true
   104  			msg.Info("Waiting on Glide global cache access")
   105  		}
   106  
   107  		// Check on the lock file every 15 seconds.
   108  		// TODO(mattfarina): should this be a different length?
   109  		time.Sleep(time.Second)
   110  	}
   111  }