1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// Copyright 2021 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 source
import (
"path/filepath"
"sync"
"github.com/bep/gitmap"
"github.com/bep/logg"
"github.com/gohugoio/hugo/common/hashing"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/hugofs"
)
// File describes a source file.
type File struct {
fim hugofs.FileMetaInfo
uniqueID string
lazyInit sync.Once
}
// IsContentAdapter returns whether the file represents a content adapter.
// This means that there may be more than one Page associated with this file.
func (fi *File) IsContentAdapter() bool {
return fi.fim.Meta().PathInfo.IsContentData()
}
// Filename returns a file's absolute path and filename on disk.
func (fi *File) 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 *File) 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.
func (fi *File) Dir() string {
return fi.pathToDir(fi.p().Dir())
}
// Ext returns a file's extension without the leading period (e.g. "md").
func (fi *File) Ext() string { return fi.p().Ext() }
// Lang returns a file's language (e.g. "sv").
// Deprecated: Use .Page.Language.Lang instead.
func (fi *File) Lang() string {
// From Hugo 0.149.0 a file may have multiple languages.
hugo.DeprecateLevelMin(".File.Lang", "Use e.g. Page.Site.Language.Lang", "v0.149.0", logg.LevelError)
return ""
}
// LogicalName returns a file's name and extension (e.g. "page.sv.md").
func (fi *File) LogicalName() string {
return fi.p().Name()
}
// BaseFileName returns a file's name without extension (e.g. "page.sv").
func (fi *File) BaseFileName() string {
return fi.p().NameNoExt()
}
// TranslationBaseName returns a file's translation base name without the
// language segment (e.g. "page").
func (fi *File) TranslationBaseName() string { return fi.p().NameNoIdentifier() }
// ContentBaseName is a either TranslationBaseName or name of containing folder
// if file is a bundle.
func (fi *File) ContentBaseName() string {
return fi.p().BaseNameNoIdentifier()
}
// Section returns a file's section.
func (fi *File) Section() string {
return fi.p().Section()
}
// UniqueID returns a file's unique, MD5 hash identifier.
func (fi *File) UniqueID() string {
fi.init()
return fi.uniqueID
}
// FileInfo returns a file's underlying os.FileInfo.
func (fi *File) FileInfo() hugofs.FileMetaInfo { return fi.fim }
func (fi *File) String() string { return fi.BaseFileName() }
// Open implements ReadableFile.
func (fi *File) Open() (hugio.ReadSeekCloser, error) {
f, err := fi.fim.Meta().Open()
return f, err
}
func (fi *File) IsZero() bool {
return fi == nil
}
// We create a lot of these FileInfo objects, but there are parts of it used only
// in some cases that is slightly expensive to construct.
func (fi *File) init() {
fi.lazyInit.Do(func() {
fi.uniqueID = hashing.MD5FromStringHexEncoded(filepath.ToSlash(fi.Path()))
})
}
func (fi *File) pathToDir(s string) string {
if s == "" {
return s
}
return filepath.FromSlash(s[1:] + "/")
}
func (fi *File) p() *paths.Path {
return fi.fim.Meta().PathInfo.Unnormalized()
}
var contentPathParser = &paths.PathParser{
IsContentExt: func(ext string) bool {
return true
},
}
// Used in tests.
func NewContentFileInfoFrom(path, filename string) *File {
meta := &hugofs.FileMeta{
Filename: filename,
PathInfo: contentPathParser.Parse(files.ComponentFolderContent, filepath.ToSlash(path)),
}
return NewFileInfo(hugofs.NewFileMetaInfo(nil, meta))
}
func NewFileInfo(fi hugofs.FileMetaInfo) *File {
return &File{
fim: fi,
}
}
// GitInfo provides information about a version controlled source file.
type GitInfo = gitmap.GitInfo
|