summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2022-07-31 23:54:29 +0700
committerShulhan <ms@kilabit.info>2022-08-01 00:24:19 +0700
commit8d347992ab2753dc878f56439883ec868e8d038d (patch)
tree19ad6b40ee3898110742850b4755f6b7c0aefb67
parentcd24f44c54b0a4a22fa9d4413fffab718df9052a (diff)
downloadciigo-8d347992ab2753dc878f56439883ec868e8d038d.tar.xz
all: export internal htmlGenerator as Converter
The purpose of Converter is to provide a single, reusable converter for AsciiDoc file or content.
-rw-r--r--ciigo.go23
-rw-r--r--converter.go134
-rw-r--r--htmlgenerator.go142
-rw-r--r--server.go29
-rw-r--r--watcher.go32
-rw-r--r--watcher_test.go20
6 files changed, 195 insertions, 185 deletions
diff --git a/ciigo.go b/ciigo.go
index ec03f46..cde73b0 100644
--- a/ciigo.go
+++ b/ciigo.go
@@ -41,7 +41,7 @@ func Convert(opts *ConvertOptions) (err error) {
var (
logp = "Convert"
- htmlg *htmlGenerator
+ converter *Converter
fileMarkups map[string]*fileMarkup
)
@@ -53,7 +53,7 @@ func Convert(opts *ConvertOptions) (err error) {
return fmt.Errorf("%s: %w", logp, err)
}
- htmlg, err = newHTMLGenerator(nil, opts.HtmlTemplate, true)
+ converter, err = NewConverter(opts.HtmlTemplate)
if err != nil {
return fmt.Errorf("%s: %w", logp, err)
}
@@ -63,7 +63,7 @@ func Convert(opts *ConvertOptions) (err error) {
return fmt.Errorf("%s: %w", logp, err)
}
- htmlg.convertFileMarkups(fileMarkups, false)
+ converter.convertFileMarkups(fileMarkups, false)
return nil
}
@@ -82,7 +82,7 @@ func GoEmbed(opts *EmbedOptions) (err error) {
var (
logp = "GoEmbed"
- htmlg *htmlGenerator
+ converter *Converter
fileMarkups map[string]*fileMarkup
mfs *memfs.MemFS
convertForce bool
@@ -96,7 +96,7 @@ func GoEmbed(opts *EmbedOptions) (err error) {
return fmt.Errorf("%s: %w", logp, err)
}
- htmlg, err = newHTMLGenerator(nil, opts.HtmlTemplate, true)
+ converter, err = NewConverter(opts.HtmlTemplate)
if err != nil {
return fmt.Errorf("%s: %w", logp, err)
}
@@ -110,7 +110,7 @@ func GoEmbed(opts *EmbedOptions) (err error) {
convertForce = true
}
- htmlg.convertFileMarkups(fileMarkups, convertForce)
+ converter.convertFileMarkups(fileMarkups, convertForce)
memfsOpts := &memfs.Options{
Root: opts.Root,
@@ -175,9 +175,10 @@ func Serve(opts *ServeOptions) (err error) {
// default HTML template.
func Watch(opts *ConvertOptions) (err error) {
var (
- logp = "Watch"
- htmlg *htmlGenerator
- w *watcher
+ logp = "Watch"
+
+ converter *Converter
+ w *watcher
)
if opts == nil {
@@ -188,12 +189,12 @@ func Watch(opts *ConvertOptions) (err error) {
return fmt.Errorf("%s: %w", logp, err)
}
- htmlg, err = newHTMLGenerator(nil, opts.HtmlTemplate, true)
+ converter, err = NewConverter(opts.HtmlTemplate)
if err != nil {
return fmt.Errorf("%s: %w", logp, err)
}
- w, err = newWatcher(htmlg, opts)
+ w, err = newWatcher(converter, opts)
if err != nil {
return fmt.Errorf("%s: %w", logp, err)
}
diff --git a/converter.go b/converter.go
new file mode 100644
index 0000000..58afad3
--- /dev/null
+++ b/converter.go
@@ -0,0 +1,134 @@
+// SPDX-FileCopyrightText: 2019 Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package ciigo
+
+import (
+ "fmt"
+ "html/template"
+ "os"
+ "path/filepath"
+
+ "git.sr.ht/~shulhan/asciidoctor-go"
+)
+
+// Converter a single, reusable AsciiDoc converter.
+type Converter struct {
+ tmpl *template.Template
+ tmplSearch *template.Template
+ htmlTemplate string
+}
+
+// NewConverter create and initialize Converter with HTML template.
+// If htmlTemplate is empty, it will use the internal, predefined template.
+func NewConverter(htmlTemplate string) (converter *Converter, err error) {
+ var (
+ logp = "NewConverter"
+
+ tmplContent string
+ bhtml []byte
+ )
+
+ converter = &Converter{}
+
+ converter.tmpl = template.New("")
+
+ if len(htmlTemplate) == 0 {
+ tmplContent = templateIndexHTML
+ } else {
+ converter.htmlTemplate = filepath.Clean(htmlTemplate)
+
+ bhtml, err = os.ReadFile(converter.htmlTemplate)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %s: %w", logp, converter.htmlTemplate, err)
+ }
+
+ tmplContent = string(bhtml)
+ }
+
+ converter.tmpl, err = converter.tmpl.Parse(tmplContent)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", logp, err)
+ }
+
+ converter.tmplSearch = template.New("search")
+ converter.tmplSearch, err = converter.tmplSearch.Parse(templateSearch)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %s: %w", logp, templateSearch, err)
+ }
+
+ return converter, nil
+}
+
+// convert the markup into HTML.
+func (converter *Converter) convert(fmarkup *fileMarkup) (err error) {
+ doc, err := asciidoctor.Open(fmarkup.path)
+ if err != nil {
+ return err
+ }
+
+ fmarkup.fhtml.rawBody.Reset()
+ err = doc.ToHTMLBody(&fmarkup.fhtml.rawBody)
+ if err != nil {
+ return err
+ }
+
+ fmarkup.fhtml.unpackAdocMetadata(doc)
+
+ return converter.write(fmarkup.fhtml)
+}
+
+// convertFileMarkups convert markup files into HTML.
+func (converter *Converter) convertFileMarkups(fileMarkups map[string]*fileMarkup, isForce bool) {
+ logp := "convertFileMarkups"
+ for _, fmarkup := range fileMarkups {
+ if !fmarkup.isNewerThanHtml() {
+ if !isForce {
+ continue
+ }
+ }
+
+ err := converter.convert(fmarkup)
+ if err != nil {
+ fmt.Printf("%s: %s\n", logp, err)
+ } else {
+ fmt.Printf("%s: converting %s\n", logp, fmarkup.path)
+ }
+ }
+}
+
+func (converter *Converter) htmlTemplateReload() (err error) {
+ converter.tmpl, err = template.ParseFiles(converter.htmlTemplate)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (converter *Converter) htmlTemplateUseInternal() (err error) {
+ converter.tmpl, err = converter.tmpl.Parse(templateIndexHTML)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// write the HTML file.
+func (converter *Converter) write(fhtml *fileHtml) (err error) {
+ f, err := os.Create(fhtml.path)
+ if err != nil {
+ return err
+ }
+
+ err = converter.tmpl.Execute(f, fhtml)
+ if err != nil {
+ return err
+ }
+
+ err = f.Close()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/htmlgenerator.go b/htmlgenerator.go
deleted file mode 100644
index c2e0b01..0000000
--- a/htmlgenerator.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// SPDX-FileCopyrightText: 2019 Shulhan <ms@kilabit.info>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package ciigo
-
-import (
- "fmt"
- "html/template"
- "os"
- "path/filepath"
-
- "git.sr.ht/~shulhan/asciidoctor-go"
- "github.com/shuLhan/share/lib/memfs"
-)
-
-// htmlGenerator provide a template to write full HTML file.
-type htmlGenerator struct {
- tmpl *template.Template
- tmplSearch *template.Template
- htmlTemplate string
-}
-
-func newHTMLGenerator(mfs *memfs.MemFS, htmlTemplate string, devel bool) (
- htmlg *htmlGenerator, err error,
-) {
- var logp = "newHTMLGenerator"
-
- htmlg = &htmlGenerator{}
-
- htmlg.tmpl = template.New("")
-
- if len(htmlTemplate) == 0 {
- htmlg.tmpl, err = htmlg.tmpl.Parse(templateIndexHTML)
- if err != nil {
- return nil, fmt.Errorf("%s: %s: %w", logp, templateIndexHTML, err)
- }
- } else if mfs == nil || devel {
- htmlg.htmlTemplate = filepath.Clean(htmlTemplate)
-
- bhtml, err := os.ReadFile(htmlg.htmlTemplate)
- if err != nil {
- return nil, fmt.Errorf("%s: %s: %w", logp, htmlg.htmlTemplate, err)
- }
-
- htmlg.tmpl, err = htmlg.tmpl.Parse(string(bhtml))
- if err != nil {
- return nil, fmt.Errorf("%s: Parse: %s", logp, err)
- }
- } else {
- // Load HTML template from memory file system.
- tmplNode, err := mfs.Get(internalTemplatePath)
- if err != nil {
- return nil, fmt.Errorf("%s: %s: %w", logp, internalTemplatePath, err)
- }
-
- htmlg.tmpl, err = htmlg.tmpl.Parse(string(tmplNode.Content))
- if err != nil {
- return nil, fmt.Errorf("%s: %s", logp, err)
- }
- }
-
- htmlg.tmplSearch = template.New("search")
- htmlg.tmplSearch, err = htmlg.tmplSearch.Parse(templateSearch)
- if err != nil {
- return nil, fmt.Errorf("%s: %s: %w", logp, templateSearch, err)
- }
-
- return htmlg, nil
-}
-
-// convert the markup into HTML.
-func (htmlg *htmlGenerator) convert(fmarkup *fileMarkup) (err error) {
- doc, err := asciidoctor.Open(fmarkup.path)
- if err != nil {
- return err
- }
-
- fmarkup.fhtml.rawBody.Reset()
- err = doc.ToHTMLBody(&fmarkup.fhtml.rawBody)
- if err != nil {
- return err
- }
-
- fmarkup.fhtml.unpackAdocMetadata(doc)
-
- return htmlg.write(fmarkup.fhtml)
-}
-
-// convertFileMarkups convert markup files into HTML.
-func (htmlg *htmlGenerator) convertFileMarkups(fileMarkups map[string]*fileMarkup, isForce bool) {
- logp := "convertFileMarkups"
- for _, fmarkup := range fileMarkups {
- if !fmarkup.isNewerThanHtml() {
- if !isForce {
- continue
- }
- }
-
- err := htmlg.convert(fmarkup)
- if err != nil {
- fmt.Printf("%s: %s\n", logp, err)
- } else {
- fmt.Printf("%s: converting %s\n", logp, fmarkup.path)
- }
- }
-}
-
-func (htmlg *htmlGenerator) htmlTemplateReload() (err error) {
- htmlg.tmpl, err = template.ParseFiles(htmlg.htmlTemplate)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (htmlg *htmlGenerator) htmlTemplateUseInternal() (err error) {
- htmlg.tmpl, err = htmlg.tmpl.Parse(templateIndexHTML)
- if err != nil {
- return err
- }
- return nil
-}
-
-// write the HTML file.
-func (htmlg *htmlGenerator) write(fhtml *fileHtml) (err error) {
- f, err := os.Create(fhtml.path)
- if err != nil {
- return err
- }
-
- err = htmlg.tmpl.Execute(f, fhtml)
- if err != nil {
- return err
- }
-
- err = f.Close()
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/server.go b/server.go
index 6b3c552..7523e85 100644
--- a/server.go
+++ b/server.go
@@ -15,10 +15,10 @@ import (
// server contains the HTTP server that serve the generated HTML files.
type server struct {
- http *libhttp.Server
- htmlg *htmlGenerator
- watcher *watcher
- opts ServeOptions
+ http *libhttp.Server
+ converter *Converter
+ watcher *watcher
+ opts ServeOptions
}
// newServer create an HTTP server to serve HTML files in directory "root".
@@ -29,6 +29,8 @@ type server struct {
func newServer(opts *ServeOptions) (srv *server, err error) {
var (
logp = "newServer"
+
+ tmplNode *memfs.Node
)
if opts.Mfs == nil {
@@ -70,18 +72,27 @@ func newServer(opts *ServeOptions) (srv *server, err error) {
return nil, fmt.Errorf("%s: %w", logp, err)
}
- srv.htmlg, err = newHTMLGenerator(opts.Mfs, opts.HtmlTemplate, opts.IsDevelopment)
+ srv.converter, err = NewConverter(opts.HtmlTemplate)
if err != nil {
return nil, fmt.Errorf("%s: %w", logp, err)
}
+ // Optionally, load HTML template from memory file system.
+ tmplNode, _ = opts.Mfs.Get(internalTemplatePath)
+ if tmplNode != nil {
+ srv.converter.tmpl, err = srv.converter.tmpl.Parse(string(tmplNode.Content))
+ if err != nil {
+ return nil, fmt.Errorf("%s: %s", logp, err)
+ }
+ }
+
if opts.IsDevelopment {
- srv.watcher, err = newWatcher(srv.htmlg, &opts.ConvertOptions)
+ srv.watcher, err = newWatcher(srv.converter, &opts.ConvertOptions)
if err != nil {
return nil, fmt.Errorf("%s: %w", logp, err)
}
- srv.htmlg.convertFileMarkups(srv.watcher.fileMarkups, false)
+ srv.converter.convertFileMarkups(srv.watcher.fileMarkups, false)
}
return srv, nil
@@ -116,7 +127,7 @@ func (srv *server) onSearch(epr *libhttp.EndpointRequest) (resBody []byte, err e
q := epr.HttpRequest.Form.Get("q")
results := srv.http.Options.Memfs.Search(strings.Fields(q), 0)
- err = srv.htmlg.tmplSearch.Execute(&bufSearch, results)
+ err = srv.converter.tmplSearch.Execute(&bufSearch, results)
if err != nil {
return nil, fmt.Errorf("%s: %w", logp, err)
}
@@ -125,7 +136,7 @@ func (srv *server) onSearch(epr *libhttp.EndpointRequest) (resBody []byte, err e
Body: template.HTML(bufSearch.String()), //nolint: gosec
}
- err = srv.htmlg.tmpl.Execute(&buf, fhtml)
+ err = srv.converter.tmpl.Execute(&buf, fhtml)
if err != nil {
return nil, fmt.Errorf("%s: %w", logp, err)
}
diff --git a/watcher.go b/watcher.go
index 7bb2036..1df157d 100644
--- a/watcher.go
+++ b/watcher.go
@@ -20,7 +20,7 @@ type watcher struct {
changes *clise.Clise
watchDir *memfs.DirWatcher
watchTemplate *memfs.Watcher
- htmlg *htmlGenerator
+ converter *Converter
// fileMarkups contains all markup files found inside "dir".
// Its used to convert all markup files when the template file
@@ -33,25 +33,25 @@ type watcher struct {
// newWatcher create a watcher that monitor every files changes in directory
// "dir" for new, modified, and deleted markup files and HTML template file.
//
-// The watcher depends on htmlGenerator to convert the markup to HTML using
-// the HTML template in htmlGenerator.
+// The watcher depends on Converter to convert the markup to HTML using
+// the HTML template in Converter.
//
// watcher
// |
-// +-- watchFileMarkup --> UPDATE --> htmlGenerator.convert()
+// +-- watchFileMarkup --> UPDATE --> Converter.convert()
// |
-// +-- watchHtmlTemplate +--> DELETE --> htmlGenerator.htmlTemplateUseInternal()
+// +-- watchHtmlTemplate +--> DELETE --> Converter.htmlTemplateUseInternal()
// |
-// +--> UPDATE --> htmlGenerated.htmlTemplateReload()
-func newWatcher(htmlg *htmlGenerator, convertOpts *ConvertOptions) (w *watcher, err error) {
+// +--> UPDATE --> Converter.htmlTemplateReload()
+func newWatcher(converter *Converter, convertOpts *ConvertOptions) (w *watcher, err error) {
var (
logp = "newWatcher"
)
w = &watcher{
- dir: convertOpts.Root,
- htmlg: htmlg,
- changes: clise.New(1),
+ dir: convertOpts.Root,
+ converter: converter,
+ changes: clise.New(1),
}
w.watchDir = &memfs.DirWatcher{
Options: memfs.Options{
@@ -89,8 +89,8 @@ func (w *watcher) start() (err error) {
go w.watchFileMarkup()
- if len(w.htmlg.htmlTemplate) > 0 {
- w.watchTemplate, err = memfs.NewWatcher(w.htmlg.htmlTemplate, 0)
+ if len(w.converter.htmlTemplate) > 0 {
+ w.watchTemplate, err = memfs.NewWatcher(w.converter.htmlTemplate, 0)
if err != nil {
return fmt.Errorf("start: %w", err)
}
@@ -156,7 +156,7 @@ func (w *watcher) watchFileMarkup() {
}
}
- err = w.htmlg.convert(fmarkup)
+ err = w.converter.convert(fmarkup)
if err != nil {
log.Printf("%s: %s\n", logp, err)
}
@@ -179,11 +179,11 @@ func (w *watcher) watchHtmlTemplate() {
if ns.State == memfs.FileStateDeleted {
log.Printf("%s: HTML template file %q has been deleted\n",
logp, ns.Node.SysPath)
- err = w.htmlg.htmlTemplateUseInternal()
+ err = w.converter.htmlTemplateUseInternal()
} else {
fmt.Printf("%s: recompiling HTML template %q ...\n", logp,
ns.Node.SysPath)
- err = w.htmlg.htmlTemplateReload()
+ err = w.converter.htmlTemplateReload()
}
if err != nil {
log.Printf("%s: %s", logp, err)
@@ -191,6 +191,6 @@ func (w *watcher) watchHtmlTemplate() {
}
fmt.Printf("%s: regenerate all markup files ...\n", logp)
- w.htmlg.convertFileMarkups(w.fileMarkups, true)
+ w.converter.convertFileMarkups(w.fileMarkups, true)
}
}
diff --git a/watcher_test.go b/watcher_test.go
index 3ce17ee..5cc2079 100644
--- a/watcher_test.go
+++ b/watcher_test.go
@@ -20,9 +20,17 @@ var (
)
func TestWatcher(t *testing.T) {
- testDir := "testdata/watcher"
+ var (
+ testDir = "testdata/watcher"
+ convertOpts = ConvertOptions{
+ Root: testDir,
+ }
+
+ converter *Converter
+ err error
+ )
- err := os.RemoveAll(testDir)
+ err = os.RemoveAll(testDir)
if err != nil {
t.Logf(err.Error())
}
@@ -36,20 +44,17 @@ func TestWatcher(t *testing.T) {
os.RemoveAll(testDir)
})
- htmlg, err := newHTMLGenerator(nil, "testdata/html.tmpl", true)
+ converter, err = NewConverter("testdata/html.tmpl")
if err != nil {
t.Fatal(err)
}
- convertOpts := ConvertOptions{
- Root: testDir,
- }
err = convertOpts.init()
if err != nil {
t.Fatal(err)
}
- testWatcher, err = newWatcher(htmlg, &convertOpts)
+ testWatcher, err = newWatcher(converter, &convertOpts)
if err != nil {
t.Fatal(err)
}
@@ -68,6 +73,7 @@ func testCreate(t *testing.T) {
var (
err error
)
+
testFileAdoc = filepath.Join(testWatcher.dir, "index.adoc")
testAdocFile, err = os.Create(testFileAdoc)
if err != nil {