madb: add version number to the binary

This CL adds 'madb version' command, which would print the version
number of the binary.

If the madb binary is one of the official releases, it 'madb version'
will print out the official version number.

Otherwise, it will print out '<version>-develop', where the version
number is the most recent release version prior to the version of this
binary.

The MADB_VERSION file contains the version number, and should be
considered as the standard place to keep the current version number.
The version string value within the 'version.go' file is updated via
'go generate' command, similar to how the doc.go / embedded_gradle.go
files are generated. This work is done in 'scripts/update_version.go'.
The potential version mismatch between MADB_VERSION file and the value
in 'version.go' will be caught by the 'madb-go-generate' test.

The 'scripts/release.go' is a script that packages the new version of
madb binaries for linux and darwin platforms.

The process of releasing a new version would be roughly as following:
- update the MADB_VERSION number and commit the CL.
- 'go generate' to update the version number within version.go
- 'go run scripts/release.go' to build the binaries
- draft a new release on GitHub with the new version number. attach
  the binaries built from the previous step.
- give the version tag using git, and push the tag to origin.
  (the mirroring job will mirror the tag to GitHub within 5min.)
- publish the release on GitHub.

Change-Id: Ibc96f50aa2237e81aef8b1e26ad4cfc8e4ba68fd
ref: #25
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a012ec2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+archive/
diff --git a/MADB_VERSION b/MADB_VERSION
new file mode 100644
index 0000000..0ec25f7
--- /dev/null
+++ b/MADB_VERSION
@@ -0,0 +1 @@
+v1.0.0
diff --git a/doc.go b/doc.go
index 0253e9b..bea4b64 100644
--- a/doc.go
+++ b/doc.go
@@ -24,6 +24,7 @@
    stop        Stop your app on all devices
    uninstall   Uninstall your app from all devices
    user        Manage default user settings for each device
+   version     Print the madb version number
    help        Display help for commands or topics
 
 The madb flags are:
@@ -675,6 +676,29 @@
    '@' sign followed by the index of the device in the output of 'adb devices'
    command, starting from 1. Command will be run only on specified devices.
 
+Madb version - Print the madb version number
+
+Prints the madb version number to the console.
+
+If this version of madb binary is an official release, this command will show
+the version number. Otherwise, the version will be in the form of
+"<version>-develop", where the version indicates the most recent stable release
+version prior to this version of madb binary.
+
+Usage:
+   madb version [flags]
+
+The madb version flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1. Command will be run only on specified devices.
+
 Madb help - Display help for commands or topics
 
 Help with no args displays the usage of the parent command.
diff --git a/madb.go b/madb.go
index 1dd3fbd..50f797b 100644
--- a/madb.go
+++ b/madb.go
@@ -4,7 +4,12 @@
 
 // The following enables go generate to generate the doc.go file.
 //go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .
-//go:generate go run testdata/embed_gradle_script.go madb_init.gradle embedded_gradle.go gradleInitScript
+
+// The following generates the embedded_gradle.go file from the madb_init.gradle file.
+//go:generate go run scripts/embed_gradle_script.go madb_init.gradle embedded_gradle.go gradleInitScript
+
+// The following generates the version.go file with the version string defined in the MADB_VERSION file.
+//go:generate go run scripts/update_version.go
 
 package main
 
@@ -76,6 +81,7 @@
 		cmdMadbStop,
 		cmdMadbUninstall,
 		cmdMadbUser,
+		cmdMadbVersion,
 	},
 	Name:  "madb",
 	Short: "Multi-device Android Debug Bridge",
diff --git a/testdata/embed_gradle_script.go b/scripts/embed_gradle_script.go
similarity index 98%
rename from testdata/embed_gradle_script.go
rename to scripts/embed_gradle_script.go
index d383438..f72f329 100644
--- a/testdata/embed_gradle_script.go
+++ b/scripts/embed_gradle_script.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build ignore
+
 // A script that takes a source Gradle script, and writes a .go file that contains a constant string
 // variable that holds the contents of the source script. By doing this, the Gradle script can be
 // embedded in the madb binary. This script is located under testdata, to avoid being installed in
