ref: Begin consolidating environment variables into a single package.

This commit starts addressing veyron/release-issues#1367.
Specifically, the plan is to:

(1) Have all the environment variables used by disparate parts of
the reference implementation be in a single "envvar" package at the
top-level. (Environment variables private to a particular component,
for example the v23test framework or the device manager will not
be moved to this top-level package).

(2) Name all environment variables consistently: i.e., with a V23_
prefix.

This particular commit takes care of:
NAMESPACE_ROOT* --> V23_NAMESPACE*
VEYRON_CREDENTIALS --> V23_CREDENTIALS
VANADIUM_I18N_CATALOGUE --> V23_I18N_CATALOGUE

Support for the old environment variables has been left where it was
deemed to be necessary for a smooth rollout (where one process might
start another process and one of them will be without this change).
This will be removed once veyron/release-issues#1367 is completely
resolved.

MultiPart: 1/6

Change-Id: I72d6fc4114c83d3ee33cb8a8b19ec4c05ac8cb01
diff --git a/envvar/envvar.go b/envvar/envvar.go
new file mode 100644
index 0000000..e53c3ba
--- /dev/null
+++ b/envvar/envvar.go
@@ -0,0 +1,106 @@
+// Copyright 2015 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 envvar defines accessors for the environment variables used by the reference v23 implementation.
+package envvar
+
+import (
+	"os"
+	"strings"
+)
+
+const (
+	// Credentials points to a directory containing all the credentials of
+	// a principal (the blessing store, the blessing roots, possibly the
+	// private key etc.).
+	//
+	// Typically only one of Credentials or AgentEndpoint will be set
+	// in a process. If both are set, then Credentials takes preference.
+	//
+	// See v.io/x/ref/security.CreatePersistentPrincipal.
+	Credentials = "V23_CREDENTIALS"
+
+	// NamespacePrefix is the prefix of all environment variables that define
+	// a namespace root.
+	NamespacePrefix = "V23_NAMESPACE"
+
+	// I18nCatalogueFiles points to a comma-separated list of i18n
+	// catalogue files to be loaded at startup.
+	I18nCatalogueFiles = "V23_I18N_CATALOGUE"
+)
+
+// NamespaceRoots returns the set of namespace roots to be used by the process,
+// as specified by environment variables.
+//
+// It returns both a map of environment variable name to value and the list of
+// values.
+func NamespaceRoots() (map[string]string, []string) {
+	m := make(map[string]string)
+	var l []string
+	for _, ev := range os.Environ() {
+		p := strings.SplitN(ev, "=", 2)
+		if len(p) != 2 {
+			continue
+		}
+		k, v := p[0], p[1]
+		if strings.HasPrefix(k, NamespacePrefix) && len(v) > 0 {
+			l = append(l, v)
+			m[k] = v
+		} else if strings.HasPrefix(k, "NAMESPACE_ROOT") && len(v) > 0 {
+			// TODO(ashankar): Remove this once the transition to
+			// the new enviornment variables is complete.
+			l = append(l, v)
+			m[k] = v
+		}
+	}
+	return m, l
+}
+
+// ClearCredentials unsets all environment variables that are used by
+// the Runtime to intialize the principal.
+func ClearCredentials() error {
+	for _, v := range []string{
+		Credentials,
+		// Old environment variables, remove when
+		// https://github.com/veyron/release-issues/issues/1367
+		// is closed.
+		"VEYRON_CREDENTIALS",
+		"VEYRON_AGENT_FD",
+	} {
+		if err := os.Unsetenv(v); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Helper function to ease the transition from VEYRON_CREDENTIALS to
+// V23_CREDENTIALS.  Remove before release (and after updating all binaries so
+// that they respect V23_CREDENTIALS).
+func DoNotUse_GetCredentials() string {
+	if dir := os.Getenv(Credentials); len(dir) > 0 {
+		return dir
+	}
+	return os.Getenv("VEYRON_CREDENTIALS")
+}
+
+// Helper function to ease the transition from NAMESPACE_ROOT to V23_NAMESPACE.
+// Once all binaries have been updated to respect V23_NAMESPACE, this function
+// can be removed and calls replaced with:
+// othervars = append(othervars, NamespacePrefix+"="+root)
+func DoNotUse_AppendNamespaceRoot(root string, othervars []string) []string {
+	return append(othervars,
+		NamespacePrefix+"="+root,
+		"NAMESPACE_ROOT="+root)
+}
+
+// Helper function to ease the transition from VEYRON_CREDENTIALS to
+// V23_CREDENTIALS.  Once all binaries have been updated to respect
+// V23_CREDENTIALS, this function can be removed and calls replaced with:
+// othervars = append(othervars, Credentials + "="+value
+func DoNotUse_AppendCredentials(value string, othervars []string) []string {
+	return append(othervars,
+		Credentials+"="+value,
+		"VEYRON_CREDENTIALS="+value)
+}
diff --git a/envvar/envvar_test.go b/envvar/envvar_test.go
new file mode 100644
index 0000000..e0fa19c
--- /dev/null
+++ b/envvar/envvar_test.go
@@ -0,0 +1,57 @@
+// Copyright 2015 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 envvar
+
+import (
+	"os"
+	"reflect"
+	"testing"
+)
+
+// Set an environment variable and return a function to undo it.
+// Typical usage:
+//   defer setenv(t, "VAR", "VALUE")()
+func setenv(t *testing.T, name, value string) func() {
+	oldval := os.Getenv(name)
+	if err := os.Setenv(name, value); err != nil {
+		t.Fatalf("Failed to set %q to %q: %v", name, value, err)
+		return func() {}
+	}
+	return func() {
+		if err := os.Setenv(name, oldval); err != nil {
+			t.Fatalf("Failed to restore %q to %q: %v", name, oldval, err)
+		}
+	}
+}
+
+func TestNamespaceRoots(t *testing.T) {
+	defer setenv(t, NamespacePrefix, "NS1")()
+	defer setenv(t, NamespacePrefix+"_BLAH", "NS_BLAH")()
+
+	wantm := map[string]string{
+		"V23_NAMESPACE":      "NS1",
+		"V23_NAMESPACE_BLAH": "NS_BLAH",
+	}
+	wantl := []string{"NS1", "NS_BLAH"}
+
+	gotm, gotl := NamespaceRoots()
+	if !reflect.DeepEqual(wantm, gotm) {
+		t.Errorf("Got %v want %v", gotm, wantm)
+	}
+	if !reflect.DeepEqual(wantl, gotl) {
+		t.Errorf("Got %v want %v", gotl, wantl)
+	}
+}
+
+func TestClearCredentials(t *testing.T) {
+	defer setenv(t, Credentials, "FOO")()
+	if got, want := os.Getenv(Credentials), "FOO"; got != want {
+		t.Errorf("Got %q, want %q", got, want)
+	}
+	ClearCredentials()
+	if got := os.Getenv(Credentials); got != "" {
+		t.Errorf("Got %q, wanted empty string", got)
+	}
+}