hugo.go (5932B)
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 hugo 15 16 import ( 17 "fmt" 18 "html/template" 19 "os" 20 "path/filepath" 21 "runtime/debug" 22 "sort" 23 "strings" 24 "sync" 25 "time" 26 27 "github.com/gohugoio/hugo/hugofs/files" 28 29 "github.com/spf13/afero" 30 31 "github.com/gohugoio/hugo/config" 32 "github.com/gohugoio/hugo/hugofs" 33 ) 34 35 const ( 36 EnvironmentDevelopment = "development" 37 EnvironmentProduction = "production" 38 ) 39 40 var ( 41 // vendorInfo contains vendor notes about the current build. 42 vendorInfo string 43 ) 44 45 // Info contains information about the current Hugo environment 46 type Info struct { 47 CommitHash string 48 BuildDate string 49 50 // The build environment. 51 // Defaults are "production" (hugo) and "development" (hugo server). 52 // This can also be set by the user. 53 // It can be any string, but it will be all lower case. 54 Environment string 55 56 // version of go that the Hugo binary was built with 57 GoVersion string 58 59 deps []*Dependency 60 } 61 62 // Version returns the current version as a comparable version string. 63 func (i Info) Version() VersionString { 64 return CurrentVersion.Version() 65 } 66 67 // Generator a Hugo meta generator HTML tag. 68 func (i Info) Generator() template.HTML { 69 return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s" />`, CurrentVersion.String())) 70 } 71 72 func (i Info) IsProduction() bool { 73 return i.Environment == EnvironmentProduction 74 } 75 76 func (i Info) IsExtended() bool { 77 return IsExtended 78 } 79 80 // Deps gets a list of dependencies for this Hugo build. 81 func (i Info) Deps() []*Dependency { 82 return i.deps 83 } 84 85 // NewInfo creates a new Hugo Info object. 86 func NewInfo(environment string, deps []*Dependency) Info { 87 if environment == "" { 88 environment = EnvironmentProduction 89 } 90 var ( 91 commitHash string 92 buildDate string 93 goVersion string 94 ) 95 96 bi := getBuildInfo() 97 if bi != nil { 98 commitHash = bi.Revision 99 buildDate = bi.RevisionTime 100 goVersion = bi.GoVersion 101 } 102 103 return Info{ 104 CommitHash: commitHash, 105 BuildDate: buildDate, 106 Environment: environment, 107 deps: deps, 108 GoVersion: goVersion, 109 } 110 } 111 112 // GetExecEnviron creates and gets the common os/exec environment used in the 113 // external programs we interact with via os/exec, e.g. postcss. 114 func GetExecEnviron(workDir string, cfg config.Provider, fs afero.Fs) []string { 115 var env []string 116 nodepath := filepath.Join(workDir, "node_modules") 117 if np := os.Getenv("NODE_PATH"); np != "" { 118 nodepath = workDir + string(os.PathListSeparator) + np 119 } 120 config.SetEnvVars(&env, "NODE_PATH", nodepath) 121 config.SetEnvVars(&env, "PWD", workDir) 122 config.SetEnvVars(&env, "HUGO_ENVIRONMENT", cfg.GetString("environment")) 123 config.SetEnvVars(&env, "HUGO_ENV", cfg.GetString("environment")) 124 125 if fs != nil { 126 fis, err := afero.ReadDir(fs, files.FolderJSConfig) 127 if err == nil { 128 for _, fi := range fis { 129 key := fmt.Sprintf("HUGO_FILE_%s", strings.ReplaceAll(strings.ToUpper(fi.Name()), ".", "_")) 130 value := fi.(hugofs.FileMetaInfo).Meta().Filename 131 config.SetEnvVars(&env, key, value) 132 } 133 } 134 } 135 136 return env 137 } 138 139 type buildInfo struct { 140 VersionControlSystem string 141 Revision string 142 RevisionTime string 143 Modified bool 144 145 GoOS string 146 GoArch string 147 148 *debug.BuildInfo 149 } 150 151 var bInfo *buildInfo 152 var bInfoInit sync.Once 153 154 func getBuildInfo() *buildInfo { 155 bInfoInit.Do(func() { 156 bi, ok := debug.ReadBuildInfo() 157 if !ok { 158 return 159 } 160 161 bInfo = &buildInfo{BuildInfo: bi} 162 163 for _, s := range bInfo.Settings { 164 switch s.Key { 165 case "vcs": 166 bInfo.VersionControlSystem = s.Value 167 case "vcs.revision": 168 bInfo.Revision = s.Value 169 case "vcs.time": 170 bInfo.RevisionTime = s.Value 171 case "vcs.modified": 172 bInfo.Modified = s.Value == "true" 173 case "GOOS": 174 bInfo.GoOS = s.Value 175 case "GOARCH": 176 bInfo.GoArch = s.Value 177 } 178 } 179 180 }) 181 182 return bInfo 183 } 184 185 // GetDependencyList returns a sorted dependency list on the format package="version". 186 // It includes both Go dependencies and (a manually maintained) list of C(++) dependencies. 187 func GetDependencyList() []string { 188 var deps []string 189 190 formatDep := func(path, version string) string { 191 return fmt.Sprintf("%s=%q", path, version) 192 } 193 194 if IsExtended { 195 deps = append( 196 deps, 197 // TODO(bep) consider adding a DepsNonGo() method to these upstream projects. 198 formatDep("github.com/sass/libsass", "3.6.5"), 199 formatDep("github.com/webmproject/libwebp", "v1.2.0"), 200 ) 201 } 202 203 bi := getBuildInfo() 204 if bi == nil { 205 return deps 206 } 207 208 for _, dep := range bi.Deps { 209 deps = append(deps, formatDep(dep.Path, dep.Version)) 210 } 211 212 sort.Strings(deps) 213 214 return deps 215 } 216 217 // IsRunningAsTest reports whether we are running as a test. 218 func IsRunningAsTest() bool { 219 for _, arg := range os.Args { 220 if strings.HasPrefix(arg, "-test") { 221 return true 222 } 223 } 224 return false 225 } 226 227 // Dependency is a single dependency, which can be either a Hugo Module or a local theme. 228 type Dependency struct { 229 // Returns the path to this module. 230 // This will either be the module path, e.g. "github.com/gohugoio/myshortcodes", 231 // or the path below your /theme folder, e.g. "mytheme". 232 Path string 233 234 // The module version. 235 Version string 236 237 // Whether this dependency is vendored. 238 Vendor bool 239 240 // Time version was created. 241 Time time.Time 242 243 // In the dependency tree, this is the first module that defines this module 244 // as a dependency. 245 Owner *Dependency 246 247 // Replaced by this dependency. 248 Replace *Dependency 249 }