...
1 package main
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "os"
8 "strings"
9 "time"
10
11 "github.com/sirupsen/logrus"
12 "github.com/urfave/cli"
13 )
14
15 const (
16 pathsFlag = "paths"
17 timeoutFlag = "timeout"
18 )
19
20 var errEmptyPaths = errors.New("paths cannot be empty")
21
22
23
24
25 func main() {
26 app := newCliApp()
27 if err := app.Run(os.Args); err != nil {
28 logrus.Fatalf("%s\n", err)
29 }
30 os.Exit(0)
31 }
32
33 func newCliApp() *cli.App {
34 app := cli.NewApp()
35 app.Name = "wait-paths"
36 app.Usage = "Provide a list paths and an optional timeout"
37 app.Flags = []cli.Flag{
38 cli.StringFlag{
39 Name: pathsFlag + ",p",
40 Usage: "Comma-separated list of paths that should become available",
41 Required: true,
42 },
43 cli.IntFlag{
44 Name: timeoutFlag + ",t",
45 Usage: "Timeout in seconds",
46 Value: 30,
47 },
48 }
49 app.Action = run
50 return app
51 }
52
53 func run(cCtx *cli.Context) error {
54 timeout := cCtx.GlobalInt(timeoutFlag)
55
56 pathsVal := cCtx.GlobalString(pathsFlag)
57 if pathsVal == "" {
58 return errEmptyPaths
59 }
60 paths := strings.Split(cCtx.GlobalString(pathsFlag), ",")
61
62 waitCtx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
63 defer cancel()
64
65 for _, path := range paths {
66 for {
67 if _, err := os.Stat(path); err != nil {
68 if !os.IsNotExist(err) {
69 return err
70 }
71 select {
72 case <-waitCtx.Done():
73 return fmt.Errorf("timeout while waiting for path %q to appear: %w", path, context.DeadlineExceeded)
74 default:
75 time.Sleep(time.Millisecond * 10)
76 continue
77 }
78 }
79 break
80 }
81 }
82 return nil
83 }
84
View as plain text