diff --git a/client/cmd/dexc/main.go b/client/cmd/dexc/main.go index 37178e3c53..bf18bbf845 100644 --- a/client/cmd/dexc/main.go +++ b/client/cmd/dexc/main.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "os/signal" + "runtime" "sync" "time" @@ -15,6 +16,7 @@ import ( _ "decred.org/dcrdex/client/asset/dcr" // register dcr asset _ "decred.org/dcrdex/client/asset/ltc" // register ltc asset "decred.org/dcrdex/client/cmd/dexc/ui" + "decred.org/dcrdex/client/cmd/dexc/version" "decred.org/dcrdex/client/core" "decred.org/dcrdex/client/rpcserver" "decred.org/dcrdex/client/webserver" @@ -62,6 +64,7 @@ func main() { } logMaker := ui.InitLogging(logStdout, cfg.DebugLevel, utc) log = logMaker.Logger("DEXC") + log.Infof("%s version %v (Go version %s)", version.AppName, version.Version(), runtime.Version()) if utc { log.Infof("Logging with UTC time stamps. Current local time is %v", time.Now().Local().Format("15:04:05 MST")) diff --git a/client/cmd/dexc/ui/config.go b/client/cmd/dexc/ui/config.go index 02c3c59fae..bb081c3100 100644 --- a/client/cmd/dexc/ui/config.go +++ b/client/cmd/dexc/ui/config.go @@ -11,6 +11,7 @@ import ( "runtime" "strings" + "decred.org/dcrdex/client/cmd/dexc/version" "decred.org/dcrdex/dex" "github.com/decred/dcrd/dcrutil/v2" flags "github.com/jessevdk/go-flags" @@ -72,6 +73,7 @@ type Config struct { ReloadHTML bool `long:"reload-html" description:"Reload the webserver's page template with every request. For development purposes."` DebugLevel string `long:"log" description:"Logging level {trace, debug, info, warn, error, critical}"` LocalLogs bool `long:"loglocal" description:"Use local time zone time stamps in log entries."` + ShowVer bool `short:"V" long:"version" description:"Display version information and exit"` Net dex.Network } @@ -105,6 +107,13 @@ func Configure() (*Config, error) { return nil, flagerr } + // Show the version and exit if the version flag was specified. + if preCfg.ShowVer { + fmt.Printf("%s version %s (Go version %s %s/%s)\n", + version.AppName, version.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) + os.Exit(0) + } + // If the app directory has been changed, but the config file path hasn't, // reform the config file path with the new directory. if preCfg.AppData != defaultApplicationDirectory && preCfg.Config == defaultConfigPath { diff --git a/client/cmd/dexc/version/version.go b/client/cmd/dexc/version/version.go new file mode 100644 index 0000000000..f0e1c05a53 --- /dev/null +++ b/client/cmd/dexc/version/version.go @@ -0,0 +1,97 @@ +// This code is available on the terms of the project LICENSE.md file, +// also available online at https://blueoakcouncil.org/license/1.0.0. + +package version + +import ( + "bytes" + "fmt" + "strings" +) + +const ( + // semanticAlphabet defines the allowed characters for the pre-release + // portion of a semantic version string. + semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + + // semanticBuildAlphabet defines the allowed characters for the build + // portion of a semantic version string. + semanticBuildAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-." +) + +// These constants define the application version and follow the semantic +// versioning 2.0.0 spec (http://semver.org/). +const ( + AppName string = "dexc" + AppMajor uint = 0 + AppMinor uint = 1 + AppPatch uint = 0 +) + +// go build -v -ldflags "-X decred.org/dcrdex/client/cmd/dexc/version.appPreRelease= -X decred.org/dcrdex/client/cmd/dexc/version.appBuild=$(git rev-parse --short HEAD)" +var ( + // appPreRelease is defined as a variable so it can be overridden during the + // build process. It MUST only contain characters from semanticAlphabet per + // the semantic versioning spec. + appPreRelease = "pre" + + // appBuild is defined as a variable so it can be overridden during the + // build process. It MUST only contain characters from semanticBuildAlphabet + // per the semantic versioning spec. + appBuild = "dev" +) + +// Version returns the application version as a properly formed string per the +// semantic versioning 2.0.0 spec (http://semver.org/). +func Version() string { + // Start with the major, minor, and patch versions. + version := fmt.Sprintf("%d.%d.%d", AppMajor, AppMinor, AppPatch) + + // Append pre-release version if there is one. The hyphen called for + // by the semantic versioning spec is automatically appended and should + // not be contained in the pre-release string. The pre-release version + // is not appended if it contains invalid characters. + preRelease := normalizePreRelString(appPreRelease) + if preRelease != "" { + version = fmt.Sprintf("%s-%s", version, preRelease) + } + + // Append build metadata if there is any. The plus called for + // by the semantic versioning spec is automatically appended and should + // not be contained in the build metadata string. The build metadata + // string is not appended if it contains invalid characters. + build := normalizeBuildString(appBuild) + if build != "" { + version = fmt.Sprintf("%s+%s", version, build) + } + + return version +} + +// normalizeSemString returns the passed string stripped of all characters +// which are not valid according to the provided semantic versioning alphabet. +func normalizeSemString(str, alphabet string) string { + var result bytes.Buffer + for _, r := range str { + if strings.ContainsRune(alphabet, r) { + result.WriteRune(r) + } + } + return result.String() +} + +// normalizePreRelString returns the passed string stripped of all characters +// which are not valid according to the semantic versioning guidelines for +// pre-release strings. In particular they MUST only contain characters in +// semanticAlphabet. +func normalizePreRelString(str string) string { + return normalizeSemString(str, semanticAlphabet) +} + +// normalizeBuildString returns the passed string stripped of all characters +// which are not valid according to the semantic versioning guidelines for build +// metadata strings. In particular they MUST only contain characters in +// semanticBuildAlphabet. +func normalizeBuildString(str string) string { + return normalizeSemString(str, semanticBuildAlphabet) +} diff --git a/server/cmd/dcrdex/config.go b/server/cmd/dcrdex/config.go index 04de93c6b2..7bb1017fb5 100644 --- a/server/cmd/dcrdex/config.go +++ b/server/cmd/dcrdex/config.go @@ -327,8 +327,8 @@ func loadConfig() (*dexConf, *procOpts, error) { // Show the version and exit if the version flag was specified. if preCfg.ShowVersion { - fmt.Printf("dcrdex version %s (Go version %s %s/%s)\n", - Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) + fmt.Printf("%s version %s (Go version %s %s/%s)\n", + AppName, Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) os.Exit(0) } diff --git a/server/cmd/dcrdex/version.go b/server/cmd/dcrdex/version.go index c1eff69124..3966b96bc8 100644 --- a/server/cmd/dcrdex/version.go +++ b/server/cmd/dcrdex/version.go @@ -24,11 +24,11 @@ const ( const ( AppName string = "dcrdex" AppMajor uint = 0 - AppMinor uint = 0 - AppPatch uint = 1 + AppMinor uint = 1 + AppPatch uint = 0 ) -// go build -v -ldflags "-X appPreRelease= -X appBuild=`git rev-parse --short HEAD`" +// go build -v -ldflags "-X main.appPreRelease= -X main.appBuild=$(git rev-parse --short HEAD)" var ( // appPreRelease is defined as a variable so it can be overridden during the // build process. It MUST only contain characters from semanticAlphabet per