diff --git a/scripts/release.go b/scripts/release.go
new file mode 100644
index 0000000..2dcfa34
--- /dev/null
+++ b/scripts/release.go
@@ -0,0 +1,78 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// A script for creating pre-compiled binary releases for multiple platforms.
+// It reads the MADB_VERSION number,
+//
+// This script is intended to be run from the parent directory with the following command:
+//
+//     go run scripts/release.go
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"v.io/x/lib/gosh"
+)
+
+var targetOS = map[string]string{
+	"linux":  "linux",
+	"darwin": "macosx",
+}
+
+var targetArch = []string{"amd64"}
+
+func main() {
+	sh := gosh.NewShell(nil)
+	defer sh.Cleanup()
+
+	// Read the version string from the file MADB_VERSION.
+	versionString, err := readVersionString()
+	if err != nil {
+		panic(err)
+	}
+
+	archiveDir := "archive"
+	if err := os.Mkdir(archiveDir, 0755); err != nil {
+		panic(err)
+	}
+
+	for osCode, osName := range targetOS {
+		for _, arch := range targetArch {
+			variantName := fmt.Sprintf("madb-%v-%v-%v", versionString, osName, arch)
+			tempDir := sh.MakeTempDir()
+			outputDir := filepath.Join(tempDir, variantName)
+			outputPath := filepath.Join(outputDir, "madb")
+
+			// The -ldflags "-X main.version=<versionString>" flag overwrites the version value
+			// declared in version.go.
+			cmd := sh.Cmd("jiri", "go", "build", "-o", outputPath, "-ldflags", fmt.Sprintf("-X main.version=%v", versionString))
+			cmd.Vars["GOOS"] = osCode
+			cmd.Vars["GOARCH"] = arch
+			cmd.Run()
+
+			// Archive the directory using the pax utility.
+			archivePath := filepath.Join(archiveDir, variantName+".tar.gz")
+			cmd = sh.Cmd("pax", "-w", "-z", "-M", "dist", "-s", "#^"+tempDir+"/##", "-f", archivePath, outputDir)
+			cmd.Run()
+		}
+	}
+}
+
+func readVersionString() (string, error) {
+	versionFile, err := os.Open("MADB_VERSION")
+	if err != nil {
+		return "", err
+	}
+	defer versionFile.Close()
+
+	bytes, err := ioutil.ReadAll(versionFile)
+	return strings.TrimSpace(string(bytes)), err
+}
diff --git a/scripts/update_version.go b/scripts/update_version.go
new file mode 100644
index 0000000..fd76389
--- /dev/null
+++ b/scripts/update_version.go
@@ -0,0 +1,95 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// A script used to update the version number in version.go, based on MADB_VERSION.
+// For example, when the MADB_VERSION file contains "v1.0.0", the value of the version variable
+// defined in version.go file should be updated to "v1.0.0-develop".
+//
+// This script is intended to be run as part of "go generate" from the parent directory.
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"text/template"
+)
+
+const (
+	tmpl = `// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file was auto-generated via go generate.
+// To see how this file is generated, please refer to "scripts/update_version.go" file.
+// DO NOT UPDATE MANUALLY
+
+package main
+
+// version contains the current version number of madb tool to be shown to the user.
+// By default, the string "develop" will be used to tell that the current binary is a development
+// version, for example when the user gets this tool with 'go get' command.
+// This value is intended to be overwritten by the command line argument of 'go build', when
+// releasing an official version. See "scripts/release.go" for more details.
+var version = "{{.VersionString}}-develop"
+`
+)
+
+const (
+	versionFile      = "MADB_VERSION"
+	versionGoSrcFile = "version.go"
+)
+
+func main() {
+	if err := updateVersion(); err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to update the version number: %v", err)
+		os.Exit(1)
+	}
+}
+
+func updateVersion() error {
+	// Read the version string from the file MADB_VERSION.
+	versionString, err := readFile(versionFile)
+	if err != nil {
+		return err
+	}
+	versionString = strings.TrimSpace(versionString)
+
+	// Load the template.
+	t, err := template.New("version").Parse(tmpl)
+	if err != nil {
+		return err
+	}
+
+	// Create the destination file.
+	destFile, err := os.Create(versionGoSrcFile)
+	if err != nil {
+		return err
+	}
+	defer destFile.Close()
+
+	// Define the data to be used within the template.
+	data := map[string]string{"VersionString": versionString}
+
+	// Execute the template with the above data.
+	if err := t.Execute(destFile, data); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func readFile(filename string) (string, error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	bytes, err := ioutil.ReadAll(f)
+	return string(bytes), err
+}
diff --git a/version.go b/version.go
new file mode 100644
index 0000000..dbb7357
--- /dev/null
+++ b/version.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file was auto-generated via go generate.
+// To see how this file is generated, please refer to "scripts/update_version.go" file.
+// DO NOT UPDATE MANUALLY
+
+package main
+
+// version contains the current version number of madb tool to be shown to the user.
+// By default, the string "develop" will be used to tell that the current binary is a development
+// version, for example when the user gets this tool with 'go get' command.
+// This value is intended to be overwritten by the command line argument of 'go build', when
+// releasing an official version. See "scripts/release.go" for more details.
+var version = "v1.0.0-develop"
diff --git a/version_cmd.go b/version_cmd.go
new file mode 100644
index 0000000..5bfcea8
--- /dev/null
+++ b/version_cmd.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+
+	"v.io/x/lib/cmdline"
+)
+
+var cmdMadbVersion = &cmdline.Command{
+	Runner: cmdline.RunnerFunc(runCmdMadbVersion),
+	Name:   "version",
+	Short:  "Print the madb version number",
+	Long: `
+Prints the madb version number to the console.
+
+If this version of madb binary is an official release, this command will show the version number.
+Otherwise, the version will be in the form of "<version>-develop", where the version indicates the
+most recent stable release version prior to this version of madb binary.`,
+}
+
+func runCmdMadbVersion(env *cmdline.Env, args []string) error {
+	fmt.Println("madb version:", version)
+	return nil
+}