github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/hugofs/language_composite_fs.go (about)

     1  // Copyright 2018 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 hugofs
    15  
    16  import (
    17  	"os"
    18  	"path"
    19  
    20  	"github.com/spf13/afero"
    21  )
    22  
    23  var (
    24  	_ afero.Fs      = (*languageCompositeFs)(nil)
    25  	_ afero.Lstater = (*languageCompositeFs)(nil)
    26  )
    27  
    28  type languageCompositeFs struct {
    29  	*afero.CopyOnWriteFs
    30  }
    31  
    32  // NewLanguageCompositeFs creates a composite and language aware filesystem.
    33  // This is a hybrid filesystem. To get a specific file in Open, Stat etc., use the full filename
    34  // to the target filesystem. This information is available in Readdir, Stat etc. via the
    35  // special LanguageFileInfo FileInfo implementation.
    36  func NewLanguageCompositeFs(base, overlay afero.Fs) afero.Fs {
    37  	return &languageCompositeFs{afero.NewCopyOnWriteFs(base, overlay).(*afero.CopyOnWriteFs)}
    38  }
    39  
    40  // Open takes the full path to the file in the target filesystem. If it is a directory, it gets merged
    41  // using the language as a weight.
    42  func (fs *languageCompositeFs) Open(name string) (afero.File, error) {
    43  	f, err := fs.CopyOnWriteFs.Open(name)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	fu, ok := f.(*afero.UnionFile)
    49  	if ok {
    50  		// This is a directory: Merge it.
    51  		fu.Merger = LanguageDirsMerger
    52  	}
    53  	return f, nil
    54  }
    55  
    56  // LanguageDirsMerger implements the afero.DirsMerger interface, which is used
    57  // to merge two directories.
    58  var LanguageDirsMerger = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) {
    59  	m := make(map[string]FileMetaInfo)
    60  
    61  	getKey := func(fim FileMetaInfo) string {
    62  		return path.Join(fim.Meta().Lang, fim.Name())
    63  	}
    64  
    65  	for _, fi := range lofi {
    66  		fim := fi.(FileMetaInfo)
    67  		m[getKey(fim)] = fim
    68  	}
    69  
    70  	for _, fi := range bofi {
    71  		fim := fi.(FileMetaInfo)
    72  		key := getKey(fim)
    73  		_, found := m[key]
    74  		if !found {
    75  			m[key] = fim
    76  		}
    77  	}
    78  
    79  	merged := make([]os.FileInfo, len(m))
    80  	i := 0
    81  	for _, v := range m {
    82  		merged[i] = v
    83  		i++
    84  	}
    85  
    86  	return merged, nil
    87  }