Merge "jiri: Clarify the arg to -remote-branch."
diff --git a/doc.go b/doc.go
index 588efd9..0e3a622 100644
--- a/doc.go
+++ b/doc.go
@@ -406,10 +406,6 @@
particular, it can be used to create new snapshots and to list existing
snapshots.
-The command-line flag "-remote" determines whether the command pertains to
-"local" snapshots that are only stored locally or "remote" snapshots the are
-revisioned in the manifest repository.
-
Usage:
jiri snapshot [flags] <command>
@@ -418,6 +414,8 @@
list List existing project snapshots
The jiri snapshot flags are:
+ -dir=
+ Directory where snapshot are stored. Defaults to $JIRI_ROOT/.snapshot.
-remote=false
Manage remote snapshots.
@@ -431,10 +429,8 @@
Jiri snapshot create - Create a new project snapshot
The "jiri snapshot create <label>" command captures the current project state in
-a manifest and, depending on the value of the -remote flag, the command either
-stores the manifest in the local $JIRI_ROOT/.snapshots directory, or in the
-manifest repository, pushing the change to the remote repository and thus making
-it available globally.
+a manifest. If the -push-remote flag is provided, the snapshot is committed and
+pushed upstream.
Internally, snapshots are organized as follows:
@@ -463,11 +459,15 @@
<label> is the snapshot label.
The jiri snapshot create flags are:
+ -push-remote=false
+ Commit and push snapshot upstream.
-time-format=2006-01-02T15:04:05Z07:00
Time format for snapshot file name.
-color=true
Use color to format output.
+ -dir=
+ Directory where snapshot are stored. Defaults to $JIRI_ROOT/.snapshot.
-n=false
Show what commands will run but do not execute them.
-remote=false
@@ -489,6 +489,8 @@
The jiri snapshot list flags are:
-color=true
Use color to format output.
+ -dir=
+ Directory where snapshot are stored. Defaults to $JIRI_ROOT/.snapshot.
-n=false
Show what commands will run but do not execute them.
-remote=false
diff --git a/gitutil/.api b/gitutil/.api
index 8bf6ac4..4ba995e 100644
--- a/gitutil/.api
+++ b/gitutil/.api
@@ -7,6 +7,7 @@
pkg gitutil, method (*Git) BranchesDiffer(string, string) (bool, error)
pkg gitutil, method (*Git) CheckoutBranch(string, ...CheckoutOpt) error
pkg gitutil, method (*Git) Clone(string, string) error
+pkg gitutil, method (*Git) CloneRecursive(string, string) error
pkg gitutil, method (*Git) Commit() error
pkg gitutil, method (*Git) CommitAmend() error
pkg gitutil, method (*Git) CommitAmendWithMessage(string) error
diff --git a/gitutil/git.go b/gitutil/git.go
index 879cabd..82d0c3c 100644
--- a/gitutil/git.go
+++ b/gitutil/git.go
@@ -113,6 +113,11 @@
// Clone clones the given repository to the given local path.
func (g *Git) Clone(repo, path string) error {
+ return g.run("clone", repo, path)
+}
+
+// CloneRecursive clones the given repository recursively to the given local path.
+func (g *Git) CloneRecursive(repo, path string) error {
return g.run("clone", "--recursive", repo, path)
}
diff --git a/jiri/.api b/jiri/.api
index 0addbef..384b799 100644
--- a/jiri/.api
+++ b/jiri/.api
@@ -11,10 +11,6 @@
pkg jiri, method (*X) BinDir() string
pkg jiri, method (*X) Clone(tool.ContextOpts) *X
pkg jiri, method (*X) JiriManifestFile() string
-pkg jiri, method (*X) LocalSnapshotDir() string
-pkg jiri, method (*X) ManifestDir() string
-pkg jiri, method (*X) ManifestFile(string) string
-pkg jiri, method (*X) RemoteSnapshotDir() string
pkg jiri, method (*X) ResolveManifestPath(string) (string, error)
pkg jiri, method (*X) RootMetaDir() string
pkg jiri, method (*X) UpdateHistoryDir() string
diff --git a/jiri/x.go b/jiri/x.go
index 685283c..20133dd 100644
--- a/jiri/x.go
+++ b/jiri/x.go
@@ -136,26 +136,6 @@
return filepath.Join(x.RootMetaDir(), "update_history")
}
-// LocalSnapshotDir returns the path to the local snapshot directory.
-func (x *X) LocalSnapshotDir() string {
- return filepath.Join(x.Root, ".snapshot")
-}
-
-// RemoteSnapshotDir returns the path to the remote snapshot directory.
-func (x *X) RemoteSnapshotDir() string {
- return filepath.Join(x.ManifestDir(), "snapshot")
-}
-
-// ManifestDir returns the path to the manifest directory.
-func (x *X) ManifestDir() string {
- return filepath.Join(x.Root, ".manifest", "v2")
-}
-
-// ManifestFile returns the path to the manifest file with the given name.
-func (x *X) ManifestFile(name string) string {
- return filepath.Join(x.ManifestDir(), name)
-}
-
// ResolveManifestPath resolves the given manifest name to an absolute path in
// the local filesystem.
func (x *X) ResolveManifestPath(name string) (string, error) {
@@ -172,18 +152,19 @@
//
// 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 x.ManifestFile(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 x.ManifestFile("default"), nil
+ return filepath.Join(manifestDir, "default"), nil
default:
return "", fmt.Errorf("Stat(%v) failed: %v", path, err)
}
diff --git a/jiritest/fake.go b/jiritest/fake.go
index 4987b15..c3e8195 100644
--- a/jiritest/fake.go
+++ b/jiritest/fake.go
@@ -63,7 +63,7 @@
if err := fake.WriteRemoteManifest(&project.Manifest{}); err != nil {
t.Fatal(err)
}
- if err := jirix.Git().Clone(fake.Projects[manifestProject], filepath.Join(jirix.Root, manifestProject)); err != nil {
+ if err := jirix.Git().CloneRecursive(fake.Projects[manifestProject], filepath.Join(jirix.Root, manifestProject)); err != nil {
t.Fatal(err)
}
diff --git a/profiles/profilescmdline/reader_cmdline.go b/profiles/profilescmdline/reader_cmdline.go
index 1573684..2afac17 100644
--- a/profiles/profilescmdline/reader_cmdline.go
+++ b/profiles/profilescmdline/reader_cmdline.go
@@ -28,7 +28,6 @@
// IsFlagSet returns true if the specified flag has been set on
// the command line.
-// TODO(cnicolaou): use this to simplify the implementation of profiles.Target
func IsFlagSet(fs *flag.FlagSet, name string) bool {
found := false
fs.Visit(func(f *flag.Flag) {
@@ -36,7 +35,7 @@
found = true
}
})
- return true
+ return found
}
// NOTE: we use functions to initialize the commands so that we
diff --git a/project/project.go b/project/project.go
index 276aeba..a877633 100644
--- a/project/project.go
+++ b/project/project.go
@@ -1851,7 +1851,12 @@
if found && strings.HasPrefix(op.project.Remote, host.Location) {
gitHookDir := filepath.Join(tmpDir, ".git", "hooks")
for _, githook := range host.GitHooks {
- mdir := jirix.ManifestDir()
+ // TODO(nlacasse): GitHook paths are relative to the manifest
+ // file. Currently all manifests live in
+ // JIRI_ROOT/.manifest/v2, but that is changing. I think
+ // GitHooks should be associated with projects, and their paths
+ // should be relative to the project root.
+ mdir := filepath.Join(jirix.Root, ".manifest", "v2")
src, err := s.ReadFile(filepath.Join(mdir, githook.Path))
if err != nil {
return err
diff --git a/snapshot.go b/snapshot.go
index 1ed9255..3238615 100644
--- a/snapshot.go
+++ b/snapshot.go
@@ -21,14 +21,28 @@
"v.io/x/lib/cmdline"
)
+const (
+ defaultSnapshotDir = ".snapshot"
+)
+
var (
- remoteFlag bool
- timeFormatFlag string
+ snapshotDirFlag string
+ pushRemoteFlag bool
+ timeFormatFlag string
+
+ // TODO(nlacasse): Remove the -remote flag once all users have moved to the
+ // -push-remote flag.
+ remoteFlag bool
)
func init() {
- cmdSnapshot.Flags.BoolVar(&remoteFlag, "remote", false, "Manage remote snapshots.")
+ cmdSnapshot.Flags.StringVar(&snapshotDirFlag, "dir", "", "Directory where snapshot are stored. Defaults to $JIRI_ROOT/.snapshot.")
+ cmdSnapshotCreate.Flags.BoolVar(&pushRemoteFlag, "push-remote", false, "Commit and push snapshot upstream.")
cmdSnapshotCreate.Flags.StringVar(&timeFormatFlag, "time-format", time.RFC3339, "Time format for snapshot file name.")
+
+ // TODO(nlacasse): Remove the -remote flag once all users have moved to the
+ // -push-remote flag.
+ cmdSnapshot.Flags.BoolVar(&remoteFlag, "remote", false, "Manage remote snapshots.")
}
var cmdSnapshot = &cmdline.Command{
@@ -38,10 +52,6 @@
The "jiri snapshot" command can be used to manage project snapshots.
In particular, it can be used to create new snapshots and to list
existing snapshots.
-
-The command-line flag "-remote" determines whether the command
-pertains to "local" snapshots that are only stored locally or "remote"
-snapshots the are revisioned in the manifest repository.
`,
Children: []*cmdline.Command{cmdSnapshotCreate, cmdSnapshotList},
}
@@ -52,12 +62,9 @@
Name: "create",
Short: "Create a new project snapshot",
Long: `
-The "jiri snapshot create <label>" command captures the current project
-state in a manifest and, depending on the value of the -remote flag,
-the command either stores the manifest in the local
-$JIRI_ROOT/.snapshots directory, or in the manifest repository, pushing
-the change to the remote repository and thus making it available
-globally.
+The "jiri snapshot create <label>" command captures the current project state
+in a manifest. If the -push-remote flag is provided, the snapshot is committed
+and pushed upstream.
Internally, snapshots are organized as follows:
@@ -94,75 +101,59 @@
return err
}
snapshotFile := filepath.Join(snapshotDir, "labels", label, time.Now().Format(timeFormatFlag))
- // Either atomically create a new snapshot that captures the project
- // state and push the changes to the remote repository (if
- // applicable), or fail with no effect.
+
+ if !remoteFlag && !pushRemoteFlag {
+ // No git operations necessary. Just create the snapshot file.
+ return createSnapshot(jirix, snapshotDir, snapshotFile, label)
+ }
+
+ // Attempt to create a snapshot on a clean master branch. If snapshot
+ // creation fails, return to the state we were in before.
createFn := func() error {
revision, err := jirix.Git().CurrentRevision()
if err != nil {
return err
}
if err := createSnapshot(jirix, snapshotDir, snapshotFile, label); err != nil {
- // Clean up on all errors.
jirix.Git().Reset(revision)
jirix.Git().RemoveUntrackedFiles()
return err
}
- return nil
+ return commitAndPushChanges(jirix, snapshotDir, snapshotFile, label)
}
- // Execute the above function in the snapshot directory.
+ // Execute the above function in the snapshot directory on a clean master branch.
p := project.Project{
Path: snapshotDir,
Protocol: "git",
Revision: "HEAD",
}
- if err := project.ApplyToLocalMaster(jirix, project.Projects{p.Key(): p}, createFn); err != nil {
- return err
- }
- return nil
+ return project.ApplyToLocalMaster(jirix, project.Projects{p.Key(): p}, createFn)
}
-// getSnapshotDir returns the path to the snapshot directory, respecting the
-// value of the "-remote" command-line flag. It performs validation that the
-// directory exists and is initialized.
+// getSnapshotDir returns the path to the snapshot directory, creating it if
+// necessary.
func getSnapshotDir(jirix *jiri.X) (string, error) {
- dir := jirix.LocalSnapshotDir()
+ dir := snapshotDirFlag
+ if dir == "" {
+ dir = filepath.Join(jirix.Root, defaultSnapshotDir)
+ }
+
+ // TODO(nlacasse): Remove once there are no more user of the -remote flag.
if remoteFlag {
- dir = jirix.RemoteSnapshotDir()
+ dir = filepath.Join(jirix.Root, ".manifest", "v2", "snapshot")
}
- s := jirix.NewSeq()
- switch _, err := s.Stat(dir); {
- case err == nil:
- return dir, nil
- case !runutil.IsNotExist(err):
- return "", err
- case remoteFlag:
- if err := s.MkdirAll(dir, 0755).Done(); err != nil {
- return "", err
- }
- return dir, nil
- }
- // Create a new local snapshot directory.
- createFn := func() (e error) {
- if err := s.MkdirAll(dir, 0755).Done(); err != nil {
- return err
- }
- if err := jirix.Git().Init(dir); err != nil {
- return err
- }
+
+ if !filepath.IsAbs(dir) {
cwd, err := os.Getwd()
if err != nil {
- return err
+ return "", err
}
- defer collect.Error(func() error { return jirix.NewSeq().Chdir(cwd).Done() }, &e)
- if err := s.Chdir(dir).Done(); err != nil {
- return err
- }
- return jirix.Git().Commit()
+ dir = filepath.Join(cwd, dir)
}
- if err := createFn(); err != nil {
- s.RemoveAll(dir)
+
+ // Make sure directory exists.
+ if err := jirix.NewSeq().MkdirAll(dir, 0755).Done(); err != nil {
return "", err
}
return dir, nil
@@ -181,23 +172,15 @@
symlink := filepath.Join(snapshotDir, label)
newSymlink := symlink + ".new"
relativeSnapshotPath := strings.TrimPrefix(snapshotFile, snapshotDir+string(os.PathSeparator))
- if err := s.RemoveAll(newSymlink).
+ return s.RemoveAll(newSymlink).
Symlink(relativeSnapshotPath, newSymlink).
- Rename(newSymlink, symlink).Done(); err != nil {
- return err
- }
-
- // Revision the changes.
- if err := revisionChanges(jirix, snapshotDir, snapshotFile, label); err != nil {
- return err
- }
- return nil
+ Rename(newSymlink, symlink).Done()
}
-// revisionChanges commits changes identified by the given manifest
-// file and label to the manifest repository and (if applicable)
-// pushes these changes to the remote repository.
-func revisionChanges(jirix *jiri.X, snapshotDir, snapshotFile, label string) (e error) {
+// commitAndPushChanges commits changes identified by the given manifest file
+// and label to the containing repository and pushes these changes to the
+// remote repository.
+func commitAndPushChanges(jirix *jiri.X, snapshotDir, snapshotFile, label string) (e error) {
cwd, err := os.Getwd()
if err != nil {
return err
@@ -217,10 +200,8 @@
if err := jirix.Git().CommitWithMessage(fmt.Sprintf("adding snapshot %q for label %q", name, label)); err != nil {
return err
}
- if remoteFlag {
- if err := jirix.Git().Push("origin", "master", gitutil.VerifyOpt(false)); err != nil {
- return err
- }
+ if err := jirix.Git().Push("origin", "master", gitutil.VerifyOpt(false)); err != nil {
+ return err
}
return nil
}
diff --git a/snapshot_test.go b/snapshot_test.go
index 8bbcf1a..7fb99d1 100644
--- a/snapshot_test.go
+++ b/snapshot_test.go
@@ -11,6 +11,7 @@
"path/filepath"
"testing"
+ "v.io/jiri/gitutil"
"v.io/jiri/jiri"
"v.io/jiri/jiritest"
"v.io/jiri/project"
@@ -18,6 +19,9 @@
)
func createLabelDir(t *testing.T, jirix *jiri.X, snapshotDir, name string, snapshots []string) {
+ if snapshotDir == "" {
+ snapshotDir = filepath.Join(jirix.Root, defaultSnapshotDir)
+ }
s := jirix.NewSeq()
labelDir, perm := filepath.Join(snapshotDir, "labels", name), os.FileMode(0700)
if err := s.MkdirAll(labelDir, perm).Done(); err != nil {
@@ -60,21 +64,20 @@
}
func TestList(t *testing.T) {
+ resetFlags()
fake, cleanup := jiritest.NewFakeJiriRoot(t)
defer cleanup()
- remoteSnapshotDir := fake.X.RemoteSnapshotDir()
- localSnapshotDir := fake.X.LocalSnapshotDir()
+ snapshotDir1 := "" // Should use default dir.
+ snapshotDir2 := filepath.Join(fake.X.Root, "some/other/dir")
// Create a test suite.
tests := []config{
config{
- remote: false,
- dir: localSnapshotDir,
+ dir: snapshotDir1,
},
config{
- remote: true,
- dir: remoteSnapshotDir,
+ dir: snapshotDir2,
},
}
labels := []label{
@@ -89,7 +92,7 @@
}
for _, test := range tests {
- remoteFlag = test.remote
+ snapshotDirFlag = test.dir
// Create the snapshots directory and populate it with the
// data specified by the test suite.
for _, label := range labels {
@@ -174,7 +177,187 @@
}
}
+func resetFlags() {
+ snapshotDirFlag = ""
+ pushRemoteFlag = false
+ remoteFlag = false
+}
+
+func TestGetSnapshotDir(t *testing.T) {
+ resetFlags()
+ defer resetFlags()
+ fake, cleanup := jiritest.NewFakeJiriRoot(t)
+ defer cleanup()
+
+ // With all flags at default values, snapshot dir should be default.
+ resetFlags()
+ got, err := getSnapshotDir(fake.X)
+ if err != nil {
+ t.Fatalf("getSnapshotDir() failed: %v\n", err)
+ }
+ if want := filepath.Join(fake.X.Root, defaultSnapshotDir); got != want {
+ t.Errorf("unexpected snapshot dir: got %v want %v", got, want)
+ }
+
+ // With remote flag set, snapshot dir should be JIRI_ROOT/.manifest/v2/snapshot.
+ resetFlags()
+ remoteFlag = true
+ got, err = getSnapshotDir(fake.X)
+ if err != nil {
+ t.Fatalf("getSnapshotDir() failed: %v\n", err)
+ }
+ if want := filepath.Join(fake.X.Root, ".manifest", "v2", "snapshot"); got != want {
+ t.Errorf("unexpected snapshot dir: got %v want %v", got, want)
+ }
+
+ // With dir flag set to absolute path, snapshot dir should be value of dir
+ // flag.
+ resetFlags()
+ tempDir, err := fake.X.NewSeq().TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir() failed: %v", err)
+ }
+ defer fake.X.NewSeq().RemoveAll(tempDir).Done()
+ snapshotDirFlag = tempDir
+ got, err = getSnapshotDir(fake.X)
+ if err != nil {
+ t.Fatalf("getSnapshotDir() failed: %v\n", err)
+ }
+ if want := snapshotDirFlag; got != want {
+ t.Errorf("unexpected snapshot dir: got %v want %v", got, want)
+ }
+
+ // With dir flag set to relative path, snapshot dir should absolute path
+ // rooted at current working dir.
+ resetFlags()
+ snapshotDirFlag = "some/relative/path"
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("os.Getwd() failed: %v", err)
+ }
+ got, err = getSnapshotDir(fake.X)
+ if err != nil {
+ t.Fatalf("getSnapshotDir() failed: %v\n", err)
+ }
+ if want := filepath.Join(cwd, snapshotDirFlag); got != want {
+ t.Errorf("unexpected snapshot dir: got %v want %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")
+ }
+}
+
+// TestCreatePushRemote checks that creating a snapshot with the -push-remote
+// flag causes the snapshot to be committed and pushed upstream.
+func TestCreatePushRemote(t *testing.T) {
+ resetFlags()
+ defer resetFlags()
+
+ fake, cleanup := jiritest.NewFakeJiriRoot(t)
+ defer cleanup()
+
+ fake.EnableRemoteManifestPush()
+ defer fake.DisableRemoteManifestPush()
+
+ manifestDir := filepath.Join(fake.X.Root, ".manifest")
+ snapshotDir := filepath.Join(manifestDir, "snapshot")
+ label := "test"
+
+ git := gitutil.New(fake.X.NewSeq(), manifestDir)
+ commitCount, err := git.CountCommits("master", "")
+ if err != nil {
+ t.Fatalf("git.CountCommits(\"master\", \"\") failed: %v", err)
+ }
+
+ // Create snapshot with -push-remote flag set to true.
+ snapshotDirFlag = snapshotDir
+ pushRemoteFlag = true
+ if err := runSnapshotCreate(fake.X, []string{label}); err != nil {
+ t.Fatalf("%v", err)
+ }
+
+ // Check that repo has one new commit.
+ newCommitCount, err := git.CountCommits("master", "")
+ if err != nil {
+ t.Fatalf("git.CountCommits(\"master\", \"\") failed: %v", err)
+ }
+ if got, want := newCommitCount, commitCount+1; got != want {
+ t.Errorf("unexpected commit count: got %v want %v", got, want)
+ }
+
+ // Check that new label is commited.
+ labelFile := filepath.Join(snapshotDir, "labels", label)
+ if !git.IsFileCommitted(labelFile) {
+ t.Errorf("expected file %v to be committed but it was not", labelFile)
+ }
+}
+
+// TestCreateDeprecated tests "local" and "remote" snapshot creation.
+// TODO(nlacasse): Delete this test once the old -remote flag has been removed.
+// The new snapshot behavior is tested in TestCreate and TestCreatePushRemote.
+func TestCreateDeprecated(t *testing.T) {
+ resetFlags()
+ defer resetFlags()
fake, cleanup := jiritest.NewFakeJiriRoot(t)
defer cleanup()
s := fake.X.NewSeq()
@@ -221,7 +404,7 @@
// Check that invoking the UpdateUniverse() with the local
// snapshot restores the local repositories.
- snapshotDir := fake.X.LocalSnapshotDir()
+ snapshotDir := filepath.Join(fake.X.Root, defaultSnapshotDir)
snapshotFile := filepath.Join(snapshotDir, "test-local")
localX := fake.X.Clone(tool.ContextOpts{
Manifest: &snapshotFile,