Skip to content
This repository has been archived by the owner on Nov 6, 2022. It is now read-only.

Commit

Permalink
fix issue #32 : support for semver semantics
Browse files Browse the repository at this point in the history
A new flag (-s) now prints a semver version number and exits. Script
version.sh has been updated so that go:generate sets a new constant
in version.go to the most recent semver value.

For now, semantic version should be incremented manually by creating
git tags.
  • Loading branch information
Seth Hoenig committed Jan 8, 2018
1 parent ebb6c40 commit 44d8bdb
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 89 deletions.
121 changes: 67 additions & 54 deletions config.go
Expand Up @@ -3,93 +3,106 @@
package main

import (
"errors"
"flag"
"fmt"
"os"
"path/filepath"

"github.com/shoenig/config"
)

type flags struct {
version bool
semver bool
configfile string
host string
login string
format string
insecure bool
}

// cli arguments override configuration file
func cliargs() (version bool, config, host, login, format string, insecure bool) {
flag.BoolVar(&version, "v", false, "version number (git sha1)")
flag.StringVar(&config, "c", "", "config file")
flag.StringVar(&host, "h", "", "marathon host with transport and port")
flag.StringVar(&login, "u", "", "username and password")
flag.StringVar(&format, "f", "", "output format")
flag.BoolVar(&insecure, "k", false, "insecure - do not verify cacert")
func cliargs() flags {
var f flags
flag.BoolVar(&f.version, "v", false, "display version (git sha1) and exit")
flag.BoolVar(&f.semver, "s", false, "display semversion and exit")
flag.StringVar(&f.configfile, "c", "", "path to configfile")
flag.StringVar(&f.host, "h", "", "override marathon host (with transport and port)")
flag.StringVar(&f.login, "u", "", "override username and password")
flag.StringVar(&f.format, "f", "", "override output format (raw, json, jsonpp)")
flag.BoolVar(&f.insecure, "k", false, "insecure - do not verify certificate authority")
flag.Parse()
return
return f
}

func readConfigfile(filename string) (host, login, format string, e error) {
c, e := config.ReadProperties(filename)
if e != nil {
return "", "", "", e
func readConfigfile(filename string) (string, string, string, error) {
props, err := config.ReadProperties(filename)
if err != nil {
return "", "", "", err
}
h := c.GetStringOr("marathon.host", "")
u := c.GetStringOr("marathon.user", "")
p := c.GetStringOr("marathon.password", "")
f := c.GetStringOr("marathon.format", "")

l := ""
if u != "" && p != "" {
l = u + ":" + p
host := props.GetStringOr("marathon.host", "")
user := props.GetStringOr("marathon.user", "")
pass := props.GetStringOr("marathon.password", "")
format := props.GetStringOr("marathon.format", "")

login := ""
if user != "" && pass != "" {
login = user + ":" + pass
}

return h, l, f, nil
return host, login, format, nil
}

func configFile() string {
configLocations := [2]string{os.Getenv("HOME") + "/.config/marathonctl/config", "/etc/marathonctl"}
for _, location := range configLocations {
func findBestConfigfile() string {
locations := [2]string{
filepath.Join(os.Getenv("HOME"), ".config", "marathonctl", "config"),
filepath.Join("etc", "marathonctl"),
}

for _, location := range locations {
if _, err := os.Stat(location); err == nil {
return location
}
}

return ""
}

// todo(someday) read $HOME/.config/marathonctl/config
// Read -config file
// Then override with cli args
func Config() (bool, string, string, string, bool, error) {
version, config, host, login, format, insecure := cliargs()
// loadConfig will parse the CLI flags.
// If --version or --semver are set, no further configuration
// is read. Otherwise, configuration is read from --configfile as
// specified, and then overridden with provided CLI flags.
func loadConfig() (flags, error) {
f := cliargs()

if version {
return version, "", "", "", false, nil
if f.version || f.semver {
return f, nil
}

if host != "" && login != "" {
return version, host, login, format, insecure, nil
if f.host != "" && f.login != "" {
return f, nil
}

if config == "" {
config = configFile()
if f.configfile == "" {
f.configfile = findBestConfigfile()
}

if config != "" {
h, l, f, e := readConfigfile(config)
if e != nil {
return false, "", "", "", false, e
if f.configfile != "" {
fileHost, fileLogin, fileFormat, err := readConfigfile(f.configfile)
if err != nil {
return flags{}, fmt.Errorf("failed to read config file: %v", err)
}
if host == "" {
host = h

if f.host == "" && fileHost != "" {
f.host = fileHost
}
if login == "" {
login = l
if f.login == "" && fileLogin != "" {
f.login = fileLogin
}
if format == "" {
format = f
if format == "" {
format = "human"
}
if f.format == "" && fileFormat != "" {
f.format = fileFormat
}
}

if host == "" {
return false, "", "", "", false, errors.New("no host info provided")
}

return version, host, login, format, insecure, nil
return f, nil
}
67 changes: 37 additions & 30 deletions main.go
Expand Up @@ -63,6 +63,8 @@ const Help = `marathonctl <flags...> [action] <args...>
json (json on one line)
jsonpp (json pretty printed)
raw (the exact response from Marathon)
-v print git sha1
-s print semver version
`

func Usage() {
Expand All @@ -71,66 +73,71 @@ func Usage() {
}

func main() {
version, host, login, format, insecure, e := Config()
conf, err := loadConfig()

if e != nil {
fmt.Printf("config error: %s\n\n", e)
if err != nil {
fmt.Printf("config error: %s\n\n", err)
Usage()
}

if version {
if conf.version {
fmt.Println(Version)
os.Exit(0)
}

f := NewFormatter(format)
l := NewLogin(host, login)
c := NewClient(l, insecure)
if conf.semver {
fmt.Println(Semver)
os.Exit(0)
}

formatter := NewFormatter(conf.format)
login := NewLogin(conf.host, conf.login)
client := NewClient(login, conf.insecure)
app := &Category{
actions: map[string]Action{
"list": AppList{c, f},
"versions": AppVersions{c, f},
"show": AppShow{c, f},
"create": AppCreate{c, f},
"update": AppUpdate{c, f},
"restart": AppRestart{c, f},
"destroy": AppDestroy{c, f},
"list": AppList{client, formatter},
"versions": AppVersions{client, formatter},
"show": AppShow{client, formatter},
"create": AppCreate{client, formatter},
"update": AppUpdate{client, formatter},
"restart": AppRestart{client, formatter},
"destroy": AppDestroy{client, formatter},
},
}
task := &Category{
actions: map[string]Action{
"list": TaskList{c, f},
"kill": TaskKill{c, f},
"queue": TaskQueue{c, f},
"list": TaskList{client, formatter},
"kill": TaskKill{client, formatter},
"queue": TaskQueue{client, formatter},
},
}
group := &Category{
actions: map[string]Action{
"list": GroupList{c, f},
"create": GroupCreate{c, f},
"update": GroupUpdate{c, f},
"destroy": GroupDestroy{c, f},
"list": GroupList{client, formatter},
"create": GroupCreate{client, formatter},
"update": GroupUpdate{client, formatter},
"destroy": GroupDestroy{client, formatter},
},
}
deploy := &Category{
actions: map[string]Action{
"list": DeployList{c, f},
"destroy": DeployCancel{c, f},
"cancel": DeployCancel{c, f},
"list": DeployList{client, formatter},
"destroy": DeployCancel{client, formatter},
"cancel": DeployCancel{client, formatter},
},
}
marathon := &Category{
actions: map[string]Action{
"leader": MarathonLeader{c, f},
"abdicate": MarathonAbdicate{c, f},
"ping": MarathonPing{c, f},
"leader": MarathonLeader{client, formatter},
"abdicate": MarathonAbdicate{client, formatter},
"ping": MarathonPing{client, formatter},
},
}
artifact := &Category{
actions: map[string]Action{
"upload": ArtifactUpload{c, f},
"get": ArtifactGet{c, f},
"delete": ArtifactDelete{c, f},
"upload": ArtifactUpload{client, formatter},
"get": ArtifactGet{client, formatter},
"delete": ArtifactDelete{client, formatter},
},
}
t := &Tool{
Expand Down
5 changes: 4 additions & 1 deletion version.go
Expand Up @@ -2,5 +2,8 @@

package main

//go:generate ./version.sh
//go:generate ./version.sh version
const Version = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

//go:generate ./version.sh semver
const Semver = "x.x.x"
19 changes: 15 additions & 4 deletions version.sh
@@ -1,7 +1,18 @@
#!/bin/bash

hash=$(git rev-parse HEAD)

sed -i s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/$hash/ version.go

set -euo pipefail

case ${1} in
version)
hash=$(git rev-parse HEAD)
sed -i s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/${hash}/ version.go
;;
semver)
latest=$(git tag --sort=version:refname | tail -n 1)
sed -i s/x.x.x/${latest}/ version.go
;;
*)
echo "unknown flag: ${1}"
exit 1
;;
esac

0 comments on commit 44d8bdb

Please sign in to comment.