|
| 1 | +package generic |
| 2 | + |
| 3 | +import ( |
| 4 | + "flag" |
| 5 | + "fmt" |
| 6 | + "github.com/google/shlex" |
| 7 | + "strconv" |
| 8 | + "strings" |
| 9 | +) |
| 10 | + |
| 11 | +type CommentParts struct { |
| 12 | + Projects []string |
| 13 | + Layer int |
| 14 | + Directories []string |
| 15 | +} |
| 16 | + |
| 17 | +type multiFlag []string |
| 18 | + |
| 19 | +func (m *multiFlag) String() string { |
| 20 | + return strings.Join(*m, ",") |
| 21 | +} |
| 22 | + |
| 23 | +func (m *multiFlag) Set(value string) error { |
| 24 | + *m = append(*m, value) |
| 25 | + return nil |
| 26 | +} |
| 27 | + |
| 28 | +// singleUseInt rejects multiple occurrences of the same flag. |
| 29 | +type singleUseInt struct { |
| 30 | + val int |
| 31 | + seen bool |
| 32 | + name string // for better error messages |
| 33 | +} |
| 34 | + |
| 35 | +func (s *singleUseInt) String() string { return strconv.Itoa(s.val) } |
| 36 | +func (s *singleUseInt) Set(v string) error { |
| 37 | + if s.seen { |
| 38 | + return fmt.Errorf("--%s specified multiple times", s.name) |
| 39 | + } |
| 40 | + i, err := strconv.Atoi(v) |
| 41 | + if err != nil { |
| 42 | + return fmt.Errorf("invalid value for --%s: %w", s.name, err) |
| 43 | + } |
| 44 | + s.val = i |
| 45 | + s.seen = true |
| 46 | + return nil |
| 47 | +} |
| 48 | + |
| 49 | +// ParseDiggerCommentFlags parse the flags in the comment such as -p and -d and --layer |
| 50 | +// validates that the right number of flags are specified |
| 51 | +// Does not validate the "digger plan" part of the command that is left to a prior function |
| 52 | +func ParseDiggerCommentFlags(comment string) (*CommentParts, bool, error) { |
| 53 | + comment = strings.TrimSpace(strings.ToLower(comment)) |
| 54 | + |
| 55 | + args, err := shlex.Split(comment) |
| 56 | + if err != nil { |
| 57 | + return nil, false, fmt.Errorf("failed to split input %v", err) |
| 58 | + |
| 59 | + } |
| 60 | + |
| 61 | + if len(args) < 2 { |
| 62 | + return nil, false, fmt.Errorf("incorrect operation specified: (%v) err: %v", comment, err) |
| 63 | + } |
| 64 | + |
| 65 | + fs := flag.NewFlagSet("digger", flag.ContinueOnError) |
| 66 | + |
| 67 | + var projects multiFlag |
| 68 | + var directories multiFlag |
| 69 | + layer := &singleUseInt{val: -1, name: "layer"} |
| 70 | + |
| 71 | + fs.Var(&projects, "p", "project (short form)") |
| 72 | + fs.Var(&projects, "project", "project (long form)") |
| 73 | + |
| 74 | + fs.Var(&directories, "d", "directory (short form)") |
| 75 | + fs.Var(&directories, "directory", "directory (long form)") |
| 76 | + |
| 77 | + fs.Var(layer, "layer", "layer to plan or apply") |
| 78 | + |
| 79 | + err = fs.Parse(args[2:]) |
| 80 | + if err != nil { |
| 81 | + return nil, false, fmt.Errorf("failed to parse input %v", comment) |
| 82 | + } |
| 83 | + |
| 84 | + // ❗ Disallow mixing --layer with -p or -d |
| 85 | + if layer.val != -1 && (len(projects) > 0 || len(directories) > 0) { |
| 86 | + return nil, false, fmt.Errorf("cannot mix --layer with -p or -d") |
| 87 | + } |
| 88 | + |
| 89 | + return &CommentParts{ |
| 90 | + Projects: projects, |
| 91 | + Layer: layer.val, |
| 92 | + Directories: directories, |
| 93 | + }, true, nil |
| 94 | +} |
0 commit comments