Merge "jiri: Remove support for old-style manifests."
diff --git a/.api b/.api
index d02b8f3..3983236 100644
--- a/.api
+++ b/.api
@@ -16,14 +16,12 @@
 pkg jiri, method (*X) JiriManifestFile() string
 pkg jiri, method (*X) ProfilesDBDir() string
 pkg jiri, method (*X) ProfilesRootDir() 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
 pkg jiri, method (*X) UsageErrorf(string, ...interface{}) error
-pkg jiri, method (*X) UsingOldManifests() bool
 pkg jiri, method (RelPath) Abs(*X) string
 pkg jiri, method (RelPath) Join(...string) RelPath
 pkg jiri, method (RelPath) Symbolic() string
diff --git a/cmd/jiri/cmd.go b/cmd/jiri/cmd.go
index a5d8ab5..5363083 100644
--- a/cmd/jiri/cmd.go
+++ b/cmd/jiri/cmd.go
@@ -41,7 +41,6 @@
 		cmdRebuild,
 		cmdSnapshot,
 		cmdUpdate,
-		cmdUpgrade,
 		cmdWhich,
 	},
 	Topics: []cmdline.Topic{
diff --git a/cmd/jiri/doc.go b/cmd/jiri/doc.go
index 2b58edd..61a3e10 100644
--- a/cmd/jiri/doc.go
+++ b/cmd/jiri/doc.go
@@ -20,7 +20,6 @@
    rebuild      Rebuild all jiri tools
    snapshot     Manage project snapshots
    update       Update all jiri tools and projects
-   upgrade      Upgrade jiri to new-style manifests
    which        Show path to the jiri tool
    help         Display help for commands or topics
 
@@ -713,49 +712,6 @@
  -v=false
    Print verbose output.
 
-Jiri upgrade - Upgrade jiri to new-style manifests
-
-Upgrades jiri to use new-style manifests.
-
-The old (deprecated) behavior only allowed a single manifest repository, located
-in $JIRI_ROOT/.manifest.  The initial manifest file is located as follows:
-  1) Use -manifest flag, if non-empty.  If it's empty...
-  2) Use $JIRI_ROOT/.local_manifest file.  If it doesn't exist...
-  3) Use $JIRI_ROOT/.manifest/v2/default.
-
-The new behavior allows multiple manifest repositories, by allowing imports to
-specify project attributes describing the remote repository.  The -manifest flag
-is no longer allowed to be set; the initial manifest file is always located in
-$JIRI_ROOT/.jiri_manifest.  The .local_manifest file is ignored.
-
-During the transition phase, both old and new behaviors are supported.  The jiri
-tool uses the existence of the $JIRI_ROOT/.jiri_manifest file as the signal; if
-it exists we run the new behavior, otherwise we run the old behavior.
-
-The new behavior includes a "jiri import" command, which writes or updates the
-.jiri_manifest file.  The new bootstrap procedure runs "jiri import", and it is
-intended as a regular command to add imports to your jiri environment.
-
-This upgrade command eases the transition by writing an initial .jiri_manifest
-file for you.  If you have an existing .local_manifest file, its contents will
-be incorporated into the new .jiri_manifest file, and it will be renamed to
-.local_manifest.BACKUP.  The -revert flag deletes the .jiri_manifest file, and
-restores the .local_manifest file.
-
-Usage:
-   jiri upgrade [flags] <kind>
-
-<kind> specifies the kind of upgrade, one of "v23" or "fuchsia".
-
-The jiri upgrade flags are:
- -revert=false
-   Revert the upgrade by deleting the $JIRI_ROOT/.jiri_manifest file.
-
- -color=true
-   Use color to format output.
- -v=false
-   Print verbose output.
-
 Jiri which - Show path to the jiri tool
 
 Which behaves similarly to the unix commandline tool.  It is useful in
diff --git a/cmd/jiri/snapshot_test.go b/cmd/jiri/snapshot_test.go
index 151fb9b..78167a6 100644
--- a/cmd/jiri/snapshot_test.go
+++ b/cmd/jiri/snapshot_test.go
@@ -307,7 +307,7 @@
 	fake.EnableRemoteManifestPush()
 	defer fake.DisableRemoteManifestPush()
 
-	manifestDir := filepath.Join(fake.X.Root, ".manifest")
+	manifestDir := filepath.Join(fake.X.Root, "manifest")
 	snapshotDir := filepath.Join(manifestDir, "snapshot")
 	label := "test"
 
