package main import ( "fmt" "log" "os" "path" "strings" "text/template" "github.com/pelletier/go-toml" ) // Site represents a site. type Site struct { Title string `toml:"title"` URLs []string `toml:"urls"` Tasks []*Task `toml:"tasks"` Feeds map[string]string `toml:"feeds"` // Deprecated. Use Task.Feeds instead Params map[string]string `toml:"params"` Permalinks map[string]string `toml:"permalinks"` permalinks map[string]*template.Template templates Templates root *Dir } // Task represents a site build task. type Task struct { Input []string `toml:"input"` // input file suffixes OutputExt string `toml:"output"` // output file suffix TemplateExt string `toml:"template"` // template file suffix Preprocess map[string]string `toml:"preprocess"` // preprocess commands Postprocess string `toml:"postprocess"` // postprocess command StaticDir string `toml:"static_dir"` // static file directory OutputDir string `toml:"output_dir"` // output directory UglyURLs bool `toml:"ugly_urls"` // whether to use ugly URLs Feeds []Feed `toml:"feeds"` feeds map[string][]Feed } type Feed struct { InputDir string `toml:"input_dir"` Title string `toml:"title"` Template string `toml:"template"` Output string `toml:"output"` // if true, the feed was specified using deprecated configuration options. deprecated bool } func (t *Task) Match(ext string) bool { for i := range t.Input { if t.Input[i] == ext { return true } } return false } // LoadSite loads the site with the given configuration file. func LoadSite(config string) (*Site, error) { f, err := os.Open(config) if err != nil { return nil, err } defer f.Close() site := &Site{} if err := toml.NewDecoder(f).Decode(site); err != nil { return nil, err } funcs := site.funcs() // Parse permalinks site.permalinks = map[string]*template.Template{} for path := range site.Permalinks { t := template.New(fmt.Sprintf("permalink %q", path)).Funcs(funcs) _, err := t.Parse(site.Permalinks[path]) if err != nil { return nil, err } site.permalinks[path] = t } // Load templates templateExts := []string{} for _, task := range site.Tasks { if task.TemplateExt != "" { templateExts = append(templateExts, task.TemplateExt) } } site.templates.Funcs(funcs) if err := site.templates.Load("templates", templateExts); err != nil { return nil, err } // Populate task feeds map for _, task := range site.Tasks { task.feeds = map[string][]Feed{} for _, feed := range task.Feeds { dir := feed.InputDir task.feeds[dir] = append(task.feeds[dir], feed) } } // Populate task feeds map with deprecated feeds for dir, title := range site.Feeds { // Deprecated feeds apply to every task for _, task := range site.Tasks { if _, ok := task.feeds[dir]; !ok { dir = strings.TrimSuffix(dir, "/") task.feeds[dir] = append(task.feeds[dir], Feed{ InputDir: dir, Title: title, Template: "atom.xml", Output: path.Join(dir, "atom.xml"), deprecated: true, }) } } } // Print deprecation warning for [feeds] if len(site.Feeds) > 0 { log.Println("WARNING: The [feeds] configuration is deprecated. Please use [[tasks.feeds]] instead:") for permalink, title := range site.Feeds { dir := strings.Trim(permalink, "/") output := path.Join(dir, "atom.xml") fmt.Fprintf(log.Writer(), `[[tasks.feeds]] input_dir = %q title = %q template = "atom.xml" output = %q `, dir, title, output) } fmt.Fprintf(log.Writer(), "# NOTE: You will also need to use .Pages instead of .Entries in your feed templates\n") } return site, nil } func (s *Site) dir(path string) *Dir { return s.root.getDir(path) } func (s *Site) page(path string) *Page { return s.root.getPage(path) }