Add uniqueid command that generates uniqueid.IDs and replaces them
in files

Change-Id: I7bd9ee4875f991a2988c04edfcbb3ac890ad7f93
diff --git a/tools/uniqueid/doc.go b/tools/uniqueid/doc.go
new file mode 100644
index 0000000..5fdbcab
--- /dev/null
+++ b/tools/uniqueid/doc.go
@@ -0,0 +1,57 @@
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+The uniqueid tool generates unique ids. It also has an option of automatically
+substituting unique ids with placeholders in files.
+
+Usage:
+   uniqueid <command>
+
+The uniqueid commands are:
+   generate    Generates UniqueIds
+   inject      Injects UniqueIds into existing files
+   help        Display help for commands or topics
+Run "uniqueid help [command]" for command usage.
+
+Uniqueid Generate
+
+Generates unique ids and outputs them to standard out.
+
+Usage:
+   uniqueid generate
+
+Uniqueid Inject
+
+Injects UniqueIds into existing files. Strings of the form "$UNIQUEID$" will be
+replaced with generated ids.
+
+Usage:
+   uniqueid inject <filenames>
+
+<filenames> List of files to inject unique ids into
+
+Uniqueid Help
+
+Help with no args displays the usage of the parent command.
+
+Help with args displays the usage of the specified sub-command or help topic.
+
+"help ..." recursively displays help for all commands and topics.
+
+The output is formatted to a target width in runes.  The target width is
+determined by checking the environment variable CMDLINE_WIDTH, falling back on
+the terminal width from the OS, falling back on 80 chars.  By setting
+CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
+if x == 0 or is unset one of the fallbacks is used.
+
+Usage:
+   uniqueid help [flags] [command/topic ...]
+
+[command/topic ...] optionally identifies a specific sub-command or help topic.
+
+The uniqueid help flags are:
+ -style=text
+   The formatting style for help output, either "text" or "godoc".
+*/
+package main
diff --git a/tools/uniqueid/main.go b/tools/uniqueid/main.go
new file mode 100644
index 0000000..ce003d0
--- /dev/null
+++ b/tools/uniqueid/main.go
@@ -0,0 +1,110 @@
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $VANADIUM_ROOT/release/go/src/v.io/lib/cmdline/testdata/gendoc.go .
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"regexp"
+
+	"v.io/core/veyron2/uniqueid"
+	"v.io/lib/cmdline"
+)
+
+func main() {
+	os.Exit(cmdUniqueId.Main())
+}
+
+var cmdUniqueId = &cmdline.Command{
+	Name:  "uniqueid",
+	Short: "Generates UniqueIds.",
+	Long: `
+The uniqueid tool generates unique ids.
+It also has an option of automatically substituting unique ids with placeholders in files.
+`,
+	Children: []*cmdline.Command{cmdGenerate, cmdInject},
+	Topics:   []cmdline.Topic{},
+}
+
+var cmdGenerate = &cmdline.Command{
+	Run:   runGenerate,
+	Name:  "generate",
+	Short: "Generates UniqueIds",
+	Long: `
+Generates unique ids and outputs them to standard out.
+`,
+	ArgsName: "",
+	ArgsLong: "",
+}
+
+var cmdInject = &cmdline.Command{
+	Run:   runInject,
+	Name:  "inject",
+	Short: "Injects UniqueIds into existing files",
+	Long: `
+Injects UniqueIds into existing files.
+Strings of the form "$UNIQUEID$" will be replaced with generated ids.
+`,
+	ArgsName: "<filenames>",
+	ArgsLong: "<filenames> List of files to inject unique ids into",
+}
+
+// runGenerate implements the generate command which outputs generated ids to stdout.
+func runGenerate(command *cmdline.Command, args []string) error {
+	if len(args) > 0 {
+		return command.UsageErrorf("expected 0 args, got %d", len(args))
+	}
+	id, err := uniqueid.Random()
+	if err != nil {
+		return err
+	}
+	fmt.Printf("%#v", id)
+	return nil
+}
+
+// runInject implements the inject command which replaces $UNIQUEID$ strings with generated ids.
+func runInject(command *cmdline.Command, args []string) error {
+	if len(args) == 0 {
+		return command.UsageErrorf("expected at least one file arg, got 0")
+	}
+	for _, arg := range args {
+		if err := injectIntoFile(arg); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// injectIntoFile replaces $UNIQUEID$ strings when they exist in the specified file.
+func injectIntoFile(filename string) error {
+	inbytes, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return err
+	}
+
+	// Replace $UNIQUEID$ with generated ids.
+	re, err := regexp.Compile("[$]UNIQUEID")
+	if err != nil {
+		return err
+	}
+	replaced := re.ReplaceAllFunc(inbytes, func(match []byte) []byte {
+		id, randErr := uniqueid.Random()
+		if randErr != nil {
+			err = randErr
+		}
+		return []byte(fmt.Sprintf("%#v", id))
+	})
+	if err != nil {
+		return err
+	}
+
+	// If the file with injections is different, write it to disk.
+	if !bytes.Equal(inbytes, replaced) {
+		fmt.Printf("Updated: %s\n", filename)
+		return ioutil.WriteFile(filename, replaced, 0)
+	}
+	return nil
+}