From 70a0c79c9a40ba15fa0637e1ed3a5b98a9a7d208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Wed, 5 Jan 2022 22:13:34 +0100 Subject: [PATCH] File --- common/paths/pathparser.go | 57 ++++++++++++----- common/paths/pathparser_test.go | 2 + source/fileInfo.go | 108 ++++---------------------------- 3 files changed, 56 insertions(+), 111 deletions(-) diff --git a/common/paths/pathparser.go b/common/paths/pathparser.go index ee870434915..0bd83cae09a 100644 --- a/common/paths/pathparser.go +++ b/common/paths/pathparser.go @@ -41,8 +41,10 @@ func Parse(s string, parseOpts ...func(b *pathBase)) Path { func parse(s string, parseOpts ...func(b *pathBase)) (*pathBase, error) { p := &pathBase{ - component: files.ComponentFolderContent, - posBase: -1, + component: files.ComponentFolderContent, + posContainerLow: -1, + posContainerHigh: -1, + posSectionHigh: -1, } for _, opt := range parseOpts { @@ -74,7 +76,7 @@ func parse(s string, parseOpts ...func(b *pathBase)) (*pathBase, error) { switch c { case '.': - if p.posBase == -1 { + if p.posContainerHigh == -1 { var high int if len(p.identifiers) > 0 { high = p.identifiers[len(p.identifiers)-1].Low - 1 @@ -84,8 +86,13 @@ func parse(s string, parseOpts ...func(b *pathBase)) (*pathBase, error) { p.identifiers = append(p.identifiers, types.LowHigh{Low: i + 1, High: high}) } case '/': - if p.posBase == -1 { - p.posBase = i + 1 + if p.posContainerHigh == -1 { + p.posContainerHigh = i + 1 + } else if p.posContainerLow == -1 { + p.posContainerLow = i + 1 + } + if i > 0 { + p.posSectionHigh = i } } } @@ -94,7 +101,7 @@ func parse(s string, parseOpts ...func(b *pathBase)) (*pathBase, error) { if p.isContent { id := p.identifiers[len(p.identifiers)-1] - b := p.s[p.posBase : id.Low-1] + b := p.s[p.posContainerHigh : id.Low-1] switch b { case "index": p.bundleType = BundleTypeLeaf @@ -111,6 +118,8 @@ func parse(s string, parseOpts ...func(b *pathBase)) (*pathBase, error) { type Path interface { identity.Identity Component() string + Container() string + Section() string Name() string NameNoExt() string NameNoIdentifier() string @@ -148,7 +157,9 @@ const ( type pathBase struct { s string - posBase int + posContainerLow int + posContainerHigh int + posSectionHigh int component string isContent bool @@ -184,14 +195,28 @@ func (p *pathBase) Component() string { return p.component } +func (p *pathBase) Container() string { + if p.posContainerLow == -1 { + return "" + } + return p.s[p.posContainerLow : p.posContainerHigh-1] +} + +func (p *pathBase) Section() string { + if p.posSectionHigh == -1 { + return "" + } + return p.s[1:p.posSectionHigh] +} + func (p *pathBase) IsContent() bool { return p.isContent } // Name returns the last element of path. func (p *pathBase) Name() string { - if p.posBase > 0 { - return p.s[p.posBase:] + if p.posContainerHigh > 0 { + return p.s[p.posContainerHigh:] } return p.s } @@ -199,23 +224,23 @@ func (p *pathBase) Name() string { // Name returns the last element of path withhout any extension. func (p *pathBase) NameNoExt() string { if i := p.identifierIndex(0); i != -1 { - return p.s[p.posBase : p.identifiers[i].Low-1] + return p.s[p.posContainerHigh : p.identifiers[i].Low-1] } - return p.s[p.posBase:] + return p.s[p.posContainerHigh:] } func (p *pathBase) NameNoIdentifier() string { if len(p.identifiers) > 0 { - return p.s[p.posBase : p.identifiers[len(p.identifiers)-1].Low-1] + return p.s[p.posContainerHigh : p.identifiers[len(p.identifiers)-1].Low-1] } if i := p.identifierIndex(0); i != -1 { } - return p.s[p.posBase:] + return p.s[p.posContainerHigh:] } func (p *pathBase) Dir() string { - if p.posBase > 0 { - return p.s[:p.posBase-1] + if p.posContainerHigh > 0 { + return p.s[:p.posContainerHigh-1] } return "/" } @@ -235,7 +260,7 @@ func (p *pathBase) Base() string { high := id.Low - 1 if p.isContent { if p.IsBundle() { - high = p.posBase - 1 + high = p.posContainerHigh - 1 } } diff --git a/common/paths/pathparser_test.go b/common/paths/pathparser_test.go index a9af3e00d8d..d184dec04de 100644 --- a/common/paths/pathparser_test.go +++ b/common/paths/pathparser_test.go @@ -99,6 +99,8 @@ func TestParse(t *testing.T) { c.Assert(p.Base(), qt.Equals, "/a/b") c.Assert(p.Dir(), qt.Equals, "/a/b") c.Assert(p.Ext(), qt.Equals, "md") + c.Assert(p.Container(), qt.Equals, "b") + c.Assert(p.Section(), qt.Equals, "a") c.Assert(p.NameNoExt(), qt.Equals, "index.no") c.Assert(p.NameNoIdentifier(), qt.Equals, "index") c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no"}) diff --git a/source/fileInfo.go b/source/fileInfo.go index 1a824ae9061..9ce29a19875 100644 --- a/source/fileInfo.go +++ b/source/fileInfo.go @@ -15,15 +15,10 @@ package source import ( "path/filepath" - "strings" "sync" "github.com/gohugoio/hugo/common/paths" - "github.com/gohugoio/hugo/hugofs/files" - - "github.com/pkg/errors" - "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/hugofs" @@ -107,21 +102,6 @@ type FileInfo struct { fim hugofs.FileMetaInfo - // Derived from filename - ext string // Extension without any "." - lang string - - name string - - dir string - relDir string - relPath string - baseName string - translationBaseName string - contentBaseName string - section string - classifier files.ContentClass - uniqueID string lazyInit sync.Once @@ -140,7 +120,7 @@ func (fi *FileInfo) Filename() string { return fi.fim.Meta().Filename } // Path gets the relative path including file name and extension. The directory // is relative to the content root. -func (fi *FileInfo) Path() string { return fi.relPath } +func (fi *FileInfo) Path() string { return filepath.Join(fi.p().Dir()[1:], fi.p().Name()) } // Dir gets the name of the directory that contains this file. The directory is // relative to the content root. @@ -172,19 +152,20 @@ func (fi *FileInfo) BaseFileName() string { // TranslationBaseName returns a file's translation base name without the // language segment (ie. "page"). -func (fi *FileInfo) TranslationBaseName() string { return fi.translationBaseName } +func (fi *FileInfo) TranslationBaseName() string { return fi.p().NameNoIdentifier() } // ContentBaseName is a either TranslationBaseName or name of containing folder -// if file is a leaf bundle. +// if file is a bundle. func (fi *FileInfo) ContentBaseName() string { - fi.init() - return fi.contentBaseName + if fi.p().IsBundle() { + return fi.p().Container() + } + return fi.p().NameNoIdentifier() } // Section returns a file's section. func (fi *FileInfo) Section() string { - fi.init() - return fi.section + return fi.p().Section() } // UniqueID returns a file's unique, MD5 hash identifier. @@ -213,31 +194,15 @@ func (fi *FileInfo) IsZero() bool { // in some cases that is slightly expensive to construct. func (fi *FileInfo) init() { fi.lazyInit.Do(func() { - relDir := strings.Trim(fi.relDir, helpers.FilePathSeparator) - parts := strings.Split(relDir, helpers.FilePathSeparator) - var section string - if (fi.classifier != files.ContentClassLeaf && len(parts) == 1) || len(parts) > 1 { - section = parts[0] - } - fi.section = section - - if fi.classifier.IsBundle() && len(parts) > 0 { - fi.contentBaseName = parts[len(parts)-1] - } else { - fi.contentBaseName = fi.translationBaseName - } - - fi.uniqueID = helpers.MD5String(filepath.ToSlash(fi.relPath)) + fi.uniqueID = helpers.MD5String(filepath.ToSlash(fi.Path())) }) } // NewTestFile creates a partially filled File used in unit tests. // TODO(bep) improve this package func NewTestFile(filename string) *FileInfo { - base := filepath.Base(filepath.Dir(filename)) return &FileInfo{ - filename: filename, - translationBaseName: base, + filename: filename, } } @@ -253,57 +218,10 @@ func (sp *SourceSpec) NewFileInfoFrom(path, filename string) (*FileInfo, error) func (sp *SourceSpec) NewFileInfo(fi hugofs.FileMetaInfo) (*FileInfo, error) { m := fi.Meta() - filename := m.Filename - relPath := m.Path - - if relPath == "" { - return nil, errors.Errorf("no Path provided by %v (%T)", m, m.Fs) - } - - if filename == "" { - return nil, errors.Errorf("no Filename provided by %v (%T)", m, m.Fs) - } - - relDir := filepath.Dir(relPath) - if relDir == "." { - relDir = "" - } - if !strings.HasSuffix(relDir, helpers.FilePathSeparator) { - relDir = relDir + helpers.FilePathSeparator - } - - lang := m.Lang - translationBaseName := m.TranslationBaseName - - dir, name := filepath.Split(relPath) - if !strings.HasSuffix(dir, helpers.FilePathSeparator) { - dir = dir + helpers.FilePathSeparator - } - - ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(name), ".")) - baseName := paths.Filename(name) - - if translationBaseName == "" { - // This is usually provided by the filesystem. But this FileInfo is also - // created in a standalone context when doing "hugo new". This is - // an approximate implementation, which is "good enough" in that case. - fileLangExt := filepath.Ext(baseName) - translationBaseName = strings.TrimSuffix(baseName, fileLangExt) - } - f := &FileInfo{ - sp: sp, - filename: filename, - fim: fi, - lang: lang, - ext: ext, - dir: dir, - relDir: relDir, // Dir() - relPath: relPath, // Path() - name: name, - baseName: baseName, // BaseFileName() - translationBaseName: translationBaseName, - classifier: m.Classifier, + sp: sp, + filename: m.Filename, + fim: fi, } return f, nil