Skip to content

Commit 8aafd94

Browse files
committed
genesis
0 parents  commit 8aafd94

File tree

9 files changed

+361
-0
lines changed

9 files changed

+361
-0
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DEBUG=true

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
8+
# Test binary, build with `go test -c`
9+
*.test
10+
11+
# Output of the go coverage tool, specifically when used with LiteIDE
12+
*.out
13+
14+
# Mac crap
15+
.DS_Store
16+
17+
# Local repos for tests
18+
*.local
19+
20+
# The binary
21+
wadsworth

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Wadsworth
2+
3+
_The Mister Handy robot of automation!_
4+
5+
![https://d1u5p3l4wpay3k.cloudfront.net/fallout_gamepedia/8/8c/Mister_Handy.png?version=e4b210e0cf711aefe37d6c3fccb8bc8e](https://d1u5p3l4wpay3k.cloudfront.net/fallout_gamepedia/8/8c/Mister_Handy.png?version=e4b210e0cf711aefe37d6c3fccb8bc8e)
6+
7+
(Work in progress, come back later...)

go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module github.com/Southclaws/wadsworth
2+
3+
require (
4+
github.com/Southclaws/gitwatch v1.0.1
5+
github.com/pkg/errors v0.8.0
6+
github.com/urfave/cli v1.20.0
7+
go.uber.org/atomic v1.3.2 // indirect
8+
go.uber.org/multierr v1.1.0 // indirect
9+
go.uber.org/zap v1.9.1
10+
)

go.sum

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
github.com/Southclaws/gitwatch v1.0.1 h1:BbSvA6+ex4TF0U2ISj8F3Sa8JnaFK7uMsSt+Kt7ZB5Y=
2+
github.com/Southclaws/gitwatch v1.0.1/go.mod h1:sJD5HhPZpjHla0hMzeJQg+oY7wCqSHso9vefmPdnW/o=
3+
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
4+
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
5+
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
6+
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
7+
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
8+
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
9+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
10+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11+
github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo=
12+
github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
13+
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
14+
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
15+
github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw=
16+
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
17+
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
18+
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
19+
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
20+
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
21+
github.com/kevinburke/ssh_config v0.0.0-20180711164746-82cf3f926438 h1:O2UbfXNOrED3WZ12PoAr2hYOb8hOXYyIHImqrEjkFGQ=
22+
github.com/kevinburke/ssh_config v0.0.0-20180711164746-82cf3f926438/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
23+
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
24+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
25+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
26+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
27+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
28+
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
29+
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
30+
github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
31+
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
32+
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
33+
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
34+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
35+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
36+
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
37+
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
38+
github.com/src-d/gcfg v1.3.0 h1:2BEDr8r0I0b8h/fOqwtxCEiq2HJu8n2JGZJQFGXWLjg=
39+
github.com/src-d/gcfg v1.3.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
40+
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
41+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
42+
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
43+
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
44+
github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro=
45+
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
46+
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
47+
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
48+
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
49+
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
50+
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
51+
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
52+
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac h1:7d7lG9fHOLdL6jZPtnV4LpI41SbohIJ1Atq7U991dMg=
53+
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
54+
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
55+
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
56+
golang.org/x/sys v0.0.0-20180828065106-d99a578cf41b h1:cmOZLU2i7CLArKNViO+ZCQ47wqYFyKEIpbGWp+b6Uoc=
57+
golang.org/x/sys v0.0.0-20180828065106-d99a578cf41b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
58+
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
59+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
60+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
61+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
62+
gopkg.in/src-d/go-billy.v4 v4.2.0 h1:VGbrP1EsYxtvVPEiHui+4//imr4E5MGEFLx66bQtusg=
63+
gopkg.in/src-d/go-billy.v4 v4.2.0/go.mod h1:ZHSF0JP+7oD97194otDUCD7Ofbk63+xFcfWP5bT6h+Q=
64+
gopkg.in/src-d/go-git-fixtures.v3 v3.1.0 h1:xjgkEQtv542nRaDzOALYfbFzcRwdt07Q/s2b82fq7AA=
65+
gopkg.in/src-d/go-git-fixtures.v3 v3.1.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
66+
gopkg.in/src-d/go-git.v4 v4.6.0 h1:3XrA9Qxiwfj7Iusd7dVYUqxMjJYPsLuBdUeQbwnL/NQ=
67+
gopkg.in/src-d/go-git.v4 v4.6.0/go.mod h1:CzbUWqMn4pvmvndg3gnh5iZFmSsbhyhUWdI0IQ60AQo=
68+
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
69+
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=

main.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/signal"
7+
"strconv"
8+
"time"
9+
10+
"github.com/pkg/errors"
11+
"github.com/urfave/cli"
12+
"go.uber.org/zap"
13+
"go.uber.org/zap/zapcore"
14+
15+
"github.com/Southclaws/wadsworth/service"
16+
)
17+
18+
var (
19+
version = "master"
20+
)
21+
22+
func init() {
23+
// constructs a logger and replaces the default global logger
24+
var config zap.Config
25+
if d, e := strconv.ParseBool(os.Getenv("DEVELOPMENT")); d && e == nil {
26+
config = zap.NewDevelopmentConfig()
27+
} else {
28+
config = zap.NewProductionConfig()
29+
}
30+
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
31+
config.DisableStacktrace = true
32+
if d, e := strconv.ParseBool(os.Getenv("DEBUG")); d && e == nil {
33+
config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
34+
}
35+
logger, err := config.Build()
36+
if err != nil {
37+
panic(err)
38+
}
39+
zap.ReplaceGlobals(logger)
40+
}
41+
42+
func main() {
43+
app := cli.NewApp()
44+
45+
app.Name = "wadsworth"
46+
app.Usage = "A git-driven task automation butler."
47+
app.UsageText = `TODO: Short usage info`
48+
app.Version = version
49+
app.Description = `TODO: Longform description`
50+
app.Author = "Southclaws"
51+
app.Email = "hello@southcla.ws"
52+
53+
app.Commands = []cli.Command{
54+
{
55+
Name: "run",
56+
Aliases: []string{"r"},
57+
Description: `Starts the Wadsworth daemon with the specified target repository. This
58+
repository should contain one or more configuration files for Wadsworth. When
59+
this repository has new commits, Wadsworth will automatically reconfigure.`,
60+
Usage: "argument `target` specifies Git repository for configuration.",
61+
ArgsUsage: "target",
62+
Flags: []cli.Flag{
63+
cli.StringFlag{Name: "directory", EnvVar: "DIRECTORY", Value: "./cache/"},
64+
cli.DurationFlag{Name: "check-interval", EnvVar: "CHECK_INTERVAL", Value: time.Second * 5},
65+
},
66+
Action: func(c *cli.Context) (err error) {
67+
if !c.Args().Present() {
68+
cli.ShowCommandHelp(c, "run")
69+
return errors.New("missing argument: target")
70+
}
71+
72+
ctx, cancel := context.WithCancel(context.Background())
73+
defer cancel()
74+
75+
svc, err := service.Initialise(ctx, service.Config{
76+
Target: c.Args().First(),
77+
Directory: c.String("directory"),
78+
CheckInterval: c.Duration("check-interval"),
79+
})
80+
if err != nil {
81+
return errors.Wrap(err, "failed to initialise")
82+
}
83+
84+
zap.L().Info("service initialised")
85+
86+
errs := make(chan error, 1)
87+
go func() { errs <- svc.Start() }()
88+
89+
s := make(chan os.Signal, 1)
90+
signal.Notify(s, os.Interrupt)
91+
92+
select {
93+
case sig := <-s:
94+
err = errors.New(sig.String())
95+
case err = <-errs:
96+
}
97+
98+
return
99+
},
100+
},
101+
}
102+
103+
err := app.Run(os.Args)
104+
if err != nil {
105+
zap.L().Fatal("exit", zap.Error(err))
106+
}
107+
}

