diff options
Diffstat (limited to 'projects/readme.go')
-rw-r--r-- | projects/readme.go | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/projects/readme.go b/projects/readme.go new file mode 100644 index 0000000..2fda69b --- /dev/null +++ b/projects/readme.go @@ -0,0 +1,133 @@ +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("<pre><code>" + html.EscapeString(string(raw)) + "</code></pre>") + } +} + +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 "<strong>Failed formatting markdown :(</strong>" + } + + 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) +} |