package projects import ( "bytes" "github.com/libgit2/git2go" "html" "html/template" "io" "log" "os" "os/exec" "path" "strings" ) type ReadmeFormat string const ( ReadmeMarkdown ReadmeFormat = "markdown" ReadmePlain ReadmeFormat = "plain" ) func (f ReadmeFormat) Format(raw []byte) template.HTML { switch f { case ReadmeMarkdown: return formatMarkdown(raw) default: return template.HTML("
" + html.EscapeString(string(raw)) + "
") } } func formatMarkdown(raw []byte) template.HTML { p := exec.Command("markdown") buf := new(bytes.Buffer) p.Stdin = bytes.NewReader(raw) p.Stdout = buf if err := p.Run(); err != nil { log.Printf("Failed formatting markdown readme: %s", err) return "Failed formatting markdown :(" } return template.HTML(buf.Bytes()) } func gitReadme(gitpath string) (raw []byte, name string, err error) { repo, err := git.OpenRepository(gitpath) if err != nil { return raw, name, err } master_tree_obj, err := repo.RevparseSingle("master:") // Root tree of commit at top of master if err != nil { return raw, name, err } master_tree, err := master_tree_obj.AsTree() if err != nil { return raw, name, err } var inner_err error = nil err = master_tree.Walk(func(_ string, entry *git.TreeEntry) int { if !(strings.HasPrefix(strings.ToLower(entry.Name), "readme") && entry.Type == git.ObjectBlob) { return 1 } name = entry.Name blob, err := repo.LookupBlob(entry.Id) if err == nil { raw = blob.Contents() } else { inner_err = err } return 1 }) if err == nil && inner_err != nil { err = inner_err } return } func (p *Project) formatReadme() { readme_name := "" var readme_raw []byte if p.ReadmePath != "" { fullpath := p.ReadmePath if !path.IsAbs(fullpath) { fullpath = path.Join(p.dir, fullpath) } fullpath = path.Clean(fullpath) f, err := os.Open(fullpath) if err != nil { log.Printf("Could not get readme for %s: failed opening %s: %s", p.Name, fullpath, err) return } defer f.Close() buf := new(bytes.Buffer) if _, err := io.Copy(buf, f); err != nil { log.Printf("Could not get readme for %s: failed reading %s: %s", p.Name, fullpath, err) return } readme_raw = buf.Bytes() readme_name = fullpath } else if len(p.Git) > 0 { var err error readme_raw, readme_name, err = gitReadme(p.Git) if err != nil { log.Printf("Could not get readme for %s from git: %s", p.Name, err) return } if readme_name == "" { return } } else { return } format := ReadmePlain switch strings.ToLower(path.Ext(readme_name)) { case ".md", ".mkd", ".markdown": format = ReadmeMarkdown } p.FormattedReadme = format.Format(readme_raw) }