1package command
2
3import (
4	"errors"
5	"flag"
6	"fmt"
7	"os"
8	"sort"
9	"strconv"
10	"strings"
11	"time"
12
13	"github.com/posener/complete"
14)
15
16// FlagExample is an interface which declares an example value.
17type FlagExample interface {
18	Example() string
19}
20
21// FlagVisibility is an interface which declares whether a flag should be
22// hidden from help and completions. This is usually used for deprecations
23// on "internal-only" flags.
24type FlagVisibility interface {
25	Hidden() bool
26}
27
28// FlagBool is an interface which boolean flags implement.
29type FlagBool interface {
30	IsBoolFlag() bool
31}
32
33// BoolPtr is a bool which is aware if it has been set.
34type BoolPtr struct {
35	v *bool
36}
37
38func (b *BoolPtr) Set(v string) error {
39	val, err := strconv.ParseBool(v)
40	if err != nil {
41		return err
42	}
43
44	if b.v == nil {
45		b.v = new(bool)
46	}
47	*b.v = val
48
49	return nil
50}
51
52func (b *BoolPtr) IsSet() bool {
53	return b.v != nil
54}
55
56func (b *BoolPtr) Get() bool {
57	if b.v == nil {
58		return false
59	}
60	return *b.v
61}
62
63func (b *BoolPtr) String() string {
64	var current bool
65	if b.v != nil {
66		current = *(b.v)
67	}
68	return fmt.Sprintf("%v", current)
69}
70
71type boolPtrValue struct {
72	hidden bool
73	target *BoolPtr
74}
75
76func newBoolPtrValue(def *bool, target *BoolPtr, hidden bool) *boolPtrValue {
77	val := &boolPtrValue{
78		hidden: hidden,
79		target: target,
80	}
81	if def != nil {
82		_ = val.target.Set(strconv.FormatBool(*def))
83	}
84	return val
85}
86
87func (b *boolPtrValue) IsBoolFlag() bool {
88	return true
89}
90
91func (b *boolPtrValue) Set(s string) error {
92	if b.target == nil {
93		b.target = new(BoolPtr)
94	}
95	return b.target.Set(s)
96}
97
98func (b *boolPtrValue) Get() interface{} { return *b.target }
99func (b *boolPtrValue) String() string   { return b.target.String() }
100func (b *boolPtrValue) Example() string  { return "*bool" }
101func (b *boolPtrValue) Hidden() bool     { return b.hidden }
102
103type BoolPtrVar struct {
104	Name       string
105	Aliases    []string
106	Usage      string
107	Hidden     bool
108	EnvVar     string
109	Default    *bool
110	Target     *BoolPtr
111	Completion complete.Predictor
112}
113
114func (f *FlagSet) BoolPtrVar(i *BoolPtrVar) {
115	def := i.Default
116	if v, exist := os.LookupEnv(i.EnvVar); exist {
117		if b, err := strconv.ParseBool(v); err == nil {
118			if def == nil {
119				def = new(bool)
120			}
121			*def = b
122		}
123	}
124
125	f.VarFlag(&VarFlag{
126		Name:       i.Name,
127		Aliases:    i.Aliases,
128		Usage:      i.Usage,
129		Value:      newBoolPtrValue(i.Default, i.Target, i.Hidden),
130		Completion: i.Completion,
131	})
132}
133
134// -- BoolVar  and boolValue
135type BoolVar struct {
136	Name       string
137	Aliases    []string
138	Usage      string
139	Default    bool
140	Hidden     bool
141	EnvVar     string
142	Target     *bool
143	Completion complete.Predictor
144}
145
146func (f *FlagSet) BoolVar(i *BoolVar) {
147	def := i.Default
148	if v, exist := os.LookupEnv(i.EnvVar); exist {
149		if b, err := strconv.ParseBool(v); err == nil {
150			def = b
151		}
152	}
153
154	f.VarFlag(&VarFlag{
155		Name:       i.Name,
156		Aliases:    i.Aliases,
157		Usage:      i.Usage,
158		Default:    strconv.FormatBool(i.Default),
159		EnvVar:     i.EnvVar,
160		Value:      newBoolValue(def, i.Target, i.Hidden),
161		Completion: i.Completion,
162	})
163}
164
165type boolValue struct {
166	hidden bool
167	target *bool
168}
169
170func newBoolValue(def bool, target *bool, hidden bool) *boolValue {
171	*target = def
172
173	return &boolValue{
174		hidden: hidden,
175		target: target,
176	}
177}
178
179func (b *boolValue) Set(s string) error {
180	v, err := strconv.ParseBool(s)
181	if err != nil {
182		return err
183	}
184
185	*b.target = v
186	return nil
187}
188
189func (b *boolValue) Get() interface{} { return *b.target }
190func (b *boolValue) String() string   { return strconv.FormatBool(*b.target) }
191func (b *boolValue) Example() string  { return "" }
192func (b *boolValue) Hidden() bool     { return b.hidden }
193func (b *boolValue) IsBoolFlag() bool { return true }
194
195// -- IntVar and intValue
196type IntVar struct {
197	Name       string
198	Aliases    []string
199	Usage      string
200	Default    int
201	Hidden     bool
202	EnvVar     string
203	Target     *int
204	Completion complete.Predictor
205}
206
207func (f *FlagSet) IntVar(i *IntVar) {
208	initial := i.Default
209	if v, exist := os.LookupEnv(i.EnvVar); exist {
210		if i, err := strconv.ParseInt(v, 0, 64); err == nil {
211			initial = int(i)
212		}
213	}
214
215	def := ""
216	if i.Default != 0 {
217		def = strconv.FormatInt(int64(i.Default), 10)
218	}
219
220	f.VarFlag(&VarFlag{
221		Name:       i.Name,
222		Aliases:    i.Aliases,
223		Usage:      i.Usage,
224		Default:    def,
225		EnvVar:     i.EnvVar,
226		Value:      newIntValue(initial, i.Target, i.Hidden),
227		Completion: i.Completion,
228	})
229}
230
231type intValue struct {
232	hidden bool
233	target *int
234}
235
236func newIntValue(def int, target *int, hidden bool) *intValue {
237	*target = def
238	return &intValue{
239		hidden: hidden,
240		target: target,
241	}
242}
243
244func (i *intValue) Set(s string) error {
245	v, err := strconv.ParseInt(s, 0, 64)
246	if err != nil {
247		return err
248	}
249
250	*i.target = int(v)
251	return nil
252}
253
254func (i *intValue) Get() interface{} { return int(*i.target) }
255func (i *intValue) String() string   { return strconv.Itoa(int(*i.target)) }
256func (i *intValue) Example() string  { return "int" }
257func (i *intValue) Hidden() bool     { return i.hidden }
258
259// -- Int64Var and int64Value
260type Int64Var struct {
261	Name       string
262	Aliases    []string
263	Usage      string
264	Default    int64
265	Hidden     bool
266	EnvVar     string
267	Target     *int64
268	Completion complete.Predictor
269}
270
271func (f *FlagSet) Int64Var(i *Int64Var) {
272	initial := i.Default
273	if v, exist := os.LookupEnv(i.EnvVar); exist {
274		if i, err := strconv.ParseInt(v, 0, 64); err == nil {
275			initial = i
276		}
277	}
278
279	def := ""
280	if i.Default != 0 {
281		def = strconv.FormatInt(int64(i.Default), 10)
282	}
283
284	f.VarFlag(&VarFlag{
285		Name:       i.Name,
286		Aliases:    i.Aliases,
287		Usage:      i.Usage,
288		Default:    def,
289		EnvVar:     i.EnvVar,
290		Value:      newInt64Value(initial, i.Target, i.Hidden),
291		Completion: i.Completion,
292	})
293}
294
295type int64Value struct {
296	hidden bool
297	target *int64
298}
299
300func newInt64Value(def int64, target *int64, hidden bool) *int64Value {
301	*target = def
302	return &int64Value{
303		hidden: hidden,
304		target: target,
305	}
306}
307
308func (i *int64Value) Set(s string) error {
309	v, err := strconv.ParseInt(s, 0, 64)
310	if err != nil {
311		return err
312	}
313
314	*i.target = v
315	return nil
316}
317
318func (i *int64Value) Get() interface{} { return int64(*i.target) }
319func (i *int64Value) String() string   { return strconv.FormatInt(int64(*i.target), 10) }
320func (i *int64Value) Example() string  { return "int" }
321func (i *int64Value) Hidden() bool     { return i.hidden }
322
323// -- UintVar && uintValue
324type UintVar struct {
325	Name       string
326	Aliases    []string
327	Usage      string
328	Default    uint
329	Hidden     bool
330	EnvVar     string
331	Target     *uint
332	Completion complete.Predictor
333}
334
335func (f *FlagSet) UintVar(i *UintVar) {
336	initial := i.Default
337	if v, exist := os.LookupEnv(i.EnvVar); exist {
338		if i, err := strconv.ParseUint(v, 0, 64); err == nil {
339			initial = uint(i)
340		}
341	}
342
343	def := ""
344	if i.Default != 0 {
345		def = strconv.FormatUint(uint64(i.Default), 10)
346	}
347
348	f.VarFlag(&VarFlag{
349		Name:       i.Name,
350		Aliases:    i.Aliases,
351		Usage:      i.Usage,
352		Default:    def,
353		EnvVar:     i.EnvVar,
354		Value:      newUintValue(initial, i.Target, i.Hidden),
355		Completion: i.Completion,
356	})
357}
358
359type uintValue struct {
360	hidden bool
361	target *uint
362}
363
364func newUintValue(def uint, target *uint, hidden bool) *uintValue {
365	*target = def
366	return &uintValue{
367		hidden: hidden,
368		target: target,
369	}
370}
371
372func (i *uintValue) Set(s string) error {
373	v, err := strconv.ParseUint(s, 0, 64)
374	if err != nil {
375		return err
376	}
377
378	*i.target = uint(v)
379	return nil
380}
381
382func (i *uintValue) Get() interface{} { return uint(*i.target) }
383func (i *uintValue) String() string   { return strconv.FormatUint(uint64(*i.target), 10) }
384func (i *uintValue) Example() string  { return "uint" }
385func (i *uintValue) Hidden() bool     { return i.hidden }
386
387// -- Uint64Var and uint64Value
388type Uint64Var struct {
389	Name       string
390	Aliases    []string
391	Usage      string
392	Default    uint64
393	Hidden     bool
394	EnvVar     string
395	Target     *uint64
396	Completion complete.Predictor
397}
398
399func (f *FlagSet) Uint64Var(i *Uint64Var) {
400	initial := i.Default
401	if v, exist := os.LookupEnv(i.EnvVar); exist {
402		if i, err := strconv.ParseUint(v, 0, 64); err == nil {
403			initial = i
404		}
405	}
406
407	def := ""
408	if i.Default != 0 {
409		strconv.FormatUint(i.Default, 10)
410	}
411
412	f.VarFlag(&VarFlag{
413		Name:       i.Name,
414		Aliases:    i.Aliases,
415		Usage:      i.Usage,
416		Default:    def,
417		EnvVar:     i.EnvVar,
418		Value:      newUint64Value(initial, i.Target, i.Hidden),
419		Completion: i.Completion,
420	})
421}
422
423type uint64Value struct {
424	hidden bool
425	target *uint64
426}
427
428func newUint64Value(def uint64, target *uint64, hidden bool) *uint64Value {
429	*target = def
430	return &uint64Value{
431		hidden: hidden,
432		target: target,
433	}
434}
435
436func (i *uint64Value) Set(s string) error {
437	v, err := strconv.ParseUint(s, 0, 64)
438	if err != nil {
439		return err
440	}
441
442	*i.target = v
443	return nil
444}
445
446func (i *uint64Value) Get() interface{} { return uint64(*i.target) }
447func (i *uint64Value) String() string   { return strconv.FormatUint(uint64(*i.target), 10) }
448func (i *uint64Value) Example() string  { return "uint" }
449func (i *uint64Value) Hidden() bool     { return i.hidden }
450
451// -- StringVar and stringValue
452type StringVar struct {
453	Name       string
454	Aliases    []string
455	Usage      string
456	Default    string
457	Hidden     bool
458	EnvVar     string
459	Target     *string
460	Completion complete.Predictor
461}
462
463func (f *FlagSet) StringVar(i *StringVar) {
464	initial := i.Default
465	if v, exist := os.LookupEnv(i.EnvVar); exist {
466		initial = v
467	}
468
469	def := ""
470	if i.Default != "" {
471		def = i.Default
472	}
473
474	f.VarFlag(&VarFlag{
475		Name:       i.Name,
476		Aliases:    i.Aliases,
477		Usage:      i.Usage,
478		Default:    def,
479		EnvVar:     i.EnvVar,
480		Value:      newStringValue(initial, i.Target, i.Hidden),
481		Completion: i.Completion,
482	})
483}
484
485type stringValue struct {
486	hidden bool
487	target *string
488}
489
490func newStringValue(def string, target *string, hidden bool) *stringValue {
491	*target = def
492	return &stringValue{
493		hidden: hidden,
494		target: target,
495	}
496}
497
498func (s *stringValue) Set(val string) error {
499	*s.target = val
500	return nil
501}
502
503func (s *stringValue) Get() interface{} { return *s.target }
504func (s *stringValue) String() string   { return *s.target }
505func (s *stringValue) Example() string  { return "string" }
506func (s *stringValue) Hidden() bool     { return s.hidden }
507
508// -- Float64Var and float64Value
509type Float64Var struct {
510	Name       string
511	Aliases    []string
512	Usage      string
513	Default    float64
514	Hidden     bool
515	EnvVar     string
516	Target     *float64
517	Completion complete.Predictor
518}
519
520func (f *FlagSet) Float64Var(i *Float64Var) {
521	initial := i.Default
522	if v, exist := os.LookupEnv(i.EnvVar); exist {
523		if i, err := strconv.ParseFloat(v, 64); err == nil {
524			initial = i
525		}
526	}
527
528	def := ""
529	if i.Default != 0 {
530		def = strconv.FormatFloat(i.Default, 'e', -1, 64)
531	}
532
533	f.VarFlag(&VarFlag{
534		Name:       i.Name,
535		Aliases:    i.Aliases,
536		Usage:      i.Usage,
537		Default:    def,
538		EnvVar:     i.EnvVar,
539		Value:      newFloat64Value(initial, i.Target, i.Hidden),
540		Completion: i.Completion,
541	})
542}
543
544type float64Value struct {
545	hidden bool
546	target *float64
547}
548
549func newFloat64Value(def float64, target *float64, hidden bool) *float64Value {
550	*target = def
551	return &float64Value{
552		hidden: hidden,
553		target: target,
554	}
555}
556
557func (f *float64Value) Set(s string) error {
558	v, err := strconv.ParseFloat(s, 64)
559	if err != nil {
560		return err
561	}
562
563	*f.target = v
564	return nil
565}
566
567func (f *float64Value) Get() interface{} { return float64(*f.target) }
568func (f *float64Value) String() string   { return strconv.FormatFloat(float64(*f.target), 'g', -1, 64) }
569func (f *float64Value) Example() string  { return "float" }
570func (f *float64Value) Hidden() bool     { return f.hidden }
571
572// -- DurationVar and durationValue
573type DurationVar struct {
574	Name       string
575	Aliases    []string
576	Usage      string
577	Default    time.Duration
578	Hidden     bool
579	EnvVar     string
580	Target     *time.Duration
581	Completion complete.Predictor
582}
583
584func (f *FlagSet) DurationVar(i *DurationVar) {
585	initial := i.Default
586	if v, exist := os.LookupEnv(i.EnvVar); exist {
587		if d, err := time.ParseDuration(appendDurationSuffix(v)); err == nil {
588			initial = d
589		}
590	}
591
592	def := ""
593	if i.Default != 0 {
594		def = i.Default.String()
595	}
596
597	f.VarFlag(&VarFlag{
598		Name:       i.Name,
599		Aliases:    i.Aliases,
600		Usage:      i.Usage,
601		Default:    def,
602		EnvVar:     i.EnvVar,
603		Value:      newDurationValue(initial, i.Target, i.Hidden),
604		Completion: i.Completion,
605	})
606}
607
608type durationValue struct {
609	hidden bool
610	target *time.Duration
611}
612
613func newDurationValue(def time.Duration, target *time.Duration, hidden bool) *durationValue {
614	*target = def
615	return &durationValue{
616		hidden: hidden,
617		target: target,
618	}
619}
620
621func (d *durationValue) Set(s string) error {
622	// Maintain bc for people specifying "system" as the value.
623	if s == "system" {
624		s = "-1"
625	}
626
627	v, err := time.ParseDuration(appendDurationSuffix(s))
628	if err != nil {
629		return err
630	}
631	*d.target = v
632	return nil
633}
634
635func (d *durationValue) Get() interface{} { return time.Duration(*d.target) }
636func (d *durationValue) String() string   { return (*d.target).String() }
637func (d *durationValue) Example() string  { return "duration" }
638func (d *durationValue) Hidden() bool     { return d.hidden }
639
640// appendDurationSuffix is used as a backwards-compat tool for assuming users
641// meant "seconds" when they do not provide a suffixed duration value.
642func appendDurationSuffix(s string) string {
643	if strings.HasSuffix(s, "s") || strings.HasSuffix(s, "m") || strings.HasSuffix(s, "h") {
644		return s
645	}
646	return s + "s"
647}
648
649// -- StringSliceVar and stringSliceValue
650type StringSliceVar struct {
651	Name       string
652	Aliases    []string
653	Usage      string
654	Default    []string
655	Hidden     bool
656	EnvVar     string
657	Target     *[]string
658	Completion complete.Predictor
659}
660
661func (f *FlagSet) StringSliceVar(i *StringSliceVar) {
662	initial := i.Default
663	if v, exist := os.LookupEnv(i.EnvVar); exist {
664		parts := strings.Split(v, ",")
665		for i := range parts {
666			parts[i] = strings.TrimSpace(parts[i])
667		}
668		initial = parts
669	}
670
671	def := ""
672	if i.Default != nil {
673		def = strings.Join(i.Default, ",")
674	}
675
676	f.VarFlag(&VarFlag{
677		Name:       i.Name,
678		Aliases:    i.Aliases,
679		Usage:      i.Usage,
680		Default:    def,
681		EnvVar:     i.EnvVar,
682		Value:      newStringSliceValue(initial, i.Target, i.Hidden),
683		Completion: i.Completion,
684	})
685}
686
687type stringSliceValue struct {
688	hidden bool
689	target *[]string
690}
691
692func newStringSliceValue(def []string, target *[]string, hidden bool) *stringSliceValue {
693	*target = def
694	return &stringSliceValue{
695		hidden: hidden,
696		target: target,
697	}
698}
699
700func (s *stringSliceValue) Set(val string) error {
701	*s.target = append(*s.target, strings.TrimSpace(val))
702	return nil
703}
704
705func (s *stringSliceValue) Get() interface{} { return *s.target }
706func (s *stringSliceValue) String() string   { return strings.Join(*s.target, ",") }
707func (s *stringSliceValue) Example() string  { return "string" }
708func (s *stringSliceValue) Hidden() bool     { return s.hidden }
709
710// -- StringMapVar and stringMapValue
711type StringMapVar struct {
712	Name       string
713	Aliases    []string
714	Usage      string
715	Default    map[string]string
716	Hidden     bool
717	Target     *map[string]string
718	Completion complete.Predictor
719}
720
721func (f *FlagSet) StringMapVar(i *StringMapVar) {
722	def := ""
723	if i.Default != nil {
724		def = mapToKV(i.Default)
725	}
726
727	f.VarFlag(&VarFlag{
728		Name:       i.Name,
729		Aliases:    i.Aliases,
730		Usage:      i.Usage,
731		Default:    def,
732		Value:      newStringMapValue(i.Default, i.Target, i.Hidden),
733		Completion: i.Completion,
734	})
735}
736
737type stringMapValue struct {
738	hidden bool
739	target *map[string]string
740}
741
742func newStringMapValue(def map[string]string, target *map[string]string, hidden bool) *stringMapValue {
743	*target = def
744	return &stringMapValue{
745		hidden: hidden,
746		target: target,
747	}
748}
749
750func (s *stringMapValue) Set(val string) error {
751	idx := strings.Index(val, "=")
752	if idx == -1 {
753		return fmt.Errorf("missing = in KV pair: %q", val)
754	}
755
756	if *s.target == nil {
757		*s.target = make(map[string]string)
758	}
759
760	k, v := val[0:idx], val[idx+1:]
761	(*s.target)[k] = v
762	return nil
763}
764
765func (s *stringMapValue) Get() interface{} { return *s.target }
766func (s *stringMapValue) String() string   { return mapToKV(*s.target) }
767func (s *stringMapValue) Example() string  { return "key=value" }
768func (s *stringMapValue) Hidden() bool     { return s.hidden }
769
770func mapToKV(m map[string]string) string {
771	list := make([]string, 0, len(m))
772	for k := range m {
773		list = append(list, k)
774	}
775	sort.Strings(list)
776
777	for i, k := range list {
778		list[i] = k + "=" + m[k]
779	}
780
781	return strings.Join(list, ",")
782}
783
784// -- VarFlag
785type VarFlag struct {
786	Name       string
787	Aliases    []string
788	Usage      string
789	Default    string
790	EnvVar     string
791	Value      flag.Value
792	Completion complete.Predictor
793}
794
795func (f *FlagSet) VarFlag(i *VarFlag) {
796	// If the flag is marked as hidden, just add it to the set and return to
797	// avoid unnecessary computations here. We do not want to add completions or
798	// generate help output for hidden flags.
799	if v, ok := i.Value.(FlagVisibility); ok && v.Hidden() {
800		f.Var(i.Value, i.Name, "")
801		return
802	}
803
804	// Calculate the full usage
805	usage := i.Usage
806
807	if len(i.Aliases) > 0 {
808		sentence := make([]string, len(i.Aliases))
809		for i, a := range i.Aliases {
810			sentence[i] = fmt.Sprintf(`"-%s"`, a)
811		}
812
813		aliases := ""
814		switch len(sentence) {
815		case 0:
816			// impossible...
817		case 1:
818			aliases = sentence[0]
819		case 2:
820			aliases = sentence[0] + " and " + sentence[1]
821		default:
822			sentence[len(sentence)-1] = "and " + sentence[len(sentence)-1]
823			aliases = strings.Join(sentence, ", ")
824		}
825
826		usage += fmt.Sprintf(" This is aliased as %s.", aliases)
827	}
828
829	if i.Default != "" {
830		usage += fmt.Sprintf(" The default is %s.", i.Default)
831	}
832
833	if i.EnvVar != "" {
834		usage += fmt.Sprintf(" This can also be specified via the %s "+
835			"environment variable.", i.EnvVar)
836	}
837
838	// Add aliases to the main set
839	for _, a := range i.Aliases {
840		f.mainSet.Var(i.Value, a, "")
841	}
842
843	f.Var(i.Value, i.Name, usage)
844	f.completions["-"+i.Name] = i.Completion
845}
846
847// Var is a lower-level API for adding something to the flags. It should be used
848// with caution, since it bypasses all validation. Consider VarFlag instead.
849func (f *FlagSet) Var(value flag.Value, name, usage string) {
850	f.mainSet.Var(value, name, usage)
851	f.flagSet.Var(value, name, usage)
852}
853
854// -- TimeVar and timeValue
855type TimeVar struct {
856	Name       string
857	Aliases    []string
858	Usage      string
859	Default    time.Time
860	Hidden     bool
861	EnvVar     string
862	Target     *time.Time
863	Completion complete.Predictor
864	Formats    TimeFormat
865}
866
867// Identify the allowable formats, identified by the minimum
868// precision accepted.
869// TODO: move this somewhere where it can be re-used for the API.
870type TimeFormat int
871
872const (
873	TimeVar_EpochSecond TimeFormat = 1 << iota
874	TimeVar_RFC3339Nano
875	TimeVar_RFC3339Second
876	TimeVar_Day
877	TimeVar_Month
878)
879
880// Default value to use
881const TimeVar_TimeOrDay TimeFormat = TimeVar_EpochSecond | TimeVar_RFC3339Nano | TimeVar_RFC3339Second | TimeVar_Day
882
883// parseTimeAlternatives attempts several different allowable variants
884// of the time field.
885func parseTimeAlternatives(input string, allowedFormats TimeFormat) (time.Time, error) {
886	// The RFC3339 formats require the inclusion of a time zone.
887	if allowedFormats&TimeVar_RFC3339Nano != 0 {
888		t, err := time.Parse(time.RFC3339Nano, input)
889		if err == nil {
890			return t, err
891		}
892	}
893
894	if allowedFormats&TimeVar_RFC3339Second != 0 {
895		t, err := time.Parse(time.RFC3339, input)
896		if err == nil {
897			return t, err
898		}
899	}
900
901	if allowedFormats&TimeVar_Day != 0 {
902		t, err := time.Parse("2006-01-02", input)
903		if err == nil {
904			return t, err
905		}
906	}
907
908	if allowedFormats&TimeVar_Month != 0 {
909		t, err := time.Parse("2006-01", input)
910		if err == nil {
911			return t, err
912		}
913	}
914
915	if allowedFormats&TimeVar_EpochSecond != 0 {
916		i, err := strconv.ParseInt(input, 10, 64)
917		if err == nil {
918			// If a customer enters 20200101 we don't want
919			// to parse that as an epoch time.
920			// This arbitrarily-chosen cutoff is around year 2000.
921			if i > 946000000 {
922				return time.Unix(i, 0), nil
923			}
924		}
925	}
926
927	return time.Time{}, errors.New("Could not parse as absolute time.")
928}
929
930func (f *FlagSet) TimeVar(i *TimeVar) {
931	initial := i.Default
932	if v, exist := os.LookupEnv(i.EnvVar); exist {
933		if d, err := parseTimeAlternatives(v, i.Formats); err == nil {
934			initial = d
935		}
936	}
937
938	def := ""
939	if !i.Default.IsZero() {
940		def = i.Default.String()
941	}
942
943	f.VarFlag(&VarFlag{
944		Name:       i.Name,
945		Aliases:    i.Aliases,
946		Usage:      i.Usage,
947		Default:    def,
948		EnvVar:     i.EnvVar,
949		Value:      newTimeValue(initial, i.Target, i.Hidden, i.Formats),
950		Completion: i.Completion,
951	})
952}
953
954type timeValue struct {
955	hidden  bool
956	target  *time.Time
957	formats TimeFormat
958}
959
960func newTimeValue(def time.Time, target *time.Time, hidden bool, f TimeFormat) *timeValue {
961	*target = def
962	return &timeValue{
963		hidden:  hidden,
964		target:  target,
965		formats: f,
966	}
967}
968
969func (d *timeValue) Set(s string) error {
970	v, err := parseTimeAlternatives(s, d.formats)
971	if err != nil {
972		return err
973	}
974	*d.target = v
975	return nil
976}
977
978func (d *timeValue) Get() interface{} { return *d.target }
979func (d *timeValue) String() string   { return (*d.target).String() }
980func (d *timeValue) Example() string  { return "time" }
981func (d *timeValue) Hidden() bool     { return d.hidden }
982
983// -- helpers
984func envDefault(key, def string) string {
985	if v, exist := os.LookupEnv(key); exist {
986		return v
987	}
988	return def
989}
990
991func envBoolDefault(key string, def bool) bool {
992	if v, exist := os.LookupEnv(key); exist {
993		b, err := strconv.ParseBool(v)
994		if err != nil {
995			panic(err)
996		}
997		return b
998	}
999	return def
1000}
1001
1002func envDurationDefault(key string, def time.Duration) time.Duration {
1003	if v, exist := os.LookupEnv(key); exist {
1004		d, err := time.ParseDuration(v)
1005		if err != nil {
1006			panic(err)
1007		}
1008		return d
1009	}
1010	return def
1011}
1012