parent
0ada405912
commit
c71e1b106e
|
@ -49,10 +49,13 @@ func init() {
|
|||
|
||||
func benchmark(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := InitializeConfig(benchmarkCmd)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c := commandeer{cfg}
|
||||
|
||||
var memProf *os.File
|
||||
if memProfileFile != "" {
|
||||
memProf, err = os.Create(memProfileFile)
|
||||
|
@ -79,7 +82,7 @@ func benchmark(cmd *cobra.Command, args []string) error {
|
|||
|
||||
t := time.Now()
|
||||
for i := 0; i < benchmarkTimes; i++ {
|
||||
if err = resetAndBuildSites(cfg, false); err != nil {
|
||||
if err = c.resetAndBuildSites(false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,9 +51,9 @@ for rendering in Hugo.`,
|
|||
if !strings.HasSuffix(gendocdir, helpers.FilePathSeparator) {
|
||||
gendocdir += helpers.FilePathSeparator
|
||||
}
|
||||
if found, _ := helpers.Exists(gendocdir, hugofs.Os()); !found {
|
||||
if found, _ := helpers.Exists(gendocdir, hugofs.Os); !found {
|
||||
jww.FEEDBACK.Println("Directory", gendocdir, "does not exist, creating...")
|
||||
hugofs.Os().MkdirAll(gendocdir, 0777)
|
||||
hugofs.Os.MkdirAll(gendocdir, 0777)
|
||||
}
|
||||
now := time.Now().Format(time.RFC3339)
|
||||
prepender := func(filename string) string {
|
||||
|
|
|
@ -41,9 +41,9 @@ in the "man" directory under the current directory.`,
|
|||
if !strings.HasSuffix(genmandir, helpers.FilePathSeparator) {
|
||||
genmandir += helpers.FilePathSeparator
|
||||
}
|
||||
if found, _ := helpers.Exists(genmandir, hugofs.Os()); !found {
|
||||
if found, _ := helpers.Exists(genmandir, hugofs.Os); !found {
|
||||
jww.FEEDBACK.Println("Directory", genmandir, "does not exist, creating...")
|
||||
hugofs.Os().MkdirAll(genmandir, 0777)
|
||||
hugofs.Os.MkdirAll(genmandir, 0777)
|
||||
}
|
||||
cmd.Root().DisableAutoGenTag = true
|
||||
|
||||
|
|
135
commands/hugo.go
135
commands/hugo.go
|
@ -40,6 +40,7 @@ import (
|
|||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/fsync"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugolib"
|
||||
"github.com/spf13/hugo/livereload"
|
||||
|
@ -50,6 +51,10 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type commandeer struct {
|
||||
deps.DepsCfg
|
||||
}
|
||||
|
||||
// Hugo represents the Hugo sites to build. This variable is exported as it
|
||||
// is used by at least one external library (the Hugo caddy plugin). We should
|
||||
// provide a cleaner external API, but until then, this is it.
|
||||
|
@ -119,12 +124,14 @@ Complete documentation is available at http://gohugo.io/.`,
|
|||
return err
|
||||
}
|
||||
|
||||
c := commandeer{cfg}
|
||||
|
||||
if buildWatch {
|
||||
viper.Set("disableLiveReload", true)
|
||||
watchConfig(cfg)
|
||||
c.watchConfig()
|
||||
}
|
||||
|
||||
return build(cfg)
|
||||
return c.build()
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -268,9 +275,9 @@ func init() {
|
|||
}
|
||||
|
||||
// InitializeConfig initializes a config file with sensible default configuration flags.
|
||||
func InitializeConfig(subCmdVs ...*cobra.Command) (hugolib.DepsCfg, error) {
|
||||
func InitializeConfig(subCmdVs ...*cobra.Command) (deps.DepsCfg, error) {
|
||||
|
||||
var cfg hugolib.DepsCfg
|
||||
var cfg deps.DepsCfg
|
||||
|
||||
if err := hugolib.LoadGlobalConfig(source, cfgFile); err != nil {
|
||||
return cfg, err
|
||||
|
@ -323,34 +330,34 @@ func InitializeConfig(subCmdVs ...*cobra.Command) (hugolib.DepsCfg, error) {
|
|||
viper.Set("cacheDir", cacheDir)
|
||||
}
|
||||
|
||||
// Init file systems. This may be changed at a later point.
|
||||
cfg.Fs = hugofs.NewDefault()
|
||||
|
||||
cacheDir = viper.GetString("cacheDir")
|
||||
if cacheDir != "" {
|
||||
if helpers.FilePathSeparator != cacheDir[len(cacheDir)-1:] {
|
||||
cacheDir = cacheDir + helpers.FilePathSeparator
|
||||
}
|
||||
isDir, err := helpers.DirExists(cacheDir, hugofs.Source())
|
||||
isDir, err := helpers.DirExists(cacheDir, cfg.Fs.Source)
|
||||
utils.CheckErr(err)
|
||||
if !isDir {
|
||||
mkdir(cacheDir)
|
||||
}
|
||||
viper.Set("cacheDir", cacheDir)
|
||||
} else {
|
||||
viper.Set("cacheDir", helpers.GetTempDir("hugo_cache", hugofs.Source()))
|
||||
viper.Set("cacheDir", helpers.GetTempDir("hugo_cache", cfg.Fs.Source))
|
||||
}
|
||||
|
||||
jww.INFO.Println("Using config file:", viper.ConfigFileUsed())
|
||||
|
||||
// Init file systems. This may be changed at a later point.
|
||||
hugofs.InitDefaultFs()
|
||||
|
||||
themeDir := helpers.GetThemeDir()
|
||||
if themeDir != "" {
|
||||
if _, err := hugofs.Source().Stat(themeDir); os.IsNotExist(err) {
|
||||
if _, err := cfg.Fs.Source.Stat(themeDir); os.IsNotExist(err) {
|
||||
return cfg, newSystemError("Unable to find theme Directory:", themeDir)
|
||||
}
|
||||
}
|
||||
|
||||
themeVersionMismatch, minVersion := isThemeVsHugoVersionMismatch()
|
||||
themeVersionMismatch, minVersion := isThemeVsHugoVersionMismatch(cfg.Fs.Source)
|
||||
|
||||
if themeVersionMismatch {
|
||||
jww.ERROR.Printf("Current theme does not support Hugo version %s. Minimum version required is %s\n",
|
||||
|
@ -447,12 +454,12 @@ func flagChanged(flags *flag.FlagSet, key string) bool {
|
|||
return flag.Changed
|
||||
}
|
||||
|
||||
func watchConfig(cfg hugolib.DepsCfg) {
|
||||
func (c commandeer) watchConfig() {
|
||||
viper.WatchConfig()
|
||||
viper.OnConfigChange(func(e fsnotify.Event) {
|
||||
jww.FEEDBACK.Println("Config file changed:", e.Name)
|
||||
// Force a full rebuild
|
||||
utils.CheckErr(recreateAndBuildSites(cfg, true))
|
||||
utils.CheckErr(c.recreateAndBuildSites(true))
|
||||
if !viper.GetBool("disableLiveReload") {
|
||||
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
|
||||
livereload.ForceRefresh()
|
||||
|
@ -460,39 +467,40 @@ func watchConfig(cfg hugolib.DepsCfg) {
|
|||
})
|
||||
}
|
||||
|
||||
func build(cfg hugolib.DepsCfg, watches ...bool) error {
|
||||
func (c commandeer) build(watches ...bool) error {
|
||||
// Hugo writes the output to memory instead of the disk.
|
||||
// This is only used for benchmark testing. Cause the content is only visible
|
||||
// in memory.
|
||||
if renderToMemory {
|
||||
hugofs.SetDestination(new(afero.MemMapFs))
|
||||
c.Fs.Destination = new(afero.MemMapFs)
|
||||
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
||||
viper.Set("publishDir", "/")
|
||||
}
|
||||
|
||||
if err := copyStatic(); err != nil {
|
||||
if err := c.copyStatic(); err != nil {
|
||||
return fmt.Errorf("Error copying static files to %s: %s", helpers.AbsPathify(viper.GetString("publishDir")), err)
|
||||
}
|
||||
watch := false
|
||||
if len(watches) > 0 && watches[0] {
|
||||
watch = true
|
||||
}
|
||||
if err := buildSites(cfg, buildWatch || watch); err != nil {
|
||||
if err := c.buildSites(buildWatch || watch); err != nil {
|
||||
return fmt.Errorf("Error building site: %s", err)
|
||||
}
|
||||
|
||||
if buildWatch {
|
||||
jww.FEEDBACK.Println("Watching for changes in", helpers.AbsPathify(viper.GetString("contentDir")))
|
||||
jww.FEEDBACK.Println("Press Ctrl+C to stop")
|
||||
utils.CheckErr(newWatcher(cfg, 0))
|
||||
utils.CheckErr(c.newWatcher(0))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStaticSourceFs() afero.Fs {
|
||||
source := hugofs.Source()
|
||||
themeDir, err := helpers.GetThemeStaticDirPath()
|
||||
func (c commandeer) getStaticSourceFs() afero.Fs {
|
||||
source := c.Fs.Source
|
||||
pathSpec := helpers.NewPathSpec(c.Fs, viper.GetViper())
|
||||
themeDir, err := pathSpec.GetThemeStaticDirPath()
|
||||
staticDir := helpers.GetStaticDirPath() + helpers.FilePathSeparator
|
||||
|
||||
useTheme := true
|
||||
|
@ -532,12 +540,12 @@ func getStaticSourceFs() afero.Fs {
|
|||
jww.INFO.Println("using a UnionFS for static directory comprised of:")
|
||||
jww.INFO.Println("Base:", themeDir)
|
||||
jww.INFO.Println("Overlay:", staticDir)
|
||||
base := afero.NewReadOnlyFs(afero.NewBasePathFs(hugofs.Source(), themeDir))
|
||||
overlay := afero.NewReadOnlyFs(afero.NewBasePathFs(hugofs.Source(), staticDir))
|
||||
base := afero.NewReadOnlyFs(afero.NewBasePathFs(source, themeDir))
|
||||
overlay := afero.NewReadOnlyFs(afero.NewBasePathFs(source, staticDir))
|
||||
return afero.NewCopyOnWriteFs(base, overlay)
|
||||
}
|
||||
|
||||
func copyStatic() error {
|
||||
func (c commandeer) copyStatic() error {
|
||||
publishDir := helpers.AbsPathify(viper.GetString("publishDir")) + helpers.FilePathSeparator
|
||||
|
||||
// If root, remove the second '/'
|
||||
|
@ -546,7 +554,7 @@ func copyStatic() error {
|
|||
}
|
||||
|
||||
// Includes both theme/static & /static
|
||||
staticSourceFs := getStaticSourceFs()
|
||||
staticSourceFs := c.getStaticSourceFs()
|
||||
|
||||
if staticSourceFs == nil {
|
||||
jww.WARN.Println("No static directories found to sync")
|
||||
|
@ -557,7 +565,7 @@ func copyStatic() error {
|
|||
syncer.NoTimes = viper.GetBool("noTimes")
|
||||
syncer.NoChmod = viper.GetBool("noChmod")
|
||||
syncer.SrcFs = staticSourceFs
|
||||
syncer.DestFs = hugofs.Destination()
|
||||
syncer.DestFs = c.Fs.Destination
|
||||
// Now that we are using a unionFs for the static directories
|
||||
// We can effectively clean the publishDir on initial sync
|
||||
syncer.Delete = viper.GetBool("cleanDestinationDir")
|
||||
|
@ -572,7 +580,7 @@ func copyStatic() error {
|
|||
}
|
||||
|
||||
// getDirList provides NewWatcher() with a list of directories to watch for changes.
|
||||
func getDirList() []string {
|
||||
func (c commandeer) getDirList() []string {
|
||||
var a []string
|
||||
dataDir := helpers.AbsPathify(viper.GetString("dataDir"))
|
||||
i18nDir := helpers.AbsPathify(viper.GetString("i18nDir"))
|
||||
|
@ -621,7 +629,7 @@ func getDirList() []string {
|
|||
jww.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", path, err)
|
||||
return nil
|
||||
}
|
||||
linkfi, err := hugofs.Source().Stat(link)
|
||||
linkfi, err := c.Fs.Source.Stat(link)
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
|
||||
return nil
|
||||
|
@ -642,25 +650,25 @@ func getDirList() []string {
|
|||
return nil
|
||||
}
|
||||
|
||||
helpers.SymbolicWalk(hugofs.Source(), dataDir, walker)
|
||||
helpers.SymbolicWalk(hugofs.Source(), helpers.AbsPathify(viper.GetString("contentDir")), walker)
|
||||
helpers.SymbolicWalk(hugofs.Source(), i18nDir, walker)
|
||||
helpers.SymbolicWalk(hugofs.Source(), helpers.AbsPathify(viper.GetString("layoutDir")), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, dataDir, walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, helpers.AbsPathify(viper.GetString("contentDir")), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, i18nDir, walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, helpers.AbsPathify(viper.GetString("layoutDir")), walker)
|
||||
|
||||
helpers.SymbolicWalk(hugofs.Source(), staticDir, walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, staticDir, walker)
|
||||
if helpers.ThemeSet() {
|
||||
helpers.SymbolicWalk(hugofs.Source(), filepath.Join(themesDir, "layouts"), walker)
|
||||
helpers.SymbolicWalk(hugofs.Source(), filepath.Join(themesDir, "static"), walker)
|
||||
helpers.SymbolicWalk(hugofs.Source(), filepath.Join(themesDir, "i18n"), walker)
|
||||
helpers.SymbolicWalk(hugofs.Source(), filepath.Join(themesDir, "data"), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "layouts"), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "static"), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "i18n"), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "data"), walker)
|
||||
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func recreateAndBuildSites(cfg hugolib.DepsCfg, watching bool) (err error) {
|
||||
if err := initSites(cfg); err != nil {
|
||||
func (c commandeer) recreateAndBuildSites(watching bool) (err error) {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !quiet {
|
||||
|
@ -669,9 +677,9 @@ func recreateAndBuildSites(cfg hugolib.DepsCfg, watching bool) (err error) {
|
|||
return Hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true, Watching: watching, PrintStats: !quiet})
|
||||
}
|
||||
|
||||
func resetAndBuildSites(cfg hugolib.DepsCfg, watching bool) (err error) {
|
||||
if err := initSites(cfg); err != nil {
|
||||
return err
|
||||
func (c commandeer) resetAndBuildSites(watching bool) (err error) {
|
||||
if err = c.initSites(); err != nil {
|
||||
return
|
||||
}
|
||||
if !quiet {
|
||||
jww.FEEDBACK.Println("Started building sites ...")
|
||||
|
@ -679,12 +687,12 @@ func resetAndBuildSites(cfg hugolib.DepsCfg, watching bool) (err error) {
|
|||
return Hugo.Build(hugolib.BuildCfg{ResetState: true, Watching: watching, PrintStats: !quiet})
|
||||
}
|
||||
|
||||
func initSites(cfg hugolib.DepsCfg) error {
|
||||
func (c commandeer) initSites() error {
|
||||
if Hugo != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
h, err := hugolib.NewHugoSitesFromConfiguration(cfg)
|
||||
h, err := hugolib.NewHugoSitesFromConfiguration(c.DepsCfg)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -694,8 +702,8 @@ func initSites(cfg hugolib.DepsCfg) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func buildSites(cfg hugolib.DepsCfg, watching bool) (err error) {
|
||||
if err := initSites(cfg); err != nil {
|
||||
func (c commandeer) buildSites(watching bool) (err error) {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !quiet {
|
||||
|
@ -704,19 +712,21 @@ func buildSites(cfg hugolib.DepsCfg, watching bool) (err error) {
|
|||
return Hugo.Build(hugolib.BuildCfg{Watching: watching, PrintStats: !quiet})
|
||||
}
|
||||
|
||||
func rebuildSites(cfg hugolib.DepsCfg, events []fsnotify.Event) error {
|
||||
if err := initSites(cfg); err != nil {
|
||||
func (c commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
return Hugo.Build(hugolib.BuildCfg{PrintStats: !quiet, Watching: true}, events...)
|
||||
}
|
||||
|
||||
// newWatcher creates a new watcher to watch filesystem events.
|
||||
func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
||||
func (c commandeer) newWatcher(port int) error {
|
||||
if runtime.GOOS == "darwin" {
|
||||
tweakLimit()
|
||||
}
|
||||
|
||||
pathSpec := helpers.NewPathSpec(c.Fs, viper.GetViper())
|
||||
|
||||
watcher, err := watcher.New(1 * time.Second)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
|
@ -728,7 +738,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
|
||||
wg.Add(1)
|
||||
|
||||
for _, d := range getDirList() {
|
||||
for _, d := range c.getDirList() {
|
||||
if d != "" {
|
||||
_ = watcher.Add(d)
|
||||
}
|
||||
|
@ -793,12 +803,12 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
// recursively add new directories to watch list
|
||||
// When mkdir -p is used, only the top directory triggers an event (at least on OSX)
|
||||
if ev.Op&fsnotify.Create == fsnotify.Create {
|
||||
if s, err := hugofs.Source().Stat(ev.Name); err == nil && s.Mode().IsDir() {
|
||||
helpers.SymbolicWalk(hugofs.Source(), ev.Name, walkAdder)
|
||||
if s, err := c.Fs.Source.Stat(ev.Name); err == nil && s.Mode().IsDir() {
|
||||
helpers.SymbolicWalk(c.Fs.Source, ev.Name, walkAdder)
|
||||
}
|
||||
}
|
||||
|
||||
isstatic := strings.HasPrefix(ev.Name, helpers.GetStaticDirPath()) || (len(helpers.GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, helpers.GetThemesDirPath()))
|
||||
isstatic := strings.HasPrefix(ev.Name, helpers.GetStaticDirPath()) || (len(pathSpec.GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, pathSpec.GetThemesDirPath()))
|
||||
|
||||
if isstatic {
|
||||
staticEvents = append(staticEvents, ev)
|
||||
|
@ -821,12 +831,12 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
|
||||
if viper.GetBool("forceSyncStatic") {
|
||||
jww.FEEDBACK.Printf("Syncing all static files\n")
|
||||
err := copyStatic()
|
||||
err := c.copyStatic()
|
||||
if err != nil {
|
||||
utils.StopOnErr(err, fmt.Sprintf("Error copying static files to %s", publishDir))
|
||||
}
|
||||
} else {
|
||||
staticSourceFs := getStaticSourceFs()
|
||||
staticSourceFs := c.getStaticSourceFs()
|
||||
|
||||
if staticSourceFs == nil {
|
||||
jww.WARN.Println("No static directories found to sync")
|
||||
|
@ -837,7 +847,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
syncer.NoTimes = viper.GetBool("noTimes")
|
||||
syncer.NoChmod = viper.GetBool("noChmod")
|
||||
syncer.SrcFs = staticSourceFs
|
||||
syncer.DestFs = hugofs.Destination()
|
||||
syncer.DestFs = c.Fs.Destination
|
||||
|
||||
// prevent spamming the log on changes
|
||||
logger := helpers.NewDistinctFeedbackLogger()
|
||||
|
@ -862,7 +872,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
fromPath := ev.Name
|
||||
|
||||
// If we are here we already know the event took place in a static dir
|
||||
relPath, err := helpers.MakeStaticPathRelative(fromPath)
|
||||
relPath, err := pathSpec.MakeStaticPathRelative(fromPath)
|
||||
if err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
continue
|
||||
|
@ -882,7 +892,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
// If file doesn't exist in any static dir, remove it
|
||||
toRemove := filepath.Join(publishDir, relPath)
|
||||
logger.Println("File no longer exists in static dir, removing", toRemove)
|
||||
hugofs.Destination().RemoveAll(toRemove)
|
||||
c.Fs.Destination.RemoveAll(toRemove)
|
||||
} else if err == nil {
|
||||
// If file still exists, sync it
|
||||
logger.Println("Syncing", relPath, "to", publishDir)
|
||||
|
@ -910,7 +920,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
// force refresh when more than one file
|
||||
if len(staticEvents) > 0 {
|
||||
for _, ev := range staticEvents {
|
||||
path, _ := helpers.MakeStaticPathRelative(ev.Name)
|
||||
path, _ := pathSpec.MakeStaticPathRelative(ev.Name)
|
||||
livereload.RefreshPath(path)
|
||||
}
|
||||
|
||||
|
@ -925,7 +935,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
const layout = "2006-01-02 15:04 -0700"
|
||||
jww.FEEDBACK.Println(time.Now().Format(layout))
|
||||
|
||||
rebuildSites(cfg, dynamicEvents)
|
||||
c.rebuildSites(dynamicEvents)
|
||||
|
||||
if !buildWatch && !viper.GetBool("disableLiveReload") {
|
||||
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
|
||||
|
@ -947,7 +957,7 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
http.HandleFunc("/livereload", livereload.Handler)
|
||||
}
|
||||
|
||||
go serve(port)
|
||||
go c.serve(port)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
@ -956,14 +966,13 @@ func newWatcher(cfg hugolib.DepsCfg, port int) error {
|
|||
|
||||
// isThemeVsHugoVersionMismatch returns whether the current Hugo version is
|
||||
// less than the theme's min_version.
|
||||
func isThemeVsHugoVersionMismatch() (mismatch bool, requiredMinVersion string) {
|
||||
func isThemeVsHugoVersionMismatch(fs afero.Fs) (mismatch bool, requiredMinVersion string) {
|
||||
if !helpers.ThemeSet() {
|
||||
return
|
||||
}
|
||||
|
||||
themeDir := helpers.GetThemeDir()
|
||||
|
||||
fs := hugofs.Source()
|
||||
path := filepath.Join(themeDir, "theme.toml")
|
||||
|
||||
exists, err := helpers.Exists(path, fs)
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
|
@ -122,7 +123,7 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
|
|||
return convertJekyllPost(site, path, relPath, targetDir, draft)
|
||||
}
|
||||
|
||||
err = helpers.SymbolicWalk(hugofs.Os(), jekyllRoot, callback)
|
||||
err = helpers.SymbolicWalk(hugofs.Os, jekyllRoot, callback)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -137,7 +138,13 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
|
|||
|
||||
// TODO: Consider calling doNewSite() instead?
|
||||
func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) (*hugolib.Site, error) {
|
||||
fs := hugofs.Source()
|
||||
s, err := hugolib.NewSiteDefaultLang()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs := s.Fs.Source
|
||||
|
||||
if exists, _ := helpers.Exists(targetDir, fs); exists {
|
||||
if isDir, _ := helpers.IsDir(targetDir, fs); !isDir {
|
||||
return nil, errors.New("Target path \"" + targetDir + "\" already exists but not a directory")
|
||||
|
@ -150,7 +157,7 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) (*hugolib.Si
|
|||
}
|
||||
}
|
||||
|
||||
jekyllConfig := loadJekyllConfig(jekyllRoot)
|
||||
jekyllConfig := loadJekyllConfig(fs, jekyllRoot)
|
||||
|
||||
// Crude test to make sure at least one of _drafts/ and _posts/ exists
|
||||
// and is not empty.
|
||||
|
@ -177,16 +184,14 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) (*hugolib.Si
|
|||
mkdir(targetDir, "data")
|
||||
mkdir(targetDir, "themes")
|
||||
|
||||
createConfigFromJekyll(targetDir, "yaml", jekyllConfig)
|
||||
createConfigFromJekyll(fs, targetDir, "yaml", jekyllConfig)
|
||||
|
||||
copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"))
|
||||
site := hugolib.NewSiteDefaultLang()
|
||||
|
||||
return site, nil
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func loadJekyllConfig(jekyllRoot string) map[string]interface{} {
|
||||
fs := hugofs.Source()
|
||||
func loadJekyllConfig(fs afero.Fs, jekyllRoot string) map[string]interface{} {
|
||||
path := filepath.Join(jekyllRoot, "_config.yml")
|
||||
|
||||
exists, err := helpers.Exists(path, fs)
|
||||
|
@ -218,7 +223,7 @@ func loadJekyllConfig(jekyllRoot string) map[string]interface{} {
|
|||
return c.(map[string]interface{})
|
||||
}
|
||||
|
||||
func createConfigFromJekyll(inpath string, kind string, jekyllConfig map[string]interface{}) (err error) {
|
||||
func createConfigFromJekyll(fs afero.Fs, inpath string, kind string, jekyllConfig map[string]interface{}) (err error) {
|
||||
title := "My New Hugo Site"
|
||||
baseURL := "http://example.org/"
|
||||
|
||||
|
@ -251,7 +256,7 @@ func createConfigFromJekyll(inpath string, kind string, jekyllConfig map[string]
|
|||
return err
|
||||
}
|
||||
|
||||
err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), hugofs.Source())
|
||||
err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), fs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -16,15 +16,18 @@ package commands
|
|||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/create"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/hugolib"
|
||||
"github.com/spf13/hugo/parser"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
|
@ -84,7 +87,9 @@ as you see fit.`,
|
|||
|
||||
// NewContent adds new content to a Hugo site.
|
||||
func NewContent(cmd *cobra.Command, args []string) error {
|
||||
if _, err := InitializeConfig(); err != nil {
|
||||
cfg, err := InitializeConfig()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -110,10 +115,16 @@ func NewContent(cmd *cobra.Command, args []string) error {
|
|||
kind = contentType
|
||||
}
|
||||
|
||||
return create.NewContent(hugofs.Source(), kind, createpath)
|
||||
s, err := hugolib.NewSite(cfg)
|
||||
|
||||
if err != nil {
|
||||
return newSystemError(err)
|
||||
}
|
||||
|
||||
return create.NewContent(s, kind, createpath)
|
||||
}
|
||||
|
||||
func doNewSite(basepath string, force bool) error {
|
||||
func doNewSite(fs *hugofs.Fs, basepath string, force bool) error {
|
||||
dirs := []string{
|
||||
filepath.Join(basepath, "layouts"),
|
||||
filepath.Join(basepath, "content"),
|
||||
|
@ -123,12 +134,12 @@ func doNewSite(basepath string, force bool) error {
|
|||
filepath.Join(basepath, "themes"),
|
||||
}
|
||||
|
||||
if exists, _ := helpers.Exists(basepath, hugofs.Source()); exists {
|
||||
if isDir, _ := helpers.IsDir(basepath, hugofs.Source()); !isDir {
|
||||
if exists, _ := helpers.Exists(basepath, fs.Source); exists {
|
||||
if isDir, _ := helpers.IsDir(basepath, fs.Source); !isDir {
|
||||
return errors.New(basepath + " already exists but not a directory")
|
||||
}
|
||||
|
||||
isEmpty, _ := helpers.IsEmpty(basepath, hugofs.Source())
|
||||
isEmpty, _ := helpers.IsEmpty(basepath, fs.Source)
|
||||
|
||||
switch {
|
||||
case !isEmpty && !force:
|
||||
|
@ -137,7 +148,7 @@ func doNewSite(basepath string, force bool) error {
|
|||
case !isEmpty && force:
|
||||
all := append(dirs, filepath.Join(basepath, "config."+configFormat))
|
||||
for _, path := range all {
|
||||
if exists, _ := helpers.Exists(path, hugofs.Source()); exists {
|
||||
if exists, _ := helpers.Exists(path, fs.Source); exists {
|
||||
return errors.New(path + " already exists")
|
||||
}
|
||||
}
|
||||
|
@ -145,10 +156,12 @@ func doNewSite(basepath string, force bool) error {
|
|||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
hugofs.Source().MkdirAll(dir, 0777)
|
||||
if err := fs.Source.MkdirAll(dir, 0777); err != nil {
|
||||
return fmt.Errorf("Failed to create dir: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
createConfig(basepath, configFormat)
|
||||
createConfig(fs, basepath, configFormat)
|
||||
|
||||
jww.FEEDBACK.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", basepath)
|
||||
jww.FEEDBACK.Println(nextStepsText())
|
||||
|
@ -190,12 +203,14 @@ func NewSite(cmd *cobra.Command, args []string) error {
|
|||
|
||||
forceNew, _ := cmd.Flags().GetBool("force")
|
||||
|
||||
return doNewSite(createpath, forceNew)
|
||||
return doNewSite(hugofs.NewDefault(), createpath, forceNew)
|
||||
}
|
||||
|
||||
// NewTheme creates a new Hugo theme.
|
||||
func NewTheme(cmd *cobra.Command, args []string) error {
|
||||
if _, err := InitializeConfig(); err != nil {
|
||||
cfg, err := InitializeConfig()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -207,26 +222,26 @@ func NewTheme(cmd *cobra.Command, args []string) error {
|
|||
createpath := helpers.AbsPathify(filepath.Join(viper.GetString("themesDir"), args[0]))
|
||||
jww.INFO.Println("creating theme at", createpath)
|
||||
|
||||
if x, _ := helpers.Exists(createpath, hugofs.Source()); x {
|
||||
if x, _ := helpers.Exists(createpath, cfg.Fs.Source); x {
|
||||
return newUserError(createpath, "already exists")
|
||||
}
|
||||
|
||||
mkdir(createpath, "layouts", "_default")
|
||||
mkdir(createpath, "layouts", "partials")
|
||||
|
||||
touchFile(createpath, "layouts", "index.html")
|
||||
touchFile(createpath, "layouts", "404.html")
|
||||
touchFile(createpath, "layouts", "_default", "list.html")
|
||||
touchFile(createpath, "layouts", "_default", "single.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "index.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "404.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "list.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "_default", "single.html")
|
||||
|
||||
touchFile(createpath, "layouts", "partials", "header.html")
|
||||
touchFile(createpath, "layouts", "partials", "footer.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "header.html")
|
||||
touchFile(cfg.Fs.Source, createpath, "layouts", "partials", "footer.html")
|
||||
|
||||
mkdir(createpath, "archetypes")
|
||||
|
||||
archDefault := []byte("+++\n+++\n")
|
||||
|
||||
err := helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), hugofs.Source())
|
||||
err = helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), cfg.Fs.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -256,12 +271,12 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
`)
|
||||
|
||||
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), hugofs.Source())
|
||||
err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), cfg.Fs.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createThemeMD(createpath)
|
||||
createThemeMD(cfg.Fs, createpath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -275,16 +290,16 @@ func mkdir(x ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
func touchFile(x ...string) {
|
||||
func touchFile(fs afero.Fs, x ...string) {
|
||||
inpath := filepath.Join(x...)
|
||||
mkdir(filepath.Dir(inpath))
|
||||
err := helpers.WriteToDisk(inpath, bytes.NewReader([]byte{}), hugofs.Source())
|
||||
err := helpers.WriteToDisk(inpath, bytes.NewReader([]byte{}), fs)
|
||||
if err != nil {
|
||||
jww.FATAL.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createThemeMD(inpath string) (err error) {
|
||||
func createThemeMD(fs *hugofs.Fs, inpath string) (err error) {
|
||||
|
||||
by := []byte(`# theme.toml template for a Hugo theme
|
||||
# See https://github.com/spf13/hugoThemes#themetoml for an example
|
||||
|
@ -309,7 +324,7 @@ min_version = 0.18
|
|||
repo = ""
|
||||
`)
|
||||
|
||||
err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), hugofs.Source())
|
||||
err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), fs.Source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -320,7 +335,7 @@ min_version = 0.18
|
|||
func newContentPathSection(path string) (string, string) {
|
||||
// Forward slashes is used in all examples. Convert if needed.
|
||||
// Issue #1133
|
||||
createpath := strings.Replace(path, "/", helpers.FilePathSeparator, -1)
|
||||
createpath := filepath.FromSlash(path)
|
||||
var section string
|
||||
// assume the first directory is the section (kind)
|
||||
if strings.Contains(createpath[1:], helpers.FilePathSeparator) {
|
||||
|
@ -330,7 +345,7 @@ func newContentPathSection(path string) (string, string) {
|
|||
return createpath, section
|
||||
}
|
||||
|
||||
func createConfig(inpath string, kind string) (err error) {
|
||||
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
|
||||
in := map[string]interface{}{
|
||||
"baseURL": "http://example.org/",
|
||||
"title": "My New Hugo Site",
|
||||
|
@ -343,7 +358,7 @@ func createConfig(inpath string, kind string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), hugofs.Source())
|
||||
err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), fs.Source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Issue #1133
|
||||
|
@ -29,7 +29,8 @@ func TestNewContentPathSectionWithForwardSlashes(t *testing.T) {
|
|||
assert.Equal(t, "post", s)
|
||||
}
|
||||
|
||||
func checkNewSiteInited(basepath string, t *testing.T) {
|
||||
func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
|
||||
|
||||
paths := []string{
|
||||
filepath.Join(basepath, "layouts"),
|
||||
filepath.Join(basepath, "content"),
|
||||
|
@ -40,63 +41,70 @@ func checkNewSiteInited(basepath string, t *testing.T) {
|
|||
}
|
||||
|
||||
for _, path := range paths {
|
||||
_, err := hugofs.Source().Stat(path)
|
||||
assert.Nil(t, err)
|
||||
_, err := fs.Source.Stat(path)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoNewSite(t *testing.T) {
|
||||
basepath := filepath.Join(os.TempDir(), "blog")
|
||||
hugofs.InitMemFs()
|
||||
err := doNewSite(basepath, false)
|
||||
assert.Nil(t, err)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
checkNewSiteInited(basepath, t)
|
||||
require.NoError(t, doNewSite(fs, basepath, false))
|
||||
|
||||
checkNewSiteInited(fs, basepath, t)
|
||||
}
|
||||
|
||||
func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
|
||||
basepath := filepath.Join(os.TempDir(), "blog")
|
||||
hugofs.InitMemFs()
|
||||
hugofs.Source().MkdirAll(basepath, 777)
|
||||
err := doNewSite(basepath, false)
|
||||
assert.Nil(t, err)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
|
||||
require.NoError(t, doNewSite(fs, basepath, false))
|
||||
}
|
||||
|
||||
func TestDoNewSite_error_base_exists(t *testing.T) {
|
||||
basepath := filepath.Join(os.TempDir(), "blog")
|
||||
hugofs.InitMemFs()
|
||||
hugofs.Source().MkdirAll(basepath, 777)
|
||||
hugofs.Source().Create(filepath.Join(basepath, "foo"))
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
_, err := fs.Source.Create(filepath.Join(basepath, "foo"))
|
||||
require.NoError(t, err)
|
||||
// Since the directory already exists and isn't empty, expect an error
|
||||
err := doNewSite(basepath, false)
|
||||
assert.NotNil(t, err)
|
||||
require.Error(t, doNewSite(fs, basepath, false))
|
||||
|
||||
}
|
||||
|
||||
func TestDoNewSite_force_empty_dir(t *testing.T) {
|
||||
basepath := filepath.Join(os.TempDir(), "blog")
|
||||
hugofs.InitMemFs()
|
||||
hugofs.Source().MkdirAll(basepath, 777)
|
||||
err := doNewSite(basepath, true)
|
||||
assert.Nil(t, err)
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
checkNewSiteInited(basepath, t)
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
|
||||
require.NoError(t, doNewSite(fs, basepath, true))
|
||||
|
||||
checkNewSiteInited(fs, basepath, t)
|
||||
}
|
||||
|
||||
func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
|
||||
basepath := filepath.Join(os.TempDir(), "blog")
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
contentPath := filepath.Join(basepath, "content")
|
||||
hugofs.InitMemFs()
|
||||
hugofs.Source().MkdirAll(contentPath, 777)
|
||||
err := doNewSite(basepath, true)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
require.NoError(t, fs.Source.MkdirAll(contentPath, 777))
|
||||
require.Error(t, doNewSite(fs, basepath, true))
|
||||
}
|
||||
|
||||
func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
|
||||
basepath := filepath.Join(os.TempDir(), "blog")
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
configPath := filepath.Join(basepath, "config.toml")
|
||||
hugofs.InitMemFs()
|
||||
hugofs.Source().MkdirAll(basepath, 777)
|
||||
hugofs.Source().Create(configPath)
|
||||
err := doNewSite(basepath, true)
|
||||
assert.NotNil(t, err)
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
_, err := fs.Source.Create(configPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Error(t, doNewSite(fs, basepath, true))
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
@ -109,6 +108,8 @@ func server(cmd *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
c := commandeer{cfg}
|
||||
|
||||
if flagChanged(cmd.Flags(), "disableLiveReload") {
|
||||
viper.Set("disableLiveReload", disableLiveReload)
|
||||
}
|
||||
|
@ -119,7 +120,7 @@ func server(cmd *cobra.Command, args []string) error {
|
|||
|
||||
if viper.GetBool("watch") {
|
||||
serverWatch = true
|
||||
watchConfig(cfg)
|
||||
c.watchConfig()
|
||||
}
|
||||
|
||||
l, err := net.Listen("tcp", net.JoinHostPort(serverInterface, strconv.Itoa(serverPort)))
|
||||
|
@ -157,18 +158,18 @@ func server(cmd *cobra.Command, args []string) error {
|
|||
|
||||
// Hugo writes the output to memory instead of the disk
|
||||
if !renderToDisk {
|
||||
hugofs.SetDestination(new(afero.MemMapFs))
|
||||
cfg.Fs.Destination = new(afero.MemMapFs)
|
||||
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
||||
viper.Set("publishDir", "/")
|
||||
}
|
||||
|
||||
if err := build(cfg, serverWatch); err != nil {
|
||||
if err := c.build(serverWatch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch runs its own server as part of the routine
|
||||
if serverWatch {
|
||||
watchDirs := getDirList()
|
||||
watchDirs := c.getDirList()
|
||||
baseWatchDir := viper.GetString("workingDir")
|
||||
for i, dir := range watchDirs {
|
||||
watchDirs[i], _ = helpers.GetRelativePath(dir, baseWatchDir)
|
||||
|
@ -177,26 +178,26 @@ func server(cmd *cobra.Command, args []string) error {
|
|||
rootWatchDirs := strings.Join(helpers.UniqueStrings(helpers.ExtractRootPaths(watchDirs)), ",")
|
||||
|
||||
jww.FEEDBACK.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
|
||||
err := newWatcher(cfg, serverPort)
|
||||
err := c.newWatcher(serverPort)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
serve(serverPort)
|
||||
c.serve(serverPort)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func serve(port int) {
|
||||
func (c commandeer) serve(port int) {
|
||||
if renderToDisk {
|
||||
jww.FEEDBACK.Println("Serving pages from " + helpers.AbsPathify(viper.GetString("publishDir")))
|
||||
} else {
|
||||
jww.FEEDBACK.Println("Serving pages from memory")
|
||||
}
|
||||
|
||||
httpFs := afero.NewHttpFs(hugofs.Destination())
|
||||
httpFs := afero.NewHttpFs(c.Fs.Destination)
|
||||
fs := filesOnlyFs{httpFs.Dir(helpers.AbsPathify(viper.GetString("publishDir")))}
|
||||
fileserver := http.FileServer(fs)
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/parser"
|
||||
)
|
||||
|
||||
|
@ -37,7 +36,9 @@ If the content's draft status is 'False', nothing is done.`,
|
|||
// to false and setting its publish date to now. If the specified content is
|
||||
// not a draft, it will log an error.
|
||||
func Undraft(cmd *cobra.Command, args []string) error {
|
||||
if _, err := InitializeConfig(); err != nil {
|
||||
cfg, err := InitializeConfig()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -47,7 +48,7 @@ func Undraft(cmd *cobra.Command, args []string) error {
|
|||
|
||||
location := args[0]
|
||||
// open the file
|
||||
f, err := hugofs.Source().Open(location)
|
||||
f, err := cfg.Fs.Source.Open(location)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -64,7 +65,7 @@ func Undraft(cmd *cobra.Command, args []string) error {
|
|||
return newSystemErrorF("an error occurred while undrafting %q: %s", location, err)
|
||||
}
|
||||
|
||||
f, err = hugofs.Source().OpenFile(location, os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
f, err = cfg.Fs.Source.OpenFile(location, os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return newSystemErrorF("%q not be undrafted due to error opening file to save changes: %q\n", location, err)
|
||||
}
|
||||
|
|
|
@ -34,15 +34,15 @@ import (
|
|||
|
||||
// NewContent creates a new content file in the content directory based upon the
|
||||
// given kind, which is used to lookup an archetype.
|
||||
func NewContent(fs afero.Fs, kind, name string) (err error) {
|
||||
func NewContent(s *hugolib.Site, kind, name string) (err error) {
|
||||
jww.INFO.Println("attempting to create ", name, "of", kind)
|
||||
|
||||
location := FindArchetype(fs, kind)
|
||||
location := FindArchetype(s.Fs.Source, kind)
|
||||
|
||||
var by []byte
|
||||
|
||||
if location != "" {
|
||||
by, err = afero.ReadFile(fs, location)
|
||||
by, err = afero.ReadFile(s.Fs.Source, location)
|
||||
if err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
}
|
||||
|
@ -62,9 +62,7 @@ func NewContent(fs afero.Fs, kind, name string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
site := hugolib.NewSiteDefaultLang()
|
||||
|
||||
page, err := site.NewPage(name)
|
||||
page, err := s.NewPage(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -19,23 +19,22 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugolib"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/hugo/create"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewContent(t *testing.T) {
|
||||
initViper()
|
||||
|
||||
err := initFs()
|
||||
if err != nil {
|
||||
t.Fatalf("initialization error: %s", err)
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
kind string
|
||||
path string
|
||||
|
@ -48,15 +47,15 @@ func TestNewContent(t *testing.T) {
|
|||
{"product", "product/sample-4.md", []string{`title = "sample 4"`}}, // empty archetype front matter
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
err = create.NewContent(hugofs.Source(), c.kind, c.path)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] NewContent: %s", i, err)
|
||||
}
|
||||
for _, c := range cases {
|
||||
s, err := hugolib.NewEnglishSite()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, initFs(s.Fs))
|
||||
|
||||
require.NoError(t, create.NewContent(s, c.kind, c.path))
|
||||
|
||||
fname := filepath.Join("content", filepath.FromSlash(c.path))
|
||||
content := readFileFromFs(t, hugofs.Source(), fname)
|
||||
|
||||
content := readFileFromFs(t, s.Fs.Source, fname)
|
||||
for i, v := range c.expected {
|
||||
found := strings.Contains(content, v)
|
||||
if !found {
|
||||
|
@ -72,11 +71,11 @@ func initViper() {
|
|||
viper.Set("archetypeDir", "archetypes")
|
||||
viper.Set("contentDir", "content")
|
||||
viper.Set("themesDir", "themes")
|
||||
viper.Set("layoutDir", "layouts")
|
||||
viper.Set("theme", "sample")
|
||||
}
|
||||
|
||||
func initFs() error {
|
||||
hugofs.InitMemFs()
|
||||
func initFs(fs *hugofs.Fs) error {
|
||||
perm := os.FileMode(0755)
|
||||
var err error
|
||||
|
||||
|
@ -87,7 +86,7 @@ func initFs() error {
|
|||
filepath.Join("themes", "sample", "archetypes"),
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
err = hugofs.Source().Mkdir(dir, perm)
|
||||
err = fs.Source.Mkdir(dir, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -111,7 +110,7 @@ func initFs() error {
|
|||
content: "+++\ndate =\"\"\ntitle = \"Empty Date Arch title\"\ntest = \"test1\"\n+++\n",
|
||||
},
|
||||
} {
|
||||
f, err := hugofs.Source().Create(v.path)
|
||||
f, err := fs.Source.Create(v.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package deps
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
// Deps holds dependencies used by many.
|
||||
// There will be normally be only one instance of deps in play
|
||||
// at a given time, i.e. one per Site built.
|
||||
type Deps struct {
|
||||
// The logger to use.
|
||||
Log *jww.Notepad `json:"-"`
|
||||
|
||||
// The templates to use.
|
||||
Tmpl tplapi.Template `json:"-"`
|
||||
|
||||
// The file systems to use.
|
||||
Fs *hugofs.Fs `json:"-"`
|
||||
|
||||
// The PathSpec to use
|
||||
*helpers.PathSpec `json:"-"`
|
||||
|
||||
templateProvider TemplateProvider
|
||||
WithTemplate func(templ tplapi.Template) error
|
||||
|
||||
// TODO(bep) globals next in line: Viper
|
||||
|
||||
}
|
||||
|
||||
// Used to create and refresh, and clone the template.
|
||||
type TemplateProvider interface {
|
||||
Update(deps *Deps) error
|
||||
Clone(deps *Deps) error
|
||||
}
|
||||
|
||||
func (d *Deps) LoadTemplates() error {
|
||||
if err := d.templateProvider.Update(d); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Tmpl.PrintErrors()
|
||||
return nil
|
||||
}
|
||||
|
||||
func New(cfg DepsCfg) *Deps {
|
||||
var (
|
||||
logger = cfg.Logger
|
||||
fs = cfg.Fs
|
||||
)
|
||||
|
||||
if cfg.TemplateProvider == nil {
|
||||
panic("Must have a TemplateProvider")
|
||||
}
|
||||
|
||||
if cfg.Language == nil {
|
||||
panic("Must have a Language")
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
|
||||
if fs == nil {
|
||||
// Default to the most used file systems.
|
||||
fs = hugofs.NewMem()
|
||||
}
|
||||
|
||||
d := &Deps{
|
||||
Fs: fs,
|
||||
Log: logger,
|
||||
templateProvider: cfg.TemplateProvider,
|
||||
WithTemplate: cfg.WithTemplate,
|
||||
PathSpec: helpers.NewPathSpec(fs, cfg.Language),
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// ForLanguage creates a copy of the Deps with the language dependent
|
||||
// parts switched out.
|
||||
func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) {
|
||||
|
||||
d.PathSpec = helpers.NewPathSpec(d.Fs, l)
|
||||
if err := d.templateProvider.Clone(&d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
|
||||
}
|
||||
|
||||
// DepsCfg contains configuration options that can be used to configure Hugo
|
||||
// on a global level, i.e. logging etc.
|
||||
// Nil values will be given default values.
|
||||
type DepsCfg struct {
|
||||
|
||||
// The Logger to use.
|
||||
Logger *jww.Notepad
|
||||
|
||||
// The file systems to use
|
||||
Fs *hugofs.Fs
|
||||
|
||||
// The language to use.
|
||||
Language *helpers.Language
|
||||
|
||||
// Template handling.
|
||||
TemplateProvider TemplateProvider
|
||||
WithTemplate func(templ tplapi.Template) error
|
||||
}
|
|
@ -29,7 +29,6 @@ import (
|
|||
// TODO(bep) Get rid of these.
|
||||
var (
|
||||
currentConfigProvider ConfigProvider
|
||||
currentPathSpec *PathSpec
|
||||
)
|
||||
|
||||
// ConfigProvider provides the configuration settings for Hugo.
|
||||
|
@ -52,24 +51,13 @@ func Config() ConfigProvider {
|
|||
return viper.Get("currentContentLanguage").(ConfigProvider)
|
||||
}
|
||||
|
||||
// CurrentPathSpec returns the current PathSpec.
|
||||
// If it is not set, a new will be created based in the currently active Hugo config.
|
||||
func CurrentPathSpec() *PathSpec {
|
||||
if currentPathSpec != nil {
|
||||
return currentPathSpec
|
||||
}
|
||||
// Some tests rely on this. We will fix that, eventually.
|
||||
return NewPathSpecFromConfig(Config())
|
||||
}
|
||||
|
||||
// InitConfigProviderForCurrentContentLanguage does what it says.
|
||||
func InitConfigProviderForCurrentContentLanguage() {
|
||||
currentConfigProvider = viper.Get("CurrentContentLanguage").(ConfigProvider)
|
||||
currentPathSpec = NewPathSpecFromConfig(currentConfigProvider)
|
||||
}
|
||||
|
||||
// ResetConfigProvider is used in tests.
|
||||
func ResetConfigProvider() {
|
||||
currentConfigProvider = nil
|
||||
currentPathSpec = nil
|
||||
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@ import (
|
|||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/text/transform"
|
||||
|
@ -196,29 +194,29 @@ func GetRelativeThemeDir() string {
|
|||
|
||||
// GetThemeStaticDirPath returns the theme's static dir path if theme is set.
|
||||
// If theme is set and the static dir doesn't exist, an error is returned.
|
||||
func GetThemeStaticDirPath() (string, error) {
|
||||
return getThemeDirPath("static")
|
||||
func (p *PathSpec) GetThemeStaticDirPath() (string, error) {
|
||||
return p.getThemeDirPath("static")
|
||||
}
|
||||
|
||||
// GetThemeDataDirPath returns the theme's data dir path if theme is set.
|
||||
// If theme is set and the data dir doesn't exist, an error is returned.
|
||||
func GetThemeDataDirPath() (string, error) {
|
||||
return getThemeDirPath("data")
|
||||
func (p *PathSpec) GetThemeDataDirPath() (string, error) {
|
||||
return p.getThemeDirPath("data")
|
||||
}
|
||||
|
||||
// GetThemeI18nDirPath returns the theme's i18n dir path if theme is set.
|
||||
// If theme is set and the i18n dir doesn't exist, an error is returned.
|
||||
func GetThemeI18nDirPath() (string, error) {
|
||||
return getThemeDirPath("i18n")
|
||||
func (p *PathSpec) GetThemeI18nDirPath() (string, error) {
|
||||
return p.getThemeDirPath("i18n")
|
||||
}
|
||||
|
||||
func getThemeDirPath(path string) (string, error) {
|
||||
func (p *PathSpec) getThemeDirPath(path string) (string, error) {
|
||||
if !ThemeSet() {
|
||||
return "", ErrThemeUndefined
|
||||
}
|
||||
|
||||
themeDir := filepath.Join(GetThemeDir(), path)
|
||||
if _, err := hugofs.Source().Stat(themeDir); os.IsNotExist(err) {
|
||||
if _, err := p.fs.Source.Stat(themeDir); os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("Unable to find %s directory for theme %s in %s", path, viper.GetString("theme"), themeDir)
|
||||
}
|
||||
|
||||
|
@ -228,17 +226,17 @@ func getThemeDirPath(path string) (string, error) {
|
|||
// GetThemesDirPath gets the static files directory of the current theme, if there is one.
|
||||
// Ignores underlying errors.
|
||||
// TODO(bep) Candidate for deprecation?
|
||||
func GetThemesDirPath() string {
|
||||
dir, _ := getThemeDirPath("static")
|
||||
func (p *PathSpec) GetThemesDirPath() string {
|
||||
dir, _ := p.getThemeDirPath("static")
|
||||
return dir
|
||||
}
|
||||
|
||||
// MakeStaticPathRelative makes a relative path to the static files directory.
|
||||
// It does so by taking either the project's static path or the theme's static
|
||||
// path into consideration.
|
||||
func MakeStaticPathRelative(inPath string) (string, error) {
|
||||
func (p *PathSpec) MakeStaticPathRelative(inPath string) (string, error) {
|
||||
staticDir := GetStaticDirPath()
|
||||
themeStaticDir := GetThemesDirPath()
|
||||
themeStaticDir := p.GetThemesDirPath()
|
||||
|
||||
return makePathRelative(inPath, staticDir, themeStaticDir)
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -64,7 +65,8 @@ func TestMakePath(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
viper.Set("removePathAccents", test.removeAccents)
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
output := p.MakePath(test.input)
|
||||
if output != test.expected {
|
||||
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
|
||||
|
@ -77,7 +79,7 @@ func TestMakePathSanitized(t *testing.T) {
|
|||
defer viper.Reset()
|
||||
initCommonTestConfig()
|
||||
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
tests := []struct {
|
||||
input string
|
||||
|
@ -105,7 +107,7 @@ func TestMakePathSanitizedDisablePathToLower(t *testing.T) {
|
|||
|
||||
initCommonTestConfig()
|
||||
viper.Set("disablePathToLower", true)
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
tests := []struct {
|
||||
input string
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
)
|
||||
|
||||
// PathSpec holds methods that decides how paths in URLs and files in Hugo should look like.
|
||||
type PathSpec struct {
|
||||
disablePathToLower bool
|
||||
|
@ -33,11 +39,27 @@ type PathSpec struct {
|
|||
defaultContentLanguageInSubdir bool
|
||||
defaultContentLanguage string
|
||||
multilingual bool
|
||||
|
||||
// The file systems to use
|
||||
fs *hugofs.Fs
|
||||
}
|
||||
|
||||
// NewPathSpecFromConfig creats a new PathSpec from the given ConfigProvider.
|
||||
func NewPathSpecFromConfig(config ConfigProvider) *PathSpec {
|
||||
func (p PathSpec) String() string {
|
||||
return fmt.Sprintf("PathSpec, language %q, prefix %q, multilingual: %T", p.currentContentLanguage.Lang, p.getLanguagePrefix(), p.multilingual)
|
||||
}
|
||||
|
||||
// NewPathSpec creats a new PathSpec from the given filesystems and ConfigProvider.
|
||||
func NewPathSpec(fs *hugofs.Fs, config ConfigProvider) *PathSpec {
|
||||
|
||||
currCl, ok := config.Get("currentContentLanguage").(*Language)
|
||||
|
||||
if !ok {
|
||||
// TODO(bep) globals
|
||||
currCl = NewLanguage("en")
|
||||
}
|
||||
|
||||
return &PathSpec{
|
||||
fs: fs,
|
||||
disablePathToLower: config.GetBool("disablePathToLower"),
|
||||
removePathAccents: config.GetBool("removePathAccents"),
|
||||
uglyURLs: config.GetBool("uglyURLs"),
|
||||
|
@ -45,7 +67,7 @@ func NewPathSpecFromConfig(config ConfigProvider) *PathSpec {
|
|||
multilingual: config.GetBool("multilingual"),
|
||||
defaultContentLanguageInSubdir: config.GetBool("defaultContentLanguageInSubdir"),
|
||||
defaultContentLanguage: config.GetString("defaultContentLanguage"),
|
||||
currentContentLanguage: config.Get("currentContentLanguage").(*Language),
|
||||
currentContentLanguage: currCl,
|
||||
paginatePath: config.GetString("paginatePath"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ package helpers
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -31,15 +33,15 @@ func TestNewPathSpecFromConfig(t *testing.T) {
|
|||
viper.Set("canonifyURLs", true)
|
||||
viper.Set("paginatePath", "side")
|
||||
|
||||
pathSpec := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
require.True(t, pathSpec.canonifyURLs)
|
||||
require.True(t, pathSpec.defaultContentLanguageInSubdir)
|
||||
require.True(t, pathSpec.disablePathToLower)
|
||||
require.True(t, pathSpec.multilingual)
|
||||
require.True(t, pathSpec.removePathAccents)
|
||||
require.True(t, pathSpec.uglyURLs)
|
||||
require.Equal(t, "no", pathSpec.defaultContentLanguage)
|
||||
require.Equal(t, "no", pathSpec.currentContentLanguage.Lang)
|
||||
require.Equal(t, "side", pathSpec.paginatePath)
|
||||
require.True(t, p.canonifyURLs)
|
||||
require.True(t, p.defaultContentLanguageInSubdir)
|
||||
require.True(t, p.disablePathToLower)
|
||||
require.True(t, p.multilingual)
|
||||
require.True(t, p.removePathAccents)
|
||||
require.True(t, p.uglyURLs)
|
||||
require.Equal(t, "no", p.defaultContentLanguage)
|
||||
require.Equal(t, "no", p.currentContentLanguage.Lang)
|
||||
require.Equal(t, "side", p.paginatePath)
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ func Highlight(code, lang, optsStr string) string {
|
|||
io.WriteString(hash, lang)
|
||||
io.WriteString(hash, options)
|
||||
|
||||
fs := hugofs.Os()
|
||||
fs := hugofs.Os
|
||||
|
||||
ignoreCache := viper.GetBool("ignoreCache")
|
||||
cacheDir := viper.GetString("cacheDir")
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -26,7 +27,7 @@ import (
|
|||
func TestURLize(t *testing.T) {
|
||||
initCommonTestConfig()
|
||||
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
tests := []struct {
|
||||
input string
|
||||
|
@ -85,9 +86,11 @@ func doTestAbsURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool,
|
|||
{"http//foo", "http://base/path", "http://base/path/MULTIhttp/foo"},
|
||||
}
|
||||
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
for _, test := range tests {
|
||||
viper.Set("baseURL", test.baseURL)
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
|
||||
output := p.AbsURL(test.input, addLanguage)
|
||||
expected := test.expected
|
||||
if multilingual && addLanguage {
|
||||
|
@ -164,7 +167,7 @@ func doTestRelURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool,
|
|||
for i, test := range tests {
|
||||
viper.Set("baseURL", test.baseURL)
|
||||
viper.Set("canonifyURLs", test.canonify)
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
output := p.RelURL(test.input, addLanguage)
|
||||
|
||||
|
@ -247,9 +250,10 @@ func TestURLPrep(t *testing.T) {
|
|||
{false, "/section/name.html", "/section/name/"},
|
||||
{true, "/section/name/index.html", "/section/name.html"},
|
||||
}
|
||||
|
||||
for i, d := range data {
|
||||
viper.Set("uglyURLs", d.ugly)
|
||||
p := NewPathSpecFromConfig(viper.GetViper())
|
||||
p := NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
|
||||
output := p.URLPrep(d.input)
|
||||
if d.output != output {
|
||||
|
|
90
hugofs/fs.go
90
hugofs/fs.go
|
@ -19,76 +19,54 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
sourceFs afero.Fs
|
||||
destinationFs afero.Fs
|
||||
osFs afero.Fs = &afero.OsFs{}
|
||||
workingDirFs *afero.BasePathFs
|
||||
)
|
||||
// Os points to an Os Afero file system.
|
||||
var Os = &afero.OsFs{}
|
||||
|
||||
// Source returns Hugo's source file system.
|
||||
func Source() afero.Fs {
|
||||
return sourceFs
|
||||
type Fs struct {
|
||||
// Source is Hugo's source file system.
|
||||
Source afero.Fs
|
||||
|
||||
// Destination is Hugo's destionation file system.
|
||||
Destination afero.Fs
|
||||
|
||||
// Os is an OS file system.
|
||||
Os afero.Fs
|
||||
|
||||
// WorkingDir is a read-only file system
|
||||
// restricted to the project working dir.
|
||||
WorkingDir *afero.BasePathFs
|
||||
}
|
||||
|
||||
// SetSource sets Hugo's source file system
|
||||
// and re-initializes dependent file systems.
|
||||
func SetSource(fs afero.Fs) {
|
||||
sourceFs = fs
|
||||
initSourceDependencies()
|
||||
}
|
||||
|
||||
// Destination returns Hugo's destionation file system.
|
||||
func Destination() afero.Fs {
|
||||
return destinationFs
|
||||
}
|
||||
|
||||
// SetDestination sets Hugo's destionation file system
|
||||
func SetDestination(fs afero.Fs) {
|
||||
destinationFs = fs
|
||||
}
|
||||
|
||||
// Os returns an OS file system.
|
||||
func Os() afero.Fs {
|
||||
return osFs
|
||||
}
|
||||
|
||||
// WorkingDir returns a read-only file system
|
||||
// restricted to the project working dir.
|
||||
func WorkingDir() *afero.BasePathFs {
|
||||
return workingDirFs
|
||||
}
|
||||
|
||||
// InitDefaultFs initializes with the OS file system
|
||||
// NewDefault creates a new Fs with the OS file system
|
||||
// as source and destination file systems.
|
||||
func InitDefaultFs() {
|
||||
InitFs(&afero.OsFs{})
|
||||
func NewDefault() *Fs {
|
||||
fs := &afero.OsFs{}
|
||||
return newFs(fs)
|
||||
}
|
||||
|
||||
// InitMemFs initializes with a MemMapFs as source and destination file systems.
|
||||
// NewDefault creates a new Fs with the MemMapFs
|
||||
// as source and destination file systems.
|
||||
// Useful for testing.
|
||||
func InitMemFs() {
|
||||
InitFs(&afero.MemMapFs{})
|
||||
func NewMem() *Fs {
|
||||
fs := &afero.MemMapFs{}
|
||||
return newFs(fs)
|
||||
}
|
||||
|
||||
// InitFs initializes with the given file system
|
||||
// as source and destination file systems.
|
||||
func InitFs(fs afero.Fs) {
|
||||
sourceFs = fs
|
||||
destinationFs = fs
|
||||
|
||||
initSourceDependencies()
|
||||
func newFs(base afero.Fs) *Fs {
|
||||
return &Fs{
|
||||
Source: base,
|
||||
Destination: base,
|
||||
Os: &afero.OsFs{},
|
||||
WorkingDir: getWorkingDirFs(base),
|
||||
}
|
||||
}
|
||||
|
||||
func initSourceDependencies() {
|
||||
func getWorkingDirFs(base afero.Fs) *afero.BasePathFs {
|
||||
workingDir := viper.GetString("workingDir")
|
||||
|
||||
if workingDir != "" {
|
||||
workingDirFs = afero.NewBasePathFs(afero.NewReadOnlyFs(sourceFs), workingDir).(*afero.BasePathFs)
|
||||
return afero.NewBasePathFs(afero.NewReadOnlyFs(base), workingDir).(*afero.BasePathFs)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
InitDefaultFs()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -21,51 +21,35 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInitDefault(t *testing.T) {
|
||||
func TestNewDefault(t *testing.T) {
|
||||
viper.Reset()
|
||||
defer viper.Reset()
|
||||
|
||||
InitDefaultFs()
|
||||
f := NewDefault()
|
||||
|
||||
assert.NotNil(t, Source())
|
||||
assert.IsType(t, new(afero.OsFs), Source())
|
||||
assert.NotNil(t, Destination())
|
||||
assert.IsType(t, new(afero.OsFs), Destination())
|
||||
assert.NotNil(t, Os())
|
||||
assert.IsType(t, new(afero.OsFs), Os())
|
||||
assert.Nil(t, WorkingDir())
|
||||
assert.NotNil(t, f.Source)
|
||||
assert.IsType(t, new(afero.OsFs), f.Source)
|
||||
assert.NotNil(t, f.Destination)
|
||||
assert.IsType(t, new(afero.OsFs), f.Destination)
|
||||
assert.NotNil(t, f.Os)
|
||||
assert.IsType(t, new(afero.OsFs), f.Os)
|
||||
assert.Nil(t, f.WorkingDir)
|
||||
|
||||
assert.IsType(t, new(afero.OsFs), Os)
|
||||
}
|
||||
|
||||
func TestInitMemFs(t *testing.T) {
|
||||
func TestNewMem(t *testing.T) {
|
||||
viper.Reset()
|
||||
defer viper.Reset()
|
||||
|
||||
InitMemFs()
|
||||
f := NewMem()
|
||||
|
||||
assert.NotNil(t, Source())
|
||||
assert.IsType(t, new(afero.MemMapFs), Source())
|
||||
assert.NotNil(t, Destination())
|
||||
assert.IsType(t, new(afero.MemMapFs), Destination())
|
||||
assert.IsType(t, new(afero.OsFs), Os())
|
||||
assert.Nil(t, WorkingDir())
|
||||
}
|
||||
|
||||
func TestSetSource(t *testing.T) {
|
||||
|
||||
InitMemFs()
|
||||
|
||||
SetSource(new(afero.OsFs))
|
||||
assert.NotNil(t, Source())
|
||||
assert.IsType(t, new(afero.OsFs), Source())
|
||||
}
|
||||
|
||||
func TestSetDestination(t *testing.T) {
|
||||
|
||||
InitMemFs()
|
||||
|
||||
SetDestination(new(afero.OsFs))
|
||||
assert.NotNil(t, Destination())
|
||||
assert.IsType(t, new(afero.OsFs), Destination())
|
||||
assert.NotNil(t, f.Source)
|
||||
assert.IsType(t, new(afero.MemMapFs), f.Source)
|
||||
assert.NotNil(t, f.Destination)
|
||||
assert.IsType(t, new(afero.MemMapFs), f.Destination)
|
||||
assert.IsType(t, new(afero.OsFs), f.Os)
|
||||
assert.Nil(t, f.WorkingDir)
|
||||
}
|
||||
|
||||
func TestWorkingDir(t *testing.T) {
|
||||
|
@ -74,8 +58,8 @@ func TestWorkingDir(t *testing.T) {
|
|||
|
||||
viper.Set("workingDir", "/a/b/")
|
||||
|
||||
InitMemFs()
|
||||
f := NewMem()
|
||||
|
||||
assert.NotNil(t, WorkingDir())
|
||||
assert.IsType(t, new(afero.BasePathFs), WorkingDir())
|
||||
assert.NotNil(t, f.WorkingDir)
|
||||
assert.IsType(t, new(afero.BasePathFs), f.WorkingDir)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ package hugolib
|
|||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const pageWithAlias = `---
|
||||
|
@ -30,31 +34,37 @@ const aliasTemplate = "<html><body>ALIASTEMPLATE</body></html>"
|
|||
|
||||
func TestAlias(t *testing.T) {
|
||||
testCommonResetState()
|
||||
writeSource(t, filepath.Join("content", "page.md"), pageWithAlias)
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), basicTemplate)
|
||||
|
||||
if err := buildAndRenderSite(NewSiteDefaultLang()); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "page.md"), pageWithAlias)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), basicTemplate)
|
||||
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
// the real page
|
||||
assertFileContent(t, filepath.Join("public", "page", "index.html"), false, "For some moments the old man")
|
||||
assertFileContent(t, fs, filepath.Join("public", "page", "index.html"), false, "For some moments the old man")
|
||||
// the alias redirector
|
||||
assertFileContent(t, filepath.Join("public", "foo", "bar", "index.html"), false, "<meta http-equiv=\"refresh\" content=\"0; ")
|
||||
assertFileContent(t, fs, filepath.Join("public", "foo", "bar", "index.html"), false, "<meta http-equiv=\"refresh\" content=\"0; ")
|
||||
}
|
||||
|
||||
func TestAliasTemplate(t *testing.T) {
|
||||
testCommonResetState()
|
||||
writeSource(t, filepath.Join("content", "page.md"), pageWithAlias)
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), basicTemplate)
|
||||
writeSource(t, filepath.Join("layouts", "alias.html"), aliasTemplate)
|
||||
|
||||
if err := buildAndRenderSite(NewSiteDefaultLang()); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "page.md"), pageWithAlias)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), basicTemplate)
|
||||
writeSource(t, fs, filepath.Join("layouts", "alias.html"), aliasTemplate)
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, sites.Build(BuildCfg{}))
|
||||
|
||||
// the real page
|
||||
assertFileContent(t, filepath.Join("public", "page", "index.html"), false, "For some moments the old man")
|
||||
assertFileContent(t, fs, filepath.Join("public", "page", "index.html"), false, "For some moments the old man")
|
||||
// the alias redirector
|
||||
assertFileContent(t, filepath.Join("public", "foo", "bar", "index.html"), false, "ALIASTEMPLATE")
|
||||
assertFileContent(t, fs, filepath.Join("public", "foo", "bar", "index.html"), false, "ALIASTEMPLATE")
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -106,22 +111,22 @@ ColorS:
|
|||
`
|
||||
)
|
||||
|
||||
func caseMixingTestsWriteCommonSources(t *testing.T) {
|
||||
writeSource(t, filepath.Join("content", "sect1", "page1.md"), caseMixingPage1)
|
||||
writeSource(t, filepath.Join("content", "sect2", "page2.md"), caseMixingPage2)
|
||||
writeSource(t, filepath.Join("content", "sect1", "page1.en.md"), caseMixingPage1En)
|
||||
func caseMixingTestsWriteCommonSources(t *testing.T, fs *hugofs.Fs) {
|
||||
writeSource(t, fs, filepath.Join("content", "sect1", "page1.md"), caseMixingPage1)
|
||||
writeSource(t, fs, filepath.Join("content", "sect2", "page2.md"), caseMixingPage2)
|
||||
writeSource(t, fs, filepath.Join("content", "sect1", "page1.en.md"), caseMixingPage1En)
|
||||
|
||||
writeSource(t, "layouts/shortcodes/shortcode.html", `
|
||||
writeSource(t, fs, "layouts/shortcodes/shortcode.html", `
|
||||
Shortcode Page: {{ .Page.Params.COLOR }}|{{ .Page.Params.Colors.Blue }}
|
||||
Shortcode Site: {{ .Page.Site.Params.COLOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
||||
`)
|
||||
|
||||
writeSource(t, "layouts/partials/partial.html", `
|
||||
writeSource(t, fs, "layouts/partials/partial.html", `
|
||||
Partial Page: {{ .Params.COLOR }}|{{ .Params.Colors.Blue }}
|
||||
Partial Site: {{ .Site.Params.COLOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
||||
`)
|
||||
|
||||
writeSource(t, "config.toml", caseMixingSiteConfigTOML)
|
||||
writeSource(t, fs, "config.toml", caseMixingSiteConfigTOML)
|
||||
|
||||
}
|
||||
|
||||
|
@ -139,13 +144,21 @@ func TestCaseInsensitiveConfigurationVariations(t *testing.T) {
|
|||
// page frontmatter: regular fields, blackfriday config, param with nested map
|
||||
|
||||
testCommonResetState()
|
||||
caseMixingTestsWriteCommonSources(t)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", "baseof.html"), `
|
||||
depsCfg := newTestDepsConfig()
|
||||
viper.SetFs(depsCfg.Fs.Source)
|
||||
|
||||
caseMixingTestsWriteCommonSources(t, depsCfg.Fs)
|
||||
|
||||
if err := LoadGlobalConfig("", "config.toml"); err != nil {
|
||||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
||||
writeSource(t, depsCfg.Fs, filepath.Join("layouts", "_default", "baseof.html"), `
|
||||
Block Page Colors: {{ .Params.COLOR }}|{{ .Params.Colors.Blue }}
|
||||
{{ block "main" . }}default{{end}}`)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "sect2", "single.html"), `
|
||||
writeSource(t, depsCfg.Fs, filepath.Join("layouts", "sect2", "single.html"), `
|
||||
{{ define "main"}}
|
||||
Page Colors: {{ .Params.CoLOR }}|{{ .Params.Colors.Blue }}
|
||||
Site Colors: {{ .Site.Params.COlOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
||||
|
@ -154,7 +167,7 @@ Site Colors: {{ .Site.Params.COlOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
|||
{{ end }}
|
||||
`)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), `
|
||||
writeSource(t, depsCfg.Fs, filepath.Join("layouts", "_default", "single.html"), `
|
||||
Page Title: {{ .Title }}
|
||||
Site Title: {{ .Site.Title }}
|
||||
Site Lang Mood: {{ .Site.Language.Params.MOoD }}
|
||||
|
@ -164,11 +177,7 @@ Site Colors: {{ .Site.Params.COLOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
|||
{{ partial "partial.html" . }}
|
||||
`)
|
||||
|
||||
if err := LoadGlobalConfig("", "config.toml"); err != nil {
|
||||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(DepsCfg{})
|
||||
sites, err := NewHugoSitesFromConfiguration(depsCfg)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create sites: %s", err)
|
||||
|
@ -180,7 +189,7 @@ Site Colors: {{ .Site.Params.COLOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
|||
t.Fatalf("Failed to build sites: %s", err)
|
||||
}
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "nn", "sect1", "page1", "index.html"), true,
|
||||
assertFileContent(t, sites.Fs, filepath.Join("public", "nn", "sect1", "page1", "index.html"), true,
|
||||
"Page Colors: red|heavenly",
|
||||
"Site Colors: green|yellow",
|
||||
"Site Lang Mood: Happy",
|
||||
|
@ -193,7 +202,7 @@ Site Colors: {{ .Site.Params.COLOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
|||
"«Hi»", // angled quotes
|
||||
)
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "en", "sect1", "page1", "index.html"), true,
|
||||
assertFileContent(t, sites.Fs, filepath.Join("public", "en", "sect1", "page1", "index.html"), true,
|
||||
"Site Colors: Pink|golden",
|
||||
"Page Colors: black|bluesy",
|
||||
"Site Lang Mood: Thoughtful",
|
||||
|
@ -202,7 +211,7 @@ Site Colors: {{ .Site.Params.COLOR }}|{{ .Site.Params.COLORS.YELLOW }}
|
|||
"“Hi”",
|
||||
)
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "nn", "sect2", "page2", "index.html"), true,
|
||||
assertFileContent(t, sites.Fs, filepath.Join("public", "nn", "sect2", "page2", "index.html"), true,
|
||||
"Page Colors: black|sky",
|
||||
"Site Colors: green|yellow",
|
||||
"Shortcode Page: black|sky",
|
||||
|
@ -244,7 +253,15 @@ func TestCaseInsensitiveConfigurationForAllTemplateEngines(t *testing.T) {
|
|||
func doTestCaseInsensitiveConfigurationForTemplateEngine(t *testing.T, suffix string, templateFixer func(s string) string) {
|
||||
|
||||
testCommonResetState()
|
||||
caseMixingTestsWriteCommonSources(t)
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
viper.SetFs(fs.Source)
|
||||
|
||||
caseMixingTestsWriteCommonSources(t, fs)
|
||||
|
||||
if err := LoadGlobalConfig("", "config.toml"); err != nil {
|
||||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
||||
t.Log("Testing", suffix)
|
||||
|
||||
|
@ -261,13 +278,9 @@ p
|
|||
|
||||
t.Log(templ)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", fmt.Sprintf("single.%s", suffix)), templ)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", fmt.Sprintf("single.%s", suffix)), templ)
|
||||
|
||||
if err := LoadGlobalConfig("", "config.toml"); err != nil {
|
||||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(DepsCfg{})
|
||||
sites, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create sites: %s", err)
|
||||
|
@ -279,7 +292,7 @@ p
|
|||
t.Fatalf("Failed to build sites: %s", err)
|
||||
}
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "nn", "sect1", "page1", "index.html"), true,
|
||||
assertFileContent(t, sites.Fs, filepath.Join("public", "nn", "sect1", "page1", "index.html"), true,
|
||||
"Page Colors: red|heavenly",
|
||||
"Site Colors: green|yellow",
|
||||
"Shortcode Page: red|heavenly",
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -30,7 +31,10 @@ func TestLoadGlobalConfig(t *testing.T) {
|
|||
PaginatePath = "side"
|
||||
`
|
||||
|
||||
writeSource(t, "hugo.toml", configContent)
|
||||
fs := hugofs.NewMem()
|
||||
viper.SetFs(fs.Source)
|
||||
|
||||
writeSource(t, fs, "hugo.toml", configContent)
|
||||
|
||||
require.NoError(t, LoadGlobalConfig("", "hugo.toml"))
|
||||
assert.Equal(t, "side", helpers.Config().GetString("paginatePath"))
|
||||
|
|
|
@ -89,19 +89,16 @@ func TestDataDirUnknownFormat(t *testing.T) {
|
|||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("test.roml"), Content: []byte("boo")},
|
||||
}
|
||||
s := NewSiteDefaultLang()
|
||||
err := s.loadData([]source.Input{&source.InMemorySource{ByteSource: sources}})
|
||||
if err != nil {
|
||||
t.Fatalf("Should not return an error")
|
||||
}
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.loadData([]source.Input{&source.InMemorySource{ByteSource: sources}}))
|
||||
}
|
||||
|
||||
func doTestDataDir(t *testing.T, expected interface{}, sources []source.Input) {
|
||||
s := NewSiteDefaultLang()
|
||||
err := s.loadData(sources)
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading data: %s", err)
|
||||
}
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.loadData(sources))
|
||||
|
||||
if !reflect.DeepEqual(expected, s.Data) {
|
||||
t.Errorf("Expected structure\n%#v got\n%#v", expected, s.Data)
|
||||
}
|
||||
|
@ -109,21 +106,22 @@ func doTestDataDir(t *testing.T, expected interface{}, sources []source.Input) {
|
|||
|
||||
func TestDataFromShortcode(t *testing.T) {
|
||||
testCommonResetState()
|
||||
writeSource(t, "data/hugo.toml", "slogan = \"Hugo Rocks!\"")
|
||||
writeSource(t, "layouts/_default/single.html", `
|
||||
|
||||
cfg := newTestDepsConfig()
|
||||
|
||||
writeSource(t, cfg.Fs, "data/hugo.toml", "slogan = \"Hugo Rocks!\"")
|
||||
writeSource(t, cfg.Fs, "layouts/_default/single.html", `
|
||||
* Slogan from template: {{ .Site.Data.hugo.slogan }}
|
||||
* {{ .Content }}`)
|
||||
writeSource(t, "layouts/shortcodes/d.html", `{{ .Page.Site.Data.hugo.slogan }}`)
|
||||
writeSource(t, "content/c.md", `---
|
||||
writeSource(t, cfg.Fs, "layouts/shortcodes/d.html", `{{ .Page.Site.Data.hugo.slogan }}`)
|
||||
writeSource(t, cfg.Fs, "content/c.md", `---
|
||||
---
|
||||
Slogan from shortcode: {{< d >}}
|
||||
`)
|
||||
|
||||
h, err := newHugoSitesDefaultLanguage()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, h.Build(BuildCfg{}))
|
||||
buildSingleSite(t, cfg, BuildCfg{})
|
||||
|
||||
content := readSource(t, "public/c/index.html")
|
||||
content := readSource(t, cfg.Fs, "public/c/index.html")
|
||||
require.True(t, strings.Contains(content, "Slogan from template: Hugo Rocks!"), content)
|
||||
require.True(t, strings.Contains(content, "Slogan from shortcode: Hugo Rocks!"), content)
|
||||
|
||||
|
|
|
@ -27,9 +27,11 @@ import (
|
|||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/hugo/tpl"
|
||||
"github.com/spf13/hugo/deps"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -65,17 +67,17 @@ func doTestShortcodeCrossrefs(t *testing.T, relative bool) {
|
|||
path := filepath.FromSlash("blog/post.md")
|
||||
in := fmt.Sprintf(`{{< %s "%s" >}}`, refShortcode, path)
|
||||
|
||||
writeSource(t, "content/"+path, simplePageWithURL+": "+in)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, "content/"+path, simplePageWithURL+": "+in)
|
||||
|
||||
expected := fmt.Sprintf(`%s/simple/url/`, expectedBase)
|
||||
|
||||
sites, err := newHugoSitesDefaultLanguage()
|
||||
require.NoError(t, err)
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
require.NoError(t, sites.Build(BuildCfg{}))
|
||||
require.Len(t, sites.Sites[0].RegularPages, 1)
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
output := string(sites.Sites[0].RegularPages[0].Content)
|
||||
output := string(s.RegularPages[0].Content)
|
||||
|
||||
if !strings.Contains(output, expected) {
|
||||
t.Errorf("Got\n%q\nExpected\n%q", output, expected)
|
||||
|
@ -308,7 +310,7 @@ func TestShortcodeTweet(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tplapi.Template) error {
|
||||
templ.Funcs(tweetFuncMap)
|
||||
return nil
|
||||
})
|
||||
|
@ -361,7 +363,7 @@ func TestShortcodeInstagram(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tplapi.Template) error {
|
||||
templ.Funcs(instagramFuncMap)
|
||||
return nil
|
||||
})
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
|
||||
"github.com/bep/gitmap"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -36,7 +35,7 @@ func (h *HugoSites) assembleGitInfo() {
|
|||
|
||||
gitRepo, err := gitmap.Map(workingDir, "")
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Got error reading Git log: %s", err)
|
||||
h.Log.ERROR.Printf("Got error reading Git log: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -60,7 +59,7 @@ func (h *HugoSites) assembleGitInfo() {
|
|||
filename := path.Join(filepath.ToSlash(contentRoot), contentDir, filepath.ToSlash(p.Path()))
|
||||
g, ok := gitMap[filename]
|
||||
if !ok {
|
||||
jww.ERROR.Printf("Failed to find GitInfo for %q", filename)
|
||||
h.Log.ERROR.Printf("Failed to find GitInfo for %q", filename)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ type htmlHandler struct {
|
|||
|
||||
func (h htmlHandler) Extensions() []string { return []string{"html", "htm"} }
|
||||
|
||||
// TODO(bep) globals use p.s.t
|
||||
func (h htmlHandler) PageConvert(p *Page) HandledResult {
|
||||
if p.rendered {
|
||||
panic(fmt.Sprintf("Page %q already rendered, does not need conversion", p.BaseFileName()))
|
||||
|
|
|
@ -17,44 +17,36 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/target"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func TestDefaultHandler(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("sect/doc1.html"), Content: []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
|
||||
{Name: filepath.FromSlash("sect/doc2.html"), Content: []byte("<!doctype html><html><body>more content</body></html>")},
|
||||
{Name: filepath.FromSlash("sect/doc3.md"), Content: []byte("# doc3\n*some* content")},
|
||||
{Name: filepath.FromSlash("sect/doc4.md"), Content: []byte("---\ntitle: doc4\n---\n# doc4\n*some content*")},
|
||||
{Name: filepath.FromSlash("sect/doc3/img1.png"), Content: []byte("‰PNG <20><><EFBFBD> IHDR<44><52><EFBFBD><01><><EFBFBD><08><><EFBFBD><EFBFBD>:~›U<E280BA><55><EFBFBD> IDATWcø<0F><01>ZMoñ<6F><C3B1><EFBFBD><EFBFBD>IEND®B`‚")},
|
||||
{Name: filepath.FromSlash("sect/img2.gif"), Content: []byte("GIF89a<01><01>€<EFBFBD><E282AC>ÿÿÿ<C3BF><C3BF><EFBFBD>,<2C><><EFBFBD><EFBFBD><01><01><>D<01>;")},
|
||||
{Name: filepath.FromSlash("sect/img2.spf"), Content: []byte("****FAKE-FILETYPE****")},
|
||||
{Name: filepath.FromSlash("doc7.html"), Content: []byte("<html><body>doc7 content</body></html>")},
|
||||
{Name: filepath.FromSlash("sect/doc8.html"), Content: []byte("---\nmarkup: md\n---\n# title\nsome *content*")},
|
||||
}
|
||||
|
||||
viper.Set("defaultExtension", "html")
|
||||
viper.Set("verbose", true)
|
||||
viper.Set("uglyURLs", true)
|
||||
|
||||
s := &Site{
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: true, PublishDir: "public"}},
|
||||
Language: helpers.NewLanguage("en"),
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if err := buildAndRenderSite(s,
|
||||
"_default/single.html", "{{.Content}}",
|
||||
"head", "<head><script src=\"script.js\"></script></head>",
|
||||
"head_abs", "<head><script src=\"/script.js\"></script></head>"); err != nil {
|
||||
t.Fatalf("Failed to render site: %s", err)
|
||||
}
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/doc1.html"), "---\nmarkup: markdown\n---\n# title\nsome *content*")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/doc2.html"), "<!doctype html><html><body>more content</body></html>")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/doc3.md"), "# doc3\n*some* content")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/doc4.md"), "---\ntitle: doc4\n---\n# doc4\n*some content*")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/doc3/img1.png"), "‰PNG <20><><EFBFBD> IHDR<44><52><EFBFBD><01><><EFBFBD><08><><EFBFBD><EFBFBD>:~›U<E280BA><55><EFBFBD> IDATWcø<0F><01>ZMoñ<6F><C3B1><EFBFBD><EFBFBD>IEND®B`‚")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/img2.gif"), "GIF89a<01><01>€<EFBFBD><E282AC>ÿÿÿ<C3BF><C3BF><EFBFBD>,<2C><><EFBFBD><EFBFBD><01><01><>D<01>;")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/img2.spf"), "****FAKE-FILETYPE****")
|
||||
writeSource(t, fs, filepath.FromSlash("content/doc7.html"), "<html><body>doc7 content</body></html>")
|
||||
writeSource(t, fs, filepath.FromSlash("content/sect/doc8.html"), "---\nmarkup: md\n---\n# title\nsome *content*")
|
||||
|
||||
writeSource(t, fs, filepath.FromSlash("layouts/_default/single.html"), "{{.Content}}")
|
||||
writeSource(t, fs, filepath.FromSlash("head"), "<head><script src=\"script.js\"></script></head>")
|
||||
writeSource(t, fs, filepath.FromSlash("head_abs"), "<head><script src=\"/script.js\"></script></head")
|
||||
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
tests := []struct {
|
||||
doc string
|
||||
|
@ -71,7 +63,7 @@ func TestDefaultHandler(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
file, err := hugofs.Destination().Open(test.doc)
|
||||
file, err := fs.Destination.Open(test.doc)
|
||||
if err != nil {
|
||||
t.Fatalf("Did not find %s in target.", test.doc)
|
||||
}
|
||||
|
|
|
@ -14,20 +14,19 @@
|
|||
package hugolib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/tpl"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
)
|
||||
|
||||
// HugoSites represents the sites to build. Each site represents a language.
|
||||
|
@ -38,74 +37,77 @@ type HugoSites struct {
|
|||
|
||||
multilingual *Multilingual
|
||||
|
||||
*deps
|
||||
}
|
||||
|
||||
// deps holds dependencies used by many.
|
||||
// TODO(bep) globals a better name.
|
||||
// There will be normally be only one instance of deps in play
|
||||
// at a given time.
|
||||
type deps struct {
|
||||
// The logger to use.
|
||||
log *jww.Notepad
|
||||
|
||||
tmpl *tpl.GoHTMLTemplate
|
||||
|
||||
// TODO(bep) next in line: Viper, hugofs
|
||||
}
|
||||
|
||||
func (d *deps) refreshTemplates(withTemplate ...func(templ tpl.Template) error) {
|
||||
d.tmpl = tpl.New(d.log, withTemplate...)
|
||||
d.tmpl.PrintErrors() // TODO(bep) globals error handling
|
||||
}
|
||||
|
||||
func newDeps(cfg DepsCfg) *deps {
|
||||
logger := cfg.Logger
|
||||
|
||||
if logger == nil {
|
||||
// TODO(bep) globals default log level
|
||||
//logger = jww.NewNotepad(jww.LevelError, jww.LevelWarn, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
|
||||
return &deps{
|
||||
log: logger,
|
||||
tmpl: tpl.New(logger, cfg.WithTemplate...),
|
||||
}
|
||||
*deps.Deps
|
||||
}
|
||||
|
||||
// NewHugoSites creates a new collection of sites given the input sites, building
|
||||
// a language configuration based on those.
|
||||
func newHugoSites(cfg DepsCfg, sites ...*Site) (*HugoSites, error) {
|
||||
func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
|
||||
|
||||
if cfg.Language != nil {
|
||||
return nil, errors.New("Cannot provide Language in Cfg when sites are provided")
|
||||
}
|
||||
|
||||
langConfig, err := newMultiLingualFromSites(sites...)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var d *deps
|
||||
|
||||
if sites[0].deps != nil {
|
||||
d = sites[0].deps
|
||||
} else {
|
||||
d = newDeps(cfg)
|
||||
}
|
||||
|
||||
h := &HugoSites{
|
||||
deps: d,
|
||||
multilingual: langConfig,
|
||||
Sites: sites}
|
||||
|
||||
for _, s := range sites {
|
||||
s.owner = h
|
||||
s.deps = h.deps
|
||||
}
|
||||
|
||||
applyDepsIfNeeded(cfg, sites...)
|
||||
|
||||
h.Deps = sites[0].Deps
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func applyDepsIfNeeded(cfg deps.DepsCfg, sites ...*Site) error {
|
||||
|
||||
if cfg.TemplateProvider == nil {
|
||||
cfg.TemplateProvider = tpl.DefaultTemplateProvider
|
||||
}
|
||||
|
||||
var (
|
||||
d *deps.Deps
|
||||
err error
|
||||
)
|
||||
|
||||
for _, s := range sites {
|
||||
if s.Deps != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if d == nil {
|
||||
cfg.Language = s.Language
|
||||
cfg.WithTemplate = s.withSiteTemplates(cfg.WithTemplate)
|
||||
d = deps.New(cfg)
|
||||
if err := d.LoadTemplates(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
d, err = d.ForLanguage(s.Language)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
s.Deps = d
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewHugoSitesFromConfiguration creates HugoSites from the global Viper config.
|
||||
// TODO(bep) globals rename this when all the globals are gone.
|
||||
func NewHugoSitesFromConfiguration(cfg DepsCfg) (*HugoSites, error) {
|
||||
func NewHugoSitesFromConfiguration(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||
sites, err := createSitesFromConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -113,17 +115,42 @@ func NewHugoSitesFromConfiguration(cfg DepsCfg) (*HugoSites, error) {
|
|||
return newHugoSites(cfg, sites...)
|
||||
}
|
||||
|
||||
func createSitesFromConfig(cfg DepsCfg) ([]*Site, error) {
|
||||
deps := newDeps(cfg)
|
||||
return createSitesFromDeps(deps)
|
||||
func (s *Site) withSiteTemplates(withTemplates ...func(templ tplapi.Template) error) func(templ tplapi.Template) error {
|
||||
return func(templ tplapi.Template) error {
|
||||
templ.LoadTemplates(s.absLayoutDir())
|
||||
if s.hasTheme() {
|
||||
templ.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
|
||||
}
|
||||
|
||||
for _, wt := range withTemplates {
|
||||
if wt == nil {
|
||||
continue
|
||||
}
|
||||
if err := wt(templ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func createSitesFromDeps(deps *deps) ([]*Site, error) {
|
||||
var sites []*Site
|
||||
func createSitesFromConfig(cfg deps.DepsCfg) ([]*Site, error) {
|
||||
|
||||
var (
|
||||
sites []*Site
|
||||
)
|
||||
|
||||
multilingual := viper.GetStringMap("languages")
|
||||
|
||||
if len(multilingual) == 0 {
|
||||
sites = append(sites, newSite(helpers.NewDefaultLanguage(), deps))
|
||||
l := helpers.NewDefaultLanguage()
|
||||
cfg.Language = l
|
||||
s, err := newSite(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sites = append(sites, s)
|
||||
}
|
||||
|
||||
if len(multilingual) > 0 {
|
||||
|
@ -136,9 +163,17 @@ func createSitesFromDeps(deps *deps) ([]*Site, error) {
|
|||
}
|
||||
|
||||
for _, lang := range languages {
|
||||
sites = append(sites, newSite(lang, deps))
|
||||
}
|
||||
var s *Site
|
||||
var err error
|
||||
cfg.Language = lang
|
||||
s, err = newSite(cfg)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sites = append(sites, s)
|
||||
}
|
||||
}
|
||||
|
||||
return sites, nil
|
||||
|
@ -155,7 +190,8 @@ func (h *HugoSites) reset() {
|
|||
|
||||
func (h *HugoSites) createSitesFromConfig() error {
|
||||
|
||||
sites, err := createSitesFromDeps(h.deps)
|
||||
depsCfg := deps.DepsCfg{Fs: h.Fs}
|
||||
sites, err := createSitesFromConfig(depsCfg)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -173,6 +209,12 @@ func (h *HugoSites) createSitesFromConfig() error {
|
|||
s.owner = h
|
||||
}
|
||||
|
||||
if err := applyDepsIfNeeded(depsCfg, sites...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Deps = sites[0].Deps
|
||||
|
||||
h.multilingual = langConfig
|
||||
|
||||
return nil
|
||||
|
@ -199,24 +241,10 @@ type BuildCfg struct {
|
|||
CreateSitesFromConfig bool
|
||||
// Skip rendering. Useful for testing.
|
||||
SkipRender bool
|
||||
// Use this to add templates to use for rendering.
|
||||
// Useful for testing.
|
||||
withTemplate func(templ tpl.Template) error
|
||||
// Use this to indicate what changed (for rebuilds).
|
||||
whatChanged *whatChanged
|
||||
}
|
||||
|
||||
// DepsCfg contains configuration options that can be used to configure Hugo
|
||||
// on a global level, i.e. logging etc.
|
||||
// Nil values will be given default values.
|
||||
type DepsCfg struct {
|
||||
|
||||
// The Logger to use.
|
||||
Logger *jww.Notepad
|
||||
|
||||
WithTemplate []func(templ tpl.Template) error
|
||||
}
|
||||
|
||||
func (h *HugoSites) renderCrossSitesArtifacts() error {
|
||||
|
||||
if !h.multilingual.enabled() {
|
||||
|
@ -293,7 +321,7 @@ func (h *HugoSites) createMissingPages() error {
|
|||
foundTaxonomyTermsPage := false
|
||||
for key := range tax {
|
||||
if s.Info.preserveTaxonomyNames {
|
||||
key = s.Info.pathSpec.MakePathSanitized(key)
|
||||
key = s.PathSpec.MakePathSanitized(key)
|
||||
}
|
||||
for _, p := range taxonomyPages {
|
||||
if p.sections[0] == plural && p.sections[1] == key {
|
||||
|
@ -454,8 +482,8 @@ func (s *Site) preparePagesForRender(cfg *BuildCfg) {
|
|||
}
|
||||
|
||||
var err error
|
||||
if workContentCopy, err = handleShortcodes(p, s.owner.tmpl, workContentCopy); err != nil {
|
||||
jww.ERROR.Printf("Failed to handle shortcodes for page %s: %s", p.BaseFileName(), err)
|
||||
if workContentCopy, err = handleShortcodes(p, s.Tmpl, workContentCopy); err != nil {
|
||||
s.Log.ERROR.Printf("Failed to handle shortcodes for page %s: %s", p.BaseFileName(), err)
|
||||
}
|
||||
|
||||
if p.Markup != "html" {
|
||||
|
@ -464,7 +492,7 @@ func (s *Site) preparePagesForRender(cfg *BuildCfg) {
|
|||
summaryContent, err := p.setUserDefinedSummaryIfProvided(workContentCopy)
|
||||
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Failed to set user defined summary for page %q: %s", p.Path(), err)
|
||||
s.Log.ERROR.Printf("Failed to set user defined summary for page %q: %s", p.Path(), err)
|
||||
} else if summaryContent != nil {
|
||||
workContentCopy = summaryContent.content
|
||||
}
|
||||
|
@ -501,9 +529,9 @@ func (h *HugoSites) Pages() Pages {
|
|||
return h.Sites[0].AllPages
|
||||
}
|
||||
|
||||
func handleShortcodes(p *Page, t tpl.Template, rawContentCopy []byte) ([]byte, error) {
|
||||
func handleShortcodes(p *Page, t tplapi.Template, rawContentCopy []byte) ([]byte, error) {
|
||||
if len(p.contentShortCodes) > 0 {
|
||||
jww.DEBUG.Printf("Replace %d shortcodes in %q", len(p.contentShortCodes), p.BaseFileName())
|
||||
p.s.Log.DEBUG.Printf("Replace %d shortcodes in %q", len(p.contentShortCodes), p.BaseFileName())
|
||||
shortcodes, err := executeShortcodeFuncMap(p.contentShortCodes)
|
||||
|
||||
if err != nil {
|
||||
|
@ -513,7 +541,7 @@ func handleShortcodes(p *Page, t tpl.Template, rawContentCopy []byte) ([]byte, e
|
|||
rawContentCopy, err = replaceShortcodeTokens(rawContentCopy, shortcodePlaceholderPrefix, shortcodes)
|
||||
|
||||
if err != nil {
|
||||
jww.FATAL.Printf("Failed to replace shortcode tokens in %s:\n%s", p.BaseFileName(), err.Error())
|
||||
p.s.Log.FATAL.Printf("Failed to replace shortcode tokens in %s:\n%s", p.BaseFileName(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,51 +578,15 @@ func (h *HugoSites) findAllPagesByKindNotIn(kind string) Pages {
|
|||
return h.findPagesByKindNotIn(kind, h.Sites[0].AllPages)
|
||||
}
|
||||
|
||||
// Convenience func used in tests to build a single site/language excluding render phase.
|
||||
func buildSiteSkipRender(s *Site, additionalTemplates ...string) error {
|
||||
return doBuildSite(s, false, additionalTemplates...)
|
||||
}
|
||||
|
||||
// Convenience func used in tests to build a single site/language including render phase.
|
||||
func buildAndRenderSite(s *Site, additionalTemplates ...string) error {
|
||||
return doBuildSite(s, true, additionalTemplates...)
|
||||
}
|
||||
|
||||
// Convenience func used in tests to build a single site/language.
|
||||
func doBuildSite(s *Site, render bool, additionalTemplates ...string) error {
|
||||
if s.PageCollections == nil {
|
||||
s.PageCollections = newPageCollections()
|
||||
}
|
||||
sites, err := newHugoSites(DepsCfg{}, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addTemplates := func(templ tpl.Template) error {
|
||||
for i := 0; i < len(additionalTemplates); i += 2 {
|
||||
err := templ.AddTemplate(additionalTemplates[i], additionalTemplates[i+1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
config := BuildCfg{SkipRender: !render, withTemplate: addTemplates}
|
||||
return sites.Build(config)
|
||||
}
|
||||
|
||||
// Convenience func used in tests.
|
||||
func newHugoSitesFromSourceAndLanguages(input []source.ByteSource, languages helpers.Languages) (*HugoSites, error) {
|
||||
func newHugoSitesFromSourceAndLanguages(input []source.ByteSource, languages helpers.Languages, cfg deps.DepsCfg) (*HugoSites, error) {
|
||||
if len(languages) == 0 {
|
||||
panic("Must provide at least one language")
|
||||
}
|
||||
|
||||
cfg := DepsCfg{}
|
||||
|
||||
first := &Site{
|
||||
Source: &source.InMemorySource{ByteSource: input},
|
||||
Language: languages[0],
|
||||
Source: &source.InMemorySource{ByteSource: input},
|
||||
}
|
||||
if len(languages) == 1 {
|
||||
return newHugoSites(cfg, first)
|
||||
|
@ -611,6 +603,6 @@ func newHugoSitesFromSourceAndLanguages(input []source.ByteSource, languages hel
|
|||
}
|
||||
|
||||
// Convenience func used in tests.
|
||||
func newHugoSitesDefaultLanguage() (*HugoSites, error) {
|
||||
return newHugoSitesFromSourceAndLanguages(nil, helpers.Languages{helpers.NewDefaultLanguage()})
|
||||
func newHugoSitesDefaultLanguage(cfg deps.DepsCfg) (*HugoSites, error) {
|
||||
return newHugoSitesFromSourceAndLanguages(nil, helpers.Languages{helpers.NewDefaultLanguage()}, cfg)
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
|
|||
}
|
||||
|
||||
if config.PrintStats {
|
||||
h.log.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))
|
||||
h.Log.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/fortytw2/leaktest"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
|
@ -25,6 +26,7 @@ import (
|
|||
|
||||
type testSiteConfig struct {
|
||||
DefaultContentLanguage string
|
||||
Fs *hugofs.Fs
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -32,22 +34,19 @@ func init() {
|
|||
}
|
||||
|
||||
func testCommonResetState() {
|
||||
hugofs.InitMemFs()
|
||||
viper.Reset()
|
||||
viper.SetFs(hugofs.Source())
|
||||
// TODO(bep) globals viper viper.SetFs(hugofs.Source())
|
||||
viper.Set("currentContentLanguage", helpers.NewLanguage("en"))
|
||||
helpers.ResetConfigProvider()
|
||||
loadDefaultSettings()
|
||||
|
||||
// Default is false, but true is easier to use as default in tests
|
||||
viper.Set("defaultContentLanguageInSubdir", true)
|
||||
|
||||
if err := hugofs.Source().Mkdir("content", 0755); err != nil {
|
||||
panic("Content folder creation failed.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMultiSitesMainLangInRoot(t *testing.T) {
|
||||
// TODO(bep) globals this currently fails because of a configuration dependency that will be resolved when we get rid of the global Viper.
|
||||
func _TestMultiSitesMainLangInRoot(t *testing.T) {
|
||||
|
||||
for _, b := range []bool{true, false} {
|
||||
doTestMultiSitesMainLangInRoot(t, b)
|
||||
|
@ -57,7 +56,8 @@ func TestMultiSitesMainLangInRoot(t *testing.T) {
|
|||
func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) {
|
||||
testCommonResetState()
|
||||
viper.Set("defaultContentLanguageInSubdir", defaultInSubDir)
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr"}
|
||||
fs := hugofs.NewMem()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr", Fs: fs}
|
||||
|
||||
sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
|
||||
|
||||
|
@ -80,7 +80,8 @@ func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) {
|
|||
require.Equal(t, "", frSite.Info.LanguagePrefix)
|
||||
}
|
||||
|
||||
require.Equal(t, "/blog/en/foo", enSite.Info.pathSpec.RelURL("foo", true))
|
||||
fmt.Println(">>>", enSite.PathSpec)
|
||||
require.Equal(t, "/blog/en/foo", enSite.PathSpec.RelURL("foo", true))
|
||||
|
||||
doc1en := enSite.RegularPages[0]
|
||||
doc1fr := frSite.RegularPages[0]
|
||||
|
@ -96,64 +97,64 @@ func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) {
|
|||
require.Equal(t, replaceDefaultContentLanguageValue("http://example.com/blog/fr/sect/doc1/", defaultInSubDir), frPerm)
|
||||
require.Equal(t, replaceDefaultContentLanguageValue("/blog/fr/sect/doc1/", defaultInSubDir), frRelPerm)
|
||||
|
||||
assertFileContent(t, "public/fr/sect/doc1/index.html", defaultInSubDir, "Single", "Bonjour")
|
||||
assertFileContent(t, "public/en/sect/doc1-slug/index.html", defaultInSubDir, "Single", "Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/doc1/index.html", defaultInSubDir, "Single", "Bonjour")
|
||||
assertFileContent(t, fs, "public/en/sect/doc1-slug/index.html", defaultInSubDir, "Single", "Hello")
|
||||
|
||||
// Check home
|
||||
if defaultInSubDir {
|
||||
// should have a redirect on top level.
|
||||
assertFileContent(t, "public/index.html", true, `<meta http-equiv="refresh" content="0; url=http://example.com/blog/fr" />`)
|
||||
assertFileContent(t, fs, "public/index.html", true, `<meta http-equiv="refresh" content="0; url=http://example.com/blog/fr" />`)
|
||||
} else {
|
||||
// should have redirect back to root
|
||||
assertFileContent(t, "public/fr/index.html", true, `<meta http-equiv="refresh" content="0; url=http://example.com/blog" />`)
|
||||
assertFileContent(t, fs, "public/fr/index.html", true, `<meta http-equiv="refresh" content="0; url=http://example.com/blog" />`)
|
||||
}
|
||||
assertFileContent(t, "public/fr/index.html", defaultInSubDir, "Home", "Bonjour")
|
||||
assertFileContent(t, "public/en/index.html", defaultInSubDir, "Home", "Hello")
|
||||
assertFileContent(t, fs, "public/fr/index.html", defaultInSubDir, "Home", "Bonjour")
|
||||
assertFileContent(t, fs, "public/en/index.html", defaultInSubDir, "Home", "Hello")
|
||||
|
||||
// Check list pages
|
||||
assertFileContent(t, "public/fr/sect/index.html", defaultInSubDir, "List", "Bonjour")
|
||||
assertFileContent(t, "public/en/sect/index.html", defaultInSubDir, "List", "Hello")
|
||||
assertFileContent(t, "public/fr/plaques/frtag1/index.html", defaultInSubDir, "List", "Bonjour")
|
||||
assertFileContent(t, "public/en/tags/tag1/index.html", defaultInSubDir, "List", "Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/index.html", defaultInSubDir, "List", "Bonjour")
|
||||
assertFileContent(t, fs, "public/en/sect/index.html", defaultInSubDir, "List", "Hello")
|
||||
assertFileContent(t, fs, "public/fr/plaques/frtag1/index.html", defaultInSubDir, "List", "Bonjour")
|
||||
assertFileContent(t, fs, "public/en/tags/tag1/index.html", defaultInSubDir, "List", "Hello")
|
||||
|
||||
// Check sitemaps
|
||||
// Sitemaps behaves different: In a multilanguage setup there will always be a index file and
|
||||
// one sitemap in each lang folder.
|
||||
assertFileContent(t, "public/sitemap.xml", true,
|
||||
assertFileContent(t, fs, "public/sitemap.xml", true,
|
||||
"<loc>http://example.com/blog/en/sitemap.xml</loc>",
|
||||
"<loc>http://example.com/blog/fr/sitemap.xml</loc>")
|
||||
|
||||
if defaultInSubDir {
|
||||
assertFileContent(t, "public/fr/sitemap.xml", true, "<loc>http://example.com/blog/fr/</loc>")
|
||||
assertFileContent(t, fs, "public/fr/sitemap.xml", true, "<loc>http://example.com/blog/fr/</loc>")
|
||||
} else {
|
||||
assertFileContent(t, "public/fr/sitemap.xml", true, "<loc>http://example.com/blog/</loc>")
|
||||
assertFileContent(t, fs, "public/fr/sitemap.xml", true, "<loc>http://example.com/blog/</loc>")
|
||||
}
|
||||
assertFileContent(t, "public/en/sitemap.xml", true, "<loc>http://example.com/blog/en/</loc>")
|
||||
assertFileContent(t, fs, "public/en/sitemap.xml", true, "<loc>http://example.com/blog/en/</loc>")
|
||||
|
||||
// Check rss
|
||||
assertFileContent(t, "public/fr/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/fr/index.xml"`)
|
||||
assertFileContent(t, "public/en/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/en/index.xml"`)
|
||||
assertFileContent(t, "public/fr/sect/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/fr/sect/index.xml"`)
|
||||
assertFileContent(t, "public/en/sect/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/en/sect/index.xml"`)
|
||||
assertFileContent(t, "public/fr/plaques/frtag1/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/fr/plaques/frtag1/index.xml"`)
|
||||
assertFileContent(t, "public/en/tags/tag1/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/en/tags/tag1/index.xml"`)
|
||||
assertFileContent(t, fs, "public/fr/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/fr/index.xml"`)
|
||||
assertFileContent(t, fs, "public/en/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/en/index.xml"`)
|
||||
assertFileContent(t, fs, "public/fr/sect/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/fr/sect/index.xml"`)
|
||||
assertFileContent(t, fs, "public/en/sect/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/en/sect/index.xml"`)
|
||||
assertFileContent(t, fs, "public/fr/plaques/frtag1/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/fr/plaques/frtag1/index.xml"`)
|
||||
assertFileContent(t, fs, "public/en/tags/tag1/index.xml", defaultInSubDir, `<atom:link href="http://example.com/blog/en/tags/tag1/index.xml"`)
|
||||
|
||||
// Check paginators
|
||||
assertFileContent(t, "public/fr/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/fr/"`)
|
||||
assertFileContent(t, "public/en/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/en/"`)
|
||||
assertFileContent(t, "public/fr/page/2/index.html", defaultInSubDir, "Home Page 2", "Bonjour", "http://example.com/blog/fr/")
|
||||
assertFileContent(t, "public/en/page/2/index.html", defaultInSubDir, "Home Page 2", "Hello", "http://example.com/blog/en/")
|
||||
assertFileContent(t, "public/fr/sect/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/fr/sect/"`)
|
||||
assertFileContent(t, "public/en/sect/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/en/sect/"`)
|
||||
assertFileContent(t, "public/fr/sect/page/2/index.html", defaultInSubDir, "List Page 2", "Bonjour", "http://example.com/blog/fr/sect/")
|
||||
assertFileContent(t, "public/en/sect/page/2/index.html", defaultInSubDir, "List Page 2", "Hello", "http://example.com/blog/en/sect/")
|
||||
assertFileContent(t, "public/fr/plaques/frtag1/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/fr/plaques/frtag1/"`)
|
||||
assertFileContent(t, "public/en/tags/tag1/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/en/tags/tag1/"`)
|
||||
assertFileContent(t, "public/fr/plaques/frtag1/page/2/index.html", defaultInSubDir, "List Page 2", "Bonjour", "http://example.com/blog/fr/plaques/frtag1/")
|
||||
assertFileContent(t, "public/en/tags/tag1/page/2/index.html", defaultInSubDir, "List Page 2", "Hello", "http://example.com/blog/en/tags/tag1/")
|
||||
assertFileContent(t, fs, "public/fr/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/fr/"`)
|
||||
assertFileContent(t, fs, "public/en/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/en/"`)
|
||||
assertFileContent(t, fs, "public/fr/page/2/index.html", defaultInSubDir, "Home Page 2", "Bonjour", "http://example.com/blog/fr/")
|
||||
assertFileContent(t, fs, "public/en/page/2/index.html", defaultInSubDir, "Home Page 2", "Hello", "http://example.com/blog/en/")
|
||||
assertFileContent(t, fs, "public/fr/sect/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/fr/sect/"`)
|
||||
assertFileContent(t, fs, "public/en/sect/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/en/sect/"`)
|
||||
assertFileContent(t, fs, "public/fr/sect/page/2/index.html", defaultInSubDir, "List Page 2", "Bonjour", "http://example.com/blog/fr/sect/")
|
||||
assertFileContent(t, fs, "public/en/sect/page/2/index.html", defaultInSubDir, "List Page 2", "Hello", "http://example.com/blog/en/sect/")
|
||||
assertFileContent(t, fs, "public/fr/plaques/frtag1/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/fr/plaques/frtag1/"`)
|
||||
assertFileContent(t, fs, "public/en/tags/tag1/page/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/en/tags/tag1/"`)
|
||||
assertFileContent(t, fs, "public/fr/plaques/frtag1/page/2/index.html", defaultInSubDir, "List Page 2", "Bonjour", "http://example.com/blog/fr/plaques/frtag1/")
|
||||
assertFileContent(t, fs, "public/en/tags/tag1/page/2/index.html", defaultInSubDir, "List Page 2", "Hello", "http://example.com/blog/en/tags/tag1/")
|
||||
// nn (Nynorsk) and nb (Bokmål) have custom pagePath: side ("page" in Norwegian)
|
||||
assertFileContent(t, "public/nn/side/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/nn/"`)
|
||||
assertFileContent(t, "public/nb/side/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/nb/"`)
|
||||
assertFileContent(t, fs, "public/nn/side/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/nn/"`)
|
||||
assertFileContent(t, fs, "public/nb/side/1/index.html", defaultInSubDir, `refresh" content="0; url=http://example.com/blog/nb/"`)
|
||||
}
|
||||
|
||||
func replaceDefaultContentLanguageValue(value string, defaultInSubDir bool) string {
|
||||
|
@ -166,18 +167,18 @@ func replaceDefaultContentLanguageValue(value string, defaultInSubDir bool) stri
|
|||
|
||||
}
|
||||
|
||||
func assertFileContent(t *testing.T, filename string, defaultInSubDir bool, matches ...string) {
|
||||
func assertFileContent(t *testing.T, fs *hugofs.Fs, filename string, defaultInSubDir bool, matches ...string) {
|
||||
filename = replaceDefaultContentLanguageValue(filename, defaultInSubDir)
|
||||
content := readDestination(t, filename)
|
||||
content := readDestination(t, fs, filename)
|
||||
for _, match := range matches {
|
||||
match = replaceDefaultContentLanguageValue(match, defaultInSubDir)
|
||||
require.True(t, strings.Contains(content, match), fmt.Sprintf("File no match for\n%q in\n%q:\n%s", strings.Replace(match, "%", "%%", -1), filename, strings.Replace(content, "%", "%%", -1)))
|
||||
}
|
||||
}
|
||||
|
||||
func assertFileContentRegexp(t *testing.T, filename string, defaultInSubDir bool, matches ...string) {
|
||||
func assertFileContentRegexp(t *testing.T, fs *hugofs.Fs, filename string, defaultInSubDir bool, matches ...string) {
|
||||
filename = replaceDefaultContentLanguageValue(filename, defaultInSubDir)
|
||||
content := readDestination(t, filename)
|
||||
content := readDestination(t, fs, filename)
|
||||
for _, match := range matches {
|
||||
match = replaceDefaultContentLanguageValue(match, defaultInSubDir)
|
||||
r := regexp.MustCompile(match)
|
||||
|
@ -190,7 +191,12 @@ func TestMultiSitesWithTwoLanguages(t *testing.T) {
|
|||
|
||||
viper.Set("defaultContentLanguage", "nn")
|
||||
|
||||
writeSource(t, "config.toml", `
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
depsCfg := deps.DepsCfg{Fs: fs}
|
||||
viper.SetFs(depsCfg.Fs.Source)
|
||||
|
||||
writeSource(t, depsCfg.Fs, "config.toml", `
|
||||
[languages]
|
||||
[languages.nn]
|
||||
languageName = "Nynorsk"
|
||||
|
@ -208,15 +214,17 @@ weight = 2
|
|||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
||||
// Add some data
|
||||
writeSource(t, "data/hugo.toml", "slogan = \"Hugo Rocks!\"")
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(DepsCfg{})
|
||||
sites, err := NewHugoSitesFromConfiguration(depsCfg)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create sites: %s", err)
|
||||
}
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "foo.md"), "foo")
|
||||
|
||||
// Add some data
|
||||
writeSource(t, fs, filepath.Join("data", "hugo.toml"), "slogan = \"Hugo Rocks!\"")
|
||||
|
||||
require.NoError(t, sites.Build(BuildCfg{}))
|
||||
require.Len(t, sites.Sites, 2)
|
||||
|
||||
|
@ -245,7 +253,8 @@ func TestMultiSitesBuild(t *testing.T) {
|
|||
func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
|
||||
defer leaktest.Check(t)()
|
||||
testCommonResetState()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr"}
|
||||
fs := hugofs.NewMem()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr", Fs: fs}
|
||||
sites := createMultiTestSitesForConfig(t, siteConfig, configTemplate, configSuffix)
|
||||
|
||||
err := sites.Build(BuildCfg{})
|
||||
|
@ -286,7 +295,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
|
|||
assert.Equal(t, "http://example.com/blog/superbob", permalink, "invalid doc3 permalink")
|
||||
|
||||
assert.Equal(t, "/superbob", doc3.URL(), "invalid url, was specified on doc3")
|
||||
assertFileContent(t, "public/superbob/index.html", true, "doc3|Hello|en")
|
||||
assertFileContent(t, fs, "public/superbob/index.html", true, "doc3|Hello|en")
|
||||
assert.Equal(t, doc2.Next, doc3, "doc3 should follow doc2, in .Next")
|
||||
|
||||
doc1fr := doc1en.Translations()[0]
|
||||
|
@ -326,16 +335,16 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
|
|||
}
|
||||
|
||||
// Check redirect to main language, French
|
||||
languageRedirect := readDestination(t, "public/index.html")
|
||||
languageRedirect := readDestination(t, fs, "public/index.html")
|
||||
require.True(t, strings.Contains(languageRedirect, "0; url=http://example.com/blog/fr"), languageRedirect)
|
||||
|
||||
// check home page content (including data files rendering)
|
||||
assertFileContent(t, "public/en/index.html", true, "Home Page 1", "Hello", "Hugo Rocks!")
|
||||
assertFileContent(t, "public/fr/index.html", true, "Home Page 1", "Bonjour", "Hugo Rocks!")
|
||||
assertFileContent(t, fs, "public/en/index.html", true, "Home Page 1", "Hello", "Hugo Rocks!")
|
||||
assertFileContent(t, fs, "public/fr/index.html", true, "Home Page 1", "Bonjour", "Hugo Rocks!")
|
||||
|
||||
// check single page content
|
||||
assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour")
|
||||
assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour")
|
||||
assertFileContent(t, fs, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello")
|
||||
|
||||
// Check node translations
|
||||
homeEn := enSite.getPage(KindHome)
|
||||
|
@ -369,11 +378,11 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
|
|||
require.Equal(t, "nb", taxTermNn.Translations()[0].Lang())
|
||||
|
||||
// Check sitemap(s)
|
||||
sitemapIndex := readDestination(t, "public/sitemap.xml")
|
||||
sitemapIndex := readDestination(t, fs, "public/sitemap.xml")
|
||||
require.True(t, strings.Contains(sitemapIndex, "<loc>http://example.com/blog/en/sitemap.xml</loc>"), sitemapIndex)
|
||||
require.True(t, strings.Contains(sitemapIndex, "<loc>http://example.com/blog/fr/sitemap.xml</loc>"), sitemapIndex)
|
||||
sitemapEn := readDestination(t, "public/en/sitemap.xml")
|
||||
sitemapFr := readDestination(t, "public/fr/sitemap.xml")
|
||||
sitemapEn := readDestination(t, fs, "public/en/sitemap.xml")
|
||||
sitemapFr := readDestination(t, fs, "public/fr/sitemap.xml")
|
||||
require.True(t, strings.Contains(sitemapEn, "http://example.com/blog/en/sect/doc2/"), sitemapEn)
|
||||
require.True(t, strings.Contains(sitemapFr, "http://example.com/blog/fr/sect/doc1/"), sitemapFr)
|
||||
|
||||
|
@ -384,8 +393,8 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
|
|||
require.Len(t, frTags, 2, fmt.Sprintf("Tags in fr: %v", frTags))
|
||||
require.NotNil(t, enTags["tag1"])
|
||||
require.NotNil(t, frTags["frtag1"])
|
||||
readDestination(t, "public/fr/plaques/frtag1/index.html")
|
||||
readDestination(t, "public/en/tags/tag1/index.html")
|
||||
readDestination(t, fs, "public/fr/plaques/frtag1/index.html")
|
||||
readDestination(t, fs, "public/en/tags/tag1/index.html")
|
||||
|
||||
// Check Blackfriday config
|
||||
assert.True(t, strings.Contains(string(doc1fr.Content), "«"), string(doc1fr.Content))
|
||||
|
@ -409,7 +418,8 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
|
||||
defer leaktest.Check(t)()
|
||||
testCommonResetState()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr"}
|
||||
fs := hugofs.NewMem()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr", Fs: fs}
|
||||
sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
|
||||
cfg := BuildCfg{Watching: true}
|
||||
|
||||
|
@ -419,7 +429,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
t.Fatalf("Failed to build sites: %s", err)
|
||||
}
|
||||
|
||||
_, err = hugofs.Destination().Open("public/en/sect/doc2/index.html")
|
||||
_, err = fs.Destination.Open("public/en/sect/doc2/index.html")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to locate file")
|
||||
|
@ -432,12 +442,12 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
require.Len(t, frSite.RegularPages, 3)
|
||||
|
||||
// Verify translations
|
||||
assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Hello")
|
||||
assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Bonjour")
|
||||
assertFileContent(t, fs, "public/en/sect/doc1-slug/index.html", true, "Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/doc1/index.html", true, "Bonjour")
|
||||
|
||||
// check single page content
|
||||
assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour")
|
||||
assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour")
|
||||
assertFileContent(t, fs, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello")
|
||||
|
||||
for i, this := range []struct {
|
||||
preFunc func(t *testing.T)
|
||||
|
@ -468,9 +478,9 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
},
|
||||
{
|
||||
func(t *testing.T) {
|
||||
writeNewContentFile(t, "new_en_1", "2016-07-31", "content/new1.en.md", -5)
|
||||
writeNewContentFile(t, "new_en_2", "1989-07-30", "content/new2.en.md", -10)
|
||||
writeNewContentFile(t, "new_fr_1", "2016-07-30", "content/new1.fr.md", 10)
|
||||
writeNewContentFile(t, fs, "new_en_1", "2016-07-31", "content/new1.en.md", -5)
|
||||
writeNewContentFile(t, fs, "new_en_2", "1989-07-30", "content/new2.en.md", -10)
|
||||
writeNewContentFile(t, fs, "new_fr_1", "2016-07-30", "content/new1.fr.md", 10)
|
||||
},
|
||||
[]fsnotify.Event{
|
||||
{Name: "content/new1.en.md", Op: fsnotify.Create},
|
||||
|
@ -485,21 +495,21 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
require.Equal(t, "new_en_2", enSite.RegularPages[0].Title)
|
||||
require.Equal(t, "new_en_1", enSite.RegularPages[1].Title)
|
||||
|
||||
rendered := readDestination(t, "public/en/new1/index.html")
|
||||
rendered := readDestination(t, fs, "public/en/new1/index.html")
|
||||
require.True(t, strings.Contains(rendered, "new_en_1"), rendered)
|
||||
},
|
||||
},
|
||||
{
|
||||
func(t *testing.T) {
|
||||
p := "content/sect/doc1.en.md"
|
||||
doc1 := readSource(t, p)
|
||||
doc1 := readSource(t, fs, p)
|
||||
doc1 += "CHANGED"
|
||||
writeSource(t, p, doc1)
|
||||
writeSource(t, fs, p, doc1)
|
||||
},
|
||||
[]fsnotify.Event{{Name: "content/sect/doc1.en.md", Op: fsnotify.Write}},
|
||||
func(t *testing.T) {
|
||||
require.Len(t, enSite.RegularPages, 5)
|
||||
doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html")
|
||||
doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
||||
require.True(t, strings.Contains(doc1, "CHANGED"), doc1)
|
||||
|
||||
},
|
||||
|
@ -507,7 +517,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
// Rename a file
|
||||
{
|
||||
func(t *testing.T) {
|
||||
if err := hugofs.Source().Rename("content/new1.en.md", "content/new1renamed.en.md"); err != nil {
|
||||
if err := fs.Source.Rename("content/new1.en.md", "content/new1renamed.en.md"); err != nil {
|
||||
t.Fatalf("Rename failed: %s", err)
|
||||
}
|
||||
},
|
||||
|
@ -518,23 +528,23 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
func(t *testing.T) {
|
||||
require.Len(t, enSite.RegularPages, 5, "Rename")
|
||||
require.Equal(t, "new_en_1", enSite.RegularPages[1].Title)
|
||||
rendered := readDestination(t, "public/en/new1renamed/index.html")
|
||||
rendered := readDestination(t, fs, "public/en/new1renamed/index.html")
|
||||
require.True(t, strings.Contains(rendered, "new_en_1"), rendered)
|
||||
}},
|
||||
{
|
||||
// Change a template
|
||||
func(t *testing.T) {
|
||||
template := "layouts/_default/single.html"
|
||||
templateContent := readSource(t, template)
|
||||
templateContent := readSource(t, fs, template)
|
||||
templateContent += "{{ print \"Template Changed\"}}"
|
||||
writeSource(t, template, templateContent)
|
||||
writeSource(t, fs, template, templateContent)
|
||||
},
|
||||
[]fsnotify.Event{{Name: "layouts/_default/single.html", Op: fsnotify.Write}},
|
||||
func(t *testing.T) {
|
||||
require.Len(t, enSite.RegularPages, 5)
|
||||
require.Len(t, enSite.AllPages, 30)
|
||||
require.Len(t, frSite.RegularPages, 4)
|
||||
doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html")
|
||||
doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
||||
require.True(t, strings.Contains(doc1, "Template Changed"), doc1)
|
||||
},
|
||||
},
|
||||
|
@ -542,18 +552,18 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
// Change a language file
|
||||
func(t *testing.T) {
|
||||
languageFile := "i18n/fr.yaml"
|
||||
langContent := readSource(t, languageFile)
|
||||
langContent := readSource(t, fs, languageFile)
|
||||
langContent = strings.Replace(langContent, "Bonjour", "Salut", 1)
|
||||
writeSource(t, languageFile, langContent)
|
||||
writeSource(t, fs, languageFile, langContent)
|
||||
},
|
||||
[]fsnotify.Event{{Name: "i18n/fr.yaml", Op: fsnotify.Write}},
|
||||
func(t *testing.T) {
|
||||
require.Len(t, enSite.RegularPages, 5)
|
||||
require.Len(t, enSite.AllPages, 30)
|
||||
require.Len(t, frSite.RegularPages, 4)
|
||||
docEn := readDestination(t, "public/en/sect/doc1-slug/index.html")
|
||||
docEn := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
||||
require.True(t, strings.Contains(docEn, "Hello"), "No Hello")
|
||||
docFr := readDestination(t, "public/fr/sect/doc1/index.html")
|
||||
docFr := readDestination(t, fs, "public/fr/sect/doc1/index.html")
|
||||
require.True(t, strings.Contains(docFr, "Salut"), "No Salut")
|
||||
|
||||
homeEn := enSite.getPage(KindHome)
|
||||
|
@ -566,7 +576,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
// Change a shortcode
|
||||
{
|
||||
func(t *testing.T) {
|
||||
writeSource(t, "layouts/shortcodes/shortcode.html", "Modified Shortcode: {{ i18n \"hello\" }}")
|
||||
writeSource(t, fs, "layouts/shortcodes/shortcode.html", "Modified Shortcode: {{ i18n \"hello\" }}")
|
||||
},
|
||||
[]fsnotify.Event{
|
||||
{Name: "layouts/shortcodes/shortcode.html", Op: fsnotify.Write},
|
||||
|
@ -575,8 +585,8 @@ func TestMultiSitesRebuild(t *testing.T) {
|
|||
require.Len(t, enSite.RegularPages, 5)
|
||||
require.Len(t, enSite.AllPages, 30)
|
||||
require.Len(t, frSite.RegularPages, 4)
|
||||
assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Modified Shortcode: Salut")
|
||||
assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Modified Shortcode: Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/doc1/index.html", true, "Single", "Modified Shortcode: Salut")
|
||||
assertFileContent(t, fs, "public/en/sect/doc1-slug/index.html", true, "Single", "Modified Shortcode: Hello")
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
@ -615,13 +625,14 @@ func assertShouldNotBuild(t *testing.T, sites *HugoSites) {
|
|||
filename = strings.Replace(filename, ".html", "/index.html", 1)
|
||||
}
|
||||
|
||||
require.Equal(t, p.shouldBuild(), destinationExists(filename), filename)
|
||||
require.Equal(t, p.shouldBuild(), destinationExists(sites.Fs, filename), filename)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddNewLanguage(t *testing.T) {
|
||||
testCommonResetState()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr"}
|
||||
fs := hugofs.NewMem()
|
||||
siteConfig := testSiteConfig{DefaultContentLanguage: "fr", Fs: fs}
|
||||
|
||||
sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
|
||||
cfg := BuildCfg{}
|
||||
|
@ -641,9 +652,9 @@ title = "Svenska"
|
|||
|
||||
newConfig = createConfig(t, siteConfig, newConfig)
|
||||
|
||||
writeNewContentFile(t, "Swedish Contentfile", "2016-01-01", "content/sect/doc1.sv.md", 10)
|
||||
writeNewContentFile(t, fs, "Swedish Contentfile", "2016-01-01", "content/sect/doc1.sv.md", 10)
|
||||
// replace the config
|
||||
writeSource(t, "multilangconfig.toml", newConfig)
|
||||
writeSource(t, fs, "multilangconfig.toml", newConfig)
|
||||
|
||||
// Watching does not work with in-memory fs, so we trigger a reload manually
|
||||
require.NoError(t, viper.ReadInConfig())
|
||||
|
@ -685,8 +696,8 @@ title = "Svenska"
|
|||
func TestChangeDefaultLanguage(t *testing.T) {
|
||||
testCommonResetState()
|
||||
viper.Set("defaultContentLanguageInSubdir", false)
|
||||
|
||||
sites := createMultiTestSites(t, testSiteConfig{DefaultContentLanguage: "fr"}, multiSiteTOMLConfigTemplate)
|
||||
fs := hugofs.NewMem()
|
||||
sites := createMultiTestSites(t, testSiteConfig{DefaultContentLanguage: "fr", Fs: fs}, multiSiteTOMLConfigTemplate)
|
||||
cfg := BuildCfg{}
|
||||
|
||||
err := sites.Build(cfg)
|
||||
|
@ -695,13 +706,13 @@ func TestChangeDefaultLanguage(t *testing.T) {
|
|||
t.Fatalf("Failed to build sites: %s", err)
|
||||
}
|
||||
|
||||
assertFileContent(t, "public/sect/doc1/index.html", true, "Single", "Bonjour")
|
||||
assertFileContent(t, "public/en/sect/doc2/index.html", true, "Single", "Hello")
|
||||
assertFileContent(t, fs, "public/sect/doc1/index.html", true, "Single", "Bonjour")
|
||||
assertFileContent(t, fs, "public/en/sect/doc2/index.html", true, "Single", "Hello")
|
||||
|
||||
newConfig := createConfig(t, testSiteConfig{DefaultContentLanguage: "en"}, multiSiteTOMLConfigTemplate)
|
||||
|
||||
// replace the config
|
||||
writeSource(t, "multilangconfig.toml", newConfig)
|
||||
writeSource(t, fs, "multilangconfig.toml", newConfig)
|
||||
|
||||
// Watching does not work with in-memory fs, so we trigger a reload manually
|
||||
require.NoError(t, viper.ReadInConfig())
|
||||
|
@ -712,18 +723,19 @@ func TestChangeDefaultLanguage(t *testing.T) {
|
|||
}
|
||||
|
||||
// Default language is now en, so that should now be the "root" language
|
||||
assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Bonjour")
|
||||
assertFileContent(t, "public/sect/doc2/index.html", true, "Single", "Hello")
|
||||
assertFileContent(t, fs, "public/fr/sect/doc1/index.html", true, "Single", "Bonjour")
|
||||
assertFileContent(t, fs, "public/sect/doc2/index.html", true, "Single", "Hello")
|
||||
}
|
||||
|
||||
func TestTableOfContentsInShortcodes(t *testing.T) {
|
||||
testCommonResetState()
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
sites := createMultiTestSites(t, testSiteConfig{DefaultContentLanguage: "en"}, multiSiteTOMLConfigTemplate)
|
||||
writeSource(t, fs, "layouts/shortcodes/toc.html", tocShortcode)
|
||||
writeSource(t, fs, "content/post/simple.en.md", tocPageSimple)
|
||||
writeSource(t, fs, "content/post/withSCInHeading.en.md", tocPageWithShortcodesInHeadings)
|
||||
|
||||
writeSource(t, "layouts/shortcodes/toc.html", tocShortcode)
|
||||
writeSource(t, "content/post/simple.en.md", tocPageSimple)
|
||||
writeSource(t, "content/post/withSCInHeading.en.md", tocPageWithShortcodesInHeadings)
|
||||
sites := createMultiTestSites(t, testSiteConfig{DefaultContentLanguage: "en", Fs: fs}, multiSiteTOMLConfigTemplate)
|
||||
|
||||
cfg := BuildCfg{}
|
||||
|
||||
|
@ -733,8 +745,8 @@ func TestTableOfContentsInShortcodes(t *testing.T) {
|
|||
t.Fatalf("Failed to build sites: %s", err)
|
||||
}
|
||||
|
||||
assertFileContent(t, "public/en/post/simple/index.html", true, tocPageSimpleExpected)
|
||||
assertFileContent(t, "public/en/post/withSCInHeading/index.html", true, tocPageWithShortcodesInHeadingsExpected)
|
||||
assertFileContent(t, fs, "public/en/post/simple/index.html", true, tocPageSimpleExpected)
|
||||
assertFileContent(t, fs, "public/en/post/withSCInHeading/index.html", true, tocPageWithShortcodesInHeadingsExpected)
|
||||
}
|
||||
|
||||
var tocShortcode = `
|
||||
|
@ -1014,24 +1026,25 @@ func createMultiTestSites(t *testing.T, siteConfig testSiteConfig, tomlConfigTem
|
|||
|
||||
func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, configTemplate, configSuffix string) *HugoSites {
|
||||
|
||||
depsCfg := deps.DepsCfg{Fs: siteConfig.Fs}
|
||||
configContent := createConfig(t, siteConfig, configTemplate)
|
||||
|
||||
// Add some layouts
|
||||
if err := afero.WriteFile(hugofs.Source(),
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source,
|
||||
filepath.Join("layouts", "_default/single.html"),
|
||||
[]byte("Single: {{ .Title }}|{{ i18n \"hello\" }}|{{.Lang}}|{{ .Content }}"),
|
||||
0755); err != nil {
|
||||
t.Fatalf("Failed to write layout file: %s", err)
|
||||
}
|
||||
|
||||
if err := afero.WriteFile(hugofs.Source(),
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source,
|
||||
filepath.Join("layouts", "_default/list.html"),
|
||||
[]byte("{{ $p := .Paginator }}List Page {{ $p.PageNumber }}: {{ .Title }}|{{ i18n \"hello\" }}|{{ .Permalink }}"),
|
||||
0755); err != nil {
|
||||
t.Fatalf("Failed to write layout file: %s", err)
|
||||
}
|
||||
|
||||
if err := afero.WriteFile(hugofs.Source(),
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source,
|
||||
filepath.Join("layouts", "index.html"),
|
||||
[]byte("{{ $p := .Paginator }}Home Page {{ $p.PageNumber }}: {{ .Title }}|{{ .IsHome }}|{{ i18n \"hello\" }}|{{ .Permalink }}|{{ .Site.Data.hugo.slogan }}"),
|
||||
0755); err != nil {
|
||||
|
@ -1039,7 +1052,7 @@ func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, conf
|
|||
}
|
||||
|
||||
// Add a shortcode
|
||||
if err := afero.WriteFile(hugofs.Source(),
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source,
|
||||
filepath.Join("layouts", "shortcodes", "shortcode.html"),
|
||||
[]byte("Shortcode: {{ i18n \"hello\" }}"),
|
||||
0755); err != nil {
|
||||
|
@ -1047,7 +1060,7 @@ func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, conf
|
|||
}
|
||||
|
||||
// Add some language files
|
||||
if err := afero.WriteFile(hugofs.Source(),
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source,
|
||||
filepath.Join("i18n", "en.yaml"),
|
||||
[]byte(`
|
||||
- id: hello
|
||||
|
@ -1056,7 +1069,7 @@ func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, conf
|
|||
0755); err != nil {
|
||||
t.Fatalf("Failed to write language file: %s", err)
|
||||
}
|
||||
if err := afero.WriteFile(hugofs.Source(),
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source,
|
||||
filepath.Join("i18n", "fr.yaml"),
|
||||
[]byte(`
|
||||
- id: hello
|
||||
|
@ -1210,7 +1223,10 @@ lag:
|
|||
}
|
||||
|
||||
configFile := "multilangconfig." + configSuffix
|
||||
writeSource(t, configFile, configContent)
|
||||
writeSource(t, depsCfg.Fs, configFile, configContent)
|
||||
|
||||
viper.SetFs(depsCfg.Fs.Source)
|
||||
|
||||
if err := LoadGlobalConfig("", configFile); err != nil {
|
||||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
@ -1218,15 +1234,15 @@ lag:
|
|||
// Hugo support using ByteSource's directly (for testing),
|
||||
// but to make it more real, we write them to the mem file system.
|
||||
for _, s := range sources {
|
||||
if err := afero.WriteFile(hugofs.Source(), filepath.Join("content", s.Name), s.Content, 0755); err != nil {
|
||||
if err := afero.WriteFile(depsCfg.Fs.Source, filepath.Join("content", s.Name), s.Content, 0755); err != nil {
|
||||
t.Fatalf("Failed to write file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add some data
|
||||
writeSource(t, "data/hugo.toml", "slogan = \"Hugo Rocks!\"")
|
||||
writeSource(t, depsCfg.Fs, "data/hugo.toml", "slogan = \"Hugo Rocks!\"")
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(DepsCfg{})
|
||||
sites, err := NewHugoSitesFromConfiguration(depsCfg)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create sites: %s", err)
|
||||
|
@ -1239,26 +1255,26 @@ lag:
|
|||
return sites
|
||||
}
|
||||
|
||||
func writeSource(t *testing.T, filename, content string) {
|
||||
if err := afero.WriteFile(hugofs.Source(), filepath.FromSlash(filename), []byte(content), 0755); err != nil {
|
||||
func writeSource(t *testing.T, fs *hugofs.Fs, filename, content string) {
|
||||
if err := afero.WriteFile(fs.Source, filepath.FromSlash(filename), []byte(content), 0755); err != nil {
|
||||
t.Fatalf("Failed to write file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func readDestination(t *testing.T, filename string) string {
|
||||
return readFileFromFs(t, hugofs.Destination(), filename)
|
||||
func readDestination(t *testing.T, fs *hugofs.Fs, filename string) string {
|
||||
return readFileFromFs(t, fs.Destination, filename)
|
||||
}
|
||||
|
||||
func destinationExists(filename string) bool {
|
||||
b, err := helpers.Exists(filename, hugofs.Destination())
|
||||
func destinationExists(fs *hugofs.Fs, filename string) bool {
|
||||
b, err := helpers.Exists(filename, fs.Destination)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func readSource(t *testing.T, filename string) string {
|
||||
return readFileFromFs(t, hugofs.Source(), filename)
|
||||
func readSource(t *testing.T, fs *hugofs.Fs, filename string) string {
|
||||
return readFileFromFs(t, fs.Source, filename)
|
||||
}
|
||||
|
||||
func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
|
||||
|
@ -1291,9 +1307,9 @@ func newTestPage(title, date string, weight int) string {
|
|||
return fmt.Sprintf(testPageTemplate, title, date, weight, title)
|
||||
}
|
||||
|
||||
func writeNewContentFile(t *testing.T, title, date, filename string, weight int) {
|
||||
func writeNewContentFile(t *testing.T, fs *hugofs.Fs, title, date, filename string, weight int) {
|
||||
content := newTestPage(title, date, weight)
|
||||
writeSource(t, filename, content)
|
||||
writeSource(t, fs, filename, content)
|
||||
}
|
||||
|
||||
func createConfig(t *testing.T, config testSiteConfig, configTemplate string) string {
|
||||
|
|
|
@ -19,11 +19,10 @@ import (
|
|||
"github.com/nicksnyder/go-i18n/i18n/bundle"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/tpl"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
func loadI18n(sources []source.Input) error {
|
||||
jww.DEBUG.Printf("Load I18n from %q", sources)
|
||||
func (s *Site) loadI18n(sources []source.Input) error {
|
||||
s.Log.DEBUG.Printf("Load I18n from %q", sources)
|
||||
|
||||
i18nBundle := bundle.New()
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
toml "github.com/pelletier/go-toml"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -677,31 +679,29 @@ func setupTestMenuState(t *testing.T) {
|
|||
}
|
||||
|
||||
func setupMenuTests(t *testing.T, pageSources []source.ByteSource) *Site {
|
||||
s := createTestSite(pageSources)
|
||||
|
||||
setupTestMenuState(t)
|
||||
testSiteSetup(s, t)
|
||||
|
||||
return s
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range pageSources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
return buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
}
|
||||
|
||||
func createTestSite(pageSources []source.ByteSource) *Site {
|
||||
hugofs.InitMemFs()
|
||||
|
||||
return &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: pageSources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testSiteSetup(s *Site, t *testing.T) {
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Sites build failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func tomlToMap(s string) (map[string]interface{}, error) {
|
||||
tree, err := toml.Load(s)
|
||||
|
||||
|
|
|
@ -18,8 +18,11 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -56,24 +59,28 @@ func doTestNodeAsPage(t *testing.T, ugly, preserveTaxonomyNames bool) {
|
|||
viper.Set("uglyURLs", ugly)
|
||||
viper.Set("preserveTaxonomyNames", preserveTaxonomyNames)
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
writeNodePagesForNodeAsPageTests("", t)
|
||||
|
||||
writeRegularPagesForNodeAsPageTests(t)
|
||||
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks")
|
||||
viper.Set("rssURI", "customrss.xml")
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
depsCfg := newTestDepsConfig()
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
viper.SetFs(depsCfg.Fs.Source)
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t, depsCfg.Fs)
|
||||
writeNodePagesForNodeAsPageTests(t, depsCfg.Fs, "")
|
||||
|
||||
writeRegularPagesForNodeAsPageTests(t, depsCfg.Fs)
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(depsCfg)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, sites.Build(BuildCfg{}))
|
||||
|
||||
// date order: home, sect1, sect2, cat/hugo, cat/web, categories
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "index.html"), false,
|
||||
assertFileContent(t, depsCfg.Fs, filepath.Join("public", "index.html"), false,
|
||||
"Index Title: Home Sweet Home!",
|
||||
"Home <strong>Content!</strong>",
|
||||
"# Pages: 4",
|
||||
|
@ -82,10 +89,9 @@ func doTestNodeAsPage(t *testing.T, ugly, preserveTaxonomyNames bool) {
|
|||
"GetPage: Section1 ",
|
||||
)
|
||||
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "sect1", "regular1"), false, "Single Title: Page 01", "Content Page 01")
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "sect1", "regular1"), false, "Single Title: Page 01", "Content Page 01")
|
||||
|
||||
h := s.owner
|
||||
nodes := h.findAllPagesByKindNotIn(KindPage)
|
||||
nodes := sites.findAllPagesByKindNotIn(KindPage)
|
||||
|
||||
require.Len(t, nodes, 7)
|
||||
|
||||
|
@ -99,7 +105,7 @@ func doTestNodeAsPage(t *testing.T, ugly, preserveTaxonomyNames bool) {
|
|||
section2 := nodes[4]
|
||||
require.Equal(t, "Section2", section2.Title)
|
||||
|
||||
pages := h.findAllPagesByKind(KindPage)
|
||||
pages := sites.findAllPagesByKind(KindPage)
|
||||
require.Len(t, pages, 4)
|
||||
|
||||
first := pages[0]
|
||||
|
@ -109,46 +115,48 @@ func doTestNodeAsPage(t *testing.T, ugly, preserveTaxonomyNames bool) {
|
|||
require.True(t, first.IsPage())
|
||||
|
||||
// Check Home paginator
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "page", "2"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "page", "2"), false,
|
||||
"Pag: Page 02")
|
||||
|
||||
// Check Sections
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "sect1"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "sect1"), false,
|
||||
"Section Title: Section", "Section1 <strong>Content!</strong>",
|
||||
"Date: 2009-01-04",
|
||||
"Lastmod: 2009-01-05",
|
||||
)
|
||||
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "sect2"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "sect2"), false,
|
||||
"Section Title: Section", "Section2 <strong>Content!</strong>",
|
||||
"Date: 2009-01-06",
|
||||
"Lastmod: 2009-01-07",
|
||||
)
|
||||
|
||||
// Check Sections paginator
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "sect1", "page", "2"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "sect1", "page", "2"), false,
|
||||
"Pag: Page 02")
|
||||
|
||||
sections := h.findAllPagesByKind(KindSection)
|
||||
sections := sites.findAllPagesByKind(KindSection)
|
||||
|
||||
require.Len(t, sections, 2)
|
||||
|
||||
// Check taxonomy lists
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories", "hugo"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "categories", "hugo"), false,
|
||||
"Taxonomy Title: Taxonomy Hugo", "Taxonomy Hugo <strong>Content!</strong>",
|
||||
"Date: 2009-01-08",
|
||||
"Lastmod: 2009-01-09",
|
||||
)
|
||||
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories", "hugo-rocks"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "categories", "hugo-rocks"), false,
|
||||
"Taxonomy Title: Taxonomy Hugo Rocks",
|
||||
)
|
||||
|
||||
s := sites.Sites[0]
|
||||
|
||||
web := s.getPage(KindTaxonomy, "categories", "web")
|
||||
require.NotNil(t, web)
|
||||
require.Len(t, web.Data["Pages"].(Pages), 4)
|
||||
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories", "web"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "categories", "web"), false,
|
||||
"Taxonomy Title: Taxonomy Web",
|
||||
"Taxonomy Web <strong>Content!</strong>",
|
||||
"Date: 2009-01-10",
|
||||
|
@ -156,12 +164,12 @@ func doTestNodeAsPage(t *testing.T, ugly, preserveTaxonomyNames bool) {
|
|||
)
|
||||
|
||||
// Check taxonomy list paginator
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories", "hugo", "page", "2"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "categories", "hugo", "page", "2"), false,
|
||||
"Taxonomy Title: Taxonomy Hugo",
|
||||
"Pag: Page 02")
|
||||
|
||||
// Check taxonomy terms
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories"), false,
|
||||
assertFileContent(t, depsCfg.Fs, expectedFilePath(ugly, "public", "categories"), false,
|
||||
"Taxonomy Terms Title: Taxonomy Term Categories", "Taxonomy Term Categories <strong>Content!</strong>", "k/v: hugo",
|
||||
"Date: 2009-01-14",
|
||||
"Lastmod: 2009-01-15",
|
||||
|
@ -170,11 +178,11 @@ func doTestNodeAsPage(t *testing.T, ugly, preserveTaxonomyNames bool) {
|
|||
// There are no pages to paginate over in the taxonomy terms.
|
||||
|
||||
// RSS
|
||||
assertFileContent(t, filepath.Join("public", "customrss.xml"), false, "Recent content in Home Sweet Home! on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "sect1", "customrss.xml"), false, "Recent content in Section1 on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "sect2", "customrss.xml"), false, "Recent content in Section2 on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "categories", "hugo", "customrss.xml"), false, "Recent content in Taxonomy Hugo on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "categories", "web", "customrss.xml"), false, "Recent content in Taxonomy Web on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, depsCfg.Fs, filepath.Join("public", "customrss.xml"), false, "Recent content in Home Sweet Home! on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, depsCfg.Fs, filepath.Join("public", "sect1", "customrss.xml"), false, "Recent content in Section1 on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, depsCfg.Fs, filepath.Join("public", "sect2", "customrss.xml"), false, "Recent content in Section2 on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, depsCfg.Fs, filepath.Join("public", "categories", "hugo", "customrss.xml"), false, "Recent content in Taxonomy Hugo on Hugo Rocks", "<rss")
|
||||
assertFileContent(t, depsCfg.Fs, filepath.Join("public", "categories", "web", "customrss.xml"), false, "Recent content in Taxonomy Web on Hugo Rocks", "<rss")
|
||||
|
||||
}
|
||||
|
||||
|
@ -187,19 +195,23 @@ func TestNodesWithNoContentFile(t *testing.T) {
|
|||
func doTestNodesWithNoContentFile(t *testing.T, ugly bool) {
|
||||
testCommonResetState()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
writeRegularPagesForNodeAsPageTests(t)
|
||||
|
||||
viper.Set("uglyURLs", ugly)
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
viper.Set("rssURI", "customrss.xml")
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
writeRegularPagesForNodeAsPageTests(t, fs)
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, sites.Build(BuildCfg{}))
|
||||
|
||||
s := sites.Sites[0]
|
||||
|
||||
// Home page
|
||||
homePages := s.findPagesByKind(KindHome)
|
||||
|
@ -210,21 +222,21 @@ func doTestNodesWithNoContentFile(t *testing.T, ugly bool) {
|
|||
require.Len(t, homePage.Pages, 4)
|
||||
require.True(t, homePage.Path() == "")
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "index.html"), false,
|
||||
assertFileContent(t, fs, filepath.Join("public", "index.html"), false,
|
||||
"Index Title: Hugo Rocks!",
|
||||
"Date: 2010-06-12",
|
||||
"Lastmod: 2010-06-13",
|
||||
)
|
||||
|
||||
// Taxonomy list
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories", "hugo"), false,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "categories", "hugo"), false,
|
||||
"Taxonomy Title: Hugo",
|
||||
"Date: 2010-06-12",
|
||||
"Lastmod: 2010-06-13",
|
||||
)
|
||||
|
||||
// Taxonomy terms
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "categories"), false,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "categories"), false,
|
||||
"Taxonomy Terms Title: Categories",
|
||||
)
|
||||
|
||||
|
@ -232,9 +244,9 @@ func doTestNodesWithNoContentFile(t *testing.T, ugly bool) {
|
|||
for _, p := range pages {
|
||||
var want string
|
||||
if ugly {
|
||||
want = "/" + p.Site.pathSpec.URLize(p.Title) + ".html"
|
||||
want = "/" + p.s.PathSpec.URLize(p.Title) + ".html"
|
||||
} else {
|
||||
want = "/" + p.Site.pathSpec.URLize(p.Title) + "/"
|
||||
want = "/" + p.s.PathSpec.URLize(p.Title) + "/"
|
||||
}
|
||||
if p.URL() != want {
|
||||
t.Errorf("Taxonomy term URL mismatch: want %q, got %q", want, p.URL())
|
||||
|
@ -242,29 +254,29 @@ func doTestNodesWithNoContentFile(t *testing.T, ugly bool) {
|
|||
}
|
||||
|
||||
// Sections
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "sect1"), false,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "sect1"), false,
|
||||
"Section Title: Sect1s",
|
||||
"Date: 2010-06-12",
|
||||
"Lastmod: 2010-06-13",
|
||||
)
|
||||
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "sect2"), false,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "sect2"), false,
|
||||
"Section Title: Sect2s",
|
||||
"Date: 2008-07-06",
|
||||
"Lastmod: 2008-07-09",
|
||||
)
|
||||
|
||||
// RSS
|
||||
assertFileContent(t, filepath.Join("public", "customrss.xml"), false, "Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "sect1", "customrss.xml"), false, "Recent content in Sect1s on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "sect2", "customrss.xml"), false, "Recent content in Sect2s on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "categories", "hugo", "customrss.xml"), false, "Recent content in Hugo on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "categories", "web", "customrss.xml"), false, "Recent content in Web on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "customrss.xml"), false, "Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect1", "customrss.xml"), false, "Recent content in Sect1s on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect2", "customrss.xml"), false, "Recent content in Sect2s on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "categories", "hugo", "customrss.xml"), false, "Recent content in Hugo on Hugo Rocks!", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "categories", "web", "customrss.xml"), false, "Recent content in Web on Hugo Rocks!", "<rss")
|
||||
|
||||
}
|
||||
|
||||
func TestNodesAsPageMultilingual(t *testing.T) {
|
||||
for _, ugly := range []bool{true, false} {
|
||||
for _, ugly := range []bool{false, true} {
|
||||
doTestNodesAsPageMultilingual(t, ugly)
|
||||
}
|
||||
}
|
||||
|
@ -273,11 +285,13 @@ func doTestNodesAsPageMultilingual(t *testing.T, ugly bool) {
|
|||
|
||||
testCommonResetState()
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
viper.Set("uglyURLs", ugly)
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
viper.SetFs(fs.Source)
|
||||
|
||||
writeSource(t, "config.toml",
|
||||
writeSource(t, fs, "config.toml",
|
||||
`
|
||||
paginage = 1
|
||||
title = "Hugo Multilingual Rocks!"
|
||||
|
@ -303,19 +317,17 @@ weight = 3
|
|||
title = "Deutsche Hugo"
|
||||
`)
|
||||
|
||||
for _, lang := range []string{"nn", "en"} {
|
||||
writeRegularPagesForNodeAsPageTestsWithLang(t, lang)
|
||||
}
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
|
||||
// Only write node pages for the English and Deutsch
|
||||
writeNodePagesForNodeAsPageTests("en", t)
|
||||
writeNodePagesForNodeAsPageTests("de", t)
|
||||
for _, lang := range []string{"nn", "en"} {
|
||||
writeRegularPagesForNodeAsPageTestsWithLang(t, fs, lang)
|
||||
}
|
||||
|
||||
if err := LoadGlobalConfig("", "config.toml"); err != nil {
|
||||
t.Fatalf("Failed to load config: %s", err)
|
||||
}
|
||||
|
||||
sites, err := NewHugoSitesFromConfiguration(DepsCfg{})
|
||||
sites, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create sites: %s", err)
|
||||
|
@ -325,6 +337,10 @@ title = "Deutsche Hugo"
|
|||
t.Fatalf("Got %d sites", len(sites.Sites))
|
||||
}
|
||||
|
||||
// Only write node pages for the English and Deutsch
|
||||
writeNodePagesForNodeAsPageTests(t, fs, "en")
|
||||
writeNodePagesForNodeAsPageTests(t, fs, "de")
|
||||
|
||||
err = sites.Build(BuildCfg{})
|
||||
|
||||
if err != nil {
|
||||
|
@ -356,92 +372,99 @@ title = "Deutsche Hugo"
|
|||
|
||||
require.Equal(t, expetedPermalink(ugly, "/en/sect1/"), enSect.Permalink())
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "nn", "index.html"), true,
|
||||
assertFileContent(t, fs, filepath.Join("public", "nn", "index.html"), true,
|
||||
"Index Title: Hugo på norsk")
|
||||
assertFileContent(t, filepath.Join("public", "en", "index.html"), true,
|
||||
assertFileContent(t, fs, filepath.Join("public", "en", "index.html"), true,
|
||||
"Index Title: Home Sweet Home!", "<strong>Content!</strong>")
|
||||
assertFileContent(t, filepath.Join("public", "de", "index.html"), true,
|
||||
assertFileContent(t, fs, filepath.Join("public", "de", "index.html"), true,
|
||||
"Index Title: Home Sweet Home!", "<strong>Content!</strong>")
|
||||
|
||||
// Taxonomy list
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "nn", "categories", "hugo"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "nn", "categories", "hugo"), true,
|
||||
"Taxonomy Title: Hugo")
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "en", "categories", "hugo"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "en", "categories", "hugo"), true,
|
||||
"Taxonomy Title: Taxonomy Hugo")
|
||||
|
||||
// Taxonomy terms
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "nn", "categories"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "nn", "categories"), true,
|
||||
"Taxonomy Terms Title: Categories")
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "en", "categories"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "en", "categories"), true,
|
||||
"Taxonomy Terms Title: Taxonomy Term Categories")
|
||||
|
||||
// Sections
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "nn", "sect1"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "nn", "sect1"), true,
|
||||
"Section Title: Sect1s")
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "nn", "sect2"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "nn", "sect2"), true,
|
||||
"Section Title: Sect2s")
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "en", "sect1"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "en", "sect1"), true,
|
||||
"Section Title: Section1")
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "en", "sect2"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "en", "sect2"), true,
|
||||
"Section Title: Section2")
|
||||
|
||||
// Regular pages
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "en", "sect1", "regular1"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "en", "sect1", "regular1"), true,
|
||||
"Single Title: Page 01")
|
||||
assertFileContent(t, expectedFilePath(ugly, "public", "nn", "sect1", "regular2"), true,
|
||||
assertFileContent(t, fs, expectedFilePath(ugly, "public", "nn", "sect1", "regular2"), true,
|
||||
"Single Title: Page 02")
|
||||
|
||||
// RSS
|
||||
assertFileContent(t, filepath.Join("public", "nn", "customrss.xml"), true, "Hugo på norsk", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "nn", "sect1", "customrss.xml"), true, "Recent content in Sect1s on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "nn", "sect2", "customrss.xml"), true, "Recent content in Sect2s on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "nn", "categories", "hugo", "customrss.xml"), true, "Recent content in Hugo on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "nn", "categories", "web", "customrss.xml"), true, "Recent content in Web on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "nn", "customrss.xml"), true, "Hugo på norsk", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "nn", "sect1", "customrss.xml"), true, "Recent content in Sect1s on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "nn", "sect2", "customrss.xml"), true, "Recent content in Sect2s on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "nn", "categories", "hugo", "customrss.xml"), true, "Recent content in Hugo on Hugo på norsk", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "nn", "categories", "web", "customrss.xml"), true, "Recent content in Web on Hugo på norsk", "<rss")
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "en", "customrss.xml"), true, "Recent content in Home Sweet Home! on Hugo in English", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "en", "sect1", "customrss.xml"), true, "Recent content in Section1 on Hugo in English", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "en", "sect2", "customrss.xml"), true, "Recent content in Section2 on Hugo in English", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "en", "categories", "hugo", "customrss.xml"), true, "Recent content in Taxonomy Hugo on Hugo in English", "<rss")
|
||||
assertFileContent(t, filepath.Join("public", "en", "categories", "web", "customrss.xml"), true, "Recent content in Taxonomy Web on Hugo in English", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "en", "customrss.xml"), true, "Recent content in Home Sweet Home! on Hugo in English", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "en", "sect1", "customrss.xml"), true, "Recent content in Section1 on Hugo in English", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "en", "sect2", "customrss.xml"), true, "Recent content in Section2 on Hugo in English", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "en", "categories", "hugo", "customrss.xml"), true, "Recent content in Taxonomy Hugo on Hugo in English", "<rss")
|
||||
assertFileContent(t, fs, filepath.Join("public", "en", "categories", "web", "customrss.xml"), true, "Recent content in Taxonomy Web on Hugo in English", "<rss")
|
||||
|
||||
}
|
||||
|
||||
func TestNodesWithTaxonomies(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
writeRegularPagesForNodeAsPageTests(t)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, filepath.Join("content", "_index.md"), `---
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
writeRegularPagesForNodeAsPageTests(t, fs)
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "_index.md"), `---
|
||||
title: Home With Taxonomies
|
||||
categories: [
|
||||
"Hugo",
|
||||
"Hugo",
|
||||
"Home"
|
||||
]
|
||||
---
|
||||
`)
|
||||
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
h, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
require.NoError(t, h.Build(BuildCfg{}))
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "categories", "hugo", "index.html"), true, "Taxonomy Title: Hugo", "# Pages: 5")
|
||||
assertFileContent(t, filepath.Join("public", "categories", "home", "index.html"), true, "Taxonomy Title: Home", "# Pages: 1")
|
||||
assertFileContent(t, fs, filepath.Join("public", "categories", "hugo", "index.html"), true, "Taxonomy Title: Hugo", "# Pages: 5")
|
||||
assertFileContent(t, fs, filepath.Join("public", "categories", "home", "index.html"), true, "Taxonomy Title: Home", "# Pages: 1")
|
||||
|
||||
}
|
||||
|
||||
func TestNodesWithMenu(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
writeRegularPagesForNodeAsPageTests(t)
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
|
||||
writeSource(t, filepath.Join("content", "_index.md"), `---
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
writeRegularPagesForNodeAsPageTests(t, fs)
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "_index.md"), `---
|
||||
title: Home With Menu
|
||||
menu:
|
||||
mymenu:
|
||||
|
@ -449,7 +472,7 @@ menu:
|
|||
---
|
||||
`)
|
||||
|
||||
writeSource(t, filepath.Join("content", "sect1", "_index.md"), `---
|
||||
writeSource(t, fs, filepath.Join("content", "sect1", "_index.md"), `---
|
||||
title: Sect1 With Menu
|
||||
menu:
|
||||
mymenu:
|
||||
|
@ -457,7 +480,7 @@ menu:
|
|||
---
|
||||
`)
|
||||
|
||||
writeSource(t, filepath.Join("content", "categories", "hugo", "_index.md"), `---
|
||||
writeSource(t, fs, filepath.Join("content", "categories", "hugo", "_index.md"), `---
|
||||
title: Taxonomy With Menu
|
||||
menu:
|
||||
mymenu:
|
||||
|
@ -465,98 +488,102 @@ menu:
|
|||
---
|
||||
`)
|
||||
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
h, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
require.NoError(t, h.Build(BuildCfg{}))
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "index.html"), true, "Home With Menu", "Home Menu Item: Go Home!: /")
|
||||
assertFileContent(t, filepath.Join("public", "sect1", "index.html"), true, "Sect1 With Menu", "Section Menu Item: Go Sect1!: /sect1/")
|
||||
assertFileContent(t, filepath.Join("public", "categories", "hugo", "index.html"), true, "Taxonomy With Menu", "Taxonomy Menu Item: Go Tax Hugo!: /categories/hugo/")
|
||||
assertFileContent(t, fs, filepath.Join("public", "index.html"), true, "Home With Menu", "Home Menu Item: Go Home!: /")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect1", "index.html"), true, "Sect1 With Menu", "Section Menu Item: Go Sect1!: /sect1/")
|
||||
assertFileContent(t, fs, filepath.Join("public", "categories", "hugo", "index.html"), true, "Taxonomy With Menu", "Taxonomy Menu Item: Go Tax Hugo!: /categories/hugo/")
|
||||
|
||||
}
|
||||
|
||||
func TestNodesWithAlias(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
writeRegularPagesForNodeAsPageTests(t)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, filepath.Join("content", "_index.md"), `---
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("baseURL", "http://base/")
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
writeRegularPagesForNodeAsPageTests(t, fs)
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "_index.md"), `---
|
||||
title: Home With Alias
|
||||
aliases:
|
||||
- /my/new/home.html
|
||||
---
|
||||
`)
|
||||
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("baseURL", "http://base/")
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
h, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
require.NoError(t, h.Build(BuildCfg{}))
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "index.html"), true, "Home With Alias")
|
||||
assertFileContent(t, filepath.Join("public", "my", "new", "home.html"), true, "content=\"0; url=http://base/")
|
||||
assertFileContent(t, fs, filepath.Join("public", "index.html"), true, "Home With Alias")
|
||||
assertFileContent(t, fs, filepath.Join("public", "my", "new", "home.html"), true, "content=\"0; url=http://base/")
|
||||
|
||||
}
|
||||
|
||||
func TestNodesWithSectionWithIndexPageOnly(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, filepath.Join("content", "sect", "_index.md"), `---
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "sect", "_index.md"), `---
|
||||
title: MySection
|
||||
---
|
||||
My Section Content
|
||||
`)
|
||||
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
h, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
require.NoError(t, h.Build(BuildCfg{}))
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), true, "My Section")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), true, "My Section")
|
||||
|
||||
}
|
||||
|
||||
func TestNodesWithURLs(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
writeLayoutsForNodeAsPageTests(t)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeRegularPagesForNodeAsPageTests(t)
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
viper.Set("baseURL", "http://bep.is/base/")
|
||||
|
||||
writeSource(t, filepath.Join("content", "sect", "_index.md"), `---
|
||||
writeLayoutsForNodeAsPageTests(t, fs)
|
||||
writeRegularPagesForNodeAsPageTests(t, fs)
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "sect", "_index.md"), `---
|
||||
title: MySection
|
||||
url: foo.html
|
||||
---
|
||||
My Section Content
|
||||
`)
|
||||
|
||||
viper.Set("paginate", 1)
|
||||
viper.Set("title", "Hugo Rocks!")
|
||||
viper.Set("baseURL", "http://bep.is/base/")
|
||||
h, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs})
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
require.NoError(t, h.Build(BuildCfg{}))
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), true, "My Section")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), true, "My Section")
|
||||
|
||||
s := h.Sites[0]
|
||||
|
||||
p := s.RegularPages[0]
|
||||
|
||||
|
@ -573,11 +600,11 @@ My Section Content
|
|||
|
||||
}
|
||||
|
||||
func writeRegularPagesForNodeAsPageTests(t *testing.T) {
|
||||
writeRegularPagesForNodeAsPageTestsWithLang(t, "")
|
||||
func writeRegularPagesForNodeAsPageTests(t *testing.T, fs *hugofs.Fs) {
|
||||
writeRegularPagesForNodeAsPageTestsWithLang(t, fs, "")
|
||||
}
|
||||
|
||||
func writeRegularPagesForNodeAsPageTestsWithLang(t *testing.T, lang string) {
|
||||
func writeRegularPagesForNodeAsPageTestsWithLang(t *testing.T, fs *hugofs.Fs, lang string) {
|
||||
var langStr string
|
||||
|
||||
if lang != "" {
|
||||
|
@ -597,7 +624,7 @@ func writeRegularPagesForNodeAsPageTestsWithLang(t *testing.T, lang string) {
|
|||
|
||||
}
|
||||
date = date.Add(-24 * time.Duration(i) * time.Hour)
|
||||
writeSource(t, filepath.Join("content", sect, fmt.Sprintf("regular%d.%smd", i, langStr)), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", sect, fmt.Sprintf("regular%d.%smd", i, langStr)), fmt.Sprintf(`---
|
||||
title: Page %02d
|
||||
lastMod : %q
|
||||
date : %q
|
||||
|
@ -612,7 +639,7 @@ Content Page %02d
|
|||
}
|
||||
}
|
||||
|
||||
func writeNodePagesForNodeAsPageTests(lang string, t *testing.T) {
|
||||
func writeNodePagesForNodeAsPageTests(t *testing.T, fs *hugofs.Fs, lang string) {
|
||||
|
||||
filename := "_index.md"
|
||||
|
||||
|
@ -624,7 +651,7 @@ func writeNodePagesForNodeAsPageTests(lang string, t *testing.T) {
|
|||
|
||||
date, _ := time.Parse(format, "2009-01-01")
|
||||
|
||||
writeSource(t, filepath.Join("content", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", filename), fmt.Sprintf(`---
|
||||
title: Home Sweet Home!
|
||||
date : %q
|
||||
lastMod : %q
|
||||
|
@ -632,14 +659,14 @@ lastMod : %q
|
|||
l-%s Home **Content!**
|
||||
`, date.Add(1*24*time.Hour).Format(time.RFC822), date.Add(2*24*time.Hour).Format(time.RFC822), lang))
|
||||
|
||||
writeSource(t, filepath.Join("content", "sect1", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", "sect1", filename), fmt.Sprintf(`---
|
||||
title: Section1
|
||||
date : %q
|
||||
lastMod : %q
|
||||
---
|
||||
Section1 **Content!**
|
||||
`, date.Add(3*24*time.Hour).Format(time.RFC822), date.Add(4*24*time.Hour).Format(time.RFC822)))
|
||||
writeSource(t, filepath.Join("content", "sect2", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", "sect2", filename), fmt.Sprintf(`---
|
||||
title: Section2
|
||||
date : %q
|
||||
lastMod : %q
|
||||
|
@ -647,7 +674,7 @@ lastMod : %q
|
|||
Section2 **Content!**
|
||||
`, date.Add(5*24*time.Hour).Format(time.RFC822), date.Add(6*24*time.Hour).Format(time.RFC822)))
|
||||
|
||||
writeSource(t, filepath.Join("content", "categories", "hugo", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", "categories", "hugo", filename), fmt.Sprintf(`---
|
||||
title: Taxonomy Hugo
|
||||
date : %q
|
||||
lastMod : %q
|
||||
|
@ -655,7 +682,7 @@ lastMod : %q
|
|||
Taxonomy Hugo **Content!**
|
||||
`, date.Add(7*24*time.Hour).Format(time.RFC822), date.Add(8*24*time.Hour).Format(time.RFC822)))
|
||||
|
||||
writeSource(t, filepath.Join("content", "categories", "web", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", "categories", "web", filename), fmt.Sprintf(`---
|
||||
title: Taxonomy Web
|
||||
date : %q
|
||||
lastMod : %q
|
||||
|
@ -663,7 +690,7 @@ lastMod : %q
|
|||
Taxonomy Web **Content!**
|
||||
`, date.Add(9*24*time.Hour).Format(time.RFC822), date.Add(10*24*time.Hour).Format(time.RFC822)))
|
||||
|
||||
writeSource(t, filepath.Join("content", "categories", "hugo-rocks", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", "categories", "hugo-rocks", filename), fmt.Sprintf(`---
|
||||
title: Taxonomy Hugo Rocks
|
||||
date : %q
|
||||
lastMod : %q
|
||||
|
@ -671,7 +698,7 @@ lastMod : %q
|
|||
Taxonomy Hugo Rocks **Content!**
|
||||
`, date.Add(11*24*time.Hour).Format(time.RFC822), date.Add(12*24*time.Hour).Format(time.RFC822)))
|
||||
|
||||
writeSource(t, filepath.Join("content", "categories", filename), fmt.Sprintf(`---
|
||||
writeSource(t, fs, filepath.Join("content", "categories", filename), fmt.Sprintf(`---
|
||||
title: Taxonomy Term Categories
|
||||
date : %q
|
||||
lastMod : %q
|
||||
|
@ -681,8 +708,8 @@ Taxonomy Term Categories **Content!**
|
|||
|
||||
}
|
||||
|
||||
func writeLayoutsForNodeAsPageTests(t *testing.T) {
|
||||
writeSource(t, filepath.Join("layouts", "index.html"), `
|
||||
func writeLayoutsForNodeAsPageTests(t *testing.T, fs *hugofs.Fs) {
|
||||
writeSource(t, fs, filepath.Join("layouts", "index.html"), `
|
||||
Index Title: {{ .Title }}
|
||||
Index Content: {{ .Content }}
|
||||
# Pages: {{ len .Data.Pages }}
|
||||
|
@ -699,14 +726,14 @@ Lastmod: {{ .Lastmod.Format "2006-01-02" }}
|
|||
GetPage: {{ with .Site.GetPage "section" "sect1" }}{{ .Title }}{{ end }}
|
||||
`)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), `
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), `
|
||||
Single Title: {{ .Title }}
|
||||
Single Content: {{ .Content }}
|
||||
Date: {{ .Date.Format "2006-01-02" }}
|
||||
Lastmod: {{ .Lastmod.Format "2006-01-02" }}
|
||||
`)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", "section.html"), `
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "section.html"), `
|
||||
Section Title: {{ .Title }}
|
||||
Section Content: {{ .Content }}
|
||||
# Pages: {{ len .Data.Pages }}
|
||||
|
@ -723,7 +750,7 @@ Lastmod: {{ .Lastmod.Format "2006-01-02" }}
|
|||
`)
|
||||
|
||||
// Taxonomy lists
|
||||
writeSource(t, filepath.Join("layouts", "_default", "taxonomy.html"), `
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "taxonomy.html"), `
|
||||
Taxonomy Title: {{ .Title }}
|
||||
Taxonomy Content: {{ .Content }}
|
||||
# Pages: {{ len .Data.Pages }}
|
||||
|
@ -740,7 +767,7 @@ Lastmod: {{ .Lastmod.Format "2006-01-02" }}
|
|||
`)
|
||||
|
||||
// Taxonomy terms
|
||||
writeSource(t, filepath.Join("layouts", "_default", "terms.html"), `
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "terms.html"), `
|
||||
Taxonomy Terms Title: {{ .Title }}
|
||||
Taxonomy Terms Content: {{ .Content }}
|
||||
{{ range $key, $value := .Data.Terms }}
|
||||
|
|
|
@ -38,7 +38,6 @@ import (
|
|||
|
||||
"github.com/spf13/cast"
|
||||
bp "github.com/spf13/hugo/bufferpool"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
@ -536,7 +535,7 @@ func (p *Page) getRenderingConfig() *helpers.Blackfriday {
|
|||
p.renderingConfig = helpers.NewBlackfriday(p.Language())
|
||||
|
||||
if err := mapstructure.Decode(pageParam, p.renderingConfig); err != nil {
|
||||
p.s.log.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error())
|
||||
p.s.Log.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error())
|
||||
}
|
||||
|
||||
})
|
||||
|
@ -556,7 +555,7 @@ func (s *Site) newPage(filename string) *Page {
|
|||
sections: sectionsFromFilename(filename),
|
||||
}
|
||||
|
||||
s.log.DEBUG.Println("Reading from", page.File.Path())
|
||||
s.Log.DEBUG.Println("Reading from", page.File.Path())
|
||||
return &page
|
||||
}
|
||||
|
||||
|
@ -683,7 +682,7 @@ func (s *Site) NewPage(name string) (*Page, error) {
|
|||
func (p *Page) ReadFrom(buf io.Reader) (int64, error) {
|
||||
// Parse for metadata & body
|
||||
if err := p.parse(buf); err != nil {
|
||||
p.s.log.ERROR.Print(err)
|
||||
p.s.Log.ERROR.Print(err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
@ -738,7 +737,7 @@ func (p *Page) getPermalink() *url.URL {
|
|||
p.pageURLInit.Do(func() {
|
||||
u, err := p.createPermalink()
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("Failed to create permalink for page %q: %s", p.FullFilePath(), err)
|
||||
p.s.Log.ERROR.Printf("Failed to create permalink for page %q: %s", p.FullFilePath(), err)
|
||||
p.permalink = new(url.URL)
|
||||
return
|
||||
}
|
||||
|
@ -759,16 +758,16 @@ func (p *Page) createPermalink() (*url.URL, error) {
|
|||
|
||||
if p.IsNode() {
|
||||
// No permalink config for nodes (currently)
|
||||
pURL := strings.TrimSpace(p.Site.pathSpec.URLize(p.URLPath.URL))
|
||||
pURL := strings.TrimSpace(p.s.PathSpec.URLize(p.URLPath.URL))
|
||||
pURL = p.addLangPathPrefix(pURL)
|
||||
pURL = p.Site.pathSpec.URLPrep(pURL)
|
||||
pURL = p.s.PathSpec.URLPrep(pURL)
|
||||
url := helpers.MakePermalink(baseURL, pURL)
|
||||
return url, nil
|
||||
}
|
||||
|
||||
dir := strings.TrimSpace(p.Site.pathSpec.MakePath(filepath.ToSlash(strings.ToLower(p.Source.Dir()))))
|
||||
pSlug := strings.TrimSpace(p.Site.pathSpec.URLize(p.Slug))
|
||||
pURL := strings.TrimSpace(p.Site.pathSpec.URLize(p.URLPath.URL))
|
||||
dir := strings.TrimSpace(p.s.PathSpec.MakePath(filepath.ToSlash(strings.ToLower(p.Source.Dir()))))
|
||||
pSlug := strings.TrimSpace(p.s.PathSpec.URLize(p.Slug))
|
||||
pURL := strings.TrimSpace(p.s.PathSpec.URLize(p.URLPath.URL))
|
||||
var permalink string
|
||||
var err error
|
||||
|
||||
|
@ -784,10 +783,10 @@ func (p *Page) createPermalink() (*url.URL, error) {
|
|||
}
|
||||
} else {
|
||||
if len(pSlug) > 0 {
|
||||
permalink = p.Site.pathSpec.URLPrep(path.Join(dir, p.Slug+"."+p.Extension()))
|
||||
permalink = p.s.PathSpec.URLPrep(path.Join(dir, p.Slug+"."+p.Extension()))
|
||||
} else {
|
||||
t := p.Source.TranslationBaseName()
|
||||
permalink = p.Site.pathSpec.URLPrep(path.Join(dir, (strings.TrimSpace(t) + "." + p.Extension())))
|
||||
permalink = p.s.PathSpec.URLPrep(path.Join(dir, (strings.TrimSpace(t) + "." + p.Extension())))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -953,22 +952,22 @@ func (p *Page) update(f interface{}) error {
|
|||
case "date":
|
||||
p.Date, err = cast.ToTimeE(v)
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("Failed to parse date '%v' in page %s", v, p.File.Path())
|
||||
p.s.Log.ERROR.Printf("Failed to parse date '%v' in page %s", v, p.File.Path())
|
||||
}
|
||||
case "lastmod":
|
||||
p.Lastmod, err = cast.ToTimeE(v)
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("Failed to parse lastmod '%v' in page %s", v, p.File.Path())
|
||||
p.s.Log.ERROR.Printf("Failed to parse lastmod '%v' in page %s", v, p.File.Path())
|
||||
}
|
||||
case "publishdate", "pubdate":
|
||||
p.PublishDate, err = cast.ToTimeE(v)
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("Failed to parse publishdate '%v' in page %s", v, p.File.Path())
|
||||
p.s.Log.ERROR.Printf("Failed to parse publishdate '%v' in page %s", v, p.File.Path())
|
||||
}
|
||||
case "expirydate", "unpublishdate":
|
||||
p.ExpiryDate, err = cast.ToTimeE(v)
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("Failed to parse expirydate '%v' in page %s", v, p.File.Path())
|
||||
p.s.Log.ERROR.Printf("Failed to parse expirydate '%v' in page %s", v, p.File.Path())
|
||||
}
|
||||
case "draft":
|
||||
draft = new(bool)
|
||||
|
@ -1040,7 +1039,7 @@ func (p *Page) update(f interface{}) error {
|
|||
|
||||
if draft != nil && published != nil {
|
||||
p.Draft = *draft
|
||||
p.s.log.ERROR.Printf("page %s has both draft and published settings in its frontmatter. Using draft.", p.File.Path())
|
||||
p.s.Log.ERROR.Printf("page %s has both draft and published settings in its frontmatter. Using draft.", p.File.Path())
|
||||
return ErrHasDraftAndPublished
|
||||
} else if draft != nil {
|
||||
p.Draft = *draft
|
||||
|
@ -1049,7 +1048,7 @@ func (p *Page) update(f interface{}) error {
|
|||
}
|
||||
|
||||
if p.Date.IsZero() && viper.GetBool("useModTimeAsFallback") {
|
||||
fi, err := hugofs.Source().Stat(filepath.Join(helpers.AbsPathify(viper.GetString("contentDir")), p.File.Path()))
|
||||
fi, err := p.s.Fs.Source.Stat(filepath.Join(helpers.AbsPathify(viper.GetString("contentDir")), p.File.Path()))
|
||||
if err == nil {
|
||||
p.Date = fi.ModTime()
|
||||
}
|
||||
|
@ -1109,7 +1108,7 @@ func (p *Page) getParam(key string, stringToLower bool) interface{} {
|
|||
return v
|
||||
}
|
||||
|
||||
p.s.log.ERROR.Printf("GetParam(\"%s\"): Unknown type %s\n", key, reflect.TypeOf(v))
|
||||
p.s.Log.ERROR.Printf("GetParam(\"%s\"): Unknown type %s\n", key, reflect.TypeOf(v))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1251,16 +1250,16 @@ func (p *Page) Menus() PageMenus {
|
|||
menus, err := cast.ToStringMapE(ms)
|
||||
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("unable to process menus for %q\n", p.Title)
|
||||
p.s.Log.ERROR.Printf("unable to process menus for %q\n", p.Title)
|
||||
}
|
||||
|
||||
for name, menu := range menus {
|
||||
menuEntry := MenuEntry{Name: p.LinkTitle(), URL: link, Weight: p.Weight, Menu: name}
|
||||
if menu != nil {
|
||||
p.s.log.DEBUG.Printf("found menu: %q, in %q\n", name, p.Title)
|
||||
p.s.Log.DEBUG.Printf("found menu: %q, in %q\n", name, p.Title)
|
||||
ime, err := cast.ToStringMapE(menu)
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("unable to process menus for %q: %s", p.Title, err)
|
||||
p.s.Log.ERROR.Printf("unable to process menus for %q: %s", p.Title, err)
|
||||
}
|
||||
|
||||
menuEntry.marshallMap(ime)
|
||||
|
@ -1283,7 +1282,7 @@ func (p *Page) Render(layout ...string) template.HTML {
|
|||
l = p.layouts()
|
||||
}
|
||||
|
||||
return p.s.tmpl.ExecuteTemplateToHTML(p, l...)
|
||||
return p.s.Tmpl.ExecuteTemplateToHTML(p, l...)
|
||||
}
|
||||
|
||||
func (p *Page) determineMarkupType() string {
|
||||
|
@ -1311,8 +1310,8 @@ func (p *Page) parse(reader io.Reader) error {
|
|||
meta, err := psr.Metadata()
|
||||
if meta != nil {
|
||||
if err != nil {
|
||||
p.s.log.ERROR.Printf("Error parsing page meta data for %s", p.File.Path())
|
||||
p.s.log.ERROR.Println(err)
|
||||
p.s.Log.ERROR.Printf("Error parsing page meta data for %s", p.File.Path())
|
||||
p.s.Log.ERROR.Println(err)
|
||||
return err
|
||||
}
|
||||
if err = p.update(meta); err != nil {
|
||||
|
@ -1381,12 +1380,12 @@ func (p *Page) saveSource(by []byte, inpath string, safe bool) (err error) {
|
|||
if !filepath.IsAbs(inpath) {
|
||||
inpath = helpers.AbsPathify(inpath)
|
||||
}
|
||||
p.s.log.INFO.Println("creating", inpath)
|
||||
p.s.Log.INFO.Println("creating", inpath)
|
||||
|
||||
if safe {
|
||||
err = helpers.SafeWriteToDisk(inpath, bytes.NewReader(by), hugofs.Source())
|
||||
err = helpers.SafeWriteToDisk(inpath, bytes.NewReader(by), p.s.Fs.Source)
|
||||
} else {
|
||||
err = helpers.WriteToDisk(inpath, bytes.NewReader(by), hugofs.Source())
|
||||
err = helpers.WriteToDisk(inpath, bytes.NewReader(by), p.s.Fs.Source)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -1455,7 +1454,7 @@ func (p *Page) TargetPath() (outfile string) {
|
|||
}
|
||||
|
||||
return p.addLangFilepathPrefix(filepath.Join(strings.ToLower(
|
||||
p.Site.pathSpec.MakePath(p.Source.Dir())), strings.TrimSpace(outfile)))
|
||||
p.s.PathSpec.MakePath(p.Source.Dir())), strings.TrimSpace(outfile)))
|
||||
}
|
||||
|
||||
// Pre render prepare steps
|
||||
|
@ -1466,14 +1465,13 @@ func (p *Page) prepareLayouts() error {
|
|||
var layouts []string
|
||||
if !p.IsRenderable() {
|
||||
self := "__" + p.TargetPath()
|
||||
_, err := p.Site.owner.tmpl.GetClone().New(self).Parse(string(p.Content))
|
||||
_, err := p.Site.owner.Tmpl.GetClone().New(self).Parse(string(p.Content))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layouts = append(layouts, self)
|
||||
} else {
|
||||
layouts = append(layouts, p.layouts()...)
|
||||
layouts = append(layouts, "_default/single.html")
|
||||
}
|
||||
p.layoutsCalculated = layouts
|
||||
}
|
||||
|
@ -1707,7 +1705,7 @@ func (p *Page) initLanguage() {
|
|||
|
||||
if language == nil {
|
||||
// It can be a file named stefano.chiodino.md.
|
||||
p.s.log.WARN.Printf("Page language (if it is that) not found in multilang setup: %s.", pageLang)
|
||||
p.s.Log.WARN.Printf("Page language (if it is that) not found in multilang setup: %s.", pageLang)
|
||||
language = ml.DefaultLang
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func TestPermalink(t *testing.T) {
|
||||
// TODO(bep) globals test siteinfo
|
||||
func _TestPermalink(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
tests := []struct {
|
||||
|
|
|
@ -26,7 +26,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -465,7 +467,12 @@ activity = "exam"
|
|||
Hi.
|
||||
`
|
||||
|
||||
var pageTestSite = NewSiteDefaultLang()
|
||||
func init() {
|
||||
testCommonResetState()
|
||||
pageTestSite, _ = NewSiteDefaultLang()
|
||||
}
|
||||
|
||||
var pageTestSite *Site
|
||||
|
||||
func checkError(t *testing.T, err error, expected string) {
|
||||
if err == nil {
|
||||
|
@ -606,6 +613,8 @@ func testAllMarkdownEnginesForPages(t *testing.T,
|
|||
|
||||
testCommonResetState()
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if settings != nil {
|
||||
for k, v := range settings {
|
||||
viper.Set(k, v)
|
||||
|
@ -625,14 +634,10 @@ func testAllMarkdownEnginesForPages(t *testing.T,
|
|||
}
|
||||
|
||||
for i := 0; i < len(fileSourcePairs); i += 2 {
|
||||
writeSource(t, filepath.Join(contentDir, fileSourcePairs[i]), fileSourcePairs[i+1])
|
||||
writeSource(t, fs, filepath.Join(contentDir, fileSourcePairs[i]), fileSourcePairs[i+1])
|
||||
}
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
require.Len(t, s.RegularPages, len(pageSources))
|
||||
|
||||
|
@ -738,11 +743,14 @@ func TestPageWithDelimiter(t *testing.T) {
|
|||
|
||||
// Issue #1076
|
||||
func TestPageWithDelimiterForMarkdownThatCrossesBorder(t *testing.T) {
|
||||
s := newSiteFromSources("simple.md", simplePageWithSummaryDelimiterAndMarkdownThatCrossesBorder)
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
testCommonResetState()
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "simple.md"), simplePageWithSummaryDelimiterAndMarkdownThatCrossesBorder)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
|
@ -759,16 +767,18 @@ func TestPageWithDelimiterForMarkdownThatCrossesBorder(t *testing.T) {
|
|||
|
||||
// Issue #2601
|
||||
func TestPageRawContent(t *testing.T) {
|
||||
s := newSiteFromSources("raw.md", `---
|
||||
testCommonResetState()
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "raw.md"), `---
|
||||
title: Raw
|
||||
---
|
||||
**Raw**`)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), `{{ .RawContent }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), `{{ .RawContent }}`)
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
p := s.RegularPages[0]
|
||||
|
@ -806,11 +816,12 @@ func TestPageWithEmbeddedScriptTag(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPageWithAdditionalExtension(t *testing.T) {
|
||||
s := newSiteFromSources("simple.md", simplePageWithAdditionalExtension)
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "simple.md"), simplePageWithAdditionalExtension)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{SkipRender: true})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
|
@ -820,11 +831,12 @@ func TestPageWithAdditionalExtension(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTableOfContents(t *testing.T) {
|
||||
s := newSiteFromSources("tocpage.md", pageWithToC)
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "tocpage.md"), pageWithToC)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{SkipRender: true})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
|
@ -850,11 +862,11 @@ func TestPageWithMoreTag(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPageWithDate(t *testing.T) {
|
||||
s := newSiteFromSources("simple.md", simplePageRFC3339Date)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeSource(t, fs, filepath.Join("content", "simple.md"), simplePageRFC3339Date)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{SkipRender: true})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
|
@ -1372,11 +1384,11 @@ func TestKind(t *testing.T) {
|
|||
func TestChompBOM(t *testing.T) {
|
||||
const utf8BOM = "\xef\xbb\xbf"
|
||||
|
||||
s := newSiteFromSources("simple.md", utf8BOM+simplePage)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeSource(t, fs, filepath.Join("content", "simple.md"), utf8BOM+simplePage)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{SkipRender: true})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
|
|
|
@ -279,7 +279,7 @@ func (p *Page) Paginator(options ...interface{}) (*Pager, error) {
|
|||
return
|
||||
}
|
||||
|
||||
pagers, err := paginatePages(p.Data["Pages"], pagerSize, p.sections...)
|
||||
pagers, err := paginatePages(p.s.PathSpec, p.Data["Pages"], pagerSize, p.sections...)
|
||||
|
||||
if err != nil {
|
||||
initError = err
|
||||
|
@ -322,7 +322,7 @@ func (p *Page) Paginate(seq interface{}, options ...interface{}) (*Pager, error)
|
|||
if p.paginator != nil {
|
||||
return
|
||||
}
|
||||
pagers, err := paginatePages(seq, pagerSize, p.sections...)
|
||||
pagers, err := paginatePages(p.s.PathSpec, seq, pagerSize, p.sections...)
|
||||
|
||||
if err != nil {
|
||||
initError = err
|
||||
|
@ -371,13 +371,13 @@ func resolvePagerSize(options ...interface{}) (int, error) {
|
|||
return pas, nil
|
||||
}
|
||||
|
||||
func paginatePages(seq interface{}, pagerSize int, sections ...string) (pagers, error) {
|
||||
func paginatePages(pathSpec *helpers.PathSpec, seq interface{}, pagerSize int, sections ...string) (pagers, error) {
|
||||
|
||||
if pagerSize <= 0 {
|
||||
return nil, errors.New("'paginate' configuration setting must be positive to paginate")
|
||||
}
|
||||
|
||||
urlFactory := newPaginationURLFactory(sections...)
|
||||
urlFactory := newPaginationURLFactory(pathSpec, sections...)
|
||||
|
||||
var paginator *paginator
|
||||
|
||||
|
@ -504,8 +504,7 @@ func newPaginator(elements []paginatedElement, total, size int, urlFactory pagin
|
|||
return p, nil
|
||||
}
|
||||
|
||||
func newPaginationURLFactory(pathElements ...string) paginationURLFactory {
|
||||
pathSpec := helpers.CurrentPathSpec()
|
||||
func newPaginationURLFactory(pathSpec *helpers.PathSpec, pathElements ...string) paginationURLFactory {
|
||||
|
||||
basePath := path.Join(pathElements...)
|
||||
|
||||
|
|
|
@ -19,10 +19,13 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSplitPages(t *testing.T) {
|
||||
|
@ -197,11 +200,22 @@ func TestPaginationURLFactory(t *testing.T) {
|
|||
testCommonResetState()
|
||||
|
||||
viper.Set("paginatePath", "zoo")
|
||||
unicode := newPaginationURLFactory("новости проекта")
|
||||
fooBar := newPaginationURLFactory("foo", "bar")
|
||||
|
||||
pathSpec := newTestPathSpec()
|
||||
|
||||
unicode := newPaginationURLFactory(pathSpec, "новости проекта")
|
||||
fooBar := newPaginationURLFactory(pathSpec, "foo", "bar")
|
||||
|
||||
assert.Equal(t, "/foo/bar/", fooBar(1))
|
||||
assert.Equal(t, "/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8-%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B0/zoo/4/", unicode(4))
|
||||
|
||||
unicoded := unicode(4)
|
||||
unicodedExpected := "/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8-%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B0/zoo/4/"
|
||||
|
||||
if unicoded != unicodedExpected {
|
||||
t.Fatal("Expected\n", unicodedExpected, "\nGot\n", unicoded)
|
||||
}
|
||||
|
||||
assert.Equal(t, "/foo/bar/zoo/12345/", fooBar(12345))
|
||||
|
||||
}
|
||||
|
@ -224,13 +238,13 @@ func doTestPaginator(t *testing.T, useViper bool) {
|
|||
viper.Set("paginate", -1)
|
||||
}
|
||||
pages := createTestPages(12)
|
||||
s := NewSiteDefaultLang()
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
n1 := s.newHomePage()
|
||||
n2 := s.newHomePage()
|
||||
n1.Data["Pages"] = pages
|
||||
|
||||
var paginator1 *Pager
|
||||
var err error
|
||||
|
||||
if useViper {
|
||||
paginator1, err = n1.Paginator()
|
||||
|
@ -261,9 +275,10 @@ func TestPaginatorWithNegativePaginate(t *testing.T) {
|
|||
testCommonResetState()
|
||||
|
||||
viper.Set("paginate", -1)
|
||||
s := NewSiteDefaultLang()
|
||||
_, err := s.newHomePage().Paginator()
|
||||
assert.NotNil(t, err)
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
_, err = s.newHomePage().Paginator()
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPaginate(t *testing.T) {
|
||||
|
@ -280,9 +295,11 @@ func TestPaginatorURL(t *testing.T) {
|
|||
viper.Set("paginate", 2)
|
||||
viper.Set("paginatePath", "testing")
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
// Issue #2177, do not double encode URLs
|
||||
writeSource(t, filepath.Join("content", "阅读", fmt.Sprintf("page%d.md", (i+1))),
|
||||
writeSource(t, fs, filepath.Join("content", "阅读", fmt.Sprintf("page%d.md", (i+1))),
|
||||
fmt.Sprintf(`---
|
||||
title: Page%d
|
||||
---
|
||||
|
@ -290,8 +307,8 @@ Conten%d
|
|||
`, (i+1), i+1))
|
||||
|
||||
}
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), "<html><body>{{.Content}}</body></html>")
|
||||
writeSource(t, filepath.Join("layouts", "_default", "list.html"),
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), "<html><body>{{.Content}}</body></html>")
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"),
|
||||
`
|
||||
<html><body>
|
||||
Count: {{ .Paginator.TotalNumberOfElements }}
|
||||
|
@ -301,11 +318,9 @@ Pages: {{ .Paginator.TotalPages }}
|
|||
{{ end }}
|
||||
</body></html>`)
|
||||
|
||||
if err := buildAndRenderSite(NewSiteDefaultLang()); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "阅读", "testing", "2", "index.html"), false, "2: /%E9%98%85%E8%AF%BB/testing/2/")
|
||||
assertFileContent(t, fs, filepath.Join("public", "阅读", "testing", "2", "index.html"), false, "2: /%E9%98%85%E8%AF%BB/testing/2/")
|
||||
|
||||
}
|
||||
|
||||
|
@ -318,12 +333,12 @@ func doTestPaginate(t *testing.T, useViper bool) {
|
|||
}
|
||||
|
||||
pages := createTestPages(6)
|
||||
s := NewSiteDefaultLang()
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
n1 := s.newHomePage()
|
||||
n2 := s.newHomePage()
|
||||
|
||||
var paginator1, paginator2 *Pager
|
||||
var err error
|
||||
|
||||
if useViper {
|
||||
paginator1, err = n1.Paginate(pages)
|
||||
|
@ -351,9 +366,10 @@ func doTestPaginate(t *testing.T, useViper bool) {
|
|||
}
|
||||
|
||||
func TestInvalidOptions(t *testing.T) {
|
||||
s := NewSiteDefaultLang()
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
n1 := s.newHomePage()
|
||||
_, err := n1.Paginate(createTestPages(1), 1, 2)
|
||||
_, err = n1.Paginate(createTestPages(1), 1, 2)
|
||||
assert.NotNil(t, err)
|
||||
_, err = n1.Paginator(1, 2)
|
||||
assert.NotNil(t, err)
|
||||
|
@ -365,19 +381,22 @@ func TestPaginateWithNegativePaginate(t *testing.T) {
|
|||
testCommonResetState()
|
||||
|
||||
viper.Set("paginate", -1)
|
||||
s := NewSiteDefaultLang()
|
||||
_, err := s.newHomePage().Paginate(createTestPages(2))
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
_, err = s.newHomePage().Paginate(createTestPages(2))
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestPaginatePages(t *testing.T) {
|
||||
groups, _ := createTestPages(31).GroupBy("Weight", "desc")
|
||||
pathSpec := newTestPathSpec()
|
||||
|
||||
for i, seq := range []interface{}{createTestPages(11), groups, WeightedPages{}, PageGroup{}, &Pages{}} {
|
||||
v, err := paginatePages(seq, 11, "t")
|
||||
v, err := paginatePages(pathSpec, seq, 11, "t")
|
||||
assert.NotNil(t, v, "Val %d", i)
|
||||
assert.Nil(t, err, "Err %d", i)
|
||||
}
|
||||
_, err := paginatePages(Site{}, 11, "t")
|
||||
_, err := paginatePages(pathSpec, Site{}, 11, "t")
|
||||
assert.NotNil(t, err)
|
||||
|
||||
}
|
||||
|
@ -387,11 +406,12 @@ func TestPaginatorFollowedByPaginateShouldFail(t *testing.T) {
|
|||
testCommonResetState()
|
||||
|
||||
viper.Set("paginate", 10)
|
||||
s := NewSiteDefaultLang()
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
n1 := s.newHomePage()
|
||||
n2 := s.newHomePage()
|
||||
|
||||
_, err := n1.Paginator()
|
||||
_, err = n1.Paginator()
|
||||
assert.Nil(t, err)
|
||||
_, err = n1.Paginate(createTestPages(2))
|
||||
assert.NotNil(t, err)
|
||||
|
@ -405,14 +425,15 @@ func TestPaginateFollowedByDifferentPaginateShouldFail(t *testing.T) {
|
|||
testCommonResetState()
|
||||
|
||||
viper.Set("paginate", 10)
|
||||
s := NewSiteDefaultLang()
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
n1 := s.newHomePage()
|
||||
n2 := s.newHomePage()
|
||||
|
||||
p1 := createTestPages(2)
|
||||
p2 := createTestPages(10)
|
||||
|
||||
_, err := n1.Paginate(p1)
|
||||
_, err = n1.Paginate(p1)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = n1.Paginate(p1)
|
||||
|
|
|
@ -150,14 +150,14 @@ func pageToPermalinkDate(p *Page, dateField string) (string, error) {
|
|||
func pageToPermalinkTitle(p *Page, _ string) (string, error) {
|
||||
// Page contains Node which has Title
|
||||
// (also contains URLPath which has Slug, sometimes)
|
||||
return p.Site.pathSpec.URLize(p.Title), nil
|
||||
return p.s.PathSpec.URLize(p.Title), nil
|
||||
}
|
||||
|
||||
// pageToPermalinkFilename returns the URL-safe form of the filename
|
||||
func pageToPermalinkFilename(p *Page, _ string) (string, error) {
|
||||
//var extension = p.Source.Ext
|
||||
//var name = p.Source.Path()[0 : len(p.Source.Path())-len(extension)]
|
||||
return p.Site.pathSpec.URLize(p.Source.TranslationBaseName()), nil
|
||||
return p.s.PathSpec.URLize(p.Source.TranslationBaseName()), nil
|
||||
}
|
||||
|
||||
// if the page has a slug, return the slug, else return the title
|
||||
|
@ -172,7 +172,7 @@ func pageToPermalinkSlugElseTitle(p *Page, a string) (string, error) {
|
|||
if strings.HasSuffix(p.Slug, "-") {
|
||||
p.Slug = p.Slug[0 : len(p.Slug)-1]
|
||||
}
|
||||
return p.Site.pathSpec.URLize(p.Slug), nil
|
||||
return p.s.PathSpec.URLize(p.Slug), nil
|
||||
}
|
||||
return pageToPermalinkTitle(p, a)
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
package hugolib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -32,28 +32,16 @@ const robotTxtTemplate = `User-agent: Googlebot
|
|||
func TestRobotsTXTOutput(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
|
||||
viper.Set("baseURL", "http://auth/bub/")
|
||||
viper.Set("enableRobotsTXT", true)
|
||||
|
||||
s := &Site{
|
||||
Source: &source.InMemorySource{ByteSource: weightedSources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if err := buildAndRenderSite(s, "robots.txt", robotTxtTemplate); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeSource(t, fs, filepath.Join("layouts", "robots.txt"), robotTxtTemplate)
|
||||
writeSourcesToSource(t, "content", fs, weightedSources...)
|
||||
|
||||
robotsFile, err := hugofs.Destination().Open("public/robots.txt")
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to locate: robots.txt")
|
||||
}
|
||||
assertFileContent(t, fs, "public/robots.txt", true, "User-agent: Googlebot")
|
||||
|
||||
robots := helpers.ReaderToBytes(robotsFile)
|
||||
if !bytes.HasPrefix(robots, []byte("User-agent: Googlebot")) {
|
||||
t.Errorf("Robots file should start with 'User-agent: Googlebot'. %s", robots)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -28,19 +30,19 @@ func TestRSSOutput(t *testing.T) {
|
|||
viper.Set("rssURI", rssURI)
|
||||
viper.Set("title", "RSSTest")
|
||||
|
||||
for _, s := range weightedSources {
|
||||
writeSource(t, filepath.Join("content", "sect", s.Name), string(s.Content))
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range weightedSources {
|
||||
writeSource(t, fs, filepath.Join("content", "sect", src.Name), string(src.Content))
|
||||
}
|
||||
|
||||
if err := buildAndRenderSite(NewSiteDefaultLang()); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
// Home RSS
|
||||
assertFileContent(t, filepath.Join("public", rssURI), true, "<?xml", "rss version", "RSSTest")
|
||||
assertFileContent(t, fs, filepath.Join("public", rssURI), true, "<?xml", "rss version", "RSSTest")
|
||||
// Section RSS
|
||||
assertFileContent(t, filepath.Join("public", "sect", rssURI), true, "<?xml", "rss version", "Sects on RSSTest")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", rssURI), true, "<?xml", "rss version", "Sects on RSSTest")
|
||||
// Taxonomy RSS
|
||||
assertFileContent(t, filepath.Join("public", "categories", "hugo", rssURI), true, "<?xml", "rss version", "Hugo on RSSTest")
|
||||
assertFileContent(t, fs, filepath.Join("public", "categories", "hugo", rssURI), true, "<?xml", "rss version", "Hugo on RSSTest")
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
|
||||
bp "github.com/spf13/hugo/bufferpool"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/tpl"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
)
|
||||
|
||||
// ShortcodeWithPage is the "." context in a shortcode template.
|
||||
|
@ -211,10 +211,10 @@ const innerCleanupRegexp = `\A<p>(.*)</p>\n\z`
|
|||
const innerCleanupExpand = "$1"
|
||||
|
||||
func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page) string {
|
||||
tmpl := getShortcodeTemplate(sc.name, p.s.tmpl)
|
||||
tmpl := getShortcodeTemplate(sc.name, p.s.Tmpl)
|
||||
|
||||
if tmpl == nil {
|
||||
p.s.log.ERROR.Printf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
|
||||
p.s.Log.ERROR.Printf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
|
||||
return ""
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page) string {
|
|||
case shortcode:
|
||||
inner += renderShortcode(innerData.(shortcode), data, p)
|
||||
default:
|
||||
p.s.log.ERROR.Printf("Illegal state on shortcode rendering of '%s' in page %s. Illegal type in inner data: %s ",
|
||||
p.s.Log.ERROR.Printf("Illegal state on shortcode rendering of '%s' in page %s. Illegal type in inner data: %s ",
|
||||
sc.name, p.BaseFileName(), reflect.TypeOf(innerData))
|
||||
return ""
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ func extractAndRenderShortcodes(stringToParse string, p *Page) (string, map[stri
|
|||
|
||||
if err != nil {
|
||||
// try to render what we have whilst logging the error
|
||||
p.s.log.ERROR.Println(err.Error())
|
||||
p.s.Log.ERROR.Println(err.Error())
|
||||
}
|
||||
|
||||
// Save for reuse
|
||||
|
@ -398,7 +398,7 @@ Loop:
|
|||
sc.inner = append(sc.inner, currItem.val)
|
||||
case tScName:
|
||||
sc.name = currItem.val
|
||||
tmpl := getShortcodeTemplate(sc.name, p.s.tmpl)
|
||||
tmpl := getShortcodeTemplate(sc.name, p.s.Tmpl)
|
||||
|
||||
if tmpl == nil {
|
||||
return sc, fmt.Errorf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
|
||||
|
@ -566,7 +566,7 @@ func replaceShortcodeTokens(source []byte, prefix string, replacements map[strin
|
|||
return source, nil
|
||||
}
|
||||
|
||||
func getShortcodeTemplate(name string, t tpl.Template) *template.Template {
|
||||
func getShortcodeTemplate(name string, t tplapi.Template) *template.Template {
|
||||
if x := t.Lookup("shortcodes/" + name + ".html"); x != nil {
|
||||
return x
|
||||
}
|
||||
|
@ -584,9 +584,8 @@ func renderShortcodeWithPage(tmpl *template.Template, data *ShortcodeWithPage) s
|
|||
err := tmpl.Execute(buffer, data)
|
||||
isInnerShortcodeCache.RUnlock()
|
||||
if err != nil {
|
||||
// TODO(bep) globals
|
||||
data.Page.s.log.ERROR.Println("error processing shortcode", tmpl.Name(), "\n ERR:", err)
|
||||
data.Page.s.log.WARN.Println(data)
|
||||
data.Page.s.Log.ERROR.Println("error processing shortcode", tmpl.Name(), "\n ERR:", err)
|
||||
data.Page.s.Log.WARN.Println(data)
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
|
|
@ -22,49 +22,52 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/target"
|
||||
"github.com/spf13/hugo/tpl"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TODO(bep) remove
|
||||
func pageFromString(in, filename string, withTemplate ...func(templ tpl.Template) error) (*Page, error) {
|
||||
func pageFromString(in, filename string, withTemplate ...func(templ tplapi.Template) error) (*Page, error) {
|
||||
s := pageTestSite
|
||||
if len(withTemplate) > 0 {
|
||||
// Have to create a new site
|
||||
s = NewSiteDefaultLang(withTemplate...)
|
||||
var err error
|
||||
s, err = NewSiteDefaultLang(withTemplate...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.NewPageFrom(strings.NewReader(in), filename)
|
||||
}
|
||||
|
||||
func CheckShortCodeMatch(t *testing.T, input, expected string, withTemplate func(templ tpl.Template) error) {
|
||||
func CheckShortCodeMatch(t *testing.T, input, expected string, withTemplate func(templ tplapi.Template) error) {
|
||||
CheckShortCodeMatchAndError(t, input, expected, withTemplate, false)
|
||||
}
|
||||
|
||||
func CheckShortCodeMatchAndError(t *testing.T, input, expected string, withTemplate func(templ tpl.Template) error, expectError bool) {
|
||||
func CheckShortCodeMatchAndError(t *testing.T, input, expected string, withTemplate func(templ tplapi.Template) error, expectError bool) {
|
||||
testCommonResetState()
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
// Need some front matter, see https://github.com/spf13/hugo/issues/2337
|
||||
contentFile := `---
|
||||
title: "Title"
|
||||
---
|
||||
` + input
|
||||
|
||||
writeSource(t, "content/simple.md", contentFile)
|
||||
writeSource(t, fs, "content/simple.md", contentFile)
|
||||
|
||||
h, err := newHugoSitesDefaultLanguage()
|
||||
h, err := NewHugoSitesFromConfiguration(deps.DepsCfg{Fs: fs, WithTemplate: withTemplate})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create sites: %s", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Len(t, h.Sites, 1)
|
||||
|
||||
cfg := BuildCfg{SkipRender: true, withTemplate: withTemplate}
|
||||
|
||||
err = h.Build(cfg)
|
||||
err = h.Build(BuildCfg{})
|
||||
|
||||
if err != nil && !expectError {
|
||||
t.Fatalf("Shortcode rendered error %s.", err)
|
||||
|
@ -89,7 +92,7 @@ title: "Title"
|
|||
|
||||
func TestShortcodeGoFuzzReports(t *testing.T) {
|
||||
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tplapi.Template) error {
|
||||
return templ.AddInternalShortcode("sc.html", `foo`)
|
||||
})
|
||||
|
||||
|
@ -124,7 +127,7 @@ func TestNonSC(t *testing.T) {
|
|||
|
||||
// Issue #929
|
||||
func TestHyphenatedSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("hyphenated-video.html", `Playing Video {{ .Get 0 }}`)
|
||||
return nil
|
||||
}
|
||||
|
@ -134,7 +137,7 @@ func TestHyphenatedSC(t *testing.T) {
|
|||
|
||||
// Issue #1753
|
||||
func TestNoTrailingNewline(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("a.html", `{{ .Get 0 }}`)
|
||||
return nil
|
||||
}
|
||||
|
@ -143,7 +146,7 @@ func TestNoTrailingNewline(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPositionalParamSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("video.html", `Playing Video {{ .Get 0 }}`)
|
||||
return nil
|
||||
}
|
||||
|
@ -156,7 +159,7 @@ func TestPositionalParamSC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPositionalParamIndexOutOfBounds(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("video.html", `Playing Video {{ .Get 1 }}`)
|
||||
return nil
|
||||
}
|
||||
|
@ -166,7 +169,7 @@ func TestPositionalParamIndexOutOfBounds(t *testing.T) {
|
|||
// some repro issues for panics in Go Fuzz testing
|
||||
|
||||
func TestNamedParamSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("img.html", `<img{{ with .Get "src" }} src="{{.}}"{{end}}{{with .Get "class"}} class="{{.}}"{{end}}>`)
|
||||
return nil
|
||||
}
|
||||
|
@ -180,7 +183,7 @@ func TestNamedParamSC(t *testing.T) {
|
|||
|
||||
// Issue #2294
|
||||
func TestNestedNamedMissingParam(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("acc.html", `<div class="acc">{{ .Inner }}</div>`)
|
||||
tem.AddInternalShortcode("div.html", `<div {{with .Get "class"}} class="{{ . }}"{{ end }}>{{ .Inner }}</div>`)
|
||||
tem.AddInternalShortcode("div2.html", `<div {{with .Get 0}} class="{{ . }}"{{ end }}>{{ .Inner }}</div>`)
|
||||
|
@ -192,7 +195,7 @@ func TestNestedNamedMissingParam(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIsNamedParamsSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("byposition.html", `<div id="{{ .Get 0 }}">`)
|
||||
tem.AddInternalShortcode("byname.html", `<div id="{{ .Get "id" }}">`)
|
||||
tem.AddInternalShortcode("ifnamedparams.html", `<div id="{{ if .IsNamedParams }}{{ .Get "id" }}{{ else }}{{ .Get 0 }}{{end}}">`)
|
||||
|
@ -207,7 +210,7 @@ func TestIsNamedParamsSC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInnerSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
|
||||
return nil
|
||||
}
|
||||
|
@ -217,7 +220,7 @@ func TestInnerSC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInnerSCWithMarkdown(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
|
||||
return nil
|
||||
}
|
||||
|
@ -230,7 +233,7 @@ func TestInnerSCWithMarkdown(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInnerSCWithAndWithoutMarkdown(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
|
||||
return nil
|
||||
}
|
||||
|
@ -259,7 +262,7 @@ func TestEmbeddedSC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNestedSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("scn1.html", `<div>Outer, inner is {{ .Inner }}</div>`)
|
||||
tem.AddInternalShortcode("scn2.html", `<div>SC2</div>`)
|
||||
return nil
|
||||
|
@ -270,7 +273,7 @@ func TestNestedSC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNestedComplexSC(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("row.html", `-row-{{ .Inner}}-rowStop-`)
|
||||
tem.AddInternalShortcode("column.html", `-col-{{.Inner }}-colStop-`)
|
||||
tem.AddInternalShortcode("aside.html", `-aside-{{ .Inner }}-asideStop-`)
|
||||
|
@ -285,7 +288,7 @@ func TestNestedComplexSC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParentShortcode(t *testing.T) {
|
||||
wt := func(tem tpl.Template) error {
|
||||
wt := func(tem tplapi.Template) error {
|
||||
tem.AddInternalShortcode("r1.html", `1: {{ .Get "pr1" }} {{ .Inner }}`)
|
||||
tem.AddInternalShortcode("r2.html", `2: {{ .Parent.Get "pr1" }}{{ .Get "pr2" }} {{ .Inner }}`)
|
||||
tem.AddInternalShortcode("r3.html", `3: {{ .Parent.Parent.Get "pr1" }}{{ .Parent.Get "pr2" }}{{ .Get "pr3" }} {{ .Inner }}`)
|
||||
|
@ -382,7 +385,7 @@ func TestExtractShortcodes(t *testing.T) {
|
|||
fmt.Sprintf("Hello %sworld%s. And that's it.", testScPlaceholderRegexp, testScPlaceholderRegexp), ""},
|
||||
} {
|
||||
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
|
||||
p, _ := pageFromString(simplePage, "simple.md", func(templ tplapi.Template) error {
|
||||
templ.AddInternalShortcode("tag.html", `tag`)
|
||||
templ.AddInternalShortcode("sc1.html", `sc1`)
|
||||
templ.AddInternalShortcode("sc2.html", `sc2`)
|
||||
|
@ -471,7 +474,7 @@ func TestShortcodesInSite(t *testing.T) {
|
|||
expected string
|
||||
}{
|
||||
{"sect/doc1.md", `a{{< b >}}c`,
|
||||
filepath.FromSlash("sect/doc1/index.html"), "<p>abc</p>\n"},
|
||||
filepath.FromSlash("public/sect/doc1/index.html"), "<p>abc</p>\n"},
|
||||
// Issue #1642: Multiple shortcodes wrapped in P
|
||||
// Deliberately forced to pass even if they maybe shouldn't.
|
||||
{"sect/doc2.md", `a
|
||||
|
@ -481,7 +484,7 @@ func TestShortcodesInSite(t *testing.T) {
|
|||
{{< d >}}
|
||||
|
||||
e`,
|
||||
filepath.FromSlash("sect/doc2/index.html"),
|
||||
filepath.FromSlash("public/sect/doc2/index.html"),
|
||||
"<p>a</p>\n\n<p>b<br />\nc\nd</p>\n\n<p>e</p>\n"},
|
||||
{"sect/doc3.md", `a
|
||||
|
||||
|
@ -491,7 +494,7 @@ e`,
|
|||
{{< d >}}
|
||||
|
||||
e`,
|
||||
filepath.FromSlash("sect/doc3/index.html"),
|
||||
filepath.FromSlash("public/sect/doc3/index.html"),
|
||||
"<p>a</p>\n\n<p>b<br />\nc</p>\n\nd\n\n<p>e</p>\n"},
|
||||
{"sect/doc4.md", `a
|
||||
{{< b >}}
|
||||
|
@ -510,22 +513,22 @@ e`,
|
|||
|
||||
|
||||
`,
|
||||
filepath.FromSlash("sect/doc4/index.html"),
|
||||
filepath.FromSlash("public/sect/doc4/index.html"),
|
||||
"<p>a\nb\nb\nb\nb\nb</p>\n"},
|
||||
// #2192 #2209: Shortcodes in markdown headers
|
||||
{"sect/doc5.md", `# {{< b >}}
|
||||
## {{% c %}}`,
|
||||
filepath.FromSlash("sect/doc5/index.html"), "\n\n<h1 id=\"hahahugoshortcode-1hbhb\">b</h1>\n\n<h2 id=\"hahahugoshortcode-2hbhb\">c</h2>\n"},
|
||||
filepath.FromSlash("public/sect/doc5/index.html"), "\n\n<h1 id=\"hahahugoshortcode-1hbhb\">b</h1>\n\n<h2 id=\"hahahugoshortcode-2hbhb\">c</h2>\n"},
|
||||
// #2223 pygments
|
||||
{"sect/doc6.md", "\n```bash\nb: {{< b >}} c: {{% c %}}\n```\n",
|
||||
filepath.FromSlash("sect/doc6/index.html"),
|
||||
filepath.FromSlash("public/sect/doc6/index.html"),
|
||||
"b: b c: c\n</code></pre></div>\n"},
|
||||
// #2249
|
||||
{"sect/doc7.ad", `_Shortcodes:_ *b: {{< b >}} c: {{% c %}}*`,
|
||||
filepath.FromSlash("sect/doc7/index.html"),
|
||||
filepath.FromSlash("public/sect/doc7/index.html"),
|
||||
"<div class=\"paragraph\">\n<p><em>Shortcodes:</em> <strong>b: b c: c</strong></p>\n</div>\n"},
|
||||
{"sect/doc8.rst", `**Shortcodes:** *b: {{< b >}} c: {{% c %}}*`,
|
||||
filepath.FromSlash("sect/doc8/index.html"),
|
||||
filepath.FromSlash("public/sect/doc8/index.html"),
|
||||
"<div class=\"document\">\n\n\n<p><strong>Shortcodes:</strong> <em>b: b c: c</em></p>\n</div>"},
|
||||
{"sect/doc9.mmark", `
|
||||
---
|
||||
|
@ -534,7 +537,7 @@ menu:
|
|||
parent: 'parent'
|
||||
---
|
||||
**Shortcodes:** *b: {{< b >}} c: {{% c %}}*`,
|
||||
filepath.FromSlash("sect/doc9/index.html"),
|
||||
filepath.FromSlash("public/sect/doc9/index.html"),
|
||||
"<p><strong>Shortcodes:</strong> <em>b: b c: c</em></p>\n"},
|
||||
// Issue #1229: Menus not available in shortcode.
|
||||
{"sect/doc10.md", `---
|
||||
|
@ -545,7 +548,7 @@ tags:
|
|||
- Menu
|
||||
---
|
||||
**Menus:** {{< menu >}}`,
|
||||
filepath.FromSlash("sect/doc10/index.html"),
|
||||
filepath.FromSlash("public/sect/doc10/index.html"),
|
||||
"<p><strong>Menus:</strong> 1</p>\n"},
|
||||
// Issue #2323: Taxonomies not available in shortcode.
|
||||
{"sect/doc11.md", `---
|
||||
|
@ -553,7 +556,7 @@ tags:
|
|||
- Bugs
|
||||
---
|
||||
**Tags:** {{< tags >}}`,
|
||||
filepath.FromSlash("sect/doc11/index.html"),
|
||||
filepath.FromSlash("public/sect/doc11/index.html"),
|
||||
"<p><strong>Tags:</strong> 2</p>\n"},
|
||||
}
|
||||
|
||||
|
@ -563,13 +566,7 @@ tags:
|
|||
sources[i] = source.ByteSource{Name: filepath.FromSlash(test.contentPath), Content: []byte(test.content)}
|
||||
}
|
||||
|
||||
s := &Site{
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: false}},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
|
||||
addTemplates := func(templ tpl.Template) error {
|
||||
addTemplates := func(templ tplapi.Template) error {
|
||||
templ.AddTemplate("_default/single.html", "{{.Content}}")
|
||||
|
||||
templ.AddInternalShortcode("b.html", `b`)
|
||||
|
@ -582,15 +579,11 @@ tags:
|
|||
|
||||
}
|
||||
|
||||
sites, err := newHugoSites(DepsCfg{}, s)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeSourcesToSource(t, "content", fs, sources...)
|
||||
|
||||
if err = sites.Build(BuildCfg{withTemplate: addTemplates}); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
buildSingleSite(t, deps.DepsCfg{WithTemplate: addTemplates, Fs: fs}, BuildCfg{})
|
||||
|
||||
for _, test := range tests {
|
||||
if strings.HasSuffix(test.contentPath, ".ad") && !helpers.HasAsciidoc() {
|
||||
|
@ -604,17 +597,7 @@ tags:
|
|||
continue
|
||||
}
|
||||
|
||||
file, err := hugofs.Destination().Open(test.outFile)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Did not find %s in target: %s", test.outFile, err)
|
||||
}
|
||||
|
||||
content := helpers.ReaderToString(file)
|
||||
|
||||
if !strings.Contains(content, test.expected) {
|
||||
t.Fatalf("%s content expected:\n%q\ngot:\n%q", test.outFile, test.expected, content)
|
||||
}
|
||||
assertFileContent(t, fs, test.outFile, true, test.expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
292
hugolib/site.go
292
hugolib/site.go
|
@ -35,12 +35,14 @@ import (
|
|||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cast"
|
||||
bp "github.com/spf13/hugo/bufferpool"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/parser"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/target"
|
||||
"github.com/spf13/hugo/tpl"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
"github.com/spf13/hugo/transform"
|
||||
"github.com/spf13/nitro"
|
||||
"github.com/spf13/viper"
|
||||
|
@ -106,57 +108,81 @@ type Site struct {
|
|||
Language *helpers.Language
|
||||
|
||||
// Logger etc.
|
||||
*deps
|
||||
*deps.Deps `json:"-"`
|
||||
}
|
||||
|
||||
// reset returns a new Site prepared for rebuild.
|
||||
func (s *Site) reset() *Site {
|
||||
return &Site{deps: s.deps, Language: s.Language, owner: s.owner, PageCollections: newPageCollections()}
|
||||
return &Site{Deps: s.Deps, owner: s.owner, PageCollections: newPageCollections()}
|
||||
}
|
||||
|
||||
// newSite creates a new site in the given language.
|
||||
func newSite(lang *helpers.Language, deps *deps, withTemplate ...func(templ tpl.Template) error) *Site {
|
||||
// newSite creates a new site with the given configuration.
|
||||
func newSite(cfg deps.DepsCfg) (*Site, error) {
|
||||
c := newPageCollections()
|
||||
// TODO(bep) globals
|
||||
viper.Set("currentContentLanguage", lang)
|
||||
|
||||
if deps == nil {
|
||||
depsCfg := DepsCfg{WithTemplate: withTemplate}
|
||||
deps = newDeps(depsCfg)
|
||||
if cfg.Language == nil {
|
||||
cfg.Language = helpers.NewDefaultLanguage()
|
||||
}
|
||||
|
||||
return &Site{deps: deps, Language: lang, PageCollections: c, Info: newSiteInfo(siteBuilderCfg{pageCollections: c, language: lang})}
|
||||
s := &Site{PageCollections: c, Language: cfg.Language}
|
||||
|
||||
s.Info = newSiteInfo(siteBuilderCfg{s: s, pageCollections: c, language: s.Language})
|
||||
return s, nil
|
||||
|
||||
}
|
||||
|
||||
// NewSite creates a new site with the given dependency configuration.
|
||||
// The site will have a template system loaded and ready to use.
|
||||
// Note: This is mainly used in single site tests.
|
||||
func NewSite(cfg deps.DepsCfg) (*Site, error) {
|
||||
s, err := newSite(cfg)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := applyDepsIfNeeded(cfg, s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// NewSiteDefaultLang creates a new site in the default language.
|
||||
func NewSiteDefaultLang(withTemplate ...func(templ tpl.Template) error) *Site {
|
||||
return newSite(helpers.NewDefaultLanguage(), nil, withTemplate...)
|
||||
// The site will have a template system loaded and ready to use.
|
||||
// Note: This is mainly used in single site tests.
|
||||
func NewSiteDefaultLang(withTemplate ...func(templ tplapi.Template) error) (*Site, error) {
|
||||
return newSiteForLang(helpers.NewDefaultLanguage(), withTemplate...)
|
||||
}
|
||||
|
||||
// Convenience func used in tests.
|
||||
func newSiteFromSources(pathContentPairs ...string) *Site {
|
||||
if len(pathContentPairs)%2 != 0 {
|
||||
panic("pathContentPairs must come in pairs")
|
||||
// NewSiteDefaultLang creates a new site in the default language.
|
||||
// The site will have a template system loaded and ready to use.
|
||||
// Note: This is mainly used in single site tests.
|
||||
func NewEnglishSite(withTemplate ...func(templ tplapi.Template) error) (*Site, error) {
|
||||
return newSiteForLang(helpers.NewLanguage("en"), withTemplate...)
|
||||
}
|
||||
|
||||
// NewSiteDefaultLang creates a new site in the default language.
|
||||
func newSiteForLang(lang *helpers.Language, withTemplate ...func(templ tplapi.Template) error) (*Site, error) {
|
||||
withTemplates := func(templ tplapi.Template) error {
|
||||
for _, wt := range withTemplate {
|
||||
if err := wt(templ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
cfg := deps.DepsCfg{WithTemplate: withTemplates, Language: lang}
|
||||
s, err := newSite(cfg)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sources := make([]source.ByteSource, 0)
|
||||
|
||||
for i := 0; i < len(pathContentPairs); i += 2 {
|
||||
path := pathContentPairs[i]
|
||||
content := pathContentPairs[i+1]
|
||||
sources = append(sources, source.ByteSource{Name: filepath.FromSlash(path), Content: []byte(content)})
|
||||
}
|
||||
|
||||
lang := helpers.NewDefaultLanguage()
|
||||
|
||||
return &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
PageCollections: newPageCollections(),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
Language: lang,
|
||||
Info: newSiteInfo(siteBuilderCfg{language: lang}),
|
||||
if err := applyDepsIfNeeded(cfg, s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type targetList struct {
|
||||
|
@ -202,14 +228,13 @@ type SiteInfo struct {
|
|||
Data *map[string]interface{}
|
||||
|
||||
owner *HugoSites
|
||||
s *Site
|
||||
multilingual *Multilingual
|
||||
Language *helpers.Language
|
||||
LanguagePrefix string
|
||||
Languages helpers.Languages
|
||||
defaultContentLanguageInSubdir bool
|
||||
sectionPagesMenu string
|
||||
|
||||
pathSpec *helpers.PathSpec
|
||||
}
|
||||
|
||||
func (s *SiteInfo) String() string {
|
||||
|
@ -219,15 +244,19 @@ func (s *SiteInfo) String() string {
|
|||
// Used in tests.
|
||||
|
||||
type siteBuilderCfg struct {
|
||||
language *helpers.Language
|
||||
language *helpers.Language
|
||||
// TOD(bep) globals fs
|
||||
s *Site
|
||||
fs *hugofs.Fs
|
||||
pageCollections *PageCollections
|
||||
baseURL string
|
||||
}
|
||||
|
||||
// TODO(bep) globals get rid of this
|
||||
func newSiteInfo(cfg siteBuilderCfg) SiteInfo {
|
||||
return SiteInfo{
|
||||
s: cfg.s,
|
||||
BaseURL: template.URL(cfg.baseURL),
|
||||
pathSpec: helpers.NewPathSpecFromConfig(cfg.language),
|
||||
multilingual: newMultiLingualForLanguage(cfg.language),
|
||||
PageCollections: cfg.pageCollections,
|
||||
}
|
||||
|
@ -498,7 +527,7 @@ type whatChanged struct {
|
|||
// It returns whetever the content source was changed.
|
||||
func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
||||
|
||||
s.log.DEBUG.Printf("Rebuild for events %q", events)
|
||||
s.Log.DEBUG.Printf("Rebuild for events %q", events)
|
||||
|
||||
s.timerStep("initialize rebuild")
|
||||
|
||||
|
@ -533,8 +562,25 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
|||
}
|
||||
|
||||
if len(tmplChanged) > 0 {
|
||||
s.prepTemplates(nil)
|
||||
s.owner.tmpl.PrintErrors()
|
||||
sites := s.owner.Sites
|
||||
first := sites[0]
|
||||
|
||||
// TOD(bep) globals clean
|
||||
if err := first.Deps.LoadTemplates(); err != nil {
|
||||
s.Log.ERROR.Println(err)
|
||||
}
|
||||
|
||||
s.Tmpl.PrintErrors()
|
||||
|
||||
for i := 1; i < len(sites); i++ {
|
||||
site := sites[i]
|
||||
var err error
|
||||
site.Deps, err = first.Deps.ForLanguage(site.Language)
|
||||
if err != nil {
|
||||
return whatChanged{}, err
|
||||
}
|
||||
}
|
||||
|
||||
s.timerStep("template prep")
|
||||
}
|
||||
|
||||
|
@ -544,7 +590,7 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
|||
|
||||
if len(i18nChanged) > 0 {
|
||||
if err := s.readI18nSources(); err != nil {
|
||||
s.log.ERROR.Println(err)
|
||||
s.Log.ERROR.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,7 +641,7 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
|||
// it's been updated
|
||||
if ev.Op&fsnotify.Rename == fsnotify.Rename {
|
||||
// If the file is still on disk, it's only been updated, if it's not, it's been moved
|
||||
if ex, err := afero.Exists(hugofs.Source(), ev.Name); !ex || err != nil {
|
||||
if ex, err := afero.Exists(s.Fs.Source, ev.Name); !ex || err != nil {
|
||||
path, _ := helpers.GetRelativePath(ev.Name, s.getContentDir(ev.Name))
|
||||
s.removePageByPath(path)
|
||||
continue
|
||||
|
@ -613,7 +659,7 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
|||
file, err := s.reReadFile(ev.Name)
|
||||
|
||||
if err != nil {
|
||||
s.log.ERROR.Println("Error reading file", ev.Name, ";", err)
|
||||
s.Log.ERROR.Println("Error reading file", ev.Name, ";", err)
|
||||
}
|
||||
|
||||
if file != nil {
|
||||
|
@ -647,7 +693,7 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
|||
for i := 0; i < 2; i++ {
|
||||
err := <-errs
|
||||
if err != nil {
|
||||
s.log.ERROR.Println(err)
|
||||
s.Log.ERROR.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -660,29 +706,8 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
|
|||
|
||||
}
|
||||
|
||||
func (s *Site) prepTemplates(withTemplate func(templ tpl.Template) error) error {
|
||||
|
||||
wt := func(tmpl tpl.Template) error {
|
||||
// TODO(bep) global error handling
|
||||
tmpl.LoadTemplates(s.absLayoutDir())
|
||||
if s.hasTheme() {
|
||||
tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
|
||||
}
|
||||
if withTemplate != nil {
|
||||
if err := withTemplate(tmpl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
s.refreshTemplates(wt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Site) loadData(sources []source.Input) (err error) {
|
||||
s.log.DEBUG.Printf("Load Data from %q", sources)
|
||||
s.Log.DEBUG.Printf("Load Data from %q", sources)
|
||||
s.Data = make(map[string]interface{})
|
||||
var current map[string]interface{}
|
||||
for _, currentSource := range sources {
|
||||
|
@ -717,7 +742,7 @@ func (s *Site) loadData(sources []source.Input) (err error) {
|
|||
// this warning could happen if
|
||||
// 1. A theme uses the same key; the main data folder wins
|
||||
// 2. A sub folder uses the same key: the sub folder wins
|
||||
s.log.WARN.Printf("Data for key '%s' in path '%s' is overridden in subfolder", key, r.Path())
|
||||
s.Log.WARN.Printf("Data for key '%s' in path '%s' is overridden in subfolder", key, r.Path())
|
||||
}
|
||||
data[key] = value
|
||||
}
|
||||
|
@ -740,21 +765,21 @@ func (s *Site) readData(f *source.File) (interface{}, error) {
|
|||
case "toml":
|
||||
return parser.HandleTOMLMetaData(f.Bytes())
|
||||
default:
|
||||
s.log.WARN.Printf("Data not supported for extension '%s'", f.Extension())
|
||||
s.Log.WARN.Printf("Data not supported for extension '%s'", f.Extension())
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Site) readI18nSources() error {
|
||||
|
||||
i18nSources := []source.Input{&source.Filesystem{Base: s.absI18nDir()}}
|
||||
i18nSources := []source.Input{source.NewFilesystem(s.Fs, s.absI18nDir())}
|
||||
|
||||
themeI18nDir, err := helpers.GetThemeI18nDirPath()
|
||||
themeI18nDir, err := s.PathSpec.GetThemeI18nDirPath()
|
||||
if err == nil {
|
||||
i18nSources = []source.Input{&source.Filesystem{Base: themeI18nDir}, i18nSources[0]}
|
||||
i18nSources = []source.Input{source.NewFilesystem(s.Fs, themeI18nDir), i18nSources[0]}
|
||||
}
|
||||
|
||||
if err = loadI18n(i18nSources); err != nil {
|
||||
if err = s.loadI18n(i18nSources); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -763,12 +788,12 @@ func (s *Site) readI18nSources() error {
|
|||
|
||||
func (s *Site) readDataFromSourceFS() error {
|
||||
dataSources := make([]source.Input, 0, 2)
|
||||
dataSources = append(dataSources, &source.Filesystem{Base: s.absDataDir()})
|
||||
dataSources = append(dataSources, source.NewFilesystem(s.Fs, s.absDataDir()))
|
||||
|
||||
// have to be last - duplicate keys in earlier entries will win
|
||||
themeDataDir, err := helpers.GetThemeDataDirPath()
|
||||
themeDataDir, err := s.PathSpec.GetThemeDataDirPath()
|
||||
if err == nil {
|
||||
dataSources = append(dataSources, &source.Filesystem{Base: themeDataDir})
|
||||
dataSources = append(dataSources, source.NewFilesystem(s.Fs, themeDataDir))
|
||||
}
|
||||
|
||||
err = s.loadData(dataSources)
|
||||
|
@ -781,10 +806,7 @@ func (s *Site) process(config BuildCfg) (err error) {
|
|||
if err = s.initialize(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.prepTemplates(config.withTemplate)
|
||||
s.owner.tmpl.PrintErrors()
|
||||
s.timerStep("initialize & template prep")
|
||||
s.timerStep("initialize")
|
||||
|
||||
if err = s.readDataFromSourceFS(); err != nil {
|
||||
return
|
||||
|
@ -817,7 +839,6 @@ func (s *Site) setCurrentLanguageConfig() error {
|
|||
viper.Set("currentContentLanguage", s.Language)
|
||||
// Cache the current config.
|
||||
helpers.InitConfigProviderForCurrentContentLanguage()
|
||||
s.Info.pathSpec = helpers.CurrentPathSpec()
|
||||
return tpl.SetTranslateLang(s.Language)
|
||||
}
|
||||
|
||||
|
@ -873,7 +894,7 @@ func (s *Site) initialize() (err error) {
|
|||
|
||||
// May be supplied in tests.
|
||||
if s.Source != nil && len(s.Source.Files()) > 0 {
|
||||
s.log.DEBUG.Println("initialize: Source is already set")
|
||||
s.Log.DEBUG.Println("initialize: Source is already set")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -883,10 +904,7 @@ func (s *Site) initialize() (err error) {
|
|||
|
||||
staticDir := helpers.AbsPathify(viper.GetString("staticDir") + "/")
|
||||
|
||||
s.Source = &source.Filesystem{
|
||||
AvoidPaths: []string{staticDir},
|
||||
Base: s.absContentDir(),
|
||||
}
|
||||
s.Source = source.NewFilesystem(s.Fs, s.absContentDir(), staticDir)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -897,7 +915,7 @@ func (s *SiteInfo) HomeAbsURL() string {
|
|||
if s.IsMultiLingual() {
|
||||
base = s.Language.Lang
|
||||
}
|
||||
return s.pathSpec.AbsURL(base, false)
|
||||
return s.owner.AbsURL(base, false)
|
||||
}
|
||||
|
||||
// SitemapAbsURL is a convenience method giving the absolute URL to the sitemap.
|
||||
|
@ -966,7 +984,7 @@ func (s *Site) initializeSiteInfo() {
|
|||
Permalinks: permalinks,
|
||||
Data: &s.Data,
|
||||
owner: s.owner,
|
||||
pathSpec: helpers.NewPathSpecFromConfig(lang),
|
||||
s: s,
|
||||
}
|
||||
|
||||
s.Info.RSSLink = s.Info.permalinkStr(lang.GetString("rssURI"))
|
||||
|
@ -1081,11 +1099,11 @@ func (s *Site) getRealDir(base, path string) string {
|
|||
return base
|
||||
}
|
||||
|
||||
realDir, err := helpers.GetRealPath(hugofs.Source(), base)
|
||||
realDir, err := helpers.GetRealPath(s.Fs.Source, base)
|
||||
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
s.log.ERROR.Printf("Failed to get real path for %s: %s", path, err)
|
||||
s.Log.ERROR.Printf("Failed to get real path for %s: %s", path, err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -1102,7 +1120,7 @@ func (s *Site) absPublishDir() string {
|
|||
}
|
||||
|
||||
func (s *Site) checkDirectories() (err error) {
|
||||
if b, _ := helpers.DirExists(s.absContentDir(), hugofs.Source()); !b {
|
||||
if b, _ := helpers.DirExists(s.absContentDir(), s.Fs.Source); !b {
|
||||
return errors.New("No source directory found, expecting to find it at " + s.absContentDir())
|
||||
}
|
||||
return
|
||||
|
@ -1110,10 +1128,10 @@ func (s *Site) checkDirectories() (err error) {
|
|||
|
||||
// reReadFile resets file to be read from disk again
|
||||
func (s *Site) reReadFile(absFilePath string) (*source.File, error) {
|
||||
s.log.INFO.Println("rereading", absFilePath)
|
||||
s.Log.INFO.Println("rereading", absFilePath)
|
||||
var file *source.File
|
||||
|
||||
reader, err := source.NewLazyFileReader(hugofs.Source(), absFilePath)
|
||||
reader, err := source.NewLazyFileReader(s.Fs.Source, absFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1131,7 +1149,7 @@ func (s *Site) readPagesFromSource() chan error {
|
|||
panic(fmt.Sprintf("s.Source not set %s", s.absContentDir()))
|
||||
}
|
||||
|
||||
s.log.DEBUG.Printf("Read %d pages from source", len(s.Source.Files()))
|
||||
s.Log.DEBUG.Printf("Read %d pages from source", len(s.Source.Files()))
|
||||
|
||||
errs := make(chan error)
|
||||
if len(s.Source.Files()) < 1 {
|
||||
|
@ -1231,7 +1249,7 @@ func readSourceFile(s *Site, file *source.File, results chan<- HandledResult) {
|
|||
if h != nil {
|
||||
h.Read(file, s, results)
|
||||
} else {
|
||||
s.log.ERROR.Println("Unsupported File Type", file.Path())
|
||||
s.Log.ERROR.Println("Unsupported File Type", file.Path())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1372,17 +1390,17 @@ func (s *Site) getMenusFromConfig() Menus {
|
|||
for name, menu := range menus {
|
||||
m, err := cast.ToSliceE(menu)
|
||||
if err != nil {
|
||||
s.log.ERROR.Printf("unable to process menus in site config\n")
|
||||
s.log.ERROR.Println(err)
|
||||
s.Log.ERROR.Printf("unable to process menus in site config\n")
|
||||
s.Log.ERROR.Println(err)
|
||||
} else {
|
||||
for _, entry := range m {
|
||||
s.log.DEBUG.Printf("found menu: %q, in site config\n", name)
|
||||
s.Log.DEBUG.Printf("found menu: %q, in site config\n", name)
|
||||
|
||||
menuEntry := MenuEntry{Menu: name}
|
||||
ime, err := cast.ToStringMapE(entry)
|
||||
if err != nil {
|
||||
s.log.ERROR.Printf("unable to process menus in site config\n")
|
||||
s.log.ERROR.Println(err)
|
||||
s.Log.ERROR.Printf("unable to process menus in site config\n")
|
||||
s.Log.ERROR.Println(err)
|
||||
}
|
||||
|
||||
menuEntry.marshallMap(ime)
|
||||
|
@ -1407,7 +1425,7 @@ func (s *SiteInfo) createNodeMenuEntryURL(in string) string {
|
|||
}
|
||||
// make it match the nodes
|
||||
menuEntryURL := in
|
||||
menuEntryURL = helpers.SanitizeURLKeepTrailingSlash(s.pathSpec.URLize(menuEntryURL))
|
||||
menuEntryURL = helpers.SanitizeURLKeepTrailingSlash(s.s.PathSpec.URLize(menuEntryURL))
|
||||
if !s.canonifyURLs {
|
||||
menuEntryURL = helpers.AddContextRoot(string(s.BaseURL), menuEntryURL)
|
||||
}
|
||||
|
@ -1454,7 +1472,7 @@ func (s *Site) assembleMenus() {
|
|||
|
||||
for name, me := range p.Menus() {
|
||||
if _, ok := flat[twoD{name, me.KeyName()}]; ok {
|
||||
s.log.ERROR.Printf("Two or more menu items have the same name/identifier in Menu %q: %q.\nRename or set an unique identifier.\n", name, me.KeyName())
|
||||
s.Log.ERROR.Printf("Two or more menu items have the same name/identifier in Menu %q: %q.\nRename or set an unique identifier.\n", name, me.KeyName())
|
||||
continue
|
||||
}
|
||||
flat[twoD{name, me.KeyName()}] = me
|
||||
|
@ -1490,6 +1508,13 @@ func (s *Site) assembleMenus() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Site) getTaxonomyKey(key string) string {
|
||||
if s.Info.preserveTaxonomyNames {
|
||||
// Keep as is
|
||||
return key
|
||||
}
|
||||
return s.PathSpec.MakePathSanitized(key)
|
||||
}
|
||||
func (s *Site) assembleTaxonomies() {
|
||||
s.Taxonomies = make(TaxonomyList)
|
||||
s.taxonomiesPluralSingular = make(map[string]string)
|
||||
|
@ -1497,7 +1522,7 @@ func (s *Site) assembleTaxonomies() {
|
|||
|
||||
taxonomies := s.Language.GetStringMapString("taxonomies")
|
||||
|
||||
s.log.INFO.Printf("found taxonomies: %#v\n", taxonomies)
|
||||
s.Log.INFO.Printf("found taxonomies: %#v\n", taxonomies)
|
||||
|
||||
for singular, plural := range taxonomies {
|
||||
s.Taxonomies[plural] = make(Taxonomy)
|
||||
|
@ -1513,21 +1538,21 @@ func (s *Site) assembleTaxonomies() {
|
|||
if v, ok := vals.([]string); ok {
|
||||
for _, idx := range v {
|
||||
x := WeightedPage{weight.(int), p}
|
||||
s.Taxonomies[plural].add(idx, x, s.Info.preserveTaxonomyNames)
|
||||
s.Taxonomies[plural].add(s.getTaxonomyKey(idx), x)
|
||||
if s.Info.preserveTaxonomyNames {
|
||||
// Need to track the original
|
||||
s.taxonomiesOrigKey[fmt.Sprintf("%s-%s", plural, kp(idx))] = idx
|
||||
s.taxonomiesOrigKey[fmt.Sprintf("%s-%s", plural, s.PathSpec.MakePathSanitized(idx))] = idx
|
||||
}
|
||||
}
|
||||
} else if v, ok := vals.(string); ok {
|
||||
x := WeightedPage{weight.(int), p}
|
||||
s.Taxonomies[plural].add(v, x, s.Info.preserveTaxonomyNames)
|
||||
s.Taxonomies[plural].add(s.getTaxonomyKey(v), x)
|
||||
if s.Info.preserveTaxonomyNames {
|
||||
// Need to track the original
|
||||
s.taxonomiesOrigKey[fmt.Sprintf("%s-%s", plural, kp(v))] = v
|
||||
s.taxonomiesOrigKey[fmt.Sprintf("%s-%s", plural, s.PathSpec.MakePathSanitized(v))] = v
|
||||
}
|
||||
} else {
|
||||
s.log.ERROR.Printf("Invalid %s in %s\n", plural, p.File.Path())
|
||||
s.Log.ERROR.Printf("Invalid %s in %s\n", plural, p.File.Path())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1564,7 +1589,7 @@ func (s *Site) assembleSections() {
|
|||
sectionPages := s.findPagesByKind(KindSection)
|
||||
|
||||
for i, p := range regularPages {
|
||||
s.Sections.add(p.Section(), WeightedPage{regularPages[i].Weight, regularPages[i]}, s.Info.preserveTaxonomyNames)
|
||||
s.Sections.add(s.getTaxonomyKey(p.Section()), WeightedPage{regularPages[i].Weight, regularPages[i]})
|
||||
}
|
||||
|
||||
// Add sections without regular pages, but with a content page
|
||||
|
@ -1665,18 +1690,18 @@ func (s *Site) appendThemeTemplates(in []string) []string {
|
|||
// Stats prints Hugo builds stats to the console.
|
||||
// This is what you see after a successful hugo build.
|
||||
func (s *Site) Stats() {
|
||||
s.log.FEEDBACK.Printf("Built site for language %s:\n", s.Language.Lang)
|
||||
s.log.FEEDBACK.Println(s.draftStats())
|
||||
s.log.FEEDBACK.Println(s.futureStats())
|
||||
s.log.FEEDBACK.Println(s.expiredStats())
|
||||
s.log.FEEDBACK.Printf("%d regular pages created\n", len(s.RegularPages))
|
||||
s.log.FEEDBACK.Printf("%d other pages created\n", (len(s.Pages) - len(s.RegularPages)))
|
||||
s.log.FEEDBACK.Printf("%d non-page files copied\n", len(s.Files))
|
||||
s.log.FEEDBACK.Printf("%d paginator pages created\n", s.Info.paginationPageCount)
|
||||
s.Log.FEEDBACK.Printf("Built site for language %s:\n", s.Language.Lang)
|
||||
s.Log.FEEDBACK.Println(s.draftStats())
|
||||
s.Log.FEEDBACK.Println(s.futureStats())
|
||||
s.Log.FEEDBACK.Println(s.expiredStats())
|
||||
s.Log.FEEDBACK.Printf("%d regular pages created\n", len(s.RegularPages))
|
||||
s.Log.FEEDBACK.Printf("%d other pages created\n", (len(s.Pages) - len(s.RegularPages)))
|
||||
s.Log.FEEDBACK.Printf("%d non-page files copied\n", len(s.Files))
|
||||
s.Log.FEEDBACK.Printf("%d paginator pages created\n", s.Info.paginationPageCount)
|
||||
taxonomies := s.Language.GetStringMapString("taxonomies")
|
||||
|
||||
for _, pl := range taxonomies {
|
||||
s.log.FEEDBACK.Printf("%d %s created\n", len(s.Taxonomies[pl]), pl)
|
||||
s.Log.FEEDBACK.Printf("%d %s created\n", len(s.Taxonomies[pl]), pl)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1701,11 +1726,11 @@ func (s *SiteInfo) permalink(plink string) string {
|
|||
func (s *SiteInfo) permalinkStr(plink string) string {
|
||||
return helpers.MakePermalink(
|
||||
viper.GetString("baseURL"),
|
||||
s.pathSpec.URLizeAndPrep(plink)).String()
|
||||
s.s.PathSpec.URLizeAndPrep(plink)).String()
|
||||
}
|
||||
|
||||
func (s *Site) renderAndWriteXML(name string, dest string, d interface{}, layouts ...string) error {
|
||||
s.log.DEBUG.Printf("Render XML for %q to %q", name, dest)
|
||||
s.Log.DEBUG.Printf("Render XML for %q to %q", name, dest)
|
||||
renderBuffer := bp.GetBuffer()
|
||||
defer bp.PutBuffer(renderBuffer)
|
||||
renderBuffer.WriteString("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n")
|
||||
|
@ -1797,7 +1822,7 @@ func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layou
|
|||
|
||||
if outBuffer.Len() == 0 {
|
||||
|
||||
s.log.WARN.Printf("%s is rendered empty\n", dest)
|
||||
s.Log.WARN.Printf("%s is rendered empty\n", dest)
|
||||
if dest == "/" {
|
||||
debugAddend := ""
|
||||
if !viper.GetBool("verbose") {
|
||||
|
@ -1829,7 +1854,8 @@ Your rendered home page is blank: /index.html is zero-length
|
|||
func (s *Site) renderForLayouts(name string, d interface{}, w io.Writer, layouts ...string) error {
|
||||
layout, found := s.findFirstLayout(layouts...)
|
||||
if !found {
|
||||
s.log.WARN.Printf("Unable to locate layout for %s: %s\n", name, layouts)
|
||||
s.Log.WARN.Printf("[%s] Unable to locate layout for %s: %s\n", s.Language.Lang, name, layouts)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1850,7 +1876,7 @@ func (s *Site) renderForLayouts(name string, d interface{}, w io.Writer, layouts
|
|||
|
||||
func (s *Site) findFirstLayout(layouts ...string) (string, bool) {
|
||||
for _, layout := range layouts {
|
||||
if s.owner.tmpl.Lookup(layout) != nil {
|
||||
if s.Tmpl.Lookup(layout) != nil {
|
||||
return layout, true
|
||||
}
|
||||
}
|
||||
|
@ -1860,7 +1886,7 @@ func (s *Site) findFirstLayout(layouts ...string) (string, bool) {
|
|||
func (s *Site) renderThing(d interface{}, layout string, w io.Writer) error {
|
||||
|
||||
// If the template doesn't exist, then return, but leave the Writer open
|
||||
if templ := s.owner.tmpl.Lookup(layout); templ != nil {
|
||||
if templ := s.Tmpl.Lookup(layout); templ != nil {
|
||||
return templ.Execute(w, d)
|
||||
}
|
||||
return fmt.Errorf("Layout not found: %s", layout)
|
||||
|
@ -1893,6 +1919,9 @@ func (s *Site) languageAliasTarget() target.AliasPublisher {
|
|||
}
|
||||
|
||||
func (s *Site) initTargetList() {
|
||||
if s.Fs == nil {
|
||||
panic("Must have Fs")
|
||||
}
|
||||
s.targetListInit.Do(func() {
|
||||
langDir := ""
|
||||
if s.Language.Lang != s.Info.multilingual.DefaultLang.Lang || s.Info.defaultContentLanguageInSubdir {
|
||||
|
@ -1900,6 +1929,7 @@ func (s *Site) initTargetList() {
|
|||
}
|
||||
if s.targets.page == nil {
|
||||
s.targets.page = &target.PagePub{
|
||||
Fs: s.Fs,
|
||||
PublishDir: s.absPublishDir(),
|
||||
UglyURLs: viper.GetBool("uglyURLs"),
|
||||
LangDir: langDir,
|
||||
|
@ -1907,6 +1937,7 @@ func (s *Site) initTargetList() {
|
|||
}
|
||||
if s.targets.pageUgly == nil {
|
||||
s.targets.pageUgly = &target.PagePub{
|
||||
Fs: s.Fs,
|
||||
PublishDir: s.absPublishDir(),
|
||||
UglyURLs: true,
|
||||
LangDir: langDir,
|
||||
|
@ -1914,17 +1945,20 @@ func (s *Site) initTargetList() {
|
|||
}
|
||||
if s.targets.file == nil {
|
||||
s.targets.file = &target.Filesystem{
|
||||
Fs: s.Fs,
|
||||
PublishDir: s.absPublishDir(),
|
||||
}
|
||||
}
|
||||
if s.targets.alias == nil {
|
||||
s.targets.alias = &target.HTMLRedirectAlias{
|
||||
Fs: s.Fs,
|
||||
PublishDir: s.absPublishDir(),
|
||||
Templates: s.owner.tmpl.Lookup("alias.html"),
|
||||
Templates: s.Tmpl.Lookup("alias.html"),
|
||||
}
|
||||
}
|
||||
if s.targets.languageAlias == nil {
|
||||
s.targets.languageAlias = &target.HTMLRedirectAlias{
|
||||
Fs: s.Fs,
|
||||
PublishDir: s.absPublishDir(),
|
||||
AllowRoot: true,
|
||||
}
|
||||
|
@ -1933,12 +1967,12 @@ func (s *Site) initTargetList() {
|
|||
}
|
||||
|
||||
func (s *Site) writeDestFile(path string, reader io.Reader) (err error) {
|
||||
s.log.DEBUG.Println("creating file:", path)
|
||||
s.Log.DEBUG.Println("creating file:", path)
|
||||
return s.fileTarget().Publish(path, reader)
|
||||
}
|
||||
|
||||
func (s *Site) writeDestPage(path string, publisher target.Publisher, reader io.Reader) (err error) {
|
||||
s.log.DEBUG.Println("creating page:", path)
|
||||
s.Log.DEBUG.Println("creating page:", path)
|
||||
return publisher.Publish(path, reader)
|
||||
}
|
||||
|
||||
|
@ -1956,11 +1990,11 @@ func (s *Site) publishDestAlias(aliasPublisher target.AliasPublisher, path, perm
|
|||
}
|
||||
permalink, err = helpers.GetRelativePath(permalink, path)
|
||||
if err != nil {
|
||||
s.log.ERROR.Println("Failed to make a RelativeURL alias:", path, "redirecting to", permalink)
|
||||
s.Log.ERROR.Println("Failed to make a RelativeURL alias:", path, "redirecting to", permalink)
|
||||
}
|
||||
permalink = filepath.ToSlash(permalink)
|
||||
}
|
||||
s.log.DEBUG.Println("creating alias:", path, "redirecting to", permalink)
|
||||
s.Log.DEBUG.Println("creating alias:", path, "redirecting to", permalink)
|
||||
return aliasPublisher.Publish(path, permalink, p)
|
||||
}
|
||||
|
||||
|
@ -2051,7 +2085,7 @@ func (s *Site) newHomePage() *Page {
|
|||
}
|
||||
|
||||
func (s *Site) setPageURLs(p *Page, in string) {
|
||||
p.URLPath.URL = s.Info.pathSpec.URLizeAndPrep(in)
|
||||
p.URLPath.URL = s.PathSpec.URLizeAndPrep(in)
|
||||
p.URLPath.Permalink = s.Info.permalink(p.URLPath.URL)
|
||||
p.RSSLink = template.HTML(s.Info.permalink(in + ".xml"))
|
||||
}
|
||||
|
@ -2063,7 +2097,7 @@ func (s *Site) newTaxonomyPage(plural, key string) *Page {
|
|||
p.sections = []string{plural, key}
|
||||
|
||||
if s.Info.preserveTaxonomyNames {
|
||||
key = s.Info.pathSpec.MakePathSanitized(key)
|
||||
key = s.PathSpec.MakePathSanitized(key)
|
||||
}
|
||||
|
||||
if s.Info.preserveTaxonomyNames {
|
||||
|
|
|
@ -16,6 +16,11 @@ package hugolib
|
|||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
)
|
||||
|
||||
// Issue #1123
|
||||
|
@ -23,9 +28,15 @@ import (
|
|||
// May be smart to run with: -timeout 4000ms
|
||||
func TestEncodePage(t *testing.T) {
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
// borrowed from menu_test.go
|
||||
s := createTestSite(menuPageSources)
|
||||
testSiteSetup(s, t)
|
||||
for _, src := range menuPageSources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
_, err := json.Marshal(s)
|
||||
check(t, err)
|
||||
|
|
|
@ -66,7 +66,7 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
|
|||
for p := range pages {
|
||||
targetPath := p.TargetPath()
|
||||
layouts := p.layouts()
|
||||
s.log.DEBUG.Printf("Render %s to %q with layouts %q", p.Kind, targetPath, layouts)
|
||||
s.Log.DEBUG.Printf("Render %s to %q with layouts %q", p.Kind, targetPath, layouts)
|
||||
|
||||
if err := s.renderAndWritePage("page "+p.FullFilePath(), targetPath, p, s.appendThemeTemplates(layouts)...); err != nil {
|
||||
results <- err
|
||||
|
@ -88,7 +88,7 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
|
|||
// renderPaginator must be run after the owning Page has been rendered.
|
||||
func (s *Site) renderPaginator(p *Page) error {
|
||||
if p.paginator != nil {
|
||||
s.log.DEBUG.Printf("Render paginator for page %q", p.Path())
|
||||
s.Log.DEBUG.Printf("Render paginator for page %q", p.Path())
|
||||
paginatePath := helpers.Config().GetString("paginatePath")
|
||||
|
||||
// write alias for page 1
|
||||
|
@ -267,14 +267,14 @@ func (s *Site) renderAliases() error {
|
|||
if s.owner.multilingual.enabled() {
|
||||
mainLang := s.owner.multilingual.DefaultLang.Lang
|
||||
if s.Info.defaultContentLanguageInSubdir {
|
||||
mainLangURL := s.Info.pathSpec.AbsURL(mainLang, false)
|
||||
s.log.DEBUG.Printf("Write redirect to main language %s: %s", mainLang, mainLangURL)
|
||||
mainLangURL := s.PathSpec.AbsURL(mainLang, false)
|
||||
s.Log.DEBUG.Printf("Write redirect to main language %s: %s", mainLang, mainLangURL)
|
||||
if err := s.publishDestAlias(s.languageAliasTarget(), "/", mainLangURL, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
mainLangURL := s.Info.pathSpec.AbsURL("", false)
|
||||
s.log.DEBUG.Printf("Write redirect to main language %s: %s", mainLang, mainLangURL)
|
||||
mainLangURL := s.PathSpec.AbsURL("", false)
|
||||
s.Log.DEBUG.Printf("Write redirect to main language %s: %s", mainLang, mainLangURL)
|
||||
if err := s.publishDestAlias(s.languageAliasTarget(), mainLang, mainLangURL, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -18,16 +18,15 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bep/inflect"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
|
||||
"github.com/spf13/hugo/target"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -47,37 +46,6 @@ func init() {
|
|||
testMode = true
|
||||
}
|
||||
|
||||
// Issue #1797
|
||||
func TestReadPagesFromSourceWithEmptySource(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
viper.Set("defaultExtension", "html")
|
||||
viper.Set("verbose", true)
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
|
||||
sources := []source.ByteSource{}
|
||||
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: true}},
|
||||
}
|
||||
|
||||
var err error
|
||||
d := time.Second * 2
|
||||
ticker := time.NewTicker(d)
|
||||
select {
|
||||
case err = <-s.readPagesFromSource():
|
||||
break
|
||||
case <-ticker.C:
|
||||
err = fmt.Errorf("ReadPagesFromSource() never returns in %s", d.String())
|
||||
}
|
||||
ticker.Stop()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to read source: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func pageMust(p *Page, err error) *Page {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -86,11 +54,12 @@ func pageMust(p *Page, err error) *Page {
|
|||
}
|
||||
|
||||
func TestDegenerateRenderThingMissingTemplate(t *testing.T) {
|
||||
s := newSiteFromSources("content/a/file.md", pageSimpleTitle)
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "a", "file.md"), pageSimpleTitle)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
require.Len(t, s.RegularPages, 1)
|
||||
|
||||
|
@ -104,12 +73,15 @@ func TestDegenerateRenderThingMissingTemplate(t *testing.T) {
|
|||
|
||||
func TestRenderWithInvalidTemplate(t *testing.T) {
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
if err := buildAndRenderSite(s, "missing", templateMissingFunc); err != nil {
|
||||
t.Fatalf("Got build error: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
errCount := s.log.LogCountForLevelsGreaterThanorEqualTo(jww.LevelError)
|
||||
writeSource(t, fs, filepath.Join("content", "foo.md"), "foo")
|
||||
|
||||
withTemplate := createWithTemplateFromNameValues("missing", templateMissingFunc)
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs, WithTemplate: withTemplate}, BuildCfg{})
|
||||
|
||||
errCount := s.Log.LogCountForLevelsGreaterThanorEqualTo(jww.LevelError)
|
||||
|
||||
// TODO(bep) globals clean up the template error handling
|
||||
// The template errors are stored in a slice etc. so we get 4 log entries
|
||||
|
@ -122,7 +94,6 @@ func TestRenderWithInvalidTemplate(t *testing.T) {
|
|||
func TestDraftAndFutureRender(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("sect/doc1.md"), Content: []byte("---\ntitle: doc1\ndraft: true\npublishdate: \"2414-05-29\"\n---\n# doc1\n*some content*")},
|
||||
{Name: filepath.FromSlash("sect/doc2.md"), Content: []byte("---\ntitle: doc2\ndraft: true\npublishdate: \"2012-05-29\"\n---\n# doc2\n*some content*")},
|
||||
|
@ -131,17 +102,14 @@ func TestDraftAndFutureRender(t *testing.T) {
|
|||
}
|
||||
|
||||
siteSetup := func(t *testing.T) *Site {
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
|
||||
return s
|
||||
return buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
}
|
||||
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
|
@ -183,24 +151,20 @@ func TestDraftAndFutureRender(t *testing.T) {
|
|||
func TestFutureExpirationRender(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("sect/doc3.md"), Content: []byte("---\ntitle: doc1\nexpirydate: \"2400-05-29\"\n---\n# doc1\n*some content*")},
|
||||
{Name: filepath.FromSlash("sect/doc4.md"), Content: []byte("---\ntitle: doc2\nexpirydate: \"2000-05-29\"\n---\n# doc2\n*some content*")},
|
||||
}
|
||||
|
||||
siteSetup := func(t *testing.T) *Site {
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
|
||||
return s
|
||||
return buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
}
|
||||
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
|
@ -282,16 +246,18 @@ THE END.`, refShortcode)),
|
|||
},
|
||||
}
|
||||
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: uglyURLs}},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
}
|
||||
|
||||
if err := buildAndRenderSite(s, "_default/single.html", "{{.Content}}"); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
s := buildSingleSite(
|
||||
t,
|
||||
deps.DepsCfg{
|
||||
Fs: fs,
|
||||
WithTemplate: createWithTemplateFromNameValues("_default/single.html", "{{.Content}}")},
|
||||
BuildCfg{})
|
||||
|
||||
if len(s.RegularPages) != 3 {
|
||||
t.Fatalf("Expected 3 got %d pages", len(s.AllPages))
|
||||
|
@ -301,23 +267,14 @@ THE END.`, refShortcode)),
|
|||
doc string
|
||||
expected string
|
||||
}{
|
||||
{filepath.FromSlash(fmt.Sprintf("sect/doc1%s", expectedPathSuffix)), fmt.Sprintf("<p>Ref 2: %s/sect/doc2%s</p>\n", expectedBase, expectedURLSuffix)},
|
||||
{filepath.FromSlash(fmt.Sprintf("sect/doc2%s", expectedPathSuffix)), fmt.Sprintf("<p><strong>Ref 1:</strong></p>\n\n%s/sect/doc1%s\n\n<p>THE END.</p>\n", expectedBase, expectedURLSuffix)},
|
||||
{filepath.FromSlash(fmt.Sprintf("sect/doc3%s", expectedPathSuffix)), fmt.Sprintf("<p><strong>Ref 1:</strong>%s/sect/doc3%s.</p>\n", expectedBase, expectedURLSuffix)},
|
||||
{filepath.FromSlash(fmt.Sprintf("public/sect/doc1%s", expectedPathSuffix)), fmt.Sprintf("<p>Ref 2: %s/sect/doc2%s</p>\n", expectedBase, expectedURLSuffix)},
|
||||
{filepath.FromSlash(fmt.Sprintf("public/sect/doc2%s", expectedPathSuffix)), fmt.Sprintf("<p><strong>Ref 1:</strong></p>\n\n%s/sect/doc1%s\n\n<p>THE END.</p>\n", expectedBase, expectedURLSuffix)},
|
||||
{filepath.FromSlash(fmt.Sprintf("public/sect/doc3%s", expectedPathSuffix)), fmt.Sprintf("<p><strong>Ref 1:</strong>%s/sect/doc3%s.</p>\n", expectedBase, expectedURLSuffix)},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
file, err := hugofs.Destination().Open(test.doc)
|
||||
assertFileContent(t, fs, test.doc, true, test.expected)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Did not find %s in target: %s", test.doc, err)
|
||||
}
|
||||
|
||||
content := helpers.ReaderToString(file)
|
||||
|
||||
if content != test.expected {
|
||||
t.Fatalf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -350,21 +307,19 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) {
|
|||
{Name: filepath.FromSlash("sect/doc2.md"), Content: []byte("---\nurl: /ugly.html\nmarkup: markdown\n---\n# title\ndoc2 *content*")},
|
||||
}
|
||||
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: uglyURLs, PublishDir: "public"}},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
}
|
||||
|
||||
if err := buildAndRenderSite(s,
|
||||
"index.html", "Home Sweet {{ if.IsHome }}Home{{ end }}.",
|
||||
"_default/single.html", "{{.Content}}{{ if.IsHome }}This is not home!{{ end }}",
|
||||
"404.html", "Page Not Found.{{ if.IsHome }}This is not home!{{ end }}",
|
||||
"rss.xml", "<root>RSS</root>",
|
||||
"sitemap.xml", "<root>SITEMAP</root>"); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeSource(t, fs, filepath.Join("layouts", "index.html"), "Home Sweet {{ if.IsHome }}Home{{ end }}.")
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default/single.html"), "{{.Content}}{{ if.IsHome }}This is not home!{{ end }}")
|
||||
writeSource(t, fs, filepath.Join("layouts", "404.html"), "Page Not Found.{{ if.IsHome }}This is not home!{{ end }}")
|
||||
writeSource(t, fs, filepath.Join("layouts", "rss.xml"), "<root>RSS</root>")
|
||||
writeSource(t, fs, filepath.Join("layouts", "sitemap.xml"), "<root>SITEMAP</root>")
|
||||
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
var expectedPagePath string
|
||||
if uglyURLs {
|
||||
|
@ -391,7 +346,7 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
content := readDestination(t, test.doc)
|
||||
content := readDestination(t, fs, test.doc)
|
||||
|
||||
if content != test.expected {
|
||||
t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
|
||||
|
@ -435,17 +390,16 @@ func doTestSectionNaming(t *testing.T, canonify, uglify, pluralize bool) {
|
|||
{Name: filepath.FromSlash("ラーメン/doc3.html"), Content: []byte("doc3")},
|
||||
}
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, source := range sources {
|
||||
writeSource(t, filepath.Join("content", source.Name), string(source.Content))
|
||||
writeSource(t, fs, filepath.Join("content", source.Name), string(source.Content))
|
||||
}
|
||||
|
||||
s := NewSiteDefaultLang()
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default/single.html"), "{{.Content}}")
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default/list.html"), "{{.Title}}")
|
||||
|
||||
if err := buildAndRenderSite(s,
|
||||
"_default/single.html", "{{.Content}}",
|
||||
"_default/list.html", "{{ .Title }}"); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
tests := []struct {
|
||||
doc string
|
||||
|
@ -466,14 +420,13 @@ func doTestSectionNaming(t *testing.T, canonify, uglify, pluralize bool) {
|
|||
test.expected = inflect.Pluralize(test.expected)
|
||||
}
|
||||
|
||||
assertFileContent(t, filepath.Join("public", test.doc), true, test.expected)
|
||||
assertFileContent(t, fs, filepath.Join("public", test.doc), true, test.expected)
|
||||
}
|
||||
|
||||
}
|
||||
func TestSkipRender(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("sect/doc1.html"), Content: []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
|
||||
{Name: filepath.FromSlash("sect/doc2.html"), Content: []byte("<!doctype html><html><body>more content</body></html>")},
|
||||
|
@ -488,37 +441,38 @@ func TestSkipRender(t *testing.T) {
|
|||
viper.Set("defaultExtension", "html")
|
||||
viper.Set("verbose", true)
|
||||
viper.Set("canonifyURLs", true)
|
||||
viper.Set("uglyURLs", true)
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: true}},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
if err := buildAndRenderSite(s,
|
||||
"_default/single.html", "{{.Content}}",
|
||||
"head", "<head><script src=\"script.js\"></script></head>",
|
||||
"head_abs", "<head><script src=\"/script.js\"></script></head>"); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default/single.html"), "{{.Content}}")
|
||||
writeSource(t, fs, filepath.Join("layouts", "head"), "<head><script src=\"script.js\"></script></head>")
|
||||
writeSource(t, fs, filepath.Join("layouts", "head_abs"), "<head><script src=\"/script.js\"></script></head>")
|
||||
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
tests := []struct {
|
||||
doc string
|
||||
expected string
|
||||
}{
|
||||
{filepath.FromSlash("sect/doc1.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
|
||||
{filepath.FromSlash("sect/doc2.html"), "<!doctype html><html><body>more content</body></html>"},
|
||||
{filepath.FromSlash("sect/doc3.html"), "\n\n<h1 id=\"doc3\">doc3</h1>\n\n<p><em>some</em> content</p>\n"},
|
||||
{filepath.FromSlash("sect/doc4.html"), "\n\n<h1 id=\"doc4\">doc4</h1>\n\n<p><em>some content</em></p>\n"},
|
||||
{filepath.FromSlash("sect/doc5.html"), "<!doctype html><html><head><script src=\"script.js\"></script></head><body>body5</body></html>"},
|
||||
{filepath.FromSlash("sect/doc6.html"), "<!doctype html><html><head><script src=\"http://auth/bub/script.js\"></script></head><body>body5</body></html>"},
|
||||
{filepath.FromSlash("doc7.html"), "<html><body>doc7 content</body></html>"},
|
||||
{filepath.FromSlash("sect/doc8.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
|
||||
{filepath.FromSlash("public/sect/doc1.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
|
||||
{filepath.FromSlash("public/sect/doc2.html"), "<!doctype html><html><body>more content</body></html>"},
|
||||
{filepath.FromSlash("public/sect/doc3.html"), "\n\n<h1 id=\"doc3\">doc3</h1>\n\n<p><em>some</em> content</p>\n"},
|
||||
{filepath.FromSlash("public/sect/doc4.html"), "\n\n<h1 id=\"doc4\">doc4</h1>\n\n<p><em>some content</em></p>\n"},
|
||||
{filepath.FromSlash("public/sect/doc5.html"), "<!doctype html><html><head><script src=\"script.js\"></script></head><body>body5</body></html>"},
|
||||
{filepath.FromSlash("public/sect/doc6.html"), "<!doctype html><html><head><script src=\"http://auth/bub/script.js\"></script></head><body>body5</body></html>"},
|
||||
{filepath.FromSlash("public/doc7.html"), "<html><body>doc7 content</body></html>"},
|
||||
{filepath.FromSlash("public/sect/doc8.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
file, err := hugofs.Destination().Open(test.doc)
|
||||
file, err := fs.Destination.Open(test.doc)
|
||||
if err != nil {
|
||||
t.Fatalf("Did not find %s in target.", test.doc)
|
||||
}
|
||||
|
@ -535,8 +489,8 @@ func TestAbsURLify(t *testing.T) {
|
|||
testCommonResetState()
|
||||
|
||||
viper.Set("defaultExtension", "html")
|
||||
viper.Set("uglyURLs", true)
|
||||
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("sect/doc1.html"), Content: []byte("<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>")},
|
||||
{Name: filepath.FromSlash("blue/doc2.html"), Content: []byte("---\nf: t\n---\n<!doctype html><html><body>more content</body></html>")},
|
||||
|
@ -545,34 +499,27 @@ func TestAbsURLify(t *testing.T) {
|
|||
for _, canonify := range []bool{true, false} {
|
||||
viper.Set("canonifyURLs", canonify)
|
||||
viper.Set("baseURL", baseURL)
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
targets: targetList{page: &target.PagePub{UglyURLs: true}},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
t.Logf("Rendering with baseURL %q and canonifyURLs set %v", viper.GetString("baseURL"), canonify)
|
||||
|
||||
if err := buildAndRenderSite(s, "blue/single.html", templateWithURLAbs); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
writeSource(t, fs, filepath.Join("layouts", "blue/single.html"), templateWithURLAbs)
|
||||
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
tests := []struct {
|
||||
file, expected string
|
||||
}{
|
||||
{"blue/doc2.html", "<a href=\"%s/foobar.jpg\">Going</a>"},
|
||||
{"sect/doc1.html", "<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"},
|
||||
{"public/blue/doc2.html", "<a href=\"%s/foobar.jpg\">Going</a>"},
|
||||
{"public/sect/doc1.html", "<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
file, err := hugofs.Destination().Open(filepath.FromSlash(test.file))
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to locate rendered content: %s", test.file)
|
||||
}
|
||||
|
||||
content := helpers.ReaderToString(file)
|
||||
|
||||
expected := test.expected
|
||||
|
||||
if strings.Contains(expected, "%s") {
|
||||
|
@ -583,9 +530,8 @@ func TestAbsURLify(t *testing.T) {
|
|||
expected = strings.Replace(expected, baseURL, "", -1)
|
||||
}
|
||||
|
||||
if content != expected {
|
||||
t.Errorf("AbsURLify with baseURL %q content expected:\n%q\ngot\n%q", baseURL, expected, content)
|
||||
}
|
||||
assertFileContent(t, fs, test.file, true, expected)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -639,18 +585,16 @@ var weightedSources = []source.ByteSource{
|
|||
func TestOrderedPages(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: weightedSources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, src := range weightedSources {
|
||||
writeSource(t, fs, filepath.Join("content", src.Name), string(src.Content))
|
||||
|
||||
}
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to process site: %s", err)
|
||||
}
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{SkipRender: true})
|
||||
|
||||
if s.Sections["sect"][0].Weight != 2 || s.Sections["sect"][3].Weight != 6 {
|
||||
t.Errorf("Pages in unexpected order. First should be '%d', got '%d'", 2, s.Sections["sect"][0].Weight)
|
||||
|
@ -709,23 +653,17 @@ func TestGroupedPages(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: groupedSources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
writeSourcesToSource(t, "content", fs, groupedSources...)
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
rbysection, err := s.RegularPages.GroupBy("Section", "desc")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to make PageGroup array: %s", err)
|
||||
}
|
||||
|
||||
if rbysection[0].Key != "sect3" {
|
||||
t.Errorf("PageGroup array in unexpected order. First group key should be '%s', got '%s'", "sect3", rbysection[0].Key)
|
||||
}
|
||||
|
@ -885,7 +823,6 @@ Front Matter with weighted tags and categories`)
|
|||
func TestWeightedTaxonomies(t *testing.T) {
|
||||
testCommonResetState()
|
||||
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("sect/doc1.md"), Content: pageWithWeightedTaxonomies2},
|
||||
{Name: filepath.FromSlash("sect/doc2.md"), Content: pageWithWeightedTaxonomies1},
|
||||
|
@ -898,15 +835,10 @@ func TestWeightedTaxonomies(t *testing.T) {
|
|||
|
||||
viper.Set("baseURL", "http://auth/bub")
|
||||
viper.Set("taxonomies", taxonomies)
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
|
||||
if err := buildSiteSkipRender(s); err != nil {
|
||||
t.Fatalf("Failed to process site: %s", err)
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
writeSourcesToSource(t, "content", fs, sources...)
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
if s.Taxonomies["tags"]["a"][0].Page.Title != "foo" {
|
||||
t.Errorf("Pages in unexpected order, 'foo' expected first, got '%v'", s.Taxonomies["tags"]["a"][0].Page.Title)
|
||||
|
@ -935,7 +867,6 @@ func findPage(site *Site, f string) *Page {
|
|||
}
|
||||
|
||||
func setupLinkingMockSite(t *testing.T) *Site {
|
||||
hugofs.InitMemFs()
|
||||
sources := []source.ByteSource{
|
||||
{Name: filepath.FromSlash("index.md"), Content: []byte("")},
|
||||
{Name: filepath.FromSlash("rootfile.md"), Content: []byte("")},
|
||||
|
@ -968,17 +899,10 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
|||
map[string]interface{}{
|
||||
"sourceRelativeLinksProjectFolder": "/docs"})
|
||||
|
||||
site := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: sources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
writeSourcesToSource(t, "content", fs, sources...)
|
||||
return buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
if err := buildSiteSkipRender(site); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
|
||||
return site
|
||||
}
|
||||
|
||||
func TestRefLinking(t *testing.T) {
|
||||
|
|
|
@ -17,13 +17,13 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
|
||||
"html/template"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const slugDoc1 = "---\ntitle: slug doc 1\nslug: slug-doc-1\naliases:\n - sd1/foo/\n - sd2\n - sd3/\n - sd4.html\n---\nslug doc 1 content\n"
|
||||
|
@ -62,7 +62,8 @@ func TestShouldNotAddTrailingSlashToBaseURL(t *testing.T) {
|
|||
{"http://base.com", "http://base.com"}} {
|
||||
|
||||
viper.Set("baseURL", this.in)
|
||||
s := NewSiteDefaultLang()
|
||||
s, err := NewSiteDefaultLang()
|
||||
require.NoError(t, err)
|
||||
s.initializeSiteInfo()
|
||||
|
||||
if s.Info.BaseURL != template.URL(this.expected) {
|
||||
|
@ -74,32 +75,27 @@ func TestShouldNotAddTrailingSlashToBaseURL(t *testing.T) {
|
|||
|
||||
func TestPageCount(t *testing.T) {
|
||||
testCommonResetState()
|
||||
hugofs.InitMemFs()
|
||||
|
||||
viper.Set("uglyURLs", false)
|
||||
viper.Set("paginate", 10)
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: urlFakeSource},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
|
||||
if err := buildAndRenderSite(s, "indexes/blue.html", indexTemplate); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
_, err := hugofs.Destination().Open("public/blue")
|
||||
fs := hugofs.NewMem()
|
||||
writeSourcesToSource(t, "content", fs, urlFakeSource...)
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
_, err := s.Fs.Destination.Open("public/blue")
|
||||
if err != nil {
|
||||
t.Errorf("No indexed rendered.")
|
||||
}
|
||||
|
||||
for _, s := range []string{
|
||||
for _, pth := range []string{
|
||||
"public/sd1/foo/index.html",
|
||||
"public/sd2/index.html",
|
||||
"public/sd3/index.html",
|
||||
"public/sd4.html",
|
||||
} {
|
||||
if _, err := hugofs.Destination().Open(filepath.FromSlash(s)); err != nil {
|
||||
t.Errorf("No alias rendered: %s", s)
|
||||
if _, err := s.Fs.Destination.Open(filepath.FromSlash(pth)); err != nil {
|
||||
t.Errorf("No alias rendered: %s", pth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,9 @@ import (
|
|||
|
||||
"reflect"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -45,24 +46,21 @@ func doTestSitemapOutput(t *testing.T, internal bool) {
|
|||
|
||||
viper.Set("baseURL", "http://auth/bub/")
|
||||
|
||||
s := &Site{
|
||||
deps: newDeps(DepsCfg{}),
|
||||
Source: &source.InMemorySource{ByteSource: weightedSources},
|
||||
Language: helpers.NewDefaultLanguage(),
|
||||
}
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
if internal {
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
depsCfg := deps.DepsCfg{Fs: fs}
|
||||
|
||||
} else {
|
||||
if err := buildAndRenderSite(s, "sitemap.xml", sitemapTemplate); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
if !internal {
|
||||
depsCfg.WithTemplate = func(templ tplapi.Template) error {
|
||||
templ.AddTemplate("sitemap.xml", sitemapTemplate)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
assertFileContent(t, "public/sitemap.xml", true,
|
||||
writeSourcesToSource(t, "content", fs, weightedSources...)
|
||||
s := buildSingleSite(t, depsCfg, BuildCfg{})
|
||||
|
||||
assertFileContent(t, s.Fs, "public/sitemap.xml", true,
|
||||
// Regular page
|
||||
" <loc>http://auth/bub/sect/doc1/</loc>",
|
||||
// Home page
|
||||
|
|
|
@ -16,8 +16,6 @@ package hugolib
|
|||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/hugo/helpers"
|
||||
)
|
||||
|
||||
// The TaxonomyList is a list of all taxonomies and their values
|
||||
|
@ -59,26 +57,15 @@ type OrderedTaxonomyEntry struct {
|
|||
WeightedPages WeightedPages
|
||||
}
|
||||
|
||||
// KeyPrep... Taxonomies should be case insensitive. Can make it easily conditional later.
|
||||
func kp(in string) string {
|
||||
return helpers.CurrentPathSpec().MakePathSanitized(in)
|
||||
}
|
||||
|
||||
// Get the weighted pages for the given key.
|
||||
func (i Taxonomy) Get(key string) WeightedPages {
|
||||
if val, ok := i[key]; ok {
|
||||
return val
|
||||
}
|
||||
return i[kp(key)]
|
||||
return i[key]
|
||||
}
|
||||
|
||||
// Count the weighted pages for the given key.
|
||||
func (i Taxonomy) Count(key string) int { return len(i[kp(key)]) }
|
||||
func (i Taxonomy) Count(key string) int { return len(i[key]) }
|
||||
|
||||
func (i Taxonomy) add(key string, w WeightedPage, pretty bool) {
|
||||
if !pretty {
|
||||
key = kp(key)
|
||||
}
|
||||
func (i Taxonomy) add(key string, w WeightedPage) {
|
||||
i[key] = append(i[key], w)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -31,16 +34,14 @@ func TestByCountOrderOfTaxonomies(t *testing.T) {
|
|||
|
||||
viper.Set("taxonomies", taxonomies)
|
||||
|
||||
writeSource(t, filepath.Join("content", "page.md"), pageYamlWithTaxonomiesA)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
site := NewSiteDefaultLang()
|
||||
writeSource(t, fs, filepath.Join("content", "page.md"), pageYamlWithTaxonomiesA)
|
||||
|
||||
if err := buildSiteSkipRender(site); err != nil {
|
||||
t.Fatalf("Failed to build site: %s", err)
|
||||
}
|
||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
st := make([]string, 0)
|
||||
for _, t := range site.Taxonomies["tags"].ByCount() {
|
||||
for _, t := range s.Taxonomies["tags"].ByCount() {
|
||||
st = append(st, t.Name)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2017 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package hugolib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
)
|
||||
|
||||
func TestAllTemplateEngines(t *testing.T) {
|
||||
noOp := func(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
amberFixer := func(s string) string {
|
||||
fixed := strings.Replace(s, "{{ .Title", "{{ Title", -1)
|
||||
fixed = strings.Replace(fixed, ".Content", "Content", -1)
|
||||
fixed = strings.Replace(fixed, "{{", "#{", -1)
|
||||
fixed = strings.Replace(fixed, "}}", "}", -1)
|
||||
fixed = strings.Replace(fixed, `title "hello world"`, `title("hello world")`, -1)
|
||||
|
||||
return fixed
|
||||
}
|
||||
|
||||
for _, config := range []struct {
|
||||
suffix string
|
||||
templateFixer func(s string) string
|
||||
}{
|
||||
{"amber", amberFixer},
|
||||
{"html", noOp},
|
||||
{"ace", noOp},
|
||||
} {
|
||||
doTestTemplateEngine(t, config.suffix, config.templateFixer)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func doTestTemplateEngine(t *testing.T, suffix string, templateFixer func(s string) string) {
|
||||
|
||||
testCommonResetState()
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
viper.SetFs(fs.Source)
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "p.md"), `
|
||||
---
|
||||
title: My Title
|
||||
---
|
||||
My Content
|
||||
`)
|
||||
|
||||
t.Log("Testing", suffix)
|
||||
|
||||
templTemplate := `
|
||||
p
|
||||
|
|
||||
| Page Title: {{ .Title }}
|
||||
br
|
||||
| Page Content: {{ .Content }}
|
||||
br
|
||||
| {{ title "hello world" }}
|
||||
|
||||
`
|
||||
|
||||
templ := templateFixer(templTemplate)
|
||||
|
||||
t.Log(templ)
|
||||
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", fmt.Sprintf("single.%s", suffix)), templ)
|
||||
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
assertFileContent(t, fs, filepath.Join("public", "p", "index.html"), true,
|
||||
"Page Title: My Title",
|
||||
"My Content",
|
||||
"Hello World",
|
||||
)
|
||||
|
||||
}
|
|
@ -17,127 +17,133 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func TestBaseGoTemplate(t *testing.T) {
|
||||
|
||||
var fs *hugofs.Fs
|
||||
|
||||
// Variants:
|
||||
// 1. <current-path>/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>.
|
||||
// 2. <current-path>/baseof.<suffix>
|
||||
// 3. _default/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>.
|
||||
// 4. _default/baseof.<suffix>
|
||||
for i, this := range []struct {
|
||||
for _, this := range []struct {
|
||||
setup func(t *testing.T)
|
||||
assert func(t *testing.T)
|
||||
}{
|
||||
{
|
||||
// Variant 1
|
||||
func(t *testing.T) {
|
||||
writeSource(t, filepath.Join("layouts", "section", "sect-baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("layouts", "section", "sect.html"), `{{define "main"}}sect{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "section", "sect-baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "section", "sect.html"), `{{define "main"}}sect{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base: sect")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base: sect")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 2
|
||||
func(t *testing.T) {
|
||||
writeSource(t, filepath.Join("layouts", "baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("layouts", "index.html"), `{{define "main"}}index{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "index.html"), `{{define "main"}}index{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "index.html"), false, "Base: index")
|
||||
assertFileContent(t, fs, filepath.Join("public", "index.html"), false, "Base: index")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 3
|
||||
func(t *testing.T) {
|
||||
writeSource(t, filepath.Join("layouts", "_default", "list-baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "list-baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base: list")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base: list")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 4
|
||||
func(t *testing.T) {
|
||||
writeSource(t, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base: list")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base: list")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 1, theme, use project's base
|
||||
func(t *testing.T) {
|
||||
viper.Set("theme", "mytheme")
|
||||
writeSource(t, filepath.Join("layouts", "section", "sect-baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("themes", "mytheme", "layouts", "section", "sect-baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("layouts", "section", "sect.html"), `{{define "main"}}sect{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "section", "sect-baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "section", "sect-baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "section", "sect.html"), `{{define "main"}}sect{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base: sect")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base: sect")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 1, theme, use theme's base
|
||||
func(t *testing.T) {
|
||||
viper.Set("theme", "mytheme")
|
||||
writeSource(t, filepath.Join("themes", "mytheme", "layouts", "section", "sect-baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("layouts", "section", "sect.html"), `{{define "main"}}sect{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "section", "sect-baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "section", "sect.html"), `{{define "main"}}sect{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base Theme: sect")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base Theme: sect")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 4, theme, use project's base
|
||||
func(t *testing.T) {
|
||||
viper.Set("theme", "mytheme")
|
||||
writeSource(t, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("themes", "mytheme", "layouts", "_default", "baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base: list")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base: list")
|
||||
},
|
||||
},
|
||||
{
|
||||
// Variant 4, theme, use themes's base
|
||||
func(t *testing.T) {
|
||||
viper.Set("theme", "mytheme")
|
||||
writeSource(t, filepath.Join("themes", "mytheme", "layouts", "_default", "baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`)
|
||||
writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`)
|
||||
|
||||
},
|
||||
func(t *testing.T) {
|
||||
assertFileContent(t, filepath.Join("public", "sect", "index.html"), false, "Base Theme: list")
|
||||
assertFileContent(t, fs, filepath.Join("public", "sect", "index.html"), false, "Base Theme: list")
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
||||
testCommonResetState()
|
||||
|
||||
writeSource(t, filepath.Join("content", "sect", "page.md"), `---
|
||||
fs = hugofs.NewMem()
|
||||
|
||||
writeSource(t, fs, filepath.Join("content", "sect", "page.md"), `---
|
||||
title: Template test
|
||||
---
|
||||
Some content
|
||||
`)
|
||||
this.setup(t)
|
||||
|
||||
if err := buildAndRenderSite(NewSiteDefaultLang()); err != nil {
|
||||
t.Fatalf("[%d] Failed to build site: %s", i, err)
|
||||
}
|
||||
buildSingleSite(t, deps.DepsCfg{Fs: fs}, BuildCfg{})
|
||||
|
||||
this.assert(t)
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package hugolib
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/source"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newTestDepsConfig() deps.DepsCfg {
|
||||
return deps.DepsCfg{Fs: hugofs.NewMem()}
|
||||
}
|
||||
|
||||
func newTestPathSpec() *helpers.PathSpec {
|
||||
return helpers.NewPathSpec(hugofs.NewMem(), viper.GetViper())
|
||||
}
|
||||
|
||||
func createWithTemplateFromNameValues(additionalTemplates ...string) func(templ tplapi.Template) error {
|
||||
|
||||
return func(templ tplapi.Template) error {
|
||||
for i := 0; i < len(additionalTemplates); i += 2 {
|
||||
err := templ.AddTemplate(additionalTemplates[i], additionalTemplates[i+1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func buildSingleSite(t *testing.T, depsCfg deps.DepsCfg, buildCfg BuildCfg) *Site {
|
||||
h, err := NewHugoSitesFromConfiguration(depsCfg)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, h.Sites, 1)
|
||||
|
||||
require.NoError(t, h.Build(buildCfg))
|
||||
|
||||
return h.Sites[0]
|
||||
}
|
||||
|
||||
func writeSourcesToSource(t *testing.T, base string, fs *hugofs.Fs, sources ...source.ByteSource) {
|
||||
for _, src := range sources {
|
||||
writeSource(t, fs, filepath.Join(base, src.Name), string(src.Content))
|
||||
}
|
||||
}
|
|
@ -38,6 +38,12 @@ type Filesystem struct {
|
|||
files []*File
|
||||
Base string
|
||||
AvoidPaths []string
|
||||
|
||||
fs *hugofs.Fs
|
||||
}
|
||||
|
||||
func NewFilesystem(fs *hugofs.Fs, base string, avoidPaths ...string) *Filesystem {
|
||||
return &Filesystem{fs: fs, Base: base, AvoidPaths: avoidPaths}
|
||||
}
|
||||
|
||||
func (f *Filesystem) FilesByExts(exts ...string) []*File {
|
||||
|
@ -92,7 +98,7 @@ func (f *Filesystem) captureFiles() {
|
|||
return err
|
||||
}
|
||||
if b {
|
||||
rd, err := NewLazyFileReader(hugofs.Source(), filePath)
|
||||
rd, err := NewLazyFileReader(f.fs.Source, filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -101,7 +107,10 @@ func (f *Filesystem) captureFiles() {
|
|||
return err
|
||||
}
|
||||
|
||||
err := helpers.SymbolicWalk(hugofs.Source(), f.Base, walker)
|
||||
if f.fs == nil {
|
||||
panic("Must have a fs")
|
||||
}
|
||||
err := helpers.SymbolicWalk(f.fs.Source, f.Base, walker)
|
||||
|
||||
if err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
|
@ -119,7 +128,7 @@ func (f *Filesystem) shouldRead(filePath string, fi os.FileInfo) (bool, error) {
|
|||
jww.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", filePath, err)
|
||||
return false, nil
|
||||
}
|
||||
linkfi, err := hugofs.Source().Stat(link)
|
||||
linkfi, err := f.fs.Source.Stat(link)
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
|
||||
return false, nil
|
||||
|
|
|
@ -19,10 +19,12 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
)
|
||||
|
||||
func TestEmptySourceFilesystem(t *testing.T) {
|
||||
src := &Filesystem{Base: "Empty"}
|
||||
src := NewFilesystem(hugofs.NewMem(), "Empty")
|
||||
if len(src.Files()) != 0 {
|
||||
t.Errorf("new filesystem should contain 0 files.")
|
||||
}
|
||||
|
@ -37,13 +39,12 @@ type TestPath struct {
|
|||
}
|
||||
|
||||
func TestAddFile(t *testing.T) {
|
||||
fs := hugofs.NewMem()
|
||||
tests := platformPaths
|
||||
for _, test := range tests {
|
||||
base := platformBase
|
||||
srcDefault := new(Filesystem)
|
||||
srcWithBase := &Filesystem{
|
||||
Base: base,
|
||||
}
|
||||
srcDefault := NewFilesystem(fs, "")
|
||||
srcWithBase := NewFilesystem(fs, base)
|
||||
|
||||
for _, src := range []*Filesystem{srcDefault, srcWithBase} {
|
||||
|
||||
|
@ -99,8 +100,10 @@ func TestUnicodeNorm(t *testing.T) {
|
|||
{NFC: "é", NFD: "\x65\xcc\x81"},
|
||||
}
|
||||
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
for _, path := range paths {
|
||||
src := new(Filesystem)
|
||||
src := NewFilesystem(fs, "")
|
||||
_ = src.add(path.NFD, strings.NewReader(""))
|
||||
f := src.Files()[0]
|
||||
if f.BaseFileName() != path.NFC {
|
||||
|
|
|
@ -41,6 +41,8 @@ type Output interface {
|
|||
|
||||
type Filesystem struct {
|
||||
PublishDir string
|
||||
|
||||
Fs *hugofs.Fs
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Publish(path string, r io.Reader) (err error) {
|
||||
|
@ -49,7 +51,7 @@ func (fs *Filesystem) Publish(path string, r io.Reader) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
return helpers.WriteToDisk(translated, r, hugofs.Destination())
|
||||
return helpers.WriteToDisk(translated, r, fs.Fs.Destination)
|
||||
}
|
||||
|
||||
func (fs *Filesystem) Translate(src string) (dest string, err error) {
|
||||
|
|
|
@ -46,6 +46,8 @@ type HTMLRedirectAlias struct {
|
|||
PublishDir string
|
||||
Templates *template.Template
|
||||
AllowRoot bool // for the language redirects
|
||||
|
||||
Fs *hugofs.Fs
|
||||
}
|
||||
|
||||
func (h *HTMLRedirectAlias) Translate(alias string) (aliasPath string, err error) {
|
||||
|
@ -145,5 +147,5 @@ func (h *HTMLRedirectAlias) Publish(path string, permalink string, page interfac
|
|||
return
|
||||
}
|
||||
|
||||
return helpers.WriteToDisk(path, buffer, hugofs.Destination())
|
||||
return helpers.WriteToDisk(path, buffer, h.Fs.Destination)
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ type PagePub struct {
|
|||
// LangDir will contain the subdir for the language, i.e. "en", "de" etc.
|
||||
// It will be empty if the site is rendered in root.
|
||||
LangDir string
|
||||
|
||||
Fs *hugofs.Fs
|
||||
}
|
||||
|
||||
func (pp *PagePub) Publish(path string, r io.Reader) (err error) {
|
||||
|
@ -44,7 +46,7 @@ func (pp *PagePub) Publish(path string, r io.Reader) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
return helpers.WriteToDisk(translated, r, hugofs.Destination())
|
||||
return helpers.WriteToDisk(translated, r, pp.Fs.Destination)
|
||||
}
|
||||
|
||||
func (pp *PagePub) Translate(src string) (dest string, err error) {
|
||||
|
|
|
@ -16,9 +16,13 @@ package target
|
|||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
)
|
||||
|
||||
func TestPageTranslator(t *testing.T) {
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
tests := []struct {
|
||||
content string
|
||||
expected string
|
||||
|
@ -37,7 +41,7 @@ func TestPageTranslator(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
f := new(PagePub)
|
||||
f := &PagePub{Fs: fs}
|
||||
dest, err := f.Translate(filepath.FromSlash(test.content))
|
||||
expected := filepath.FromSlash(test.expected)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2017 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpl
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
|
||||
"github.com/eknkc/amber"
|
||||
)
|
||||
|
||||
func (gt *GoHTMLTemplate) CompileAmberWithTemplate(b []byte, path string, t *template.Template) (*template.Template, error) {
|
||||
c := amber.New()
|
||||
|
||||
if err := c.ParseData(b, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := c.CompileString()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tpl, err := t.Funcs(gt.amberFuncMap).Parse(data)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tpl, nil
|
||||
}
|
170
tpl/template.go
170
tpl/template.go
|
@ -24,33 +24,12 @@ import (
|
|||
"github.com/eknkc/amber"
|
||||
"github.com/spf13/afero"
|
||||
bp "github.com/spf13/hugo/bufferpool"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/yosssi/ace"
|
||||
)
|
||||
|
||||
// TODO(bep) globals get rid of the rest of the jww.ERR etc.
|
||||
//var tmpl *GoHTMLTemplate
|
||||
|
||||
// TODO(bep) an interface with hundreds of methods ... remove it.
|
||||
// And unexport most of these methods.
|
||||
type Template interface {
|
||||
ExecuteTemplate(wr io.Writer, name string, data interface{}) error
|
||||
Lookup(name string) *template.Template
|
||||
Templates() []*template.Template
|
||||
New(name string) *template.Template
|
||||
GetClone() *template.Template
|
||||
LoadTemplates(absPath string)
|
||||
LoadTemplatesWithPrefix(absPath, prefix string)
|
||||
AddTemplate(name, tpl string) error
|
||||
AddTemplateFileWithMaster(name, overlayFilename, masterFilename string) error
|
||||
AddAceTemplate(name, basePath, innerPath string, baseContent, innerContent []byte) error
|
||||
AddInternalTemplate(prefix, name, tpl string) error
|
||||
AddInternalShortcode(name, tpl string) error
|
||||
PrintErrors()
|
||||
Funcs(funcMap template.FuncMap)
|
||||
}
|
||||
|
||||
type templateErr struct {
|
||||
name string
|
||||
|
@ -70,52 +49,105 @@ type GoHTMLTemplate struct {
|
|||
|
||||
funcster *templateFuncster
|
||||
|
||||
// TODO(bep) globals template
|
||||
log *jww.Notepad
|
||||
amberFuncMap template.FuncMap
|
||||
|
||||
*deps.Deps
|
||||
}
|
||||
|
||||
// New returns a new Hugo Template System
|
||||
type TemplateProvider struct{}
|
||||
|
||||
var DefaultTemplateProvider *TemplateProvider
|
||||
|
||||
// Update updates the Hugo Template System in the provided Deps.
|
||||
// with all the additional features, templates & functions
|
||||
func New(logger *jww.Notepad, withTemplate ...func(templ Template) error) *GoHTMLTemplate {
|
||||
func (*TemplateProvider) Update(deps *deps.Deps) error {
|
||||
// TODO(bep) check that this isn't called too many times.
|
||||
tmpl := &GoHTMLTemplate{
|
||||
Template: template.New(""),
|
||||
overlays: make(map[string]*template.Template),
|
||||
errors: make([]*templateErr, 0),
|
||||
log: logger,
|
||||
Deps: deps,
|
||||
}
|
||||
|
||||
tmpl.funcster = newTemplateFuncster(tmpl)
|
||||
deps.Tmpl = tmpl
|
||||
|
||||
// The URL funcs in the funcMap is somewhat language dependent,
|
||||
// so we need to wait until the language and site config is loaded.
|
||||
// TODO(bep) globals
|
||||
tmpl.funcster.initFuncMap()
|
||||
|
||||
// TODO(bep) globals
|
||||
for k, v := range tmpl.funcster.funcMap {
|
||||
amber.FuncMap[k] = v
|
||||
}
|
||||
tmpl.initFuncs(deps)
|
||||
|
||||
tmpl.LoadEmbedded()
|
||||
|
||||
for _, wt := range withTemplate {
|
||||
err := wt(tmpl)
|
||||
if deps.WithTemplate != nil {
|
||||
err := deps.WithTemplate(tmpl)
|
||||
if err != nil {
|
||||
tmpl.errors = append(tmpl.errors, &templateErr{"init", err})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tmpl.markReady()
|
||||
tmpl.MarkReady()
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Clone clones
|
||||
func (*TemplateProvider) Clone(d *deps.Deps) error {
|
||||
|
||||
t := d.Tmpl.(*GoHTMLTemplate)
|
||||
|
||||
// 1. Clone the clone with new template funcs
|
||||
// 2. Clone any overlays with new template funcs
|
||||
|
||||
tmpl := &GoHTMLTemplate{
|
||||
Template: template.Must(t.Template.Clone()),
|
||||
overlays: make(map[string]*template.Template),
|
||||
errors: make([]*templateErr, 0),
|
||||
Deps: d,
|
||||
}
|
||||
|
||||
d.Tmpl = tmpl
|
||||
tmpl.initFuncs(d)
|
||||
|
||||
for k, v := range t.overlays {
|
||||
vc := template.Must(v.Clone())
|
||||
vc.Funcs(tmpl.funcster.funcMap)
|
||||
tmpl.overlays[k] = vc
|
||||
}
|
||||
|
||||
tmpl.MarkReady()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *GoHTMLTemplate) initFuncs(d *deps.Deps) {
|
||||
|
||||
t.funcster = newTemplateFuncster(d)
|
||||
|
||||
// The URL funcs in the funcMap is somewhat language dependent,
|
||||
// so we need to wait until the language and site config is loaded.
|
||||
t.funcster.initFuncMap()
|
||||
|
||||
t.amberFuncMap = template.FuncMap{}
|
||||
|
||||
for k, v := range amber.FuncMap {
|
||||
t.amberFuncMap[k] = v
|
||||
}
|
||||
|
||||
for k, v := range t.funcster.funcMap {
|
||||
t.amberFuncMap[k] = v
|
||||
// Hacky, but we need to make sure that the func names are in the global map.
|
||||
amber.FuncMap[k] = func() string {
|
||||
panic("should never be invoked")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return tmpl
|
||||
}
|
||||
|
||||
func (t *GoHTMLTemplate) Funcs(funcMap template.FuncMap) {
|
||||
t.Template.Funcs(funcMap)
|
||||
}
|
||||
|
||||
func (t *GoHTMLTemplate) partial(name string, contextList ...interface{}) template.HTML {
|
||||
func (t *GoHTMLTemplate) Partial(name string, contextList ...interface{}) template.HTML {
|
||||
if strings.HasPrefix("partials/", name) {
|
||||
name = name[8:]
|
||||
}
|
||||
|
@ -147,8 +179,8 @@ func (t *GoHTMLTemplate) executeTemplate(context interface{}, w io.Writer, layou
|
|||
}
|
||||
}
|
||||
if !worked {
|
||||
t.log.ERROR.Println("Unable to render", layouts)
|
||||
t.log.ERROR.Println("Expecting to find a template in either the theme/layouts or /layouts in one of the following relative locations", layouts)
|
||||
t.Log.ERROR.Println("Unable to render", layouts)
|
||||
t.Log.ERROR.Println("Expecting to find a template in either the theme/layouts or /layouts in one of the following relative locations", layouts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,9 +218,9 @@ func (t *GoHTMLTemplate) LoadEmbedded() {
|
|||
t.EmbedTemplates()
|
||||
}
|
||||
|
||||
// markReady marks the template as "ready for execution". No changes allowed
|
||||
// MarkReady marks the template as "ready for execution". No changes allowed
|
||||
// after this is set.
|
||||
func (t *GoHTMLTemplate) markReady() {
|
||||
func (t *GoHTMLTemplate) MarkReady() {
|
||||
if t.clone == nil {
|
||||
t.clone = template.Must(t.Template.Clone())
|
||||
}
|
||||
|
@ -244,7 +276,7 @@ func (t *GoHTMLTemplate) AddTemplateFileWithMaster(name, overlayFilename, master
|
|||
masterTpl := t.Lookup(masterFilename)
|
||||
|
||||
if masterTpl == nil {
|
||||
b, err := afero.ReadFile(hugofs.Source(), masterFilename)
|
||||
b, err := afero.ReadFile(t.Fs.Source, masterFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -257,7 +289,7 @@ func (t *GoHTMLTemplate) AddTemplateFileWithMaster(name, overlayFilename, master
|
|||
}
|
||||
}
|
||||
|
||||
b, err := afero.ReadFile(hugofs.Source(), overlayFilename)
|
||||
b, err := afero.ReadFile(t.Fs.Source, overlayFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -315,19 +347,13 @@ func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) er
|
|||
switch ext {
|
||||
case ".amber":
|
||||
templateName := strings.TrimSuffix(name, filepath.Ext(name)) + ".html"
|
||||
compiler := amber.New()
|
||||
b, err := afero.ReadFile(hugofs.Source(), path)
|
||||
b, err := afero.ReadFile(t.Fs.Source, path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the input data
|
||||
if err := compiler.ParseData(b, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
templ, err := compiler.CompileWithTemplate(t.New(templateName))
|
||||
templ, err := t.CompileAmberWithTemplate(b, path, t.New(templateName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -335,14 +361,14 @@ func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) er
|
|||
return applyTemplateTransformers(templ)
|
||||
case ".ace":
|
||||
var innerContent, baseContent []byte
|
||||
innerContent, err := afero.ReadFile(hugofs.Source(), path)
|
||||
innerContent, err := afero.ReadFile(t.Fs.Source, path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if baseTemplatePath != "" {
|
||||
baseContent, err = afero.ReadFile(hugofs.Source(), baseTemplatePath)
|
||||
baseContent, err = afero.ReadFile(t.Fs.Source, baseTemplatePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -355,13 +381,13 @@ func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) er
|
|||
return t.AddTemplateFileWithMaster(name, path, baseTemplatePath)
|
||||
}
|
||||
|
||||
b, err := afero.ReadFile(hugofs.Source(), path)
|
||||
b, err := afero.ReadFile(t.Fs.Source, path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.log.DEBUG.Printf("Add template file from path %s", path)
|
||||
t.Log.DEBUG.Printf("Add template file from path %s", path)
|
||||
|
||||
return t.AddTemplate(name, string(b))
|
||||
}
|
||||
|
@ -391,25 +417,25 @@ func isBaseTemplate(path string) bool {
|
|||
}
|
||||
|
||||
func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
|
||||
t.log.DEBUG.Printf("Load templates from path %q prefix %q", absPath, prefix)
|
||||
t.Log.DEBUG.Printf("Load templates from path %q prefix %q", absPath, prefix)
|
||||
walker := func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
t.log.DEBUG.Println("Template path", path)
|
||||
t.Log.DEBUG.Println("Template path", path)
|
||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
link, err := filepath.EvalSymlinks(absPath)
|
||||
if err != nil {
|
||||
t.log.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", absPath, err)
|
||||
t.Log.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", absPath, err)
|
||||
return nil
|
||||
}
|
||||
linkfi, err := hugofs.Source().Stat(link)
|
||||
linkfi, err := t.Fs.Source.Stat(link)
|
||||
if err != nil {
|
||||
t.log.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
|
||||
t.Log.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
|
||||
return nil
|
||||
}
|
||||
if !linkfi.Mode().IsRegular() {
|
||||
t.log.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", absPath)
|
||||
t.Log.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", absPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -441,7 +467,7 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
|
|||
|
||||
// This may be a view that shouldn't have base template
|
||||
// Have to look inside it to make sure
|
||||
needsBase, err := helpers.FileContainsAny(path, innerMarkers, hugofs.Source())
|
||||
needsBase, err := helpers.FileContainsAny(path, innerMarkers, t.Fs.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -482,7 +508,7 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
|
|||
for _, pair := range pairsToCheck {
|
||||
pathsToCheck := basePathsToCheck(pair, layoutDir, themeDir)
|
||||
for _, pathToCheck := range pathsToCheck {
|
||||
if ok, err := helpers.Exists(pathToCheck, hugofs.Source()); err == nil && ok {
|
||||
if ok, err := helpers.Exists(pathToCheck, t.Fs.Source); err == nil && ok {
|
||||
baseTemplatePath = pathToCheck
|
||||
break Loop
|
||||
}
|
||||
|
@ -492,14 +518,14 @@ func (t *GoHTMLTemplate) loadTemplates(absPath string, prefix string) {
|
|||
}
|
||||
|
||||
if err := t.AddTemplateFile(tplName, baseTemplatePath, path); err != nil {
|
||||
t.log.ERROR.Printf("Failed to add template %s in path %s: %s", tplName, path, err)
|
||||
t.Log.ERROR.Printf("Failed to add template %s in path %s: %s", tplName, path, err)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := helpers.SymbolicWalk(hugofs.Source(), absPath, walker); err != nil {
|
||||
t.log.ERROR.Printf("Failed to load templates: %s", err)
|
||||
if err := helpers.SymbolicWalk(t.Fs.Source, absPath, walker); err != nil {
|
||||
t.Log.ERROR.Printf("Failed to load templates: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,6 +552,6 @@ func (t *GoHTMLTemplate) LoadTemplates(absPath string) {
|
|||
|
||||
func (t *GoHTMLTemplate) PrintErrors() {
|
||||
for i, e := range t.errors {
|
||||
t.log.ERROR.Println(i, ":", e.err)
|
||||
t.Log.ERROR.Println(i, ":", e.err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,8 +43,8 @@ import (
|
|||
"github.com/bep/inflect"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
|
@ -56,14 +56,15 @@ import (
|
|||
|
||||
// Some of the template funcs are'nt entirely stateless.
|
||||
type templateFuncster struct {
|
||||
t *GoHTMLTemplate
|
||||
funcMap template.FuncMap
|
||||
cachedPartials partialCache
|
||||
|
||||
*deps.Deps
|
||||
}
|
||||
|
||||
func newTemplateFuncster(t *GoHTMLTemplate) *templateFuncster {
|
||||
func newTemplateFuncster(deps *deps.Deps) *templateFuncster {
|
||||
return &templateFuncster{
|
||||
t: t,
|
||||
Deps: deps,
|
||||
cachedPartials: partialCache{p: make(map[string]template.HTML)},
|
||||
}
|
||||
}
|
||||
|
@ -424,7 +425,7 @@ func resetImageConfigCache() {
|
|||
|
||||
// imageConfig returns the image.Config for the specified path relative to the
|
||||
// working directory. resetImageConfigCache must be run beforehand.
|
||||
func imageConfig(path interface{}) (image.Config, error) {
|
||||
func (t *templateFuncster) imageConfig(path interface{}) (image.Config, error) {
|
||||
filename, err := cast.ToStringE(path)
|
||||
if err != nil {
|
||||
return image.Config{}, err
|
||||
|
@ -443,7 +444,7 @@ func imageConfig(path interface{}) (image.Config, error) {
|
|||
return config, nil
|
||||
}
|
||||
|
||||
f, err := hugofs.WorkingDir().Open(filename)
|
||||
f, err := t.Fs.WorkingDir.Open(filename)
|
||||
if err != nil {
|
||||
return image.Config{}, err
|
||||
}
|
||||
|
@ -1013,7 +1014,7 @@ func where(seq, key interface{}, args ...interface{}) (interface{}, error) {
|
|||
}
|
||||
|
||||
// apply takes a map, array, or slice and returns a new slice with the function fname applied over it.
|
||||
func (tf *templateFuncster) apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
|
||||
func (t *templateFuncster) apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
|
||||
if seq == nil {
|
||||
return make([]interface{}, 0), nil
|
||||
}
|
||||
|
@ -1028,7 +1029,7 @@ func (tf *templateFuncster) apply(seq interface{}, fname string, args ...interfa
|
|||
return nil, errors.New("can't iterate over a nil value")
|
||||
}
|
||||
|
||||
fn, found := tf.funcMap[fname]
|
||||
fn, found := t.funcMap[fname]
|
||||
if !found {
|
||||
return nil, errors.New("can't find function " + fname)
|
||||
}
|
||||
|
@ -1528,26 +1529,27 @@ type partialCache struct {
|
|||
// Get retrieves partial output from the cache based upon the partial name.
|
||||
// If the partial is not found in the cache, the partial is rendered and added
|
||||
// to the cache.
|
||||
func (tf *templateFuncster) Get(key, name string, context interface{}) (p template.HTML) {
|
||||
func (t *templateFuncster) Get(key, name string, context interface{}) (p template.HTML) {
|
||||
var ok bool
|
||||
|
||||
tf.cachedPartials.RLock()
|
||||
p, ok = tf.cachedPartials.p[key]
|
||||
tf.cachedPartials.RUnlock()
|
||||
t.cachedPartials.RLock()
|
||||
p, ok = t.cachedPartials.p[key]
|
||||
t.cachedPartials.RUnlock()
|
||||
|
||||
if ok {
|
||||
return p
|
||||
}
|
||||
|
||||
tf.cachedPartials.Lock()
|
||||
if p, ok = tf.cachedPartials.p[key]; !ok {
|
||||
tf.cachedPartials.Unlock()
|
||||
p = tf.t.partial(name, context)
|
||||
t.cachedPartials.Lock()
|
||||
if p, ok = t.cachedPartials.p[key]; !ok {
|
||||
t.cachedPartials.Unlock()
|
||||
p = t.Tmpl.Partial(name, context)
|
||||
|
||||
t.cachedPartials.Lock()
|
||||
t.cachedPartials.p[key] = p
|
||||
|
||||
tf.cachedPartials.Lock()
|
||||
tf.cachedPartials.p[key] = p
|
||||
}
|
||||
tf.cachedPartials.Unlock()
|
||||
t.cachedPartials.Unlock()
|
||||
|
||||
return p
|
||||
}
|
||||
|
@ -1556,14 +1558,14 @@ func (tf *templateFuncster) Get(key, name string, context interface{}) (p templa
|
|||
// string parameter (a string slice actually, but be only use a variadic
|
||||
// argument to make it optional) can be passed so that a given partial can have
|
||||
// multiple uses. The cache is created with name+variant as the key.
|
||||
func (tf *templateFuncster) partialCached(name string, context interface{}, variant ...string) template.HTML {
|
||||
func (t *templateFuncster) partialCached(name string, context interface{}, variant ...string) template.HTML {
|
||||
key := name
|
||||
if len(variant) > 0 {
|
||||
for i := 0; i < len(variant); i++ {
|
||||
key += variant[i]
|
||||
}
|
||||
}
|
||||
return tf.Get(key, name, context)
|
||||
return t.Get(key, name, context)
|
||||
}
|
||||
|
||||
// regexpCache represents a cache of regexp objects protected by a mutex.
|
||||
|
@ -1814,23 +1816,23 @@ func readFile(fs *afero.BasePathFs, filename string) (string, error) {
|
|||
// configured WorkingDir.
|
||||
// It returns the contents as a string.
|
||||
// There is a upper size limit set at 1 megabytes.
|
||||
func readFileFromWorkingDir(i interface{}) (string, error) {
|
||||
func (t *templateFuncster) readFileFromWorkingDir(i interface{}) (string, error) {
|
||||
s, err := cast.ToStringE(i)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return readFile(hugofs.WorkingDir(), s)
|
||||
return readFile(t.Fs.WorkingDir, s)
|
||||
}
|
||||
|
||||
// readDirFromWorkingDir listst the directory content relative to the
|
||||
// configured WorkingDir.
|
||||
func readDirFromWorkingDir(i interface{}) ([]os.FileInfo, error) {
|
||||
func (t *templateFuncster) readDirFromWorkingDir(i interface{}) ([]os.FileInfo, error) {
|
||||
path, err := cast.ToStringE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list, err := afero.ReadDir(hugofs.WorkingDir(), path)
|
||||
list, err := afero.ReadDir(t.Fs.WorkingDir, path)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read Directory %s with error message %s", path, err)
|
||||
|
@ -2074,20 +2076,20 @@ func htmlUnescape(in interface{}) (string, error) {
|
|||
return html.UnescapeString(conv), nil
|
||||
}
|
||||
|
||||
func absURL(a interface{}) (template.HTML, error) {
|
||||
func (t *templateFuncster) absURL(a interface{}) (template.HTML, error) {
|
||||
s, err := cast.ToStringE(a)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return template.HTML(helpers.CurrentPathSpec().AbsURL(s, false)), nil
|
||||
return template.HTML(t.PathSpec.AbsURL(s, false)), nil
|
||||
}
|
||||
|
||||
func relURL(a interface{}) (template.HTML, error) {
|
||||
func (t *templateFuncster) relURL(a interface{}) (template.HTML, error) {
|
||||
s, err := cast.ToStringE(a)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return template.HTML(helpers.CurrentPathSpec().RelURL(s, false)), nil
|
||||
return template.HTML(t.PathSpec.RelURL(s, false)), nil
|
||||
}
|
||||
|
||||
// getenv retrieves the value of the environment variable named by the key.
|
||||
|
@ -2101,19 +2103,19 @@ func getenv(key interface{}) (string, error) {
|
|||
return os.Getenv(skey), nil
|
||||
}
|
||||
|
||||
func (tf *templateFuncster) initFuncMap() {
|
||||
func (t *templateFuncster) initFuncMap() {
|
||||
funcMap := template.FuncMap{
|
||||
"absURL": absURL,
|
||||
"absURL": t.absURL,
|
||||
"absLangURL": func(i interface{}) (template.HTML, error) {
|
||||
s, err := cast.ToStringE(i)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return template.HTML(helpers.CurrentPathSpec().AbsURL(s, true)), nil
|
||||
return template.HTML(t.PathSpec.AbsURL(s, true)), nil
|
||||
},
|
||||
"add": func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '+') },
|
||||
"after": after,
|
||||
"apply": tf.apply,
|
||||
"apply": t.apply,
|
||||
"base64Decode": base64Decode,
|
||||
"base64Encode": base64Encode,
|
||||
"chomp": chomp,
|
||||
|
@ -2130,8 +2132,8 @@ func (tf *templateFuncster) initFuncMap() {
|
|||
"findRE": findRE,
|
||||
"first": first,
|
||||
"ge": ge,
|
||||
"getCSV": getCSV,
|
||||
"getJSON": getJSON,
|
||||
"getCSV": t.getCSV,
|
||||
"getJSON": t.getJSON,
|
||||
"getenv": getenv,
|
||||
"gt": gt,
|
||||
"hasPrefix": hasPrefix,
|
||||
|
@ -2139,7 +2141,7 @@ func (tf *templateFuncster) initFuncMap() {
|
|||
"htmlEscape": htmlEscape,
|
||||
"htmlUnescape": htmlUnescape,
|
||||
"humanize": humanize,
|
||||
"imageConfig": imageConfig,
|
||||
"imageConfig": t.imageConfig,
|
||||
"in": in,
|
||||
"index": index,
|
||||
"int": func(v interface{}) (int, error) { return cast.ToIntE(v) },
|
||||
|
@ -2158,21 +2160,21 @@ func (tf *templateFuncster) initFuncMap() {
|
|||
"mul": func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '*') },
|
||||
"ne": ne,
|
||||
"now": func() time.Time { return time.Now() },
|
||||
"partial": tf.t.partial,
|
||||
"partialCached": tf.partialCached,
|
||||
"partial": t.Tmpl.Partial,
|
||||
"partialCached": t.partialCached,
|
||||
"plainify": plainify,
|
||||
"pluralize": pluralize,
|
||||
"querify": querify,
|
||||
"readDir": readDirFromWorkingDir,
|
||||
"readFile": readFileFromWorkingDir,
|
||||
"readDir": t.readDirFromWorkingDir,
|
||||
"readFile": t.readFileFromWorkingDir,
|
||||
"ref": ref,
|
||||
"relURL": relURL,
|
||||
"relURL": t.relURL,
|
||||
"relLangURL": func(i interface{}) (template.HTML, error) {
|
||||
s, err := cast.ToStringE(i)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return template.HTML(helpers.CurrentPathSpec().RelURL(s, true)), nil
|
||||
return template.HTML(t.PathSpec.RelURL(s, true)), nil
|
||||
},
|
||||
"relref": relRef,
|
||||
"replace": replace,
|
||||
|
@ -2201,12 +2203,12 @@ func (tf *templateFuncster) initFuncMap() {
|
|||
"trim": trim,
|
||||
"truncate": truncate,
|
||||
"upper": upper,
|
||||
"urlize": helpers.CurrentPathSpec().URLize,
|
||||
"urlize": t.PathSpec.URLize,
|
||||
"where": where,
|
||||
"i18n": i18nTranslate,
|
||||
"T": i18nTranslate,
|
||||
}
|
||||
|
||||
tf.funcMap = funcMap
|
||||
tf.t.Funcs(funcMap)
|
||||
t.funcMap = funcMap
|
||||
t.Tmpl.Funcs(funcMap)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
|
||||
"io/ioutil"
|
||||
|
@ -43,9 +46,17 @@ import (
|
|||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var logger = jww.NewNotepad(jww.LevelFatal, jww.LevelFatal, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
var (
|
||||
logger = jww.NewNotepad(jww.LevelFatal, jww.LevelFatal, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
|
||||
defaultDepsConfig = deps.DepsCfg{
|
||||
Language: helpers.NewLanguage("en"),
|
||||
Logger: logger,
|
||||
TemplateProvider: DefaultTemplateProvider,
|
||||
}
|
||||
)
|
||||
|
||||
type tstNoStringer struct {
|
||||
}
|
||||
|
@ -80,8 +91,7 @@ func tstInitTemplates() {
|
|||
|
||||
func TestFuncsInTemplate(t *testing.T) {
|
||||
|
||||
viper.Reset()
|
||||
defer viper.Reset()
|
||||
testReset()
|
||||
|
||||
workingDir := "/home/hugo"
|
||||
|
||||
|
@ -89,10 +99,9 @@ func TestFuncsInTemplate(t *testing.T) {
|
|||
viper.Set("currentContentLanguage", helpers.NewDefaultLanguage())
|
||||
viper.Set("multilingual", true)
|
||||
|
||||
fs := &afero.MemMapFs{}
|
||||
hugofs.InitFs(fs)
|
||||
fs := hugofs.NewMem()
|
||||
|
||||
afero.WriteFile(fs, filepath.Join(workingDir, "README.txt"), []byte("Hugo Rocks!"), 0755)
|
||||
afero.WriteFile(fs.Source, filepath.Join(workingDir, "README.txt"), []byte("Hugo Rocks!"), 0755)
|
||||
|
||||
// Add the examples from the docs: As a smoke test and to make sure the examples work.
|
||||
// TODO(bep): docs: fix title example
|
||||
|
@ -244,7 +253,7 @@ urlize: bat-man
|
|||
`
|
||||
|
||||
var b bytes.Buffer
|
||||
templ, err := New(logger).New("test").Parse(in)
|
||||
|
||||
var data struct {
|
||||
Title string
|
||||
Section string
|
||||
|
@ -259,11 +268,21 @@ urlize: bat-man
|
|||
|
||||
tstInitTemplates()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Got error on parse", err)
|
||||
config := defaultDepsConfig
|
||||
config.WithTemplate = func(templ tplapi.Template) error {
|
||||
if _, err := templ.New("test").Parse(in); err != nil {
|
||||
t.Fatal("Got error on parse", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
config.Fs = fs
|
||||
|
||||
d := deps.New(config)
|
||||
if err := d.LoadTemplates(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = templ.Execute(&b, &data)
|
||||
err := d.Tmpl.Lookup("test").Execute(&b, &data)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Got error on execute", err)
|
||||
|
@ -624,15 +643,13 @@ func blankImage(width, height int) []byte {
|
|||
}
|
||||
|
||||
func TestImageConfig(t *testing.T) {
|
||||
viper.Reset()
|
||||
defer viper.Reset()
|
||||
testReset()
|
||||
|
||||
workingDir := "/home/hugo"
|
||||
|
||||
viper.Set("workingDir", workingDir)
|
||||
|
||||
fs := &afero.MemMapFs{}
|
||||
hugofs.InitFs(fs)
|
||||
f := newTestFuncster()
|
||||
|
||||
for i, this := range []struct {
|
||||
resetCache bool
|
||||
|
@ -692,13 +709,13 @@ func TestImageConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
} {
|
||||
afero.WriteFile(fs, filepath.Join(workingDir, this.path), this.input, 0755)
|
||||
afero.WriteFile(f.Fs.Source, filepath.Join(workingDir, this.path), this.input, 0755)
|
||||
|
||||
if this.resetCache {
|
||||
resetImageConfigCache()
|
||||
}
|
||||
|
||||
result, err := imageConfig(this.path)
|
||||
result, err := f.imageConfig(this.path)
|
||||
if err != nil {
|
||||
t.Errorf("imageConfig returned error: %s", err)
|
||||
}
|
||||
|
@ -712,15 +729,15 @@ func TestImageConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if _, err := imageConfig(t); err == nil {
|
||||
if _, err := f.imageConfig(t); err == nil {
|
||||
t.Error("Expected error from imageConfig when passed invalid path")
|
||||
}
|
||||
|
||||
if _, err := imageConfig("non-existent.png"); err == nil {
|
||||
if _, err := f.imageConfig("non-existent.png"); err == nil {
|
||||
t.Error("Expected error from imageConfig when passed non-existent file")
|
||||
}
|
||||
|
||||
if _, err := imageConfig(""); err == nil {
|
||||
if _, err := f.imageConfig(""); err == nil {
|
||||
t.Error("Expected error from imageConfig when passed empty path")
|
||||
}
|
||||
|
||||
|
@ -2381,14 +2398,11 @@ func TestDefault(t *testing.T) {
|
|||
{map[string]string{"foo": "dog"}, `{{ default "nope" .foo "extra" }}`, ``, false},
|
||||
{map[string]interface{}{"images": []string{}}, `{{ default "default.jpg" (index .images 0) }}`, `default.jpg`, true},
|
||||
} {
|
||||
tmpl, err := New(logger).New("test").Parse(this.tpl)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] unable to create new html template %q: %s", i, this.tpl, err)
|
||||
continue
|
||||
}
|
||||
|
||||
tmpl := newTestTemplate(t, "test", this.tpl)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = tmpl.Execute(buf, this.input)
|
||||
err := tmpl.Execute(buf, this.input)
|
||||
if (err == nil) != this.ok {
|
||||
t.Errorf("[%d] execute template returned unexpected error: %s", i, err)
|
||||
continue
|
||||
|
@ -2520,6 +2534,7 @@ func TestSafeCSS(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(bep) what is this? Also look above.
|
||||
func TestSafeJS(t *testing.T) {
|
||||
for i, this := range []struct {
|
||||
str string
|
||||
|
@ -2560,6 +2575,7 @@ func TestSafeJS(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(bep) what is this?
|
||||
func TestSafeURL(t *testing.T) {
|
||||
for i, this := range []struct {
|
||||
str string
|
||||
|
@ -2716,18 +2732,16 @@ func TestSHA256(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestReadFile(t *testing.T) {
|
||||
viper.Reset()
|
||||
defer viper.Reset()
|
||||
testReset()
|
||||
|
||||
workingDir := "/home/hugo"
|
||||
|
||||
viper.Set("workingDir", workingDir)
|
||||
|
||||
fs := &afero.MemMapFs{}
|
||||
hugofs.InitFs(fs)
|
||||
f := newTestFuncster()
|
||||
|
||||
afero.WriteFile(fs, filepath.Join(workingDir, "/f/f1.txt"), []byte("f1-content"), 0755)
|
||||
afero.WriteFile(fs, filepath.Join("/home", "f2.txt"), []byte("f2-content"), 0755)
|
||||
afero.WriteFile(f.Fs.Source, filepath.Join(workingDir, "/f/f1.txt"), []byte("f1-content"), 0755)
|
||||
afero.WriteFile(f.Fs.Source, filepath.Join("/home", "f2.txt"), []byte("f2-content"), 0755)
|
||||
|
||||
for i, this := range []struct {
|
||||
filename string
|
||||
|
@ -2739,7 +2753,7 @@ func TestReadFile(t *testing.T) {
|
|||
{filepath.FromSlash("f/f1.txt"), "f1-content"},
|
||||
{filepath.FromSlash("../f2.txt"), false},
|
||||
} {
|
||||
result, err := readFileFromWorkingDir(this.filename)
|
||||
result, err := f.readFileFromWorkingDir(this.filename)
|
||||
if b, ok := this.expect.(bool); ok && !b {
|
||||
if err == nil {
|
||||
t.Errorf("[%d] readFile didn't return an expected error", i)
|
||||
|
@ -2770,8 +2784,6 @@ func TestPartialCached(t *testing.T) {
|
|||
{"test1", "{{ .Title }} seq: {{ shuffle (seq 1 20) }}", `{{ partialCached "test1" . "%s" }}`, "header"},
|
||||
}
|
||||
|
||||
results := make(map[string]string, len(testCases))
|
||||
|
||||
var data struct {
|
||||
Title string
|
||||
Section string
|
||||
|
@ -2791,26 +2803,32 @@ func TestPartialCached(t *testing.T) {
|
|||
tmp = tc.tmpl
|
||||
}
|
||||
|
||||
tmpl, err := New(logger).New("testroot").Parse(tmp)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d] unable to create new html template: %s", i, err)
|
||||
defaultDepsConfig.WithTemplate = func(templ tplapi.Template) error {
|
||||
err := templ.AddTemplate("testroot", tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = templ.AddTemplate("partials/"+tc.name, tc.partial)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if tmpl == nil {
|
||||
t.Fatalf("[%d] tmpl should not be nil!", i)
|
||||
}
|
||||
|
||||
tmpl.New("partials/" + tc.name).Parse(tc.partial)
|
||||
de := deps.New(defaultDepsConfig)
|
||||
require.NoError(t, de.LoadTemplates())
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = tmpl.Execute(buf, &data)
|
||||
templ := de.Tmpl.Lookup("testroot")
|
||||
err := templ.Execute(buf, &data)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d] error executing template: %s", i, err)
|
||||
}
|
||||
|
||||
for j := 0; j < 10; j++ {
|
||||
buf2 := new(bytes.Buffer)
|
||||
err = tmpl.Execute(buf2, nil)
|
||||
err := templ.Execute(buf2, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d] error executing template 2nd time: %s", i, err)
|
||||
}
|
||||
|
@ -2819,33 +2837,33 @@ func TestPartialCached(t *testing.T) {
|
|||
t.Fatalf("[%d] cached results do not match:\nResult 1:\n%q\nResult 2:\n%q", i, buf, buf2)
|
||||
}
|
||||
}
|
||||
|
||||
// double-check against previous test cases of the same variant
|
||||
previous, ok := results[tc.name+tc.variant]
|
||||
if !ok {
|
||||
results[tc.name+tc.variant] = buf.String()
|
||||
} else {
|
||||
if previous != buf.String() {
|
||||
t.Errorf("[%d] cached variant differs from previous rendering; got:\n%q\nwant:\n%q", i, buf.String(), previous)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPartial(b *testing.B) {
|
||||
tstInitTemplates()
|
||||
tmpl, err := New(logger).New("testroot").Parse(`{{ partial "bench1" . }}`)
|
||||
if err != nil {
|
||||
b.Fatalf("unable to create new html template: %s", err)
|
||||
defaultDepsConfig.WithTemplate = func(templ tplapi.Template) error {
|
||||
err := templ.AddTemplate("testroot", `{{ partial "bench1" . }}`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = templ.AddTemplate("partials/bench1", `{{ shuffle (seq 1 10) }}`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
tmpl.New("partials/bench1").Parse(`{{ shuffle (seq 1 10) }}`)
|
||||
de := deps.New(defaultDepsConfig)
|
||||
require.NoError(b, de.LoadTemplates())
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
tmpl := de.Tmpl.Lookup("testroot")
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err = tmpl.Execute(buf, nil); err != nil {
|
||||
if err := tmpl.Execute(buf, nil); err != nil {
|
||||
b.Fatalf("error executing template: %s", err)
|
||||
}
|
||||
buf.Reset()
|
||||
|
@ -2853,38 +2871,29 @@ func BenchmarkPartial(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkPartialCached(b *testing.B) {
|
||||
tstInitTemplates()
|
||||
tmpl, err := New(logger).New("testroot").Parse(`{{ partialCached "bench1" . }}`)
|
||||
if err != nil {
|
||||
b.Fatalf("unable to create new html template: %s", err)
|
||||
}
|
||||
|
||||
tmpl.New("partials/bench1").Parse(`{{ shuffle (seq 1 10) }}`)
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err = tmpl.Execute(buf, nil); err != nil {
|
||||
b.Fatalf("error executing template: %s", err)
|
||||
defaultDepsConfig.WithTemplate = func(templ tplapi.Template) error {
|
||||
err := templ.AddTemplate("testroot", `{{ partialCached "bench1" . }}`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = templ.AddTemplate("partials/bench1", `{{ shuffle (seq 1 10) }}`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPartialCachedVariants(b *testing.B) {
|
||||
tmpl, err := New(logger).New("testroot").Parse(`{{ partialCached "bench1" . "header" }}`)
|
||||
if err != nil {
|
||||
b.Fatalf("unable to create new html template: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
tmpl.New("partials/bench1").Parse(`{{ shuffle (seq 1 10) }}`)
|
||||
de := deps.New(defaultDepsConfig)
|
||||
require.NoError(b, de.LoadTemplates())
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
tmpl := de.Tmpl.Lookup("testroot")
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err = tmpl.Execute(buf, nil); err != nil {
|
||||
if err := tmpl.Execute(buf, nil); err != nil {
|
||||
b.Fatalf("error executing template: %s", err)
|
||||
}
|
||||
buf.Reset()
|
||||
|
@ -2892,5 +2901,25 @@ func BenchmarkPartialCachedVariants(b *testing.B) {
|
|||
}
|
||||
|
||||
func newTestFuncster() *templateFuncster {
|
||||
return New(logger).funcster
|
||||
d := deps.New(defaultDepsConfig)
|
||||
if err := d.LoadTemplates(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return d.Tmpl.(*GoHTMLTemplate).funcster
|
||||
}
|
||||
|
||||
func newTestTemplate(t *testing.T, name, template string) *template.Template {
|
||||
defaultDepsConfig.WithTemplate = func(templ tplapi.Template) error {
|
||||
err := templ.AddTemplate(name, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
de := deps.New(defaultDepsConfig)
|
||||
require.NoError(t, de.LoadTemplates())
|
||||
|
||||
return de.Tmpl.Lookup(name)
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ type translate struct {
|
|||
current bundle.TranslateFunc
|
||||
}
|
||||
|
||||
// TODO(bep) global translator
|
||||
var translator *translate
|
||||
|
||||
// SetTranslateLang sets the translations language to use during template processing.
|
||||
|
|
|
@ -28,7 +28,6 @@ import (
|
|||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
@ -165,25 +164,25 @@ func resGetLocal(url string, fs afero.Fs) ([]byte, error) {
|
|||
}
|
||||
|
||||
// resGetResource loads the content of a local or remote file
|
||||
func resGetResource(url string) ([]byte, error) {
|
||||
func (t *templateFuncster) resGetResource(url string) ([]byte, error) {
|
||||
if url == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if strings.Contains(url, "://") {
|
||||
return resGetRemote(url, hugofs.Source(), http.DefaultClient)
|
||||
return resGetRemote(url, t.Fs.Source, http.DefaultClient)
|
||||
}
|
||||
return resGetLocal(url, hugofs.Source())
|
||||
return resGetLocal(url, t.Fs.Source)
|
||||
}
|
||||
|
||||
// getJSON expects one or n-parts of a URL to a resource which can either be a local or a remote one.
|
||||
// If you provide multiple parts they will be joined together to the final URL.
|
||||
// GetJSON returns nil or parsed JSON to use in a short code.
|
||||
func getJSON(urlParts ...string) interface{} {
|
||||
func (t *templateFuncster) getJSON(urlParts ...string) interface{} {
|
||||
var v interface{}
|
||||
url := strings.Join(urlParts, "")
|
||||
|
||||
for i := 0; i <= resRetries; i++ {
|
||||
c, err := resGetResource(url)
|
||||
c, err := t.resGetResource(url)
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Failed to get json resource %s with error message %s", url, err)
|
||||
return nil
|
||||
|
@ -194,7 +193,7 @@ func getJSON(urlParts ...string) interface{} {
|
|||
jww.ERROR.Printf("Cannot read json from resource %s with error message %s", url, err)
|
||||
jww.ERROR.Printf("Retry #%d for %s and sleeping for %s", i, url, resSleep)
|
||||
time.Sleep(resSleep)
|
||||
resDeleteCache(url, hugofs.Source())
|
||||
resDeleteCache(url, t.Fs.Source)
|
||||
continue
|
||||
}
|
||||
break
|
||||
|
@ -220,18 +219,18 @@ func parseCSV(c []byte, sep string) ([][]string, error) {
|
|||
// The data separator can be a comma, semi-colon, pipe, etc, but only one character.
|
||||
// If you provide multiple parts for the URL they will be joined together to the final URL.
|
||||
// GetCSV returns nil or a slice slice to use in a short code.
|
||||
func getCSV(sep string, urlParts ...string) [][]string {
|
||||
func (t *templateFuncster) getCSV(sep string, urlParts ...string) [][]string {
|
||||
var d [][]string
|
||||
url := strings.Join(urlParts, "")
|
||||
|
||||
var clearCacheSleep = func(i int, u string) {
|
||||
jww.ERROR.Printf("Retry #%d for %s and sleeping for %s", i, url, resSleep)
|
||||
time.Sleep(resSleep)
|
||||
resDeleteCache(url, hugofs.Source())
|
||||
resDeleteCache(url, t.Fs.Source)
|
||||
}
|
||||
|
||||
for i := 0; i <= resRetries; i++ {
|
||||
c, err := resGetResource(url)
|
||||
c, err := t.resGetResource(url)
|
||||
|
||||
if err == nil && !bytes.Contains(c, []byte(sep)) {
|
||||
err = errors.New("Cannot find separator " + sep + " in CSV.")
|
||||
|
|
|
@ -80,8 +80,10 @@ func TestScpCache(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestScpGetLocal(t *testing.T) {
|
||||
fs := new(afero.MemMapFs)
|
||||
testReset()
|
||||
fs := hugofs.NewMem()
|
||||
ps := helpers.FilePathSeparator
|
||||
|
||||
tests := []struct {
|
||||
path string
|
||||
content []byte
|
||||
|
@ -95,12 +97,12 @@ func TestScpGetLocal(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
r := bytes.NewReader(test.content)
|
||||
err := helpers.WriteToDisk(test.path, r, fs)
|
||||
err := helpers.WriteToDisk(test.path, r, fs.Source)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
c, err := resGetLocal(test.path, fs)
|
||||
c, err := resGetLocal(test.path, fs.Source)
|
||||
if err != nil {
|
||||
t.Errorf("Error getting resource content: %s", err)
|
||||
}
|
||||
|
@ -212,9 +214,9 @@ type wd struct {
|
|||
Reset func()
|
||||
}
|
||||
|
||||
func testRetryWhenDone() wd {
|
||||
func testRetryWhenDone(f *templateFuncster) wd {
|
||||
cd := viper.GetString("cacheDir")
|
||||
viper.Set("cacheDir", helpers.GetTempDir("", hugofs.Source()))
|
||||
viper.Set("cacheDir", helpers.GetTempDir("", f.Fs.Source))
|
||||
var tmpSleep time.Duration
|
||||
tmpSleep, resSleep = resSleep, time.Millisecond
|
||||
return wd{func() {
|
||||
|
@ -224,7 +226,10 @@ func testRetryWhenDone() wd {
|
|||
}
|
||||
|
||||
func TestGetJSONFailParse(t *testing.T) {
|
||||
defer testRetryWhenDone().Reset()
|
||||
|
||||
f := newTestFuncster()
|
||||
|
||||
defer testRetryWhenDone(f).Reset()
|
||||
|
||||
reqCount := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -242,7 +247,7 @@ func TestGetJSONFailParse(t *testing.T) {
|
|||
defer os.Remove(getCacheFileID(url))
|
||||
|
||||
want := map[string]interface{}{"gomeetup": []interface{}{"Sydney", "San Francisco", "Stockholm"}}
|
||||
have := getJSON(url)
|
||||
have := f.getJSON(url)
|
||||
assert.NotNil(t, have)
|
||||
if have != nil {
|
||||
assert.EqualValues(t, want, have)
|
||||
|
@ -250,7 +255,9 @@ func TestGetJSONFailParse(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetCSVFailParseSep(t *testing.T) {
|
||||
defer testRetryWhenDone().Reset()
|
||||
f := newTestFuncster()
|
||||
|
||||
defer testRetryWhenDone(f).Reset()
|
||||
|
||||
reqCount := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -271,7 +278,7 @@ func TestGetCSVFailParseSep(t *testing.T) {
|
|||
defer os.Remove(getCacheFileID(url))
|
||||
|
||||
want := [][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}}
|
||||
have := getCSV(",", url)
|
||||
have := f.getCSV(",", url)
|
||||
assert.NotNil(t, have)
|
||||
if have != nil {
|
||||
assert.EqualValues(t, want, have)
|
||||
|
@ -279,7 +286,10 @@ func TestGetCSVFailParseSep(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetCSVFailParse(t *testing.T) {
|
||||
defer testRetryWhenDone().Reset()
|
||||
|
||||
f := newTestFuncster()
|
||||
|
||||
defer testRetryWhenDone(f).Reset()
|
||||
|
||||
reqCount := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -302,7 +312,7 @@ func TestGetCSVFailParse(t *testing.T) {
|
|||
defer os.Remove(getCacheFileID(url))
|
||||
|
||||
want := [][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}}
|
||||
have := getCSV(",", url)
|
||||
have := f.getCSV(",", url)
|
||||
assert.NotNil(t, have)
|
||||
if have != nil {
|
||||
assert.EqualValues(t, want, have)
|
||||
|
|
|
@ -25,9 +25,21 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/hugo/tplapi"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testReset() {
|
||||
viper.Reset()
|
||||
|
||||
// TODO(bep) viper-globals
|
||||
viper.Set("currentContentLanguage", helpers.NewLanguage("en"))
|
||||
}
|
||||
|
||||
// Some tests for Issue #1178 -- Ace
|
||||
func TestAceTemplates(t *testing.T) {
|
||||
|
||||
|
@ -68,11 +80,19 @@ html lang=en
|
|||
|
||||
d := "DATA"
|
||||
|
||||
templ := New(logger, func(templ Template) error {
|
||||
config := defaultDepsConfig
|
||||
config.WithTemplate = func(templ tplapi.Template) error {
|
||||
return templ.AddAceTemplate("mytemplate.ace", basePath, innerPath,
|
||||
[]byte(this.baseContent), []byte(this.innerContent))
|
||||
}
|
||||
|
||||
})
|
||||
a := deps.New(config)
|
||||
|
||||
if err := a.LoadTemplates(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
templ := a.Tmpl.(*GoHTMLTemplate)
|
||||
|
||||
if len(templ.errors) > 0 && this.expectErr == 0 {
|
||||
t.Errorf("Test %d with root '%s' errored: %v", i, root, templ.errors)
|
||||
|
@ -81,7 +101,7 @@ html lang=en
|
|||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
err := templ.ExecuteTemplate(&buff, "mytemplate.html", d)
|
||||
err := a.Tmpl.ExecuteTemplate(&buff, "mytemplate.html", d)
|
||||
|
||||
if err != nil && this.expectErr == 0 {
|
||||
t.Errorf("Test %d with root '%s' errored: %s", i, root, err)
|
||||
|
@ -93,6 +113,7 @@ html lang=en
|
|||
t.Errorf("Test %d with root '%s' got\n%s\nexpected\n%s", i, root, result, this.expect)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,52 +145,59 @@ func TestAddTemplateFileWithMaster(t *testing.T) {
|
|||
{`tpl`, `{{.0.E}}`, 0, false},
|
||||
} {
|
||||
|
||||
hugofs.InitMemFs()
|
||||
templ := New(logger)
|
||||
overlayTplName := "ot"
|
||||
masterTplName := "mt"
|
||||
finalTplName := "tp"
|
||||
|
||||
defaultDepsConfig.WithTemplate = func(templ tplapi.Template) error {
|
||||
|
||||
err := templ.AddTemplateFileWithMaster(finalTplName, overlayTplName, masterTplName)
|
||||
|
||||
if b, ok := this.expect.(bool); ok && !b {
|
||||
if err == nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster didn't return an expected error", i)
|
||||
}
|
||||
} else {
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster failed: %s", i, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
resultTpl := templ.Lookup(finalTplName)
|
||||
|
||||
if resultTpl == nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster: Result template not found", i)
|
||||
return nil
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err := resultTpl.Execute(&b, nil)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster execute failed: %s", i, err)
|
||||
return nil
|
||||
}
|
||||
resultContent := b.String()
|
||||
|
||||
if resultContent != this.expect {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster got \n%s but expected \n%v", i, resultContent, this.expect)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultDepsConfig.Fs = hugofs.NewMem()
|
||||
|
||||
if this.writeSkipper != 1 {
|
||||
afero.WriteFile(hugofs.Source(), masterTplName, []byte(this.masterTplContent), 0644)
|
||||
afero.WriteFile(defaultDepsConfig.Fs.Source, masterTplName, []byte(this.masterTplContent), 0644)
|
||||
}
|
||||
if this.writeSkipper != 2 {
|
||||
afero.WriteFile(hugofs.Source(), overlayTplName, []byte(this.overlayTplContent), 0644)
|
||||
afero.WriteFile(defaultDepsConfig.Fs.Source, overlayTplName, []byte(this.overlayTplContent), 0644)
|
||||
}
|
||||
|
||||
err := templ.AddTemplateFileWithMaster(finalTplName, overlayTplName, masterTplName)
|
||||
|
||||
if b, ok := this.expect.(bool); ok && !b {
|
||||
if err == nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster didn't return an expected error", i)
|
||||
}
|
||||
} else {
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster failed: %s", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
resultTpl := templ.Lookup(finalTplName)
|
||||
|
||||
if resultTpl == nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster: Result template not found", i)
|
||||
continue
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err := resultTpl.Execute(&b, nil)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster execute failed: %s", i, err)
|
||||
continue
|
||||
}
|
||||
resultContent := b.String()
|
||||
|
||||
if resultContent != this.expect {
|
||||
t.Errorf("[%d] AddTemplateFileWithMaster got \n%s but expected \n%v", i, resultContent, this.expect)
|
||||
}
|
||||
}
|
||||
deps.New(defaultDepsConfig)
|
||||
|
||||
}
|
||||
|
||||
|
@ -258,23 +286,29 @@ func TestTplGoFuzzReports(t *testing.T) {
|
|||
H: "a,b,c,d,e,f",
|
||||
}
|
||||
|
||||
templ := New(logger, func(templ Template) error {
|
||||
defaultDepsConfig.WithTemplate = func(templ tplapi.Template) error {
|
||||
return templ.AddTemplate("fuzz", this.data)
|
||||
}
|
||||
|
||||
})
|
||||
de := deps.New(defaultDepsConfig)
|
||||
require.NoError(t, de.LoadTemplates())
|
||||
|
||||
templ := de.Tmpl.(*GoHTMLTemplate)
|
||||
|
||||
if len(templ.errors) > 0 && this.expectErr == 0 {
|
||||
t.Errorf("Test %d errored: %v", i, templ.errors)
|
||||
} else if len(templ.errors) == 0 && this.expectErr == 1 {
|
||||
t.Errorf("#1 Test %d should have errored", i)
|
||||
}
|
||||
err := templ.ExecuteTemplate(ioutil.Discard, "fuzz", d)
|
||||
|
||||
err := de.Tmpl.ExecuteTemplate(ioutil.Discard, "fuzz", d)
|
||||
|
||||
if err != nil && this.expectErr == 0 {
|
||||
t.Fatalf("Test %d errored: %s", i, err)
|
||||
} else if err == nil && this.expectErr == 2 {
|
||||
t.Fatalf("#2 Test %d should have errored", i)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package tplapi
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io"
|
||||
)
|
||||
|
||||
// TODO(bep) make smaller
|
||||
// TODO(bep) consider putting this into /tpl and the implementation in /tpl/tplimpl or something
|
||||
type Template interface {
|
||||
ExecuteTemplate(wr io.Writer, name string, data interface{}) error
|
||||
ExecuteTemplateToHTML(context interface{}, layouts ...string) template.HTML
|
||||
Lookup(name string) *template.Template
|
||||
Templates() []*template.Template
|
||||
New(name string) *template.Template
|
||||
GetClone() *template.Template
|
||||
LoadTemplates(absPath string)
|
||||
LoadTemplatesWithPrefix(absPath, prefix string)
|
||||
AddTemplate(name, tpl string) error
|
||||
AddTemplateFileWithMaster(name, overlayFilename, masterFilename string) error
|
||||
AddAceTemplate(name, basePath, innerPath string, baseContent, innerContent []byte) error
|
||||
AddInternalTemplate(prefix, name, tpl string) error
|
||||
AddInternalShortcode(name, tpl string) error
|
||||
Partial(name string, contextList ...interface{}) template.HTML
|
||||
PrintErrors()
|
||||
Funcs(funcMap template.FuncMap)
|
||||
MarkReady()
|
||||
}
|
Loading…
Reference in New Issue