diff --git a/vendor/github.com/marcsauter/single/LICENSE b/vendor/github.com/marcsauter/single/LICENSE new file mode 100644 index 00000000..97b81c5f --- /dev/null +++ b/vendor/github.com/marcsauter/single/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Marc Sauter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/marcsauter/single/README.md b/vendor/github.com/marcsauter/single/README.md new file mode 100644 index 00000000..33281fa8 --- /dev/null +++ b/vendor/github.com/marcsauter/single/README.md @@ -0,0 +1,29 @@ +# single + +`single` provides a mechanism to ensure, that only one instance of a program is running. + + package main + + import ( + "log" + "time" + + "github.com/marcsauter/single" + ) + + func main() { + s := single.New("your-app-name") + if err := s.CheckLock(); err != nil && err == single.ErrAlreadyRunning { + log.Fatal("another instance of the app is already running, exiting") + } else if err != nil { + // Another error occurred, might be worth handling it as well + log.Fatalf("failed to acquire exclusive app lock: %v", err) + } + defer s.TryUnlock() + + log.Println("working") + time.Sleep(60 * time.Second) + log.Println("finished") + } + +The package currently supports `linux`, `solaris` and `windows`. diff --git a/vendor/github.com/marcsauter/single/single.go b/vendor/github.com/marcsauter/single/single.go new file mode 100644 index 00000000..e8173e66 --- /dev/null +++ b/vendor/github.com/marcsauter/single/single.go @@ -0,0 +1,41 @@ +// package single provides a mechanism to ensure, that only one instance of a program is running + +package single + +import ( + "errors" + "log" + "os" +) + +var ( + // ErrAlreadyRunning -- the instance is already running + ErrAlreadyRunning = errors.New("the program is already running") + // Lockfile -- the lock file to check + Lockfile string +) + +// Single represents the name and the open file descriptor +type Single struct { + name string + file *os.File +} + +// New creates a Single instance +func New(name string) *Single { + return &Single{name: name} +} + +// Lock tries to obtain an exclude lock on a lockfile and exits the program if an error occurs +func (s *Single) Lock() { + if err := s.CheckLock(); err != nil { + log.Fatal(err) + } +} + +// Unlock releases the lock, closes and removes the lockfile. All errors will be reported directly. +func (s *Single) Unlock() { + if err := s.TryUnlock(); err != nil { + log.Print(err) + } +} diff --git a/vendor/github.com/marcsauter/single/single_bsd.go b/vendor/github.com/marcsauter/single/single_bsd.go new file mode 100644 index 00000000..58c35c76 --- /dev/null +++ b/vendor/github.com/marcsauter/single/single_bsd.go @@ -0,0 +1,16 @@ +// +build freebsd openbsd netbsd dragonfly + +package single + +import ( + "fmt" + "path/filepath" +) + +// Filename returns an absolute filename, appropriate for the operating system +func (s *Single) Filename() string { + if len(Lockfile) > 0 { + return Lockfile + } + return filepath.Join("/var/run", fmt.Sprintf("%s.lock", s.name)) +} diff --git a/vendor/github.com/marcsauter/single/single_darwin.go b/vendor/github.com/marcsauter/single/single_darwin.go new file mode 100644 index 00000000..60e27721 --- /dev/null +++ b/vendor/github.com/marcsauter/single/single_darwin.go @@ -0,0 +1,15 @@ +package single + +import ( + "fmt" + "os" + "path/filepath" +) + +// Filename returns an absolute filename, appropriate for the operating system +func (s *Single) Filename() string { + if len(Lockfile) > 0 { + return Lockfile + } + return filepath.Join(os.TempDir(), fmt.Sprintf("%s.lock", s.name)) +} diff --git a/vendor/github.com/marcsauter/single/single_linux.go b/vendor/github.com/marcsauter/single/single_linux.go new file mode 100644 index 00000000..2523c9c6 --- /dev/null +++ b/vendor/github.com/marcsauter/single/single_linux.go @@ -0,0 +1,14 @@ +package single + +import ( + "fmt" + "path/filepath" +) + +// Filename returns an absolute filename, appropriate for the operating system +func (s *Single) Filename() string { + if len(Lockfile) > 0 { + return Lockfile + } + return filepath.Join("/var/lock", fmt.Sprintf("%s.lock", s.name)) +} diff --git a/vendor/github.com/marcsauter/single/single_solaris.go b/vendor/github.com/marcsauter/single/single_solaris.go new file mode 100644 index 00000000..e4629f86 --- /dev/null +++ b/vendor/github.com/marcsauter/single/single_solaris.go @@ -0,0 +1,14 @@ +package single + +import ( + "fmt" + "path/filepath" +) + +// Filename returns an absolute filename, appropriate for the operating system +func (s *Single) Filename() string { + if len(Lockfile) > 0 { + return Lockfile + } + return filepath.Join("/var/run", fmt.Sprintf("%s.lock", s.name)) +} diff --git a/vendor/github.com/marcsauter/single/single_unix.go b/vendor/github.com/marcsauter/single/single_unix.go new file mode 100644 index 00000000..30545f1f --- /dev/null +++ b/vendor/github.com/marcsauter/single/single_unix.go @@ -0,0 +1,50 @@ +// +build linux solaris darwin freebsd openbsd netbsd dragonfly + +package single + +import ( + "fmt" + "os" + "syscall" +) + +// CheckLock tries to obtain an exclude lock on a lockfile and returns an error if one occurs +func (s *Single) CheckLock() error { + + // open/create lock file + f, err := os.OpenFile(s.Filename(), os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + return err + } + s.file = f + // set the lock type to F_WRLCK, therefor the file has to be opened writable + flock := syscall.Flock_t{ + Type: syscall.F_WRLCK, + Pid: int32(os.Getpid()), + } + // try to obtain an exclusive lock - FcntlFlock seems to be the portable *ix way + if err := syscall.FcntlFlock(s.file.Fd(), syscall.F_SETLK, &flock); err != nil { + return ErrAlreadyRunning + } + + return nil +} + +// TryUnlock unlocks, closes and removes the lockfile +func (s *Single) TryUnlock() error { + // set the lock type to F_UNLCK + flock := syscall.Flock_t{ + Type: syscall.F_UNLCK, + Pid: int32(os.Getpid()), + } + if err := syscall.FcntlFlock(s.file.Fd(), syscall.F_SETLK, &flock); err != nil { + return fmt.Errorf("failed to unlock the lock file: %v", err) + } + if err := s.file.Close(); err != nil { + return fmt.Errorf("failed to close the lock file: %v", err) + } + if err := os.Remove(s.Filename()); err != nil { + return fmt.Errorf("failed to remove the lock file: %v", err) + } + return nil +} diff --git a/vendor/github.com/marcsauter/single/single_windows.go b/vendor/github.com/marcsauter/single/single_windows.go new file mode 100644 index 00000000..1f883481 --- /dev/null +++ b/vendor/github.com/marcsauter/single/single_windows.go @@ -0,0 +1,44 @@ +// +build windows + +package single + +import ( + "fmt" + "os" + "path/filepath" +) + +// Filename returns an absolute filename, appropriate for the operating system +func (s *Single) Filename() string { + if len(Lockfile) > 0 { + return Lockfile + } + return filepath.Join(os.TempDir(), fmt.Sprintf("%s.lock", s.name)) +} + +// CheckLock tries to obtain an exclude lock on a lockfile and returns an error if one occurs +func (s *Single) CheckLock() error { + + if err := os.Remove(s.Filename()); err != nil && !os.IsNotExist(err) { + return ErrAlreadyRunning + } + + file, err := os.OpenFile(s.Filename(), os.O_EXCL|os.O_CREATE, 0600) + if err != nil { + return err + } + s.file = file + + return nil +} + +// TryUnlock closes and removes the lockfile +func (s *Single) TryUnlock() error { + if err := s.file.Close(); err != nil { + return fmt.Errorf("failed to close the lock file: %v", err) + } + if err := os.Remove(s.Filename()); err != nil { + return fmt.Errorf("failed to remove the lock file: %v", err) + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b19b1753..f1ae5f72 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -143,6 +143,8 @@ github.com/kyokomi/emoji github.com/logrusorgru/aurora # github.com/magiconair/properties v1.8.1 github.com/magiconair/properties +# github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0 +github.com/marcsauter/single # github.com/mattn/go-colorable v0.1.2 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.10