summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py90
-rwxr-xr-xtests.branching/branch-cleans-up-on-failure.script28
-rw-r--r--tests.branching/branch-cleans-up-on-failure.stderr1
-rwxr-xr-xtests.branching/checkout-cleans-up-on-failure.script27
-rw-r--r--tests.branching/checkout-cleans-up-on-failure.stderr1
5 files changed, 117 insertions, 30 deletions
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 0943e8b6..714f2838 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -16,9 +16,11 @@
import cliapp
import copy
-import os
-import json
import glob
+import json
+import logging
+import os
+import shutil
import socket
import tempfile
import time
@@ -251,6 +253,26 @@ class BranchAndMergePlugin(cliapp.Plugin):
return path
@staticmethod
+ def remove_branch_dir_safe(workspace, branch):
+ # This function avoids throwing any exceptions, so it is safe to call
+ # inside an 'except' block without altering the backtrace.
+
+ def handle_error(function, path, excinfo):
+ logging.warning ("Warning: error while trying to clean up %s: %s" %
+ (path, excinfo))
+
+ branch_dir = os.path.join(workspace, branch)
+ shutil.rmtree(branch_dir, onerror=handle_error)
+
+ # Remove parent directories that are empty too, avoiding exceptions
+ parent = os.path.dirname(branch_dir)
+ while parent != os.path.abspath(workspace):
+ if len(os.listdir(parent)) > 0 or os.path.islink(parent):
+ break
+ os.rmdir(parent)
+ parent = os.path.dirname(parent)
+
+ @staticmethod
def walk_special_directories(root_dir, special_subdir=None, max_subdirs=0):
assert(special_subdir is not None)
assert(max_subdirs >= 0)
@@ -368,26 +390,30 @@ class BranchAndMergePlugin(cliapp.Plugin):
branch_dir = os.path.join(workspace, new_branch)
os.makedirs(branch_dir)
- # Create a .morph-system-branch directory to clearly identify
- # this directory as a morph system branch.
- os.mkdir(os.path.join(branch_dir, '.morph-system-branch'))
+ try:
+ # Create a .morph-system-branch directory to clearly identify
+ # this directory as a morph system branch.
+ os.mkdir(os.path.join(branch_dir, '.morph-system-branch'))
- # Remember the system branch name and the repository we branched
- # off from initially.
- self.set_branch_config(branch_dir, 'branch.name', new_branch)
- self.set_branch_config(branch_dir, 'branch.root', repo)
+ # Remember the system branch name and the repository we branched
+ # off from initially.
+ self.set_branch_config(branch_dir, 'branch.name', new_branch)
+ self.set_branch_config(branch_dir, 'branch.root', repo)
- # Generate a UUID for the branch. We will use this for naming
- # temporary refs, e.g. building.
- self.set_branch_config(branch_dir, 'branch.uuid', uuid.uuid4().hex)
+ # Generate a UUID for the branch. We will use this for naming
+ # temporary refs, e.g. building.
+ self.set_branch_config(branch_dir, 'branch.uuid', uuid.uuid4().hex)
- # Clone into system branch directory.
- repo_dir = os.path.join(branch_dir, self.convert_uri_to_path(repo))
- self.clone_to_directory(repo_dir, repo, commit)
+ # Clone into system branch directory.
+ repo_dir = os.path.join(branch_dir, self.convert_uri_to_path(repo))
+ self.clone_to_directory(repo_dir, repo, commit)
- # Create a new branch in the local morphs repository.
- self.app.runcmd(['git', 'checkout', '-b', new_branch, commit],
- cwd=repo_dir)
+ # Create a new branch in the local morphs repository.
+ self.app.runcmd(['git', 'checkout', '-b', new_branch, commit],
+ cwd=repo_dir)
+ except:
+ self.remove_branch_dir_safe(workspace, new_branch)
+ raise
def checkout(self, args):
'''Check out an existing system branch.'''
@@ -404,21 +430,25 @@ class BranchAndMergePlugin(cliapp.Plugin):
branch_dir = os.path.join(workspace, system_branch)
os.makedirs(branch_dir)
- # Create a .morph-system-branch directory to clearly identify
- # this directory as a morph system branch.
- os.mkdir(os.path.join(branch_dir, '.morph-system-branch'))
+ try:
+ # Create a .morph-system-branch directory to clearly identify
+ # this directory as a morph system branch.
+ os.mkdir(os.path.join(branch_dir, '.morph-system-branch'))
- # Remember the system branch name and the repository we
- # branched off from.
- self.set_branch_config(branch_dir, 'branch.name', system_branch)
- self.set_branch_config(branch_dir, 'branch.root', repo)
+ # Remember the system branch name and the repository we
+ # branched off from.
+ self.set_branch_config(branch_dir, 'branch.name', system_branch)
+ self.set_branch_config(branch_dir, 'branch.root', repo)
- # Generate a UUID for the branch.
- self.set_branch_config(branch_dir, 'branch.uuid', uuid.uuid4().hex)
+ # Generate a UUID for the branch.
+ self.set_branch_config(branch_dir, 'branch.uuid', uuid.uuid4().hex)
- # Clone into system branch directory.
- repo_dir = os.path.join(branch_dir, self.convert_uri_to_path(repo))
- self.clone_to_directory(repo_dir, repo, system_branch)
+ # Clone into system branch directory.
+ repo_dir = os.path.join(branch_dir, self.convert_uri_to_path(repo))
+ self.clone_to_directory(repo_dir, repo, system_branch)
+ except:
+ self.remove_branch_dir_safe(workspace, system_branch)
+ raise
def show_system_branch(self, args):
'''Print name of current system branch.'''
diff --git a/tests.branching/branch-cleans-up-on-failure.script b/tests.branching/branch-cleans-up-on-failure.script
new file mode 100755
index 00000000..4036046c
--- /dev/null
+++ b/tests.branching/branch-cleans-up-on-failure.script
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Copyright (C) 2012 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# If a command fails, the state of the workspace should be as if the command
+# was never run
+
+set -eu
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+
+# This will fail because we're trying to branch off a ref that doesn't exist
+"$SRCDIR/scripts/test-morph" branch baserock:morphs foo/bar invalid-ref || true
+
+[ ! -d "$DATADIR/workspace/foo" ]
diff --git a/tests.branching/branch-cleans-up-on-failure.stderr b/tests.branching/branch-cleans-up-on-failure.stderr
new file mode 100644
index 00000000..5465e700
--- /dev/null
+++ b/tests.branching/branch-cleans-up-on-failure.stderr
@@ -0,0 +1 @@
+ERROR: Failed to check out file://TMP/morphs:invalid-ref into TMP/workspace/foo/bar/baserock:morphs
diff --git a/tests.branching/checkout-cleans-up-on-failure.script b/tests.branching/checkout-cleans-up-on-failure.script
new file mode 100755
index 00000000..b2a59e6c
--- /dev/null
+++ b/tests.branching/checkout-cleans-up-on-failure.script
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright (C) 2012 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# If a command fails, the state of the workspace should be as if the command
+# was never run
+
+set -eu
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+
+"$SRCDIR/scripts/test-morph" checkout baserock:morphs i/do/not/exist || true
+
+[ ! -d "$DATADIR/workspace/i" ]
diff --git a/tests.branching/checkout-cleans-up-on-failure.stderr b/tests.branching/checkout-cleans-up-on-failure.stderr
new file mode 100644
index 00000000..472764dd
--- /dev/null
+++ b/tests.branching/checkout-cleans-up-on-failure.stderr
@@ -0,0 +1 @@
+ERROR: Failed to check out file://TMP/morphs:i/do/not/exist into TMP/workspace/i/do/not/exist/baserock:morphs