github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/tpl/os/os.go (about) 1 // Copyright 2017 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 os 15 16 import ( 17 "errors" 18 "fmt" 19 _os "os" 20 21 "github.com/gohugoio/hugo/deps" 22 "github.com/spf13/afero" 23 "github.com/spf13/cast" 24 ) 25 26 // New returns a new instance of the os-namespaced template functions. 27 func New(deps *deps.Deps) *Namespace { 28 29 // Since Hugo 0.38 we can have multiple content dirs. This can make it hard to 30 // reason about where the file is placed relative to the project root. 31 // To make the {{ readFile .Filename }} variant just work, we create a composite 32 // filesystem that first checks the work dir fs and then the content fs. 33 var rfs afero.Fs 34 if deps.Fs != nil { 35 rfs = deps.Fs.WorkingDir 36 if deps.PathSpec != nil && deps.PathSpec.BaseFs != nil { 37 rfs = afero.NewReadOnlyFs(afero.NewCopyOnWriteFs(deps.PathSpec.BaseFs.ContentFs, deps.Fs.WorkingDir)) 38 } 39 } 40 41 return &Namespace{ 42 readFileFs: rfs, 43 deps: deps, 44 } 45 } 46 47 // Namespace provides template functions for the "os" namespace. 48 type Namespace struct { 49 readFileFs afero.Fs 50 deps *deps.Deps 51 } 52 53 // Getenv retrieves the value of the environment variable named by the key. 54 // It returns the value, which will be empty if the variable is not present. 55 func (ns *Namespace) Getenv(key interface{}) (string, error) { 56 skey, err := cast.ToStringE(key) 57 if err != nil { 58 return "", nil 59 } 60 61 return _os.Getenv(skey), nil 62 } 63 64 // readFile reads the file named by filename in the given filesystem 65 // and returns the contents as a string. 66 // There is a upper size limit set at 1 megabytes. 67 func readFile(fs afero.Fs, filename string) (string, error) { 68 if filename == "" { 69 return "", errors.New("readFile needs a filename") 70 } 71 72 if info, err := fs.Stat(filename); err == nil { 73 if info.Size() > 1000000 { 74 return "", fmt.Errorf("File %q is too big", filename) 75 } 76 } else { 77 return "", err 78 } 79 b, err := afero.ReadFile(fs, filename) 80 81 if err != nil { 82 return "", err 83 } 84 85 return string(b), nil 86 } 87 88 // ReadFile reads the file named by filename relative to the configured WorkingDir. 89 // It returns the contents as a string. 90 // There is an upper size limit set at 1 megabytes. 91 func (ns *Namespace) ReadFile(i interface{}) (string, error) { 92 s, err := cast.ToStringE(i) 93 if err != nil { 94 return "", err 95 } 96 97 return readFile(ns.readFileFs, s) 98 } 99 100 // ReadDir lists the directory contents relative to the configured WorkingDir. 101 func (ns *Namespace) ReadDir(i interface{}) ([]_os.FileInfo, error) { 102 path, err := cast.ToStringE(i) 103 if err != nil { 104 return nil, err 105 } 106 107 list, err := afero.ReadDir(ns.deps.Fs.WorkingDir, path) 108 if err != nil { 109 return nil, fmt.Errorf("Failed to read Directory %s with error message %s", path, err) 110 } 111 112 return list, nil 113 } 114 115 // FileExists checks whether a file exists under the given path. 116 func (ns *Namespace) FileExists(i interface{}) (bool, error) { 117 path, err := cast.ToStringE(i) 118 if err != nil { 119 return false, err 120 } 121 122 if path == "" { 123 return false, errors.New("fileExists needs a path to a file") 124 } 125 126 status, err := afero.Exists(ns.readFileFs, path) 127 if err != nil { 128 return false, err 129 } 130 131 return status, nil 132 }