Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zakuro9715 committed Nov 4, 2020
0 parents commit 95997fd
Show file tree
Hide file tree
Showing 11 changed files with 378 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Z

Simple task runner

# Installation

```
go get github.com/zakuro9715/z
```

# Examples

See [Examples](./examples) and [Examples Test](./examples_test.go)
132 changes: 132 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package main

import (
"fmt"
"io"
"os"
"strings"
)

var exit = os.Exit

const version = "v0.1.0"
const helpTextBase = `
z - Z Task runner
Usage:
z [OPTIONS] task... [ARGS]
`

func isHelpFlag(s string) bool {
return s == "-h" || s == "--help"
}

func showTextAndExit(code int, text string) {
if code == 0 {
fmt.Println(text)
} else {
fmt.Fprintln(os.Stderr, text)
}
exit(code)
}

func fprintTasks(w io.Writer, tasks map[string]*Task) {
fmt.Fprintln(w, "Tasks:")
maxNameLen := 0
for k := range tasks {
if len(k) > maxNameLen {
maxNameLen = len(k)
}
}
for k, t := range tasks {
fmt.Fprintf(w,
" %v%v - %v\n",
k,
strings.Repeat(" ", maxNameLen-len(k)),
t.Description,
)
}
}

func fprintHelp(w io.Writer, config *Config) {
var sb strings.Builder
sb.WriteString(helpTextBase)
if config != nil {
sb.WriteString("\n")
fprintTasks(&sb, config.Tasks)
}
fmt.Fprintln(w, sb.String())
}

func fprintTaskHelp(w io.Writer, task *Task) {
var sb strings.Builder
sb.WriteString(task.Description)
if len(task.Tasks) > 0 {
fprintTasks(&sb, task.Tasks)
}
fmt.Fprint(w, sb.String())
}

func fprintVersion(w io.Writer) {
fmt.Fprintf(w, "z task runner %v\n", version)
}

func realMain(args []string) int {
i := 0
configPath := "z.yaml"
if p, ok := os.LookupEnv("ZCONFIG"); ok {
configPath = p
}

config, err := LoadConfig(configPath)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}

for ; i < len(args); i++ {
arg := args[i]
if arg[0] != '-' {
break
}
switch {
case isHelpFlag(arg):
fprintHelp(os.Stdout, config)
return 0
case arg == "-v" || arg == "--version":
fprintVersion(os.Stdout)
default: // unknow flag
fprintHelp(os.Stderr, nil)
return 1
}
}

if i >= len(args) {
fprintHelp(os.Stderr, config)
return 1
}

task, ok := config.Tasks[args[i]]
if !ok {
fmt.Fprintf(os.Stderr, "Unknown task: %v\n", args[i])
exit(1)
}
i++
for ; i < len(args); i++ {
if isHelpFlag(args[i]) {
fprintTaskHelp(os.Stdout, task)
return 0
}
if args[i] == "--" {
i += 1
break
}
if subtask, ok := task.Tasks[args[i]]; ok {
task = subtask
} else {
break
}
}
task.Run(args[i:])
return 0
}
32 changes: 32 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"io/ioutil"

"github.com/goccy/go-yaml"
)

type Config struct {
Shell string `yaml:"shell"`
Tasks Tasks `yaml:"tasks"`
}

func LoadConfig(filename string) (*Config, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
config := new(Config)
if err = yaml.Unmarshal(data, config); err != nil {
return nil, err
}
for _, t := range config.Tasks {
t.setConfig(config)
}
return config, nil
}

type Hooks struct {
Pre string `yaml:"pre"`
Post string `yaml:"post"`
}
58 changes: 58 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

func TestExampleIsValid(t *testing.T) {
assert.NoError(t,
filepath.Walk("examples", func(path string, info os.FileInfo, err error) error {
assert.NoError(t, err)
if info.IsDir() {
return nil
}
_, err = LoadConfig(path)
return err
}),
)
}

func TestLoadHelloExample(t *testing.T) {
expected := &Config{
Shell: "bash",
Tasks: map[string]*Task{
"hello": {
Cmds: []string{"echo hello"},
Hooks: Hooks{
Pre: "echo saying hello",
Post: "echo said hello",
},
Tasks: map[string]*Task{
"world": {
Cmds: []string{"z hello -- world"},
Description: "Hello World",
},
"cjk": {
Cmds: []string{
"z hello japan",
"z hello korea",
"z hello china",
},
},
},
},
},
}
for _, task := range expected.Tasks {
task.setConfig(expected)
}

actual, err := LoadConfig("examples/hello.yaml")
assert.NoError(t, err)

assert.Equal(t, expected, actual)
}
12 changes: 12 additions & 0 deletions examples/cc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
tasks:
compile:
run:
- clang $@
desc: Compile
hooks:
pre: echo Compiling
post: echo Compiled
tasks:
main:
run:
- z -c examples/cc.yaml compile main.c
18 changes: 18 additions & 0 deletions examples/hello.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
shell: bash
tasks:
hello:
run:
- echo hello
hooks:
pre: echo saying hello
post: echo said hello
tasks:
world:
desc: Hello World
run:
- z hello -- world
cjk:
run:
- z hello japan
- z hello korea
- z hello china
18 changes: 18 additions & 0 deletions examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"os"
)

func ExampleHello() {
os.Setenv("ZCONFIG", "examples/hello.yaml")
realMain([]string{"hello"})
realMain([]string{"hello", "world"})
realMain([]string{"hello", "cjk"})
// Output:
// hello
// hello world
// hello japan
// hello korea
// hello china
}
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/zakuro9715/z

go 1.15

require (
github.com/goccy/go-yaml v1.8.3
github.com/stretchr/testify v1.6.1
)
34 changes: 34 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/goccy/go-yaml v1.8.3 h1:VGzw2KWSUyQX0yXai02S0nttBc+Oa4Kvh6RCFoxt8SE=
github.com/goccy/go-yaml v1.8.3/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
9 changes: 9 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"os"
)

func main() {
os.Exit(realMain(os.Args[1:]))
}
44 changes: 44 additions & 0 deletions task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"os"
"os/exec"
"strings"
)

type Tasks map[string]*Task
type Task struct {
Cmds []string `yaml:"run"`
Config *Config
Description string `yaml:"desc"`
Hooks Hooks `yaml:"hooks"`
Tasks Tasks `yaml:"tasks"`
}

func (t *Task) setConfig(c *Config) {
t.Config = c
for _, sub := range t.Tasks {
sub.setConfig(c)
}
}

func (t *Task) Run(args []string) error {
shell := t.Config.GetShell()
for _, command := range t.Cmds {
cmd := exec.Command(shell, "-c", command+" "+strings.Join(args, " "))
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}
}
return nil
}

func (c *Config) GetShell() string {
if len(c.Shell) == 0 {
return "sh"
}
return c.Shell
}

0 comments on commit 95997fd

Please sign in to comment.