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 }