diff options
author | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2012-09-06 18:14:56 +0100 |
---|---|---|
committer | Jannis Pohlmann <jannis.pohlmann@codethink.co.uk> | 2012-09-10 11:37:01 +0000 |
commit | 6075afa879da2eba9468b913332b41ff23a4e269 (patch) | |
tree | 6eac5ca3e94f261692f8dfb3d0caac24b0e9b68a | |
parent | 7f493ba9b6c60f25e21c16fd85ce80ceec31f2fc (diff) | |
download | morph-6075afa879da2eba9468b913332b41ff23a4e269.tar.gz |
morph branch,checkout: Clean up the branch dir on failure
-rw-r--r-- | morphlib/plugins/branch_and_merge_plugin.py | 90 | ||||
-rwxr-xr-x | tests.branching/branch-cleans-up-on-failure.script | 28 | ||||
-rw-r--r-- | tests.branching/branch-cleans-up-on-failure.stderr | 1 | ||||
-rwxr-xr-x | tests.branching/checkout-cleans-up-on-failure.script | 27 | ||||
-rw-r--r-- | tests.branching/checkout-cleans-up-on-failure.stderr | 1 |
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 |