Skip to content

Commit f131d38

Browse files
committed
File mount
1 parent 8ca6306 commit f131d38

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+802
-558
lines changed

‎commands/hugobuilder.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/bep/simplecobra"
3131
"github.com/fsnotify/fsnotify"
3232
"github.com/gohugoio/hugo/common/herrors"
33+
"github.com/gohugoio/hugo/common/hstrings"
3334
"github.com/gohugoio/hugo/common/htime"
3435
"github.com/gohugoio/hugo/common/hugo"
3536
"github.com/gohugoio/hugo/common/loggers"
@@ -142,7 +143,7 @@ func (c *hugoBuilder) getDirList() ([]string, error) {
142143
return nil, err
143144
}
144145

145-
return helpers.UniqueStringsSorted(h.PathSpec.BaseFs.WatchFilenames()), nil
146+
return hstrings.UniqueStringsSorted(h.PathSpec.BaseFs.WatchFilenames()), nil
146147
}
147148

148149
func (c *hugoBuilder) initCPUProfile() (func(), error) {

‎common/hstrings/strings.go‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"fmt"
1818
"regexp"
1919
"slices"
20+
"sort"
2021
"strings"
2122
"sync"
2223

@@ -127,3 +128,62 @@ func ToString(v any) (string, bool) {
127128
}
128129
return "", false
129130
}
131+
132+
// UniqueStrings returns a new slice with any duplicates removed.
133+
func UniqueStrings(s []string) []string {
134+
unique := make([]string, 0, len(s))
135+
for i, val := range s {
136+
var seen bool
137+
for j := range i {
138+
if s[j] == val {
139+
seen = true
140+
break
141+
}
142+
}
143+
if !seen {
144+
unique = append(unique, val)
145+
}
146+
}
147+
return unique
148+
}
149+
150+
// UniqueStringsReuse returns a slice with any duplicates removed.
151+
// It will modify the input slice.
152+
func UniqueStringsReuse(s []string) []string {
153+
result := s[:0]
154+
for i, val := range s {
155+
var seen bool
156+
157+
for j := range i {
158+
if s[j] == val {
159+
seen = true
160+
break
161+
}
162+
}
163+
164+
if !seen {
165+
result = append(result, val)
166+
}
167+
}
168+
return result
169+
}
170+
171+
// UniqueStringsSorted returns a sorted slice with any duplicates removed.
172+
// It will modify the input slice.
173+
func UniqueStringsSorted(s []string) []string {
174+
if len(s) == 0 {
175+
return nil
176+
}
177+
ss := sort.StringSlice(s)
178+
ss.Sort()
179+
i := 0
180+
for j := 1; j < len(s); j++ {
181+
if !ss.Less(i, j) {
182+
continue
183+
}
184+
i++
185+
s[i] = s[j]
186+
}
187+
188+
return s[:i+1]
189+
}

‎common/hstrings/strings_test.go‎

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 The Hugo Authors. All rights reserved.
1+
// Copyright 2025 The Hugo Authors. All rights reserved.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
1414
package hstrings
1515

