2017-06-10 21:38:09 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2017-06-11 01:32:39 +02:00
|
|
|
"sort"
|
2017-06-12 00:11:52 +02:00
|
|
|
"strings"
|
2017-06-10 21:38:09 +02:00
|
|
|
"time"
|
|
|
|
|
2017-06-12 23:12:40 +02:00
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
|
2017-06-10 21:38:09 +02:00
|
|
|
"github.com/acstech/liquid"
|
|
|
|
)
|
|
|
|
|
2017-06-12 23:12:40 +02:00
|
|
|
// Command-line options
|
|
|
|
var options struct {
|
|
|
|
useHardLinks bool
|
2017-06-13 17:00:24 +02:00
|
|
|
dryRun bool
|
2017-06-12 23:12:40 +02:00
|
|
|
}
|
|
|
|
|
2017-06-10 21:38:09 +02:00
|
|
|
// This is the longest label. Pull it out here so we can both use it, and measure it for alignment.
|
|
|
|
const configurationFileLabel = "Configuration file:"
|
|
|
|
|
|
|
|
func printSetting(label string, value string) {
|
|
|
|
fmt.Printf("%s %s\n",
|
2017-06-11 22:00:03 +02:00
|
|
|
leftPad(label, len(configurationFileLabel)), value)
|
2017-06-10 21:38:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func printPathSetting(label string, path string) {
|
|
|
|
path, err := filepath.Abs(path)
|
|
|
|
if err != nil {
|
|
|
|
panic("Couldn't convert to absolute path")
|
|
|
|
}
|
|
|
|
printSetting(label, path)
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
liquid.Tags["link"] = LinkFactory
|
|
|
|
|
2017-06-12 23:12:40 +02:00
|
|
|
// general options
|
2017-06-13 14:50:12 +02:00
|
|
|
source := flag.String("source", ".", "Source directory")
|
2017-06-13 17:00:24 +02:00
|
|
|
dest := flag.String("destination", "./_site", "Destination directory")
|
2017-06-11 01:32:39 +02:00
|
|
|
|
2017-06-12 23:12:40 +02:00
|
|
|
// maybe add flags for these
|
2017-06-13 17:00:24 +02:00
|
|
|
flag.BoolVar(&options.dryRun, "dry-run", false, "Dry run")
|
|
|
|
// flag.BoolVar(&options.useHardLinks, "-n", false, "Dry run")
|
2017-06-12 23:12:40 +02:00
|
|
|
|
2017-06-11 01:32:39 +02:00
|
|
|
// routes subcommand
|
|
|
|
dynamic := flag.Bool("dynamic", false, "Dynamic routes only")
|
|
|
|
|
2017-06-10 21:38:09 +02:00
|
|
|
flag.Parse()
|
2017-06-12 00:11:52 +02:00
|
|
|
if len(flag.Args()) < 1 {
|
|
|
|
fmt.Println("A subcommand is required.")
|
|
|
|
return
|
|
|
|
}
|
2017-06-10 21:38:09 +02:00
|
|
|
|
2017-06-13 17:27:24 +02:00
|
|
|
start := time.Now()
|
|
|
|
if err := ReadConfiguration(*source, *dest); err != nil {
|
2017-06-12 23:12:40 +02:00
|
|
|
fmt.Println(err)
|
2017-06-10 21:38:09 +02:00
|
|
|
}
|
|
|
|
|
2017-06-13 17:27:24 +02:00
|
|
|
if site.ConfigFile != nil {
|
|
|
|
printPathSetting(configurationFileLabel, *site.ConfigFile)
|
|
|
|
} else {
|
|
|
|
printSetting(configurationFileLabel, "none")
|
|
|
|
|
|
|
|
}
|
|
|
|
printPathSetting("Source:", site.Source)
|
|
|
|
|
|
|
|
if err := site.ReadFiles(); err != nil {
|
2017-06-10 21:38:09 +02:00
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch flag.Arg(0) {
|
|
|
|
case "s", "serve", "server":
|
2017-06-13 17:27:24 +02:00
|
|
|
if err := server(); err != nil {
|
2017-06-11 20:57:57 +02:00
|
|
|
fmt.Println(err)
|
|
|
|
}
|
2017-06-10 21:38:09 +02:00
|
|
|
case "b", "build":
|
2017-06-13 17:27:24 +02:00
|
|
|
printPathSetting("Destination:", site.Dest)
|
2017-06-10 21:38:09 +02:00
|
|
|
printSetting("Generating...", "")
|
2017-06-13 17:27:24 +02:00
|
|
|
if err := site.Build(); err != nil {
|
2017-06-11 20:57:57 +02:00
|
|
|
fmt.Println(err)
|
|
|
|
break
|
|
|
|
}
|
2017-06-10 21:38:09 +02:00
|
|
|
elapsed := time.Since(start)
|
|
|
|
printSetting("", fmt.Sprintf("done in %.2fs.", elapsed.Seconds()))
|
2017-06-12 23:12:40 +02:00
|
|
|
case "data":
|
|
|
|
path := flag.Arg(1)
|
|
|
|
page := findPageForCLIArg(path)
|
|
|
|
if page == nil {
|
|
|
|
fmt.Println("No page at", path)
|
|
|
|
return
|
|
|
|
}
|
2017-06-13 17:00:24 +02:00
|
|
|
|
2017-06-13 17:27:24 +02:00
|
|
|
printSetting("Data:", "")
|
2017-06-13 17:00:24 +02:00
|
|
|
// The YAML representation including collections is impractically large for debugging.
|
|
|
|
// (Actually it's circular, which the yaml package can't handle.)
|
|
|
|
// Neuter it. This destroys it as Liquid data, but that's okay in this context.
|
2017-06-13 17:27:24 +02:00
|
|
|
for _, c := range site.Collections {
|
|
|
|
site.Data[c.Name] = fmt.Sprintf("<elided page data for %d items>", len(site.Data[c.Name].([]interface{})))
|
2017-06-12 23:12:40 +02:00
|
|
|
}
|
|
|
|
b, _ := yaml.Marshal(stringMap(page.Data()))
|
|
|
|
fmt.Println(string(b))
|
|
|
|
default:
|
|
|
|
fmt.Println("A subcommand is required.")
|
2017-06-10 21:38:09 +02:00
|
|
|
case "routes":
|
2017-06-13 17:27:24 +02:00
|
|
|
printSetting("Routes:", "")
|
2017-06-11 01:32:39 +02:00
|
|
|
urls := []string{}
|
2017-06-13 17:00:24 +02:00
|
|
|
for u, p := range site.Paths {
|
2017-06-11 01:32:39 +02:00
|
|
|
if !(*dynamic && p.Static) {
|
|
|
|
urls = append(urls, u)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Strings(urls)
|
|
|
|
for _, u := range urls {
|
2017-06-13 17:00:24 +02:00
|
|
|
fmt.Printf(" %s -> %s\n", u, site.Paths[u].Path)
|
2017-06-10 21:38:09 +02:00
|
|
|
}
|
2017-06-10 23:51:46 +02:00
|
|
|
case "render":
|
2017-06-12 00:11:52 +02:00
|
|
|
path := flag.Arg(1)
|
2017-06-12 23:12:40 +02:00
|
|
|
page := findPageForCLIArg(path)
|
|
|
|
if page == nil {
|
|
|
|
fmt.Println("No page at", path)
|
|
|
|
return
|
2017-06-12 02:30:25 +02:00
|
|
|
}
|
2017-06-13 17:27:24 +02:00
|
|
|
printPathSetting("Render:", filepath.Join(site.Source, page.Path))
|
2017-06-12 02:51:01 +02:00
|
|
|
printSetting("URL:", page.Permalink)
|
2017-06-13 17:27:24 +02:00
|
|
|
printSetting("Content:", "")
|
2017-06-12 02:51:01 +02:00
|
|
|
if err := page.Render(os.Stdout); err != nil {
|
2017-06-12 02:30:25 +02:00
|
|
|
fmt.Println(err)
|
2017-06-10 21:38:09 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-12 23:12:40 +02:00
|
|
|
|
2017-06-13 17:00:24 +02:00
|
|
|
// If path starts with /, it's a URL path. Else it's a file path relative
|
|
|
|
// to the site source directory. Either way, return the Page or nil.
|
2017-06-12 23:12:40 +02:00
|
|
|
func findPageForCLIArg(path string) *Page {
|
|
|
|
if path == "" {
|
|
|
|
path = "/"
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(path, "/") {
|
2017-06-13 17:00:24 +02:00
|
|
|
return site.Paths[path]
|
2017-06-12 23:12:40 +02:00
|
|
|
}
|
2017-06-13 17:00:24 +02:00
|
|
|
return site.FindPageByFilePath(path)
|
2017-06-12 23:12:40 +02:00
|
|
|
}
|
|
|
|
|
2017-06-13 17:00:24 +02:00
|
|
|
// FindPageByFilePath returns a Page or nil, referenced by relative path.
|
|
|
|
func (s *Site) FindPageByFilePath(path string) *Page {
|
|
|
|
for _, p := range s.Paths {
|
2017-06-12 23:12:40 +02:00
|
|
|
if p.Path == path {
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|