jiri: Replace manifest Labels with SnapshotPath.

The term "label" used to refer to two different but related things:
* The label used to create a snapshot (e.g. "rc" or "go-stable"),
  which is only used to determine the location of the snapshot file.
* The filename of the snapshot being checked out
  (e.g. "snapshot/labels/rc/2016-02-10.04\:18"), which got recorded in
  as the "label" attribute in the JIRI_ROOT/.current_manifest file.

Ignoring this confustion for a second, the label attribute in manifests
isn't as useful in the new jiri world, sinse manifest often import other
manifest, which may themselves have labels.

This CL preserves the first usage of "labels", but replaces the second
usage with "snapshotpath", which is a new attribute only set on Snapshot
manifests (which are required to not have imports).

The snapshotpath is analagous to the second usage of "label" above.  The
snapshot path is set when running "jiri snapshot checkout".

This CL also re-enables the vanadium-release manifest check that was
disabled in v.io/c/19778, replacing "label" with "snapshotpath".

MultiPart: 1/2

Change-Id: Ia15c247526b54f86cd2e0c335947f24dc7ee5d42
diff --git a/project/.api b/project/.api
index aaa67a5..28a5de7 100644
--- a/project/.api
+++ b/project/.api
@@ -4,7 +4,7 @@
 pkg project, func BuildTools(*jiri.X, Projects, Tools, string) error
 pkg project, func CheckoutSnapshot(*jiri.X, string, bool) error
 pkg project, func CleanupProjects(*jiri.X, Projects, bool) error
-pkg project, func CreateSnapshot(*jiri.X, string, string) error
+pkg project, func CreateSnapshot(*jiri.X, string) error
 pkg project, func CurrentManifest(*jiri.X) (*Manifest, error)
 pkg project, func CurrentProjectKey(*jiri.X) (ProjectKey, error)
 pkg project, func DataDirPath(*jiri.X, string) (string, error)
@@ -53,9 +53,9 @@
 pkg project, type LocalImport struct, XMLName struct{}
 pkg project, type Manifest struct
 pkg project, type Manifest struct, Imports []Import
-pkg project, type Manifest struct, Label string
 pkg project, type Manifest struct, LocalImports []LocalImport
 pkg project, type Manifest struct, Projects []Project
+pkg project, type Manifest struct, SnapshotPath string
 pkg project, type Manifest struct, Tools []Tool
 pkg project, type Manifest struct, XMLName struct{}
 pkg project, type Project struct
diff --git a/project/project.go b/project/project.go
index d2be1ce..742d3b7 100644
--- a/project/project.go
+++ b/project/project.go
@@ -44,10 +44,12 @@
 type Manifest struct {
 	Imports      []Import      `xml:"imports>import"`
 	LocalImports []LocalImport `xml:"imports>localimport"`
-	Label        string        `xml:"label,attr,omitempty"`
 	Projects     []Project     `xml:"projects>project"`
 	Tools        []Tool        `xml:"tools>tool"`
-	XMLName      struct{}      `xml:"manifest"`
+	// SnapshotPath is the relative path to the snapshot file from JIRI_ROOT.
+	// It is only set when running "jiri snapshot checkout <path>".
+	SnapshotPath string   `xml:"snapshotpath,attr,omitempty"`
+	XMLName      struct{} `xml:"manifest"`
 }
 
 // ManifestFromBytes returns a manifest parsed from data, with defaults filled
