Delete project when create operation fails.
Don't leave behind stale state
Change-Id: I592e55dc89190d05e8ed6f029bfc541bdb7e8ae7
diff --git a/project/operations.go b/project/operations.go
index 1ec2486..53c3504 100644
--- a/project/operations.go
+++ b/project/operations.go
@@ -84,40 +84,8 @@
return "create"
}
-func (op createOperation) Run(jirix *jiri.X) (e error) {
- path, perm := filepath.Dir(op.destination), os.FileMode(0755)
-
- // Check the local file system.
- if _, err := os.Stat(op.destination); err != nil {
- if !os.IsNotExist(err) {
- return fmtError(err)
- }
- } else {
- if isEmpty, err := isEmpty(op.destination); err != nil {
- return err
- } else if !isEmpty {
- return fmt.Errorf("cannot create %q as it already exists and is not empty", op.destination)
- } else {
- if err := os.RemoveAll(op.destination); err != nil {
- return fmt.Errorf("Not able to delete %q", op.destination)
- }
- }
- }
- // Create a temporary directory for the initial setup of the
- // project to prevent an untimely termination from leaving the
- // root directory in an inconsistent state.
- if err := os.MkdirAll(path, perm); err != nil {
- return fmtError(err)
- }
-
- cache, err := op.project.CacheDirPath(jirix)
- if err != nil {
- return err
- }
- if !isPathDir(cache) {
- cache = ""
- }
-
+func (op createOperation) checkoutProject(jirix *jiri.X, cache string) error {
+ var err error
if jirix.Shared && cache != "" {
err = clone(jirix, cache, op.destination, gitutil.SharedOpt(true),
gitutil.NoCheckoutOpt(true), gitutil.DepthOpt(op.project.HistoryDepth))
@@ -131,15 +99,10 @@
gitutil.NoCheckoutOpt(true), gitutil.DepthOpt(op.project.HistoryDepth))
}
if err != nil {
- if err2 := os.RemoveAll(op.destination); err2 != nil {
- return fmt.Errorf("Not able to remove %q after clone failed: %s, original error: %s", op.destination, err2, err)
- }
return err
}
+
if err := os.Chmod(op.destination, os.FileMode(0755)); err != nil {
- if err2 := os.RemoveAll(op.destination); err2 != nil {
- return fmt.Errorf("Not able to remove %q after chmod failed: %s, original error: %s", op.destination, err2, fmtError(err))
- }
return fmtError(err)
}
@@ -165,6 +128,47 @@
return nil
}
+func (op createOperation) Run(jirix *jiri.X) (e error) {
+ path, perm := filepath.Dir(op.destination), os.FileMode(0755)
+
+ // Check the local file system.
+ if _, err := os.Stat(op.destination); err != nil {
+ if !os.IsNotExist(err) {
+ return fmtError(err)
+ }
+ } else {
+ if isEmpty, err := isEmpty(op.destination); err != nil {
+ return err
+ } else if !isEmpty {
+ return fmt.Errorf("cannot create %q as it already exists and is not empty", op.destination)
+ } else {
+ if err := os.RemoveAll(op.destination); err != nil {
+ return fmt.Errorf("Not able to delete %q", op.destination)
+ }
+ }
+ }
+
+ if err := os.MkdirAll(path, perm); err != nil {
+ return fmtError(err)
+ }
+
+ cache, err := op.project.CacheDirPath(jirix)
+ if err != nil {
+ return err
+ }
+ if !isPathDir(cache) {
+ cache = ""
+ }
+
+ if err := op.checkoutProject(jirix, cache); err != nil {
+ if err := os.RemoveAll(op.destination); err != nil {
+ jirix.Logger.Warningf("Not able to remove %q after create failed: %s", op.destination, err)
+ }
+ return err
+ }
+ return nil
+}
+
func (op createOperation) String() string {
return fmt.Sprintf("create project %q in %q and advance it to %q", op.project.Name, op.destination, fmtRevision(op.project.Revision))
}
diff --git a/project/project_test.go b/project/project_test.go
index ef60bcd..bbd22ec 100644
--- a/project/project_test.go
+++ b/project/project_test.go
@@ -1042,6 +1042,38 @@
}
}
+// TestUpdateUniverseWithBadRevision checks that UpdateUniverse
+// will not leave bad state behind.
+func TestUpdateUniverseWithBadRevision(t *testing.T) {
+ localProjects, fake, cleanup := setupUniverse(t)
+ defer cleanup()
+
+ 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 = "badrev"
+ }
+ projects = append(projects, p)
+ }
+ m.Projects = projects
+ if err := fake.WriteRemoteManifest(m); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := fake.UpdateUniverse(false); err == nil {
+ t.Fatal("should have thrown error")
+ }
+
+ if err := dirExists(localProjects[1].Path); err == nil {
+ t.Fatalf("expected project %q at path %q not to exist but it did", localProjects[1].Name, localProjects[1].Path)
+ }
+
+}
+
func commitChanges(t *testing.T, jirix *jiri.X, dir string) {
scm := gitutil.New(jirix, gitutil.UserNameOpt("John Doe"), gitutil.UserEmailOpt("john.doe@example.com"), gitutil.RootDirOpt(dir))
if err := scm.AddUpdatedFiles(); err != nil {