Skip to content

Commit

Permalink
cmd: Use newly-available version information
Browse files Browse the repository at this point in the history
Close #4926

New Version() function returns a simple and full version string.

Go module information is still preferred. Then vcs info.
  • Loading branch information
mholt committed Aug 4, 2022
1 parent 63c7720 commit 496c888
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 69 deletions.
131 changes: 107 additions & 24 deletions caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ func Load(cfgJSON []byte, forceReload bool) error {
// forcefully reloaded, then errConfigUnchanged This function is safe for
// concurrent use.
// The ifMatchHeader can optionally be given a string of the format:
// "<path> <hash>"
//
// "<path> <hash>"
//
// where <path> is the absolute path in the config and <hash> is the expected hash of
// the config at that path. If the hash in the ifMatchHeader doesn't match
// the hash of the config, then an APIError with status 412 will be returned.
Expand Down Expand Up @@ -791,38 +793,118 @@ func InstanceID() (uuid.UUID, error) {
return uuid.ParseBytes(uuidFileBytes)
}

// GoModule returns the build info of this Caddy
// build from debug.BuildInfo (requires Go modules).
// If no version information is available, a non-nil
// value will still be returned, but with an
// unknown version.
func GoModule() *debug.Module {
var mod debug.Module
return goModule(&mod)
}

// goModule holds the actual implementation of GoModule.
// Allocating debug.Module in GoModule() and passing a
// reference to goModule enables mid-stack inlining.
func goModule(mod *debug.Module) *debug.Module {
mod.Version = "unknown"
// Version returns the Caddy version in a simple/short form, and
// a full version string. The short form will not have spaces and
// is intended for User-Agent strings and similar, but may be
// omitting valuable information. Note that Caddy must be compiled
// in a special way to properly embed complete version information.
// First this function tries to get the version from the embedded
// build info provided by go.mod dependencies; then it tries to
// get info from embedded VCS information, which requires having
// built Caddy from a git repository. If no version is available,
// this function returns "(devel)" becaise Go uses that, but for
// the simple form we change it to "unknown".
//
// See relevant Go issues: https://github.com/golang/go/issues/29228
// and https://github.com/golang/go/issues/50603.
//
// This function is experimental and subject to change or removal.
func Version() (simple, full string) {
// the currently-recommended way to build Caddy involves
// building it as a dependency so we can extract version
// information from go.mod tooling; once the upstream
// Go issues are fixed, we should just be able to use
// bi.Main... hopefully.
var module *debug.Module
bi, ok := debug.ReadBuildInfo()
if ok {
mod.Path = bi.Main.Path
// The recommended way to build Caddy involves
// creating a separate main module, which
// TODO: track related Go issue: https://github.com/golang/go/issues/29228
// once that issue is fixed, we should just be able to use bi.Main... hopefully.
// find the Caddy module in the dependency list
for _, dep := range bi.Deps {
if dep.Path == ImportPath {
return dep
module = dep
break
}
}
}
if module != nil {
simple, full = module.Version, module.Version
if module.Sum != "" {
full += " " + module.Sum
}
if module.Replace != nil {
full += " => " + module.Replace.Path
if module.Replace.Version != "" {
simple = module.Replace.Version + "_custom"
full += "@" + module.Replace.Version
}
if module.Replace.Sum != "" {
full += " " + module.Replace.Sum
}
}
}

if full == "" {
var vcsRevision string
var vcsTime time.Time
var vcsModified bool
for _, setting := range bi.Settings {
switch setting.Key {
case "vcs.revision":
vcsRevision = setting.Value
case "vcs.time":
vcsTime, _ = time.Parse(time.RFC3339, setting.Value)
case "vcs.modified":
vcsModified, _ = strconv.ParseBool(setting.Value)
}
}
return &bi.Main

if vcsRevision != "" {
var modified string
if vcsModified {
modified = "+modified"
}
full = fmt.Sprintf("%s%s (%s)", vcsRevision, modified, vcsTime.Format(time.RFC822))
simple = vcsRevision

// use short checksum for simple, if hex-only
if _, err := hex.DecodeString(simple); err == nil {
simple = simple[:8]
}

// append date to simple since it can be convenient
// to know the commit date as part of the version
if !vcsTime.IsZero() {
simple += "-" + vcsTime.Format("20060102")
}
}
}

if simple == "" || simple == "(devel)" {
simple = "unknown"
}
return mod

return
}

// func goModule(mod *debug.Module) *debug.Module {
// mod.Version = "unknown"
// bi, ok := debug.ReadBuildInfo()
// if ok {
// mod.Path = bi.Main.Path
// // The recommended way to build Caddy involves
// // creating a separate main module, which
// // TODO: track related Go issue: https://github.com/golang/go/issues/29228
// // once that issue is fixed, we should just be able to use bi.Main... hopefully.
// for _, dep := range bi.Deps {
// if dep.Path == ImportPath {
// return dep
// }
// }
// return &bi.Main
// }
// return mod
// }

func ActiveContext() Context {
currentCtxMu.RLock()
defer currentCtxMu.RUnlock()
Expand Down Expand Up @@ -867,4 +949,5 @@ var (
var errSameConfig = errors.New("config is unchanged")

// ImportPath is the package import path for Caddy core.
// This identifier may be removed in the future.
const ImportPath = "github.com/caddyserver/caddy/v2"
21 changes: 4 additions & 17 deletions cmd/commandfuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,30 +331,17 @@ func cmdReload(fl Flags) (int, error) {
}

func cmdVersion(_ Flags) (int, error) {
fmt.Println(CaddyVersion())
_, full := caddy.Version()
fmt.Println(full)
return caddy.ExitCodeSuccess, nil
}

func cmdBuildInfo(fl Flags) (int, error) {
func cmdBuildInfo(_ Flags) (int, error) {
bi, ok := debug.ReadBuildInfo()
if !ok {
return caddy.ExitCodeFailedStartup, fmt.Errorf("no build information")
}

fmt.Printf("go_version: %s\n", runtime.Version())
fmt.Printf("go_os: %s\n", runtime.GOOS)
fmt.Printf("go_arch: %s\n", runtime.GOARCH)
fmt.Printf("path: %s\n", bi.Path)
fmt.Printf("main: %s %s %s\n", bi.Main.Path, bi.Main.Version, bi.Main.Sum)
fmt.Println("dependencies:")

for _, goMod := range bi.Deps {
fmt.Printf("%s %s %s", goMod.Path, goMod.Version, goMod.Sum)
if goMod.Replace != nil {
fmt.Printf(" => %s %s %s", goMod.Replace.Path, goMod.Replace.Version, goMod.Replace.Sum)
}
fmt.Println()
}
fmt.Println(bi)
return caddy.ExitCodeSuccess, nil
}

Expand Down
26 changes: 4 additions & 22 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ import (

func init() {
// set a fitting User-Agent for ACME requests
goModule := caddy.GoModule()
cleanModVersion := strings.TrimPrefix(goModule.Version, "v")
version, _ := caddy.Version()
cleanModVersion := strings.TrimPrefix(version, "v")
certmagic.UserAgent = "Caddy/" + cleanModVersion

// by using Caddy, user indicates agreement to CA terms
Expand Down Expand Up @@ -441,11 +441,12 @@ func parseEnvFile(envInput io.Reader) (map[string]string, error) {
}

func printEnvironment() {
_, version := caddy.Version()
fmt.Printf("caddy.HomeDir=%s\n", caddy.HomeDir())
fmt.Printf("caddy.AppDataDir=%s\n", caddy.AppDataDir())
fmt.Printf("caddy.AppConfigDir=%s\n", caddy.AppConfigDir())
fmt.Printf("caddy.ConfigAutosavePath=%s\n", caddy.ConfigAutosavePath)
fmt.Printf("caddy.Version=%s\n", CaddyVersion())
fmt.Printf("caddy.Version=%s\n", version)
fmt.Printf("runtime.GOOS=%s\n", runtime.GOOS)
fmt.Printf("runtime.GOARCH=%s\n", runtime.GOARCH)
fmt.Printf("runtime.Compiler=%s\n", runtime.Compiler)
Expand All @@ -462,25 +463,6 @@ func printEnvironment() {
}
}

// CaddyVersion returns a detailed version string, if available.
func CaddyVersion() string {
goModule := caddy.GoModule()
ver := goModule.Version
if goModule.Sum != "" {
ver += " " + goModule.Sum
}
if goModule.Replace != nil {
ver += " => " + goModule.Replace.Path
if goModule.Replace.Version != "" {
ver += "@" + goModule.Replace.Version
}
if goModule.Replace.Sum != "" {
ver += " " + goModule.Replace.Sum
}
}
return ver
}

// StringSlice is a flag.Value that enables repeated use of a string flag.
type StringSlice []string

Expand Down
6 changes: 2 additions & 4 deletions modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,8 @@ func (t *Transport) Provision(ctx caddy.Context) error {
t.Root = "{http.vars.root}"
}

t.serverSoftware = "Caddy"
if mod := caddy.GoModule(); mod.Version != "" {
t.serverSoftware += "/" + mod.Version
}
version, _ := caddy.Version()
t.serverSoftware = "Caddy/" + version

// Set a relatively short default dial timeout.
// This is helpful to make load-balancer retries more speedy.
Expand Down
4 changes: 2 additions & 2 deletions modules/caddyhttp/tracing/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/caddyserver/caddy/v2"

caddycmd "github.com/caddyserver/caddy/v2/cmd"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
Expand Down Expand Up @@ -52,7 +51,8 @@ func newOpenTelemetryWrapper(
spanName: spanName,
}

res, err := ot.newResource(webEngineName, caddycmd.CaddyVersion())
version, _ := caddy.Version()
res, err := ot.newResource(webEngineName, version)
if err != nil {
return ot, fmt.Errorf("creating resource error: %w", err)
}
Expand Down

0 comments on commit 496c888

Please # to comment.