mirror of
https://github.com/danog/gojekyll.git
synced 2025-01-22 12:51:24 +01:00
Update LTS protocol; more README
This commit is contained in:
parent
1d65456040
commit
0bb1227769
31
README.md
31
README.md
@ -58,18 +58,35 @@ git pull -f osteele
|
||||
|
||||
(See articles by [Shlomi Noach](http://code.openark.org/blog/development/forking-golang-repositories-on-github-and-managing-the-import-path) and [Francesc Campoy](http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html) for how this works and why it is necessary.)
|
||||
|
||||
## Run
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
gojekyll build # builds into ./_site
|
||||
gojekyll serve # serves from memory, w/ live reload
|
||||
gojekyll render index.md # render a file to stdout
|
||||
gojekyll render / # render a URL to stdout
|
||||
gojekyll data / # print a file or URL's variables
|
||||
gojekyll --remote-liquid # use a local Liquid engine server
|
||||
gojekyll build # builds into ./_site
|
||||
gojekyll serve # serves from memory, w/ live reload
|
||||
gojekyll render index.md # render a file to stdout
|
||||
gojekyll render / # render a URL to stdout
|
||||
gojekyll data / # print a file or URL's variables
|
||||
gojekyll # use a local Liquid engine server
|
||||
gojekyll help
|
||||
```
|
||||
|
||||
### Liquid Template Server
|
||||
|
||||
The embedded Liquid server isn't very compliant with Shopfiy Liquid syntax.
|
||||
|
||||
You can run a "Liquid Template Server" on the same machine, and tell `gojekyll` to use this instead.
|
||||
This is currently about 10x slower than using the embedded engine, but still 5x faster than Ruby `jekyll`.
|
||||
|
||||
1. Download and run (liquid-template-server)[https://github.com/osteele/liquid-template-server].
|
||||
2. Invoke `gojekyll` with the `--use-liquid-server` option; e.g.:
|
||||
|
||||
```bash
|
||||
gojekyll --use-liquid-server build
|
||||
gojekyll --use-liquid-server serve
|
||||
```
|
||||
|
||||
Neither the embedded Liquid server nor the Liquid Template Server implements very many Jekyll Liquid filters or tags. I'm adding to these as necessary to support my own sites.
|
||||
|
||||
## Development
|
||||
|
||||
`./scripts/gojekyll` is an alternative to the `gojekyll` executable, that uses `go run` each time it's invoked.
|
||||
|
@ -50,7 +50,7 @@ func main() {
|
||||
Destination: &destination,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "remote-liquid",
|
||||
Name: "use-liquid-server",
|
||||
Usage: "Use Liquid JSON-RPC server",
|
||||
Destination: &useRemoteLiquidEngine,
|
||||
},
|
||||
|
@ -16,13 +16,17 @@ type Template interface {
|
||||
// LocalEngine runs in the same process, and can resolve tag arguments via local handlers.
|
||||
type LocalEngine interface {
|
||||
Engine
|
||||
IncludeHandler(func(string, io.Writer, map[string]interface{}))
|
||||
LinkHandler(LinkHandler)
|
||||
IncludeHandler(IncludeTagHandler)
|
||||
LinkTagHandler(LinkTagHandler)
|
||||
}
|
||||
|
||||
// RemoteEngine runs out-of-process. It needs static tables for tag argument resolution.
|
||||
type RemoteEngine interface {
|
||||
Engine
|
||||
FileURLMap(map[string]string)
|
||||
IncludeDirs([]string)
|
||||
FileURLMap(map[string]string) error
|
||||
IncludeDirs([]string) error
|
||||
}
|
||||
|
||||
// IncludeTagHandler resolves the filename in a Liquid include tag into the expanded content
|
||||
// of the included file.
|
||||
type IncludeTagHandler func(string, io.Writer, map[string]interface{}) error
|
||||
|
@ -13,13 +13,13 @@ func init() {
|
||||
liquid.Tags["link"] = LinkFactory
|
||||
}
|
||||
|
||||
// A LinkHandler given an include tag file name returns a URL.
|
||||
type LinkHandler func(string) (string, bool)
|
||||
// A LinkTagHandler given an include tag file name returns a URL.
|
||||
type LinkTagHandler func(string) (string, bool)
|
||||
|
||||
var currentLinkHandler LinkHandler
|
||||
var currentLinkHandler LinkTagHandler
|
||||
|
||||
// SetLinkHandler sets the function that resolves an include tag file name to a URL.
|
||||
func SetLinkHandler(h LinkHandler) {
|
||||
func SetLinkHandler(h LinkTagHandler) {
|
||||
currentLinkHandler = h
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package liquid
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/acstech/liquid"
|
||||
"github.com/acstech/liquid/core"
|
||||
@ -11,7 +12,7 @@ import (
|
||||
// LocalWrapperEngine is a wrapper around acstech/liquid.
|
||||
type LocalWrapperEngine struct {
|
||||
config *core.Configuration
|
||||
linkHandler LinkHandler
|
||||
linkHandler LinkTagHandler
|
||||
}
|
||||
|
||||
type localTemplate struct {
|
||||
@ -24,14 +25,20 @@ func NewLocalWrapperEngine() LocalEngine {
|
||||
return &LocalWrapperEngine{}
|
||||
}
|
||||
|
||||
// LinkHandler sets the link tag handler.
|
||||
func (engine *LocalWrapperEngine) LinkHandler(h LinkHandler) {
|
||||
// LinkTagHandler sets the link tag handler.
|
||||
func (engine *LocalWrapperEngine) LinkTagHandler(h LinkTagHandler) {
|
||||
engine.linkHandler = h
|
||||
}
|
||||
|
||||
// IncludeHandler sets the include tag handler.
|
||||
func (engine *LocalWrapperEngine) IncludeHandler(h func(string, io.Writer, map[string]interface{})) {
|
||||
engine.config = liquid.Configure().IncludeHandler(h)
|
||||
func (engine *LocalWrapperEngine) IncludeHandler(h IncludeTagHandler) {
|
||||
engine.config = liquid.Configure().IncludeHandler(func(name string, w io.Writer, context map[string]interface{}) {
|
||||
name = strings.TrimLeft(strings.TrimRight(name, "}}"), "{{")
|
||||
err := h(name, w, context)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Parse is a wrapper for liquid.Parse.
|
||||
|
@ -1,6 +1,8 @@
|
||||
package liquid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
||||
"github.com/ybbus/jsonrpc"
|
||||
@ -8,23 +10,36 @@ import (
|
||||
|
||||
// RPCClientEngine connects via JSON-RPC to a Liquid template server.
|
||||
type RPCClientEngine struct {
|
||||
rpcClient *jsonrpc.RPCClient
|
||||
rpcSessionID string
|
||||
rpcClient *jsonrpc.RPCClient
|
||||
}
|
||||
|
||||
// DefaultServer is the default HTTP address for a Liquid template server.
|
||||
// This is an unclaimed port number from https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Registered_ports
|
||||
const DefaultServer = "localhost:4545"
|
||||
|
||||
// RPCVersion is the Liquid Template Server RPC version.
|
||||
const RPCVersion = "0.0.1"
|
||||
|
||||
type remoteTemplate struct {
|
||||
engine RemoteEngine
|
||||
text []byte
|
||||
}
|
||||
|
||||
// RPCError wraps jsonrpc.RPCError into an Error.
|
||||
type RPCError struct{ jsonrpc.RPCError }
|
||||
|
||||
func (engine *RPCError) Error() string {
|
||||
return engine.Message
|
||||
}
|
||||
|
||||
// NewRPCClientEngine creates a RemoteEngine.
|
||||
func NewRPCClientEngine(address string) RemoteEngine {
|
||||
func NewRPCClientEngine(address string) (RemoteEngine, error) {
|
||||
rpcClient := jsonrpc.NewRPCClient("http://" + address)
|
||||
return &RPCClientEngine{rpcClient: rpcClient}
|
||||
engine := RPCClientEngine{rpcClient: rpcClient}
|
||||
if err := engine.createSession(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &engine, nil
|
||||
}
|
||||
|
||||
// Parse parses the template.
|
||||
@ -32,37 +47,30 @@ func (engine *RPCClientEngine) Parse(text []byte) (Template, error) {
|
||||
return &remoteTemplate{engine, text}, nil
|
||||
}
|
||||
|
||||
// RPCError wraps jsonrpc.RPCError into an Error
|
||||
type RPCError struct{ jsonrpc.RPCError }
|
||||
|
||||
func (engine *RPCError) Error() string {
|
||||
return engine.Message
|
||||
}
|
||||
|
||||
func (engine *RPCClientEngine) getSessionID() string {
|
||||
if engine.rpcSessionID != "" {
|
||||
return engine.rpcSessionID
|
||||
}
|
||||
func (engine *RPCClientEngine) createSession() error {
|
||||
res, err := engine.rpcClient.Call("session")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
if res.Error != nil {
|
||||
panic(&RPCError{*res.Error})
|
||||
return &RPCError{*res.Error}
|
||||
}
|
||||
var result struct {
|
||||
SessionID string
|
||||
SessionID string
|
||||
RPCVersion string
|
||||
}
|
||||
if err := res.GetObject(&result); err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
engine.rpcSessionID = result.SessionID
|
||||
return engine.rpcSessionID
|
||||
if result.RPCVersion != RPCVersion {
|
||||
return fmt.Errorf("Liquid server RPC mismatch: expected %s; actual %s", RPCVersion, result.RPCVersion)
|
||||
}
|
||||
engine.rpcClient.SetCustomHeader("Session-ID", result.SessionID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (engine *RPCClientEngine) rpcCall(method string, params ...interface{}) (*jsonrpc.RPCResponse, error) {
|
||||
args := append([]interface{}{engine.getSessionID()}, params...)
|
||||
res, err := engine.rpcClient.Call(method, args...)
|
||||
res, err := engine.rpcClient.Call(method, params...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -73,19 +81,22 @@ func (engine *RPCClientEngine) rpcCall(method string, params ...interface{}) (*j
|
||||
}
|
||||
|
||||
// FileURLMap sets the filename -> permalink map that is used during link tag expansion.
|
||||
func (engine *RPCClientEngine) FileURLMap(m map[string]string) {
|
||||
_, err := engine.rpcCall("fileUrls", m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
func (engine *RPCClientEngine) FileURLMap(m map[string]string) (err error) {
|
||||
_, err = engine.rpcCall("fileUrls", m)
|
||||
return
|
||||
}
|
||||
|
||||
// IncludeDirs specifies the directories that the include tag looks in.
|
||||
func (engine *RPCClientEngine) IncludeDirs(dirs []string) {
|
||||
_, err := engine.rpcCall("includeDirs", dirs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// IncludeDirs specifies the search directories for the include tag.
|
||||
func (engine *RPCClientEngine) IncludeDirs(dirs []string) (err error) {
|
||||
abs := make([]string, len(dirs))
|
||||
for i, dir := range dirs {
|
||||
abs[i], err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
_, err = engine.rpcCall("includeDirs", abs)
|
||||
return
|
||||
}
|
||||
|
||||
// ParseAndRender parses and then renders the template.
|
||||
|
42
site.go
42
site.go
@ -183,47 +183,55 @@ func (s *Site) initTemplateAttributes() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Site) createLocalEngine() liquid.Engine {
|
||||
func (s *Site) makeLocalLiquidEngine() liquid.Engine {
|
||||
engine := liquid.NewLocalWrapperEngine()
|
||||
engine.LinkHandler(s.GetFileURL)
|
||||
includeHandler := func(name string, w io.Writer, scope map[string]interface{}) {
|
||||
name = strings.TrimLeft(strings.TrimRight(name, "}}"), "{{")
|
||||
engine.LinkTagHandler(s.GetFileURL)
|
||||
includeHandler := func(name string, w io.Writer, scope map[string]interface{}) error {
|
||||
filename := filepath.Join(s.Source, s.config.IncludesDir, name)
|
||||
template, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
text, err := engine.ParseAndRender(template, scope)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(text)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
engine.IncludeHandler(includeHandler)
|
||||
return engine
|
||||
}
|
||||
|
||||
func (s *Site) createRemoteEngine() liquid.Engine {
|
||||
engine := liquid.NewRPCClientEngine(liquid.DefaultServer)
|
||||
func (s *Site) makeLiquidClient() (engine liquid.RemoteEngine, err error) {
|
||||
engine, err = liquid.NewRPCClientEngine(liquid.DefaultServer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
urls := map[string]string{}
|
||||
for _, p := range s.Paths {
|
||||
urls[p.Path()] = p.Permalink()
|
||||
}
|
||||
engine.FileURLMap(urls)
|
||||
engine.IncludeDirs([]string{filepath.Join(s.Source, s.config.IncludesDir)})
|
||||
return engine
|
||||
err = engine.FileURLMap(urls)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = engine.IncludeDirs([]string{filepath.Join(s.Source, s.config.IncludesDir)})
|
||||
return
|
||||
}
|
||||
|
||||
// LiquidEngine create a liquid engine with site-specific behavior.
|
||||
// LiquidEngine create a liquid engine configured to with include paths and link tag resolution
|
||||
// for this site.
|
||||
func (s *Site) LiquidEngine() liquid.Engine {
|
||||
if s.liquidEngine == nil {
|
||||
if s.UseRemoteLiquidEngine {
|
||||
s.liquidEngine = s.createRemoteEngine()
|
||||
var err error
|
||||
s.liquidEngine, err = s.makeLiquidClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
s.liquidEngine = s.createLocalEngine()
|
||||
s.liquidEngine = s.makeLocalLiquidEngine()
|
||||
}
|
||||
}
|
||||
return s.liquidEngine
|
||||
|
Loading…
x
Reference in New Issue
Block a user