Introduce kingpin as CLI helper library

This commit is contained in:
Matthias Loibl 2018-04-26 23:37:30 +02:00
parent bd22799e96
commit 2ef36da33a
No known key found for this signature in database
GPG key ID: B1C7DF661ABB2C1A

View file

@ -19,31 +19,31 @@ package main
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings"
"github.com/jsonnet-bundler/jsonnet-bundler/pkg" "github.com/jsonnet-bundler/jsonnet-bundler/pkg"
"github.com/jsonnet-bundler/jsonnet-bundler/spec" "github.com/jsonnet-bundler/jsonnet-bundler/spec"
"github.com/pkg/errors" "github.com/pkg/errors"
"gopkg.in/alecthomas/kingpin.v2"
) )
const ( const (
installSubcommand = "install" installActionName = "install"
initSubcommand = "init" initActionName = "init"
basePath = ".jsonnetpkg" basePath = ".jsonnetpkg"
srcDirName = "src" srcDirName = "src"
) )
var ( var (
availableSubcommands = []string{ availableSubcommands = []string{
initSubcommand, initActionName,
installSubcommand, installActionName,
} }
githubSlugRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)") githubSlugRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)")
githubSlugWithVersionRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)@(.*)") githubSlugWithVersionRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)@(.*)")
@ -51,43 +51,63 @@ var (
githubSlugWithPathAndVersionRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/(.*)@(.*)") githubSlugWithPathAndVersionRegex = regexp.MustCompile("github.com/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/(.*)@(.*)")
) )
type config struct { func main() {
JsonnetHome string os.Exit(Main())
} }
func Main() int { func Main() int {
cfg := config{} cfg := struct {
JsonnetHome string
}{}
flagset := flag.NewFlagSet(os.Args[0], flag.ExitOnError) a := kingpin.New(filepath.Base(os.Args[0]), "A jsonnet package manager")
flagset.StringVar(&cfg.JsonnetHome, "jsonnetpkg-home", "vendor", "The directory used to cache packages in.") a.HelpFlag.Short('h')
flagset.Parse(os.Args[1:])
subcommand := "install" a.Flag("jsonnetpkg-home", "The directory used to cache packages in.").
args := flagset.Args() Default("vendor").StringVar(&cfg.JsonnetHome)
if len(args) >= 1 {
subcommand = args[0] initCmd := a.Command(initActionName, "Initialize a new empty jsonnetfile")
installCmd := a.Command(installActionName, "Install all dependencies or install specific ones")
installCmdURLs := installCmd.Arg("packages", "URLs to package to install").URLList()
command, err := a.Parse(os.Args[1:])
if err != nil {
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Error parsing commandline arguments"))
a.Usage(os.Args[1:])
return 2
} }
err := RunSubcommand(context.TODO(), cfg, subcommand, args[1:]) switch command {
case initCmd.FullCommand():
return initCommand()
case installCmd.FullCommand():
return installCommand(cfg.JsonnetHome, *installCmdURLs...)
default:
installCommand(cfg.JsonnetHome)
}
return 0
}
func initCommand() int {
err := ioutil.WriteFile(pkg.JsonnetFile, []byte("{}"), 0644)
if err != nil { if err != nil {
fmt.Fprint(os.Stderr, err) kingpin.Fatalf("Failed to write new jsonnetfile.json: %v", err)
return 1 return 1
} }
return 0 return 0
} }
func RunSubcommand(ctx context.Context, cfg config, subcommand string, args []string) error { func installCommand(jsonnetHome string, urls ...*url.URL) int {
switch subcommand { m, err := pkg.LoadJsonnetfile(pkg.JsonnetFile)
case initSubcommand: if err != nil {
return ioutil.WriteFile(pkg.JsonnetFile, []byte("{}"), 0644) kingpin.Fatalf("failed to load jsonnetfile: %v", err)
case installSubcommand: return 1
m, err := pkg.LoadJsonnetfile(pkg.JsonnetFile) }
if err != nil { if len(urls) > 0 {
return errors.Wrap(err, "failed to load jsonnetfile") for _, url := range urls {
}
if len(args) == 1 {
// install package specified in command // install package specified in command
// $ jsonnetpkg install ksonnet git@github.com:ksonnet/ksonnet-lib // $ jsonnetpkg install ksonnet git@github.com:ksonnet/ksonnet-lib
// $ jsonnetpkg install grafonnet git@github.com:grafana/grafonnet-lib grafonnet // $ jsonnetpkg install grafonnet git@github.com:grafana/grafonnet-lib grafonnet
@ -95,36 +115,37 @@ func RunSubcommand(ctx context.Context, cfg config, subcommand string, args []st
// //
// github.com/(slug)/(dir) // github.com/(slug)/(dir)
if githubSlugRegex.MatchString(args[0]) { urlString := url.String()
if githubSlugRegex.MatchString(urlString) {
name := "" name := ""
user := "" user := ""
repo := "" repo := ""
subdir := "" subdir := ""
version := "master" version := "master"
if githubSlugWithPathRegex.MatchString(args[0]) { if githubSlugWithPathRegex.MatchString(urlString) {
if githubSlugWithPathAndVersionRegex.MatchString(args[0]) { if githubSlugWithPathAndVersionRegex.MatchString(urlString) {
matches := githubSlugWithPathAndVersionRegex.FindStringSubmatch(args[0]) matches := githubSlugWithPathAndVersionRegex.FindStringSubmatch(urlString)
user = matches[1] user = matches[1]
repo = matches[2] repo = matches[2]
subdir = matches[3] subdir = matches[3]
version = matches[4] version = matches[4]
name = path.Base(subdir) name = path.Base(subdir)
} else { } else {
matches := githubSlugWithPathRegex.FindStringSubmatch(args[0]) matches := githubSlugWithPathRegex.FindStringSubmatch(urlString)
user = matches[1] user = matches[1]
repo = matches[2] repo = matches[2]
subdir = matches[3] subdir = matches[3]
name = path.Base(subdir) name = path.Base(subdir)
} }
} else { } else {
if githubSlugWithVersionRegex.MatchString(args[0]) { if githubSlugWithVersionRegex.MatchString(urlString) {
matches := githubSlugWithVersionRegex.FindStringSubmatch(args[0]) matches := githubSlugWithVersionRegex.FindStringSubmatch(urlString)
user = matches[1] user = matches[1]
repo = matches[2] repo = matches[2]
name = repo name = repo
version = matches[3] version = matches[3]
} else { } else {
matches := githubSlugRegex.FindStringSubmatch(args[0]) matches := githubSlugRegex.FindStringSubmatch(urlString)
user = matches[1] user = matches[1]
repo = matches[2] repo = matches[2]
name = repo name = repo
@ -161,43 +182,43 @@ func RunSubcommand(ctx context.Context, cfg config, subcommand string, args []st
} }
} }
srcPath := filepath.Join(cfg.JsonnetHome) srcPath := filepath.Join(jsonnetHome)
err = os.MkdirAll(srcPath, os.ModePerm) err = os.MkdirAll(srcPath, os.ModePerm)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to create jsonnet home path") kingpin.Fatalf("failed to create jsonnet home path: %v", err)
return 3
} }
lock, err := pkg.Install(ctx, m, cfg.JsonnetHome) lock, err := pkg.Install(context.TODO(), m, jsonnetHome)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to install") kingpin.Fatalf("failed to install: %v", err)
return 3
} }
b, err := json.MarshalIndent(m, "", " ") b, err := json.MarshalIndent(m, "", " ")
if err != nil { if err != nil {
return errors.Wrap(err, "failed to encode jsonnet file") kingpin.Fatalf("failed to encode jsonnet file: %v", err)
return 3
} }
err = ioutil.WriteFile(pkg.JsonnetFile, b, 0644) err = ioutil.WriteFile(pkg.JsonnetFile, b, 0644)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to write jsonnet file") kingpin.Fatalf("failed to write jsonnet file: %v", err)
return 3
} }
b, err = json.MarshalIndent(lock, "", " ") b, err = json.MarshalIndent(lock, "", " ")
if err != nil { if err != nil {
return errors.Wrap(err, "failed to encode jsonnet file") kingpin.Fatalf("failed to encode jsonnet file: %v", err)
return 3
} }
err = ioutil.WriteFile(pkg.JsonnetLockFile, b, 0644) err = ioutil.WriteFile(pkg.JsonnetLockFile, b, 0644)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to write lock file") kingpin.Fatalf("failed to write lock file: %v", err)
return 3
} }
default:
return fmt.Errorf("Subcommand \"%s\" not availble. Available subcommands: %s", subcommand, strings.Join(availableSubcommands, ", "))
} }
return nil return 0
}
func main() {
os.Exit(Main())
} }