Skip to content

Commit 10c6d2b

Browse files
author
Mario L Gutierrez
committed
support quoted env vars
1 parent 668ed4f commit 10c6d2b

File tree

9 files changed

+120
-34
lines changed

9 files changed

+120
-34
lines changed

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
. "gopkg.in/godo.v1"
2323
)
2424

25-
func Tasks(p *Project) {
25+
func tasks(p *Project) {
2626
Env = "GOPATH=.vendor::$GOPATH PG_PASSWORD=dev"
2727

2828
p.Task("default", D{"hello", "build"})
@@ -36,22 +36,23 @@ func Tasks(p *Project) {
3636
}
3737
})
3838

39-
p.Task("build", W{"**/*.go"}, func() {
39+
p.Task("build", func() {
4040
Run("GOOS=linux GOARCH=amd64 go build", In{"cmd/server"})
41-
})
41+
}).Watch("**/*.go")
4242

43-
p.Task("views", W{"templates/**/*.go.html"}, func() {
43+
p.Task("views", func() {
4444
Run("razor templates")
45-
})
45+
}).Watch("templates/**/*.go.html")
4646

47-
p.Task("server", D{"views"}, W{"server/**/*.go", "cmd/server/*.{go,json}"}, Debounce(3000), func() {
47+
p.Task("server", D{"views"}, func() {
4848
// rebuilds and restarts the process when a watched file changes
4949
Start("main.go", In{"cmd/server"})
50-
})
50+
}).Watch("server/**/*.go", "cmd/server/*.{go,json}").
51+
Debounce(3000)
5152
}
5253

5354
func main() {
54-
Godo(Tasks)
55+
Godo(tasks)
5556
}
5657
```
5758

@@ -77,7 +78,6 @@ p.Task("build?", func() {})
7778
Task options
7879

7980
D{} or Dependencies{} - dependent tasks which run before task
80-
Debounce() - minimum milliseconds before task can run again
8181
W{} or Watches{} - array of glob file patterns to watch
8282

8383
/**/ - match zero or more directories
@@ -86,7 +86,7 @@ Task options
8686
? - match a single non-separator char
8787
**/ - match any directory, start of pattern only
8888
/** - match any in this directory, end of pattern only
89-
! - removes files from resultset, start of pattern only
89+
! - removes files from result set, start of pattern only
9090

9191
Task handlers
9292

@@ -124,7 +124,7 @@ godo hello -- -n dude
124124
Args functions are categorized as
125125

126126
* `Must*` - Argument must be set by user or panic.
127-
127+
128128
```go
129129
c.Args.MustInt("number", "n")
130130
```

cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func killSpawned(command string) {
9797

9898
err := process.Kill()
9999
if err != nil {
100-
util.Error("Start", "Could not kill existing process %+v\n", process)
100+
util.Error("Start", "Could not kill existing process %+v\n%s\n", process, err.Error())
101101
return
102102
}
103103
}

env.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func interpolateEnv(env []string, kv string) string {
7070

7171
func getEnv(env []string, key string, checkParent bool) string {
7272
for _, kv := range env {
73-
pair := strings.Split(kv, "=")
73+
pair := splitKV(kv)
7474
if pair[0] == key {
7575
return pair[1]
7676
}
@@ -82,16 +82,28 @@ func getEnv(env []string, key string, checkParent bool) string {
8282
return ""
8383
}
8484

85+
func splitKV(kv string) []string {
86+
index := strings.Index(kv, "=")
87+
if index < 0 {
88+
return nil
89+
}
90+
91+
return []string{
92+
kv[0:index],
93+
kv[index+1:],
94+
}
95+
}
96+
8597
// upsertenv updates or inserts a key=value pair into an environment.
8698
func upsertenv(env *[]string, kv string) {
87-
pair := strings.Split(kv, "=")
88-
if len(pair) != 2 {
99+
pair := splitKV(kv)
100+
if pair == nil {
89101
return
90102
}
91103

92104
set := false
93105
for i, item := range *env {
94-
ipair := strings.Split(item, "=")
106+
ipair := splitKV(item)
95107
if ipair[0] == pair[0] {
96108
(*env)[i] = interpolateEnv(*env, kv)
97109
set = true
@@ -134,8 +146,8 @@ func parseStringEnv(s string) []string {
134146
}
135147

136148
s = str.Clean(s)
137-
pairs := strings.Split(s, " ")
138-
for _, kv := range pairs {
149+
argv := str.ToArgv(s)
150+
for _, kv := range argv {
139151
if !strings.Contains(kv, "=") {
140152
continue
141153
}

env_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ func TestEnvironment(t *testing.T) {
6363
SetEnviron("", true)
6464
}
6565

66+
func TestQuotedVar(t *testing.T) {
67+
// set back to defaults
68+
defer SetEnviron("", true)
69+
env := effectiveEnv([]string{`FOO="a=bar b=bah c=baz"`})
70+
v := getEnv(env, "FOO", false)
71+
if v != `"a=bar b=bah c=baz"` {
72+
t.Errorf("Quoted var failed %q", v)
73+
}
74+
}
75+
6676
func TestExpansion(t *testing.T) {
6777
SetEnviron(`
6878
FOO=foo

