2017-01-10 04:55:03 -05:00
package hugolib
import (
"path/filepath"
"testing"
2018-03-16 13:27:44 -04:00
"bytes"
2017-02-17 14:52:50 -05:00
"fmt"
2018-03-15 04:37:30 -04:00
"regexp"
2017-02-17 14:52:50 -05:00
"strings"
2018-03-16 13:27:44 -04:00
"text/template"
2017-02-17 14:52:50 -05:00
2018-03-18 06:07:24 -04:00
"github.com/sanity-io/litter"
2018-03-15 04:37:30 -04:00
jww "github.com/spf13/jwalterweatherman"
2017-06-13 12:42:45 -04:00
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/deps"
2017-06-13 13:07:35 -04:00
"github.com/spf13/afero"
2017-02-20 03:33:35 -05:00
2017-06-13 12:42:45 -04:00
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/tpl"
2017-01-10 04:55:03 -05:00
"github.com/spf13/viper"
2017-02-04 22:20:06 -05:00
"io/ioutil"
"os"
"log"
2017-06-13 12:42:45 -04:00
"github.com/gohugoio/hugo/hugofs"
2018-03-16 13:27:44 -04:00
"github.com/stretchr/testify/assert"
2017-01-10 04:55:03 -05:00
"github.com/stretchr/testify/require"
)
2018-03-15 04:37:30 -04:00
const ( )
type sitesBuilder struct {
Cfg config . Provider
Fs * hugofs . Fs
T testing . TB
2018-05-08 04:10:13 -04:00
logger * jww . Notepad
2018-03-18 06:07:24 -04:00
dumper litter . Options
2018-03-16 13:27:44 -04:00
// Aka the Hugo server mode.
running bool
2018-03-15 04:37:30 -04:00
H * HugoSites
2018-03-18 06:07:24 -04:00
theme string
2018-03-16 13:27:44 -04:00
// Default toml
configFormat string
2018-03-21 12:21:46 -04:00
// Default is empty.
// TODO(bep) revisit this and consider always setting it to something.
// Consider this in relation to using the BaseFs.PublishFs to all publishing.
workingDir string
2018-03-17 14:24:02 -04:00
// Base data/content
contentFilePairs [ ] string
templateFilePairs [ ] string
i18nFilePairs [ ] string
dataFilePairs [ ] string
// Additional data/content.
// As in "use the base, but add these on top".
contentFilePairsAdded [ ] string
templateFilePairsAdded [ ] string
i18nFilePairsAdded [ ] string
dataFilePairsAdded [ ] string
2018-03-15 04:37:30 -04:00
}
func newTestSitesBuilder ( t testing . TB ) * sitesBuilder {
v := viper . New ( )
fs := hugofs . NewMem ( v )
2018-03-18 06:07:24 -04:00
litterOptions := litter . Options {
HidePrivateFields : true ,
StripPackageNames : true ,
Separator : " " ,
}
return & sitesBuilder { T : t , Fs : fs , configFormat : "toml" , dumper : litterOptions }
2018-03-16 13:27:44 -04:00
}
func ( s * sitesBuilder ) Running ( ) * sitesBuilder {
s . running = true
return s
}
2018-05-08 04:10:13 -04:00
func ( s * sitesBuilder ) WithLogger ( logger * jww . Notepad ) * sitesBuilder {
s . logger = logger
return s
}
2018-03-21 12:21:46 -04:00
func ( s * sitesBuilder ) WithWorkingDir ( dir string ) * sitesBuilder {
s . workingDir = dir
return s
}
2018-03-16 13:27:44 -04:00
func ( s * sitesBuilder ) WithConfigTemplate ( data interface { } , format , configTemplate string ) * sitesBuilder {
if format == "" {
format = "toml"
}
templ , err := template . New ( "test" ) . Parse ( configTemplate )
if err != nil {
2018-03-17 14:24:02 -04:00
s . Fatalf ( "Template parse failed: %s" , err )
2018-03-16 13:27:44 -04:00
}
var b bytes . Buffer
templ . Execute ( & b , data )
2018-03-17 14:24:02 -04:00
return s . WithConfigFile ( format , b . String ( ) )
2018-03-15 04:37:30 -04:00
}
2018-03-17 14:24:02 -04:00
func ( s * sitesBuilder ) WithViper ( v * viper . Viper ) * sitesBuilder {
loadDefaultSettingsFor ( v )
s . Cfg = v
return s
}
func ( s * sitesBuilder ) WithConfigFile ( format , conf string ) * sitesBuilder {
2018-03-16 13:27:44 -04:00
writeSource ( s . T , s . Fs , "config." + format , conf )
s . configFormat = format
2018-03-15 04:37:30 -04:00
return s
}
2018-03-18 06:07:24 -04:00
func ( s * sitesBuilder ) WithThemeConfigFile ( format , conf string ) * sitesBuilder {
if s . theme == "" {
s . theme = "test-theme"
}
filename := filepath . Join ( "themes" , s . theme , "config." + format )
writeSource ( s . T , s . Fs , filename , conf )
return s
}
2018-05-23 04:03:11 -04:00
const commonConfigSections = `
[ services ]
[ services . disqus ]
shortname = "disqus_shortname"
[ services . googleAnalytics ]
id = "ga_id"
2018-05-25 04:53:39 -04:00
[ privacy ]
[ privacy . disqus ]
disable = false
[ privacy . googleAnalytics ]
respectDoNotTrack = true
anonymizeIP = true
[ privacy . instagram ]
simple = true
[ privacy . speakerDeck ]
[ privacy . twitter ]
enableDNT = true
[ privacy . vimeo ]
disable = false
[ privacy . youtube ]
disable = false
privacyEnhanced = true
2018-05-23 04:03:11 -04:00
`
2018-03-17 14:24:02 -04:00
func ( s * sitesBuilder ) WithSimpleConfigFile ( ) * sitesBuilder {
var config = `
baseURL = "http://example.com/"
2018-05-23 04:03:11 -04:00
` + commonConfigSections
2018-03-17 14:24:02 -04:00
return s . WithConfigFile ( "toml" , config )
}
2018-03-15 04:37:30 -04:00
func ( s * sitesBuilder ) WithDefaultMultiSiteConfig ( ) * sitesBuilder {
var defaultMultiSiteConfig = `
baseURL = "http://example.com/blog"
paginate = 1
disablePathToLower = true
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true
[ permalinks ]
other = "/somewhere/else/:filename"
[ blackfriday ]
angledQuotes = true
[ Taxonomies ]
tag = "tags"
[ Languages ]
[ Languages . en ]
weight = 10
title = "In English"
languageName = "English"
[ Languages . en . blackfriday ]
angledQuotes = false
[ [ Languages . en . menu . main ] ]
url = "/"
name = "Home"
weight = 0
[ Languages . fr ]
weight = 20
title = "Le Français"
languageName = "Français"
[ Languages . fr . Taxonomies ]
plaque = "plaques"
[ Languages . nn ]
weight = 30
title = "På nynorsk"
languageName = "Nynorsk"
paginatePath = "side"
[ Languages . nn . Taxonomies ]
lag = "lag"
[ [ Languages . nn . menu . main ] ]
url = "/"
name = "Heim"
weight = 1
[ Languages . nb ]
weight = 40
title = "På bokmål"
languageName = "Bokmål"
paginatePath = "side"
[ Languages . nb . Taxonomies ]
lag = "lag"
2018-05-23 04:03:11 -04:00
` + commonConfigSections
2018-03-15 04:37:30 -04:00
2018-03-17 14:24:02 -04:00
return s . WithConfigFile ( "toml" , defaultMultiSiteConfig )
2018-03-15 04:37:30 -04:00
}
func ( s * sitesBuilder ) WithContent ( filenameContent ... string ) * sitesBuilder {
2018-03-17 14:24:02 -04:00
s . contentFilePairs = append ( s . contentFilePairs , filenameContent ... )
return s
2018-03-16 13:27:44 -04:00
}
func ( s * sitesBuilder ) WithContentAdded ( filenameContent ... string ) * sitesBuilder {
2018-03-17 14:24:02 -04:00
s . contentFilePairsAdded = append ( s . contentFilePairsAdded , filenameContent ... )
2018-03-15 04:37:30 -04:00
return s
}
func ( s * sitesBuilder ) WithTemplates ( filenameContent ... string ) * sitesBuilder {
2018-03-17 14:24:02 -04:00
s . templateFilePairs = append ( s . templateFilePairs , filenameContent ... )
return s
2018-03-16 13:27:44 -04:00
}
func ( s * sitesBuilder ) WithTemplatesAdded ( filenameContent ... string ) * sitesBuilder {
2018-03-17 14:24:02 -04:00
s . templateFilePairsAdded = append ( s . templateFilePairsAdded , filenameContent ... )
return s
}
func ( s * sitesBuilder ) WithData ( filenameContent ... string ) * sitesBuilder {
s . dataFilePairs = append ( s . dataFilePairs , filenameContent ... )
return s
}
func ( s * sitesBuilder ) WithDataAdded ( filenameContent ... string ) * sitesBuilder {
s . dataFilePairsAdded = append ( s . dataFilePairsAdded , filenameContent ... )
return s
}
func ( s * sitesBuilder ) WithI18n ( filenameContent ... string ) * sitesBuilder {
s . i18nFilePairs = append ( s . i18nFilePairs , filenameContent ... )
return s
}
func ( s * sitesBuilder ) WithI18nAdded ( filenameContent ... string ) * sitesBuilder {
s . i18nFilePairsAdded = append ( s . i18nFilePairsAdded , filenameContent ... )
return s
}
func ( s * sitesBuilder ) writeFilePairs ( folder string , filenameContent [ ] string ) * sitesBuilder {
if len ( filenameContent ) % 2 != 0 {
s . Fatalf ( "expect filenameContent for %q in pairs (%d)" , folder , len ( filenameContent ) )
}
2018-03-15 04:37:30 -04:00
for i := 0 ; i < len ( filenameContent ) ; i += 2 {
filename , content := filenameContent [ i ] , filenameContent [ i + 1 ]
2018-03-21 12:21:46 -04:00
target := folder
// TODO(bep) clean up this magic.
if strings . HasPrefix ( filename , folder ) {
target = ""
}
if s . workingDir != "" {
target = filepath . Join ( s . workingDir , target )
}
writeSource ( s . T , s . Fs , filepath . Join ( target , filename ) , content )
2018-03-15 04:37:30 -04:00
}
return s
}
func ( s * sitesBuilder ) CreateSites ( ) * sitesBuilder {
2018-03-17 14:24:02 -04:00
s . addDefaults ( )
s . writeFilePairs ( "content" , s . contentFilePairs )
s . writeFilePairs ( "content" , s . contentFilePairsAdded )
s . writeFilePairs ( "layouts" , s . templateFilePairs )
s . writeFilePairs ( "layouts" , s . templateFilePairsAdded )
s . writeFilePairs ( "data" , s . dataFilePairs )
s . writeFilePairs ( "data" , s . dataFilePairsAdded )
s . writeFilePairs ( "i18n" , s . i18nFilePairs )
s . writeFilePairs ( "i18n" , s . i18nFilePairsAdded )
2018-03-15 04:37:30 -04:00
if s . Cfg == nil {
2018-03-18 06:07:24 -04:00
cfg , configFiles , err := LoadConfig ( ConfigSourceDescriptor { Fs : s . Fs . Source , Filename : "config." + s . configFormat } )
2018-03-15 04:37:30 -04:00
if err != nil {
2018-03-17 14:24:02 -04:00
s . Fatalf ( "Failed to load config: %s" , err )
2018-03-15 04:37:30 -04:00
}
2018-03-18 06:07:24 -04:00
expectedConfigs := 1
if s . theme != "" {
expectedConfigs = 2
}
require . Equal ( s . T , expectedConfigs , len ( configFiles ) , fmt . Sprintf ( "Configs: %v" , configFiles ) )
2018-03-15 04:37:30 -04:00
s . Cfg = cfg
}
2018-05-08 04:10:13 -04:00
sites , err := NewHugoSites ( deps . DepsCfg { Fs : s . Fs , Cfg : s . Cfg , Logger : s . logger , Running : s . running } )
2018-03-15 04:37:30 -04:00
if err != nil {
2018-03-17 14:24:02 -04:00
s . Fatalf ( "Failed to create sites: %s" , err )
2018-03-15 04:37:30 -04:00
}
s . H = sites
return s
}
func ( s * sitesBuilder ) Build ( cfg BuildCfg ) * sitesBuilder {
2018-03-24 04:19:49 -04:00
return s . build ( cfg , false )
}
func ( s * sitesBuilder ) BuildFail ( cfg BuildCfg ) * sitesBuilder {
return s . build ( cfg , true )
}
func ( s * sitesBuilder ) build ( cfg BuildCfg , shouldFail bool ) * sitesBuilder {
2018-03-15 04:37:30 -04:00
if s . H == nil {
2018-03-17 14:24:02 -04:00
s . CreateSites ( )
2018-03-15 04:37:30 -04:00
}
err := s . H . Build ( cfg )
2018-05-23 04:03:11 -04:00
if err == nil {
logErrorCount := s . H . NumLogErrors ( )
if logErrorCount > 0 {
err = fmt . Errorf ( "logged %d errors" , logErrorCount )
}
}
2018-03-24 04:19:49 -04:00
if err != nil && ! shouldFail {
2018-03-17 14:24:02 -04:00
s . Fatalf ( "Build failed: %s" , err )
2018-03-24 04:19:49 -04:00
} else if err == nil && shouldFail {
s . Fatalf ( "Expected error" )
2018-03-15 04:37:30 -04:00
}
return s
}
2018-03-17 14:24:02 -04:00
func ( s * sitesBuilder ) addDefaults ( ) {
2018-03-15 04:37:30 -04:00
2018-03-17 14:24:02 -04:00
var (
contentTemplate = ` -- -
2018-03-15 04:37:30 -04:00
title : doc1
weight : 1
tags :
- tag1
date : "2018-02-28"
-- -
# doc1
* some "content" *
{ { < shortcode > } }
{ { < lingo > } }
`
2018-03-17 14:24:02 -04:00
defaultContent = [ ] string {
"content/sect/doc1.en.md" , contentTemplate ,
"content/sect/doc1.fr.md" , contentTemplate ,
"content/sect/doc1.nb.md" , contentTemplate ,
"content/sect/doc1.nn.md" , contentTemplate ,
}
defaultTemplates = [ ] string {
"_default/single.html" , "Single: {{ .Title }}|{{ i18n \"hello\" }}|{{.Lang}}|{{ .Content }}" ,
"_default/list.html" , "{{ $p := .Paginator }}List Page {{ $p.PageNumber }}: {{ .Title }}|{{ i18n \"hello\" }}|{{ .Permalink }}|Pager: {{ template \"_internal/pagination.html\" . }}" ,
"index.html" , "{{ $p := .Paginator }}Default Home Page {{ $p.PageNumber }}: {{ .Title }}|{{ .IsHome }}|{{ i18n \"hello\" }}|{{ .Permalink }}|{{ .Site.Data.hugo.slogan }}" ,
"index.fr.html" , "{{ $p := .Paginator }}French Home Page {{ $p.PageNumber }}: {{ .Title }}|{{ .IsHome }}|{{ i18n \"hello\" }}|{{ .Permalink }}|{{ .Site.Data.hugo.slogan }}" ,
// Shortcodes
"shortcodes/shortcode.html" , "Shortcode: {{ i18n \"hello\" }}" ,
// A shortcode in multiple languages
"shortcodes/lingo.html" , "LingoDefault" ,
"shortcodes/lingo.fr.html" , "LingoFrench" ,
}
defaultI18n = [ ] string {
"en.yaml" , `
hello :
other : "Hello"
` ,
"fr.yaml" , `
hello :
other : "Bonjour"
` ,
}
defaultData = [ ] string {
"hugo.toml" , "slogan = \"Hugo Rocks!\"" ,
}
)
if len ( s . contentFilePairs ) == 0 {
s . writeFilePairs ( "content" , defaultContent )
}
if len ( s . templateFilePairs ) == 0 {
s . writeFilePairs ( "layouts" , defaultTemplates )
}
if len ( s . dataFilePairs ) == 0 {
s . writeFilePairs ( "data" , defaultData )
}
if len ( s . i18nFilePairs ) == 0 {
s . writeFilePairs ( "i18n" , defaultI18n )
}
2018-03-15 04:37:30 -04:00
}
2018-03-16 13:27:44 -04:00
func ( s * sitesBuilder ) Fatalf ( format string , args ... interface { } ) {
Fatalf ( s . T , format , args ... )
}
func Fatalf ( t testing . TB , format string , args ... interface { } ) {
trace := strings . Join ( assert . CallerInfo ( ) , "\n\r\t\t\t" )
format = format + "\n%s"
args = append ( args , trace )
t . Fatalf ( format , args ... )
}
2018-03-15 04:37:30 -04:00
func ( s * sitesBuilder ) AssertFileContent ( filename string , matches ... string ) {
content := readDestination ( s . T , s . Fs , filename )
for _ , match := range matches {
if ! strings . Contains ( content , match ) {
2018-03-16 13:27:44 -04:00
s . Fatalf ( "No match for %q in content for %s\n%q" , match , filename , content )
2018-03-15 04:37:30 -04:00
}
}
}
2018-03-18 06:07:24 -04:00
func ( s * sitesBuilder ) AssertObject ( expected string , object interface { } ) {
got := s . dumper . Sdump ( object )
expected = strings . TrimSpace ( expected )
if expected != got {
fmt . Println ( got )
diff := helpers . DiffStrings ( expected , got )
s . Fatalf ( "diff:\n%s\nexpected\n%s\ngot\n%s" , diff , expected , got )
}
}
2018-03-15 04:37:30 -04:00
func ( s * sitesBuilder ) AssertFileContentRe ( filename string , matches ... string ) {
content := readDestination ( s . T , s . Fs , filename )
for _ , match := range matches {
r := regexp . MustCompile ( match )
if ! r . MatchString ( content ) {
2018-03-16 13:27:44 -04:00
s . Fatalf ( "No match for %q in content for %s\n%q" , match , filename , content )
2018-03-15 04:37:30 -04:00
}
}
}
2018-03-17 14:24:02 -04:00
func ( s * sitesBuilder ) CheckExists ( filename string ) bool {
return destinationExists ( s . Fs , filepath . Clean ( filename ) )
}
2017-02-17 14:52:50 -05:00
type testHelper struct {
Cfg config . Provider
Fs * hugofs . Fs
T testing . TB
}
2017-02-17 15:14:52 -05:00
func ( th testHelper ) assertFileContent ( filename string , matches ... string ) {
filename = th . replaceDefaultContentLanguageValue ( filename )
2017-02-17 14:52:50 -05:00
content := readDestination ( th . T , th . Fs , filename )
for _ , match := range matches {
2017-02-17 15:14:52 -05:00
match = th . replaceDefaultContentLanguageValue ( match )
2017-02-17 14:52:50 -05:00
require . True ( th . 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 ) ) )
}
}
2017-02-17 15:14:52 -05:00
func ( th testHelper ) assertFileContentRegexp ( filename string , matches ... string ) {
filename = th . replaceDefaultContentLanguageValue ( filename )
content := readDestination ( th . T , th . Fs , filename )
for _ , match := range matches {
match = th . replaceDefaultContentLanguageValue ( match )
2017-02-17 14:52:50 -05:00
r := regexp . MustCompile ( match )
require . True ( th . T , r . MatchString ( content ) , fmt . Sprintf ( "File no match for\n%q in\n%q:\n%s" , strings . Replace ( match , "%" , "%%" , - 1 ) , filename , strings . Replace ( content , "%" , "%%" , - 1 ) ) )
}
}
2017-04-23 16:03:25 -04:00
func ( th testHelper ) assertFileNotExist ( filename string ) {
exists , err := helpers . Exists ( filename , th . Fs . Destination )
require . NoError ( th . T , err )
require . False ( th . T , exists )
}
2017-02-17 15:14:52 -05:00
func ( th testHelper ) replaceDefaultContentLanguageValue ( value string ) string {
defaultInSubDir := th . Cfg . GetBool ( "defaultContentLanguageInSubDir" )
replace := th . Cfg . GetString ( "defaultContentLanguage" ) + "/"
if ! defaultInSubDir {
value = strings . Replace ( value , replace , "" , 1 )
}
return value
}
2017-02-04 22:20:06 -05:00
func newTestPathSpec ( fs * hugofs . Fs , v * viper . Viper ) * helpers . PathSpec {
l := helpers . NewDefaultLanguage ( v )
2017-03-25 09:37:04 -04:00
ps , _ := helpers . NewPathSpec ( fs , l )
return ps
2017-01-10 04:55:03 -05:00
}
2017-03-09 13:19:29 -05:00
func newTestDefaultPathSpec ( ) * helpers . PathSpec {
v := viper . New ( )
// Easier to reason about in tests.
v . Set ( "disablePathToLower" , true )
2018-03-21 12:21:46 -04:00
v . Set ( "contentDir" , "content" )
2017-03-09 13:19:29 -05:00
fs := hugofs . NewDefault ( v )
2017-03-25 09:37:04 -04:00
ps , _ := helpers . NewPathSpec ( fs , v )
return ps
2017-03-09 13:19:29 -05:00
}
2017-02-04 22:20:06 -05:00
func newTestCfg ( ) ( * viper . Viper , * hugofs . Fs ) {
v := viper . New ( )
fs := hugofs . NewMem ( v )
v . SetFs ( fs . Source )
loadDefaultSettingsFor ( v )
// Default is false, but true is easier to use as default in tests
v . Set ( "defaultContentLanguageInSubdir" , true )
return v , fs
}
// newTestSite creates a new site in the English language with in-memory Fs.
// The site will have a template system loaded and ready to use.
// Note: This is only used in single site tests.
func newTestSite ( t testing . TB , configKeyValues ... interface { } ) * Site {
cfg , fs := newTestCfg ( )
for i := 0 ; i < len ( configKeyValues ) ; i += 2 {
cfg . Set ( configKeyValues [ i ] . ( string ) , configKeyValues [ i + 1 ] )
}
2017-03-06 13:54:46 -05:00
d := deps . DepsCfg { Language : helpers . NewLanguage ( "en" , cfg ) , Fs : fs , Cfg : cfg }
2017-02-04 22:20:06 -05:00
s , err := NewSiteForCfg ( d )
if err != nil {
2018-03-16 13:27:44 -04:00
Fatalf ( t , "Failed to create Site: %s" , err )
2017-02-04 22:20:06 -05:00
}
return s
}
2017-03-27 14:43:49 -04:00
func newTestSitesFromConfig ( t testing . TB , afs afero . Fs , tomlConfig string , layoutPathContentPairs ... string ) ( testHelper , * HugoSites ) {
2017-02-20 03:33:35 -05:00
if len ( layoutPathContentPairs ) % 2 != 0 {
2018-03-16 13:27:44 -04:00
Fatalf ( t , "Layouts must be provided in pairs" )
2017-02-20 03:33:35 -05:00
}
2017-03-27 14:43:49 -04:00
writeToFs ( t , afs , "config.toml" , tomlConfig )
2017-02-20 03:33:35 -05:00
2018-03-18 05:32:29 -04:00
cfg , err := LoadConfigDefault ( afs )
2017-02-20 03:33:35 -05:00
require . NoError ( t , err )
2017-03-27 14:43:49 -04:00
fs := hugofs . NewFrom ( afs , cfg )
2017-02-20 03:33:35 -05:00
th := testHelper { cfg , fs , t }
for i := 0 ; i < len ( layoutPathContentPairs ) ; i += 2 {
writeSource ( t , fs , layoutPathContentPairs [ i ] , layoutPathContentPairs [ i + 1 ] )
}
h , err := NewHugoSites ( deps . DepsCfg { Fs : fs , Cfg : cfg } )
require . NoError ( t , err )
return th , h
}
func newTestSitesFromConfigWithDefaultTemplates ( t testing . TB , tomlConfig string ) ( testHelper , * HugoSites ) {
2017-03-27 14:43:49 -04:00
return newTestSitesFromConfig ( t , afero . NewMemMapFs ( ) , tomlConfig ,
2017-02-20 03:33:35 -05:00
"layouts/_default/single.html" , "Single|{{ .Title }}|{{ .Content }}" ,
"layouts/_default/list.html" , "List|{{ .Title }}|{{ .Content }}" ,
"layouts/_default/terms.html" , "Terms List|{{ .Title }}|{{ .Content }}" ,
)
}
2017-02-04 22:20:06 -05:00
func newDebugLogger ( ) * jww . Notepad {
return jww . NewNotepad ( jww . LevelDebug , jww . LevelError , os . Stdout , ioutil . Discard , "" , log . Ldate | log . Ltime )
2017-01-10 04:55:03 -05:00
}
2017-03-03 04:47:43 -05:00
func newErrorLogger ( ) * jww . Notepad {
return jww . NewNotepad ( jww . LevelError , jww . LevelError , os . Stdout , ioutil . Discard , "" , log . Ldate | log . Ltime )
}
:sparkles: Implement Page bundling and image handling
This commit is not the smallest in Hugo's history.
Some hightlights include:
* Page bundles (for complete articles, keeping images and content together etc.).
* Bundled images can be processed in as many versions/sizes as you need with the three methods `Resize`, `Fill` and `Fit`.
* Processed images are cached inside `resources/_gen/images` (default) in your project.
* Symbolic links (both files and dirs) are now allowed anywhere inside /content
* A new table based build summary
* The "Total in nn ms" now reports the total including the handling of the files inside /static. So if it now reports more than you're used to, it is just **more real** and probably faster than before (see below).
A site building benchmark run compared to `v0.31.1` shows that this should be slightly faster and use less memory:
```bash
▶ ./benchSite.sh "TOML,num_langs=.*,num_root_sections=5,num_pages=(500|1000),tags_per_page=5,shortcodes,render"
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 101785785 78067944 -23.30%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 185481057 149159919 -19.58%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 103149918 85679409 -16.94%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 203515478 169208775 -16.86%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 532464 391539 -26.47%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1056549 772702 -26.87%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 555974 406630 -26.86%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1086545 789922 -27.30%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 53243246 43598155 -18.12%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 105811617 86087116 -18.64%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 54558852 44545097 -18.35%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 106903858 86978413 -18.64%
```
Fixes #3651
Closes #3158
Fixes #1014
Closes #2021
Fixes #1240
Updates #3757
2017-07-24 03:00:23 -04:00
func newWarningLogger ( ) * jww . Notepad {
return jww . NewNotepad ( jww . LevelWarn , jww . LevelError , os . Stdout , ioutil . Discard , "" , log . Ldate | log . Ltime )
}
2017-03-27 14:43:49 -04:00
func createWithTemplateFromNameValues ( additionalTemplates ... string ) func ( templ tpl . TemplateHandler ) error {
2017-01-10 04:55:03 -05:00
2017-03-27 14:43:49 -04:00
return func ( templ tpl . TemplateHandler ) error {
2017-01-10 04:55:03 -05:00
for i := 0 ; i < len ( additionalTemplates ) ; i += 2 {
err := templ . AddTemplate ( additionalTemplates [ i ] , additionalTemplates [ i + 1 ] )
if err != nil {
return err
}
}
return nil
}
}
2017-05-23 05:10:15 -04:00
func buildSingleSite ( t testing . TB , depsCfg deps . DepsCfg , buildCfg BuildCfg ) * Site {
2017-02-04 22:20:06 -05:00
return buildSingleSiteExpected ( t , false , depsCfg , buildCfg )
}
2017-05-23 05:10:15 -04:00
func buildSingleSiteExpected ( t testing . TB , expectBuildError bool , depsCfg deps . DepsCfg , buildCfg BuildCfg ) * Site {
2017-02-04 22:20:06 -05:00
h , err := NewHugoSites ( depsCfg )
2017-01-10 04:55:03 -05:00
require . NoError ( t , err )
require . Len ( t , h . Sites , 1 )
2017-02-04 22:20:06 -05:00
if expectBuildError {
require . Error ( t , h . Build ( buildCfg ) )
return nil
}
2017-01-10 04:55:03 -05:00
require . NoError ( t , h . Build ( buildCfg ) )
return h . Sites [ 0 ]
}
:sparkles: Implement Page bundling and image handling
This commit is not the smallest in Hugo's history.
Some hightlights include:
* Page bundles (for complete articles, keeping images and content together etc.).
* Bundled images can be processed in as many versions/sizes as you need with the three methods `Resize`, `Fill` and `Fit`.
* Processed images are cached inside `resources/_gen/images` (default) in your project.
* Symbolic links (both files and dirs) are now allowed anywhere inside /content
* A new table based build summary
* The "Total in nn ms" now reports the total including the handling of the files inside /static. So if it now reports more than you're used to, it is just **more real** and probably faster than before (see below).
A site building benchmark run compared to `v0.31.1` shows that this should be slightly faster and use less memory:
```bash
▶ ./benchSite.sh "TOML,num_langs=.*,num_root_sections=5,num_pages=(500|1000),tags_per_page=5,shortcodes,render"
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 101785785 78067944 -23.30%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 185481057 149159919 -19.58%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 103149918 85679409 -16.94%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 203515478 169208775 -16.86%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 532464 391539 -26.47%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1056549 772702 -26.87%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 555974 406630 -26.86%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1086545 789922 -27.30%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 53243246 43598155 -18.12%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 105811617 86087116 -18.64%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 54558852 44545097 -18.35%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 106903858 86978413 -18.64%
```
Fixes #3651
Closes #3158
Fixes #1014
Closes #2021
Fixes #1240
Updates #3757
2017-07-24 03:00:23 -04:00
func writeSourcesToSource ( t * testing . T , base string , fs * hugofs . Fs , sources ... [ 2 ] string ) {
2017-01-10 04:55:03 -05:00
for _ , src := range sources {
:sparkles: Implement Page bundling and image handling
This commit is not the smallest in Hugo's history.
Some hightlights include:
* Page bundles (for complete articles, keeping images and content together etc.).
* Bundled images can be processed in as many versions/sizes as you need with the three methods `Resize`, `Fill` and `Fit`.
* Processed images are cached inside `resources/_gen/images` (default) in your project.
* Symbolic links (both files and dirs) are now allowed anywhere inside /content
* A new table based build summary
* The "Total in nn ms" now reports the total including the handling of the files inside /static. So if it now reports more than you're used to, it is just **more real** and probably faster than before (see below).
A site building benchmark run compared to `v0.31.1` shows that this should be slightly faster and use less memory:
```bash
▶ ./benchSite.sh "TOML,num_langs=.*,num_root_sections=5,num_pages=(500|1000),tags_per_page=5,shortcodes,render"
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 101785785 78067944 -23.30%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 185481057 149159919 -19.58%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 103149918 85679409 -16.94%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 203515478 169208775 -16.86%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 532464 391539 -26.47%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1056549 772702 -26.87%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 555974 406630 -26.86%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1086545 789922 -27.30%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 53243246 43598155 -18.12%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 105811617 86087116 -18.64%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 54558852 44545097 -18.35%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 106903858 86978413 -18.64%
```
Fixes #3651
Closes #3158
Fixes #1014
Closes #2021
Fixes #1240
Updates #3757
2017-07-24 03:00:23 -04:00
writeSource ( t , fs , filepath . Join ( base , src [ 0 ] ) , src [ 1 ] )
}
}
func dumpPages ( pages ... * Page ) {
for i , p := range pages {
fmt . Printf ( "%d: Kind: %s Title: %-10s RelPermalink: %-10s Path: %-10s sections: %s Len Sections(): %d\n" ,
i + 1 ,
2018-01-15 14:40:39 -05:00
p . Kind , p . title , p . RelPermalink ( ) , p . Path ( ) , p . sections , len ( p . Sections ( ) ) )
2017-01-10 04:55:03 -05:00
}
}
2017-06-13 15:22:47 -04:00
func isCI ( ) bool {
return os . Getenv ( "CI" ) != ""
}