1
0
Fork 0
mirror of https://github.com/avelino/awesome-go.git synced 2024-11-13 11:14:37 -05:00
go/main.go

221 lines
4.8 KiB
Go
Raw Normal View History

package main
import (
"bytes"
"fmt"
cp "github.com/otiai10/copy"
"os"
2023-02-03 20:39:51 -05:00
"path/filepath"
"strings"
"text/template"
"github.com/PuerkitoBio/goquery"
2022-08-30 17:52:53 -04:00
"github.com/avelino/awesome-go/pkg/slug"
)
type Link struct {
Title string
Url string
Description string
}
type Object struct {
Title string
Slug string
Description string
Items []Link
}
2023-02-14 12:58:36 -05:00
// Source files
2023-02-03 20:39:51 -05:00
const readmePath = "README.md"
2023-02-14 12:58:36 -05:00
// This files should be copied 'as is' to outDir directory
var staticFiles = []string{
"tmpl/assets",
"tmpl/_redirects",
"tmpl/robots.txt",
}
2023-02-03 20:39:51 -05:00
2023-02-14 13:12:57 -05:00
// TODO: embed
// Templates
var tplIndex = template.Must(template.ParseFiles("tmpl/tmpl.html"))
var tplCategoryIndex = template.Must(template.ParseFiles("tmpl/cat-tmpl.html"))
var tplSitemap = template.Must(template.ParseFiles("tmpl/sitemap-tmpl.xml"))
2023-02-03 20:39:51 -05:00
2023-02-14 12:58:36 -05:00
// Output files
const outDir = "out/" // NOTE: trailing slash is required
var outIndexFile = filepath.Join(outDir, "index.html")
var outSitemapFile = filepath.Join(outDir, "sitemap.xml")
2023-02-03 20:39:51 -05:00
func main() {
2023-02-03 21:01:22 -05:00
// Cleanup and re-create output directory
{
if err := os.RemoveAll(outDir); err != nil {
panic(err)
}
if err := mkdirAll(outDir); err != nil {
panic(err)
}
}
err := GenerateHTML(readmePath, outIndexFile)
if err != nil {
panic(err)
}
2023-02-03 20:39:51 -05:00
input, err := os.ReadFile(outIndexFile)
if err != nil {
panic(err)
}
2023-02-03 20:39:51 -05:00
2023-02-14 13:12:57 -05:00
query, err := goquery.NewDocumentFromReader(bytes.NewReader(input))
if err != nil {
panic(err)
}
2023-02-14 13:56:32 -05:00
objs := make(map[string]Object)
query.Find("body #contents").NextFiltered("ul").Find("ul").Each(func(_ int, s *goquery.Selection) {
s.Find("li a").Each(func(_ int, s *goquery.Selection) {
selector, exists := s.Attr("href")
if !exists {
return
}
2022-08-30 13:26:14 -04:00
obj := makeObjByID(selector, query.Find("body"))
if obj == nil {
return
}
2023-02-14 13:56:32 -05:00
objs[selector] = *obj
})
})
2023-02-03 20:39:51 -05:00
if err := makeSiteStruct(objs); err != nil {
// FIXME: remove all panics
panic(err)
}
changeLinksInIndex(string(input), query, objs)
makeSitemap(objs)
for _, srcFilename := range staticFiles {
dstFilename := filepath.Join(outDir, filepath.Base(srcFilename))
fmt.Printf("Copy static file: %s -> %s\n", srcFilename, dstFilename)
if err := cp.Copy(srcFilename, dstFilename); err != nil {
panic(err)
}
}
}
2023-02-03 20:39:51 -05:00
func mkdirAll(path string) error {
_, err := os.Stat(path)
// NOTE: directory is exists
if err == nil {
return nil
}
// NOTE: unknown error
if !os.IsNotExist(err) {
return err
}
// NOTE: directory is not exists
if err := os.MkdirAll(path, 0o755); err != nil {
return err
}
return nil
}
2023-02-14 13:56:32 -05:00
func makeSiteStruct(objs map[string]Object) error {
for _, obj := range objs {
categoryDir := filepath.Join(outDir, obj.Slug)
if err := mkdirAll(categoryDir); err != nil {
2023-02-03 20:39:51 -05:00
return err
}
// FIXME: embed templates
// FIXME: parse templates once at start
2023-02-14 12:50:14 -05:00
categoryIndexFilename := filepath.Join(categoryDir, "index.html")
f, err := os.Create(categoryIndexFilename)
if err != nil {
2023-02-03 20:39:51 -05:00
return err
}
2023-02-14 12:50:14 -05:00
fmt.Printf("Write category Index file: %s\n", categoryIndexFilename)
2023-02-14 13:12:57 -05:00
if err := tplCategoryIndex.Execute(f, obj); err != nil {
2023-02-03 20:39:51 -05:00
return err
}
}
2023-02-03 20:39:51 -05:00
return nil
}
2023-02-14 13:56:32 -05:00
func makeSitemap(objs map[string]Object) {
2023-02-14 12:50:14 -05:00
// FIXME: handle error
f, _ := os.Create(outSitemapFile)
2023-02-14 12:50:14 -05:00
fmt.Printf("Render Sitemap to: %s\n", outSitemapFile)
2023-02-14 13:12:57 -05:00
_ = tplSitemap.Execute(f, objs)
}
2022-08-30 13:26:14 -04:00
func makeObjByID(selector string, s *goquery.Selection) (obj *Object) {
s.Find(selector).Each(func(_ int, s *goquery.Selection) {
desc := s.NextFiltered("p")
ul := s.NextFilteredUntil("ul", "h2")
links := []Link{}
ul.Find("li").Each(func(_ int, s *goquery.Selection) {
url, _ := s.Find("a").Attr("href")
link := Link{
Title: s.Find("a").Text(),
Description: s.Text(),
Url: url,
}
links = append(links, link)
})
2022-08-30 10:21:44 -04:00
if len(links) == 0 {
return
}
obj = &Object{
2022-08-30 17:52:53 -04:00
Slug: slug.Generate(s.Text()),
Title: s.Text(),
Description: desc.Text(),
Items: links,
}
})
return
}
2023-02-14 13:56:32 -05:00
func changeLinksInIndex(html string, query *goquery.Document, objs map[string]Object) {
query.Find("body #content ul li ul li a").Each(func(_ int, s *goquery.Selection) {
href, hrefExists := s.Attr("href")
if !hrefExists {
2023-02-14 13:46:53 -05:00
// FIXME: looks like is an error. Tag `a` in our case always
// should have `href` attr.
return
}
// do not replace links if no page has been created for it
_, objExists := objs[href]
if !objExists {
return
}
2023-02-14 13:46:53 -05:00
// FIXME: parse url
uri := strings.SplitAfter(href, "#")
if len(uri) >= 2 && uri[1] != "contents" {
2023-02-14 13:46:53 -05:00
// FIXME: use s.SetAttr
html = strings.ReplaceAll(
2023-02-14 13:46:53 -05:00
html,
fmt.Sprintf(`href="%s"`, href),
fmt.Sprintf(`href="%s"`, uri[1]),
)
}
})
2023-02-14 12:50:14 -05:00
fmt.Printf("Rewrite links in Index file: %s\n", outIndexFile)
_ = os.WriteFile(outIndexFile, []byte(html), 0644)
}