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  }