makefile

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
VERSION := $(shell git describe --tags --dirty --always)
2+
SERVICE := $(shell basename $(shell pwd))
3+
OWNER := southclaws
4+
LDFLAGS := -ldflags "-X main.version=$(VERSION)"
5+
-include .env
6+
7+
# -
8+
# Local Development
9+
#-
10+
11+
static:
12+
go get
13+
CGO_ENABLED=0 GOOS=linux go build -a $(LDFLAGS) -o $(SERVICE) .
14+
15+
fast:
16+
go build $(LDFLAGS) -o $(SERVICE)
17+
18+
local: fast
19+
./$(SERVICE)
20+
21+
test:
22+
go test -v -race ./storage
23+
go test -v -race ./bot/commands
24+
25+
version:
26+
git tag $(VERSION)
27+
git push
28+
git push origin $(VERSION)
29+
30+
31+
# -
32+
# Docker
33+
# -
34+
35+
build:
36+
docker build --no-cache -t $(OWNER)/$(SERVICE):$(VERSION) .
37+
38+
push:
39+
docker push $(OWNER)/$(SERVICE):$(VERSION)
40+
docker tag $(OWNER)/$(SERVICE):$(VERSION) $(OWNER)/$(SERVICE):latest
41+
docker push $(OWNER)/$(SERVICE):latest

