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 := seq.MkdirAll(jirix.RootMetaDir(), 0755).Done(); err != nil { return err } // Update all projects to their latest version. // Attempt <attemptsFlag> times before failing. updateFn := func() error { return project.UpdateUniverse(jirix, gcFlag) } if err := retry.Function(jirix.Context, updateFn, retry.AttemptsOpt(attemptsFlag)); err != nil { return err } if err := project.WriteUpdateHistorySnapshot(jirix, ""); err != nil { return err } // Only attempt the bin dir transition after the update has succeeded, to // avoid messy partial states. return project.TransitionBinDir(jirix) }
// UpdateUniverse synchronizes the content of the Vanadium fake based // on the content of the remote manifest. func (fake FakeJiriRoot) UpdateUniverse(gc bool) error { oldRoot := os.Getenv(jiri.RootEnv) if err := os.Setenv(jiri.RootEnv, fake.X.Root); err != nil { return fmt.Errorf("Setenv() failed: %v", err) } defer os.Setenv(jiri.RootEnv, oldRoot) if err := project.UpdateUniverse(fake.X, gc); err != nil { return err } return nil }
func TestRemoteImportCycle(t *testing.T) { fake, cleanup := jiritest.NewFakeJiriRoot(t) defer cleanup() // Set up two remote manifest projects, remote1 and remote1. if err := fake.CreateRemoteProject("remote1"); err != nil { t.Fatal(err) } if err := fake.CreateRemoteProject("remote2"); err != nil { t.Fatal(err) } remote1 := fake.Projects["remote1"] remote2 := fake.Projects["remote2"] fileA, fileB := filepath.Join(remote1, "A"), filepath.Join(remote2, "B") // Set up the cycle .jiri_manifest -> remote1+A -> remote2+B -> remote1+A jiriManifest := project.Manifest{ Imports: []project.Import{ {Manifest: "A", Name: "n1", Remote: remote1}, }, } manifestA := project.Manifest{ Imports: []project.Import{ {Manifest: "B", Name: "n2", Remote: remote2}, }, } manifestB := project.Manifest{ Imports: []project.Import{ {Manifest: "A", Name: "n3", Remote: remote1}, }, } if err := jiriManifest.ToFile(fake.X, fake.X.JiriManifestFile()); err != nil { t.Fatal(err) } if err := manifestA.ToFile(fake.X, fileA); err != nil { t.Fatal(err) } if err := manifestB.ToFile(fake.X, fileB); err != nil { t.Fatal(err) } commitFile(t, fake.X, remote1, fileA, "commit A") commitFile(t, fake.X, remote2, fileB, "commit B") // The update should complain about the cycle. err := project.UpdateUniverse(fake.X, false) if got, want := fmt.Sprint(err), "import cycle detected in remote manifest imports"; !strings.Contains(got, want) { t.Errorf("got error %v, want substr %v", got, want) } }
func runUpdate(env *cmdline.Env, _ []string) error { ctx := tool.NewContextFromEnv(env) // Create a snapshot of the current state of all projects and // write it to the $JIRI_ROOT/.update_history folder. root, err := project.JiriRoot() if err != nil { return err } snapshotFile := filepath.Join(root, ".update_history", time.Now().Format(time.RFC3339)) if err := project.CreateSnapshot(ctx, snapshotFile); err != nil { return err } // Update all projects to their latest version. // Attempt <attemptsFlag> times before failing. updateFn := func() error { return project.UpdateUniverse(ctx, gcFlag) } return retry.Function(ctx, updateFn, retry.AttemptsOpt(attemptsFlag)) }
func TestFileImportCycle(t *testing.T) { jirix, cleanup := jiritest.NewX(t) defer cleanup() // Set up the cycle .jiri_manifest -> A -> B -> A jiriManifest := project.Manifest{ LocalImports: []project.LocalImport{ {File: "A"}, }, } manifestA := project.Manifest{ LocalImports: []project.LocalImport{ {File: "B"}, }, } manifestB := project.Manifest{ LocalImports: []project.LocalImport{ {File: "A"}, }, } if err := jiriManifest.ToFile(jirix, jirix.JiriManifestFile()); err != nil { t.Fatal(err) } if err := manifestA.ToFile(jirix, filepath.Join(jirix.Root, "A")); err != nil { t.Fatal(err) } if err := manifestB.ToFile(jirix, filepath.Join(jirix.Root, "B")); err != nil { t.Fatal(err) } // The update should complain about the cycle. err := project.UpdateUniverse(jirix, false) if got, want := fmt.Sprint(err), "import cycle detected in local manifest files"; !strings.Contains(got, want) { t.Errorf("got error %v, want substr %v", got, want) } }
// TestCreate tests creating and checking out a snapshot. func TestCreate(t *testing.T) { resetFlags() defer resetFlags() fake, cleanup := jiritest.NewFakeJiriRoot(t) defer cleanup() s := fake.X.NewSeq() // Setup the initial remote and local projects. numProjects, remoteProjects := 2, []string{} for i := 0; i < numProjects; i++ { if err := fake.CreateRemoteProject(remoteProjectName(i)); err != nil { t.Fatalf("%v", err) } if err := fake.AddProject(project.Project{ Name: remoteProjectName(i), Path: localProjectName(i), Remote: fake.Projects[remoteProjectName(i)], }); err != nil { t.Fatalf("%v", err) } } // Create initial commits in the remote projects and use UpdateUniverse() // to mirror them locally. for i := 0; i < numProjects; i++ { writeReadme(t, fake.X, fake.Projects[remoteProjectName(i)], "revision 1") } if err := project.UpdateUniverse(fake.X, true); err != nil { t.Fatalf("%v", err) } // Create a snapshot. var stdout bytes.Buffer fake.X.Context = tool.NewContext(tool.ContextOpts{Stdout: &stdout}) if err := runSnapshotCreate(fake.X, []string{"test-local"}); err != nil { t.Fatalf("%v", err) } // Remove the local project repositories. for i, _ := range remoteProjects { localProject := filepath.Join(fake.X.Root, localProjectName(i)) if err := s.RemoveAll(localProject).Done(); err != nil { t.Fatalf("%v", err) } } // Check that invoking the UpdateUniverse() with the snapshot restores the // local repositories. snapshotDir := filepath.Join(fake.X.Root, defaultSnapshotDir) snapshotFile := filepath.Join(snapshotDir, "test-local") localX := fake.X.Clone(tool.ContextOpts{ Manifest: &snapshotFile, }) if err := project.UpdateUniverse(localX, true); err != nil { t.Fatalf("%v", err) } for i, _ := range remoteProjects { localProject := filepath.Join(fake.X.Root, localProjectName(i)) checkReadme(t, fake.X, localProject, "revision 1") } }
func TestCreate(t *testing.T) { ctx := tool.NewDefaultContext() // Setup a fake JIRI_ROOT instance. root, err := project.NewFakeJiriRoot(ctx) if err != nil { t.Fatalf("%v", err) } defer func() { if err := root.Cleanup(ctx); err != nil { t.Fatalf("%v", err) } }() // Setup the initial remote and local projects. numProjects, remoteProjects := 2, []string{} for i := 0; i < numProjects; i++ { if err := root.CreateRemoteProject(ctx, remoteProjectName(i)); err != nil { t.Fatalf("%v", err) } if err := root.AddProject(ctx, project.Project{ Name: remoteProjectName(i), Path: localProjectName(i), Remote: root.Projects[remoteProjectName(i)], }); err != nil { t.Fatalf("%v", err) } } // Point the JIRI_ROOT environment variable to the fake. oldRoot, err := project.JiriRoot() if err := os.Setenv("JIRI_ROOT", root.Dir); err != nil { t.Fatalf("%v", err) } defer os.Setenv("JIRI_ROOT", oldRoot) // Create initial commits in the remote projects and use // UpdateUniverse() to mirror them locally. for i := 0; i < numProjects; i++ { writeReadme(t, ctx, root.Projects[remoteProjectName(i)], "revision 1") } if err := project.UpdateUniverse(ctx, true); err != nil { t.Fatalf("%v", err) } // Create a local snapshot. var stdout bytes.Buffer env := &cmdline.Env{Stdout: &stdout} remoteFlag = false if err := runSnapshotCreate(env, []string{"test-local"}); err != nil { t.Fatalf("%v", err) } // Remove the local project repositories. for i, _ := range remoteProjects { localProject := filepath.Join(root.Dir, localProjectName(i)) if err := ctx.Run().RemoveAll(localProject); err != nil { t.Fatalf("%v", err) } } // Check that invoking the UpdateUniverse() with the local // snapshot restores the local repositories. snapshotDir, err := project.LocalSnapshotDir() if err != nil { t.Fatalf("%v", err) } snapshotFile := filepath.Join(snapshotDir, "test-local") localCtx := ctx.Clone(tool.ContextOpts{ Manifest: &snapshotFile, }) if err := project.UpdateUniverse(localCtx, true); err != nil { t.Fatalf("%v", err) } for i, _ := range remoteProjects { localProject := filepath.Join(root.Dir, localProjectName(i)) checkReadme(t, ctx, localProject, "revision 1") } // Create a remote snapshot. remoteFlag = true root.EnableRemoteManifestPush(ctx) if err := runSnapshotCreate(env, []string{"test-remote"}); err != nil { t.Fatalf("%v", err) } // Remove the local project repositories. for i, _ := range remoteProjects { localProject := filepath.Join(root.Dir, localProjectName(i)) if err := ctx.Run().RemoveAll(localProject); err != nil { t.Fatalf("%v", err) } } // Check that invoking the UpdateUniverse() with the remote snapshot // restores the local repositories. manifest := "snapshot/test-remote" remoteCtx := ctx.Clone(tool.ContextOpts{ Manifest: &manifest, }) if err := project.UpdateUniverse(remoteCtx, true); err != nil { t.Fatalf("%v", err) } for i, _ := range remoteProjects { localProject := filepath.Join(root.Dir, localProjectName(i)) checkReadme(t, ctx, localProject, "revision 1") } }