1616
import (
17+
"reflect"
1718
"regexp"
1819
"testing"
1920

@@ -43,6 +44,84 @@ func TestGetOrCompileRegexp(t *testing.T) {
4344
c.Assert(re.MatchString("123"), qt.Equals, true)
4445
}
4546

47+
func TestUniqueStrings(t *testing.T) {
48+
in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
49+
output := UniqueStrings(in)
50+
expected := []string{"a", "b", "c", "", "d"}
51+
if !reflect.DeepEqual(output, expected) {
52+
t.Errorf("Expected %#v, got %#v\n", expected, output)
53+
}
54+
}
55+
56+
func TestUniqueStringsReuse(t *testing.T) {
57+
in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
58+
output := UniqueStringsReuse(in)
59+
expected := []string{"a", "b", "c", "", "d"}
60+
if !reflect.DeepEqual(output, expected) {
61+
t.Errorf("Expected %#v, got %#v\n", expected, output)
62+
}
63+
}
64+
65+
func TestUniqueStringsSorted(t *testing.T) {
66+
c := qt.New(t)
67+
in := []string{"a", "a", "b", "c", "b", "", "a", "", "d"}
68+
output := UniqueStringsSorted(in)
69+
expected := []string{"", "a", "b", "c", "d"}
70+
c.Assert(output, qt.DeepEquals, expected)
71+
c.Assert(UniqueStringsSorted(nil), qt.IsNil)
72+
}
73+
74+
func BenchmarkUniqueStrings(b *testing.B) {
75+
input := []string{"a", "b", "d", "e", "d", "h", "a", "i"}
76+
77+
b.Run("Safe", func(b *testing.B) {
78+
for i := 0; i < b.N; i++ {
79+
result := UniqueStrings(input)
80+
if len(result) != 6 {
81+
b.Fatalf("invalid count: %d", len(result))
82+
}
83+
}
84+
})
85+
86+
b.Run("Reuse slice", func(b *testing.B) {
87+
b.StopTimer()
88+
inputs := make([][]string, b.N)
89+
for i := 0; i < b.N; i++ {
90+
inputc := make([]string, len(input))
91+
copy(inputc, input)
92+
inputs[i] = inputc
93+
}
94+
b.StartTimer()
95+
for i := 0; i < b.N; i++ {
96+
inputc := inputs[i]
97+
98+
result := UniqueStringsReuse(inputc)
99+
if len(result) != 6 {
100+
b.Fatalf("invalid count: %d", len(result))
101+
}
102+
}
103+
})
104+
105+
b.Run("Reuse slice sorted", func(b *testing.B) {
106+
b.StopTimer()
107+
inputs := make([][]string, b.N)
108+
for i := 0; i < b.N; i++ {
109+
inputc := make([]string, len(input))
110+
copy(inputc, input)
111+
inputs[i] = inputc
112+
}
113+
b.StartTimer()
114+
for i := 0; i < b.N; i++ {
115+
inputc := inputs[i]
116+
117+
result := UniqueStringsSorted(inputc)
118+
if len(result) != 6 {
119+
b.Fatalf("invalid count: %d", len(result))
120+
}
121+
}
122+
})
123+
}
124+
46125
func BenchmarkGetOrCompileRegexp(b *testing.B) {
47126
for i := 0; i < b.N; i++ {
48127
GetOrCompileRegexp(`\d+`)

‎common/maps/orderedintset.go‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ func (m *OrderedIntSet) Set(key int) {
4848
m.keys = append(m.keys, key)
4949
}
5050

51+
// SetFrom sets the values from another OrderedIntSet.
52+
func (m *OrderedIntSet) SetFrom(other *OrderedIntSet) {
53+
if m == nil || other == nil {
54+
return
55+
}
56+
for _, key := range other.keys {
57+
m.Set(key)
58+
}
59+
}
60+
5161
func (m *OrderedIntSet) Has(key int) bool {
5262
if m == nil {
5363
return false

‎config/allconfig/allconfig.go‎

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828

2929
"github.com/gohugoio/hugo/cache/filecache"
3030
"github.com/gohugoio/hugo/cache/httpcache"
31+
"github.com/gohugoio/hugo/common/hstrings"
3132
"github.com/gohugoio/hugo/common/hugo"
3233
"github.com/gohugoio/hugo/common/loggers"
3334
"github.com/gohugoio/hugo/common/maps"
@@ -142,12 +143,15 @@ type Config struct {
142143
// The outputformats configuration sections maps a format name (a string) to a configuration object for that format.
143144
OutputFormats *config.ConfigNamespace[map[string]output.OutputFormatConfig, output.Formats] `mapstructure:"-"`
144145

145-
// The roles configuration section contains the top level roles configuration options.
146-
Roles *config.ConfigNamespace[map[string]roles.RoleConfig, roles.RolesInternal] `mapstructure:"-"`
146+
// The languages configuration sections maps a language code (a string) to a configuration object for that language.
147+
Languages *config.ConfigNamespace[map[string]langs.LanguageConfig, langs.LanguagesInternal] `mapstructure:"-"`
147148

148149
// The versions configuration section contains the top level versions configuration options.
149150
Versions *config.ConfigNamespace[map[string]versions.VersionConfig, versions.VersionsInternal] `mapstructure:"-"`
150151

152+
// The roles configuration section contains the top level roles configuration options.
153+
Roles *config.ConfigNamespace[map[string]roles.RoleConfig, roles.RolesInternal] `mapstructure:"-"`
154+
151155
// The outputs configuration section maps a Page Kind (a string) to a slice of output formats.
152156
// This can be overridden in the front matter.
153157
Outputs map[string][]string `mapstructure:"-"`
@@ -209,9 +213,6 @@ type Config struct {
209213
// <docsmeta>{"refs": ["config:languages:params"] }</docsmeta>
210214
Params maps.Params `mapstructure:"-"`
211215

212-
// The languages configuration sections maps a language code (a string) to a configuration object for that language.
213-
Languages map[string]langs.LanguageConfig `mapstructure:"-"`
214-
215216
// UglyURLs configuration. Either a boolean or a sections map.
216217
UglyURLs any `mapstructure:"-"`
217218
}
@@ -328,18 +329,6 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
328329
for _, lang := range c.DisableLanguages {
329330
disabledLangs[lang] = true
330331
}
331-
for lang, language := range c.Languages {
332-
if !language.Disabled && disabledLangs[lang] {
333-
language.Disabled = true
334-
c.Languages[lang] = language
335-
}
336-
if language.Disabled {
337-
disabledLangs[lang] = true
338-
if lang == c.DefaultContentLanguage {
339-
return fmt.Errorf("cannot disable default content language %q", lang)
340-
}
341-
}
342-
}
343332

344333
for i, s := range c.IgnoreLogs {
345334
c.IgnoreLogs[i] = strings.ToLower(s)
@@ -773,7 +762,7 @@ func (c RootConfig) staticDirs() []string {
773762
dirs = append(dirs, c.StaticDir8...)
774763
dirs = append(dirs, c.StaticDir9...)
775764
dirs = append(dirs, c.StaticDir10...)
776-
return helpers.UniqueStringsReuse(dirs)
765+
return hstrings.UniqueStringsReuse(dirs)
777766
}
778767

779768
type Configs struct {
@@ -821,51 +810,10 @@ func (c *Configs) IsZero() bool {
821810
func (c *Configs) Init() error {
822811
var languages langs.Languages
823812

824-
var langKeys []string
825-
var hasEn bool
826-
827-
const en = "en"
828-
829-
for k := range c.LanguageConfigMap {
830-
langKeys = append(langKeys, k)
831-
if k == en {
832-
hasEn = true
833-
}
834-
}
835-
836-
// Sort the LanguageConfigSlice by language weight (if set) or lang.
837-
sort.Slice(langKeys, func(i, j int) bool {
838-
ki := langKeys[i]
839-
kj := langKeys[j]
840-
lki := c.LanguageConfigMap[ki]
841-
lkj := c.LanguageConfigMap[kj]
842-
li := lki.Languages[ki]
843-
lj := lkj.Languages[kj]
844-
if li.Weight != lj.Weight {
845-
return li.Weight < lj.Weight
846-
}
847-
return ki < kj
848-
})
849-
850-
// See issue #13646.
851-
defaultConfigLanguageFallback := en
852-
if !hasEn {
853-
// Pick the first one.
854-
defaultConfigLanguageFallback = langKeys[0]
855-
}
856-
857-
if c.Base.DefaultContentLanguage == "" {
858-
c.Base.DefaultContentLanguage = defaultConfigLanguageFallback
859-
}
860-
861-
for _, k := range langKeys {
862-
v := c.LanguageConfigMap[k]
863-
if v.DefaultContentLanguage == "" {
864-
v.DefaultContentLanguage = defaultConfigLanguageFallback
865-
}
866-
c.LanguageConfigSlice = append(c.LanguageConfigSlice, v)
867-
languageConf := v.Languages[k]
868-
language, err := langs.NewLanguage(k, c.Base.DefaultContentLanguage, v.TimeZone, languageConf)
813+
// TODO1 more cleanups, please.
814+
for _, f := range c.Base.Languages.Config.Sorted {
815+
v := c.LanguageConfigMap[f.Name]
816+
language, err := langs.NewLanguage(f.Name, c.Base.DefaultContentLanguage, v.TimeZone, f.LanguageConfig)
869817
if err != nil {
870818
return err
871819
}
@@ -968,7 +916,7 @@ func (c Configs) GetFirstLanguageConfig() config.AllProvider {
968916

969917
func (c Configs) GetByLang(lang string) config.AllProvider {
970918
for _, l := range c.configLangs {
971-
if l.Language().Lang == lang {
919+
if l.Language().(*langs.Language).Lang == lang {
972920
return l
973921
}
974922
}
@@ -1083,7 +1031,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
10831031
}
10841032
}
10851033
}
1086-
differentRootKeys = helpers.UniqueStringsSorted(differentRootKeys)
1034+
differentRootKeys = hstrings.UniqueStringsSorted(differentRootKeys)
10871035

10881036
if len(differentRootKeys) == 0 {
10891037
langConfigMap[k] = all

0 commit comments

Comments
 (0)