When updating projects, set origin to the remote in the manifest.

Currently, changing the remote in the manifest after a project has been
created has no effect.  This CL will set the origin to to the manifest
remote.  It will error if the project does not have a remote listed in
the manifest.

It also renames RepoName to RemoteUrl, to better match its
functionality.

Change-Id: Ia114b14eb2c10861205924aa02dd2b088cec15fb
diff --git a/gitutil/git.go b/gitutil/git.go
index c97b418..d41b9a6 100644
--- a/gitutil/git.go
+++ b/gitutil/git.go
@@ -506,23 +506,24 @@
 	return g.run(args...)
 }
 
-// RemoveUntrackedFiles removes untracked files and directories.
-func (g *Git) RemoveUntrackedFiles() error {
-	return g.run("clean", "-d", "-f")
-}
-
-// RepoName gets the name of the current repository.
-func (g *Git) RepoName() (string, error) {
-	out, err := g.runOutputWithOpts(g.disableDryRun(), "config", "--get", "remote.origin.url")
+// RemoteUrl gets the url of the remote with the given name.
+func (g *Git) RemoteUrl(name string) (string, error) {
+	configKey := fmt.Sprintf("remote.%s.url", name)
+	out, err := g.runOutputWithOpts(g.disableDryRun(), "config", "--get", configKey)
 	if err != nil {
 		return "", err
 	}
 	if got, want := len(out), 1; got != want {
-		return "", fmt.Errorf("unexpected length of %v: got %v, want %v", out, got, want)
+		return "", fmt.Errorf("RemoteUrl: unexpected length of remotes %v: got %v, want %v", out, got, want)
 	}
 	return out[0], nil
 }
 
+// RemoveUntrackedFiles removes untracked files and directories.
+func (g *Git) RemoveUntrackedFiles() error {
+	return g.run("clean", "-d", "-f")
+}
+
 // Reset resets the current branch to the target, discarding any
 // uncommitted changes.
 func (g *Git) Reset(target string, opts ...ResetOpt) error {
@@ -538,6 +539,11 @@
 	return g.run(args...)
 }
 
+// SetRemoteUrl sets the url of the remote with given name to the given url.
+func (g *Git) SetRemoteUrl(name, url string) error {
+	return g.run("remote", "set-url", name, url)
+}
+
 // Stash attempts to stash any unsaved changes. It returns true if
 // anything was actually stashed, otherwise false. An error is
 // returned if the stash command fails.
diff --git a/project/project.go b/project/project.go
index 8af2d12..ade8eb8 100644
--- a/project/project.go
+++ b/project/project.go
@@ -447,7 +447,7 @@
 					return nil, err
 				}
 
-				// Fetch the latest from remote.
+				// Fetch the latest from origin.
 				if err := ctx.Git().FetchRefspec("origin", updateOp.project.RemoteBranch); err != nil {
 					return nil, err
 				}
@@ -485,6 +485,20 @@
 	return p, t, e
 }
 
+// getManifestRemote returns the remote url of the origin from the manifest
+// repo.
+// TODO(nlacasse,toddw): Once the manifest project is specified in the
+// manifest, we should get the remote directly from the manifest, and not from
+// the filesystem.
+func getManifestRemote(ctx *tool.Context, manifestPath string) (string, error) {
+	var remote string
+	return remote, ctx.NewSeq().Pushd(manifestPath).Call(
+		func() (e error) {
+			remote, e = ctx.Git().RemoteUrl("origin")
+			return
+		}, "get manifest origin").Done()
+}
+
 // readManifest implements the ReadManifest logic and provides an
 // optional flag that can be used to fetch the latest manifest updates
 // from the manifest repository.
@@ -496,9 +510,14 @@
 		if err != nil {
 			return nil, nil, nil, nil, err
 		}
+		manifestRemote, err := getManifestRemote(ctx, manifestPath)
+		if err != nil {
+			return nil, nil, nil, nil, err
+		}
 		project := Project{
 			Path:         manifestPath,
 			Protocol:     "git",
+			Remote:       manifestRemote,
 			Revision:     "HEAD",
 			RemoteBranch: "master",
 		}
@@ -940,6 +959,12 @@
 	fn := func() error {
 		switch project.Protocol {
 		case "git":
+			if project.Remote == "" {
+				return fmt.Errorf("project %v does not have a remote", project.Name)
+			}
+			if err := ctx.Git().SetRemoteUrl("origin", project.Remote); err != nil {
+				return err
+			}
 			if err := ctx.Git().Fetch("origin"); err != nil {
 				return err
 			}