diff options
Diffstat (limited to 'morphlib/app.py')
-rwxr-xr-x | morphlib/app.py | 338 |
1 files changed, 170 insertions, 168 deletions
diff --git a/morphlib/app.py b/morphlib/app.py index 491adb16..3e4a0bf5 100755 --- a/morphlib/app.py +++ b/morphlib/app.py @@ -1,14 +1,14 @@ # 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. @@ -29,21 +29,21 @@ import morphlib defaults = { 'repo-alias': [ - 'upstream=' + ('upstream=' 'git://roadtrain.codethink.co.uk/delta/#' - 'gitano@roadtrain.codethink.co.uk:delta/', - 'baserock=' + 'gitano@roadtrain.codethink.co.uk:delta/'), + ('baserock=' 'git://roadtrain.codethink.co.uk/baserock/#' - 'gitano@roadtrain.codethink.co.uk:baserock/', - 'freedesktop=' + 'gitano@roadtrain.codethink.co.uk:baserock/'), + ('freedesktop=' 'git://anongit.freedesktop.org/#' - 'ssh://git.freedesktop.org/', - 'gnome=' + 'ssh://git.freedesktop.org/'), + ('gnome=' 'git://git.gnome.org/%s#' - 'ssh://git.gnome.org/git/%s', - 'github=' + 'ssh://git.gnome.org/git/%s'), + ('github=' 'git://github.com/%s#' - 'git@github.com:%s', + 'git@github.com:%s'), ], 'cachedir': os.path.expanduser('~/.cache/morph'), 'max-jobs': morphlib.util.make_concurrency(), @@ -57,13 +57,13 @@ defaults = { class BuildCommand(object): '''High level logic for building. - + This controls how the whole build process goes. This is a separate class to enable easy experimentation of different approaches to the various parts of the process. - + ''' - + def __init__(self, app): self.app = app self.build_env = self.new_build_env() @@ -75,7 +75,7 @@ class BuildCommand(object): '''Build triplets specified on command line.''' self.app.status(msg='Build starts', chatty=True) - + for repo_name, ref, filename in self.app._itertriplets(args): self.app.status(msg='Building %(repo_name)s %(ref)s %(filename)s', repo_name=repo_name, ref=ref, filename=filename) @@ -111,7 +111,7 @@ class BuildCommand(object): '''Create a new directory for the local artifact cache.''' artifact_cachedir = os.path.join( - self.app.settings['cachedir'], 'artifacts') + self.app.settings['cachedir'], 'artifacts') if not os.path.exists(artifact_cachedir): os.mkdir(artifact_cachedir) return artifact_cachedir @@ -124,8 +124,8 @@ class BuildCommand(object): gits_dir = os.path.join(cachedir, 'gits') bundle_base_url = self.app.settings['bundle-server'] repo_resolver = morphlib.repoaliasresolver.RepoAliasResolver(aliases) - lrc = morphlib.localrepocache.LocalRepoCache(self.app, - gits_dir, repo_resolver, bundle_base_url=bundle_base_url) + lrc = morphlib.localrepocache.LocalRepoCache( + self.app, gits_dir, repo_resolver, bundle_base_url=bundle_base_url) url = self.app.settings['cache-server'] if url: @@ -149,7 +149,7 @@ class BuildCommand(object): self.app.status(msg='Creating source pool', chatty=True) srcpool = self.app._create_source_pool( - self.lrc, self.rrc, (repo_name, ref, filename)) + self.lrc, self.rrc, (repo_name, ref, filename)) self.app.status(msg='Creating artifact resolver', chatty=True) ar = morphlib.artifactresolver.ArtifactResolver() @@ -164,7 +164,7 @@ class BuildCommand(object): self.app.status(msg='Computing build order', chatty=True) order = morphlib.buildorder.BuildOrder(artifacts) - + return order def build_in_order(self, order): @@ -173,13 +173,13 @@ class BuildCommand(object): chatty=True) for group in order.groups: self.build_artifacts(group) - + def build_artifacts(self, artifacts): '''Build a set of artifact. - + Typically, this would be a build group, but might be anything. At this level of abstraction we don't care. - + ''' self.app.status(msg='Building a set of artifacts', chatty=True) @@ -188,10 +188,10 @@ class BuildCommand(object): def build_artifact(self, artifact): '''Build one artifact. - + All the dependencies are assumed to be built and available in either the local or remote cache already. - + ''' self.app.status(msg='Checking if %(kind)s %(name)s needs building', @@ -213,7 +213,7 @@ class BuildCommand(object): if self.app.settings['staging-chroot']: if artifact.source.morphology.needs_staging_area: self.install_fillers(staging_area) - self.install_chunk_artifacts(staging_area, + self.install_chunk_artifacts(staging_area, deps) self.build_and_cache(staging_area, artifact) if self.app.settings['bootstrap']: @@ -270,8 +270,8 @@ class BuildCommand(object): # Update submodules. done = set() self.app._cache_repo_and_submodules( - self.lrc, artifact.source.repo.url, - artifact.source.sha1, done) + self.lrc, artifact.source.repo.url, + artifact.source.sha1, done) def cache_artifacts_locally(self, artifacts): '''Get artifacts missing from local cache from remote cache.''' @@ -280,22 +280,22 @@ class BuildCommand(object): shutil.copyfileobj(remote, local) remote.close() local.close() - + for artifact in artifacts: if not self.lac.has(artifact): self.app.status(msg='Fetching to local cache: ' 'artifact %(name)s', name=artifact.name) copy(self.rac.get(artifact), self.lac.put(artifact)) - + if artifact.source.morphology.needs_artifact_metadata_cached: if not self.lac.has_artifact_metadata(artifact, 'meta'): self.app.status(msg='Fetching to local cache: ' 'artifact metadata %(name)s', name=artifact.name) - copy(self.rac.get_artifact_metadata(artifact, 'meta'), + copy(self.rac.get_artifact_metadata(artifact, 'meta'), self.lac.put_artifact_metadata(artifact, 'meta')) - + def create_staging_area(self, artifact): '''Create the staging area for building a single artifact.''' @@ -318,36 +318,36 @@ class BuildCommand(object): if staging_area.dirname != '/': self.app.status(msg='Removing staging area') staging_area.remove() - if (staging_area.tempdir != '/' and - os.path.exists(staging_area.tempdir)): + temp_path = staging_area.tempdir + if temp_path != '/' and os.path.exists(temp_path): self.app.status(msg='Removing temporary staging directory') - shutil.rmtree(staging_area.tempdir) + shutil.rmtree(temp_path) def install_fillers(self, staging_area): '''Install staging fillers into the staging area. - + This must not be called in bootstrap mode. - + ''' - + logging.debug('Pre-populating staging area %s' % staging_area.dirname) - logging.debug('Fillers: %s' % - repr(self.app.settings['staging-filler'])) + logging.debug('Fillers: %s' % + repr(self.app.settings['staging-filler'])) for filename in self.app.settings['staging-filler']: with open(filename, 'rb') as f: - self.app.status(msg='Installing %(filename)s', + self.app.status(msg='Installing %(filename)s', filename=filename) staging_area.install_artifact(f) def install_chunk_artifacts(self, staging_area, artifacts): '''Install chunk artifacts into staging area. - + We only ever care about chunk artifacts as build dependencies, so this is not a generic artifact installer into staging area. Any non-chunk artifacts are silently ignored. - + All artifacts MUST be in the local artifact cache already. - + ''' for artifact in artifacts: @@ -363,9 +363,9 @@ class BuildCommand(object): self.app.status(msg='Starting actual build') setup_mounts = self.app.settings['staging-chroot'] - builder = morphlib.builder2.Builder(self.app, - staging_area, self.lac, self.rac, self.lrc, self.build_env, - self.app.settings['max-jobs'], setup_mounts) + builder = morphlib.builder2.Builder( + self.app, staging_area, self.lac, self.rac, self.lrc, + self.build_env, self.app.settings['max-jobs'], setup_mounts) return builder.build_and_cache(artifact) @@ -375,18 +375,19 @@ class Morph(cliapp.Application): system_repo_name = 'baserock:%s' % system_repo_base def add_settings(self): - self.settings.boolean(['verbose', 'v'], + self.settings.boolean(['verbose', 'v'], 'show what is happening in much detail') self.settings.boolean(['quiet', 'q'], 'show no output unless there is an error') self.settings.string_list(['repo-alias'], - 'define URL prefix aliases to allow repository ' - 'addresses to be shortened; ' - 'use alias=pullpattern=pushpattern ' - 'to allow alias:shortname to be used instead ' - 'of the full URL; the patterns must contain ' - 'a %s where the shortname gets replaced', - default=defaults['repo-alias']) + 'define URL prefix aliases to allow ' + 'repository addresses to be shortened; ' + 'use alias=pullpattern=pushpattern ' + 'to allow alias:shortname to be used ' + 'instead of the full URL; the patterns must ' + 'contain a %s where the shortname gets ' + 'replaced', + default=defaults['repo-alias']) self.settings.string(['bundle-server'], 'base URL to download bundles', metavar='URL', @@ -395,9 +396,9 @@ class Morph(cliapp.Application): 'HTTP URL of the morph cache server to use', metavar='URL', default=None) - self.settings.string(['cachedir'], + self.settings.string(['cachedir'], 'put build results in DIR', - metavar='DIR', + metavar='DIR', default=defaults['cachedir']) self.settings.string(['prefix'], 'build chunks with prefix PREFIX', @@ -415,65 +416,65 @@ class Morph(cliapp.Application): default='') self.settings.string(['tempdir'], 'temporary directory to use for builds ' - '(this is separate from just setting $TMPDIR ' - 'or /tmp because those are used internally ' - 'by things that cannot be on NFS, but ' - 'this setting can point at a directory in ' - 'NFS)', - metavar='DIR', + '(this is separate from just setting $TMPDIR ' + 'or /tmp because those are used internally ' + 'by things that cannot be on NFS, but ' + 'this setting can point at a directory in ' + 'NFS)', + metavar='DIR', default=os.environ.get('TMPDIR')) self.settings.boolean(['no-ccache'], 'do not use ccache') self.settings.string(['ccache-remotedir'], 'allow ccache to download objects from REMOTEDIR ' - 'if they are not cached locally', + 'if they are not cached locally', metavar='REMOTEDIR', default=defaults['ccache-remotedir']) self.settings.integer(['ccache-remotenlevels'], 'assume ccache directory objects are split into ' - 'NLEVELS levels of subdirectories', + 'NLEVELS levels of subdirectories', metavar='NLEVELS', default=defaults['ccache-remotenlevels']) self.settings.boolean(['no-distcc'], 'do not use distcc') - self.settings.integer(['max-jobs'], + self.settings.integer(['max-jobs'], 'run at most N parallel jobs with make (default ' - 'is to a value based on the number of CPUs ' - 'in the machine running morph', + 'is to a value based on the number of CPUs ' + 'in the machine running morph', metavar='N', default=defaults['max-jobs']) - self.settings.boolean(['keep-path'], + self.settings.boolean(['keep-path'], 'do not touch the PATH environment variable') - self.settings.boolean(['bootstrap'], + self.settings.boolean(['bootstrap'], 'build stuff in bootstrap mode; this is ' - 'DANGEROUS and will install stuff on your ' - 'system') + 'DANGEROUS and will install stuff on your ' + 'system') self.settings.boolean(['ignore-submodules'], 'do not cache repositories of git submodules ' 'or unpack them into the build directory') self.settings.boolean(['no-git-update'], 'do not update the cached git repositories ' - 'during a build (user must have done that ' - 'already using the update-gits subcommand)') + 'during a build (user must have done that ' + 'already using the update-gits subcommand)') self.settings.string_list(['staging-filler'], 'unpack BLOB into staging area for ' - 'non-bootstrap builds (this will ' - 'eventually be replaced with proper ' - 'build dependencies)', - metavar='BLOB') + 'non-bootstrap builds (this will ' + 'eventually be replaced with proper ' + 'build dependencies)', + metavar='BLOB') self.settings.boolean(['staging-chroot'], 'build things in a staging chroot ' - '(require real root to use)') + '(require real root to use)') def setup_plugin_manager(self): cliapp.Application.setup_plugin_manager(self) self.pluginmgr.locations += os.path.join( - os.path.dirname(morphlib.__file__), 'plugins') + os.path.dirname(morphlib.__file__), 'plugins') s = os.environ.get('MORPH_PLUGIN_PATH', '') self.pluginmgr.locations += s.split(':') - + self.hookmgr = cliapp.HookManager() self.hookmgr.new('new-build-command', cliapp.FilterHook()) self.system_kind_builder_factory = \ @@ -481,10 +482,10 @@ class Morph(cliapp.Application): def _itertriplets(self, args): '''Generate repo, ref, filename triples from args.''' - + if (len(args) % 3) != 0: raise cliapp.AppException('Argument list must have full triplets') - + while args: assert len(args) >= 2, args yield args[0], args[1], args[2] @@ -505,17 +506,17 @@ class Morph(cliapp.Application): def cmd_build(self, args): '''Build a binary from a morphology. - + Command line arguments are the repository, git tree-ish reference, and morphology filename. Morph takes care of building all dependencies before building the morphology. All generated binaries are put into the cache. - + (The triplet of command line arguments may be repeated as many times as necessary.) - + ''' - + build_command = BuildCommand(self) build_command = self.hookmgr.call('new-build-command', build_command) build_command.build(args) @@ -528,12 +529,12 @@ class Morph(cliapp.Application): cachedir = os.path.join(self.settings['cachedir'], 'gits') bundle_base_url = self.settings['bundle-server'] repo_resolver = morphlib.repoaliasresolver.RepoAliasResolver( - self.settings['repo-alias']) - lrc = morphlib.localrepocache.LocalRepoCache(self, - cachedir, repo_resolver, bundle_base_url) + self.settings['repo-alias']) + lrc = morphlib.localrepocache.LocalRepoCache( + self, cachedir, repo_resolver, bundle_base_url) if self.settings['cache-server']: rrc = morphlib.remoterepocache.RemoteRepoCache( - self.settings['cache-server'], repo_resolver) + self.settings['cache-server'], repo_resolver) else: rrc = None @@ -544,7 +545,7 @@ class Morph(cliapp.Application): resolver = morphlib.artifactresolver.ArtifactResolver() artifacts = resolver.resolve_artifacts(pool) - self.output.write('dependency graph for %s|%s|%s:\n' % + self.output.write('dependency graph for %s|%s|%s:\n' % (repo, ref, filename)) for artifact in sorted(artifacts, key=str): self.output.write(' %s\n' % artifact) @@ -563,7 +564,7 @@ class Morph(cliapp.Application): '''Resolves the sha1 of the ref in reponame and returns it. If update is True then this has the side-effect of updating - or cloning the repository into the local repo cache. + or cloning the repository into the local repo cache. ''' absref = None @@ -574,12 +575,12 @@ class Morph(cliapp.Application): reponame=reponame) repo.update() absref = repo.resolve_ref(ref) - elif rrc != None: + elif rrc is not None: try: absref = rrc.resolve_ref(reponame, ref) except: pass - if absref == None: + if absref is None: if update: self.status(msg='Caching git repository %(reponame)s', reponame=reponame) @@ -599,7 +600,7 @@ class Morph(cliapp.Application): reponame, ref, filename = queue.popleft() absref = self._resolveref(lrc, rrc, reponame, ref, update) morphology = morph_factory.get_morphology( - reponame, absref, filename) + reponame, absref, filename) visit(reponame, ref, filename, absref, morphology) if morphology['kind'] == 'system': queue.extend((reponame, ref, '%s.morph' % s) @@ -608,7 +609,7 @@ class Morph(cliapp.Application): if morphology['build-depends']: queue.extend((reponame, ref, '%s.morph' % s) for s in morphology['build-depends']) - queue.extend((c['repo'], c['ref'], '%s.morph' % c['morph']) + queue.extend((c['repo'], c['ref'], '%s.morph' % c['morph']) for c in morphology['sources']) def cmd_update_gits(self, args): @@ -617,20 +618,20 @@ class Morph(cliapp.Application): Parse the given morphologies, and their dependencies, and update all the git repositories referred to by them in the morph cache directory. - + ''' 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']) + self.settings['repo-alias']) bundle_base_url = self.settings['bundle-server'] - cache = morphlib.localrepocache.LocalRepoCache(self, - cachedir, repo_resolver, bundle_base_url) + cache = morphlib.localrepocache.LocalRepoCache( + self, cachedir, repo_resolver, bundle_base_url) subs_to_process = set() - + def visit(reponame, ref, filename, absref, morphology): self.status(msg='Updating %(repo_name)s %(ref)s %(filename)s', repo_name=reponame, ref=ref, filename=filename) @@ -645,7 +646,7 @@ class Morph(cliapp.Application): else: for submod in submodules: subs_to_process.add((submod.url, submod.commit)) - + self._traverse_morphs(self._itertriplets(args), cache, None, update=True, visit=visit) @@ -675,9 +676,9 @@ class Morph(cliapp.Application): def cmd_make_patch(self, args): '''Create a Trebuchet patch between two system images.''' - + logging.debug('cmd_make_patch starting') - + if len(args) != 7: raise cliapp.AppException('make-patch requires arguments: ' 'name of output file plus two triplest') @@ -691,15 +692,15 @@ class Morph(cliapp.Application): build_env = morphlib.buildenvironment.BuildEnvironment(self.settings) ckc = morphlib.cachekeycomputer.CacheKeyComputer(build_env) lac = morphlib.localartifactcache.LocalArtifactCache( - os.path.join(cachedir, 'artifacts')) + os.path.join(cachedir, 'artifacts')) repo_resolver = morphlib.repoaliasresolver.RepoAliasResolver( - self.settings['repo-alias']) - lrc = morphlib.localrepocache.LocalRepoCache(self, - os.path.join(cachedir, 'gits'), repo_resolver, - bundle_base_url=self.settings['bundle-server']) + self.settings['repo-alias']) + lrc = morphlib.localrepocache.LocalRepoCache( + self, os.path.join(cachedir, 'gits'), repo_resolver, + bundle_base_url=self.settings['bundle-server']) if self.settings['cache-server']: rrc = morphlib.remoterepocache.RemoteRepoCache( - self.settings['cache-server'], repo_resolver) + self.settings['cache-server'], repo_resolver) else: rrc = None @@ -710,14 +711,15 @@ class Morph(cliapp.Application): def get_artifact(repo_name, ref, filename): srcpool = self._create_source_pool( - lrc, rrc, (repo_name, ref, filename)) + lrc, rrc, (repo_name, ref, filename)) ar = morphlib.artifactresolver.ArtifactResolver() artifacts = ar.resolve_artifacts(srcpool) for artifact in artifacts: artifact.cache_key = ckc.compute_key(artifact) if the_one(artifact.source, repo_name, ref, filename): - a = morphlib.artifact.Artifact(artifact.source, - artifact.source.morphology['name']+'-rootfs') + a = morphlib.artifact.Artifact( + artifact.source, + artifact.source.morphology['name'] + '-rootfs') a.cache_key = artifact.cache_key return a @@ -726,7 +728,7 @@ class Morph(cliapp.Application): image_path_1 = lac.get(artifact1).name image_path_2 = lac.get(artifact2).name - + def setup(path): part = morphlib.fsutils.setup_device_mapping(self.runcmd, path) mount_point = tempfile.mkdtemp(dir=self.settings['tempdir']) @@ -762,10 +764,10 @@ class Morph(cliapp.Application): finally: cleanup(image_path_1, mount_point_1) cleanup(image_path_2, mount_point_2) - + def cmd_init(self, args): '''Initialize a mine.''' - + if not args: args = ['.'] elif len(args) > 1: @@ -779,7 +781,7 @@ class Morph(cliapp.Application): 'directory: %s' % dirname) else: raise cliapp.AppException('can only initialize an existing ' - 'empty directory: %s' % dirname) + 'empty directory: %s' % dirname) os.mkdir(os.path.join(dirname, '.morph')) @@ -794,24 +796,24 @@ class Morph(cliapp.Application): 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 _resolve_reponame(self, reponame): '''Return the full pull URL of a reponame.''' resolver = morphlib.repoaliasresolver.RepoAliasResolver( - self.settings['repo-alias']) + 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. @@ -819,36 +821,37 @@ class Morph(cliapp.Application): os.mkdir(self.settings['cachedir']) cachedir = os.path.join(self.settings['cachedir'], 'gits') repo_resolver = morphlib.repoaliasresolver.RepoAliasResolver( - self.settings['repo-alias']) + self.settings['repo-alias']) bundle_base_url = self.settings['bundle-server'] - cache = morphlib.localrepocache.LocalRepoCache(self, - cachedir, repo_resolver, bundle_base_url) + 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), + ('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 cmd_branch(self, args): '''Branch the whole system.''' - + if len(args) not in [1, 2]: raise cliapp.AppException('morph branch needs name of branch ' - 'as parameter') + 'as parameter') new_branch = args[0] commit = 'master' if len(args) == 1 else args[1] @@ -859,7 +862,7 @@ class Morph(cliapp.Application): # Clone into system branch directory. new_repo = os.path.join(new_branch, self.system_repo_base) self._clone_to_directory(new_repo, self.system_repo_name, commit) - + # Create a new branch in the local morphs repository. self.runcmd(['git', 'checkout', '-b', new_branch, commit], cwd=new_repo) @@ -869,7 +872,7 @@ class Morph(cliapp.Application): if len(args) != 1: raise cliapp.AppException('morph checkout needs name of ' - 'branch as parameter') + 'branch as parameter') system_branch = args[0] @@ -888,31 +891,31 @@ class Morph(cliapp.Application): 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) not in (1,2): + + if len(args) not in (1, 2): raise cliapp.AppException('morph edit must get a repository name ' - 'and commit ref as argument') + 'and commit ref as argument') mine_directory = self._deduce_mine_directory() system_branch = self._deduce_system_branch() @@ -932,10 +935,10 @@ class Morph(cliapp.Application): if ref is None: raise morphlib.Error('Cannot deduce commit to start edit from') - new_repo = os.path.join(mine_directory, system_branch, + 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) @@ -950,7 +953,7 @@ class Morph(cliapp.Application): 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, filename)) spec['ref'] = system_branch changed = True if changed: @@ -996,15 +999,15 @@ class Morph(cliapp.Application): 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') + '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:]: repo = self._resolve_reponame(repo) basename = os.path.basename(repo) @@ -1019,15 +1022,15 @@ class Morph(cliapp.Application): os.mkdir(self.settings['cachedir']) cachedir = os.path.join(self.settings['cachedir'], 'gits') repo_resolver = morphlib.repoaliasresolver.RepoAliasResolver( - self.settings['repo-alias']) + self.settings['repo-alias']) bundle_base_url = self.settings['bundle-server'] - cache = morphlib.localrepocache.LocalRepoCache(self, - cachedir, repo_resolver, bundle_base_url) - + cache = morphlib.localrepocache.LocalRepoCache( + self, cachedir, repo_resolver, bundle_base_url) + for filename in args: with open(filename) as f: morph = json.load(f) - + if morph['kind'] != 'stratum': self.status(msg='Not a stratum: %(filename)s', filename=filename) @@ -1039,28 +1042,28 @@ class Morph(cliapp.Application): reponame = source.get('repo', source['name']) ref = source['ref'] self.status(msg='Looking up sha1 for %(repo_name)s %(ref)s', - repo_name=reponame, + repo_name=reponame, ref=ref) repo = cache.get_repo(reponame) source['ref'] = repo.resolve_ref(ref) - + with open(filename, 'w') as f: json.dump(morph, f, indent=2) def status(self, **kwargs): '''Show user a status update. - + The keyword arguments are formatted and presented to the user in a pleasing manner. Some keywords are special: - + * ``msg`` is the message text; it can use ``%(foo)s`` to embed the value of keyword argument ``foo`` * ``chatty`` should be true when the message is only informative, and only useful for users who want to know everything (--verbose) * ``error`` should be true when it is an error message - + All other keywords are ignored unless embedded in ``msg``. - + ''' assert 'msg' in kwargs @@ -1077,7 +1080,7 @@ class Morph(cliapp.Application): logging.debug(text) else: logging.info(text) - + ok = verbose or error or (not quiet and not chatty) if ok: timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()) @@ -1100,11 +1103,10 @@ class Morph(cliapp.Application): self.status(msg='# %(cmdline)s', cmdline=' | '.join(commands), chatty=True) - + # Log the environment. for name in kwargs['env']: logging.debug('environment: %s=%s' % (name, kwargs['env'][name])) # run the command line return cliapp.Application.runcmd(self, argv, *args, **kwargs) - |