diff --git a/plan/command/add.go b/plan/command/add.go index 028b104..42592ed 100644 --- a/plan/command/add.go +++ b/plan/command/add.go @@ -20,8 +20,7 @@ type AddCmd struct { localIDRepo storage.LocalID eventRepo storage.Event syncRepo storage.Sync - title string - flags map[string]Flag + argSet *ArgSet } func NewAddCmd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { @@ -29,35 +28,38 @@ func NewAddCmd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo stor localIDRepo: localRepo, eventRepo: eventRepo, syncRepo: syncRepo, - flags: map[string]Flag{ - FlagOn: &FlagDate{}, - FlagAt: &FlagTime{}, - FlagFor: &FlagDuration{}, + argSet: &ArgSet{ + Flags: map[string]Flag{ + FlagOn: &FlagDate{}, + FlagAt: &FlagTime{}, + FlagFor: &FlagDuration{}, + }, }, } } -func (add *AddCmd) Parse(as *ArgSet) error { - if len(as.Main) == 0 || as.Main[0] != "add " { +func (add *AddCmd) Parse(main []string, flags map[string]string) error { + if len(main) == 0 || main[0] != "add " { return ErrWrongCommand } - add.title = strings.Join(as.Main[1:], " ") - for k := range add.flags { - if err := add.flags[k].Set(as.Flags[k]); err != nil { + as := add.argSet + as.Main = strings.Join(main[1:], " ") + for k := range as.Flags { + if err := as.Set(k, flags[k]); err != nil { return fmt.Errorf("could not set %s: %v", k, err) } } - if add.title == "" { + if as.Main == "" { return fmt.Errorf("%w: title is required", ErrInvalidArg) } - if !add.flags[FlagOn].IsSet() { + if !as.IsSet(FlagOn) { return fmt.Errorf("%w: date is required", ErrInvalidArg) } - if !add.flags[FlagAt].IsSet() && add.flags[FlagFor].IsSet() { + if !as.IsSet(FlagAt) && as.IsSet(FlagFor) { return fmt.Errorf("%w: can not have duration without start time", ErrInvalidArg) } - if !add.flags[FlagAt].IsSet() && !add.flags[FlagFor].IsSet() { - if err := add.flags[FlagFor].Set("24h"); err != nil { + if !as.IsSet(FlagAt) && !as.IsSet(FlagFor) { + if err := as.Flags[FlagFor].Set("24h"); err != nil { return fmt.Errorf("could not set duration to 24 hours") } } @@ -66,15 +68,13 @@ func (add *AddCmd) Parse(as *ArgSet) error { } func (add *AddCmd) Do() error { - startFormat := "2006-01-02" - startStr := as.Flag(FlagOn) - if as.HasFlag(FlagAt) { - startFormat = fmt.Sprintf("%s 15:04", startFormat) - startStr = fmt.Sprintf("%s %s", startStr, as.Flag(FlagAt)) - } - start, err := time.Parse(startFormat, startStr) - if err != nil { - return fmt.Errorf("%w: could not parse start time and date: %v", ErrInvalidArg, err) + as := add.argSet + start := as.GetTime(FlagOn) + if as.IsSet(FlagAt) { + at := as.GetTime(FlagAt) + h := time.Duration(at.Hour()) * time.Hour + m := time.Duration(at.Minute()) * time.Minute + start = start.Add(h).Add(m) } e := item.Event{ @@ -85,12 +85,8 @@ func (add *AddCmd) Do() error { }, } - if as.HasFlag(FlagFor) { - fr, err := time.ParseDuration(as.Flag(FlagFor)) - if err != nil { - return fmt.Errorf("%w: could not parse duration: %s", ErrInvalidArg, err) - } - e.Duration = fr + if as.IsSet(FlagFor) { + e.Duration = as.GetDuration(FlagFor) } if err := add.eventRepo.Store(e); err != nil { return fmt.Errorf("could not store event: %v", err) diff --git a/plan/command/argset.go b/plan/command/argset.go new file mode 100644 index 0000000..138b80d --- /dev/null +++ b/plan/command/argset.go @@ -0,0 +1,63 @@ +package command + +import ( + "fmt" + "time" +) + +type ArgSet struct { + Main string + Flags map[string]Flag +} + +func (as *ArgSet) Set(name, val string) error { + f, ok := as.Flags[name] + if !ok { + return fmt.Errorf("unknown flag %s", name) + } + return f.Set(val) +} + +func (as *ArgSet) IsSet(name string) bool { + f, ok := as.Flags[name] + if !ok { + return false + } + return f.IsSet() +} + +func (as *ArgSet) GetString(name string) string { + flag, ok := as.Flags[name] + if !ok { + return "" + } + val, ok := flag.Get().(string) + if !ok { + return "" + } + return val +} + +func (as *ArgSet) GetTime(name string) time.Time { + flag, ok := as.Flags[name] + if !ok { + return time.Time{} + } + val, ok := flag.Get().(time.Time) + if !ok { + return time.Time{} + } + return val +} + +func (as *ArgSet) GetDuration(name string) time.Duration { + flag, ok := as.Flags[name] + if !ok { + return time.Duration(0) + } + val, ok := flag.Get().(time.Duration) + if !ok { + return time.Duration(0) + } + return val +} diff --git a/plan/command/command.go b/plan/command/command.go index 4beaae1..4d47c69 100644 --- a/plan/command/command.go +++ b/plan/command/command.go @@ -6,13 +6,8 @@ import ( "strings" ) -type ArgSet struct { - Main []string - Flags map[string]string -} - type Command interface { - Parse(args *ArgSet) error + Parse([]string, map[string]string) error Do() error } @@ -21,12 +16,12 @@ type CLI struct { } func (cli *CLI) Run(args []string) error { - as, err := ParseFlags(args) + main, flags, err := ParseFlags(args) if err != nil { return err } for _, c := range cli.Commands { - err := c.Parse(as) + err := c.Parse(main, flags) switch { case errors.Is(err, ErrWrongCommand): continue @@ -40,7 +35,7 @@ func (cli *CLI) Run(args []string) error { return fmt.Errorf("could not find matching command") } -func ParseFlags(args []string) (*ArgSet, error) { +func ParseFlags(args []string) ([]string, map[string]string, error) { flags := make(map[string]string) main := make([]string, 0) var inMain bool @@ -48,7 +43,7 @@ func ParseFlags(args []string) (*ArgSet, error) { if strings.HasPrefix(args[i], "-") { inMain = false if i+1 >= len(args) { - return nil, fmt.Errorf("flag wihout value") + return nil, nil, fmt.Errorf("flag wihout value") } flags[strings.TrimPrefix(args[i], "-")] = args[i+1] i++ @@ -56,14 +51,11 @@ func ParseFlags(args []string) (*ArgSet, error) { } if !inMain && len(main) > 0 { - return nil, fmt.Errorf("two mains") + return nil, nil, fmt.Errorf("two mains") } inMain = true main = append(main, args[i]) } - return &ArgSet{ - Main: main, - Flags: flags, - }, nil + return main, flags, nil } diff --git a/plan/command/flag.go b/plan/command/flag.go index fe6848c..b8ea3c5 100644 --- a/plan/command/flag.go +++ b/plan/command/flag.go @@ -19,6 +19,7 @@ var ( type Flag interface { Set(val string) error IsSet() bool + Get() any } type FlagString struct { @@ -35,6 +36,10 @@ func (fs *FlagString) IsSet() bool { return fs.Value != "" } +func (fs *FlagString) Get() any { + return fs.Value +} + type FlagDate struct { Name string Value time.Time @@ -54,6 +59,10 @@ func (ft *FlagDate) IsSet() bool { return ft.Value.IsZero() } +func (fs *FlagDate) Get() any { + return fs.Value +} + type FlagTime struct { Name string Value time.Time @@ -73,6 +82,10 @@ func (fd *FlagTime) IsSet() bool { return fd.Value.IsZero() } +func (fs *FlagTime) Get() any { + return fs.Value +} + type FlagDuration struct { Name string Value time.Duration @@ -90,3 +103,7 @@ func (fd *FlagDuration) Set(val string) error { func (fd *FlagDuration) IsSet() bool { return fd.Value.String() != "0s" } + +func (fs *FlagDuration) Get() any { + return fs.Value +}