github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/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 provides template functions for interacting with the operating 15 // system. 16 package os 17 18 import ( 19 "errors" 20 "fmt" 21 _os "os" 22 "path/filepath" 23 24 "github.com/bep/overlayfs" 25 "github.com/gohugoio/hugo/common/herrors" 26 "github.com/gohugoio/hugo/deps" 27 "github.com/spf13/afero" 28 "github.com/spf13/cast" 29 ) 30 31 // New returns a new instance of the os-namespaced template functions. 32 func New(d *deps.Deps) *Namespace { 33 var readFileFs, workFs afero.Fs 34 35 // The docshelper script does not have or need all the dependencies set up. 36 if d.PathSpec != nil { 37 readFileFs = overlayfs.New(overlayfs.Options{ 38 Fss: []afero.Fs{ 39 d.PathSpec.BaseFs.Work, 40 d.PathSpec.BaseFs.Content.Fs, 41 }, 42 }) 43 // See #9599 44 workFs = d.PathSpec.BaseFs.WorkDir 45 } 46 47 return &Namespace{ 48 readFileFs: readFileFs, 49 workFs: workFs, 50 deps: d, 51 } 52 } 53 54 // Namespace provides template functions for the "os" namespace. 55 type Namespace struct { 56 readFileFs afero.Fs 57 workFs afero.Fs 58 deps *deps.Deps 59 } 60 61 // Getenv retrieves the value of the environment variable named by the key. 62 // It returns the value, which will be empty if the variable is not present. 63 func (ns *Namespace) Getenv(key any) (string, error) { 64 skey, err := cast.ToStringE(key) 65 if err != nil { 66 return "", nil 67 } 68 69 if err = ns.deps.ExecHelper.Sec().CheckAllowedGetEnv(skey); err != nil { 70 return "", err 71 } 72 73 return _os.Getenv(skey), nil 74 } 75 76 // readFile reads the file named by filename in the given filesystem 77 // and returns the contents as a string. 78 func readFile(fs afero.Fs, filename string) (string, error) { 79 filename = filepath.Clean(filename) 80 if filename == "" || filename == "." || filename == string(_os.PathSeparator) { 81 return "", errors.New("invalid filename") 82 } 83 84 b, err := afero.ReadFile(fs, filename) 85 if err != nil { 86 return "", err 87 } 88 89 return string(b), nil 90 } 91 92 // ReadFile reads the file named by filename relative to the configured WorkingDir. 93 // It returns the contents as a string. 94 // There is an upper size limit set at 1 megabytes. 95 func (ns *Namespace) ReadFile(i any) (string, error) { 96 s, err := cast.ToStringE(i) 97 if err != nil { 98 return "", err 99 } 100 101 if ns.deps.PathSpec != nil { 102 s = ns.deps.PathSpec.RelPathify(s) 103 } 104 105 s, err = readFile(ns.readFileFs, s) 106 if err != nil && herrors.IsNotExist(err) { 107 return "", nil 108 } 109 return s, err 110 } 111 112 // ReadDir lists the directory contents relative to the configured WorkingDir. 113 func (ns *Namespace) ReadDir(i any) ([]_os.FileInfo, error) { 114 path, err := cast.ToStringE(i) 115 if err != nil { 116 return nil, err 117 } 118 119 list, err := afero.ReadDir(ns.workFs, path) 120 if err != nil { 121 return nil, fmt.Errorf("failed to read directory %q: %s", path, err) 122 } 123 124 return list, nil 125 } 126 127 // FileExists checks whether a file exists under the given path. 128 func (ns *Namespace) FileExists(i any) (bool, error) { 129 path, err := cast.ToStringE(i) 130 if err != nil { 131 return false, err 132 } 133 134 if path == "" { 135 return false, errors.New("fileExists needs a path to a file") 136 } 137 138 status, err := afero.Exists(ns.readFileFs, path) 139 if err != nil { 140 return false, err 141 } 142 143 return status, nil 144 } 145 146 // Stat returns the os.FileInfo structure describing file. 147 func (ns *Namespace) Stat(i any) (_os.FileInfo, error) { 148 path, err := cast.ToStringE(i) 149 if err != nil { 150 return nil, err 151 } 152 153 if path == "" { 154 return nil, errors.New("fileStat needs a path to a file") 155 } 156 157 r, err := ns.readFileFs.Stat(path) 158 if err != nil { 159 return nil, err 160 } 161 162 return r, nil 163 }