Skip to content

Add roles and versions as new dimensions (in addition to language) #13679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cache/dynacache/dynacache.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ func GetOrCreatePartition[K comparable, V any](c *Cache, name string, opts Optio
panic("invalid Weight, must be between 1 and 100")
}

if partitionNameRe.FindString(name) != name {
if !partitionNameRe.MatchString(name) {
panic(fmt.Sprintf("invalid partition name %q", name))
}

Expand Down
5 changes: 0 additions & 5 deletions common/hstrings/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,3 @@ func ToString(v any) (string, bool) {
}
return "", false
}

type (
Strings2 [2]string
Strings3 [3]string
)
48 changes: 46 additions & 2 deletions common/hugo/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/version"
"github.com/gohugoio/hugo/hugofs/files"

"github.com/spf13/afero"
Expand Down Expand Up @@ -80,7 +81,7 @@ type HugoInfo struct {
}

// Version returns the current version as a comparable version string.
func (i HugoInfo) Version() VersionString {
func (i HugoInfo) Version() version.VersionString {
return CurrentVersion.Version()
}

Expand Down Expand Up @@ -451,7 +452,7 @@ func deprecateLevelWithLogger(item, alternative, version string, level logg.Leve
// We want people to run at least the current and previous version without any warnings.
// We want people who don't update Hugo that often to see the warnings and errors before we remove the feature.
func deprecationLogLevelFromVersion(ver string) logg.Level {
from := MustParseVersion(ver)
from := version.MustParseVersion(ver)
to := CurrentVersion
minorDiff := to.Minor - from.Minor
switch {
Expand All @@ -465,3 +466,46 @@ func deprecationLogLevelFromVersion(ver string) logg.Level {
return logg.LevelInfo
}
}

// BuildVersionString creates a version string. This is what you see when
// running "hugo version".
func BuildVersionString() string {
// program := "Hugo Static Site Generator"
program := "hugo"

version := "v" + CurrentVersion.String()

bi := getBuildInfo()
if bi == nil {
return version
}
if bi.Revision != "" {
version += "-" + bi.Revision
}
if IsExtended {
version += "+extended"
}
if IsWithdeploy {
version += "+withdeploy"
}

osArch := bi.GoOS + "/" + bi.GoArch

date := bi.RevisionTime
if date == "" {
// Accept vendor-specified build date if .git/ is unavailable.
date = buildDate
}
if date == "" {
date = "unknown"
}

versionString := fmt.Sprintf("%s %s %s BuildDate=%s",
program, version, osArch, date)

if vendorInfo != "" {
versionString += " VendorInfo=" + vendorInfo
}

return versionString
}
3 changes: 2 additions & 1 deletion common/hugo/hugo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/bep/logg"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/common/version"
)

func TestHugoInfo(t *testing.T) {
Expand All @@ -29,7 +30,7 @@ func TestHugoInfo(t *testing.T) {
hugoInfo := NewInfo(conf, nil)

c.Assert(hugoInfo.Version(), qt.Equals, CurrentVersion.Version())
c.Assert(fmt.Sprintf("%T", VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
c.Assert(fmt.Sprintf("%T", version.VersionString("")), qt.Equals, fmt.Sprintf("%T", hugoInfo.Version()))
c.Assert(hugoInfo.WorkingDir(), qt.Equals, "/mywork")

bi := getBuildInfo()
Expand Down
6 changes: 4 additions & 2 deletions common/hugo/version_current.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// Copyright 2025 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.
Expand All @@ -13,9 +13,11 @@

package hugo

import "github.com/gohugoio/hugo/common/version"

// CurrentVersion represents the current build version.
// This should be the only one.
var CurrentVersion = Version{
var CurrentVersion = version.Version{
Major: 0,
Minor: 148,
PatchLevel: 0,
Expand Down
70 changes: 70 additions & 0 deletions common/maps/orderedintset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2025 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 maps

import (
"fmt"

"github.com/bits-and-blooms/bitset"
)

type OrderedIntSet struct {
keys []int
values bitset.BitSet
}

// NewOrderedIntSet creates a new OrderedIntSet.
// Note that this is backed by https://github.com/bits-and-blooms/bitset
func NewOrderedIntSet(vals ...int) *OrderedIntSet {
m := &OrderedIntSet{}
for _, v := range vals {
m.Set(v)
}
return m
}

// Set sets the value for the given key.
// Note that insertion order is not affected if a key is re-inserted into the set.
func (m *OrderedIntSet) Set(key int) {
if m == nil {
return
}
keyu := uint(key)
if m.values.Test(keyu) {
return
}
m.values.Set(keyu)
m.keys = append(m.keys, key)
}

func (m *OrderedIntSet) Has(key int) bool {
if m == nil {
return false
}
return m.values.Test(uint(key))
}

func (m *OrderedIntSet) Len() int {
if m == nil {
return 0
}
return len(m.keys)
}

func (m *OrderedIntSet) String() string {
if m == nil {
return "[]"
}
return fmt.Sprintf("%v", m.keys)
}
57 changes: 57 additions & 0 deletions common/maps/orderedintset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2025 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 maps

import (
"testing"

qt "github.com/frankban/quicktest"
)

func TestOrderedIntSet(t *testing.T) {
c := qt.New(t)

m := NewOrderedIntSet(1, 2, 3)

c.Assert(m.Len(), qt.Equals, 3)
c.Assert(m.Has(1), qt.Equals, true)
c.Assert(m.Has(4), qt.Equals, false)
c.Assert(m.String(), qt.Equals, "[1 2 3]")
m.Set(4)
c.Assert(m.Len(), qt.Equals, 4)
c.Assert(m.Has(4), qt.Equals, true)
c.Assert(m.String(), qt.Equals, "[1 2 3 4]")

var nilset *OrderedIntSet
c.Assert(nilset.Len(), qt.Equals, 0)
c.Assert(nilset.Has(1), qt.Equals, false)
c.Assert(nilset.String(), qt.Equals, "[]")
}

func BenchmarkOrderedIntSetHasInSmallSet(b *testing.B) {
m := NewOrderedIntSet()
for i := range 8 {
m.Set(i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Has(i % 32)
}
}

func BenchmarkOrderedIntSetNew(b *testing.B) {
for i := 0; i < b.N; i++ {
NewOrderedIntSet(1, 2, 3, 4, 5, 6, 7, 8)
}
}
10 changes: 10 additions & 0 deletions common/paths/pathparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package paths

import (
"fmt"
"path"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -780,3 +781,12 @@ func HasExt(p string) bool {
}
return false
}

// ValidateIdentifier returns true if the given string is a valid identifier according
// to Hugo's basic path normalization rules.
func ValidateIdentifier(s string) error {
if s == NormalizePathStringBasic(s) {
return nil
}
return fmt.Errorf("must be all lower case and no spaces")
}
65 changes: 65 additions & 0 deletions common/predicate/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package predicate

import (
"iter"
"strings"

hglob "github.com/gohugoio/hugo/hugofs/glob"
)

type Filter[T any] struct {
exclude P[T]
include P[T]
}

func (f Filter[T]) ShouldExcludeCoarse(v T) bool {
return f.exclude != nil && f.exclude(v)
}

// TODO1 simplify this.
func (f Filter[T]) ShouldExcludeFine(v T) bool {
if f.exclude != nil && f.exclude(v) {
return true
}
return f.include != nil && !f.include(v)
}

func NewFilter[T any](include, exclude P[T]) Filter[T] {
return Filter[T]{exclude: exclude, include: include}
}

func NewFilterFromGlobs(patterns []string) (Filter[string], error) {
var filter Filter[string]
for _, p := range patterns {
p = strings.TrimSpace(p)
if p == "" {
continue
}
if strings.HasPrefix(p, "! ") {
p = p[2:]
g, err := hglob.GetGlob(p)
if err != nil {
return filter, err
}
fn := func(s string) bool {
return g.Match(s)
}
filter.exclude = filter.exclude.Or(fn)
} else {
g, err := hglob.GetGlob(p)
if err != nil {
return filter, err
}
fn := func(s string) bool {
return g.Match(s)
}
filter.include = filter.include.Or(fn)
}
}

return filter, nil
}

type IndexMatcher interface {
IndexMatch(filter Filter[string]) (iter.Seq[int], error)
}
7 changes: 7 additions & 0 deletions common/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,10 @@ func NewBool(b bool) *bool {
type PrintableValueProvider interface {
PrintableValue() any
}

type (
Strings2 [2]string
Strings3 [3]string
Ints2 [2]int
Ints3 [3]int
)
Loading
Loading