diff --git a/claat/cmd/build.go b/claat/cmd/build.go index 01b53284f..c1a8344f8 100644 --- a/claat/cmd/build.go +++ b/claat/cmd/build.go @@ -29,7 +29,9 @@ import ( "sync" ) -func CmdBuild() { +// CmdBuild is the "claat build ..." subcommand. +// It returns a process exit code. +func CmdBuild() int { const depsDir = "bower_components" var codelabElem = []byte(` @@ -46,6 +48,7 @@ func CmdBuild() { if err := writeFile(filepath.Join("elements", "codelab.html"), codelabElem); err != nil { log.Fatalf(err.Error()) } + return 0 } func writeFile(name string, content []byte) error { diff --git a/claat/cmd/export.go b/claat/cmd/export.go index 942b4ebb3..7afa484f8 100644 --- a/claat/cmd/export.go +++ b/claat/cmd/export.go @@ -34,6 +34,8 @@ type CmdExportOptions struct { AuthToken string // Expenv is the codelab environment to export to. Expenv string + // ExtraVars is extra template variables. + ExtraVars map[string]string // GlobalGA is the global Google Analytics account to use. GlobalGA string // Output is the output directory, or "-" for stdout. @@ -45,7 +47,9 @@ type CmdExportOptions struct { } // CmdExport is the "claat export ..." subcommand. -func CmdExport(opts CmdExportOptions) { +// It returns a process exit code. +func CmdExport(opts CmdExportOptions) int { + var exitCode int if flag.NArg() == 0 { log.Fatalf("Need at least one source. Try '-h' for options.") } @@ -65,11 +69,13 @@ func CmdExport(opts CmdExportOptions) { for range args { res := <-ch if res.err != nil { - errorf(reportErr, res.src, res.err) + exitCode = 1 + log.Printf(reportErr, res.src, res.err) } else if !isStdout(opts.Output) { log.Printf(reportOk, res.meta.ID) } } + return exitCode } // exportCodelab fetches codelab src from either local disk or remote, @@ -116,12 +122,13 @@ func exportCodelab(src string, opts CmdExportOptions) (*types.Meta, error) { } } // write codelab and its metadata to disk - return meta, writeCodelab(dir, clab.Codelab, ctx) + return meta, writeCodelab(dir, clab.Codelab, opts.ExtraVars, ctx) } // writeCodelab stores codelab main content in ctx.Format and its metadata // in JSON format on disk. -func writeCodelab(dir string, clab *types.Codelab, ctx *types.Context) error { +// extraVars is extra variables to pass into the template context. +func writeCodelab(dir string, clab *types.Codelab, extraVars map[string]string, ctx *types.Context) error { // output to stdout does not include metadata if !isStdout(dir) { // make sure codelab dir exists @@ -149,7 +156,7 @@ func writeCodelab(dir string, clab *types.Codelab, ctx *types.Context) error { GlobalGA: ctx.MainGA, Meta: &clab.Meta, Steps: clab.Steps, - Extra: ExtraVars, + Extra: extraVars, }} if ctx.Format != "offline" { w := os.Stdout diff --git a/claat/cmd/serve.go b/claat/cmd/serve.go index cba2cad7a..5b3ff60d4 100644 --- a/claat/cmd/serve.go +++ b/claat/cmd/serve.go @@ -23,7 +23,8 @@ import ( // CmdServe is the "claat serve ..." subcommand. // addr is the hostname and port to bind the web server to. -func CmdServe(addr string) { +// It returns a process exit code. +func CmdServe(addr string) int { CmdBuild() http.Handle("/", http.FileServer(http.Dir("."))) log.Printf("Serving codelabs on %s, opening browser tab now...", addr) @@ -33,6 +34,7 @@ func CmdServe(addr string) { }() openBrowser("http://" + addr) log.Fatalf("claat serve: %v", <-ch) + return 0 } // openBrowser tries to open the URL in a browser. diff --git a/claat/cmd/update.go b/claat/cmd/update.go index 8569cfe12..de061c738 100644 --- a/claat/cmd/update.go +++ b/claat/cmd/update.go @@ -34,6 +34,8 @@ import ( type CmdUpdateOptions struct { // AuthToken is the token to use for the Drive API. AuthToken string + // ExtraVars is extra template variables. + ExtraVars map[string]string // GlobalGA is the global Google Analytics account to use. GlobalGA string // Prefix is a URL prefix to prepend when using HTML format. @@ -41,7 +43,8 @@ type CmdUpdateOptions struct { } // CmdUpdate is the "claat update ..." subcommand. -func CmdUpdate(opts CmdUpdateOptions) { +// It returns a process exit code. +func CmdUpdate(opts CmdUpdateOptions) int { roots := flag.Args() if len(roots) == 0 { roots = []string{"."} @@ -69,14 +72,18 @@ func CmdUpdate(opts CmdUpdateOptions) { ch <- &result{d, meta, err} }(d) } + + var exitCode int for range dirs { res := <-ch if res.err != nil { - errorf(reportErr, res.dir, res.err) + exitCode = 1 + log.Printf(reportErr, res.dir, res.err) } else { log.Printf(reportOk, res.meta.ID) } } + return exitCode } // updateCodelab reads metadata from a dir/codelab.json file, @@ -122,7 +129,7 @@ func updateCodelab(dir string, opts CmdUpdateOptions) (*types.Meta, error) { } // write codelab and its metadata - if err := writeCodelab(newdir, clab.Codelab, &meta.Context); err != nil { + if err := writeCodelab(newdir, clab.Codelab, opts.ExtraVars, &meta.Context); err != nil { return nil, err } diff --git a/claat/cmd/util.go b/claat/cmd/util.go index 2afa09f25..e65ab8c28 100644 --- a/claat/cmd/util.go +++ b/claat/cmd/util.go @@ -20,9 +20,6 @@ package cmd import ( - "encoding/json" - "log" - "sync" // allow parsers to register themselves _ "github.com/googlecodelabs/tools/claat/parser/gdoc" @@ -43,36 +40,7 @@ const ( reportOk = "ok\t%s" ) -var ( - Exit int // program exit code - exitMu sync.Mutex // guards exit - ExtraVars map[string]string // Extra template variables passed on the command line. -) - // isStdout reports whether filename is stdout. func isStdout(filename string) bool { return filename == stdout } - -// errorf calls log.Printf with fmt and args, and sets non-zero exit code. -func errorf(format string, args ...interface{}) { - log.Printf(format, args...) - exitMu.Lock() - Exit = 1 - exitMu.Unlock() -} - -// ParseExtraVars parses extra template variables from command line. -// extra is any additional arguments to pass to format templates. Should be formatted as JSON objects of string:string KV pairs. -func ParseExtraVars(extra string) map[string]string { - vars := make(map[string]string) - if extra == "" { - return vars - } - b := []byte(extra) - err := json.Unmarshal(b, &vars) - if err != nil { - errorf("Error parsing additional template data: %v", err) - } - return vars -} diff --git a/claat/main.go b/claat/main.go index 5ecf98534..b5991ef47 100644 --- a/claat/main.go +++ b/claat/main.go @@ -20,6 +20,7 @@ package main import ( + "encoding/json" "flag" "fmt" "log" @@ -61,25 +62,32 @@ func main() { flag.Usage = usage flag.CommandLine.Parse(os.Args[2:]) - cmd.ExtraVars = cmd.ParseExtraVars(*extra) + extraVars, err := ParseExtraVars(*extra) + if err != nil { + os.Exit(1) + } + + exitCode := 0 switch os.Args[1] { case "export": - cmd.CmdExport(cmd.CmdExportOptions{ + exitCode = cmd.CmdExport(cmd.CmdExportOptions{ AuthToken: *authToken, Expenv: *expenv, + ExtraVars: extraVars, GlobalGA: *globalGA, Output: *output, Prefix: *prefix, Tmplout: *tmplout, }) case "serve": - cmd.CmdServe(*addr) + exitCode = cmd.CmdServe(*addr) case "build": - cmd.CmdBuild() + exitCode = cmd.CmdBuild() case "update": - cmd.CmdUpdate(cmd.CmdUpdateOptions{ + exitCode = cmd.CmdUpdate(cmd.CmdUpdateOptions{ AuthToken: *authToken, + ExtraVars: extraVars, GlobalGA: *globalGA, Prefix: *prefix, }) @@ -90,7 +98,24 @@ func main() { default: log.Fatalf("Unknown subcommand. Try '-h' for options.") } - os.Exit(cmd.Exit) + + os.Exit(exitCode) +} + +// ParseExtraVars parses extra template variables from command line. +// extra is any additional arguments to pass to format templates. Should be formatted as JSON objects of string:string KV pairs. +func ParseExtraVars(extra string) (map[string]string, error) { + vars := make(map[string]string) + if extra == "" { + return vars, nil + } + b := []byte(extra) + err := json.Unmarshal(b, &vars) + if err != nil { + log.Printf("Error parsing additional template data: %v", err) + return nil, err + } + return vars, nil } // usage prints usageText and program arguments to stderr.