about summary refs log tree commit diff
path: root/main.go
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@gmail.com>2017-05-04T16·32+0200
committerVincent Ambo <tazjin@gmail.com>2017-05-04T16·49+0200
commitc8a63861aee60a156ed4a63f6b5211dc6abac225 (patch)
treef17e3d5238637d6641dd40b0334eb741fb7c4e80 /main.go
parent32ca64c50a0080198a924c4d9f7c18637b4a76f4 (diff)
refactor main: Move to Kingpin CLI library
Replace urfave/cli with the kingpin[1] library.

It has slightly more sensible argument validation than the other Go libraries.

Additionally I've opted for removing the '-f / --file' flag in favour of positional arguments to commands.

A previous command like `kontemplate template -f somefile.yml` is now just `kontemplate template somefile.yml`. All other arguments remain the same.

[1]: https://github.com/alecthomas/kingpin
Diffstat (limited to 'main.go')
-rw-r--r--main.go236
1 files changed, 84 insertions, 152 deletions
diff --git a/main.go b/main.go
index f5af420150..d2aa8209bc 100644
--- a/main.go
+++ b/main.go
@@ -8,141 +8,111 @@ import (
 	"github.com/polydawn/meep"
 	"github.com/tazjin/kontemplate/context"
 	"github.com/tazjin/kontemplate/templater"
-	"github.com/urfave/cli"
+	"gopkg.in/alecthomas/kingpin.v2"
 )
 
 type KubeCtlError struct {
 	meep.AllTraits
 }
 
+var (
+	app = kingpin.New("kontemplate", "simple Kubernetes resource templating")
+
+	// Global flags
+	includes = app.Flag("include", "Resource sets to include explicitly").Short('i').Strings()
+	excludes = app.Flag("exclude", "Resource sets to exclude explicitly").Short('e').Strings()
+
+	// Commands
+	template     = app.Command("template", "Template resource sets and print them")
+	templateFile = template.Arg("file", "Cluster configuration file to use").Required().String()
+
+	apply       = app.Command("apply", "Template resources and pass to 'kubectl apply'")
+	applyFile   = apply.Arg("file", "Cluster configuration file to use").Required().String()
+	applyDryRun = apply.Flag("dry-run", "Print remote operations without executing them").Default("false").Bool()
+
+	replace     = app.Command("replace", "Template resources and pass to 'kubectl replace'")
+	replaceFile = replace.Arg("file", "Cluster configuration file to use").Required().String()
+
+	delete     = app.Command("delete", "Template resources and pass to 'kubectl delete'")
+	deleteFile = delete.Arg("file", "Cluster configuration file to use").Required().String()
+
+	create     = app.Command("create", "Template resources and pass to 'kubectl create'")
+	createFile = create.Arg("file", "Cluster configuration file to use").Required().String()
+)
+
 func main() {
-	app := cli.NewApp()
+	app.HelpFlag.Short('h')
 
-	app.Name = "kontemplate"
-	app.Usage = "simple Kubernetes resource templating"
-	app.Version = "v1.0.0-beta1"
+	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
+	case template.FullCommand():
+		templateCommand()
 
-	app.Commands = []cli.Command{
-		templateCommand(),
-		applyCommand(),
-		replaceCommand(),
-		deleteCommand(),
-	}
+	case apply.FullCommand():
+		applyCommand()
 
-	app.Run(os.Args)
-}
+	case replace.FullCommand():
+		replaceCommand()
 
-func templateCommand() cli.Command {
-	return cli.Command{
-		Name:  "template",
-		Usage: "Interpolate and print templates",
-		Flags: commonFlags(),
-		Action: func(c *cli.Context) error {
-			include := c.StringSlice("include")
-			exclude := c.StringSlice("exclude")
-
-			ctx, err := loadContext(c)
-			if err != nil {
-				return err
-			}
-
-			resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
-			if err != nil {
-				return err
-			}
-
-			for _, r := range resources {
-				fmt.Println(r)
-			}
-
-			return nil
-		},
+	case delete.FullCommand():
+		deleteCommand()
+
+	case create.FullCommand():
+		createCommand()
 	}
 }
 
