package main import ( "flag" "io" "log" "os" "os/exec" "path/filepath" "sort" "strings" "time" "unicode" ) type component struct { filename string wrapPre, wrapPost string files []string } func (c *component) combine(w io.Writer) (err error) { if c.wrapPre != "" { if _, err = io.WriteString(w, c.wrapPre); err != nil { return } } for _, fname := range c.files { var f *os.File if f, err = os.Open(fname); err != nil { return } if *verbose { log.Printf("processing file: %v", fname) } w.Write([]byte("// " + fname + "\n")) io.Copy(w, f) f.Close() if _, err = io.WriteString(w, ";\n"); err != nil { return } } if c.wrapPost != "" { if _, err = io.WriteString(w, c.wrapPost); err != nil { return } return } return } func getFileList() (files []string) { files = append(files, "js/mustache.js", "js/canvasRenderingTool.js", "js/templates.js", "js/dummyData.js", "js/core.js", "js/controllers.js") for _, d := range [...]string{"js/plugins/*.js", "js/controllers/*.js", "js/apps/base/*.js", "js/apps/*.js"} { lst, _ := filepath.Glob(d) sort.Strings(lst) files = append(files, lst...) } return } var ( closureExec = flag.String("cp", "google-closure-compiler", "the path to closure compiler (can include other args)") doCmp = flag.String("cmp", "default", "compile a component [default, drawmap, heatmaps]") output = flag.String("o", "", "output") verbose = flag.Bool("v", false, "output some debug stuff") components = map[string]*component{ "drawmap": { filename: "js/drawMap.compiled.js", files: []string{ "js/mustache.js", "js/plugins/loop.js", "js/plugins/eventManager.js", "js/plugins/elements.js", "js/plugins/elements.js", "js/plugins/dropdown.js", "js/plugins/psStore.js", "js/plugins/drawMap.js", }, }, "heatmaps": { filename: "js/heatmaps.compiled.js", wrapPre: "var heatmaps = (function(){\n\t", files: []string{ "js/mustache.js", "js/core.js", "js/plugins/loop.js", "js/plugins/eventManager.js", "js/plugins/psStore.js", "js/plugins/clickmap.js", "js/plugins/heatmaps.js", }, wrapPost: "\n\treturn heatmaps;\n})();", }, "default": { filename: "js/compiled.js", files: getFileList(), }, } ) func combineAll(files []string, pre, post string, w io.Writer) (err error) { var ( f *os.File sep = []byte(";\n") ) for _, fname := range files { if f, err = os.Open(fname); err != nil { return } if *verbose { log.Printf("processing file: %v", fname) } w.Write([]byte("// " + fname + "\n")) io.Copy(w, f) f.Close() if _, err = w.Write(sep); err != nil { return } } return } func shSplit(argv string) []string { lastQuote := rune(0) f := func(c rune) bool { switch { case c == lastQuote: lastQuote = rune(0) return false case lastQuote != rune(0): return false case unicode.In(c, unicode.Quotation_Mark): lastQuote = c return false default: return unicode.IsSpace(c) } } return strings.FieldsFunc(argv, f) } func main() { flag.Parse() log.SetFlags(log.Lshortfile | log.Lmicroseconds) var ( st = time.Now() cmp, ok = components[*doCmp] ) if !ok { log.Fatalf("%q not defined.", *doCmp) } if out := *output; out != "" { cmp.filename = out } defer func() { log.Printf("finished in %v", time.Now().Sub(st)) }() if *closureExec == "-" { f, err := os.Create(cmp.filename) if err != nil { log.Fatal(err) } defer f.Close() cmp.combine(f) } else if err := compile(cmp); err != nil { log.Printf("error compiling: %v", err) } } func compile(cmp *component) error { pr, pw := io.Pipe() defer pr.Close() argv := shSplit(*closureExec) if cmp.filename != "-" { argv = append(argv, `--js_output_file="`+cmp.filename+`"`) } //argv = append(argv, `--language_in=ECMASCRIPT5`) cmd := exec.Command(argv[0], argv[1:]...) cmd.Stdin = pr cmd.Stdout = os.Stdout if *verbose { log.Printf("executing %v", argv) cmd.Stderr = os.Stderr } go func() { pw.CloseWithError(cmp.combine(pw)) }() return cmd.Run() }