github.com/rezahousseini/hugo@v0.32.3/source/fileInfo.go (about) 1 // Copyright 2017-present The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package source 15 16 import ( 17 "io" 18 "os" 19 "path/filepath" 20 "strings" 21 "sync" 22 23 "github.com/gohugoio/hugo/helpers" 24 ) 25 26 // fileInfo implements the File interface. 27 var ( 28 _ File = (*FileInfo)(nil) 29 _ ReadableFile = (*FileInfo)(nil) 30 ) 31 32 type File interface { 33 34 // Filename gets the full path and filename to the file. 35 Filename() string 36 37 // Path gets the relative path including file name and extension. 38 // The directory is relative to the content root. 39 Path() string 40 41 // Dir gets the name of the directory that contains this file. 42 // The directory is relative to the content root. 43 Dir() string 44 45 // Extension gets the file extension, i.e "myblogpost.md" will return "md". 46 Extension() string 47 // Ext is an alias for Extension. 48 Ext() string // Hmm... Deprecate Extension 49 50 // Lang for this page, if `Multilingual` is enabled on your site. 51 Lang() string 52 53 // LogicalName is filename and extension of the file. 54 LogicalName() string 55 56 // Section is first directory below the content root. 57 Section() string 58 59 // BaseFileName is a filename without extension. 60 BaseFileName() string 61 62 // TranslationBaseName is a filename with no extension, 63 // not even the optional language extension part. 64 TranslationBaseName() string 65 66 // UniqueID is the MD5 hash of the file's path and is for most practical applications, 67 // Hugo content files being one of them, considered to be unique. 68 UniqueID() string 69 70 FileInfo() os.FileInfo 71 72 String() string 73 74 // Deprecated 75 Bytes() []byte 76 } 77 78 // A ReadableFile is a File that is readable. 79 type ReadableFile interface { 80 File 81 Open() (io.ReadCloser, error) 82 } 83 84 type FileInfo struct { 85 86 // Absolute filename to the file on disk. 87 filename string 88 fi os.FileInfo 89 90 // Derived from filename 91 ext string // Extension without any "." 92 lang string 93 94 name string 95 96 dir string 97 relDir string 98 relPath string 99 baseName string 100 translationBaseName string 101 section string 102 103 uniqueID string 104 105 sp *SourceSpec 106 107 lazyInit sync.Once 108 } 109 110 func (fi *FileInfo) Filename() string { return fi.filename } 111 func (fi *FileInfo) Path() string { return fi.relPath } 112 func (fi *FileInfo) Dir() string { return fi.relDir } 113 func (fi *FileInfo) Extension() string { return fi.Ext() } 114 func (fi *FileInfo) Ext() string { return fi.ext } 115 func (fi *FileInfo) Lang() string { return fi.lang } 116 func (fi *FileInfo) LogicalName() string { return fi.name } 117 func (fi *FileInfo) BaseFileName() string { return fi.baseName } 118 func (fi *FileInfo) TranslationBaseName() string { return fi.translationBaseName } 119 120 func (fi *FileInfo) Section() string { 121 fi.init() 122 return fi.section 123 } 124 125 func (fi *FileInfo) UniqueID() string { 126 fi.init() 127 return fi.uniqueID 128 } 129 func (fi *FileInfo) FileInfo() os.FileInfo { 130 return fi.fi 131 } 132 133 func (fi *FileInfo) Bytes() []byte { 134 // Remove in Hugo 0.34 135 helpers.Deprecated("File", "Bytes", "", false) 136 return []byte("") 137 } 138 139 func (fi *FileInfo) String() string { return fi.BaseFileName() } 140 141 // We create a lot of these FileInfo objects, but there are parts of it used only 142 // in some cases that is slightly expensive to construct. 143 func (fi *FileInfo) init() { 144 fi.lazyInit.Do(func() { 145 parts := strings.Split(fi.relDir, helpers.FilePathSeparator) 146 var section string 147 if len(parts) == 1 { 148 section = parts[0] 149 } else if len(parts) > 1 { 150 if parts[0] == "" { 151 section = parts[1] 152 } else { 153 section = parts[0] 154 } 155 } 156 157 fi.section = section 158 159 fi.uniqueID = helpers.MD5String(filepath.ToSlash(fi.relPath)) 160 161 }) 162 } 163 164 func (sp *SourceSpec) NewFileInfo(baseDir, filename string, fi os.FileInfo) *FileInfo { 165 166 dir, name := filepath.Split(filename) 167 if !strings.HasSuffix(dir, helpers.FilePathSeparator) { 168 dir = dir + helpers.FilePathSeparator 169 } 170 171 baseDir = strings.TrimSuffix(baseDir, helpers.FilePathSeparator) 172 173 relDir := "" 174 if dir != baseDir { 175 relDir = strings.TrimPrefix(dir, baseDir) 176 } 177 178 relDir = strings.TrimPrefix(relDir, helpers.FilePathSeparator) 179 180 relPath := filepath.Join(relDir, name) 181 182 ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(name), ".")) 183 baseName := helpers.Filename(name) 184 185 lang := strings.TrimPrefix(filepath.Ext(baseName), ".") 186 var translationBaseName string 187 188 if _, ok := sp.Languages[lang]; lang == "" || !ok { 189 lang = sp.DefaultContentLanguage 190 translationBaseName = baseName 191 } else { 192 translationBaseName = helpers.Filename(baseName) 193 } 194 195 f := &FileInfo{ 196 sp: sp, 197 filename: filename, 198 fi: fi, 199 lang: lang, 200 ext: ext, 201 dir: dir, 202 relDir: relDir, 203 relPath: relPath, 204 name: name, 205 baseName: baseName, 206 translationBaseName: translationBaseName, 207 } 208 209 return f 210 211 } 212 213 // Open implements ReadableFile. 214 func (fi *FileInfo) Open() (io.ReadCloser, error) { 215 return fi.sp.Fs.Source.Open(fi.Filename()) 216 }