github.com/blend/go-sdk@v1.20220411.3/cmd/fslock/main.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package main
     9  
    10  import (
    11  	"context"
    12  	"flag"
    13  	"fmt"
    14  	"os"
    15  	"time"
    16  
    17  	"github.com/blend/go-sdk/filelock"
    18  )
    19  
    20  var (
    21  	flagExclusive = flag.Bool("exclusive", false, "If the lock is exclusive or not")
    22  	flagRemove    = flag.Bool("remove", false, "If the lock file should be removed when complete")
    23  	flagWaitFor   = flag.Duration("wait-for", 10*time.Second, "The duration to hold the lock for")
    24  	flagHoldFor   = flag.Duration("hold-for", 10*time.Second, "The duration to hold the lock for")
    25  )
    26  
    27  func init() {
    28  	flag.Parse()
    29  }
    30  
    31  func main() {
    32  	filePath := flag.Arg(0)
    33  	if filePath == "" {
    34  		fmt.Fprintf(os.Stderr, "Must provide a filepath; see usage for details")
    35  		os.Exit(1)
    36  	}
    37  
    38  	mu := filelock.MutexAt(filePath)
    39  
    40  	var lockfn func() (func(), error)
    41  	if *flagExclusive {
    42  		lockfn = mu.Lock
    43  	} else {
    44  		lockfn = mu.RLock
    45  	}
    46  
    47  	unlock, err := waitAcquired(lockfn, *flagWaitFor)
    48  	if err != nil {
    49  		fmt.Fprintf(os.Stderr, "Error acquiring lock for file %q; %+v\n", filePath, err)
    50  		os.Exit(1)
    51  	}
    52  	defer func() {
    53  		unlock()
    54  		if *flagRemove {
    55  			fmt.Println("Removing lock file", filePath)
    56  			_ = os.Remove(filePath)
    57  		}
    58  	}()
    59  
    60  	fmt.Println("Acquired lock", filePath, "holding for", *flagHoldFor)
    61  	<-time.After(*flagHoldFor)
    62  }
    63  
    64  func waitAcquired(lockfn func() (func(), error), waitFor time.Duration) (unlock func(), err error) {
    65  	finished := make(chan struct{})
    66  	go func() {
    67  		defer close(finished)
    68  		unlock, err = lockfn()
    69  	}()
    70  	select {
    71  	case <-finished:
    72  		return
    73  	case <-time.After(waitFor):
    74  		err = context.Canceled
    75  		return
    76  	}
    77  }