godo

package module
v2.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2015 License: MIT Imports: 23 Imported by: 99

README

Documentation is WIP

godo

godoc

godo is a task runner and file watcher for golang in the spirit of rake, gulp.

To install

go get -u gopkg.in/godo.v2/cmd/godo

Godofile

Godo runs Gododir/main.go.

As an example, create a file Gododir/main.go with this content

package main

import (
    "fmt"
    do "gopkg.in/godo.v2"
)

func tasks(p *do.Project) {
    do.Env = `GOPATH=.vendor::$GOPATH`

    p.Task("default", do.S{"hello", "build"}, nil)

    p.Task("hello", nil, func(c *do.Context) {
        name := c.Args.AsString("name", "n")
        if name == "" {
            c.Bash("echo Hello $USER!")
        } else {
            fmt.Println("Hello", name)
        }
    })

    p.Task("assets?", nil,  func(c *do.Context) {
        // The "?" tells Godo to run this task ONLY ONCE regardless of
        // how many tasks depend on it. In this case watchify watches
        // on its own.
	    c.Run("watchify public/js/index.js d -o dist/js/app.bundle.js")
    }).Src("public/**/*.{css,js,html}")

    p.Task("build", do.S{"views", "assets"}, func(c *do.Context) {
        c.Run("GOOS=linux GOARCH=amd64 go build", do.M{"$in": "cmd/server"})
    }).Src("**/*.go")

    p.Task("server", do.S{"views", "assets"}, func(c *do.Context) {
        // rebuilds and restarts when a watched file changes
        c.Start("main.go", do.M{"$in": "cmd/server"})
    }).Src("server/**/*.go", "cmd/server/*.{go,json}").
       Debounce(3000)

    p.Task("views", nil, func(c *do.Context) {
        c.Run("razor templates")
    }).Src("templates/**/*.go.html")
}

func main() {
    do.Godo(tasks)
}

To run "server" task from parent dir of tasks/

godo server

To rerun "server" and its dependencies whenever any of their watched files change

godo server --watch

To run the "default" task which runs "hello" and "build"

godo

Task names may add a "?" suffix to execute only once even when watching

// build once regardless of number of dependents
p.Task("assets?", nil, func(*do.Context) {})

Task dependencies

S{} or Series{} - dependent tasks to run in series
P{} or Parallel{} - dependent tasks to run in parallel

