draft overhaul #8
@@ -1,14 +1,14 @@
|
|||||||
package caddyhugo
|
package caddyhugo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"git.stephensearles.com/stephen/acedoc"
|
"git.stephensearles.com/stephen/acedoc"
|
||||||
"git.stephensearles.com/stephen/idleshut"
|
"git.stephensearles.com/stephen/idleshut"
|
||||||
)
|
)
|
||||||
@@ -18,7 +18,7 @@ type editSession struct {
|
|||||||
docname string
|
docname string
|
||||||
filename string
|
filename string
|
||||||
doc *acedoc.Document
|
doc *acedoc.Document
|
||||||
tmpdir string
|
tmpfs afero.Fs
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,16 +38,16 @@ func (ch *CaddyHugo) newEditSession(docName string) (*editSession, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
draftPrefix := fmt.Sprintf("draft-%s", base64.RawURLEncoding.EncodeToString([]byte(docName)))
|
|
||||||
tmpdir := path.Join(os.TempDir(), draftPrefix)
|
|
||||||
|
|
||||||
es := &editSession{
|
es := &editSession{
|
||||||
docname: docName,
|
docname: docName,
|
||||||
filename: filename,
|
filename: filename,
|
||||||
doc: acedoc.NewString(string(contents)),
|
doc: acedoc.NewString(string(contents)),
|
||||||
tmpdir: tmpdir,
|
// tmpfs: afero.NewCopyOnWriteFs(afero.NewBasePathFs(afero.NewOsFs(), ch.Dir+"/"), afero.NewMemMapFs()),
|
||||||
|
tmpfs: afero.NewCopyOnWriteFs(afero.NewReadOnlyFs(afero.NewBasePathFs(afero.NewOsFs(), ch.Dir)), afero.NewMemMapFs()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printTree(es.tmpfs)
|
||||||
|
|
||||||
err = es.doc.LogToFile(path.Join(ch.Dir, "logs", docName))
|
err = es.doc.LogToFile(path.Join(ch.Dir, "logs", docName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -56,7 +56,10 @@ func (ch *CaddyHugo) newEditSession(docName string) (*editSession, error) {
|
|||||||
|
|
||||||
ch.docs[filename] = es
|
ch.docs[filename] = es
|
||||||
|
|
||||||
ch.renderDraft(es)
|
err = ch.renderDraft(es)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return es, nil
|
return es, nil
|
||||||
}
|
}
|
||||||
@@ -70,9 +73,13 @@ func (ch *CaddyHugo) renderDraft(es *editSession) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc = idleshut.New(HugoCmdProcessConfig(ch, es, f))
|
cfg, err := HugoCmdProcessConfig(ch, es, f)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("rendering draft: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
proc = idleshut.New(cfg)
|
||||||
|
return proc.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch *CaddyHugo) hasEditSession(docName string) (*editSession, bool) {
|
func (ch *CaddyHugo) hasEditSession(docName string) (*editSession, bool) {
|
||||||
|
|||||||
@@ -16,11 +16,6 @@ type DeltaConn interface {
|
|||||||
WriteJSON(v interface{}) error
|
WriteJSON(v interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
IdleWebsocketTimeout = 10 * time.Minute
|
|
||||||
WebsocketFileTicker = 1 * time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
func (ch *CaddyHugo) ObserveLTime(ltime uint64) uint64 {
|
func (ch *CaddyHugo) ObserveLTime(ltime uint64) uint64 {
|
||||||
ch.mtx.Lock()
|
ch.mtx.Lock()
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
"git.stephensearles.com/stephen/caddy-hugo2/assets"
|
"git.stephensearles.com/stephen/caddy-hugo2/assets"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ch *CaddyHugo) ServeHTTPWithNext(next httpserver.Handler, c *caddy.Controller, w http.ResponseWriter, r *http.Request) (int, error) {
|
func (ch *CaddyHugo) ServeHTTPWithNext(next httpserver.Handler, c *caddy.Controller, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
@@ -199,7 +201,7 @@ func (ch *CaddyHugo) serveDraft(w http.ResponseWriter, r *http.Request) (int, er
|
|||||||
r.URL.Path = strings.ToLower(r.URL.Path)
|
r.URL.Path = strings.ToLower(r.URL.Path)
|
||||||
|
|
||||||
prefix := "/hugo/draft/" + encoded
|
prefix := "/hugo/draft/" + encoded
|
||||||
r.URL.Path = r.URL.Path[len(prefix):]
|
r.URL.Path = path.Join("public", r.URL.Path[len(prefix):])
|
||||||
|
|
||||||
page := ch.HugoSites.GetContentPage(ch.docFilename(name))
|
page := ch.HugoSites.GetContentPage(ch.docFilename(name))
|
||||||
if page == nil {
|
if page == nil {
|
||||||
@@ -208,7 +210,48 @@ func (ch *CaddyHugo) serveDraft(w http.ResponseWriter, r *http.Request) (int, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.URL.Path = page.RelPermalink()
|
r.URL.Path = page.RelPermalink()
|
||||||
http.FileServer(http.Dir(docref.tmpdir)).ServeHTTP(w, r)
|
http.FileServer(aferoHTTP{afero.NewBasePathFs(docref.tmpfs, "public")}).ServeHTTP(w, r)
|
||||||
|
|
||||||
return 200, nil
|
return 200, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printTree(fs afero.Fs) {
|
||||||
|
const tab = " "
|
||||||
|
|
||||||
|
afero.Walk(fs, "/", filepath.WalkFunc(func(path string, info os.FileInfo, err error) error {
|
||||||
|
if path == "/" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if filepath.Base(path) == ".git" {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
fmt.Println(err)
|
||||||
|
return err
|
||||||
|
} else if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nIndent := len(strings.Split(path, string(filepath.Separator))) - 1
|
||||||
|
indent := strings.Repeat(tab, nIndent)
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
fmt.Printf("%s├ %s\n", indent, info.Name())
|
||||||
|
nIndent++
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s| %s\t%d\n", indent, info.Name(), info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
type aferoHTTP struct {
|
||||||
|
afero.Fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a aferoHTTP) Open(name string) (http.File, error) {
|
||||||
|
af, err := a.Fs.Open(name)
|
||||||
|
return af, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,13 +2,21 @@ package caddyhugo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"time"
|
||||||
"os"
|
|
||||||
"os/exec"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
"github.com/gohugoio/hugo/hugolib"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"git.stephensearles.com/stephen/idleshut"
|
"git.stephensearles.com/stephen/idleshut"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IdleWebsocketTimeout = 10 * time.Minute
|
||||||
|
WebsocketFileTicker = 1 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
type HugoInteractor interface {
|
type HugoInteractor interface {
|
||||||
Render(srcdir, workdir string) HugoRenderer
|
Render(srcdir, workdir string) HugoRenderer
|
||||||
}
|
}
|
||||||
@@ -19,48 +27,52 @@ type HugoRenderer interface {
|
|||||||
Stop() error
|
Stop() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func HugoCmdProcessConfig(ch *CaddyHugo, es *editSession, touchFn func()) idleshut.Config {
|
func HugoCmdProcessConfig(ch *CaddyHugo, es *editSession, touchFn func()) (idleshut.Config, error) {
|
||||||
cmd := exec.Command("hugo", "--watch", "-D", "-d", es.tmpdir)
|
|
||||||
cmd.Dir = es.tmpdir
|
printTree(es.tmpfs)
|
||||||
|
var err error
|
||||||
|
hugoCfg := &deps.DepsCfg{Fs: hugofs.NewFrom(es.tmpfs, ch.HugoCfg.Cfg)}
|
||||||
|
hugoCfg.Cfg, err = hugolib.LoadConfig(es.tmpfs, "/", "config.toml")
|
||||||
|
if err != nil {
|
||||||
|
return idleshut.Config{}, fmt.Errorf("caddy-hugo: loading site configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hugoCfg.Cfg.Set("workingdir", "/")
|
||||||
|
hugoSites, err := hugolib.NewHugoSites(*hugoCfg)
|
||||||
|
if err != nil {
|
||||||
|
return idleshut.Config{}, fmt.Errorf("caddy-hugo: initializing site: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hugoSites.Build(hugolib.BuildCfg{ResetState: true})
|
||||||
|
if err != nil {
|
||||||
|
// TODO better
|
||||||
|
return idleshut.Config{}, fmt.Errorf("caddy-hugo: building site: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return idleshut.Config{
|
return idleshut.Config{
|
||||||
TickDuration: WebsocketFileTicker,
|
TickDuration: WebsocketFileTicker,
|
||||||
MaxIdleTicks: uint(IdleWebsocketTimeout/WebsocketFileTicker) + 1,
|
MaxIdleTicks: uint(IdleWebsocketTimeout/WebsocketFileTicker) + 1,
|
||||||
Start: func() error {
|
|
||||||
|
|
||||||
err := cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error starting hugo: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
Stop: func() error {
|
Stop: func() error {
|
||||||
if cmd == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := cmd.Process.Signal(os.Interrupt)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error signalling hugo to stop: %v", err)
|
|
||||||
}
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error waiting for hugo to stop: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
es.doc.Close()
|
es.doc.Close()
|
||||||
os.RemoveAll(es.tmpdir)
|
|
||||||
delete(ch.docs, es.filename)
|
delete(ch.docs, es.filename)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
TickError: func(err error) {
|
TickError: func(err error) {
|
||||||
fmt.Println("error processing draft:", err)
|
fmt.Println("error processing draft:", err)
|
||||||
},
|
},
|
||||||
Tick: func() error {
|
Tick: func() error {
|
||||||
return ioutil.WriteFile(es.filename, []byte(es.doc.Contents()), 0644)
|
fmt.Println("TICK")
|
||||||
|
err := afero.WriteFile(es.tmpfs, es.filename, []byte(es.doc.Contents()), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hugoSites.Build(hugolib.BuildCfg{ResetState: true})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user