This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git

commit 47408438ee3be5095504f740395f85e2e59a76d8
Author: Rohit Yadav <[email protected]>
AuthorDate: Mon Oct 22 00:45:58 2018 +0530

    cmk: implement file lock for config read/write
    
    Signed-off-by: Rohit Yadav <[email protected]>
---
 config/config.go                               |  19 ++-
 go.mod                                         |   1 +
 go.sum                                         |   2 +
 vendor/github.com/gofrs/flock/.gitignore       |  24 +++
 vendor/github.com/gofrs/flock/.travis.yml      |  10 ++
 vendor/github.com/gofrs/flock/LICENSE          |  27 ++++
 vendor/github.com/gofrs/flock/README.md        |  40 +++++
 vendor/github.com/gofrs/flock/appveyor.yml     |  25 ++++
 vendor/github.com/gofrs/flock/flock.go         | 127 ++++++++++++++++
 vendor/github.com/gofrs/flock/flock_unix.go    | 195 +++++++++++++++++++++++++
 vendor/github.com/gofrs/flock/flock_winapi.go  |  76 ++++++++++
 vendor/github.com/gofrs/flock/flock_windows.go | 140 ++++++++++++++++++
 vendor/modules.txt                             |   2 +
 13 files changed, 686 insertions(+), 2 deletions(-)

diff --git a/config/config.go b/config/config.go
index 0b0ad6b..42af265 100644
--- a/config/config.go
+++ b/config/config.go
@@ -27,6 +27,7 @@ import (
        "strconv"
        "time"
 
+       "github.com/gofrs/flock"
        "github.com/mitchellh/go-homedir"
        "gopkg.in/ini.v1"
 )