For example, S{"clean", P{"stylesheets", "templates"}, "build"}
Task Option Funcs
  • Task#Src() - specify watch paths or the src files for Task#Dest()

    Glob patterns
    
        /**/   - match zero or more directories
        {a,b}  - match a or b, no spaces
        *      - match any non-separator char
        ?      - match a single non-separator char
        **/    - match any directory, start of pattern only
        /**    - match any in this directory, end of pattern only
        !      - removes files from result set, start of pattern only
    
  • Task#Dest(globs ...string) - If globs in Src are newer than Dest, then the task is run

  • Task#Desc(description string) - Set task's description in usage.

  • Task#Debounce(duration time.Duration) - Disallow a task from running until duration has elapsed.

  • Task#Deps(names ...interface{}) - Can be {S, Series, P, Parallel, string}

Task CLI Arguments

Task CLI arguments follow POSIX style flag convention (unlike go's built-in flag package). Any command line arguments succeeding -- are passed to each task. Note, arguments before -- are reserved for godo.

As an example,

p.Task("hello", nil, func(c *do.Context) {
    // "(none)" is the default value
    msg := c.Args.MayString("(none)", "message", "msg", "m")
    var name string
    if len(c.Args.NonFlags() == 1) {
        name = c.Args.NonFlags()[0]
    }
    fmt.Println(msg, name)
})

running

# prints "(none)"
godo hello

# prints "Hello dude" using POSIX style flags
godo hello -- dude --message Hello
godo hello -- dude --msg Hello
godo hello -- -m Hello dude

Args functions are categorized as

  • Must* - Argument must be set by user or panic.

c.Args.MustInt("number", "n")


*  `May*` - If argument is not set, default to first value.

    ```go
// defaults to 100
c.Args.MayInt(100, "number", "n")
  • As* - If argument is not set, default to zero value.

// defaults to 0 c.Args.AsInt("number", "n")



## Modularity and Namespaces

A project may include other tasks functions with `Project#Use`. `Use` requires a namespace to
prevent task name conflicts with existing tasks.

```go
func buildTasks(p *do.Project) {
    p.Task("default", S{"clean"}, nil)

    p.Task("clean", nil, func(*do.Context) {
        fmt.Println("build clean")
    })
}

func tasks(p *do.Project) {
    p.Use("build", buildTasks)

    p.Task("clean", nil, func(*do.Context) {
        fmt.Println("root clean")
    })

    p.Task("build", do.S{"build:default"}, func(*do.Context) {
        fmt.Println("root clean")
    })
}

Running godo build:. or godo build results in output of build clean. Note that it uses the clean task in its namespace not the clean in the parent project.

The special name build:. is alias for build:default.

Task dependencies that start with "/" are relative to the parent project and may be called referenced from sub projects.

godobin

godo compiles Godofile.go to godobin-VERSION (godobin-VERSION.exe on Windows) whenever Godofile.go changes. The binary file is built into the same directory as Godofile.go and should be ignored by adding the path godobin* to .gitignore.

Exec functions

All of these functions accept a map[string]interface{} or M for options. Option keys that start with "$" are reserved for godo. Other fields can be used as context for template.

Bash

Bash functions uses the bash executable and may not run on all OS.

Run a bash script string. The script can be multiline line with continutation.

Bash(`
    echo -n $USER
    echo some really long \
        command
`)

Bash can use Go templates

Bash(`echo -n {{.name}}`, do.M{"name": "mario", "$in": "cmd/bar"})

Run a bash script and capture STDOUT and STDERR.

output, err := BashOutput(`echo -n $USER`)
Run

Run go build inside of cmd/app and set environment variables.

Run(`GOOS=linux GOARCH=amd64 go build`, do.M{"$in": "cmd/app"})

Run can use Go templates

Run(`echo -n {{.name}}`, do.M{"name": "mario", "$in": "cmd/app"})

Run and capture STDOUT and STDERR

output, err := RunOutput("whoami")
Start

Start an async command. If the executable has suffix ".go" then it will be "go install"ed then executed. Use this for watching a server task.

Start("main.go", M{"$in": "cmd/app"})

Godo tracks the process ID of started processes to restart the app gracefully.

Inside

To run many commands inside a directory, use Inside instead of the $in option. Inside changes the working directory.

Inside("somedir", func() {
    Run("...")
    Bash("...")
})

User Input

To get plain string

user := Prompt("user: ")

To get password

password := PromptPassword("password: ")

Godofile Run-Time Environment

From command-line

Environment variables may be set via key-value pairs as arguments to godo. This feature was added to facilitate users on Windows.

godo NAME=mario GOPATH=./vendor hello
From source code

To specify whether to inherit from parent's process environment, set InheritParentEnv. This setting defaults to true

InheritParentEnv = false

To specify the base environment for your tasks, set Env. Separate with whitespace or newlines.

Env = `
    GOPATH=.vendor::$GOPATH
    PG_USER=mario
`

TIP: Set the Env when using a dependency manager like godep

wd, _ := os.Getwd()
ws := path.Join(wd, "Godeps/_workspace")
Env = fmt.Sprintf("GOPATH=%s::$GOPATH", ws)

Functions can add or override environment variables as part of the command string. Note that environment variables are set before the executable similar to a shell; however, the Run and Start functions do not use a shell.

p.Task("build", nil, func(c *Context) {
    c.Run("GOOS=linux GOARCH=amd64 go build" )
})

The effective environment for exec functions is: parent (if inherited) <- Env <- func parsed env

Paths should use :: as a cross-platform path list separator. On Windows :: is replaced with ;. On Mac and linux :: is replaced with :.

From godoenv file

For special circumstances where the GOPATH needs to be set before building the Gododir, use Gododir/godoenv file.

    # Gododir/godoenv
    GOPATH=$PWD/cmd/app/Godeps/_workspace::$GOPATH

Documentation

Overview

Package godo is a task runner, file watcher in the spirit of Rake, Gulp ...

To install

go get -u gopkg.in/godo.v2/cmd/godo

Index

Constants

View Source
const (
	// CaptureStdout is a bitmask to capture STDOUT
	CaptureStdout = 1
	// CaptureStderr is a bitmask to capture STDERR
	CaptureStderr = 2
	// CaptureBoth captures STDOUT and STDERR
	CaptureBoth = CaptureStdout + CaptureStderr
)

Variables

View Source
var Debounce time.Duration

DebounceMs is the default time (1500 ms) to debounce task events in watch mode.

Env is the default environment to use for all commands. That is, the effective environment for all commands is the merged set of (parent environment, Env, func specified environment). Whitespace or newline separate key value pairs. $VAR interpolation is allowed.

Env = "GOOS=linux GOARCH=amd64" Env = `

GOOS=linux
GOPATH=./vendor:$GOPATH

`

View Source
var InheritParentEnv bool

InheritParentEnv whether to inherit parent's environment

View Source
var PathListSeparator = "::"

PathListSeparator is a cross-platform path list separator. On Windows, PathListSeparator is replacd by ";". On others, PathListSeparator is replaced by ":"

View Source
var Processes = make(map[string]*os.Process)

Proccesses are the processes spawned by Start()

View Source
var Version = "2.0.0-pre"

Version is the current version

Functions

func Bash

func Bash(script string, options ...map[string]interface{}) (string, error)

Bash executes a bash script (string).

func BashOutput

func BashOutput(script string, options ...map[string]interface{}) (string, error)

BashOutput executes a bash script and returns the output

func EffectiveEnv added in v2.0.2

func EffectiveEnv(funcEnv []string) []string

EffectiveEnv is the effective environment for an exec function.

func GetWatchDelay

func GetWatchDelay() time.Duration

GetWatchDelay gets the watch delay

func Getenv

func Getenv(key string) string

Getenv environment variable from a string array.

func GoThrottle

func GoThrottle(throttle int, fns ...func() error) error

GoThrottle starts to run the given list of fns concurrently, at most n fns at a time.

func Godo

func Godo(tasksFunc func(*Project))

Godo runs a project of tasks.

func Halt

func Halt(v interface{})

Halt is a soft panic and stops a task.

func Inside

func Inside(dir string, lambda func()) error

Inside temporarily changes the working directory and restores it when lambda finishes.

func ParseStringEnv added in v2.0.2

func ParseStringEnv(s string) []string

ParseStringEnv parse the package Env string and converts it into an environment slice.

func Prompt

func Prompt(prompt string) string

Prompt prompts user for input with default value.

func PromptPassword

func PromptPassword(prompt string) string

PromptPassword prompts user for password input.

func Run

func Run(commandstr string, options ...map[string]interface{}) (string, error)

Run runs a command.

func RunOutput

func RunOutput(commandstr string, options ...map[string]interface{}) (string, error)

RunOutput runs a command and returns output.

func SetEnviron

func SetEnviron(envstr string, inheritParent bool)

SetEnviron sets the environment for child processes. Note that SetEnviron(Env, InheritParentEnv) is called once automatically.

func SetWatchDelay

func SetWatchDelay(delay time.Duration)

SetWatchDelay sets the time duration between watches.

func Start

func Start(commandstr string, options ...map[string]interface{}) error

Start starts an async command. If executable has suffix ".go" then it will be "go install"ed then executed. Use this for watching a server task.

If Start is called with the same command it kills the previous process.

The working directory is optional.

func Usage

func Usage(tasks string)

Usage prints a usage screen with task descriptions.

Types

type Context

type Context struct {
	// Task is the currently running task.
	Task *Task

	// FileEvent is an event from the watcher with change details.
	FileEvent *watcher.FileEvent

	// Task command line arguments
	Args minimist.ArgMap

	Error error
}

Context is the data passed to a task.

func (*Context) AnyFile

func (context *Context) AnyFile() []string

AnyFile returns either a non-DELETe FileEvent file or the WatchGlob patterns which can be used by goa.Load()

func (*Context) Bash

func (context *Context) Bash(cmd string, options ...map[string]interface{})

Bash runs a bash shell.

func (*Context) BashOutput added in v2.0.1

func (context *Context) BashOutput(script string, options ...map[string]interface{}) string

BashOutput executes a bash script and returns the output

func (*Context) Check

func (context *Context) Check(err error, msg string)

Check halts the task if err is not nil.

Do this

Check(err, "Some error occured")

Instead of

if err != nil {
	Halt(err)
}

func (*Context) Run

func (context *Context) Run(cmd string, options ...map[string]interface{})

Run runs a command

func (*Context) RunOutput added in v2.0.1

func (context *Context) RunOutput(commandstr string, options ...map[string]interface{}) string

RunOutput runs a command and returns output.

func (*Context) Start

func (context *Context) Start(cmd string, options ...map[string]interface{})

Start run aysnchronously.

type Dependency

type Dependency interface {
	// contains filtered or unexported methods
}

Dependency marks an interface as a dependency.

type Handler

type Handler interface {
	Handle(*Context)
}

Handler is the interface which all task handlers eventually implement.

type HandlerFunc

type HandlerFunc func(*Context)

HandlerFunc is a Handler adapter.

func (HandlerFunc) Handle

func (f HandlerFunc) Handle(ctx *Context)

Handle implements Handler.

type M

type M map[string]interface{}

M is generic string to interface alias

type Message

type Message struct {
	Event string
	Data  string
}

Message are sent on the Events channel

type P

type P []interface{}

P is alias for Parallel

type Parallel

type Parallel []interface{}

Parallel runs tasks in parallel

type Project

type Project struct {
	sync.Mutex
	Tasks     map[string]*Task
	Namespace map[string]*Project
	// contains filtered or unexported fields
}

Project is a container for tasks.

func NewProject

func NewProject(tasksFunc func(*Project), exitFn func(code int), argm minimist.ArgMap) *Project

NewProject creates am empty project ready for tasks.

func (*Project) Define

func (project *Project) Define(fn func(*Project))

Define defines tasks

func (*Project) Exit

func (project *Project) Exit(code int)

Exit quits the project.

func (*Project) Run

func (project *Project) Run(name string) error

Run runs a task by name.

func (*Project) Task

func (project *Project) Task(name string, dependencies Dependency, handler func(*Context)) *Task

Task adds a task to the project with dependencies and handler.

func (*Project) Task1

func (project *Project) Task1(name string, handler func(*Context)) *Task

Task1 adds a simple task to the project.

func (*Project) TaskD

func (project *Project) TaskD(name string, dependencies Dependency) *Task

TaskD adds a task which runs other dependencies with no handler.

func (*Project) Use

func (project *Project) Use(namespace string, tasksFunc func(*Project))

Use uses another project's task within a namespace.

func (*Project) Watch

func (project *Project) Watch(names []string, isParent bool) bool

Watch watches the Files of a task and reruns the task on a watch event. Any direct dependency is also watched. Returns true if watching.

TODO: 1. Only the parent task watches, but it gathers wath info from all dependencies.

2. Anything without src files always run when a dependency is triggered by a glob match.

build [generate{*.go} compile] => go file changes =>  build, generate and compile

3. Tasks with src only run if it matches a src

build [generate{*.go} css{*.scss} compile] => go file changes => build, generate and compile
css does not need to run since no SCSS files ran

X depends on [A:txt, B] => txt changes A runs, X runs without deps X:txt on [A, B] => txt changes A, B, X runs

type S

type S []interface{}

S is alias for Series

type Series

type Series []interface{}

Series are dependent tasks which must run in series.

type Task

type Task struct {
	Name string

	Handler Handler

	// computed based on dependencies
	EffectiveWatchRegexps []*glob.RegexpInfo
	EffectiveWatchGlobs   []string

	// Complete indicates whether this task has already ran. This flag is
	// ignored in watch mode.
	Complete bool

	RunOnce bool

	SrcFiles   []*glob.FileAsset
	SrcGlobs   []string
	SrcRegexps []*glob.RegexpInfo

	DestFiles   []*glob.FileAsset
	DestGlobs   []string
	DestRegexps []*glob.RegexpInfo

	// used when a file event is received between debounce intervals, the file event
	// will queue itself and set this flag and force debounce to run it
	// when time has elapsed
	sync.Mutex
	// contains filtered or unexported fields
}

A Task is an operation performed on a user's project directory.

func NewTask

func NewTask(name string, argm minimist.ArgMap) *Task

NewTask creates a new Task.

func (*Task) Debounce

func (task *Task) Debounce(duration time.Duration) *Task

Debounce is minimum milliseconds before task can run again

func (*Task) DependencyNames

func (task *Task) DependencyNames() []string

DependencyNames gets the flattened dependency names.

func (*Task) Deps

func (task *Task) Deps(names ...interface{})

Deps are task dependencies and must specify how to run tasks in series or in parallel.

func (*Task) Desc

func (task *Task) Desc(desc string) *Task

Desc is alias for Description.

func (*Task) Description

func (task *Task) Description(desc string) *Task

Description sets the description for the task.

func (*Task) Dest

func (task *Task) Dest(globs ...string) *Task

Dest adds target globs which are used to calculated outdated files. The tasks is not run unless ANY file Src are newer than ANY in DestN.

func (*Task) Run

func (task *Task) Run() error

Run runs all the dependencies of this task and when they have completed, runs this task.

func (*Task) RunWithEvent

func (task *Task) RunWithEvent(logName string, e *watcher.FileEvent) (err error)

RunWithEvent runs this task when triggered from a watch. *e* FileEvent contains information about the file/directory which changed in watch mode.

func (*Task) Src

func (task *Task) Src(globs ...string) *Task

Src adds a source globs to this task. The task is not run unless files are outdated between Src and Dest globs.

type WaitGroupN

type WaitGroupN struct {
	sync.WaitGroup
	sync.Mutex
	N int
}

WaitGroupN is a custom wait group that tracks the number added so it can be stopped.

func (*WaitGroupN) Add

func (wg *WaitGroupN) Add(n int)

Add adds to counter.

func (*WaitGroupN) Done

func (wg *WaitGroupN) Done()

Done removes from counter.

func (*WaitGroupN) Stop

func (wg *WaitGroupN) Stop()

Stop calls done on remaining counter.

Directories

Path Synopsis
cmd
Package util contains general purpose utility and logging functions.
Package util contains general purpose utility and logging functions.
Package watcher implements filesystem notification,.
Package watcher implements filesystem notification,.
fswatch
Package fswatch provides simple UNIX file system watching in Go.
Package fswatch provides simple UNIX file system watching in Go.
fswatch/clinotify
clinotify provides an example file system watching command line app.
clinotify provides an example file system watching command line app.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL