jiri: Maintain "latest" and "second-latest" symlinks in update-history.

And make devtools/postsubmit read the "second-latest" symlink, rather
than try to calculate the second-latest snapshot the hard way.

MultiPart: 1/2
Change-Id: I177c18bbd3ebf0a7546b74d7fc6a5760387ac175
diff --git a/jiri/.api b/jiri/.api
index bbf12c1..f71ff54 100644
--- a/jiri/.api
+++ b/jiri/.api
@@ -15,6 +15,7 @@
 pkg jiri, method (*X) RootMetaDir() string
 pkg jiri, method (*X) UpdateHistoryDir() string
 pkg jiri, method (*X) UpdateHistoryLatestLink() string
+pkg jiri, method (*X) UpdateHistorySecondLatestLink() string
 pkg jiri, method (*X) UsageErrorf(string, ...interface{}) error
 pkg jiri, method (*X) UsingOldManifests() bool
 pkg jiri, method (RelPath) Abs(*X) string
diff --git a/jiri/x.go b/jiri/x.go
index c67a452..09f77f0 100644
--- a/jiri/x.go
+++ b/jiri/x.go
@@ -142,6 +142,12 @@
 	return filepath.Join(x.UpdateHistoryDir(), "latest")
 }
 
+// UpdateHistorySecondLatestLink returns the path to a symlink that points to
+// the second latest update in the update history directory.
+func (x *X) UpdateHistorySecondLatestLink() string {
+	return filepath.Join(x.UpdateHistoryDir(), "second-latest")
+}
+
 // ResolveManifestPath resolves the given manifest name to an absolute path in
 // the local filesystem.
 //
diff --git a/update.go b/update.go
index aaccb51..36a9877 100644
--- a/update.go
+++ b/update.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"os"
 	"path/filepath"
 	"time"
 
@@ -44,12 +45,13 @@
 }
 
 func runUpdate(jirix *jiri.X, _ []string) error {
+	seq := jirix.NewSeq()
 	// Create the $JIRI_ROOT/.jiri_root directory if it doesn't already exist.
 	//
 	// TODO(toddw): Remove this logic after the transition to .jiri_root is done.
 	// The bootstrapping logic should create this directory, and jiri should fail
 	// if the directory doesn't exist.
-	if err := jirix.NewSeq().MkdirAll(jirix.RootMetaDir(), 0755).Done(); err != nil {
+	if err := seq.MkdirAll(jirix.RootMetaDir(), 0755).Done(); err != nil {
 		return err
 	}
 
@@ -65,16 +67,34 @@
 	if err := project.CreateSnapshot(jirix, snapshotFile); err != nil {
 		return err
 	}
-	// Point the "latest" update history symlink to the new snapshot file.  Try to
-	// keep the symlink relative, to make it easy to move or copy the entire
-	// update_history directory.
-	link, latest := jirix.UpdateHistoryLatestLink(), snapshotFile
-	if rel, err := filepath.Rel(filepath.Dir(link), latest); err == nil {
-		latest = rel
-	}
-	if err := jirix.NewSeq().RemoveAll(link).Symlink(latest, link).Done(); err != nil {
+
+	latestLink, secondLatestLink := jirix.UpdateHistoryLatestLink(), jirix.UpdateHistorySecondLatestLink()
+
+	// If the "latest" symlink exists, point the "second-latest" symlink to its value.
+	latestLinkExists, err := seq.IsFile(latestLink)
+	if err != nil {
 		return err
 	}
+	if latestLinkExists {
+		latestFile, err := os.Readlink(latestLink)
+		if err != nil {
+			return err
+		}
+		if err := seq.RemoveAll(secondLatestLink).Symlink(latestFile, secondLatestLink).Done(); err != nil {
+			return err
+		}
+	}
+
+	// Point the "latest" update history symlink to the new snapshot file.  Try
+	// to keep the symlink relative, to make it easy to move or copy the entire
+	// update_history directory.
+	if rel, err := filepath.Rel(filepath.Dir(latestLink), snapshotFile); err == nil {
+		snapshotFile = rel
+	}
+	if err := seq.RemoveAll(latestLink).Symlink(snapshotFile, latestLink).Done(); err != nil {
+		return err
+	}
+
 	// Only attempt the bin dir transition after the update has succeeded, to
 	// avoid messy partial states.
 	return project.TransitionBinDir(jirix)