@@ -140,6 +141,18 @@ func newHTTPClient(cfg *Config) *http.Client {
 }
 
 func reloadConfig(cfg *Config) *Config {
+       fileLock := flock.New(path.Join(getDefaultConfigDir(), "lock"))
+       err := fileLock.Lock()
+       if err != nil {
+               fmt.Println("Failed to grab config file lock, please try again")
+               return cfg
+       }
+       cfg = saveConfig(cfg)
+       fileLock.Unlock()
+       return cfg
+}
+
+func saveConfig(cfg *Config) *Config {
        if _, err := os.Stat(cfg.Dir); err != nil {
                os.Mkdir(cfg.Dir, 0700)
        }
@@ -214,7 +227,7 @@ func reloadConfig(cfg *Config) *Config {
 }
 
 // UpdateConfig updates and saves config
-func (c *Config) UpdateConfig(key string, value string) {
+func (c *Config) UpdateConfig(key string, value string, update bool) {
        switch key {
        case "prompt":
                c.Core.Prompt = value
@@ -246,7 +259,9 @@ func (c *Config) UpdateConfig(key string, value string) {
                c.Core.VerifyCert = value == "true"
        }
 
-       reloadConfig(c)
+       if update {
+               reloadConfig(c)
+       }
 }
 
 // NewConfig creates or reload config and loads API cache
diff --git a/go.mod b/go.mod
index ed2a67a..d403cd0 100644
--- a/go.mod
+++ b/go.mod
@@ -21,6 +21,7 @@ require (
        github.com/briandowns/spinner v0.0.0-20181018151057-dd69c579ff20
        github.com/c-bata/go-prompt v0.2.2
        github.com/fatih/color v1.7.0 // indirect
+       github.com/gofrs/flock v0.7.0
        github.com/google/shlex v0.0.0-20150127133951-6f45313302b9
        github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // 
indirect
        github.com/jtolds/gls v4.2.1+incompatible // indirect
diff --git a/go.sum b/go.sum
index d7b7057..5bf1766 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,8 @@ github.com/c-bata/go-prompt v0.2.2 
h1:uyKRz6Z6DUyj49QVijyM339UJV9yhbr70gESwbNU3e
 github.com/c-bata/go-prompt v0.2.2/go.mod 
h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
 github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/gofrs/flock v0.7.0 h1:pGFUjl501gafK9HBt1VGL1KCOd/YhIooID+xgyJCf3g=
+github.com/gofrs/flock v0.7.0/go.mod 
h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/google/shlex v0.0.0-20150127133951-6f45313302b9 
h1:JM174NTeGNJ2m/oLH3UOWOvWQQKd+BoL3hcSCUWFLt0=
 github.com/google/shlex v0.0.0-20150127133951-6f45313302b9/go.mod 
h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 
h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
diff --git a/vendor/github.com/gofrs/flock/.gitignore 
b/vendor/github.com/gofrs/flock/.gitignore
new file mode 100644
index 0000000..daf913b
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/gofrs/flock/.travis.yml 
b/vendor/github.com/gofrs/flock/.travis.yml
new file mode 100644
index 0000000..b791a74
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go:
+  - 1.10.x
+  - 1.11.x
+script: go test -v -check.vv -race ./...
+sudo: false
+notifications:
+  email:
+    on_success: never
+    on_failure: always
diff --git a/vendor/github.com/gofrs/flock/LICENSE 
b/vendor/github.com/gofrs/flock/LICENSE
new file mode 100644
index 0000000..aff7d35
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2015, Tim Heckman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of linode-netint nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/gofrs/flock/README.md 
b/vendor/github.com/gofrs/flock/README.md
new file mode 100644
index 0000000..42d580f
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/README.md
@@ -0,0 +1,40 @@
+# flock
+[![TravisCI Build 
Status](https://img.shields.io/travis/gofrs/flock/master.svg?style=flat)](https://travis-ci.org/gofrs/flock)
+[![GoDoc](https://img.shields.io/badge/godoc-go--flock-blue.svg?style=flat)](https://godoc.org/github.com/gofrs/flock)
+[![License](https://img.shields.io/badge/license-BSD_3--Clause-brightgreen.svg?style=flat)](https://github.com/gofrs/flock/blob/master/LICENSE)
+
+`flock` implements a thread-safe sync.Locker interface for file locking. It 
also
+includes a non-blocking TryLock() function to allow locking without blocking 
execution.
+
+## License
+`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for 
more details.
+
+## Go Compatibility
+This package makes use of the `context` package that was introduced in Go 1.7. 
As such, this
+package has an implicit dependency on Go 1.7+.
+
+## Installation
+```
+go get -u github.com/gofrs/flock
+```
+
+## Usage
+```Go
+import "github.com/gofrs/flock"
+
+fileLock := flock.New("/var/lock/go-lock.lock")
+
+locked, err := fileLock.TryLock()
+
+if err != nil {
+       // handle locking error
+}
+
+if locked {
+       // do work
+       fileLock.Unlock()
+}
+```
+
+For more detailed usage information take a look at the package API docs on
+[GoDoc](https://godoc.org/github.com/gofrs/flock).
diff --git a/vendor/github.com/gofrs/flock/appveyor.yml 
b/vendor/github.com/gofrs/flock/appveyor.yml
new file mode 100644
index 0000000..6848e94
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/appveyor.yml
@@ -0,0 +1,25 @@
+version: '{build}'
+
+build: false
+deploy: false
+
+clone_folder: 'c:\gopath\src\github.com\gofrs\flock'
+
+environment:
+  GOPATH: 'c:\gopath'
+  GOVERSION: '1.11'
+
+init:
+  - git config --global core.autocrlf input
+
+install:
+  - rmdir c:\go /s /q
+  - appveyor DownloadFile 
https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
+  - msiexec /i go%GOVERSION%.windows-amd64.msi /q
+  - set Path=c:\go\bin;c:\gopath\bin;%Path%
+  - go version
+  - go env
+
+test_script:
+  - go get -t ./...
+  - go test -race -v ./...
diff --git a/vendor/github.com/gofrs/flock/flock.go 
b/vendor/github.com/gofrs/flock/flock.go
new file mode 100644
index 0000000..5783a49
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/flock.go
@@ -0,0 +1,127 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+// Package flock implements a thread-safe sync.Locker interface for file 
locking.
+// It also includes a non-blocking TryLock() function to allow locking
+// without blocking execution.
+//
+// Package flock is released under the BSD 3-Clause License. See the LICENSE 
file
+// for more details.
+//
+// While using this library, remember that the locking behaviors are not
+// guaranteed to be the same on each platform. For example, some UNIX-like
+// operating systems will transparently convert a shared lock to an exclusive
+// lock. If you Unlock() the flock from a location where you believe that you
+// have the shared lock, you may accidently drop the exclusive lock.
+package flock
+
+import (
+       "context"
+       "os"
+       "sync"
+       "time"
+)
+
+// Flock is the struct type to handle file locking. All fields are unexported,
+// with access to some of the fields provided by getter methods (Path() and 
Locked()).
+type Flock struct {
+       path string
+       m    sync.RWMutex
+       fh   *os.File
+       l    bool
+       r    bool
+}
+
+// New returns a new instance of *Flock. The only parameter
+// it takes is the path to the desired lockfile.
+func New(path string) *Flock {
+       return &Flock{path: path}
+}
+
+// NewFlock returns a new instance of *Flock. The only parameter
+// it takes is the path to the desired lockfile.
+//
+// Deprecated: Use New instead.
+func NewFlock(path string) *Flock {
+       return New(path)
+}
+
+// Close is equivalent to calling Unlock.
+//
+// This will release the lock and close the underlying file descriptor.
+// It will not remove the file from disk, that's up to your application.
+func (f *Flock) Close() error {
+       return f.Unlock()
+}
+
+// Path returns the path as provided in NewFlock().
+func (f *Flock) Path() string {
+       return f.path
+}
+
+// Locked returns the lock state (locked: true, unlocked: false).
+//
+// Warning: by the time you use the returned value, the state may have changed.
+func (f *Flock) Locked() bool {
+       f.m.RLock()
+       defer f.m.RUnlock()
+       return f.l
+}
+
+// RLocked returns the read lock state (locked: true, unlocked: false).
+//
+// Warning: by the time you use the returned value, the state may have changed.
+func (f *Flock) RLocked() bool {
+       f.m.RLock()
+       defer f.m.RUnlock()
+       return f.r
+}
+
+func (f *Flock) String() string {
+       return f.path
+}
+
+// TryLockContext repeatedly tries to take an exclusive lock until one of the
+// conditions is met: TryLock succeeds, TryLock fails with error, or Context
+// Done channel is closed.
+func (f *Flock) TryLockContext(ctx context.Context, retryDelay time.Duration) 
(bool, error) {
+       return tryCtx(f.TryLock, ctx, retryDelay)
+}
+
+// TryRLockContext repeatedly tries to take a shared lock until one of the
+// conditions is met: TryRLock succeeds, TryRLock fails with error, or Context
+// Done channel is closed.
+func (f *Flock) TryRLockContext(ctx context.Context, retryDelay time.Duration) 
(bool, error) {
+       return tryCtx(f.TryRLock, ctx, retryDelay)
+}
+
+func tryCtx(fn func() (bool, error), ctx context.Context, retryDelay 
time.Duration) (bool, error) {
+       if ctx.Err() != nil {
+               return false, ctx.Err()
+       }
+       for {
+               if ok, err := fn(); ok || err != nil {
+                       return ok, err
+               }
+               select {
+               case <-ctx.Done():
+                       return false, ctx.Err()
+               case <-time.After(retryDelay):
+                       // try again
+               }
+       }
+}
+
+func (f *Flock) setFh() error {
+       // open a new os.File instance
+       // create it if it doesn't exist, and open the file read-only.
+       fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDONLY, 
os.FileMode(0600))
+       if err != nil {
+               return err
+       }
+
+       // set the filehandle on the struct
+       f.fh = fh
+       return nil
+}
diff --git a/vendor/github.com/gofrs/flock/flock_unix.go 
b/vendor/github.com/gofrs/flock/flock_unix.go
new file mode 100644
index 0000000..45f71a7
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/flock_unix.go
@@ -0,0 +1,195 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package flock
+
+import (
+       "os"
+       "syscall"
+)
+
+// Lock is a blocking call to try and take an exclusive file lock. It will wait
+// until it is able to obtain the exclusive file lock. It's recommended that
+// TryLock() be used over this function. This function may block the ability to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already exclusive-locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+//
+// If the *Flock has a shared lock (RLock), this may transparently replace the
+// shared lock with an exclusive lock on some UNIX-like operating systems. Be
+// careful when using exclusive locks in conjunction with shared locks
+// (RLock()), because calling Unlock() may accidentally release the exclusive
+// lock that was once a shared lock.
+func (f *Flock) Lock() error {
+       return f.lock(&f.l, syscall.LOCK_EX)
+}
+
+// RLock is a blocking call to try and take a shared file lock. It will wait
+// until it is able to obtain the shared file lock. It's recommended that
+// TryRLock() be used over this function. This function may block the ability 
to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already shared-locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+func (f *Flock) RLock() error {
+       return f.lock(&f.r, syscall.LOCK_SH)
+}
+
+func (f *Flock) lock(locked *bool, flag int) error {
+       f.m.Lock()
+       defer f.m.Unlock()
+
+       if *locked {
+               return nil
+       }
+
+       if f.fh == nil {
+               if err := f.setFh(); err != nil {
+                       return err
+               }
+       }
+
+       if err := syscall.Flock(int(f.fh.Fd()), flag); err != nil {
+               shouldRetry, reopenErr := f.reopenFDOnError(err)
+               if reopenErr != nil {
+                       return reopenErr
+               }
+
+               if !shouldRetry {
+                       return err
+               }
+
+               if err = syscall.Flock(int(f.fh.Fd()), flag); err != nil {
+                       return err
+               }
+       }
+
+       *locked = true
+       return nil
+}
+
+// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
+// while it is running the Locked() and RLocked() functions will be blocked.
+//
+// This function short-circuits if we are unlocked already. If not, it calls
+// syscall.LOCK_UN on the file and closes the file descriptor. It does not
+// remove the file from disk. It's up to your application to do.
+//
+// Please note, if your shared lock became an exclusive lock this may
+// unintentionally drop the exclusive lock if called by the consumer that
+// believes they have a shared lock. Please see Lock() for more details.
+func (f *Flock) Unlock() error {
+       f.m.Lock()
+       defer f.m.Unlock()
+
+       // if we aren't locked or if the lockfile instance is nil
+       // just return a nil error because we are unlocked
+       if (!f.l && !f.r) || f.fh == nil {
+               return nil
+       }
+
+       // mark the file as unlocked
+       if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil {
+               return err
+       }
+
+       f.fh.Close()
+
+       f.l = false
+       f.r = false
+       f.fh = nil
+
+       return nil
+}
+
+// TryLock is the preferred function for taking an exclusive file lock. This
+// function takes an RW-mutex lock before it tries to lock the file, so there 
is
+// the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the exclusive
+// file lock, the function will return false instead of waiting for the lock. 
If
+// we get the lock, we also set the *Flock instance as being exclusive-locked.
+func (f *Flock) TryLock() (bool, error) {
+       return f.try(&f.l, syscall.LOCK_EX)
+}
+
+// TryRLock is the preferred function for taking a shared file lock. This
+// function takes an RW-mutex lock before it tries to lock the file, so there 
is
+// the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the shared 
file
+// lock, the function will return false instead of waiting for the lock. If we
+// get the lock, we also set the *Flock instance as being share-locked.
+func (f *Flock) TryRLock() (bool, error) {
+       return f.try(&f.r, syscall.LOCK_SH)
+}
+
+func (f *Flock) try(locked *bool, flag int) (bool, error) {
+       f.m.Lock()
+       defer f.m.Unlock()
+
+       if *locked {
+               return true, nil
+       }
+
+       if f.fh == nil {
+               if err := f.setFh(); err != nil {
+                       return false, err
+               }
+       }
+
+       var retried bool
+retry:
+       err := syscall.Flock(int(f.fh.Fd()), flag|syscall.LOCK_NB)
+
+       switch err {
+       case syscall.EWOULDBLOCK:
+               return false, nil
+       case nil:
+               *locked = true
+               return true, nil
+       }
+       if !retried {
+               if shouldRetry, reopenErr := f.reopenFDOnError(err); reopenErr 
!= nil {
+                       return false, reopenErr
+               } else if shouldRetry {
+                       retried = true
+                       goto retry
+               }
+       }
+
+       return false, err
+}
+
+// reopenFDOnError determines whether we should reopen the file handle
+// in readwrite mode and try again. This comes from 
util-linux/sys-utils/flock.c:
+//  Since Linux 3.4 (commit 55725513)
+//  Probably NFSv4 where flock() is emulated by fcntl().
+func (f *Flock) reopenFDOnError(err error) (bool, error) {
+       if err != syscall.EIO && err != syscall.EBADF {
+               return false, nil
+       }
+       if st, err := f.fh.Stat(); err == nil {
+               // if the file is able to be read and written
+               if st.Mode()&0600 == 0600 {
+                       f.fh.Close()
+                       f.fh = nil
+
+                       // reopen in read-write mode and set the filehandle
+                       fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDWR, 
os.FileMode(0600))
+                       if err != nil {
+                               return false, err
+                       }
+                       f.fh = fh
+                       return true, nil
+               }
+       }
+
+       return false, nil
+}
diff --git a/vendor/github.com/gofrs/flock/flock_winapi.go 
b/vendor/github.com/gofrs/flock/flock_winapi.go
new file mode 100644
index 0000000..fe405a2
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/flock_winapi.go
@@ -0,0 +1,76 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package flock
+
+import (
+       "syscall"
+       "unsafe"
+)
+
+var (
+       kernel32, _         = syscall.LoadLibrary("kernel32.dll")
+       procLockFileEx, _   = syscall.GetProcAddress(kernel32, "LockFileEx")
+       procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx")
+)
+
+const (
+       winLockfileFailImmediately = 0x00000001
+       winLockfileExclusiveLock   = 0x00000002
+       winLockfileSharedLock      = 0x00000000
+)
+
+// Use of 0x00000000 for the shared lock is a guess based on some the MS 
Windows
+// `LockFileEX` docs, which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as:
+//
+// > The function requests an exclusive lock. Otherwise, it requests a shared
+// > lock.
+//
+// 
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
+
+func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, 
numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset 
*syscall.Overlapped) (bool, syscall.Errno) {
+       r1, _, errNo := syscall.Syscall6(
+               uintptr(procLockFileEx),
+               6,
+               uintptr(handle),
+               uintptr(flags),
+               uintptr(reserved),
+               uintptr(numberOfBytesToLockLow),
+               uintptr(numberOfBytesToLockHigh),
+               uintptr(unsafe.Pointer(offset)))
+
+       if r1 != 1 {
+               if errNo == 0 {
+                       return false, syscall.EINVAL
+               }
+
+               return false, errNo
+       }
+
+       return true, 0
+}
+
+func unlockFileEx(handle syscall.Handle, reserved uint32, 
numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset 
*syscall.Overlapped) (bool, syscall.Errno) {
+       r1, _, errNo := syscall.Syscall6(
+               uintptr(procUnlockFileEx),
+               5,
+               uintptr(handle),
+               uintptr(reserved),
+               uintptr(numberOfBytesToLockLow),
+               uintptr(numberOfBytesToLockHigh),
+               uintptr(unsafe.Pointer(offset)),
+               0)
+
+       if r1 != 1 {
+               if errNo == 0 {
+                       return false, syscall.EINVAL
+               }
+
+               return false, errNo
+       }
+
+       return true, 0
+}
diff --git a/vendor/github.com/gofrs/flock/flock_windows.go 
b/vendor/github.com/gofrs/flock/flock_windows.go
new file mode 100644
index 0000000..9f4a5f1
--- /dev/null
+++ b/vendor/github.com/gofrs/flock/flock_windows.go
@@ -0,0 +1,140 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+package flock
+
+import (
+       "syscall"
+)
+
+// ErrorLockViolation is the error code returned from the Windows syscall when 
a
+// lock would block and you ask to fail immediately.
+const ErrorLockViolation syscall.Errno = 0x21 // 33
+
+// Lock is a blocking call to try and take an exclusive file lock. It will wait
+// until it is able to obtain the exclusive file lock. It's recommended that
+// TryLock() be used over this function. This function may block the ability to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+func (f *Flock) Lock() error {
+       return f.lock(&f.l, winLockfileExclusiveLock)
+}
+
+// RLock is a blocking call to try and take a shared file lock. It will wait
+// until it is able to obtain the shared file lock. It's recommended that
+// TryRLock() be used over this function. This function may block the ability 
to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+func (f *Flock) RLock() error {
+       return f.lock(&f.r, winLockfileSharedLock)
+}
+
+func (f *Flock) lock(locked *bool, flag uint32) error {
+       f.m.Lock()
+       defer f.m.Unlock()
+
+       if *locked {
+               return nil
+       }
+
+       if f.fh == nil {
+               if err := f.setFh(); err != nil {
+                       return err
+               }
+       }
+
+       if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag, 0, 1, 0, 
&syscall.Overlapped{}); errNo > 0 {
+               return errNo
+       }
+
+       *locked = true
+       return nil
+}
+
+// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
+// while it is running the Locked() and RLocked() functions will be blocked.
+//
+// This function short-circuits if we are unlocked already. If not, it calls
+// UnlockFileEx() on the file and closes the file descriptor. It does not 
remove
+// the file from disk. It's up to your application to do.
+func (f *Flock) Unlock() error {
+       f.m.Lock()
+       defer f.m.Unlock()
+
+       // if we aren't locked or if the lockfile instance is nil
+       // just return a nil error because we are unlocked
+       if (!f.l && !f.r) || f.fh == nil {
+               return nil
+       }
+
+       // mark the file as unlocked
+       if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, 
&syscall.Overlapped{}); errNo > 0 {
+               return errNo
+       }
+
+       f.fh.Close()
+
+       f.l = false
+       f.r = false
+       f.fh = nil
+
+       return nil
+}
+
+// TryLock is the preferred function for taking an exclusive file lock. This
+// function does take a RW-mutex lock before it tries to lock the file, so 
there
+// is the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the exclusive
+// file lock, the function will return false instead of waiting for the lock. 
If
+// we get the lock, we also set the *Flock instance as being exclusive-locked.
+func (f *Flock) TryLock() (bool, error) {
+       return f.try(&f.l, winLockfileExclusiveLock)
+}
+
+// TryRLock is the preferred function for taking a shared file lock. This
+// function does take a RW-mutex lock before it tries to lock the file, so 
there
+// is the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the shared 
file
+// lock, the function will return false instead of waiting for the lock. If we
+// get the lock, we also set the *Flock instance as being shared-locked.
+func (f *Flock) TryRLock() (bool, error) {
+       return f.try(&f.r, winLockfileSharedLock)
+}
+
+func (f *Flock) try(locked *bool, flag uint32) (bool, error) {
+       f.m.Lock()
+       defer f.m.Unlock()
+
+       if *locked {
+               return true, nil
+       }
+
+       if f.fh == nil {
+               if err := f.setFh(); err != nil {
+                       return false, err
+               }
+       }
+
+       _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), 
flag|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{})
+
+       if errNo > 0 {
+               if errNo == ErrorLockViolation || errNo == 
syscall.ERROR_IO_PENDING {
+                       return false, nil
+               }
+
+               return false, errNo
+       }
+
+       *locked = true
+
+       return true, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index d15237f..b2fda38 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -4,6 +4,8 @@ github.com/briandowns/spinner
 github.com/c-bata/go-prompt
 # github.com/fatih/color v1.7.0
 github.com/fatih/color
+# github.com/gofrs/flock v0.7.0
+github.com/gofrs/flock
 # github.com/google/shlex v0.0.0-20150127133951-6f45313302b9
 github.com/google/shlex
 # github.com/mattn/go-colorable v0.0.9

Reply via email to