project.go

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (project *Project) namespaceTaskName(name string) (namespace string, taskNa
6262
}
6363

6464
func (project *Project) debounce(task *Task) bool {
65-
debounceMs := task.Debounce
65+
debounceMs := task.debounce
6666
if debounceMs == 0 {
6767
debounceMs = DebounceMs
6868
}
@@ -135,7 +135,7 @@ func (project *Project) usage() string {
135135

136136
for _, name := range names {
137137
task := m[name]
138-
description := task.Description
138+
description := task.description
139139
if description == "" {
140140
if len(task.Dependencies) > 0 {
141141
description = "Runs {" + strings.Join(task.Dependencies, ", ") + ", " + name + "} tasks"
@@ -156,6 +156,36 @@ func (project *Project) Use(namespace string, tasksFunc func(*Project)) {
156156
project.Namespace[namespace] = proj
157157
}
158158

159+
func printDeprecatedWatchWarning(name string, globs []string) {
160+
if !deprecatedWarnings {
161+
return
162+
}
163+
util.Deprecate(fmt.Sprintf(`W{} and Watch{} are deprecated. Use Task#Watch()
164+
p.Task("%s", func(){
165+
}).Watch(%q)
166+
`, name, globs[0]))
167+
}
168+
169+
func printDeprecatedDebounceWarning(name string, ms int64) {
170+
if !deprecatedWarnings {
171+
return
172+
}
173+
util.Deprecate(fmt.Sprintf(`Debounce() option is deprecated. Use Task#Debounce()
174+
p.Task("%s", func(){
175+
}).Debounce(%d)
176+
`, name, ms))
177+
}
178+
179+
func printDeprecatedDescriptionWarning(name string, desc string) {
180+
if !deprecatedWarnings {
181+
return
182+
}
183+
util.Deprecate(fmt.Sprintf(`Description option is deprecated. Use Task#Description()
184+
p.Task("%s", func(){
185+
}).Description(%q)
186+
`, name, desc))
187+
}
188+
159189
// Task adds a task to the project.
160190
func (project *Project) Task(name string, args ...interface{}) *Task {
161191
runOnce := false
@@ -170,21 +200,25 @@ func (project *Project) Task(name string, args ...interface{}) *Task {
170200
default:
171201
util.Panic("project", "unexpected type %T\n", t) // %T prints whatever type t has
172202
case Watch:
173-
task.WatchGlobs = t
203+
task.Watch(t...)
204+
printDeprecatedWatchWarning(name, t)
174205
case W:
175-
task.WatchGlobs = t
206+
task.Watch(t...)
207+
printDeprecatedWatchWarning(name, t)
176208
case Dependencies:
177209
task.Dependencies = t
178210
case D:
179211
task.Dependencies = t
180212
case Debounce:
181-
task.Debounce = int64(t)
213+
task.Debounce(int64(t))
214+
printDeprecatedDebounceWarning(name, int64(t))
182215
case func():
183216
task.Handler = t
184217
case func(*Context):
185218
task.ContextHandler = t
186219
case string:
187-
task.Description = t
220+
task.Description(t)
221+
printDeprecatedDescriptionWarning(name, t)
188222
}
189223
}
190224
project.Tasks[name] = task
@@ -197,7 +231,6 @@ func watchTask(root string, logName string, handler func(e *watcher.FileEvent))
197231
if err != nil {
198232
util.Panic("project", "%v\n", err)
199233
}
200-
//waitTime := time.Duration(0.1 * float64(time.Second))
201234
watchr.WatchRecursive(root)
202235
watchr.ErrorHandler = func(err error) {
203236
util.Error("project", "%v\n", err)
@@ -220,8 +253,6 @@ func watchTask(root string, logName string, handler func(e *watcher.FileEvent))
220253
continue
221254
}
222255
handler(event)
223-
// prevent multiple restart in short time
224-
//time.Sleep(waitTime)
225256
}
226257
}
227258

runner.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var watching bool
1212
var help bool
1313
var verbose bool
1414
var version bool
15+
var deprecatedWarnings bool
1516

1617
// DebounceMs is the default time (1500 ms) to debounce task events in watch mode.
1718
var DebounceMs int64
@@ -31,6 +32,7 @@ func Usage(tasks string) {
3132
format := `godo %s - do task(s)
3233
3334
Usage: godo [flags] [task...]
35+
-D Print deprecated warnings
3436
-h, --help This screen
3537
--verbose Log verbosely
3638
-v, --version Print version
@@ -60,6 +62,7 @@ func godo(tasksFunc func(*Project), argv []string) {
6062
verbose = argm.ZeroBool("verbose")
6163
version = argm.ZeroBool("version", "v")
6264
watching = argm.ZeroBool("watch", "w")
65+
deprecatedWarnings = argm.ZeroBool("D")
6366
contextArgm = minimist.ParseArgv(argm.Unparsed())
6467

6568
project := NewProject(tasksFunc)

task.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
// A Task is an operation performed on a user's project directory.
1717
type Task struct {
1818
Name string
19-
Description string
19+
description string
2020
Dependencies []string
2121
Handler func()
2222
ContextHandler func(*Context)
@@ -34,7 +34,7 @@ type Task struct {
3434
// Complete indicates whether this task has already ran. This flag is
3535
// ignored in watch mode.
3636
Complete bool
37-
Debounce int64
37+
debounce int64
3838
RunOnce bool
3939
}
4040

@@ -142,3 +142,27 @@ func (task *Task) RunWithEvent(logName string, e *watcher.FileEvent) {
142142

143143
task.Complete = true
144144
}
145+
146+
// Debounce is minimum milliseconds before task can run again
147+
func (task *Task) Debounce(ms int64) *Task {
148+
if ms > 0 {
149+
task.debounce = ms
150+
}
151+
return task
152+
}
153+
154+
// Watch a set of glob file patterns.
155+
func (task *Task) Watch(globs ...string) *Task {
156+
if len(globs) > 0 {
157+
task.WatchGlobs = globs
158+
}
159+
return task
160+
}
161+
162+
// Description sets the description for the task.
163+
func (task *Task) Description(desc string) *Task {
164+
if desc != "" {
165+
task.description = desc
166+
}
167+
return task
168+
}

tasks/Godofile.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import (
99
. "gopkg.in/godo.v1"
1010
)
1111

12-
// Tasks is local project.
13-
func Tasks(p *Project) {
12+
func tasks(p *Project) {
1413

1514
p.Task("dist", D{"test", "lint"})
1615

@@ -56,12 +55,12 @@ func Tasks(p *Project) {
5655
Run("whoami")
5756
})
5857

59-
p.Task("hello", func(c *Context) {
58+
p.Task("hello", Debounce(3000), W{"*.hello"}, func(c *Context) {
6059
name := c.Args.MayString("default value", "name", "n")
6160
fmt.Println("Hello", name)
6261
})
6362
}
6463

6564
func main() {
66-
Godo(Tasks)
65+
Godo(tasks)
6766
}

util/logging.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package util
22

33
import (
44
"fmt"
5-
"github.com/mgutz/ansi"
65
"runtime"
6+
7+
"github.com/mgutz/ansi"
78
)
89

910
var cyan = ansi.ColorFunc("cyan")
1011
var red = ansi.ColorFunc("red+b")
12+
var yellow = ansi.ColorFunc("yellow+b")
1113
var redInverse = ansi.ColorFunc("white:red")
1214
var gray = ansi.ColorFunc("black+h")
1315
var magenta = ansi.ColorFunc("magenta+h")
@@ -41,3 +43,8 @@ func Panic(group string, format string, any ...interface{}) {
4143
fmt.Printf(redInverse(group) + " ")
4244
fmt.Printf(redInverse(format), any...)
4345
}
46+
47+
// Deprecate writes a deprecation warning.
48+
func Deprecate(message string) {
49+
fmt.Printf(yellow("godo") + " " + message)
50+
}

0 commit comments

Comments
 (0)