diff --git a/cmd/jiri/upgrade.go b/cmd/jiri/upgrade.go
deleted file mode 100644
index 08eb99a..0000000
--- a/cmd/jiri/upgrade.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// 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 main
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-
-	"v.io/jiri"
-	"v.io/jiri/project"
-	"v.io/jiri/runutil"
-	"v.io/x/lib/cmdline"
-)
-
-// TODO(toddw): Remove the upgrade command after the transition to new-style
-// manifests is complete.
-
-var flagUpgradeRevert bool
-
-func init() {
-	cmdUpgrade.Flags.BoolVar(&flagUpgradeRevert, "revert", false, `Revert the upgrade by deleting the $JIRI_ROOT/.jiri_manifest file.`)
-}
-
-var cmdUpgrade = &cmdline.Command{
-	Runner: jiri.RunnerFunc(runUpgrade),
-	Name:   "upgrade",
-	Short:  "Upgrade jiri to new-style manifests",
-	Long: `
-Upgrades jiri to use new-style manifests.
-
-The old (deprecated) behavior only allowed a single manifest repository, located
-in $JIRI_ROOT/.manifest.  The initial manifest file is located as follows:
-  1) Use -manifest flag, if non-empty.  If it's empty...
-  2) Use $JIRI_ROOT/.local_manifest file.  If it doesn't exist...
-  3) Use $JIRI_ROOT/.manifest/v2/default.
-
-The new behavior allows multiple manifest repositories, by allowing imports to
-specify project attributes describing the remote repository.  The -manifest flag
-is no longer allowed to be set; the initial manifest file is always located in
-$JIRI_ROOT/.jiri_manifest.  The .local_manifest file is ignored.
-
-During the transition phase, both old and new behaviors are supported.  The jiri
-tool uses the existence of the $JIRI_ROOT/.jiri_manifest file as the signal; if
-it exists we run the new behavior, otherwise we run the old behavior.
-
-The new behavior includes a "jiri import" command, which writes or updates the
-.jiri_manifest file.  The new bootstrap procedure runs "jiri import", and it is
-intended as a regular command to add imports to your jiri environment.
-
-This upgrade command eases the transition by writing an initial .jiri_manifest
-file for you.  If you have an existing .local_manifest file, its contents will
-be incorporated into the new .jiri_manifest file, and it will be renamed to
-.local_manifest.BACKUP.  The -revert flag deletes the .jiri_manifest file, and
-restores the .local_manifest file.
-`,
-	ArgsName: "<kind>",
-	ArgsLong: `
-<kind> specifies the kind of upgrade, one of "v23" or "fuchsia".
-`,
-}
-
-func runUpgrade(jirix *jiri.X, args []string) error {
-	localFile := filepath.Join(jirix.Root, ".local_manifest")
-	backupFile := localFile + ".BACKUP"
-	if flagUpgradeRevert {
-		// Restore .local_manifest.BACKUP if it exists.
-		switch _, err := jirix.NewSeq().Stat(backupFile); {
-		case err != nil && !runutil.IsNotExist(err):
-			return err
-		case err == nil:
-			if err := jirix.NewSeq().Rename(backupFile, localFile).Done(); err != nil {
-				return fmt.Errorf("couldn't restore %v to %v: %v", backupFile, localFile, err)
-			}
-		}
-		// Deleting the .jiri_manifest file reverts to the old behavior.
-		return jirix.NewSeq().Remove(jirix.JiriManifestFile()).Done()
-	}
-	if len(args) != 1 {
-		return jirix.UsageErrorf("must specify upgrade kind")
-	}
-	kind := args[0]
-	var argRemote, argName, argManifest string
-	switch kind {
-	case "v23":
-		argRemote = "https://vanadium.googlesource.com/manifest"
-		argName, argManifest = "manifest", "public"
-	case "fuchsia":
-		argRemote = "https://fuchsia.googlesource.com/fnl-start"
-		argName, argManifest = "fnl-start", "manifest/fuchsia"
-	default:
-		return jirix.UsageErrorf("unknown upgrade kind %q", kind)
-	}
-	// Initialize manifest from .local_manifest.
-	hasLocalFile := true
-	manifest, err := project.ManifestFromFile(jirix, localFile)
-	if err != nil {
-		if !runutil.IsNotExist(err) {
-			return err
-		}
-		hasLocalFile = false
-		manifest = &project.Manifest{}
-	}
-	oldImports := manifest.Imports
-	manifest.Imports = nil
-	for _, oldImport := range oldImports {
-		if oldImport.Remote != "" {
-			// This is a new-style remote import, carry it over directly.
-			manifest.Imports = append(manifest.Imports, oldImport)
-			continue
-		}
-		// This is an old-style import, convert it to the new style.
-		oldName := oldImport.Name
-		switch {
-		case kind == "v23" && oldName == "default":
-			oldName = "public"
-		case kind == "fuchsia" && oldName == "default":
-			oldName = "manifest/fuchsia"
-		}
-		manifest.Imports = append(manifest.Imports, project.Import{
-			Manifest: oldName,
-			Name:     argName,
-			Remote:   argRemote,
-		})
-	}
-	if len(manifest.Imports) == 0 {
-		manifest.Imports = append(manifest.Imports, project.Import{
-			Manifest: argManifest,
-			Name:     argName,
-			Remote:   argRemote,
-		})
-	}
-	// Write output to .jiri_manifest file.
-	outFile := jirix.JiriManifestFile()
-	if _, err := os.Stat(outFile); err == nil {
-		return fmt.Errorf("%v already exists", outFile)
-	}
-	if err := manifest.ToFile(jirix, outFile); err != nil {
-		return err
-	}
-	// Backup .local_manifest file, if it exists.
-	if hasLocalFile {
-		if err := jirix.NewSeq().Rename(localFile, backupFile).Done(); err != nil {
-			return fmt.Errorf("couldn't backup %v to %v: %v", localFile, backupFile, err)
-		}
-	}
-	return nil
-}
diff --git a/cmd/jiri/upgrade_test.go b/cmd/jiri/upgrade_test.go
deleted file mode 100644
index 16f4f72..0000000
--- a/cmd/jiri/upgrade_test.go
+++ /dev/null
@@ -1,310 +0,0 @@
-// 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 main
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"strings"
-	"testing"
-
-	"v.io/jiri"
-	"v.io/x/lib/gosh"
-)
-
-type upgradeTestCase struct {
-	Args        []string
-	Exist       bool
-	Local, Want string
-	Stderr      string
-}
-
-func TestUpgrade(t *testing.T) {
-	tests := []upgradeTestCase{
-		{
-			Stderr: `must specify upgrade kind`,
-		},
-		{
-			Args:   []string{"foo"},
-			Stderr: `unknown upgrade kind "foo"`,
-		},
-		// Test v23 upgrades.
-		{
-			Args:   []string{"v23"},
-			Exist:  true,
-			Stderr: `.jiri_manifest already exists`,
-		},
-		{
-			Args: []string{"v23"},
-			Want: `<manifest>
-  <imports>
-    <import manifest="public" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"v23"},
-			Local: `<manifest>
-  <imports>
-    <import name="default"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="public" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"v23"},
-			Local: `<manifest>
-  <imports>
-    <import name="private"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="private" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"v23"},
-			Local: `<manifest>
-  <imports>
-    <import name="private"/>
-    <import name="infrastructure"/>
-    <import name="default"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="private" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-    <import manifest="infrastructure" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-    <import manifest="public" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"v23"},
-			Local: `<manifest>
-  <imports>
-    <import name="default"/>
-    <import name="infrastructure"/>
-    <import name="private"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="public" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-    <import manifest="infrastructure" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-    <import manifest="private" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-  </imports>
-</manifest>
-`,
-		},
-		// Test fuchsia upgrades.
-		{
-			Args:   []string{"fuchsia"},
-			Exist:  true,
-			Stderr: `.jiri_manifest already exists`,
-		},
-		{
-			Args: []string{"fuchsia"},
-			Want: `<manifest>
-  <imports>
-    <import manifest="manifest/fuchsia" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"fuchsia"},
-			Local: `<manifest>
-  <imports>
-    <import name="default"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="manifest/fuchsia" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"fuchsia"},
-			Local: `<manifest>
-  <imports>
-    <import name="private"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="private" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"fuchsia"},
-			Local: `<manifest>
-  <imports>
-    <import name="private"/>
-    <import name="infrastructure"/>
-    <import name="default"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="private" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-    <import manifest="infrastructure" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-    <import manifest="manifest/fuchsia" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-  </imports>
-</manifest>
-`,
-		},
-		{
-			Args: []string{"fuchsia"},
-			Local: `<manifest>
-  <imports>
-    <import name="default"/>
-    <import name="infrastructure"/>
-    <import name="private"/>
-  </imports>
-</manifest>
-`,
-			Want: `<manifest>
-  <imports>
-    <import manifest="manifest/fuchsia" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-    <import manifest="infrastructure" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-    <import manifest="private" name="fnl-start" remote="https://fuchsia.googlesource.com/fnl-start"/>
-  </imports>
-</manifest>
-`,
-		},
-	}
-	sh := gosh.NewShell(t)
-	defer sh.Cleanup()
-	jiriTool := gosh.BuildGoPkg(sh, sh.MakeTempDir(), "v.io/jiri/cmd/jiri")
-	for _, test := range tests {
-		if err := testUpgrade(t, jiriTool, test); err != nil {
-			t.Errorf("%v: %v", test.Args, err)
-		}
-	}
-}
-
-func testUpgrade(t *testing.T, jiriTool string, test upgradeTestCase) error {
-	sh := gosh.NewShell(t)
-	sh.PropagateChildOutput = true
-	defer sh.Cleanup()
-	jiriRoot := sh.MakeTempDir()
-	sh.Pushd(jiriRoot)
-	// Set up an existing file or local_manifest, if they were specified
-	if test.Exist {
-		if err := ioutil.WriteFile(".jiri_manifest", []byte("<manifest/>"), 0644); err != nil {
-			return err
-		}
-	}
-	if test.Local != "" {
-		if err := ioutil.WriteFile(".local_manifest", []byte(test.Local), 0644); err != nil {
-			return err
-		}
-	}
-	// Run upgrade and check the error.
-	sh.Vars[jiri.RootEnv] = jiriRoot
-	cmd := sh.Cmd(jiriTool, append([]string{"upgrade"}, test.Args...)...)
-	if test.Stderr != "" {
-		cmd.ExitErrorIsOk = true
-	}
-	_, stderr := cmd.StdoutStderr()
-	if got, want := stderr, test.Stderr; !strings.Contains(got, want) || (got != "" && want == "") {
-		return fmt.Errorf("stderr got %q, want substr %q", got, want)
-	}
-	// Make sure the right file is generated.
-	if test.Want != "" {
-		data, err := ioutil.ReadFile(".jiri_manifest")
-		if err != nil {
-			return err
-		}
-		if got, want := string(data), test.Want; got != want {
-			return fmt.Errorf("GOT\n%s\nWANT\n%s", got, want)
-		}
-	}
-	// Make sure the .local_manifest file is backed up.
-	if test.Local != "" && test.Stderr == "" {
-		data, err := ioutil.ReadFile(".local_manifest.BACKUP")
-		if err != nil {
-			return fmt.Errorf("local manifest backup got error: %v", err)
-		}
-		if got, want := string(data), test.Local; got != want {
-			return fmt.Errorf("local manifest backup GOT\n%s\nWANT\n%s", got, want)
-		}
-	}
-	return nil
-}
-
-func TestUpgradeRevert(t *testing.T) {
-	sh := gosh.NewShell(t)
-	defer sh.Cleanup()
-	jiriRoot := sh.MakeTempDir()
-	sh.Pushd(jiriRoot)
-	jiriTool := gosh.BuildGoPkg(sh, sh.MakeTempDir(), "v.io/jiri/cmd/jiri")
-	localData := `<manifest/>`
-	jiriData := `<manifest>
-  <imports>
-    <import manifest="public" name="manifest" remote="https://vanadium.googlesource.com/manifest"/>
-  </imports>
-</manifest>
-`
-	// Set up an existing local_manifest.
-	if err := ioutil.WriteFile(".local_manifest", []byte(localData), 0644); err != nil {
-		t.Errorf("couldn't write local manifest: %v", err)
-	}
-	// Run a regular upgrade first, and make sure files are as expected.
-	sh.Vars[jiri.RootEnv] = jiriRoot
-	sh.Cmd(jiriTool, "upgrade", "v23").Run()
-	gotJiri, err := ioutil.ReadFile(".jiri_manifest")
-	if err != nil {
-		t.Errorf("couldn't read jiri manifest: %v", err)
-	}
-	if got, want := string(gotJiri), jiriData; got != want {
-		t.Errorf("jiri manifest GOT\n%s\nWANT\n%s", got, want)
-	}
-	gotBackup, err := ioutil.ReadFile(".local_manifest.BACKUP")
-	if err != nil {
-		t.Errorf("couldn't read local manifest backup: %v", err)
-	}
-	if got, want := string(gotBackup), localData; got != want {
-		t.Errorf("local manifest backup GOT\n%s\nWANT\n%s", got, want)
-	}
-	// Now run a revert, and make sure files are as expected.
-	sh.Cmd(jiriTool, "upgrade", "-revert").Run()
-	if _, err := os.Stat(".jiri_manifest"); !os.IsNotExist(err) {
-		t.Errorf(".jiri_manifest still exists after revert: %v", err)
-	}
-	if _, err := os.Stat(".local_manifest.BACKUP"); !os.IsNotExist(err) {
-		t.Errorf(".local_manifest.BACKUP still exists after revert: %v", err)
-	}
-	gotLocal, err := ioutil.ReadFile(".local_manifest")
-	if err != nil {
-		t.Errorf("couldn't read local manifest: %v", err)
-	}
-	if got, want := string(gotLocal), localData; got != want {
-		t.Errorf("local manifest GOT\n%s\nWANT\n%s", got, want)
-	}
-}
diff --git a/jiritest/.api b/jiritest/.api
index 5ba67b4..48b6fe4 100644
--- a/jiritest/.api
+++ b/jiritest/.api
@@ -5,10 +5,10 @@
 pkg jiritest, method (FakeJiriRoot) CreateRemoteProject(string) error
 pkg jiritest, method (FakeJiriRoot) DisableRemoteManifestPush() error
 pkg jiritest, method (FakeJiriRoot) EnableRemoteManifestPush() error
-pkg jiritest, method (FakeJiriRoot) ReadLocalManifest() (*project.Manifest, error)
+pkg jiritest, method (FakeJiriRoot) ReadJiriManifest() (*project.Manifest, error)
 pkg jiritest, method (FakeJiriRoot) ReadRemoteManifest() (*project.Manifest, error)
 pkg jiritest, method (FakeJiriRoot) UpdateUniverse(bool) error
-pkg jiritest, method (FakeJiriRoot) WriteLocalManifest(*project.Manifest) error
+pkg jiritest, method (FakeJiriRoot) WriteJiriManifest(*project.Manifest) error
 pkg jiritest, method (FakeJiriRoot) WriteRemoteManifest(*project.Manifest) error
 pkg jiritest, type FakeJiriRoot struct
 pkg jiritest, type FakeJiriRoot struct, Projects map[string]string
diff --git a/jiritest/fake.go b/jiritest/fake.go
index 155fc74..f0aa2e5 100644
--- a/jiritest/fake.go
+++ b/jiritest/fake.go
@@ -24,11 +24,10 @@
 }
 
 const (
-	defaultDataDir  = "data"
-	defaultManifest = "default"
-	manifestProject = ".manifest"
-	manifestVersion = "v2"
-	toolsProject    = "tools"
+	defaultDataDir      = "data"
+	manifestFileName    = "public"
+	manifestProjectName = "manifest"
+	manifestProjectPath = "manifest"
 )
 
 // NewFakeJiriRoot returns a new FakeJiriRoot and a cleanup closure.  The
@@ -48,40 +47,34 @@
 		t.Fatalf("TempDir() failed: %v", err)
 	}
 	fake.remote = remoteDir
-	if err := fake.CreateRemoteProject(manifestProject); err != nil {
+	if err := fake.CreateRemoteProject(manifestProjectPath); err != nil {
 		t.Fatal(err)
 	}
-	if err := fake.CreateRemoteProject(toolsProject); err != nil {
-		t.Fatal(err)
-	}
-
 	// Create a fake manifest.
-	manifestDir := filepath.Join(remoteDir, manifestProject, manifestVersion)
+	manifestDir := filepath.Join(remoteDir, manifestProjectPath)
 	if err := s.MkdirAll(manifestDir, os.FileMode(0700)).Done(); err != nil {
 		t.Fatal(err)
 	}
 	if err := fake.WriteRemoteManifest(&project.Manifest{}); err != nil {
 		t.Fatal(err)
 	}
-	if err := gitutil.New(jirix.NewSeq()).CloneRecursive(fake.Projects[manifestProject], filepath.Join(jirix.Root, manifestProject)); err != nil {
-		t.Fatal(err)
-	}
-
-	// Add the "tools" project and a fake "jiri" tool to the
-	// manifests. This is necessary to make sure that the commonly
-	// invoked DataDirPath() function, which uses the "jiri" tool
-	// configuration for its default, works.
+	// Add the "manifest" project to the manifest.
 	if err := fake.AddProject(project.Project{
-		Name:   toolsProject,
-		Path:   toolsProject,
-		Remote: fake.Projects[toolsProject],
+		Name:   manifestProjectName,
+		Path:   manifestProjectPath,
+		Remote: fake.Projects[manifestProjectName],
 	}); err != nil {
 		t.Fatal(err)
 	}
-	if err := fake.AddTool(project.Tool{
-		Name:    "jiri",
-		Data:    defaultDataDir,
-		Project: toolsProject,
+	// Create a .jiri_manifest file which imports the manifest created above.
+	if err := fake.WriteJiriManifest(&project.Manifest{
+		Imports: []project.Import{
+			project.Import{
+				Manifest: manifestFileName,
+				Name:     manifestProjectName,
+				Remote:   filepath.Join(fake.remote, manifestProjectPath),
+			},
+		},
 	}); err != nil {
 		t.Fatal(err)
 	}
@@ -140,7 +133,7 @@
 // DisableRemoteManifestPush disables pushes to the remote manifest
 // repository.
 func (fake FakeJiriRoot) DisableRemoteManifestPush() error {
-	dir := gitutil.RootDirOpt(filepath.Join(fake.remote, manifestProject))
+	dir := gitutil.RootDirOpt(filepath.Join(fake.remote, manifestProjectPath))
 	if err := gitutil.New(fake.X.NewSeq(), dir).CheckoutBranch("master"); err != nil {
 		return err
 	}
@@ -150,7 +143,7 @@
 // EnableRemoteManifestPush enables pushes to the remote manifest
 // repository.
 func (fake FakeJiriRoot) EnableRemoteManifestPush() error {
-	dir := gitutil.RootDirOpt(filepath.Join(fake.remote, manifestProject))
+	dir := gitutil.RootDirOpt(filepath.Join(fake.remote, manifestProjectPath))
 	if !gitutil.New(fake.X.NewSeq(), dir).BranchExists("non-master") {
 		if err := gitutil.New(fake.X.NewSeq(), dir).CreateBranch("non-master"); err != nil {
 			return err
@@ -178,23 +171,9 @@
 	return nil
 }
 
-func getManifest(jirix *jiri.X) string {
-	manifest := jirix.Manifest()
-	if manifest != "" {
-		return manifest
-	}
-	return defaultManifest
-}
-
-// ReadLocalManifest read a manifest from the local manifest project.
-func (fake FakeJiriRoot) ReadLocalManifest() (*project.Manifest, error) {
-	path := filepath.Join(fake.X.Root, manifestProject, manifestVersion, getManifest(fake.X))
-	return project.ManifestFromFile(fake.X, path)
-}
-
 // ReadRemoteManifest read a manifest from the remote manifest project.
 func (fake FakeJiriRoot) ReadRemoteManifest() (*project.Manifest, error) {
-	path := filepath.Join(fake.remote, manifestProject, manifestVersion, getManifest(fake.X))
+	path := filepath.Join(fake.remote, manifestProjectPath, manifestFileName)
 	return project.ManifestFromFile(fake.X, path)
 }
 
@@ -212,30 +191,33 @@
 	return nil
 }
 
-// WriteLocalManifest writes the given manifest to the local
-// manifest project.
-func (fake FakeJiriRoot) WriteLocalManifest(manifest *project.Manifest) error {
-	dir := filepath.Join(fake.X.Root, manifestProject)
-	path := filepath.Join(dir, manifestVersion, getManifest(fake.X))
-	return fake.writeManifest(manifest, dir, path)
+// ReadJiriManifest reads the .jiri_manifest manifest.
+func (fake FakeJiriRoot) ReadJiriManifest() (*project.Manifest, error) {
+	return project.ManifestFromFile(fake.X, fake.X.JiriManifestFile())
+}
+
+// WriteJiriManifest writes the given manifest to the .jiri_manifest file.
+func (fake FakeJiriRoot) WriteJiriManifest(manifest *project.Manifest) error {
+	return manifest.ToFile(fake.X, fake.X.JiriManifestFile())
 }
 
 // WriteRemoteManifest writes the given manifest to the remote
 // manifest project.
 func (fake FakeJiriRoot) WriteRemoteManifest(manifest *project.Manifest) error {
-	dir := filepath.Join(fake.remote, manifestProject)
-	path := filepath.Join(dir, manifestVersion, getManifest(fake.X))
+	dir := filepath.Join(fake.remote, manifestProjectPath)
+	path := filepath.Join(dir, manifestFileName)
 	return fake.writeManifest(manifest, dir, path)
 }
 
 func (fake FakeJiriRoot) writeManifest(manifest *project.Manifest, dir, path string) error {
+	git := gitutil.New(fake.X.NewSeq(), gitutil.RootDirOpt(dir))
 	if err := manifest.ToFile(fake.X, path); err != nil {
 		return err
 	}
-	if err := gitutil.New(fake.X.NewSeq(), gitutil.RootDirOpt(dir)).Add(path); err != nil {
+	if err := git.Add(path); err != nil {
 		return err
 	}
-	if err := gitutil.New(fake.X.NewSeq(), gitutil.RootDirOpt(dir)).Commit(); err != nil {
+	if err := git.Commit(); err != nil {
 		return err
 	}
 	return nil
diff --git a/project/project.go b/project/project.go
index 18c8cd1..5bc5c0a 100644
--- a/project/project.go
+++ b/project/project.go
@@ -220,13 +220,6 @@
 	Manifest string `xml:"manifest,attr,omitempty"`
 	// Name is the name of the remote manifest project, used to determine the
 	// project key.
-	//
-	// If Remote and Manifest are empty, it is the old-style name of the manifest
-	// to import, similar to localimport. This is deprecated behavior, and will be
-	// removed.
-	//
-	// TODO(toddw): Remove the old behavior when the transition to new-style
-	// manifests is complete.
 	Name string `xml:"name,attr,omitempty"`
 	// Protocol is the version control protocol used by the remote manifest
 	// project. If not set, "git" is used as the default.
@@ -243,47 +236,28 @@
 }
 
 func (i *Import) fillDefaults() error {
-	if i.Remote != "" {
-		if i.Protocol == "" {
-			i.Protocol = "git"
-		}
-		if i.RemoteBranch == "" {
-			i.RemoteBranch = "master"
-		}
+	if i.Protocol == "" {
+		i.Protocol = "git"
+	}
+	if i.RemoteBranch == "" {
+		i.RemoteBranch = "master"
 	}
 	return i.validate()
 }
 
 func (i *Import) unfillDefaults() error {
-	if i.Remote != "" {
-		if i.Protocol == "git" {
-			i.Protocol = ""
-		}
-		if i.RemoteBranch == "master" {
-			i.RemoteBranch = ""
-		}
+	if i.Protocol == "git" {
+		i.Protocol = ""
+	}
+	if i.RemoteBranch == "master" {
+		i.RemoteBranch = ""
 	}
 	return i.validate()
 }
 
 func (i *Import) validate() error {
-	// After our transition is done, the "import" element will always denote
-	// remote imports, and the "remote" and "manifest" attributes will be
-	// required.  During the transition we allow old-style local imports, which
-	// only set the "name" attribute.
-	//
-	// This is a bit tricky, since the "name" attribute is allowed in both old and
-	// new styles, but have different semantics.  We distinguish between old and
-	// new styles based on the existence of the "remote" attribute.
-	oldStyle := *i
-	oldStyle.Name = ""
-	switch {
-	case i.Name != "" && oldStyle == Import{}:
-		// Only "name" is set, this is the old-style.
-	case i.Remote != "" && i.Manifest != "":
-		// At least "remote" and "manifest" are set, this is the new-style.
-	default:
-		return fmt.Errorf("bad import: neither old style (only name is set) or new style (at least remote and manifest are set): %+v", *i)
+	if i.Manifest == "" || i.Remote == "" {
+		return fmt.Errorf("bad import: both manifest and remote must be specified")
 	}
 	return nil
 }
@@ -396,13 +370,6 @@
 	XMLName struct{} `xml:"project"`
 }
 
-var (
-	startUpperProjectBytes = []byte("<Project")
-	startLowerProjectBytes = []byte("<project")
-	endUpperProjectBytes   = []byte("</Project>")
-	endLowerProjectBytes   = []byte("</project>")
-)
-
 // ProjectFromFile returns a project parsed from the contents of filename,
 // with defaults filled in and all paths absolute.
 func ProjectFromFile(jirix *jiri.X, filename string) (*Project, error) {
@@ -411,16 +378,6 @@
 		return nil, err
 	}
 
-	// Previous versions of the jiri tool had a bug where the project start and
-	// end elements were in upper-case, since the XMLName field was missing.  That
-	// bug is now fixed, but the xml.Unmarshal call is case-sensitive, and will
-	// fail if it sees the upper-case version.  This hack rewrites the elements to
-	// the lower-case version.
-	//
-	// TODO(toddw): Remove when the transition to new manifests is complete.
-	data = bytes.Replace(data, startUpperProjectBytes, startLowerProjectBytes, -1)
-	data = bytes.Replace(data, endUpperProjectBytes, endLowerProjectBytes, -1)
-
 	p := new(Project)
 	if err := xml.Unmarshal(data, p); err != nil {
 		return nil, err
@@ -684,17 +641,11 @@
 	}
 
 	// Add all tools from the current manifest to the snapshot manifest.
-	var tools Tools
-	if jirix.UsingOldManifests() {
-		// TODO(nlacasse): Remove this logic when the transition to new manifests is done.
-		_, tools, err = LoadManifest(jirix)
-	} else {
-		// We can't just call LoadManifest here, since that determines the
-		// local projects using FastScan, but if we're calling CreateSnapshot
-		// during "jiri update" and we added some new projects, they won't be
-		// found anymore.
-		_, tools, err = loadManifestFile(jirix, jirix.JiriManifestFile(), localProjects)
-	}
+	// We can't just call LoadManifest here, since that determines the
+	// local projects using FastScan, but if we're calling CreateSnapshot
+	// during "jiri update" and we added some new projects, they won't be
+	// found anymore.
+	_, tools, err := loadManifestFile(jirix, jirix.JiriManifestFile(), localProjects)
 	if err != nil {
 		return err
 	}
@@ -921,10 +872,6 @@
 // resolving remote and local imports.  Returns the projects and tools specified
 // by the manifest.
 //
-// If the user is still using old-style manifests, it uses the old
-// ResolveManifestPath logic to determine the initial manifest file, since the
-// .jiri_manifest doesn't exist.
-//
 // WARNING: LoadManifest cannot be run multiple times in parallel!  It invokes
 // git operations which require a lock on the filesystem.  If you see errors
 // about ".git/index.lock exists", you are likely calling LoadManifest in
@@ -932,18 +879,8 @@
 func LoadManifest(jirix *jiri.X) (Projects, Tools, error) {
 	jirix.TimerPush("load manifest")
 	defer jirix.TimerPop()
-	var (
-		file          string
-		localProjects Projects
-		err           error
-	)
-	// TODO(toddw): Remove old manifest logic when the transition is complete.
-	if jirix.UsingOldManifests() {
-		file, err = jirix.ResolveManifestPath(jirix.Manifest())
-	} else {
-		file = jirix.JiriManifestFile()
-		localProjects, err = LocalProjects(jirix, FastScan)
-	}
+	file := jirix.JiriManifestFile()
+	localProjects, err := LocalProjects(jirix, FastScan)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -983,10 +920,6 @@
 func loadUpdatedManifest(jirix *jiri.X, localProjects Projects) (Projects, Tools, string, error) {
 	jirix.TimerPush("load updated manifest")
 	defer jirix.TimerPop()
-	if jirix.UsingOldManifests() {
-		projects, tools, err := loadUpdatedManifestDeprecated(jirix)
-		return projects, tools, "", err
-	}
 	ld := newManifestLoader(localProjects, true)
 	if err := ld.Load(jirix, "", jirix.JiriManifestFile(), ""); err != nil {
 		return nil, nil, ld.TmpDir, err
@@ -994,30 +927,6 @@
 	return ld.Projects, ld.Tools, ld.TmpDir, nil
 }
 
-// TODO(toddw): Remove this logic when the transition to new manifests is done.
-func loadUpdatedManifestDeprecated(jirix *jiri.X) (Projects, Tools, error) {
-	manifestPath := filepath.Join(jirix.Root, ".manifest")
-	manifestRemote, err := getManifestRemote(jirix, manifestPath)
-	if err != nil {
-		return nil, nil, err
-	}
-	project := Project{
-		Path:   manifestPath,
-		Remote: manifestRemote,
-	}
-	if err := project.fillDefaults(); err != nil {
-		return nil, nil, err
-	}
-	if err := syncProjectMaster(jirix, project); err != nil {
-		return nil, nil, err
-	}
-	file, err := jirix.ResolveManifestPath(jirix.Manifest())
-	if err != nil {
-		return nil, nil, err
-	}
-	return loadManifestFile(jirix, file, nil)
-}
-
 // UpdateUniverse updates all local projects and tools to match the remote
 // counterparts identified in the manifest. Optionally, the 'gc' flag can be
 // used to indicate that local projects that no longer exist remotely should be
@@ -1638,10 +1547,6 @@
 	}
 	// Process remote imports.
 	for _, remote := range m.Imports {
-		if remote.Remote == "" {
-			// Old-style named imports handled in loop below.
-			continue
-		}
 		nextRoot := filepath.Join(root, remote.Root)
 		key := remote.ProjectKey()
 		p, ok := ld.localProjects[key]
@@ -1668,9 +1573,9 @@
 			}
 			ld.localProjects[key] = p
 		}
-		// Reset the project to its specified branch and load the next file.
-		// Note that we call load() recursively, so multiple files may be
-		// loaded by resetAndLoad.
+		// Reset the project to its specified branch and load the next file.  Note
+		// that we call load() recursively, so multiple files may be loaded by
+		// resetAndLoad.
 		p.Revision = "HEAD"
 		p.RemoteBranch = remote.RemoteBranch
 		nextFile := filepath.Join(p.Path, remote.Manifest)
@@ -1678,22 +1583,6 @@
 			return err
 		}
 	}
-	// Process old-style named imports.
-	//
-	// TODO(toddw): Remove this logic when the manifest transition is done.
-	for _, named := range m.Imports {
-		if named.Remote != "" {
-			// New-style remote imports handled in loop above.
-			continue
-		}
-		nextFile, err := jirix.ResolveManifestPath(named.Name)
-		if err != nil {
-			return err
-		}
-		if err := ld.Load(jirix, root, nextFile, ""); err != nil {
-			return err
-		}
-	}
 	// Process local imports.
 	for _, local := range m.LocalImports {
 		// TODO(toddw): Add our invariant check that the file is in the same
diff --git a/project/project_test.go b/project/project_test.go
index fb12f3e..d8b44f1 100644
--- a/project/project_test.go
+++ b/project/project_test.go
@@ -19,43 +19,28 @@
 	"v.io/jiri/gitutil"
 	"v.io/jiri/jiritest"
 	"v.io/jiri/project"
-	"v.io/jiri/runutil"
 )
 
-func addRemote(t *testing.T, jirix *jiri.X, localProject, name, remoteProject string) {
-	cwd, err := os.Getwd()
-	if err != nil {
+func checkReadme(t *testing.T, jirix *jiri.X, p project.Project, message string) {
+	if _, err := jirix.NewSeq().Stat(p.Path); err != nil {
 		t.Fatalf("%v", err)
 	}
-	defer jirix.NewSeq().Chdir(cwd)
-	if err := jirix.NewSeq().Chdir(localProject).Done(); err != nil {
-		t.Fatalf("%v", err)
-	}
-	if err := gitutil.New(jirix.NewSeq()).AddRemote(name, remoteProject); err != nil {
-		t.Fatalf("%v", err)
-	}
-}
-
-func checkReadme(t *testing.T, jirix *jiri.X, project, message string) {
-	if _, err := jirix.NewSeq().Stat(project); err != nil {
-		t.Fatalf("%v", err)
-	}
-	readmeFile := filepath.Join(project, "README")
+	readmeFile := filepath.Join(p.Path, "README")
 	data, err := ioutil.ReadFile(readmeFile)
 	if err != nil {
 		t.Fatalf("ReadFile(%v) failed: %v", readmeFile, err)
 	}
 	if got, want := data, []byte(message); bytes.Compare(got, want) != 0 {
-		t.Fatalf("unexpected content %v:\ngot\n%s\nwant\n%s\n", project, got, want)
+		t.Fatalf("unexpected content in project %v:\ngot\n%s\nwant\n%s\n", p.Name, got, want)
 	}
 }
 
 // Checks that /.jiri/ is ignored in a local project checkout
-func checkGitIgnore(t *testing.T, jirix *jiri.X, project string) {
-	if _, err := jirix.NewSeq().Stat(project); err != nil {
+func checkMetadataIsIgnored(t *testing.T, jirix *jiri.X, p project.Project) {
+	if _, err := jirix.NewSeq().Stat(p.Path); err != nil {
 		t.Fatalf("%v", err)
 	}
-	gitInfoExcludeFile := filepath.Join(project, ".git", "info", "exclude")
+	gitInfoExcludeFile := filepath.Join(p.Path, ".git", "info", "exclude")
 	data, err := ioutil.ReadFile(gitInfoExcludeFile)
 	if err != nil {
 		t.Fatalf("ReadFile(%v) failed: %v", gitInfoExcludeFile, err)
@@ -66,30 +51,6 @@
 	}
 }
 
-func createLocalManifestCopy(t *testing.T, jirix *jiri.X, dir, manifestDir string) {
-	// Load the remote manifest.
-	m, err := project.ManifestFromFile(jirix, filepath.Join(manifestDir, "v2", "default"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Store the manifest locally.
-	if err := m.ToFile(jirix, filepath.Join(dir, ".local_manifest")); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func createLocalManifestStub(t *testing.T, jirix *jiri.X, dir string) {
-	// Create a manifest stub.
-	manifest := project.Manifest{}
-	imp := project.Import{}
-	imp.Name = "default"
-	manifest.Imports = append(manifest.Imports, imp)
-	// Store the manifest locally.
-	if err := manifest.ToFile(jirix, filepath.Join(dir, ".local_manifest")); err != nil {
-		t.Fatal(err)
-	}
-}
-
 func commitFile(t *testing.T, jirix *jiri.X, dir, file, msg string) {
 	cwd, err := os.Getwd()
 	if err != nil {
@@ -104,126 +65,8 @@
 	}
 }
 
-func createRemoteManifest(t *testing.T, jirix *jiri.X, dir string, remotes []string) {
-	manifestDir, perm := filepath.Join(dir, "v2"), os.FileMode(0755)
-	if err := jirix.NewSeq().MkdirAll(manifestDir, perm).Done(); err != nil {
-		t.Fatalf("%v", err)
-	}
-	manifest := project.Manifest{}
-	for i, remote := range remotes {
-		project := project.Project{
-			Name:     remote,
-			Path:     localProjectName(i),
-			Protocol: "git",
-			Remote:   remote,
-		}
-		manifest.Projects = append(manifest.Projects, project)
-	}
-	commitManifest(t, jirix, &manifest, dir)
-}
-
-func commitManifest(t *testing.T, jirix *jiri.X, manifest *project.Manifest, manifestDir string) {
-	manifestFile := filepath.Join(manifestDir, "v2", "default")
-	if err := manifest.ToFile(jirix, manifestFile); err != nil {
-		t.Fatal(err)
-	}
-	commitFile(t, jirix, manifestDir, manifestFile, "creating manifest")
-}
-
-func createProject(t *testing.T, jirix *jiri.X, manifestDir, name, remote, path string) {
-	m, err := project.ManifestFromFile(jirix, filepath.Join(manifestDir, "v2", "default"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	m.Projects = append(m.Projects, project.Project{Name: name, Remote: remote, Path: path})
-	commitManifest(t, jirix, m, manifestDir)
-}
-
-func deleteProject(t *testing.T, jirix *jiri.X, manifestDir, remote string) {
-	m, err := project.ManifestFromFile(jirix, filepath.Join(manifestDir, "v2", "default"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	deleteKey := project.MakeProjectKey(remote, remote)
-	var projects []project.Project
-	for _, p := range m.Projects {
-		if p.Key() != deleteKey {
-			projects = append(projects, p)
-		}
-	}
-	m.Projects = projects
-	commitManifest(t, jirix, m, manifestDir)
-}
-
-// Identify the current revision for a given project.
-func currentRevision(t *testing.T, jirix *jiri.X, name string) string {
-	cwd, err := os.Getwd()
-	if err != nil {
-		t.Fatalf("%v", err)
-	}
-	defer jirix.NewSeq().Chdir(cwd)
-	if err := jirix.NewSeq().Chdir(name).Done(); err != nil {
-		t.Fatalf("%v", err)
-	}
-	revision, err := gitutil.New(jirix.NewSeq()).CurrentRevision()
-	if err != nil {
-		t.Fatalf("%v", err)
-	}
-	return revision
-}
-
-// Fix the revision in the manifest file.
-func setRevisionForProject(t *testing.T, jirix *jiri.X, manifestDir, name, revision string) {
-	m, err := project.ManifestFromFile(jirix, filepath.Join(manifestDir, "v2", "default"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	updated := false
-	for i, p := range m.Projects {
-		if p.Name == name {
-			p.Revision = revision
-			m.Projects[i] = p
-			updated = true
-			break
-		}
-	}
-	if !updated {
-		t.Fatalf("failed to fix revision for project %v", name)
-	}
-	commitManifest(t, jirix, m, manifestDir)
-}
-
-func holdProjectBack(t *testing.T, jirix *jiri.X, manifestDir, name string) {
-	revision := currentRevision(t, jirix, name)
-	setRevisionForProject(t, jirix, manifestDir, name, revision)
-}
-
-func localProjectName(i int) string {
-	return "test-local-project-" + fmt.Sprintf("%d", i)
-}
-
-func moveProject(t *testing.T, jirix *jiri.X, manifestDir, name, dst string) {
-	m, err := project.ManifestFromFile(jirix, filepath.Join(manifestDir, "v2", "default"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	updated := false
-	for i, p := range m.Projects {
-		if p.Name == name {
-			p.Path = dst
-			m.Projects[i] = p
-			updated = true
-			break
-		}
-	}
-	if !updated {
-		t.Fatalf("failed to set path for project %v", name)
-	}
-	commitManifest(t, jirix, m, manifestDir)
-}
-
-func remoteProjectName(i int) string {
-	return "test-remote-project-" + fmt.Sprintf("%d", i)
+func projectName(i int) string {
+	return fmt.Sprintf("project-%d", i)
 }
 
 func setupNewProject(t *testing.T, jirix *jiri.X, dir, name string, ignore bool) string {
@@ -258,14 +101,6 @@
 	return projectDir
 }
 
-func writeEmptyMetadata(t *testing.T, jirix *jiri.X, projectDir string) {
-	metadataFile := filepath.Join(projectDir, jiri.ProjectMetaDir, jiri.ProjectMetaFile)
-	p := project.Project{}
-	if err := p.ToFile(jirix, metadataFile); err != nil {
-		t.Fatal(err)
-	}
-}
-
 func writeReadme(t *testing.T, jirix *jiri.X, projectDir, message string) {
 	path, perm := filepath.Join(projectDir, "README"), os.FileMode(0644)
 	if err := ioutil.WriteFile(path, []byte(message), perm); err != nil {
@@ -274,34 +109,6 @@
 	commitFile(t, jirix, projectDir, path, "creating README")
 }
 
-func createAndCheckoutBranch(t *testing.T, jirix *jiri.X, projectDir, branch string) {
-	cwd, err := os.Getwd()
-	if err != nil {
-		t.Fatalf("%v", err)
-	}
-	defer jirix.NewSeq().Chdir(cwd)
-	if err := jirix.NewSeq().Chdir(projectDir).Done(); err != nil {
-		t.Fatalf("%v", err)
-	}
-	if err := gitutil.New(jirix.NewSeq()).CreateAndCheckoutBranch(branch); err != nil {
-		t.Fatalf("%v", err)
-	}
-}
-
-func resetToOriginMaster(t *testing.T, jirix *jiri.X, projectDir string) {
-	cwd, err := os.Getwd()
-	if err != nil {
-		t.Fatalf("%v", err)
-	}
-	defer jirix.NewSeq().Chdir(cwd)
-	if err := jirix.NewSeq().Chdir(projectDir).Done(); err != nil {
-		t.Fatalf("%v", err)
-	}
-	if err := gitutil.New(jirix.NewSeq()).Reset("origin/master"); err != nil {
-		t.Fatalf("%v", err)
-	}
-}
-
 func checkProjectsMatchPaths(t *testing.T, gotProjects project.Projects, wantProjectPaths []string) {
 	gotProjectPaths := []string{}
 	for _, p := range gotProjects {
@@ -323,7 +130,7 @@
 	// Create some projects.
 	numProjects, projectPaths := 3, []string{}
 	for i := 0; i < numProjects; i++ {
-		name := localProjectName(i)
+		name := projectName(i)
 		path := setupNewProject(t, jirix, jirix.Root, name, true)
 		p := project.Project{
 			Path:     path,
@@ -341,7 +148,7 @@
 		Projects: []project.Project{
 			{
 				Name:     projectPaths[0],
-				Path:     localProjectName(0),
+				Path:     projectName(0),
 				Protocol: "git",
 				Remote:   projectPaths[0],
 			},
@@ -381,196 +188,300 @@
 	checkProjectsMatchPaths(t, foundProjects, projectPaths[1:])
 }
 
-// TestUpdateUniverse is a comprehensive test of the "jiri update"
-// logic that handles projects.
-//
-// TODO(jsimsa): Add tests for the logic that updates tools.
-func TestUpdateUniverse(t *testing.T) {
-	// Setup an instance of jiri universe, creating the remote repositories for
-	// the manifest and projects under the ".remote" directory, which is ignored
-	// from the consideration of LocalProjects().
-	jirix, cleanup := jiritest.NewX(t)
-	defer cleanup()
+// setupUniverse creates a fake jiri root with 3 remote projects.  Each project
+// has a README with text "initial readme".
+func setupUniverse(t *testing.T) ([]project.Project, *jiritest.FakeJiriRoot, func()) {
+	fake, cleanup := jiritest.NewFakeJiriRoot(t)
+	success := false
+	defer func() {
+		if !success {
+			cleanup()
+		}
+	}()
 
-	localDir := jirix.Root
-	remoteDir := filepath.Join(jirix.Root, ".remote")
-
-	localManifest := setupNewProject(t, jirix, localDir, ".manifest", false)
-	writeEmptyMetadata(t, jirix, localManifest)
-	remoteManifest := setupNewProject(t, jirix, remoteDir, "test-remote-manifest", false)
-	addRemote(t, jirix, localManifest, "origin", remoteManifest)
-	numProjects, remoteProjects := 6, []string{}
+	// Create some projects and add them to the remote manifest.
+	numProjects := 3
+	localProjects := []project.Project{}
 	for i := 0; i < numProjects; i++ {
-		remoteProject := setupNewProject(t, jirix, remoteDir, remoteProjectName(i), true)
-		remoteProjects = append(remoteProjects, remoteProject)
-	}
-	createRemoteManifest(t, jirix, remoteManifest, remoteProjects)
-
-	// Check that calling UpdateUniverse() creates local copies of
-	// the remote repositories, advancing projects to HEAD or to
-	// the fixed revision set in the manifest.
-	for _, remoteProject := range remoteProjects {
-		writeReadme(t, jirix, remoteProject, "revision 1")
-	}
-	holdProjectBack(t, jirix, remoteManifest, remoteProjects[0])
-	for _, remoteProject := range remoteProjects {
-		writeReadme(t, jirix, remoteProject, "revision 2")
-	}
-	if err := project.UpdateUniverse(jirix, false); err != nil {
-		t.Fatalf("%v", err)
-	}
-	checkCreateFn := func(i int, revision string) {
-		localProject := filepath.Join(localDir, localProjectName(i))
-		checkGitIgnore(t, jirix, localProject)
-		if i == 0 {
-			checkReadme(t, jirix, localProject, "revision 1")
-		} else {
-			checkReadme(t, jirix, localProject, revision)
+		name := projectName(i)
+		path := fmt.Sprintf("path-%d", i)
+		if err := fake.CreateRemoteProject(name); err != nil {
+			t.Fatal(err)
+		}
+		p := project.Project{
+			Name:   name,
+			Path:   filepath.Join(fake.X.Root, path),
+			Remote: fake.Projects[name],
+		}
+		localProjects = append(localProjects, p)
+		if err := fake.AddProject(p); err != nil {
+			t.Fatal(err)
 		}
 	}
-	for i, _ := range remoteProjects {
-		checkCreateFn(i, "revision 2")
+
+	// Create initial commit in each repo.
+	for _, remoteProjectDir := range fake.Projects {
+		writeReadme(t, fake.X, remoteProjectDir, "initial readme")
 	}
 
-	// Commit more work to the remote repositories and check that
-	// calling UpdateUniverse() advances project to HEAD or to the
-	// fixed revision set in the manifest.
-	holdProjectBack(t, jirix, remoteManifest, remoteProjects[1])
-	for _, remoteProject := range remoteProjects {
-		writeReadme(t, jirix, remoteProject, "revision 3")
+	success = true
+	return localProjects, fake, cleanup
+}
+
+// TestUpdateUniverseSimple tests that UpdateUniverse will pull remote projects
+// locally, and that jiri metadata is ignored in the repos.
+func TestUpdateUniverseSimple(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	s := fake.X.NewSeq()
+
+	// Check that calling UpdateUniverse() creates local copies of the remote
+	// repositories, and that jiri metadata is ignored by git.
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
-	if err := project.UpdateUniverse(jirix, false); err != nil {
-		t.Fatalf("%v", err)
+	for _, p := range localProjects {
+		if err := s.AssertDirExists(p.Path).Done(); err != nil {
+			t.Fatalf("expected project to exist at path %q but none found", p.Path)
+		}
+		checkReadme(t, fake.X, p, "initial readme")
+		checkMetadataIsIgnored(t, fake.X, p)
 	}
-	checkUpdateFn := func(i int, revision string) {
+}
+
+// TestUpdateUniverseWithRevision checks that UpdateUniverse will pull remote
+// projects at the specified revision.
+func TestUpdateUniverseWithRevision(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	s := fake.X.NewSeq()
+
+	// Set project 1's revision in the manifest to the current revision.
+	git := gitutil.New(s, gitutil.RootDirOpt(fake.Projects[localProjects[1].Name]))
+	rev, err := git.CurrentRevision()
+	if err != nil {
+		t.Fatal(err)
+	}
+	m, err := fake.ReadRemoteManifest()
+	if err != nil {
+		t.Fatal(err)
+	}
+	projects := []project.Project{}
+	for _, p := range m.Projects {
+		if p.Name == localProjects[1].Name {
+			p.Revision = rev
+		}
+		projects = append(projects, p)
+	}
+	m.Projects = projects
+	if err := fake.WriteRemoteManifest(m); err != nil {
+		t.Fatal(err)
+	}
+	// Update README in all projects.
+	for _, remoteProjectDir := range fake.Projects {
+		writeReadme(t, fake.X, remoteProjectDir, "new revision")
+	}
+	// Check that calling UpdateUniverse() updates all projects except for
+	// project 1.
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
+	}
+	for i, p := range localProjects {
 		if i == 1 {
-			checkReadme(t, jirix, filepath.Join(localDir, localProjectName(i)), "revision 2")
+			checkReadme(t, fake.X, p, "initial readme")
 		} else {
-			checkCreateFn(i, revision)
+			checkReadme(t, fake.X, p, "new revision")
 		}
 	}
-	for i, _ := range remoteProjects {
-		checkUpdateFn(i, "revision 3")
+}
+
+// TestUpdateUniverseWithUncommitted checks that uncommitted files are not droped
+// by UpdateUniverse(). This ensures that the "git reset --hard" mechanism used
+// for pointing the master branch to a fixed revision does not lose work in
+// progress.
+func TestUpdateUniverseWithUncommitted(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
 
-	// Create an uncommitted file and make sure UpdateUniverse()
-	// does not drop it. This ensures that the "git reset --hard"
-	// mechanism used for pointing the master branch to a fixed
-	// revision does not lose work in progress.
-	file, perm, want := filepath.Join(remoteProjects[1], "uncommitted_file"), os.FileMode(0644), []byte("uncommitted work")
+	// Create an uncommitted file in project 1.
+	file, perm, want := filepath.Join(localProjects[1].Path, "uncommitted_file"), os.FileMode(0644), []byte("uncommitted work")
 	if err := ioutil.WriteFile(file, want, perm); err != nil {
 		t.Fatalf("WriteFile(%v, %v) failed: %v", file, err, perm)
 	}
-	if err := project.UpdateUniverse(jirix, false); err != nil {
-		t.Fatalf("%v", err)
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
 	got, err := ioutil.ReadFile(file)
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
 	if bytes.Compare(got, want) != 0 {
-		t.Fatalf("unexpected content %v:\ngot\n%s\nwant\n%s\n", remoteProjects[1], got, want)
+		t.Fatalf("unexpected content %v:\ngot\n%s\nwant\n%s\n", localProjects[1], got, want)
+	}
+}
+
+// TestUpdateUniverseMovedProject checks that UpdateUniverse can move a
+// project.
+func TestUpdateUniverseMovedProject(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	s := fake.X.NewSeq()
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
 
-	// Update the local path at which a remote project is to be
-	// located and check that UpdateUniverse() moves the local
-	// copy of the project.
-	destination := filepath.Join("test", localProjectName(2))
-	moveProject(t, jirix, remoteManifest, remoteProjects[2], destination)
-	if err := project.UpdateUniverse(jirix, false); err != nil {
-		t.Fatalf("%v", err)
+	// Update the local path at which project 1 is located.
+	m, err := fake.ReadRemoteManifest()
+	if err != nil {
+		t.Fatal(err)
 	}
-	checkMoveFn := func(i int, revision string) {
-		if i == 2 {
-			checkReadme(t, jirix, filepath.Join(localDir, destination), revision)
-		} else {
-			checkUpdateFn(i, revision)
+	oldProjectPath := localProjects[1].Path
+	localProjects[1].Path = filepath.Join(fake.X.Root, "new-project-path")
+	projects := []project.Project{}
+	for _, p := range m.Projects {
+		if p.Name == localProjects[1].Name {
+			p.Path = localProjects[1].Path
 		}
+		projects = append(projects, p)
 	}
-	for i, _ := range remoteProjects {
-		checkMoveFn(i, "revision 3")
+	m.Projects = projects
+	if err := fake.WriteRemoteManifest(m); err != nil {
+		t.Fatal(err)
+	}
+	// Check that UpdateUniverse() moves the local copy of the project 1.
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
+	}
+	if err := s.AssertDirExists(oldProjectPath).Done(); err == nil {
+		t.Fatalf("expected project %q at path %q not to exist but it did", localProjects[1].Name, oldProjectPath)
+	}
+	if err := s.AssertDirExists(localProjects[2].Path).Done(); err != nil {
+		t.Fatalf("expected project %q at path %q to exist but it did not", localProjects[1].Name, localProjects[1].Path)
+	}
+	checkReadme(t, fake.X, localProjects[1], "initial readme")
+}
+
+// TestUpdateUniverseDeletedProject checks that UpdateUniverse will delete a
+// project iff gc=true.
+func TestUpdateUniverseDeletedProject(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	s := fake.X.NewSeq()
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
 
-	// Delete a remote project and check that UpdateUniverse()
-	// deletes the local copy of the project.
-	deleteProject(t, jirix, remoteManifest, remoteProjects[3])
-	if err := project.UpdateUniverse(jirix, true); err != nil {
-		t.Fatalf("%v", err)
+	// Delete project 1.
+	m, err := fake.ReadRemoteManifest()
+	if err != nil {
+		t.Fatal(err)
 	}
-	checkDeleteFn := func(i int, revision string) {
-		if i == 3 {
-			localProject := filepath.Join(localDir, localProjectName(i))
-			if _, err := jirix.NewSeq().Stat(localProject); err == nil {
-				t.Fatalf("project %v has not been deleted", localProject)
-			} else {
-				if !runutil.IsNotExist(err) {
-					t.Fatalf("%v", err)
-				}
-			}
-		} else {
-			checkMoveFn(i, revision)
+	projects := []project.Project{}
+	for _, p := range m.Projects {
+		if p.Name == localProjects[1].Name {
+			continue
 		}
+		projects = append(projects, p)
 	}
-	for i, _ := range remoteProjects {
-		checkDeleteFn(i, "revision 3")
+	m.Projects = projects
+	if err := fake.WriteRemoteManifest(m); err != nil {
+		t.Fatal(err)
+	}
+	// Check that UpdateUniverse() with gc=false does not delete the local copy
+	// of the project.
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
+	}
+	if err := s.AssertDirExists(localProjects[1].Path).Done(); err != nil {
+		t.Fatalf("expected project %q at path %q to exist but it did not", localProjects[1].Name, localProjects[1].Path)
+	}
+	checkReadme(t, fake.X, localProjects[1], "initial readme")
+	// Check that UpdateUniverse() with gc=true does delete the local copy of
+	// the project.
+	if err := fake.UpdateUniverse(true); err != nil {
+		t.Fatal(err)
+	}
+	if err := s.AssertDirExists(localProjects[1].Path).Done(); err == nil {
+		t.Fatalf("expected project %q at path %q not to exist but it did", localProjects[1].Name, localProjects[3].Path)
+	}
+}
+
+// TestUpdateUniverseNewProjectSamePath checks that UpdateUniverse can handle a
+// new project with the same path as a deleted project, but a different path.
+func TestUpdateUniverseNewProjectSamePath(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
 
-	// Delete a project and create a new one with a different name but the same
-	// path.  Check that UpdateUniverse() does not fail.
-	deleteProject(t, jirix, remoteManifest, remoteProjects[4])
-	createProject(t, jirix, remoteManifest, "new.project", remoteProjects[4], localProjectName(4))
-	if err := project.UpdateUniverse(jirix, true); err != nil {
-		t.Fatalf("%v", err)
+	// Delete a project 1 and create a new one with a different name but the
+	// same path.
+	m, err := fake.ReadRemoteManifest()
+	if err != nil {
+		t.Fatal(err)
 	}
-
-	// Commit to a non-master branch of a remote project and check that
-	// UpdateUniverse() can update the local project to point to a revision on
-	// that branch.
-	writeReadme(t, jirix, remoteProjects[5], "master commit")
-	createAndCheckoutBranch(t, jirix, remoteProjects[5], "non_master")
-	writeReadme(t, jirix, remoteProjects[5], "non master commit")
-	remoteBranchRevision := currentRevision(t, jirix, remoteProjects[5])
-	setRevisionForProject(t, jirix, remoteManifest, remoteProjects[5], remoteBranchRevision)
-	if err := project.UpdateUniverse(jirix, true); err != nil {
-		t.Fatalf("%v", err)
-	}
-	localProject := filepath.Join(localDir, localProjectName(5))
-	localBranchRevision := currentRevision(t, jirix, localProject)
-	if localBranchRevision != remoteBranchRevision {
-		t.Fatalf("project 5 is at revision %v, expected %v\n", localBranchRevision, remoteBranchRevision)
-	}
-	// Reset back to origin/master so the next update without a "revision" works.
-	resetToOriginMaster(t, jirix, localProject)
-
-	// Create a local manifest that imports the remote manifest
-	// and check that UpdateUniverse() has no effect.
-	createLocalManifestStub(t, jirix, localDir)
-	if err := project.UpdateUniverse(jirix, true); err != nil {
-		t.Fatalf("%v", err)
-	}
-
-	checkRebaseFn := func(i int, revision string) {
-		if i == 5 {
-			checkReadme(t, jirix, localProject, "non master commit")
-		} else {
-			checkDeleteFn(i, revision)
+	newProjectName := "new-project-name"
+	projects := []project.Project{}
+	for _, p := range m.Projects {
+		if p.Path == localProjects[1].Path {
+			p.Name = newProjectName
 		}
+		projects = append(projects, p)
 	}
-	for i, _ := range remoteProjects {
-		checkRebaseFn(i, "revision 3")
+	localProjects[1].Name = newProjectName
+	m.Projects = projects
+	if err := fake.WriteRemoteManifest(m); err != nil {
+		t.Fatal(err)
+	}
+	// Check that UpdateUniverse() does not fail.
+	if err := fake.UpdateUniverse(true); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// TestUpdateUniverseRemoteBranch checks that UpdateUniverse can pull from a
+// non-master remote branch.
+func TestUpdateUniverseRemoteBranch(t *testing.T) {
+	localProjects, fake, cleanup := setupUniverse(t)
+	defer cleanup()
+	s := fake.X.NewSeq()
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
 	}
 
-	// Create a local manifest that matches the remote manifest,
-	// then revert the remote manifest to its initial version and
-	// check that UpdateUniverse() has no effect.
-	createLocalManifestCopy(t, jirix, localDir, remoteManifest)
-	createRemoteManifest(t, jirix, remoteManifest, remoteProjects)
-	if err := project.UpdateUniverse(jirix, true); err != nil {
-		t.Fatalf("%v", err)
+	// Commit to master branch of a project 1.
+	writeReadme(t, fake.X, fake.Projects[localProjects[1].Name], "master commit")
+	// Create and checkout a new branch of project 1 and make a new commit.
+	git := gitutil.New(s, gitutil.RootDirOpt(fake.Projects[localProjects[1].Name]))
+	if err := git.CreateAndCheckoutBranch("non-master"); err != nil {
+		t.Fatal(err)
 	}
-	for i, _ := range remoteProjects {
-		checkRebaseFn(i, "revision 3")
+	writeReadme(t, fake.X, fake.Projects[localProjects[1].Name], "non-master commit")
+	// Point the manifest to the new non-master branch.
+	m, err := fake.ReadRemoteManifest()
+	if err != nil {
+		t.Fatal(err)
 	}
+	projects := []project.Project{}
+	for _, p := range m.Projects {
+		if p.Name == localProjects[1].Name {
+			p.RemoteBranch = "non-master"
+		}
+		projects = append(projects, p)
+	}
+	m.Projects = projects
+	if err := fake.WriteRemoteManifest(m); err != nil {
+		t.Fatal(err)
+	}
+	// Check that UpdateUniverse pulls the commit from the non-master branch.
+	if err := fake.UpdateUniverse(false); err != nil {
+		t.Fatal(err)
+	}
+	checkReadme(t, fake.X, localProjects[1], "non-master commit")
 }
 
 func TestFileImportCycle(t *testing.T) {
@@ -928,9 +839,6 @@
 						Remote:       "remote2",
 						RemoteBranch: "branch2",
 					},
-					{
-						Name: "oldimport",
-					},
 				},
 				LocalImports: []project.LocalImport{
 					{File: "fileimport"},
@@ -968,7 +876,6 @@
   <imports>
     <import manifest="manifest1" name="remoteimport1" remote="remote1"/>
     <import manifest="manifest2" name="remoteimport2" remote="remote2" remotebranch="branch2"/>
-    <import name="oldimport"/>
     <localimport file="fileimport"/>
   </imports>
   <projects>
@@ -1057,63 +964,3 @@
 		}
 	}
 }
-
-func TestProjectFromFileBackwardsCompatible(t *testing.T) {
-	jirix, cleanup := jiritest.NewX(t)
-	defer cleanup()
-
-	tests := []struct {
-		XML     string
-		Project project.Project
-	}{
-		// Make sure <Project> opening tag is accepted.
-		{
-			`<Project name="project" path="path" remote="remote"/>`,
-			project.Project{
-				Name:         "project",
-				Path:         filepath.Join(jirix.Root, "path"),
-				Protocol:     "git",
-				Remote:       "remote",
-				RemoteBranch: "master",
-				Revision:     "HEAD",
-			},
-		},
-		// Make sure <Project> opening and closing tags are accepted.
-		{
-			`<Project name="project" path="path" remote="remote"></Project>`,
-			project.Project{
-				Name:         "project",
-				Path:         filepath.Join(jirix.Root, "path"),
-				Protocol:     "git",
-				Remote:       "remote",
-				RemoteBranch: "master",
-				Revision:     "HEAD",
-			},
-		},
-		// Make sure "this_attribute_should_be_ignored" is silently ignored.
-		{
-			`<Project this_attribute_should_be_ignored="junk" name="project" path="path" remote="remote" remotebranch="branch" revision="rev"></Project>`,
-			project.Project{
-				Name:         "project",
-				Path:         filepath.Join(jirix.Root, "path"),
-				Protocol:     "git",
-				Remote:       "remote",
-				RemoteBranch: "branch",
-				Revision:     "rev",
-			},
-		},
-	}
-	for index, test := range tests {
-		filename := filepath.Join(jirix.Root, fmt.Sprintf("test-%d", index))
-		if err := jirix.NewSeq().WriteFile(filename, []byte(test.XML), 0644).Done(); err != nil {
-			t.Errorf("%+v WriteFile failed: %v", test.Project, err)
-		}
-		project, err := project.ProjectFromFile(jirix, filename)
-		if err != nil {
-			t.Errorf("%+v FromFile failed: %v", test.Project, err)
-		}
-		if got, want := project, &test.Project; !reflect.DeepEqual(got, want) {
-			t.Errorf("%+v FromFile got %#v, want %#v", test.Project, got, want)
-		}
-	}
-}
diff --git a/x.go b/x.go
index 2dda4b1..726cdd8 100644
--- a/x.go
+++ b/x.go
@@ -143,14 +143,6 @@
 	return filepath.Join(x.Root, JiriManifestFile)
 }
 
-// UsingOldManifests returns true iff the JIRI_ROOT/.jiri_manifest file does not
-// exist.  This is the one signal used to decide whether to use the old manifest
-// logic (checking .local_manifest and the -manifest flag), or the new logic.
-func (x *X) UsingOldManifests() bool {
-	_, err := os.Stat(x.JiriManifestFile())
-	return os.IsNotExist(err)
-}
-
 // BinDir returns the path to the bin directory.
 func (x *X) BinDir() string {
 	return filepath.Join(x.RootMetaDir(), "bin")
@@ -188,43 +180,6 @@
 	return filepath.Join(x.UpdateHistoryDir(), "second-latest")
 }
 
-// ResolveManifestPath resolves the given manifest name to an absolute path in
-// the local filesystem.
-//
-// TODO(toddw): Remove this once the transition to new manifests is done.  In
-// the new world, we always start with the JiriManifestFile.
-func (x *X) ResolveManifestPath(name string) (string, error) {
-	if x.UsingOldManifests() {
-		return x.resolveManifestPathDeprecated(name)
-	}
-	if name != "" {
-		return "", fmt.Errorf("-manifest flag isn't supported with .jiri_manifest")
-	}
-	return x.JiriManifestFile(), nil
-}
-
-// Deprecated logic, only run if JIRI_ROOT/.jiri_manifest doesn't exist.
-//
-// TODO(toddw): Remove this logic when the transition to .jiri_manifest is done.
-func (x *X) resolveManifestPathDeprecated(name string) (string, error) {
-	manifestDir := filepath.Join(x.Root, ".manifest", "v2")
-	if name != "" {
-		if filepath.IsAbs(name) {
-			return name, nil
-		}
-		return filepath.Join(manifestDir, name), nil
-	}
-	path := filepath.Join(x.Root, ".local_manifest")
-	switch _, err := os.Stat(path); {
-	case err == nil:
-		return path, nil
-	case os.IsNotExist(err):
-		return filepath.Join(manifestDir, "default"), nil
-	default:
-		return "", fmt.Errorf("Stat(%v) failed: %v", path, err)
-	}
-}
-
 // RunnerFunc is an adapter that turns regular functions into cmdline.Runner.
 // This is similar to cmdline.RunnerFunc, but the first function argument is
 // jiri.X, rather than cmdline.Env.