summaryrefslogtreecommitdiff
path: root/morph
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2012-03-26 15:15:25 +0100
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2012-03-26 15:15:25 +0100
commitca7900299dc32c7b59e896f5f4b9a38978f226a0 (patch)
treed1f15db7c51c83c1eb1fa11565adc2a295c48eec /morph
parent7d7d597afd0a562916f106d259f4ff78383f9631 (diff)
parent9e18d7cc163ab95524349567fc8c4205cd0f11ce (diff)
downloadmorph-ca7900299dc32c7b59e896f5f4b9a38978f226a0.tar.gz
Add rudimentary branch+merge support
Diffstat (limited to 'morph')
-rwxr-xr-xmorph168
1 files changed, 167 insertions, 1 deletions
diff --git a/morph b/morph
index 92fe5d76..754f3b8e 100755
--- a/morph
+++ b/morph
@@ -403,6 +403,172 @@ class Morph(cliapp.Application):
morphlib.fsutils.undo_device_mapping(ex, paths[name])
factory.remove_staging()
+ def cmd_init(self, args):
+ '''Initialize a mine.'''
+
+ if not args:
+ args = ['.']
+ elif len(args) > 1:
+ raise cliapp.AppException('init must get at most one argument')
+
+ dirname = args[0]
+
+ if os.path.exists(dirname):
+ if os.listdir(dirname) != []:
+ raise cliapp.AppException('can only initialize empty '
+ 'directory: %s' % dirname)
+ else:
+ raise cliapp.AppException('can only initialize an existing '
+ 'empty directory: %s' % dirname)
+
+ os.mkdir(os.path.join(dirname, '.morph'))
+
+ def _deduce_mine_directory(self):
+ dirname = os.getcwd()
+ while dirname != '/':
+ dot_morph = os.path.join(dirname, '.morph')
+ if os.path.isdir(dot_morph):
+ return dirname
+ dirname = os.path.dirname(dirname)
+ return None
+
+ def cmd_minedir(self, args):
+ '''Find morph mine directory from current working directory.'''
+
+ dirname = self._deduce_mine_directory()
+ if dirname is None:
+ raise cliapp.AppException("Can't find the mine directory")
+ self.output.write('%s\n' % dirname)
+
+ def _clone_to_directory(self, dirname, repo, ref):
+ '''Clone a repository below a directory.
+
+ As a side effect, clone it into the morph repository.
+
+ '''
+
+ # Get the repository into the cache.
+ tempdir = morphlib.tempdir.Tempdir(self.settings['tempdir'])
+ morph_loader = MorphologyLoader(self.settings)
+ source_manager = morphlib.sourcemanager.SourceManager(self,
+ update=not self.settings['no-git-update'])
+ treeish = source_manager.get_treeish(repo, ref)
+
+ # Clone it from cache to target directory.
+ morphlib.git.clone(dirname, treeish.repo, self.msg)
+
+ # Set the origin to point at the original repository.
+ morphlib.git.set_remote(dirname, 'origin', treeish.original_repo)
+
+ # Update remotes.
+ self.runcmd(['git', 'remote', 'update'], cwd=dirname)
+
+ def cmd_branch(self, args):
+ '''Branch the whole system.'''
+
+ if len(args) != 1:
+ raise cliapp.AppException('morph branch needs name of branch '
+ 'as parameter')
+
+ new_branch = args[0]
+ repo = 'morphs'
+ commit = 'master'
+
+ # Create the system branch directory.
+ os.makedirs(new_branch)
+
+ # Clone into system branch directory.
+ new_repo = os.path.join(new_branch, os.path.basename(repo))
+ self._clone_to_directory(new_repo, repo, commit)
+
+ # Create a new branch in the local morphs repository.
+ self.runcmd(['git', 'checkout', '-b', new_branch, commit],
+ cwd=new_repo)
+
+ def cmd_checkout(self, args):
+ '''Check out an existing system branch.'''
+
+ if len(args) != 1:
+ raise cliapp.AppException('morph checkout needs name of '
+ 'branch as parameter')
+
+ system_branch = args[0]
+ repo = 'morphs'
+
+ # Create the system branch directory.
+ os.makedirs(system_branch)
+
+ # Clone into system branch directory.
+ new_repo = os.path.join(system_branch, os.path.basename(repo))
+ self._clone_to_directory(new_repo, repo, system_branch)
+
+ def _deduce_system_branch(self):
+ minedir = self._deduce_mine_directory()
+ if minedir is None:
+ return None
+
+ if not minedir.endswith('/'):
+ minedir += '/'
+
+ cwd = os.getcwd()
+ if not cwd.startswith(minedir):
+ return None
+
+ return os.path.dirname(cwd[len(minedir):])
+
+ def cmd_show_system_branch(self, args):
+ '''Print name of current system branch.
+
+ This must be run in the system branch's ``morphs`` repository.
+
+ '''
+
+ system_branch = self._deduce_system_branch()
+ if system_branch is None:
+ raise cliapp.AppException("Can't determine system branch")
+ self.output.write('%s\n' % system_branch)
+
+ def cmd_edit(self, args):
+ '''Edit a component in a system branch.'''
+
+ if len(args) != 2:
+ raise cliapp.AppException('morph edit must get a repository name '
+ 'and commit ref as argument')
+
+ repo = args[0]
+ ref = args[1]
+
+ mine_directory = self._deduce_mine_directory()
+ system_branch = self._deduce_system_branch()
+ new_repo = os.path.join(mine_directory, system_branch,
+ os.path.basename(repo))
+ self._clone_to_directory(new_repo, repo, ref)
+
+ system_branch = self._deduce_system_branch()
+ if system_branch == ref:
+ self.runcmd(['git', 'checkout', system_branch],
+ cwd=new_repo)
+ else:
+ self.runcmd(['git', 'checkout', '-b', system_branch, ref],
+ cwd=new_repo)
+
+ def cmd_merge(self, args):
+ '''Merge specified repositories from another system branch.'''
+
+ if len(args) == 0:
+ raise cliapp.AppException('morph merge must get a branch name '
+ 'and some repo names as arguments')
+
+ other_branch = args[0]
+ mine = self._deduce_mine_directory()
+ this_branch = self._deduce_system_branch()
+
+ for repo in args[1:]:
+ basename = os.path.basename(repo)
+ pull_from = os.path.join(mine, other_branch, basename)
+ repo_dir = os.path.join(mine, this_branch, basename)
+ self.runcmd(['git', 'pull', pull_from, other_branch], cwd=repo_dir)
+
def msg(self, msg):
'''Show a message to the user about what is going on.'''
logging.debug(msg)
@@ -429,7 +595,7 @@ class Morph(cliapp.Application):
msg('# %s' % ' | '.join(commands))
# run the command line
- cliapp.Application.runcmd(self, argv, *args, **kwargs)
+ return cliapp.Application.runcmd(self, argv, *args, **kwargs)
# This is in morph so that policy is easily visible, and not embedded
# deep down in the call stack.