git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/singleinstance/singleinstance.go (about)

     1  // Package singleinstance provides a mechanism to ensure, that only one instance of a program is running
     2  package singleinstance
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  )
    10  
    11  // Option configures Single
    12  type Option func(*SingleInstance)
    13  
    14  // WithLockPath configures the path for the lockfile
    15  func WithLockPath(lockpath string) Option {
    16  	return func(s *SingleInstance) {
    17  		s.path = lockpath
    18  	}
    19  }
    20  
    21  var (
    22  	// ErrAlreadyRunning another instance of is already running
    23  	ErrAlreadyRunning = errors.New("another instance is already running")
    24  )
    25  
    26  // SingleInstance represents the name and the open file descriptor
    27  type SingleInstance struct {
    28  	name string
    29  	path string
    30  	file *os.File
    31  }
    32  
    33  // New creates a SingleInstance instance where name is the basename of the lock file (<name>.lock)
    34  // if no path is given (WithLockPath option) the lock will be created in an operating specific path as <name>.lock
    35  // panics if namr is empty
    36  func New(name string, opts ...Option) *SingleInstance {
    37  	if name == "" {
    38  		panic("singleinstance: name cannot be empty")
    39  	}
    40  
    41  	s := &SingleInstance{
    42  		name: name,
    43  	}
    44  
    45  	for _, o := range opts {
    46  		o(s)
    47  	}
    48  
    49  	if s.path == "" {
    50  		s.path = os.TempDir()
    51  	}
    52  
    53  	return s
    54  }
    55  
    56  // Lockfile returns the full path of the lock file
    57  func (s *SingleInstance) Lockfile() string {
    58  	return filepath.Join(s.path, fmt.Sprintf("%s.lock", s.name))
    59  }