diff --git a/release/prep_release.sh b/release/prep_release.sh index 2f32b400..648e1a7c 100644 --- a/release/prep_release.sh +++ b/release/prep_release.sh @@ -26,6 +26,7 @@ PROJECT=btcd PROJECT_UC=$(echo $PROJECT | tr '[:lower:]' '[:upper:]') SCRIPT=$(basename $0) VERFILE=../version.go +VERFILES="$VERFILE ../util/btcctl/version.go" PROJ_CHANGES=../CHANGES # verify params @@ -37,11 +38,13 @@ fi CUR_DIR=$(pwd) cd "$(dirname $0)" -# verify version file exists -if [ ! -f "$VERFILE" ]; then - echo "$SCRIPT: error: $VERFILE does not exist" 1>&2 - exit 1 -fi +# verify version files exist +for verfile in $VERFILES; do + if [ ! -f "$verfile" ]; then + echo "$SCRIPT: error: $verfile does not exist" 1>&2 + exit 1 + fi +done # verify changes file exists if [ ! -f "$PROJ_CHANGES" ]; then @@ -172,17 +175,21 @@ awk ' second_line==1 { print $0 } ' <"$PROJ_CHANGES" >>"${PROJ_CHANGES}.tmp" -# update version file with new version -sed -E " - s/${PAT_PREFIX}Major${PAT_SUFFIX}/\1${MAJOR}/; - s/${PAT_PREFIX}Minor${PAT_SUFFIX}/\1${MINOR}/; - s/${PAT_PREFIX}Patch${PAT_SUFFIX}/\1${PATCH}/; -" <"$VERFILE" >"${VERFILE}.tmp" +# update version filef with new version +for verfile in $VERFILES; do + sed -E " + s/${PAT_PREFIX}Major${PAT_SUFFIX}/\1${MAJOR}/; + s/${PAT_PREFIX}Minor${PAT_SUFFIX}/\1${MINOR}/; + s/${PAT_PREFIX}Patch${PAT_SUFFIX}/\1${PATCH}/; + " <"$verfile" >"${verfile}.tmp" +done # Apply changes mv "${PROJ_CHANGES}.tmp" "$PROJ_CHANGES" -mv "${VERFILE}.tmp" "$VERFILE" +for verfile in $VERFILES; do + mv "${verfile}.tmp" "$verfile" +done echo "All files have been prepared for release." echo "Use the following commands to review the changes for accuracy:" diff --git a/util/btcctl/config.go b/util/btcctl/config.go index 75a6495f..642ea793 100644 --- a/util/btcctl/config.go +++ b/util/btcctl/config.go @@ -6,6 +6,7 @@ import ( "github.com/conformal/go-flags" "os" "path/filepath" + "strings" ) var ( @@ -19,6 +20,7 @@ var ( // // See loadConfig for details on the configuration load process. type config struct { + ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"` RpcUser string `short:"u" long:"rpcuser" description:"RPC username"` RpcPassword string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password"` @@ -48,12 +50,20 @@ func loadConfig() (*flags.Parser, *config, []string, error) { } // Pre-parse the command line options to see if an alternative config - // file was specified. Any errors can be ignored here since they will - // be caught be the final parse below. + // file or the version flag was specified. Any errors can be ignored + // here since they will be caught be the final parse below. preCfg := cfg preParser := flags.NewParser(&preCfg, flags.None) preParser.Parse() + // Show the version and exit if the version flag was specified. + if preCfg.ShowVersion { + appName := filepath.Base(os.Args[0]) + appName = strings.TrimSuffix(appName, filepath.Ext(appName)) + fmt.Println(appName, "version", version()) + os.Exit(0) + } + // Load additional config from file. parser := flags.NewParser(&cfg, flags.PassDoubleDash|flags.HelpFlag) err := parser.ParseIniFile(preCfg.ConfigFile) diff --git a/util/btcctl/version.go b/util/btcctl/version.go new file mode 100644 index 00000000..535faac9 --- /dev/null +++ b/util/btcctl/version.go @@ -0,0 +1,72 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "strings" +) + +// semanticAlphabet +const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + +// These constants define the application version and follow the semantic +// versioning 2.0.0 spec (http://semver.org/). +const ( + appMajor uint = 0 + appMinor uint = 3 + appPatch uint = 3 + + // appPreRelease MUST only contain characters from semanticAlphabet + // per the semantic versioning spec. + appPreRelease = "alpha" +) + +// appBuild is defined as a variable so it can be overridden during the build +// process with '-ldflags "-X main.appBuild foo' if needed. It MUST only +// contain characters from semanticAlphabet per the semantic versioning spec. +var appBuild string + +// 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 := normalizeVerString(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 := normalizeVerString(appBuild) + if build != "" { + version = fmt.Sprintf("%s+%s", version, build) + } + + return version +} + +// normalizeVerString returns the passed string stripped of all characters which +// are not valid according to the semantic versioning guidelines for pre-release +// version and build metadata strings. In particular they MUST only contain +// characters in semanticAlphabet. +func normalizeVerString(str string) string { + var result bytes.Buffer + for _, r := range str { + if strings.ContainsRune(semanticAlphabet, r) { + result.WriteRune(r) + } + } + return result.String() +}