service/reconfigure.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package service
2+
3+
import (
4+
"github.com/Southclaws/gitwatch"
5+
"github.com/pkg/errors"
6+
"go.uber.org/zap"
7+
)
8+
9+
// reconfigure will close the configuration watcher and target watcher (unless
10+
// it's the first run) then create a watcher for the application's config target
11+
// repo (the repo that contains the configuration file(s)) then wait for the
12+
// first event (either from a fresh clone, a pull, or just a noop event) then
13+
// read the configuration file(s) from the repository, gather all the targets
14+
// and set up the target watcher. This should always happen in sync with the
15+
// rest of the service to prevent a reconfiguration during an event handler.
16+
func (app *App) reconfigure() (err error) {
17+
zap.L().Debug("reconfiguring")
18+
if app.configWatcher != nil {
19+
zap.L().Debug("closing existing watcher")
20+
app.configWatcher.Close()
21+
}
22+
23+
app.configWatcher, err = gitwatch.New(
24+
app.ctx,
25+
[]string{app.config.Target},
26+
app.config.CheckInterval,
27+
app.config.Directory,
28+
nil,
29+
true)
30+
if err != nil {
31+
return errors.Wrap(err, "failed to watch config target")
32+
}
33+
go app.configWatcher.Run() //nolint:errcheck - no worthwhile errors returned
34+
zap.L().Debug("created new watcher, awaiting initial event")
35+
36+
<-app.configWatcher.InitialDone
37+
zap.L().Debug("initial event received")
38+
39+
// read config from repo
40+
// recreate targets gitwatch
41+
// diff?
42+
43+
return
44+
}

service/service.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package service
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/Southclaws/gitwatch"
8+
"go.uber.org/zap"
9+
)
10+
11+
// App stores application state
12+
type App struct {
13+
config Config
14+
configWatcher *gitwatch.Session
15+
targets []string
16+
targetsWatcher *gitwatch.Session
17+
ctx context.Context
18+
cancel context.CancelFunc
19+
}
20+
21+
type Config struct {
22+
Target string
23+
Directory string
24+
CheckInterval time.Duration
25+
}
26+
27+
// Initialise prepares an instance of the app to run
28+
func Initialise(ctx context.Context, config Config) (app *App, err error) {
29+
app = new(App)
30+
31+
app.ctx, app.cancel = context.WithCancel(ctx)
32+
app.config = config
33+
34+
err = app.reconfigure()
35+
if err != nil {
36+
return
37+
}
38+
39+
return
40+
}
41+
42+
// Start launches the app and blocks until fatal error
43+
func (app *App) Start() (final error) {
44+
f := func() (err error) {
45+
select {
46+
case <-app.configWatcher.Events:
47+
err = app.reconfigure()
48+
}
49+
return
50+
}
51+
52+
zap.L().Debug("starting service daemon")
53+
54+
for {
55+
final = f()
56+
if final != nil {
57+
break
58+
}
59+
}
60+
return
61+
}

0 commit comments

Comments
 (0)