github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/tpl/path/path.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 path provides template functions for manipulating paths. 15 package path 16 17 import ( 18 _path "path" 19 "path/filepath" 20 "strings" 21 22 "github.com/gohugoio/hugo/common/paths" 23 "github.com/gohugoio/hugo/deps" 24 "github.com/spf13/cast" 25 ) 26 27 // New returns a new instance of the path-namespaced template functions. 28 func New(deps *deps.Deps) *Namespace { 29 return &Namespace{ 30 deps: deps, 31 } 32 } 33 34 // Namespace provides template functions for the "os" namespace. 35 type Namespace struct { 36 deps *deps.Deps 37 } 38 39 // Ext returns the file name extension used by path. 40 // The extension is the suffix beginning at the final dot 41 // in the final slash-separated element of path; 42 // it is empty if there is no dot. 43 // The input path is passed into filepath.ToSlash converting any Windows slashes 44 // to forward slashes. 45 func (ns *Namespace) Ext(path any) (string, error) { 46 spath, err := cast.ToStringE(path) 47 if err != nil { 48 return "", err 49 } 50 spath = filepath.ToSlash(spath) 51 return _path.Ext(spath), nil 52 } 53 54 // Dir returns all but the last element of path, typically the path's directory. 55 // After dropping the final element using Split, the path is Cleaned and trailing 56 // slashes are removed. 57 // If the path is empty, Dir returns ".". 58 // If the path consists entirely of slashes followed by non-slash bytes, Dir 59 // returns a single slash. In any other case, the returned path does not end in a 60 // slash. 61 // The input path is passed into filepath.ToSlash converting any Windows slashes 62 // to forward slashes. 63 func (ns *Namespace) Dir(path any) (string, error) { 64 spath, err := cast.ToStringE(path) 65 if err != nil { 66 return "", err 67 } 68 spath = filepath.ToSlash(spath) 69 return _path.Dir(spath), nil 70 } 71 72 // Base returns the last element of path. 73 // Trailing slashes are removed before extracting the last element. 74 // If the path is empty, Base returns ".". 75 // If the path consists entirely of slashes, Base returns "/". 76 // The input path is passed into filepath.ToSlash converting any Windows slashes 77 // to forward slashes. 78 func (ns *Namespace) Base(path any) (string, error) { 79 spath, err := cast.ToStringE(path) 80 if err != nil { 81 return "", err 82 } 83 spath = filepath.ToSlash(spath) 84 return _path.Base(spath), nil 85 } 86 87 // BaseName returns the last element of path, removing the extension if present. 88 // Trailing slashes are removed before extracting the last element. 89 // If the path is empty, Base returns ".". 90 // If the path consists entirely of slashes, Base returns "/". 91 // The input path is passed into filepath.ToSlash converting any Windows slashes 92 // to forward slashes. 93 func (ns *Namespace) BaseName(path any) (string, error) { 94 spath, err := cast.ToStringE(path) 95 if err != nil { 96 return "", err 97 } 98 spath = filepath.ToSlash(spath) 99 return strings.TrimSuffix(_path.Base(spath), _path.Ext(spath)), nil 100 } 101 102 // Split splits path immediately following the final slash, 103 // separating it into a directory and file name component. 104 // If there is no slash in path, Split returns an empty dir and 105 // file set to path. 106 // The input path is passed into filepath.ToSlash converting any Windows slashes 107 // to forward slashes. 108 // The returned values have the property that path = dir+file. 109 func (ns *Namespace) Split(path any) (paths.DirFile, error) { 110 spath, err := cast.ToStringE(path) 111 if err != nil { 112 return paths.DirFile{}, err 113 } 114 spath = filepath.ToSlash(spath) 115 dir, file := _path.Split(spath) 116 117 return paths.DirFile{Dir: dir, File: file}, nil 118 } 119 120 // Join joins any number of path elements into a single path, adding a 121 // separating slash if necessary. All the input 122 // path elements are passed into filepath.ToSlash converting any Windows slashes 123 // to forward slashes. 124 // The result is Cleaned; in particular, 125 // all empty strings are ignored. 126 func (ns *Namespace) Join(elements ...any) (string, error) { 127 var pathElements []string 128 for _, elem := range elements { 129 switch v := elem.(type) { 130 case []string: 131 for _, e := range v { 132 pathElements = append(pathElements, filepath.ToSlash(e)) 133 } 134 case []any: 135 for _, e := range v { 136 elemStr, err := cast.ToStringE(e) 137 if err != nil { 138 return "", err 139 } 140 pathElements = append(pathElements, filepath.ToSlash(elemStr)) 141 } 142 default: 143 elemStr, err := cast.ToStringE(elem) 144 if err != nil { 145 return "", err 146 } 147 pathElements = append(pathElements, filepath.ToSlash(elemStr)) 148 } 149 } 150 return _path.Join(pathElements...), nil 151 } 152 153 // Clean replaces the separators used with standard slashes and then 154 // extraneous slashes are removed. 155 func (ns *Namespace) Clean(path any) (string, error) { 156 spath, err := cast.ToStringE(path) 157 158 if err != nil { 159 return "", err 160 } 161 spath = filepath.ToSlash(spath) 162 return _path.Clean(spath), nil 163 }