From 399e543b4a012cc2d62b2c948a13631a6fea968a Mon Sep 17 00:00:00 2001 From: adnano Date: Tue, 29 Sep 2020 21:30:50 -0400 Subject: [PATCH] Refactor --- go.mod | 2 +- go.sum | 4 +- kiln.go | 213 ++++++++++++++++++++++++--------------------------- main.go | 13 ++-- templates.go | 24 +++--- 5 files changed, 124 insertions(+), 132 deletions(-) diff --git a/go.mod b/go.mod index 7c00065..2743845 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module kiln go 1.15 -require git.sr.ht/~adnano/gmi v0.0.1-alpha +require git.sr.ht/~adnano/gmi v0.0.1-alpha.1 diff --git a/go.sum b/go.sum index 035c174..bc395f4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -git.sr.ht/~adnano/gmi v0.0.1-alpha h1:6SRpwsKRowrKfExhyYQaQ0SBYcMIhHG4hUaWF67iP4k= -git.sr.ht/~adnano/gmi v0.0.1-alpha/go.mod h1:4MWQDsleal4HRi/LuxxM6ymWJQikP3Gh7xZindVCHzg= +git.sr.ht/~adnano/gmi v0.0.1-alpha.1 h1:zXcPeenDDt3opygDCunf52x3IJdVFEc1V0wf8aHshzc= +git.sr.ht/~adnano/gmi v0.0.1-alpha.1/go.mod h1:4MWQDsleal4HRi/LuxxM6ymWJQikP3Gh7xZindVCHzg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= diff --git a/kiln.go b/kiln.go index 3044962..5d68f98 100644 --- a/kiln.go +++ b/kiln.go @@ -18,29 +18,42 @@ import ( // Site represents a kiln site. type Site struct { - URL string // Site URL - Directory *Directory // Site directory - Templates *template.Template // Templates + Title string // Site title. + URL string // Site URL. + dir *Dir // Site directory. + tmpl *template.Template // Templates. + feeds bool // Whether or not to generate feeds. } -// Load loads the Site from the specified source directory. -func (s *Site) Load(srcDir string) error { - s.Directory = NewDirectory("") - - tmpl, err := template.New("templates").ParseGlob("templates/*.gmi") - if err != nil { +// load loads the Site from the current directory. +func (s *Site) load() error { + // Load content + const srcDir = "src" + s.dir = NewDir("") + if err := site.dir.Read(srcDir, ""); err != nil { return err } - s.Templates = tmpl - - if err := site.Directory.Read(""); err != nil { + // Load templates + const tmplDir = "templates" + s.tmpl = template.New(tmplDir) + // Add default templates + s.tmpl.AddParseTree("atom.xml", atomTmpl.Tree) + s.tmpl.AddParseTree("index.gmi", indexTmpl.Tree) + s.tmpl.AddParseTree("page.gmi", pageTmpl.Tree) + // Add function to get site + s.tmpl = s.tmpl.Funcs(template.FuncMap{ + "site": func() *Site { return s }, + }) + var err error + s.tmpl, err = s.tmpl.ParseGlob(filepath.Join(tmplDir, "*.gmi")) + if err != nil { return err } return nil } -// Write writes the contents of the Index to the provided destination directory. -func (s *Site) Write(dstDir string, format OutputFormat) error { +// write writes the contents of the Index to the provided destination directory. +func (s *Site) write(dstDir string, format OutputFormat) error { // Empty the destination directory if err := os.RemoveAll(dstDir); err != nil { return err @@ -49,105 +62,88 @@ func (s *Site) Write(dstDir string, format OutputFormat) error { if err := os.MkdirAll(dstDir, 0755); err != nil { return err } - // Write the directory - return s.Directory.Write(dstDir, format) + return s.dir.Write(dstDir, format) } -// Manipulate processes and manipulates the site's content. -func (s *Site) Manipulate(dir *Directory) error { +// manipulate processes and manipulates the site's content. +func (s *Site) manipulate() error { + // FIXME: manipulate doesn't descend into subdirectories // Write the directory index file, if it doesn't exist - if dir.Index == nil { - path := filepath.Join(dir.Permalink, "index.gmi") + const indexPath = "index.gmi" + if s.dir.index == nil { var b bytes.Buffer - tmpl := s.Templates.Lookup("index.gmi") - if tmpl == nil { - tmpl = indexTmpl - } - if err := tmpl.Execute(&b, dir); err != nil { + tmpl := s.tmpl.Lookup(indexPath) + if err := tmpl.Execute(&b, s.dir); err != nil { return err } - content := b.Bytes() - permalink := filepath.Dir(path) - if permalink == "." { - permalink = "" + s.dir.index = &Page{ + Permalink: s.dir.Permalink, + content: b.Bytes(), } - page := &Page{ - Permalink: "/" + permalink, - content: content, - } - dir.Index = page } - // Manipulate pages - for i := range dir.Pages { + const pagePath = "page.gmi" + for i := range s.dir.Pages { var b bytes.Buffer - tmpl := s.Templates.Lookup("page.gmi") - if tmpl == nil { - tmpl = pageTmpl - } - if err := tmpl.Execute(&b, dir.Pages[i]); err != nil { + tmpl := s.tmpl.Lookup(pagePath) + if err := tmpl.Execute(&b, s.dir.Pages[i]); err != nil { return err } - dir.Pages[i].content = b.Bytes() + s.dir.Pages[i].content = b.Bytes() } - return nil } -// Sort sorts the site's pages by date. -func (s *Site) Sort() { - s.Directory.Sort() +// sort sorts the site's pages by date. +func (s *Site) sort() { + s.dir.Sort() } +// Feed represents a feed. type Feed struct { - Title string - Path string - SiteURL string - Updated time.Time - Entries []*Page + Title string // Feed title. + Path string // Feed path. + URL string // Site URL. + Updated time.Time // Last updated time. + Entries []*Page // Feed entries. } -// CreateFeeds creates Atom feeds. -func (s *Site) CreateFeeds() error { +// createFeeds creates Atom feeds. +func (s *Site) createFeeds() error { const atomPath = "atom.xml" var b bytes.Buffer - tmpl := s.Templates.Lookup(atomPath) - if tmpl == nil { - tmpl = atomTmpl - } + tmpl := s.tmpl.Lookup(atomPath) feed := &Feed{ - Title: "Example Feed", - Path: filepath.Join(s.Directory.Permalink, atomPath), - SiteURL: s.URL, + Title: s.Title, + Path: filepath.Join(s.dir.Permalink, atomPath), + URL: s.URL, Updated: time.Now(), - Entries: s.Directory.Pages, + Entries: s.dir.Pages, } if err := tmpl.Execute(&b, feed); err != nil { return err } - path := filepath.Join(s.Directory.Permalink, atomPath) - s.Directory.Static[path] = b.Bytes() + path := filepath.Join(s.dir.Permalink, atomPath) + s.dir.Files[path] = b.Bytes() return nil } // Page represents a page. type Page struct { - // The permalink to this page. - Permalink string - // The title of this page, parsed from the Gemini contents. - Title string - // The date of the page. Dates are specified in the filename. - // Ex: 2020-09-22-hello-world.gmi - Date time.Time - // The content of this page. - content []byte + Title string // The title of this page. + Permalink string // The permalink to this page. + Date time.Time // The date of the page. + content []byte // The content of this page. } +// Content returns the page content as a string. +// Used in templates. func (p *Page) Content() string { return string(p.content) } +// Regexp to parse title from Gemini files var titleRE = regexp.MustCompile("^# ?([^#\r\n]+)\r?\n?\r?\n?") // NewPage returns a new Page with the given path and content. @@ -196,82 +192,77 @@ func NewPage(path string, content []byte) *Page { } } -// Directory represents a directory of pages. -type Directory struct { - // The permalink to this directory. - Permalink string - // The pages in this directory. - Pages []*Page - // The subdirectories of this directory. - Directories []*Directory - // The index file (index.gmi). - Index *Page - // Static files - Static map[string][]byte +// Dir represents a directory. +type Dir struct { + Permalink string // Permalink to this directory. + Pages []*Page // Pages in this directory. + Dirs []*Dir // Subdirectories. + Files map[string][]byte // Static files. + index *Page // The index file (index.gmi). } -// NewDirectory returns a new Directory with the given path. -func NewDirectory(path string) *Directory { +// NewDir returns a new Dir with the given path. +func NewDir(path string) *Dir { var permalink string if path == "" { permalink = "/" } else { permalink = "/" + path + "/" } - return &Directory{ + return &Dir{ Permalink: permalink, - Static: map[string][]byte{}, + Files: map[string][]byte{}, } } // Read reads from a directory and indexes the files and directories within it. -func (d *Directory) Read(path string) error { - entries, err := ioutil.ReadDir(filepath.Join("src", path)) +func (d *Dir) Read(srcDir string, path string) error { + entries, err := ioutil.ReadDir(filepath.Join(srcDir, path)) if err != nil { return err } - for _, entry := range entries { name := entry.Name() + // Ignore names that start with '_' + if strings.HasPrefix(name, "_") { + continue + } + path := filepath.Join(path, name) if entry.IsDir() { // Gather directory data - path := filepath.Join(path, name) - dir := NewDirectory(path) - if err := dir.Read(path); err != nil { + dir := NewDir(path) + if err := dir.Read(srcDir, path); err != nil { return err } - d.Directories = append(d.Directories, dir) + d.Dirs = append(d.Dirs, dir) } else { - srcPath := filepath.Join("src", path, name) + srcPath := filepath.Join(srcDir, path) content, err := ioutil.ReadFile(srcPath) if err != nil { return err } switch filepath.Ext(name) { - case ".gmi", ".gemini": - path := filepath.Join(path, name) + case ".gmi": // Gather page data page := NewPage(path, content) - if name == "index.gmi" { - d.Index = page + d.index = page } else { d.Pages = append(d.Pages, page) } default: // Static file - path := filepath.Join(path, name) - d.Static[path] = content + d.Files[path] = content } } } return nil } -// Write writes the Directory to the provided destination path. -func (d *Directory) Write(dstDir string, format OutputFormat) error { +// Write writes the Dir to the provided destination path. +func (d *Dir) Write(dstDir string, format OutputFormat) error { // Create the directory dirPath := filepath.Join(dstDir, d.Permalink) if err := os.MkdirAll(dirPath, 0755); err != nil { @@ -279,13 +270,13 @@ func (d *Directory) Write(dstDir string, format OutputFormat) error { } // Write static files - for path := range d.Static { + for path := range d.Files { dstPath := filepath.Join(dstDir, path) f, err := os.Create(dstPath) if err != nil { return err } - data := d.Static[path] + data := d.Files[path] if _, err := f.Write(data); err != nil { return err } @@ -307,8 +298,8 @@ func (d *Directory) Write(dstDir string, format OutputFormat) error { } // Write the index file - if d.Index != nil { - path, content := format(d.Index) + if d.index != nil { + path, content := format(d.index) dstPath := filepath.Join(dstDir, path) f, err := os.Create(dstPath) if err != nil { @@ -320,19 +311,19 @@ func (d *Directory) Write(dstDir string, format OutputFormat) error { } // Write subdirectories - for _, dir := range d.Directories { + for _, dir := range d.Dirs { dir.Write(dstDir, format) } return nil } // Sort sorts the directory's pages by date. -func (d *Directory) Sort() { +func (d *Dir) Sort() { sort.Slice(d.Pages, func(i, j int) bool { return d.Pages[i].Date.After(d.Pages[j].Date) }) // Sort subdirectories - for _, d := range d.Directories { + for _, d := range d.Dirs { d.Sort() } } diff --git a/main.go b/main.go index 3a91d4a..56c7248 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ func init() { flag.BoolVar(&serveSite, "serve", false, "serve the site") flag.BoolVar(&toHtml, "html", false, "output HTML") flag.BoolVar(&toAtom, "atom", false, "output Atom feed") + flag.StringVar(&site.Title, "title", "", "site title") flag.StringVar(&site.URL, "url", "", "site URL") } @@ -35,23 +36,23 @@ func main() { // build the site func build() error { - if err := site.Load("src"); err != nil { + if err := site.load(); err != nil { return err } - site.Sort() - if err := site.Manipulate(site.Directory); err != nil { + site.sort() + if err := site.manipulate(); err != nil { return err } if toAtom { - if err := site.CreateFeeds(); err != nil { + if err := site.createFeeds(); err != nil { return err } } - if err := site.Write("dst", OutputGemini); err != nil { + if err := site.write("dst", OutputGemini); err != nil { return err } if toHtml { - if err := site.Write("dst.html", OutputHTML); err != nil { + if err := site.write("dst.html", OutputHTML); err != nil { return err } } diff --git a/templates.go b/templates.go index d5eb68b..34ac3bd 100644 --- a/templates.go +++ b/templates.go @@ -7,28 +7,28 @@ import "text/template" const atom_xml = ` {{ .Title }} - - + + {{ .Updated }} -{{ .SiteURL }}{{ .Path }} -{{ $siteURL := .SiteURL }} -{{ range .Entries }} +{{ .URL }}{{ .Path }} +{{- $url := .URL -}} +{{- range .Entries }} {{ .Title }} - - {{ $siteURL }}{{ .Permalink }} + + {{ $url }}{{ .Permalink }} {{ .Date.Format "2006-01-02T15:04:05Z07:00" }} - + -{{ end }} +{{ end -}} ` const index_gmi = `# Index of {{ .Permalink }} -{{ range .Directories }}=> {{ .Permalink }} -{{ end }} +{{ range .Dirs }}=> {{ .Permalink }} +{{ end -}} {{ range .Pages }}=> {{ .Permalink }} -{{ end }}` +{{ end -}}` const page_gmi = `# {{ .Title }}