func Compile() gonzo.Stage { return func(ctx context.Context, in <-chan gonzo.File, out chan<- gonzo.File) error { for { select { case file, ok := <-in: if !ok { return nil } buff := new(bytes.Buffer) name := strings.TrimSuffix(file.FileInfo().Name(), ".gcss") + ".css" ctx.Infof("Compiling %s to %s", file.FileInfo().Name(), name) n, err := gcss.Compile(buff, file) if err != nil { return err } file = gonzo.NewFile(ioutil.NopCloser(buff), file.FileInfo()) file.FileInfo().SetSize(int64(n)) file.FileInfo().SetName(name) out <- file case <-ctx.Done(): return nil } } } }
// Write the given source bytes as GCSS converted to CSS, to a writer. // filename is only used if there are errors. func gcssPage(w http.ResponseWriter, req *http.Request, filename string, gcssdata []byte) { var buf bytes.Buffer if _, err := gcss.Compile(&buf, bytes.NewReader(gcssdata)); err != nil { if debugMode { fmt.Fprintf(w, "Could not compile GCSS:\n\n%s\n%s", err, string(gcssdata)) } else { log.Errorf("Could not compile GCSS:\n%s\n%s", err, string(gcssdata)) } return } // Write the resulting GCSS to the client NewDataBlock(buf.Bytes()).ToClient(w, req) }
// compileCSS gets the CSS name from the URL, determines if there is a pre-built version // and compiles the CSS if need be before serving it to the client func compileCSS(w http.ResponseWriter, r *http.Request) { file := r.URL.Path[len("/css/"):] if file == "" { errorHandler(w, r, http.StatusInternalServerError, "did not get a name of a CSS file") return } if !appengine.IsDevAppServer() { _, err := os.Stat("static/css/" + file) if err == nil { http.ServeFile(w, r, "static/css/"+file) return } } // check if a generated version of the file exists _, err := os.Stat("static/css/" + file) if err == nil { http.ServeFile(w, r, "static/css/"+file) return } // convert the .css extension to .gcss and build out path to the file f := gcss.Path(file) f = fmt.Sprintf("static/css/%s", f) // read the GCSS file css, err := os.Open(f) if err != nil { errorHandler(w, r, http.StatusInternalServerError, err.Error()) return } // close out the file resource once done defer func() { if err := css.Close(); err != nil { errorHandler(w, r, http.StatusInternalServerError, err.Error()) return } }() // set the content type header so browsers will know how to handle it w.Header().Set("Content-Type", "text/css") // build out the CSS and serve it to the browser _, err = gcss.Compile(w, css) if err != nil { errorHandler(w, r, http.StatusInternalServerError, err.Error()) return } }
// CompileStylesheets compiles a set of stylesheet files into a single large // file by appending them all to each other. Files are appended in alphabetical // order so we depend on the fact that there aren't too many interdependencies // between files. CSS reset in particular is given an underscore prefix so that // it gets to load first. // // If a file has a ".sass" suffix, we attempt to render it as GCSS. This isn't // a perfect symmetry, but works well enough for these cases. func CompileStylesheets(inPath, outPath string) error { start := time.Now() defer func() { log.Debugf("Compiled stylesheet assets in %v.", time.Now().Sub(start)) }() log.Debugf("Building: %v", outPath) stylesheetInfos, err := ioutil.ReadDir(inPath) if err != nil { return err } outFile, err := os.Create(outPath) if err != nil { return err } defer outFile.Close() for _, stylesheetInfo := range stylesheetInfos { if isHidden(stylesheetInfo.Name()) { continue } log.Debugf("Including: %v", stylesheetInfo.Name()) inFile, err := os.Open(path.Join(inPath, stylesheetInfo.Name())) if err != nil { return err } outFile.WriteString("/* " + stylesheetInfo.Name() + " */\n\n") if strings.HasSuffix(stylesheetInfo.Name(), ".sass") { _, err := gcss.Compile(outFile, inFile) if err != nil { return fmt.Errorf("Error compiling %v: %v", stylesheetInfo.Name(), err) } } else { _, err := io.Copy(outFile, inFile) if err != nil { return err } } outFile.WriteString("\n\n") } return nil }
func main() { v := flag.Bool("v", false, "Print the version and exit.") flag.Parse() if *v { writeTo(os.Stdout, gcss.Version) exit(0) return } args := flag.Args() argsL := len(args) if argsL > validArgsLen { writeTo(os.Stderr, "The number of the command line args should be 1.") exit(1) return } if argsL == 0 { if _, err := gcss.Compile(os.Stdout, stdin); err != nil { writeTo(os.Stderr, err.Error()) exit(1) return } } else { pathc, errc := gcss.CompileFile(args[0]) select { case path := <-pathc: writeTo(os.Stdout, "compiled "+path) case err := <-errc: writeTo(os.Stderr, err.Error()) exit(1) return } } }
func getStyles() string { if stylesheet != "" { return stylesheet } asset, err := os.Open("assets/stylesheet.gcss") if err != nil { log.Fatalln(err) } defer asset.Close() var buffer bytes.Buffer if _, err := gcss.Compile(&buffer, asset); err != nil { log.Fatalln(err) } result := buffer.String() if isDebugMode() != true { stylesheet = result } return result }
// Expose functions that are related to rendering text, to the given Lua state func exportRenderFunctions(w http.ResponseWriter, req *http.Request, L *lua.LState) { // Output Markdown as HTML L.SetGlobal("mprint", L.NewFunction(func(L *lua.LState) int { // Retrieve all the function arguments as a bytes.Buffer buf := arguments2buffer(L, true) // Convert the buffer to markdown and return the translated string w.Write(blackfriday.MarkdownCommon([]byte(buf.String()))) return 0 // number of results })) // Output text as rendered amber. L.SetGlobal("aprint", L.NewFunction(func(L *lua.LState) int { // Retrieve all the function arguments as a bytes.Buffer buf := arguments2buffer(L, true) // Use the buffer as a template. // Options are "Pretty printing, but without line numbers." tpl, err := amber.Compile(buf.String(), amber.Options{PrettyPrint: true, LineNumbers: false}) if err != nil { if debugMode { fmt.Fprint(w, "Could not compile Amber template:\n\t"+err.Error()+"\n\n"+buf.String()) } else { log.Errorf("Could not compile Amber template:\n%s\n%s", err, buf.String()) } return 0 // number of results } // Using "MISSING" instead of nil for a slightly better error message // if the values in the template should not be found. tpl.Execute(w, "MISSING") return 0 // number of results })) // Output text as rendered GCSS L.SetGlobal("gprint", L.NewFunction(func(L *lua.LState) int { // Retrieve all the function arguments as a bytes.Buffer buf := arguments2buffer(L, true) // Transform GCSS to CSS and output the result. // Ignoring the number of bytes written. if _, err := gcss.Compile(w, &buf); err != nil { if debugMode { fmt.Fprint(w, "Could not compile GCSS:\n\t"+err.Error()+"\n\n"+buf.String()) } else { log.Errorf("Could not compile GCSS:\n%s\n%s", err, buf.String()) } //return 0 // number of results } return 0 // number of results })) // Output text as rendered JSX L.SetGlobal("jprint", L.NewFunction(func(L *lua.LState) int { // Retrieve all the function arguments as a bytes.Buffer buf := arguments2buffer(L, true) // Transform JSX to JavaScript and output the result. prog, err := parser.ParseFile(nil, "<input>", &buf, parser.IgnoreRegExpErrors) if err != nil { if debugMode { // TODO: Use a similar error page as for Lua fmt.Fprint(w, "Could not parse JSX:\n\t"+err.Error()+"\n\n"+buf.String()) } else { log.Errorf("Could not parse JSX:\n%s\n%s", err, buf.String()) } return 0 // number of results } gen, err := generator.Generate(prog) if err != nil { if debugMode { // TODO: Use a similar error page as for Lua fmt.Fprint(w, "Could not generate JavaScript:\n\t"+err.Error()+"\n\n"+buf.String()) } else { log.Errorf("Could not generate JavaScript:\n%s\n%s", err, buf.String()) } return 0 // number of results } if gen != nil { io.Copy(w, gen) } return 0 // number of results })) }
// Check if the given data is valid GCSS func validGCSS(gcssdata []byte) error { buf := bytes.NewBuffer(gcssdata) var w bytes.Buffer _, err := gcss.Compile(&w, buf) return err }