Skip to content

Commit

Permalink
File
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Jan 5, 2022
1 parent 658ba38 commit 70a0c79
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 111 deletions.
57 changes: 41 additions & 16 deletions common/paths/pathparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
}
}
}
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -148,7 +157,9 @@ const (
type pathBase struct {
s string

posBase int
posContainerLow int
posContainerHigh int
posSectionHigh int

component string
isContent bool
Expand Down Expand Up @@ -184,38 +195,52 @@ 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
}

// 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 "/"
}
Expand All @@ -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
}
}

Expand Down
2 changes: 2 additions & 0 deletions common/paths/pathparser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"})
Expand Down
108 changes: 13 additions & 95 deletions source/fileInfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
}
}

Expand All @@ -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
Expand Down

0 comments on commit 70a0c79

Please sign in to comment.