Skip to content

Commit

Permalink
Make it possible to add a language in server mode
Browse files Browse the repository at this point in the history
  • Loading branch information
bep authored and tychoish committed Aug 13, 2017
1 parent 3aace98 commit cd14f94
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 69 deletions.
6 changes: 2 additions & 4 deletions commands/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ func benchmark(cmd *cobra.Command, args []string) error {
return err
}
for i := 0; i < benchmarkTimes; i++ {
_ = buildSites()
Hugo.Reset()
_ = resetAndbuildSites(false)
}
pprof.WriteHeapProfile(f)
f.Close()
Expand All @@ -76,8 +75,7 @@ func benchmark(cmd *cobra.Command, args []string) error {
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
for i := 0; i < benchmarkTimes; i++ {
_ = buildSites()
Hugo.Reset()
_ = resetAndbuildSites(false)
}
}

Expand Down
43 changes: 30 additions & 13 deletions commands/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,14 +419,6 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
helpers.HugoReleaseVersion(), minVersion)
}

h, err := hugolib.NewHugoSitesFromConfiguration()

if err != nil {
return err
}
//TODO(bep) ml refactor ...
Hugo = h

return nil

}
Expand All @@ -444,8 +436,7 @@ func watchConfig() {
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
// Force a full rebuild
Hugo.Reset()
utils.CheckErr(buildSites(true))
utils.CheckErr(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()
Expand Down Expand Up @@ -638,13 +629,39 @@ func getDirList() []string {
return a
}

func buildSites(watching ...bool) (err error) {
func reCreateAndbuildSites(watching bool) (err error) {
fmt.Println("Started building sites ...")
return Hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true, Watching: watching, PrintStats: true})
}

func resetAndbuildSites(watching bool) (err error) {
fmt.Println("Started building sites ...")
return Hugo.Build(hugolib.BuildCfg{ResetState: true, Watching: watching, PrintStats: true})
}

func initSites() error {
if Hugo != nil {
return nil
}

h, err := hugolib.NewHugoSitesFromConfiguration()

if err != nil {
return err
}
Hugo = h

return nil
}

func buildSites(watching bool) (err error) {
initSites()
fmt.Println("Started building sites ...")
w := len(watching) > 0 && watching[0]
return Hugo.Build(hugolib.BuildCfg{Watching: w, PrintStats: true})
return Hugo.Build(hugolib.BuildCfg{Watching: watching, PrintStats: true})
}

func rebuildSites(events []fsnotify.Event) error {
initSites()
return Hugo.Rebuild(hugolib.BuildCfg{PrintStats: true}, events...)
}

Expand Down
91 changes: 71 additions & 20 deletions hugolib/hugo_sites.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,25 @@ type HugoSites struct {
// NewHugoSites creates a new collection of sites given the input sites, building
// a language configuration based on those.
func NewHugoSites(sites ...*Site) (*HugoSites, error) {
languages := make(Languages, len(sites))
for i, s := range sites {
if s.Language == nil {
return nil, errors.New("Missing language for site")
}
languages[i] = s.Language
}
defaultLang := viper.GetString("DefaultContentLanguage")
if defaultLang == "" {
defaultLang = "en"
langConfig, err := newMultiLingualFromSites(sites...)

if err != nil {
return nil, err
}
langConfig := &Multilingual{Languages: languages, DefaultLang: NewLanguage(defaultLang)}

return &HugoSites{Multilingual: langConfig, Sites: sites}, nil
}

// NewHugoSitesFromConfiguration creates HugoSites from the global Viper config.
func NewHugoSitesFromConfiguration() (*HugoSites, error) {
sites, err := createSitesFromConfig()
if err != nil {
return nil, err
}
return NewHugoSites(sites...)
}

func createSitesFromConfig() ([]*Site, error) {
var sites []*Site
multilingual := viper.GetStringMap("Languages")
if len(multilingual) == 0 {
Expand All @@ -80,19 +81,43 @@ func NewHugoSitesFromConfiguration() (*HugoSites, error) {

}

return NewHugoSites(sites...)

return sites, nil
}

// Reset resets the sites, making it ready for a full rebuild.
// TODO(bep) multilingo
func (h HugoSites) Reset() {
func (h *HugoSites) reset() {
for i, s := range h.Sites {
h.Sites[i] = s.Reset()
}
}

func (h HugoSites) toSiteInfos() []*SiteInfo {
func (h *HugoSites) reCreateFromConfig() error {
oldSite := h.Sites[0]
sites, err := createSitesFromConfig()

if err != nil {
return err
}

langConfig, err := newMultiLingualFromSites(sites...)

if err != nil {
return err
}

h.Sites = sites
h.Multilingual = langConfig

for _, s := range h.Sites {
// TODO(bep) ml Tmpl
s.Tmpl = oldSite.Tmpl
}

return nil
}

func (h *HugoSites) toSiteInfos() []*SiteInfo {
infos := make([]*SiteInfo, len(h.Sites))
for i, s := range h.Sites {
infos[i] = &s.Info
Expand All @@ -106,6 +131,11 @@ type BuildCfg struct {
Watching bool
// Print build stats at the end of a build
PrintStats bool
// Reset site state before build. Use to force full rebuilds.
ResetState bool
// Re-creates the sites from configuration before a build.
// This is needed if new languages are added.
CreateSitesFromConfig bool
// Skip rendering. Useful for testing.
SkipRender bool
// Use this to add templates to use for rendering.
Expand All @@ -114,13 +144,19 @@ type BuildCfg struct {
}

// Build builds all sites.
func (h HugoSites) Build(config BuildCfg) error {
func (h *HugoSites) Build(config BuildCfg) error {

if h.Sites == nil || len(h.Sites) == 0 {
return errors.New("No site(s) to build")
t0 := time.Now()

if config.ResetState {
h.reset()
}

t0 := time.Now()
if config.CreateSitesFromConfig {
if err := h.reCreateFromConfig(); err != nil {
return err
}
}

// We should probably refactor the Site and pull up most of the logic from there to here,
// but that seems like a daunting task.
Expand All @@ -143,6 +179,7 @@ func (h HugoSites) Build(config BuildCfg) error {
if len(h.Sites) > 1 {
// Initialize the rest
for _, site := range h.Sites[1:] {
// TODO(bep) ml Tmpl
site.Tmpl = firstSite.Tmpl
site.initializeSiteInfo()
}
Expand Down Expand Up @@ -184,9 +221,23 @@ func (h HugoSites) Build(config BuildCfg) error {
}

// Rebuild rebuilds all sites.
func (h HugoSites) Rebuild(config BuildCfg, events ...fsnotify.Event) error {
func (h *HugoSites) Rebuild(config BuildCfg, events ...fsnotify.Event) error {
t0 := time.Now()

if config.CreateSitesFromConfig {
return errors.New("Rebuild does not support 'CreateSitesFromConfig'. Use Build.")
}

if config.ResetState {
return errors.New("Rebuild does not support 'ResetState'. Use Build.")
}

for _, s := range h.Sites {
// TODO(bep) ml
s.Multilingual = h.Multilingual
s.RunMode.Watching = config.Watching
}

firstSite := h.Sites[0]

for _, s := range h.Sites {
Expand Down
120 changes: 88 additions & 32 deletions hugolib/hugo_sites_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func testCommonResetState() {

func TestMultiSitesBuild(t *testing.T) {
testCommonResetState()
sites := createMultiTestSites(t)
sites := createMultiTestSites(t, multiSiteTomlConfig)

err := sites.Build(BuildCfg{})

Expand Down Expand Up @@ -141,7 +141,7 @@ func TestMultiSitesBuild(t *testing.T) {

func TestMultiSitesRebuild(t *testing.T) {
testCommonResetState()
sites := createMultiTestSites(t)
sites := createMultiTestSites(t, multiSiteTomlConfig)
cfg := BuildCfg{}

err := sites.Build(cfg)
Expand Down Expand Up @@ -299,10 +299,95 @@ func TestMultiSitesRebuild(t *testing.T) {

this.assertFunc(t)
}
}

func TestAddNewLanguage(t *testing.T) {
testCommonResetState()

sites := createMultiTestSites(t, multiSiteTomlConfig)
cfg := BuildCfg{}

err := sites.Build(cfg)

if err != nil {
t.Fatalf("Failed to build sites: %s", err)
}

newConfig := multiSiteTomlConfig + `
[Languages.no]
weight = 15
title = "Norsk"
`

writeNewContentFile(t, "Norwegian Contentfile", "2016-01-01", "content/sect/doc1.no.md", 10)
// replace the config
writeSource(t, "multilangconfig.toml", newConfig)

// Watching does not work with in-memory fs, so we trigger a reload manually
require.NoError(t, viper.ReadInConfig())

err = sites.Build(BuildCfg{CreateSitesFromConfig: true})

if err != nil {
t.Fatalf("Failed to rebuild sites: %s", err)
}

require.Len(t, sites.Sites, 3, fmt.Sprintf("Len %d", len(sites.Sites)))

// The Norwegian site should be put in the middle (language weight=15)
enSite := sites.Sites[0]
noSite := sites.Sites[1]
frSite := sites.Sites[2]
require.True(t, enSite.Language.Lang == "en", enSite.Language.Lang)
require.True(t, noSite.Language.Lang == "no", noSite.Language.Lang)
require.True(t, frSite.Language.Lang == "fr", frSite.Language.Lang)

require.Len(t, enSite.Pages, 3)
require.Len(t, frSite.Pages, 3)

// Veriy Norwegian site
require.Len(t, noSite.Pages, 1)
noPage := noSite.Pages[0]
require.Equal(t, "Norwegian Contentfile", noPage.Title)
require.Equal(t, "no", noPage.Lang())
require.Len(t, noPage.Translations(), 2)
require.Len(t, noPage.AllTranslations(), 3)
require.Equal(t, "en", noPage.Translations()[0].Lang())
//noFile := readDestination(t, "/public/no/doc1/index.html")
//require.True(t, strings.Contains("foo", noFile), noFile)

}

func createMultiTestSites(t *testing.T) *HugoSites {
var multiSiteTomlConfig = `
DefaultExtension = "html"
baseurl = "http://example.com/blog"
DisableSitemap = false
DisableRSS = false
RSSUri = "index.xml"
paginate = 2
DefaultContentLanguage = "fr"
[permalinks]
other = "/somewhere/else/:filename"
[Taxonomies]
tag = "tags"
[Languages]
[Languages.en]
weight = 10
title = "English"
[Languages.fr]
weight = 20
title = "Français"
[Languages.fr.Taxonomies]
plaque = "plaques"
`

func createMultiTestSites(t *testing.T, tomlConfig string) *HugoSites {

// Add some layouts
if err := afero.WriteFile(hugofs.Source(),
Expand Down Expand Up @@ -445,35 +530,6 @@ draft: true
`)},
}

tomlConfig := `
DefaultExtension = "html"
baseurl = "http://example.com/blog"
DisableSitemap = false
DisableRSS = false
RSSUri = "index.xml"
paginate = 2
DefaultContentLanguage = "fr"
[permalinks]
other = "/somewhere/else/:filename"
[Taxonomies]
tag = "tags"
[Languages]
[Languages.en]
weight = 1
title = "English"
[Languages.fr]
weight = 2
title = "Français"
[Languages.fr.Taxonomies]
plaque = "plaques"
`

writeSource(t, "multilangconfig.toml", tomlConfig)
if err := LoadGlobalConfig("", "multilangconfig.toml"); err != nil {
t.Fatalf("Failed to load config: %s", err)
Expand Down
Loading

0 comments on commit cd14f94

Please sign in to comment.