summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xmorphlib/app.py156
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py94
2 files changed, 94 insertions, 156 deletions
diff --git a/morphlib/app.py b/morphlib/app.py
index d36d7370..de292674 100755
--- a/morphlib/app.py
+++ b/morphlib/app.py
@@ -16,8 +16,6 @@
import cliapp
import collections
-import glob
-import json
import logging
import os
import shutil
@@ -576,160 +574,6 @@ class Morph(cliapp.Application):
category=DeprecationWarning)
return self.cache_repo_and_submodules(*args)
- 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 _resolve_reponame(self, reponame):
- '''Return the full pull URL of a reponame.'''
-
- resolver = morphlib.repoaliasresolver.RepoAliasResolver(
- self.settings['repo-alias'])
- return resolver.pull_url(reponame)
-
- def _clone_to_directory(self, dirname, reponame, ref):
- '''Clone a repository below a directory.
-
- As a side effect, clone it into the morph repository.
-
- '''
-
- # Setup.
- if not os.path.exists(self.settings['cachedir']):
- os.mkdir(self.settings['cachedir'])
- cachedir = os.path.join(self.settings['cachedir'], 'gits')
- repo_resolver = morphlib.repoaliasresolver.RepoAliasResolver(
- self.settings['repo-alias'])
- bundle_base_url = self.settings['bundle-server']
- cache = morphlib.localrepocache.LocalRepoCache(
- self, cachedir, repo_resolver, bundle_base_url)
-
- # Get the repository into the cache; make sure it is up to date.
- repo = cache.cache_repo(reponame)
- if not self.settings['no-git-update']:
- repo.update()
-
- # Clone it from cache to target directory.
- repo.checkout(ref, os.path.abspath(dirname))
-
- # Set the origin to point at the original repository.
- morphlib.git.set_remote(self.runcmd, dirname, 'origin', repo.url)
-
- # Add push url rewrite rule to .git/config.
- self.runcmd(['git', 'config',
- ('url.%s.pushInsteadOf' %
- repo_resolver.push_url(reponame)),
- repo_resolver.pull_url(reponame)], cwd=dirname)
-
- # Update remotes.
- self.runcmd(['git', 'remote', 'update'], cwd=dirname)
-
- 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_edit(self, args):
- '''Edit a component in a system branch.'''
-
- if len(args) not in (1, 2):
- raise cliapp.AppException('morph edit must get a repository name '
- 'and commit ref as argument')
-
- mine_directory = self._deduce_mine_directory()
- system_branch = self._deduce_system_branch()
- if system_branch is None:
- raise morphlib.Error('Cannot deduce system branch')
-
- morphs_dirname = os.path.join(mine_directory, system_branch, 'morphs')
- if morphs_dirname is None:
- raise morphlib.Error('Can not find morphs directory')
-
- repo = self._resolve_reponame(args[0])
-
- if len(args) == 2:
- ref = args[1]
- else:
- ref = self._find_edit_ref(morphs_dirname, repo)
- if ref is None:
- raise morphlib.Error('Cannot deduce commit to start edit from')
-
- new_repo = os.path.join(mine_directory, system_branch,
- os.path.basename(repo))
- self._clone_to_directory(new_repo, args[0], ref)
-
- 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)
-
- for filename, morph in self._morphs_for_repo(morphs_dirname, repo):
- changed = False
- for spec in morph['sources']:
- spec_repo = self._resolve_reponame(spec['repo'])
- if spec_repo == repo and spec['ref'] != system_branch:
- if self.settings['verbose']:
- print ('Replacing ref "%s" with "%s" in %s' %
- (spec['ref'], system_branch, filename))
- spec['ref'] = system_branch
- changed = True
- if changed:
- self._write_morphology(filename, morph)
-
- def _find_edit_ref(self, morphs_dirname, repo):
- for filename, morph in self._morphs_for_repo(morphs_dirname, repo):
- for spec in morph['sources']:
- spec_repo = self._resolve_reponame(spec['repo'])
- if spec_repo == repo:
- return spec['ref']
- return None
-
- def _load_morphologies(self, dirname):
- pattern = os.path.join(dirname, '*.morph')
- for filename in glob.glob(pattern):
- with open(filename) as f:
- text = f.read()
- morphology = morphlib.morph2.Morphology(text)
- yield filename, morphology
-
- def _morphs_for_repo(self, morphs_dirname, repo):
- for filename, morph in self._load_morphologies(morphs_dirname):
- if morph['kind'] == 'stratum':
- for spec in morph['sources']:
- spec_repo = self._resolve_reponame(spec['repo'])
- if spec_repo == repo:
- yield filename, morph
- break
-
- def _write_morphology(self, filename, morphology):
- as_dict = {}
- for key in morphology.keys():
- value = morphology[key]
- if value:
- as_dict[key] = value
- fd, tempname = tempfile.mkstemp(dir=os.path.dirname(filename))
- os.close(fd)
- with open(tempname, 'w') as f:
- json.dump(as_dict, fp=f, indent=4, sort_keys=True)
- f.write('\n')
- os.rename(tempname, filename)
-
def status(self, **kwargs):
'''Show user a status update.
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 0a2d92a1..910022e0 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -17,6 +17,8 @@
import cliapp
import os
import json
+import glob
+import tempfile
import morphlib
@@ -39,6 +41,8 @@ class BranchAndMergePlugin(cliapp.Plugin):
arg_synopsis='')
self.app.add_subcommand('merge', self.merge,
arg_synopsis='BRANCH REPO...')
+ self.app.add_subcommand('edit', self.edit,
+ arg_synopsis='REPO [REF]')
def disable(self):
pass
@@ -108,6 +112,45 @@ class BranchAndMergePlugin(cliapp.Plugin):
app.settings['repo-alias'])
return resolver.pull_url(reponame)
+ @staticmethod
+ def load_morphologies(dirname):
+ pattern = os.path.join(dirname, '*.morph')
+ for filename in glob.iglob(pattern):
+ with open(filename) as f:
+ text = f.read()
+ morphology = morphlib.morph2.Morphology(text)
+ yield filename, morphology
+
+ @classmethod
+ def morphs_for_repo(cls, app, morphs_dirname, repo):
+ for filename, morph in cls.load_morphologies(morphs_dirname):
+ if morph['kind'] == 'stratum':
+ for spec in morph['sources']:
+ spec_repo = cls.resolve_reponame(app, spec['repo'])
+ if spec_repo == repo:
+ yield filename, morph
+ break
+
+ @classmethod
+ def find_edit_ref(cls, app, morphs_dirname, repo):
+ for filename, morph in cls.morphs_for_repo(app, morphs_dirname, repo):
+ for spec in morph['sources']:
+ spec_repo = cls.resolve_reponame(app, spec['repo'])
+ if spec_repo == repo:
+ return spec['ref']
+ return None
+
+ @staticmethod
+ def write_morphology(filename, morphology):
+ as_dict = {}
+ for key in morphology.keys():
+ value = morphology[key]
+ if value:
+ as_dict[key] = value
+ with morphlib.savefile.SaveFile(filename, 'w') as f:
+ json.dump(as_dict, fp=f, indent=4, sort_keys=True)
+ f.write('\n')
+
def petrify(self, args):
'''Make refs to chunks be absolute SHA-1s.'''
@@ -236,3 +279,54 @@ class BranchAndMergePlugin(cliapp.Plugin):
pull_from = os.path.join(mine, other_branch, basename)
repo_dir = os.path.join(mine, this_branch, basename)
app.runcmd(['git', 'pull', pull_from, other_branch], cwd=repo_dir)
+
+ def edit(self, args):
+ '''Edit a component in a system branch.'''
+
+ if len(args) not in (1, 2):
+ raise cliapp.AppException('morph edit must get a repository name '
+ 'and commit ref as argument')
+
+ app = self.app
+ mine_directory = self.deduce_mine_directory()
+ system_branch = self.deduce_system_branch()
+ if system_branch is None:
+ raise morphlib.Error('Cannot deduce system branch')
+
+ morphs_dirname = os.path.join(mine_directory, system_branch, 'morphs')
+ if morphs_dirname is None:
+ raise morphlib.Error('Can not find morphs directory')
+
+ repo = self.resolve_reponame(app, args[0])
+
+ if len(args) == 2:
+ ref = args[1]
+ else:
+ ref = self.find_edit_ref(app, morphs_dirname, repo)
+ if ref is None:
+ raise morphlib.Error('Cannot deduce commit to start edit from')
+
+ new_repo = os.path.join(mine_directory, system_branch,
+ os.path.basename(repo))
+ self.clone_to_directory(app, new_repo, args[0], ref)
+
+ if system_branch == ref:
+ app.runcmd(['git', 'checkout', system_branch],
+ cwd=new_repo)
+ else:
+ app.runcmd(['git', 'checkout', '-b', system_branch, ref],
+ cwd=new_repo)
+
+ for filename, morph in self.morphs_for_repo(app, morphs_dirname, repo):
+ changed = False
+ for spec in morph['sources']:
+ spec_repo = self.resolve_reponame(app, spec['repo'])
+ if spec_repo == repo and spec['ref'] != system_branch:
+ app.status(msg='Replacing ref "%(ref)s" with "%(branch)s"'
+ 'in %(filename)s',
+ ref=spec['ref'], branch=system_branch,
+ filename=filename, chatty=True)
+ spec['ref'] = system_branch
+ changed = True
+ if changed:
+ self.write_morphology(filename, morph)