@@ -97,7 +99,7 @@
 // deepCopy returns a deep copy of Manifest.
 func (m *Manifest) deepCopy() *Manifest {
 	x := new(Manifest)
-	x.Label = m.Label
+	x.SnapshotPath = m.SnapshotPath
 	x.Imports = append([]Import(nil), m.Imports...)
 	x.LocalImports = append([]LocalImport(nil), m.LocalImports...)
 	x.Projects = append([]Project(nil), m.Projects...)
@@ -476,6 +478,15 @@
 // Projects maps ProjectKeys to Projects.
 type Projects map[ProjectKey]Project
 
+// toSlice returns a slice of Projects in the Projects map.
+func (ps Projects) toSlice() []Project {
+	var pSlice []Project
+	for _, p := range ps {
+		pSlice = append(pSlice, p)
+	}
+	return pSlice
+}
+
 // Find returns all projects in Projects with the given key or name.
 func (ps Projects) Find(keyOrName string) Projects {
 	projects := Projects{}
@@ -512,6 +523,15 @@
 // Tools maps jiri tool names, to their detailed description.
 type Tools map[string]Tool
 
+// toSlice returns a slice of Tools in the Tools map.
+func (ts Tools) toSlice() []Tool {
+	var tSlice []Tool
+	for _, t := range ts {
+		tSlice = append(tSlice, t)
+	}
+	return tSlice
+}
+
 // Tool represents a jiri tool.
 type Tool struct {
 	// Data is a relative path to a directory for storing tool data
@@ -572,11 +592,11 @@
 
 // CreateSnapshot creates a manifest that encodes the current state of master
 // branches of all projects and writes this snapshot out to the given file.
-func CreateSnapshot(jirix *jiri.X, path, label string) error {
+func CreateSnapshot(jirix *jiri.X, path string) error {
 	jirix.TimerPush("create snapshot")
 	defer jirix.TimerPop()
 
-	manifest := Manifest{Label: label}
+	manifest := Manifest{}
 
 	// Add all local projects to manifest.
 	localProjects, err := LocalProjects(jirix, FullScan)
@@ -615,7 +635,7 @@
 
 // CheckoutSnapshot updates project state to the state specified in the given
 // snapshot file.  Note that the snapshot file must not contain remote imports.
-func CheckoutSnapshot(jirix *jiri.X, manifest string, gc bool) error {
+func CheckoutSnapshot(jirix *jiri.X, snapshot string, gc bool) error {
 	// Find all local projects.
 	scanMode := FastScan
 	if gc {
@@ -625,14 +645,35 @@
 	if err != nil {
 		return err
 	}
-	remoteProjects, remoteTools, err := loadManifestFile(jirix, manifest, nil)
+	remoteProjects, remoteTools, err := loadManifestFile(jirix, snapshot, nil)
 	if err != nil {
 		return err
 	}
 	if err := updateTo(jirix, localProjects, remoteProjects, remoteTools, gc); err != nil {
 		return err
 	}
-	return WriteUpdateHistorySnapshot(jirix)
+	if err := WriteUpdateHistorySnapshot(jirix); err != nil {
+		return err
+	}
+
+	// Get a clean, symlink-free, relative path to the snapshot.
+	snapshotPath := filepath.Clean(snapshot)
+	evaledSnapshotPath, err := filepath.EvalSymlinks(snapshotPath)
+	if err != nil {
+		evaledSnapshotPath = snapshotPath
+
+	}
+	relSnapshotPath, err := filepath.Rel(jirix.Root, evaledSnapshotPath)
+	if err != nil {
+		relSnapshotPath = evaledSnapshotPath
+	}
+	// Write current manifest, including the SnapshotPath.
+	manifest := &Manifest{
+		SnapshotPath: relSnapshotPath,
+		Projects:     remoteProjects.toSlice(),
+		Tools:        remoteTools.toSlice(),
+	}
+	return writeCurrentManifest(jirix, manifest)
 }
 
 // CurrentManifest returns a manifest that identifies the result of
@@ -995,7 +1036,7 @@
 func WriteUpdateHistorySnapshot(jirix *jiri.X) error {
 	seq := jirix.NewSeq()
 	snapshotFile := filepath.Join(jirix.UpdateHistoryDir(), time.Now().Format(time.RFC3339))
-	if err := CreateSnapshot(jirix, snapshotFile, "update-history"); err != nil {
+	if err := CreateSnapshot(jirix, snapshotFile); err != nil {
 		return err
 	}
 
@@ -1756,7 +1797,7 @@
 		}
 	}
 	failed := false
-	manifest := &Manifest{Label: jirix.Manifest()}
+	manifest := &Manifest{}
 	s := jirix.NewSeq()
 	for _, op := range ops {
 		updateFn := func() error { return op.Run(jirix, manifest) }
diff --git a/project/project_test.go b/project/project_test.go
index f19cc97..a060e36 100644
--- a/project/project_test.go
+++ b/project/project_test.go
@@ -913,7 +913,6 @@
 		},
 		{
 			project.Manifest{
-				Label: "label",
 				Imports: []project.Import{
 					{
 						Manifest:     "manifest1",
@@ -965,7 +964,7 @@
 					},
 				},
 			},
-			`<manifest label="label">
+			`<manifest>
   <imports>
     <import manifest="manifest1" name="remoteimport1" remote="remote1"/>
     <import manifest="manifest2" name="remoteimport2" remote="remote2" remotebranch="branch2"/>
diff --git a/snapshot.go b/snapshot.go
index 78df15c..de89012 100644
--- a/snapshot.go
+++ b/snapshot.go
@@ -153,7 +153,7 @@
 func createSnapshot(jirix *jiri.X, snapshotDir, snapshotFile, label string) error {
 	// Create a snapshot that encodes the current state of master
 	// branches for all local projects.
-	if err := project.CreateSnapshot(jirix, snapshotFile, label); err != nil {
+	if err := project.CreateSnapshot(jirix, snapshotFile); err != nil {
 		return err
 	}