summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2012-10-12 17:49:27 +0100
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2012-10-12 17:49:27 +0100
commitcf7ed1cb79d4862c92261ac57a27b082a8f10f84 (patch)
treee3f28dc551cd164e00ec76d46a209b93e474778b
parent5a430fdf91be1c569d1f1b8d8e3de929a20c2e1b (diff)
parent4249b7ed46d383b48aa1fbcdb1fa6459022fb4db (diff)
downloaddefinitions-cf7ed1cb79d4862c92261ac57a27b082a8f10f84.tar.gz
Merge branch 'samthursfield/morph-status'
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py135
-rwxr-xr-xtests.branching/status-in-clean-branch.script26
-rw-r--r--tests.branching/status-in-clean-branch.stdout3
-rwxr-xr-xtests.branching/status-in-dirty-branch.script39
-rw-r--r--tests.branching/status-in-dirty-branch.stdout5
-rwxr-xr-xtests.branching/status-in-workspace.script29
-rw-r--r--tests.branching/status-in-workspace.stdout4
7 files changed, 208 insertions, 33 deletions
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 6713fce9..384f0550 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -36,17 +36,12 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.init_changelog()
def enable(self):
+ # User-facing commands
self.app.add_subcommand('init', self.init, arg_synopsis='[DIR]')
- self.app.add_subcommand('workspace', self.workspace,
- arg_synopsis='')
self.app.add_subcommand('branch', self.branch,
arg_synopsis='REPO NEW [OLD]')
self.app.add_subcommand('checkout', self.checkout,
arg_synopsis='REPO BRANCH')
- self.app.add_subcommand('show-system-branch', self.show_system_branch,
- arg_synopsis='')
- self.app.add_subcommand('show-branch-root', self.show_branch_root,
- arg_synopsis='')
self.app.add_subcommand('merge', self.merge,
arg_synopsis='BRANCH')
self.app.add_subcommand('edit', self.edit,
@@ -55,9 +50,20 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.app.add_subcommand('unpetrify', self.unpetrify)
self.app.add_subcommand('build', self.build,
arg_synopsis='SYSTEM')
+ self.app.add_subcommand('status', self.status)
+
+ # Advanced commands
self.app.add_subcommand('foreach', self.foreach,
arg_synopsis='COMMAND')
+ # Plumbing commands (FIXME: should be hidden from --help by default)
+ self.app.add_subcommand('workspace', self.workspace,
+ arg_synopsis='')
+ self.app.add_subcommand('show-system-branch', self.show_system_branch,
+ arg_synopsis='')
+ self.app.add_subcommand('show-branch-root', self.show_branch_root,
+ arg_synopsis='')
+
def disable(self):
pass
@@ -119,7 +125,12 @@ class BranchAndMergePlugin(cliapp.Plugin):
def find_repository(self, branch_dir, repo):
for dirname in self.walk_special_directories(branch_dir,
special_subdir='.git'):
- original_repo = self.get_repo_config(dirname, 'morph.repository')
+ try:
+ original_repo = self.get_repo_config(
+ dirname, 'morph.repository')
+ except cliapp.AppException:
+ # The user may have manually put a git repo in the branch
+ continue
if repo == original_repo:
return dirname
return None
@@ -148,6 +159,15 @@ class BranchAndMergePlugin(cliapp.Plugin):
value = self.app.runcmd(['git', 'config', option], cwd=repo_dir)
return value.strip()
+ def get_head(self, repo_path):
+ '''Return the ref that the working tree is on for a repo'''
+
+ ref = self.app.runcmd(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
+ cwd=repo_path).strip()
+ if ref == 'HEAD':
+ ref = 'detached HEAD'
+ return ref
+
def get_uncommitted_changes(self, repo_dir, env={}):
status = self.app.runcmd(['git', 'status', '--porcelain'],
cwd=repo_dir, env=env)
@@ -421,6 +441,18 @@ class BranchAndMergePlugin(cliapp.Plugin):
parent = os.path.dirname(parent)
@staticmethod
+ def iterate_branch_repos(branch_path, root_repo_path):
+ '''Produces a sorted list of component repos in a branch checkout'''
+
+ dirs = [d for d in BranchAndMergePlugin.walk_special_directories(
+ branch_path, special_subdir='.git')
+ if not os.path.samefile(d, root_repo_path)]
+ dirs.sort()
+
+ for d in [root_repo_path] + dirs:
+ yield d
+
+ @staticmethod
def walk_special_directories(root_dir, special_subdir=None, max_subdirs=0):
assert(special_subdir is not None)
assert(max_subdirs >= 0)
@@ -472,11 +504,6 @@ class BranchAndMergePlugin(cliapp.Plugin):
os.mkdir(os.path.join(dirname, '.morph'))
self.app.status(msg='Initialized morph workspace', chatty=True)
- def workspace(self, args):
- '''Find morph workspace directory from current working directory.'''
-
- self.app.output.write('%s\n' % self.deduce_workspace())
-
def branch(self, args):
'''Branch the whole system.'''
@@ -560,20 +587,6 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.remove_branch_dir_safe(workspace, system_branch)
raise
- def show_system_branch(self, args):
- '''Print name of current system branch.'''
-
- branch, dirname = self.deduce_system_branch()
- self.app.output.write('%s\n' % branch)
-
- def show_branch_root(self, args):
- '''Print name of the repository that was branched off from.'''
-
- workspace = self.deduce_workspace()
- system_branch, branch_dir = self.deduce_system_branch()
- branch_root = self.get_branch_config(branch_dir, 'branch.root')
- self.app.output.write('%s\n' % branch_root)
-
def checkout_repository(self, branch_dir, repo, ref, parent_ref=None):
'''Make a chunk or stratum repository available for a system branch
@@ -1299,6 +1312,48 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.app.runcmd(['git', 'push', 'origin',
':%s' % info['build-ref']], cwd=info['dirname'])
+ def status(self, args):
+ if len(args) != 0:
+ raise cliapp.AppException('morph status takes no arguments')
+
+ workspace = self.deduce_workspace()
+ try:
+ branch, branch_path = self.deduce_system_branch()
+ except cliapp.AppException:
+ branch = None
+
+ if branch is None:
+ self.app.output.write("System branches in current workspace:\n")
+ for dirname in self.walk_special_directories(
+ workspace, special_subdir='.morph-system-branch'):
+ branch = self.get_branch_config(dirname, 'branch.name')
+ self.app.output.write(" %s\n" % branch)
+ return
+
+ root_repo = self.get_branch_config(branch_path, 'branch.root')
+ root_repo_path = self.find_repository(branch_path, root_repo)
+
+ self.app.output.write("On branch %s, root %s\n" % (branch, root_repo))
+
+ has_uncommitted_changes = False
+ for d in self.iterate_branch_repos(branch_path, root_repo_path):
+ try:
+ repo = self.get_repo_config(d, 'morph.repository')
+ except cliapp.AppException:
+ self.app.output.write(
+ ' %s: not part of system branch\n' % d)
+ continue
+ head = self.get_head(d)
+ if head != branch:
+ self.app.output.write(
+ ' %s: unexpected ref checked out "%s"\n' % (repo, head))
+ if len(self.get_uncommitted_changes(d)) > 0:
+ has_uncommitted_changes = True
+ self.app.output.write(' %s: uncommitted changes\n' % repo)
+
+ if not has_uncommitted_changes:
+ self.app.output.write("\nNo repos have outstanding changes.\n")
+
def foreach(self, args):
'''Run a command in each repository checked out in a system branch
@@ -1319,14 +1374,9 @@ class BranchAndMergePlugin(cliapp.Plugin):
branch, branch_path = self.deduce_system_branch()
root_repo = self.get_branch_config(branch_path, 'branch.root')
- root_repo_dir = self.convert_uri_to_path(root_repo)
- root_repo_path = os.path.join(branch_path, root_repo_dir)
+ root_repo_path = self.find_repository(branch_path, root_repo)
- dirs = [d for d in self.walk_special_directories(
- branch_path, special_subdir='.git')
- if not os.path.samefile(d, root_repo_path)]
- dirs.sort()
- for d in [root_repo_path] + dirs:
+ for d in self.iterate_branch_repos(branch_path, root_repo_path):
try:
repo = self.get_repo_config(d, 'morph.repository')
except cliapp.AppException:
@@ -1342,3 +1392,22 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.app.output.write(error)
raise cliapp.AppException(
'Command failed at repo %s: %s' % (repo, ' '.join(args)))
+
+ def workspace(self, args):
+ '''Find morph workspace directory from current working directory.'''
+
+ self.app.output.write('%s\n' % self.deduce_workspace())
+
+ def show_system_branch(self, args):
+ '''Print name of current system branch.'''
+
+ branch, dirname = self.deduce_system_branch()
+ self.app.output.write('%s\n' % branch)
+
+ def show_branch_root(self, args):
+ '''Print name of the repository that was branched off from.'''
+
+ workspace = self.deduce_workspace()
+ system_branch, branch_dir = self.deduce_system_branch()
+ branch_root = self.get_branch_config(branch_dir, 'branch.root')
+ self.app.output.write('%s\n' % branch_root)
diff --git a/tests.branching/status-in-clean-branch.script b/tests.branching/status-in-clean-branch.script
new file mode 100755
index 00000000..c102d287
--- /dev/null
+++ b/tests.branching/status-in-clean-branch.script
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Copyright (C) 2011, 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.
+
+
+# 'morph status' within a branch
+
+set -eu
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init .
+"$SRCDIR/scripts/test-morph" branch baserock:morphs test
+
+"$SRCDIR/scripts/test-morph" status
diff --git a/tests.branching/status-in-clean-branch.stdout b/tests.branching/status-in-clean-branch.stdout
new file mode 100644
index 00000000..d8468519
--- /dev/null
+++ b/tests.branching/status-in-clean-branch.stdout
@@ -0,0 +1,3 @@
+On branch test, root baserock:morphs
+
+No repos have outstanding changes.
diff --git a/tests.branching/status-in-dirty-branch.script b/tests.branching/status-in-dirty-branch.script
new file mode 100755
index 00000000..36ed781d
--- /dev/null
+++ b/tests.branching/status-in-dirty-branch.script
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Copyright (C) 2011, 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.
+
+
+# 'morph status' within a branch
+
+set -eu
+
+. "$SRCDIR/tests.branching/setup-3rd-party-strata"
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" branch baserock:morphs test
+
+# Make the branch have some interesting changes and pitfalls
+cd test
+"$SRCDIR/scripts/test-morph" edit hello-system stratum2 hello
+
+cd baserock:stratum2-hello
+git checkout -q master
+
+cd ..
+mkdir red-herring
+cd red-herring
+git init -q .
+
+"$SRCDIR/scripts/test-morph" status
diff --git a/tests.branching/status-in-dirty-branch.stdout b/tests.branching/status-in-dirty-branch.stdout
new file mode 100644
index 00000000..a81aa765
--- /dev/null
+++ b/tests.branching/status-in-dirty-branch.stdout
@@ -0,0 +1,5 @@
+On branch test, root baserock:morphs
+ baserock:morphs: uncommitted changes
+ baserock:external-strata: uncommitted changes
+ baserock:stratum2-hello: unexpected ref checked out "master"
+ TMP/workspace/test/red-herring: not part of system branch
diff --git a/tests.branching/status-in-workspace.script b/tests.branching/status-in-workspace.script
new file mode 100755
index 00000000..5e13b433
--- /dev/null
+++ b/tests.branching/status-in-workspace.script
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Copyright (C) 2011, 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.
+
+
+# 'morph status' within a workspace
+
+set -eu
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init .
+"$SRCDIR/scripts/test-morph" checkout baserock:morphs master
+"$SRCDIR/scripts/test-morph" branch baserock:morphs a/b/c/d/e/foo
+"$SRCDIR/scripts/test-morph" branch baserock:morphs a/b/c/d/e/bar
+mkdir a/b/c/red-herring
+
+"$SRCDIR/scripts/test-morph" status
diff --git a/tests.branching/status-in-workspace.stdout b/tests.branching/status-in-workspace.stdout
new file mode 100644
index 00000000..8d34a8a6
--- /dev/null
+++ b/tests.branching/status-in-workspace.stdout
@@ -0,0 +1,4 @@
+System branches in current workspace:
+ master
+ a/b/c/d/e/bar
+ a/b/c/d/e/foo