summaryrefslogtreecommitdiff
path: root/cmd/cmd.go
blob: 224279ed58790ec3a19459b16236f057346a5f32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Package cmd used for command line options for the complete tool
package cmd

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/posener/complete/cmd/install"
)

// CLI for command line
type CLI struct {
	Name          string
	InstallName   string
	UninstallName string

	install   bool
	uninstall bool
	yes       bool
}

const (
	defaultInstallName   = "install"
	defaultUninstallName = "uninstall"
)

// Run is used when running complete in command line mode.
// this is used when the complete is not completing words, but to
// install it or uninstall it.
func (f *CLI) Run() bool {

	fs := flag.NewFlagSet(f.Name, 0)
	// add flags and parse them in case they were not added and parsed
	// by the main program
	f.AddFlags(fs)
	fs.Parse(os.Args[1:])

	err := f.validate()
	if err != nil {
		os.Stderr.WriteString(err.Error() + "\n")
		os.Exit(1)
	}

	switch {
	case f.install:
		f.prompt()
		err = install.Install(f.Name)
	case f.uninstall:
		f.prompt()
		err = install.Uninstall(f.Name)
	default:
		// non of the action flags matched,
		// returning false should make the real program execute
		return false
	}

	if err != nil {
		fmt.Printf("%s failed! %s\n", f.action(), err)
		os.Exit(3)
	}
	fmt.Println("Done!")
	return true
}

// prompt use for approval
// exit if approval was not given
func (f *CLI) prompt() {
	defer fmt.Println(f.action() + "ing...")
	if f.yes {
		return
	}
	fmt.Printf("%s completion for %s? ", f.action(), f.Name)
	var answer string
	fmt.Scanln(&answer)

	switch strings.ToLower(answer) {
	case "y", "yes":
		return
	default:
		fmt.Println("Cancelling...")
		os.Exit(1)
	}
}

// AddFlags adds the CLI flags to the flag set.
// If flags is nil, the default command line flags will be taken.
// Pass non-empty strings as installName and uninstallName to override the default
// flag names.
func (f *CLI) AddFlags(flags *flag.FlagSet) {
	if flags == nil {
		flags = flag.CommandLine
	}

	if f.InstallName == "" {
		f.InstallName = defaultInstallName
	}
	if f.UninstallName == "" {
		f.UninstallName = defaultUninstallName
	}

	if flags.Lookup(f.InstallName) == nil {
		flags.BoolVar(&f.install, f.InstallName, false,
			fmt.Sprintf("Install completion for %s command", f.Name))
	}
	if flags.Lookup(f.UninstallName) == nil {
		flags.BoolVar(&f.uninstall, f.UninstallName, false,
			fmt.Sprintf("Uninstall completion for %s command", f.Name))
	}
	if flags.Lookup("y") == nil {
		flags.BoolVar(&f.yes, "y", false, "Don't prompt user for typing 'yes'")
	}
}

// validate the CLI
func (f *CLI) validate() error {
	if f.install && f.uninstall {
		return errors.New("Install and uninstall are mutually exclusive")
	}
	return nil
}

// action name according to the CLI values.
func (f *CLI) action() string {
	switch {
	case f.install:
		return "Install"
	case f.uninstall:
		return "Uninstall"
	default:
		return "unknown"
	}
}