-func applyCommand() cli.Command {
-	dryRun := false
-
-	return cli.Command{
-		Name:  "apply",
-		Usage: "Interpolate templates and run 'kubectl apply'",
-		Flags: append(commonFlags(), cli.BoolFlag{
-			Name:        "dry-run",
-			Usage:       "Only print objects that would be sent, without sending them",
-			Destination: &dryRun,
-		}),
-		Action: func(c *cli.Context) error {
-			include := c.StringSlice("include")
-			exclude := c.StringSlice("exclude")
-			ctx, err := loadContext(c)
-			if err != nil {
-				return err
-			}
-
-			resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
-			if err != nil {
-				return err
-			}
-
-			var args []string
-			if dryRun {
-				args = []string{"apply", "-f", "-", "--dry-run"}
-			} else {
-				args = []string{"apply", "-f", "-"}
-			}
-
-			return runKubectlWithResources(ctx, &args, &resources)
-		},
+func templateCommand() {
+	_, resources := loadContextAndResources(templateFile)
+
+	for _, r := range *resources {
+		fmt.Println(r)
 	}
 }
 
-func replaceCommand() cli.Command {
-	return cli.Command{
-		Name:  "replace",
-		Usage: "Interpolate templates and run 'kubectl replace'",
-		Flags: commonFlags(),
-		Action: func(c *cli.Context) error {
-			include := c.StringSlice("include")
-			exclude := c.StringSlice("exclude")
-			ctx, err := loadContext(c)
-			if err != nil {
-				return err
-			}
-
-			resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
-			if err != nil {
-				return err
-			}
-
-			args := []string{"replace", "--save-config=true", "-f", "-"}
-			return runKubectlWithResources(ctx, &args, &resources)
-		},
+func applyCommand() {
+	ctx, resources := loadContextAndResources(applyFile)
+
+	var kubectlArgs []string
+
+	if *applyDryRun {
+		kubectlArgs = []string{"apply", "-f", "-", "--dry-run"}
+	} else {
+		kubectlArgs = []string{"apply", "-f", "-"}
 	}
+
+	runKubectlWithResources(ctx, &kubectlArgs, resources)
+}
+
+func replaceCommand() {
+	ctx, resources := loadContextAndResources(replaceFile)
+	args := []string{"replace", "--save-config=true", "-f", "-"}
+	runKubectlWithResources(ctx, &args, resources)
+}
+
+func deleteCommand() {
+	ctx, resources := loadContextAndResources(deleteFile)
+	args := []string{"delete", "-f", "-"}
+	runKubectlWithResources(ctx, &args, resources)
 }
 
-func deleteCommand() cli.Command {
-	return cli.Command{
-		Name:  "delete",
-		Usage: "Interpolate templates and run 'kubectl delete'",
-		Flags: commonFlags(),
-		Action: func(c *cli.Context) error {
-			include := c.StringSlice("include")
-			exclude := c.StringSlice("exclude")
-
-			ctx, err := loadContext(c)
-			if err != nil {
-				return err
-			}
-
-			resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
-			if err != nil {
-				return err
-			}
-
-			args := []string{"delete", "-f", "-"}
-			return runKubectlWithResources(ctx, &args, &resources)
-		},
+func createCommand() {
+	ctx, resources := loadContextAndResources(createFile)
+	args := []string{"create", "--save-config=true", "-f", "-"}
+	runKubectlWithResources(ctx, &args, resources)
+}
+
+func loadContextAndResources(file *string) (*context.Context, *[]string) {
+	ctx, err := context.LoadContextFromFile(*file)
+	if err != nil {
+		app.Fatalf("Error loading context: %v\n", err)
+	}
+
+	resources, err := templater.LoadAndPrepareTemplates(includes, excludes, ctx)
+	if err != nil {
+		app.Fatalf("Error templating resource sets: %v\n", err)
 	}
+
+	return ctx, &resources
 }
 
 func runKubectlWithResources(c *context.Context, kubectlArgs *[]string, resources *[]string) error {
@@ -171,41 +141,3 @@ func runKubectlWithResources(c *context.Context, kubectlArgs *[]string, resource
 
 	return nil
 }
-
-func commonFlags() []cli.Flag {
-	return []cli.Flag{
-		cli.StringFlag{
-			Name:  "file, f",
-			Usage: "Cluster configuration file to use",
-		},
-		cli.StringSliceFlag{
-			Name:  "include, i",
-			Usage: "Limit templating to explicitly included resource sets",
-		},
-		cli.StringSliceFlag{
-			Name:  "exclude, e",
-			Usage: "Exclude certain resource sets from templating",
-		},
-	}
-}
-
-func loadContext(c *cli.Context) (*context.Context, error) {
-	f := c.String("file")
-
-	if f == "" {
-		return nil, meep.New(
-			&meep.ErrInvalidParam{
-				Param:  "file",
-				Reason: "Cluster config file must be specified (-f)",
-			},
-		)
-	}
-
-	ctx, err := context.LoadContextFromFile(f)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return ctx, nil
-}