diff --git a/tools/format b/tools/format index 99c5089..cdec6a5 100755 --- a/tools/format +++ b/tools/format @@ -2,7 +2,7 @@ set -eo pipefail -paths=$(ls tools/*.go examples/*/*.go) +paths=$(ls examples/*/*.go) gbe_to_4spaces() { local os=$(tr [A-Z] [a-z] <<< "`uname`") diff --git a/tools/generate.go b/tools/generate.go index ee5db8d..c30137f 100644 --- a/tools/generate.go +++ b/tools/generate.go @@ -1,17 +1,17 @@ package main import ( - "crypto/sha1" - "fmt" - "github.com/russross/blackfriday" - "io/ioutil" - "net/http" - "os" - "os/exec" - "path/filepath" - "regexp" - "strings" - "text/template" + "crypto/sha1" + "fmt" + "github.com/russross/blackfriday" + "io/ioutil" + "net/http" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "text/template" ) var cacheDir = "/tmp/gobyexample-cache" @@ -19,99 +19,99 @@ var siteDir = "./public" var pygmentizeBin = "./vendor/pygments/pygmentize" func check(err error) { - if err != nil { - panic(err) - } + if err != nil { + panic(err) + } } func ensureDir(dir string) { - err := os.MkdirAll(dir, 0755) - check(err) + err := os.MkdirAll(dir, 0755) + check(err) } func copyFile(src, dst string) { - dat, err := ioutil.ReadFile(src) - check(err) - err = ioutil.WriteFile(dst, dat, 0644) - check(err) + dat, err := ioutil.ReadFile(src) + check(err) + err = ioutil.WriteFile(dst, dat, 0644) + check(err) } func pipe(bin string, arg []string, src string) []byte { - cmd := exec.Command(bin, arg...) - in, err := cmd.StdinPipe() - check(err) - out, err := cmd.StdoutPipe() - check(err) - err = cmd.Start() - check(err) - _, err = in.Write([]byte(src)) - check(err) - err = in.Close() - check(err) - bytes, err := ioutil.ReadAll(out) - check(err) - err = cmd.Wait() - check(err) - return bytes + cmd := exec.Command(bin, arg...) + in, err := cmd.StdinPipe() + check(err) + out, err := cmd.StdoutPipe() + check(err) + err = cmd.Start() + check(err) + _, err = in.Write([]byte(src)) + check(err) + err = in.Close() + check(err) + bytes, err := ioutil.ReadAll(out) + check(err) + err = cmd.Wait() + check(err) + return bytes } func sha1Sum(s string) string { - h := sha1.New() - h.Write([]byte(s)) - b := h.Sum(nil) - return fmt.Sprintf("%x", b) + h := sha1.New() + h.Write([]byte(s)) + b := h.Sum(nil) + return fmt.Sprintf("%x", b) } func mustReadFile(path string) string { - bytes, err := ioutil.ReadFile(path) - check(err) - return string(bytes) + bytes, err := ioutil.ReadFile(path) + check(err) + return string(bytes) } func cachedPygmentize(lex string, src string) string { - ensureDir(cacheDir) - arg := []string{"-l", lex, "-f", "html"} - cachePath := cacheDir + "/pygmentize-" + strings.Join(arg, "-") + "-" + sha1Sum(src) - cacheBytes, cacheErr := ioutil.ReadFile(cachePath) - if cacheErr == nil { - return string(cacheBytes) - } - renderBytes := pipe(pygmentizeBin, arg, src) - // Newer versions of Pygments add silly empty spans. - renderCleanString := strings.Replace(string(renderBytes), "", "", -1) - writeErr := ioutil.WriteFile(cachePath, []byte(renderCleanString), 0600) - check(writeErr) - return renderCleanString + ensureDir(cacheDir) + arg := []string{"-l", lex, "-f", "html"} + cachePath := cacheDir + "/pygmentize-" + strings.Join(arg, "-") + "-" + sha1Sum(src) + cacheBytes, cacheErr := ioutil.ReadFile(cachePath) + if cacheErr == nil { + return string(cacheBytes) + } + renderBytes := pipe(pygmentizeBin, arg, src) + // Newer versions of Pygments add silly empty spans. + renderCleanString := strings.Replace(string(renderBytes), "", "", -1) + writeErr := ioutil.WriteFile(cachePath, []byte(renderCleanString), 0600) + check(writeErr) + return renderCleanString } func markdown(src string) string { - return string(blackfriday.MarkdownCommon([]byte(src))) + return string(blackfriday.MarkdownCommon([]byte(src))) } func readLines(path string) []string { - src := mustReadFile(path) - return strings.Split(src, "\n") + src := mustReadFile(path) + return strings.Split(src, "\n") } func mustGlob(glob string) []string { - paths, err := filepath.Glob(glob) - check(err) - return paths + paths, err := filepath.Glob(glob) + check(err) + return paths } func whichLexer(path string) string { - if strings.HasSuffix(path, ".go") { - return "go" - } else if strings.HasSuffix(path, ".sh") { - return "console" - } - panic("No lexer for " + path) + if strings.HasSuffix(path, ".go") { + return "go" + } else if strings.HasSuffix(path, ".sh") { + return "console" + } + panic("No lexer for " + path) } func debug(msg string) { - if os.Getenv("DEBUG") == "1" { - fmt.Fprintln(os.Stderr, msg) - } + if os.Getenv("DEBUG") == "1" { + fmt.Fprintln(os.Stderr, msg) + } } var docsPat = regexp.MustCompile("^\\s*(\\/\\/|#)\\s") @@ -119,169 +119,169 @@ var dashPat = regexp.MustCompile("\\-+") // Seg is a segment of an example type Seg struct { - Docs, DocsRendered string - Code, CodeRendered string - CodeEmpty, CodeLeading, CodeRun bool + Docs, DocsRendered string + Code, CodeRendered string + CodeEmpty, CodeLeading, CodeRun bool } // Example is info extracted from an example file type Example struct { - ID, Name string - GoCode, GoCodeHash, URLHash string - Segs [][]*Seg - NextExample *Example + ID, Name string + GoCode, GoCodeHash, URLHash string + Segs [][]*Seg + NextExample *Example } func parseHashFile(sourcePath string) (string, string) { - lines := readLines(sourcePath) - return lines[0], lines[1] + lines := readLines(sourcePath) + return lines[0], lines[1] } func resetURLHashFile(codehash, code, sourcePath string) string { - payload := strings.NewReader(code) - resp, err := http.Post("https://play.golang.org/share", "text/plain", payload) - if err != nil { - panic(err) - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - urlkey := string(body) - data := fmt.Sprintf("%s\n%s\n", codehash, urlkey) - ioutil.WriteFile(sourcePath, []byte(data), 0644) - return urlkey + payload := strings.NewReader(code) + resp, err := http.Post("https://play.golang.org/share", "text/plain", payload) + if err != nil { + panic(err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + urlkey := string(body) + data := fmt.Sprintf("%s\n%s\n", codehash, urlkey) + ioutil.WriteFile(sourcePath, []byte(data), 0644) + return urlkey } func parseSegs(sourcePath string) ([]*Seg, string) { - lines := readLines(sourcePath) - filecontent := strings.Join(lines, "\n") - segs := []*Seg{} - lastSeen := "" - for _, line := range lines { - if line == "" { - lastSeen = "" - continue - } - matchDocs := docsPat.MatchString(line) - matchCode := !matchDocs - newDocs := (lastSeen == "") || ((lastSeen != "docs") && (segs[len(segs)-1].Docs != "")) - newCode := (lastSeen == "") || ((lastSeen != "code") && (segs[len(segs)-1].Code != "")) - if newDocs || newCode { - debug("NEWSEG") - } - if matchDocs { - trimmed := docsPat.ReplaceAllString(line, "") - if newDocs { - newSeg := Seg{Docs: trimmed, Code: ""} - segs = append(segs, &newSeg) - } else { - segs[len(segs)-1].Docs = segs[len(segs)-1].Docs + "\n" + trimmed - } - debug("DOCS: " + line) - lastSeen = "docs" - } else if matchCode { - if newCode { - newSeg := Seg{Docs: "", Code: line} - segs = append(segs, &newSeg) - } else { - segs[len(segs)-1].Code = segs[len(segs)-1].Code + "\n" + line - } - debug("CODE: " + line) - lastSeen = "code" - } - } - for i, seg := range segs { - seg.CodeEmpty = (seg.Code == "") - seg.CodeLeading = (i < (len(segs) - 1)) - seg.CodeRun = strings.Contains(seg.Code, "package main") - } - return segs, filecontent + lines := readLines(sourcePath) + filecontent := strings.Join(lines, "\n") + segs := []*Seg{} + lastSeen := "" + for _, line := range lines { + if line == "" { + lastSeen = "" + continue + } + matchDocs := docsPat.MatchString(line) + matchCode := !matchDocs + newDocs := (lastSeen == "") || ((lastSeen != "docs") && (segs[len(segs)-1].Docs != "")) + newCode := (lastSeen == "") || ((lastSeen != "code") && (segs[len(segs)-1].Code != "")) + if newDocs || newCode { + debug("NEWSEG") + } + if matchDocs { + trimmed := docsPat.ReplaceAllString(line, "") + if newDocs { + newSeg := Seg{Docs: trimmed, Code: ""} + segs = append(segs, &newSeg) + } else { + segs[len(segs)-1].Docs = segs[len(segs)-1].Docs + "\n" + trimmed + } + debug("DOCS: " + line) + lastSeen = "docs" + } else if matchCode { + if newCode { + newSeg := Seg{Docs: "", Code: line} + segs = append(segs, &newSeg) + } else { + segs[len(segs)-1].Code = segs[len(segs)-1].Code + "\n" + line + } + debug("CODE: " + line) + lastSeen = "code" + } + } + for i, seg := range segs { + seg.CodeEmpty = (seg.Code == "") + seg.CodeLeading = (i < (len(segs) - 1)) + seg.CodeRun = strings.Contains(seg.Code, "package main") + } + return segs, filecontent } func parseAndRenderSegs(sourcePath string) ([]*Seg, string) { - segs, filecontent := parseSegs(sourcePath) - lexer := whichLexer(sourcePath) - for _, seg := range segs { - if seg.Docs != "" { - seg.DocsRendered = markdown(seg.Docs) - } - if seg.Code != "" { - seg.CodeRendered = cachedPygmentize(lexer, seg.Code) - } - } - // we are only interested in the 'go' code to pass to play.golang.org - if lexer != "go" { - filecontent = "" - } - return segs, filecontent + segs, filecontent := parseSegs(sourcePath) + lexer := whichLexer(sourcePath) + for _, seg := range segs { + if seg.Docs != "" { + seg.DocsRendered = markdown(seg.Docs) + } + if seg.Code != "" { + seg.CodeRendered = cachedPygmentize(lexer, seg.Code) + } + } + // we are only interested in the 'go' code to pass to play.golang.org + if lexer != "go" { + filecontent = "" + } + return segs, filecontent } func parseExamples() []*Example { - exampleNames := readLines("examples.txt") - examples := make([]*Example, 0) - for _, exampleName := range exampleNames { - if (exampleName != "") && !strings.HasPrefix(exampleName, "#") { - example := Example{Name: exampleName} - exampleID := strings.ToLower(exampleName) - exampleID = strings.Replace(exampleID, " ", "-", -1) - exampleID = strings.Replace(exampleID, "/", "-", -1) - exampleID = strings.Replace(exampleID, "'", "", -1) - exampleID = dashPat.ReplaceAllString(exampleID, "-") - example.ID = exampleID - example.Segs = make([][]*Seg, 0) - sourcePaths := mustGlob("examples/" + exampleID + "/*") - for _, sourcePath := range sourcePaths { - if strings.HasSuffix(sourcePath, ".hash") { - example.GoCodeHash, example.URLHash = parseHashFile(sourcePath) - } else { - sourceSegs, filecontents := parseAndRenderSegs(sourcePath) - if filecontents != "" { - example.GoCode = filecontents - } - example.Segs = append(example.Segs, sourceSegs) - } - } - newCodeHash := sha1Sum(example.GoCode) - if example.GoCodeHash != newCodeHash { - example.URLHash = resetURLHashFile(newCodeHash, example.GoCode, "examples/"+example.ID+"/"+example.ID+".hash") - } - examples = append(examples, &example) - } - } - for i, example := range examples { - if i < (len(examples) - 1) { - example.NextExample = examples[i+1] - } - } - return examples + exampleNames := readLines("examples.txt") + examples := make([]*Example, 0) + for _, exampleName := range exampleNames { + if (exampleName != "") && !strings.HasPrefix(exampleName, "#") { + example := Example{Name: exampleName} + exampleID := strings.ToLower(exampleName) + exampleID = strings.Replace(exampleID, " ", "-", -1) + exampleID = strings.Replace(exampleID, "/", "-", -1) + exampleID = strings.Replace(exampleID, "'", "", -1) + exampleID = dashPat.ReplaceAllString(exampleID, "-") + example.ID = exampleID + example.Segs = make([][]*Seg, 0) + sourcePaths := mustGlob("examples/" + exampleID + "/*") + for _, sourcePath := range sourcePaths { + if strings.HasSuffix(sourcePath, ".hash") { + example.GoCodeHash, example.URLHash = parseHashFile(sourcePath) + } else { + sourceSegs, filecontents := parseAndRenderSegs(sourcePath) + if filecontents != "" { + example.GoCode = filecontents + } + example.Segs = append(example.Segs, sourceSegs) + } + } + newCodeHash := sha1Sum(example.GoCode) + if example.GoCodeHash != newCodeHash { + example.URLHash = resetURLHashFile(newCodeHash, example.GoCode, "examples/"+example.ID+"/"+example.ID+".hash") + } + examples = append(examples, &example) + } + } + for i, example := range examples { + if i < (len(examples) - 1) { + example.NextExample = examples[i+1] + } + } + return examples } func renderIndex(examples []*Example) { - indexTmpl := template.New("index") - _, err := indexTmpl.Parse(mustReadFile("templates/index.tmpl")) - check(err) - indexF, err := os.Create(siteDir + "/index.html") - check(err) - err = indexTmpl.Execute(indexF, examples) - check(err) + indexTmpl := template.New("index") + _, err := indexTmpl.Parse(mustReadFile("templates/index.tmpl")) + check(err) + indexF, err := os.Create(siteDir + "/index.html") + check(err) + err = indexTmpl.Execute(indexF, examples) + check(err) } func renderExamples(examples []*Example) { - exampleTmpl := template.New("example") - _, err := exampleTmpl.Parse(mustReadFile("templates/example.tmpl")) - check(err) - for _, example := range examples { - exampleF, err := os.Create(siteDir + "/" + example.ID) - check(err) - exampleTmpl.Execute(exampleF, example) - } + exampleTmpl := template.New("example") + _, err := exampleTmpl.Parse(mustReadFile("templates/example.tmpl")) + check(err) + for _, example := range examples { + exampleF, err := os.Create(siteDir + "/" + example.ID) + check(err) + exampleTmpl.Execute(exampleF, example) + } } func main() { - copyFile("templates/site.css", siteDir+"/site.css") - copyFile("templates/favicon.ico", siteDir+"/favicon.ico") - copyFile("templates/404.html", siteDir+"/404.html") - copyFile("templates/play.png", siteDir+"/play.png") - examples := parseExamples() - renderIndex(examples) - renderExamples(examples) + copyFile("templates/site.css", siteDir+"/site.css") + copyFile("templates/favicon.ico", siteDir+"/favicon.ico") + copyFile("templates/404.html", siteDir+"/404.html") + copyFile("templates/play.png", siteDir+"/play.png") + examples := parseExamples() + renderIndex(examples) + renderExamples(examples) } diff --git a/tools/measure.go b/tools/measure.go index 9ea4e10..a4fafb1 100644 --- a/tools/measure.go +++ b/tools/measure.go @@ -1,45 +1,45 @@ package main import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - "unicode/utf8" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + "unicode/utf8" ) func check(err error) { - if err != nil { - panic(err) - } + if err != nil { + panic(err) + } } func readLines(path string) []string { - srcBytes, err := ioutil.ReadFile(path) - check(err) - return strings.Split(string(srcBytes), "\n") + srcBytes, err := ioutil.ReadFile(path) + check(err) + return strings.Split(string(srcBytes), "\n") } var commentPat = regexp.MustCompile("\\s*\\/\\/") func main() { - sourcePaths, err := filepath.Glob("./examples/*/*") - check(err) - foundLongFile := false - for _, sourcePath := range sourcePaths { - foundLongLine := false - lines := readLines(sourcePath) - for i, line := range lines { - if !foundLongLine && !commentPat.MatchString(line) && (utf8.RuneCountInString(line) > 58) { - fmt.Printf("measure: %s:%d\n", sourcePath, i+1) - foundLongLine = true - foundLongFile = true - } - } - } - if foundLongFile { - os.Exit(1) - } + sourcePaths, err := filepath.Glob("./examples/*/*") + check(err) + foundLongFile := false + for _, sourcePath := range sourcePaths { + foundLongLine := false + lines := readLines(sourcePath) + for i, line := range lines { + if !foundLongLine && !commentPat.MatchString(line) && (utf8.RuneCountInString(line) > 58) { + fmt.Printf("measure: %s:%d\n", sourcePath, i+1) + foundLongLine = true + foundLongFile = true + } + } + } + if foundLongFile { + os.Exit(1) + } }