TBR: jiri: Copy scripts/jiri to JIRI_ROOT/.jiri_root/scripts/jiri when updating

It should be rare that we need to update the jiri script, but it
happens.  See v.io/c/20086

When we do update the jiri script, it should be installed in
JIRI_ROOT/.jiri_root/scripts/jiri during the next "jiri update".  This
CL does that.

This is the same CL as v.io/c/20112, which was reverted, but with an
extra call to MkdirAll.

Change-Id: Ied4e254b31a56f7ed9a4e6a83a3aadf551315072
diff --git a/jiri/.api b/jiri/.api
index 8b75c99..2358c18 100644
--- a/jiri/.api
+++ b/jiri/.api
@@ -17,6 +17,7 @@
 pkg jiri, method (*X) ProfilesDBDir() string
 pkg jiri, method (*X) ResolveManifestPath(string) (string, error)
 pkg jiri, method (*X) RootMetaDir() string
+pkg jiri, method (*X) ScriptsDir() string
 pkg jiri, method (*X) UpdateHistoryDir() string
 pkg jiri, method (*X) UpdateHistoryLatestLink() string
 pkg jiri, method (*X) UpdateHistorySecondLatestLink() string
diff --git a/jiri/x.go b/jiri/x.go
index 09087b5..abe6b31 100644
--- a/jiri/x.go
+++ b/jiri/x.go
@@ -147,6 +147,11 @@
 	return filepath.Join(x.RootMetaDir(), "bin")
 }
 
+// ScriptsDir returns the path to the scripts directory.
+func (x *X) ScriptsDir() string {
+	return filepath.Join(x.RootMetaDir(), "scripts")
+}
+
 // UpdateHistoryDir returns the path to the update history directory.
 func (x *X) UpdateHistoryDir() string {
 	return filepath.Join(x.RootMetaDir(), "update_history")
diff --git a/project/project.go b/project/project.go
index 0a59d01..6d8c5d7 100644
--- a/project/project.go
+++ b/project/project.go
@@ -1000,7 +1000,17 @@
 		return err
 	}
 	// 3. Install the tools into $JIRI_ROOT/.jiri_root/bin.
-	return InstallTools(jirix, tmpToolsDir)
+	if err := InstallTools(jirix, tmpToolsDir); err != nil {
+		return err
+	}
+	// 4. If we have the jiri project, then update the jiri script in
+	// $JIRI_ROOT/.jiri_root/scripts.
+	jiriProject, err := remoteProjects.FindUnique(JiriProject)
+	if err != nil {
+		// jiri project not found.  This happens often in tests.  Ok to ignore.
+		return nil
+	}
+	return updateJiriScript(jirix, jiriProject)
 }
 
 // WriteUpdateHistorySnapshot creates a snapshot of the current state of all
@@ -1347,6 +1357,32 @@
 	return nil
 }
 
+// updateJiriScript copies the scripts/jiri script from the jiri repo to
+// JIRI_ROOT/.jiri_root/scripts/jiri.
+func updateJiriScript(jirix *jiri.X, jiriProject Project) error {
+	s := jirix.NewSeq()
+	updateFn := func() error {
+		return ApplyToLocalMaster(jirix, Projects{jiriProject.Key(): jiriProject}, func() error {
+			newJiriScriptPath := filepath.Join(jiriProject.Path, "scripts", "jiri")
+			newJiriScript, err := s.Open(newJiriScriptPath)
+			if err != nil {
+				return err
+			}
+			s.MkdirAll(jirix.ScriptsDir(), 0755)
+			jiriScriptOutPath := filepath.Join(jirix.ScriptsDir(), "jiri")
+			jiriScriptOut, err := s.Create(jiriScriptOutPath)
+			if err != nil {
+				return err
+			}
+			if _, err := s.Copy(jiriScriptOut, newJiriScript); err != nil {
+				return err
+			}
+			return nil
+		})
+	}
+	return jirix.NewSeq().Verbose(true).Call(updateFn, "update jiri script").Done()
+}
+
 // TransitionBinDir handles the transition from the old location
 // $JIRI_ROOT/devtools/bin to the new $JIRI_ROOT/.jiri_root/bin.  In
 // InstallTools above we've already installed the tools to the new location.