From 665ea01218dcba658d95b86014c7da5dd974a8a7 Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Fri, 1 May 2015 19:14:38 +0000 Subject: Add DefinitionsRepo class The intention is for this class to take over the from the Workspace and SystemBranch classes. It allows Morph to load and parse definitions from a Git repo, without requiring the user to run `morph checkout` or `morph branch`: it can operate from any normal Git repository. The class behaves differently when the Git repository is inside a Morph system-branch checkout made with `morph branch` or `morph checkout`, to avoid changing things under the feet of people who are used to those commands. Change-Id: I52a898efb9f6fb7f7e94c65b9ed38516bd51f49d --- morphlib/__init__.py | 1 + morphlib/buildbranch.py | 99 +++++++++-- morphlib/definitions_repo.py | 415 +++++++++++++++++++++++++++++++++++++++++++ morphlib/gitdir.py | 5 +- morphlib/sysbranchdir.py | 39 ++-- without-test-modules | 1 + 6 files changed, 521 insertions(+), 39 deletions(-) create mode 100644 morphlib/definitions_repo.py diff --git a/morphlib/__init__.py b/morphlib/__init__.py index 94b42580..551e04cb 100644 --- a/morphlib/__init__.py +++ b/morphlib/__init__.py @@ -60,6 +60,7 @@ import builder import cachedrepo import cachekeycomputer import cmdline_parse_utils +import definitions_repo import extensions import extractedtarball import fsutils diff --git a/morphlib/buildbranch.py b/morphlib/buildbranch.py index 2a2530b0..e16bf2b4 100644 --- a/morphlib/buildbranch.py +++ b/morphlib/buildbranch.py @@ -57,24 +57,70 @@ class BuildBranch(object): # would be better to not use local repositories and temporary refs, # so building from a workspace appears to be identical to using # `morph build-morphology` - def __init__(self, sb, build_ref_prefix): - - self._sb = sb + def __init__(self, build_ref_prefix, build_uuid, system_branch=None, + definitions_repo=None): + self._sb = system_branch + self._definitions_repo = definitions_repo self._cleanup = collections.deque() self._to_push = {} self._td = fs.tempfs.TempFS() self._register_cleanup(self._td.close) - self._branch_root = sb.get_config('branch.root') + if system_branch: + # Old-style Morph system branch which may involve multiple repos. + # + # Temporary refs will look like this: + # + # $build-ref-prefix/$branch_uuid/$repo_uuid. For + # + # For example: + # + # baserock/builds/f0b21fe240b244edb7e4142b6e201658/8df11f234ab... + self._to_push = self.collect_repos_for_system_branch( + system_branch, build_ref_prefix) + + branch_root = system_branch.get_config('branch.root') + self._root = system_branch.definitions_repo + _, self._root_index = self._to_push[self._root] + else: + # Temporary branch of only a definitions.git repo. + # + # Temporary ref will look like this: + # + # $build-ref-prefix/$HEAD/$build_uuid + # + # For example: + # + # baserock/builds/master/f0b21fe240b244edb7e4142b6e201658 + ref = definitions_repo.HEAD + build_ref = os.path.join( + 'refs/heads', build_ref_prefix, ref, build_uuid) + + index = definitions_repo.get_index(self._td.getsyspath('index')) + head_tree = definitions_repo.resolve_ref_to_tree(ref) + index.set_to_tree(head_tree) + + self._to_push[definitions_repo] = (build_ref, index) + self._root, self._root_index = definitions_repo, index + + def collect_repos_for_system_branch(self, sb, build_ref_prefix): branch_uuid = sb.get_config('branch.uuid') - + to_push = dict() for count, gd in enumerate(sb.list_git_directories()): try: repo_uuid = gd.get_config('morph.uuid') except cliapp.AppException: # Not a repository cloned by morph, ignore continue + + if gd.dirname == sb.definitions_repo.dirname: + # Avoid creating a new GitDirectory instance for the + # definitions repo, which we already have a DefinitionsRepo + # instance for. This means that to_push[sb.definitions_repo] + # returns the expected results. + gd = sb.definitions_repo + build_ref = os.path.join('refs/heads', build_ref_prefix, branch_uuid, repo_uuid) # index is commit of workspace + uncommitted changes may want @@ -82,15 +128,12 @@ class BuildBranch(object): # so they can add new files first index = gd.get_index(self._td.getsyspath(repo_uuid)) index.set_to_tree(gd.resolve_ref_to_tree(gd.HEAD)) - self._to_push[gd] = (build_ref, index) + to_push[gd] = (build_ref, index) - if len(self._to_push) == 0: + if len(to_push) == 0: raise NoReposError(self, count) - rootinfo, = ((gd, index) for gd, (build_ref, index) - in self._to_push.iteritems() - if gd.get_config('morph.repository') == self._branch_root) - self._root, self._root_index = rootinfo + return to_push def _register_cleanup(self, func, *args, **kwargs): self._cleanup.append((func, args, kwargs)) @@ -116,6 +159,12 @@ class BuildBranch(object): sha1 = gd.store_blob(loader.save_to_string(morphology)) yield 0o100644, sha1, morphology.filename + def load_all_morphologies(self, loader): + if self._sb: + return self._sb.load_all_morphologies(loader) + else: + return self._root.load_all_morphologies(loader) + def inject_build_refs(self, loader, use_local_repos, inject_cb=lambda **kwargs: None): '''Update system and stratum morphologies to point to our branch. @@ -128,15 +177,21 @@ class BuildBranch(object): files into their in-memory representations and back again. ''' - root_repo = self._root.get_config('morph.repository') + root_repo = self._root.remote_url root_ref = self._root.HEAD morphs = morphlib.morphset.MorphologySet() - for morph in self._sb.load_all_morphologies(loader): + + for morph in self.load_all_morphologies(loader): morphs.add_morphology(morph) sb_info = {} for gd, (build_ref, index) in self._to_push.iteritems(): - repo, ref = gd.get_config('morph.repository'), gd.HEAD + if gd == self._root: + repo, ref = root_repo, root_ref + else: + # This branch can only run if we are in a Morph system branch + # checkout, because only there will we consider chunk repos. + repo, ref = gd.get_config('morph.repository'), gd.HEAD sb_info[repo, ref] = (gd, build_ref) def filter(m, kind, spec): @@ -186,8 +241,10 @@ class BuildBranch(object): 4. commit message describing the current build using `uuid` ''' - commit_message = 'Morph build %s\n\nSystem branch: %s\n' % \ - (uuid, self._sb.system_branch_name) + commit_message = 'Morph build %s\n' % uuid + if self._sb: + commit_message += "\nSystem branch: %s\n'" % \ + self._sb.system_branch_name author_name = name committer_name = 'Morph (on behalf of %s)' % name author_email = committer_email = email @@ -258,11 +315,17 @@ class BuildBranch(object): @property def root_repo_url(self): '''URI of the repository that systems may be found in.''' - return self._sb.get_config('branch.root') + if self._sb: + return self._sb.get_config('branch.root') + else: + return self._definitions_repo.remote_url @property def root_ref(self): - return self._sb.get_config('branch.name') + if self._sb: + return self._sb.get_config('branch.name') + else: + return self._definitions_repo.HEAD @property def root_commit(self): diff --git a/morphlib/definitions_repo.py b/morphlib/definitions_repo.py new file mode 100644 index 00000000..a7875148 --- /dev/null +++ b/morphlib/definitions_repo.py @@ -0,0 +1,415 @@ +# Copyright (C) 2015 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, see . + + +'''Handles the Git repository containing Baserock definitions.''' + + +import cliapp + +import contextlib +import logging +import os +import urlparse +import uuid + +import morphlib +import gitdir + + +class DefinitionsRepoNotFound(cliapp.AppException): + def __init__(self): + cliapp.AppException.__init__(self, + 'This command must be run from inside a Git repository ' + 'containing Baserock definitions.') + + +class FileOutsideRepo(cliapp.AppException): + def __init__(self, path, repo): + cliapp.AppException.__init__(self, + 'File %s is not in repo %s.' % (path, repo)) + + +class DefinitionsRepo(gitdir.GitDirectory): + '''Represents a definitions.git repo checked out locally. + + This can either be a normal Git clone, or a Git clone inside an old-style + Morph workspace. + + If the repo is inside a Morph workspace, certain behaviours are enabled for + consistency with old versions of Morph. See function documentation for + details. + + ''' + def __init__(self, path, search_for_root=False, system_branch=None, + allow_missing=False): + morphlib.gitdir.GitDirectory.__init__( + self, path, search_for_root=search_for_root, + allow_missing=allow_missing) + self.system_branch = system_branch + + @property + def HEAD(self): + '''Return the ref considered to be HEAD of this definitions repo. + + In a normal Git checkout, this will return whatever ref is checked out + as the working tree (HEAD, in Git terminology). + + If this definitions repo is in an old-style Morph system branch, it + will return the ref that was checked out with `morph branch` or `morph + checkout`, which will NOT necessarily correspond to what is checked out + in the Git repo. + + ''' + if self.system_branch is None: + return morphlib.gitdir.GitDirectory.HEAD.fget(self) + else: + return self.system_branch.get_config('branch.name') + + @property + def remote_url(self): + '''Return the 'upstream' URL of this repo. + + If this repo is inside a Morph system branch checkout, this will be + whatever URL was passed to `morph checkout` or `morph branch`. That may + be a keyed URL such as baserock:baserock/definitions. + + Otherwise, the fetch URL of the 'origin' remote is returned. + + ''' + if self.system_branch is None: + return self.get_remote('origin').get_fetch_url() + else: + return self.system_branch.root_repository_url + + def branch_with_local_changes(self, uuid, push=True, build_ref_prefix=None, + git_user_name=None, git_user_email=None, + status_cb=None): + '''Yield a branch that includes the user's local changes to this repo. + + When operating on local repos, this isn't really necessary. But when + doing distributed building, any local changes the user has made need + to be pushed. As a convenience for the user, Morph supports creating + temporary branches with their local changes and pushing them to the + 'origin' remote of the repo they are working in. + + If there are no local changes, there is no temporary branch created, + and the function yields whatever branch was checked out. + + The 'git_user_name' and 'git_user_email' parameters are used when + creating commits in the temporary branch. The 'build_ref_prefix' is + prepended to the ref name of the temporary branch. Pushing is limited + to only certain refs in some Git servers. + + ''' + if status_cb: + status_cb(msg='Looking for uncommitted changes (pass ' + '--local-changes=ignore to skip)') + + if self.system_branch: + bb = morphlib.buildbranch.BuildBranch( + build_ref_prefix, uuid, system_branch=self.system_branch) + else: + bb = morphlib.buildbranch.BuildBranch( + build_ref_prefix, uuid, definitions_repo=self) + + loader = morphlib.morphloader.MorphologyLoader() + pbb = morphlib.buildbranch.pushed_build_branch( + bb, loader=loader, + changes_need_pushing=push, name=git_user_name, + email=git_user_email, build_uuid=uuid, + status=status_cb) + return pbb # (repo_url, commit, original_ref) + + @contextlib.contextmanager + def source_pool(self, lrc, rrc, cachedir, ref, system_filename, + include_local_changes=False, push_local_changes=False, + update_repos=True, status_cb=None, build_ref_prefix=None, + git_user_name=None, git_user_email=None): + '''Load the system defined in 'morph' and all the sources it contains. + + This is a context manager, because depending on the settings given it + may create and push a temporary build branch. This is useful when there + are local changes that you would like distributed build workers to + build. + + If 'include_local_changes' is False, the on-disk definitions.git repo + is used only to query the HEAD ref. Morph then looks for this ref in + its local clone of that repo's 'origin' remote, which ensures that the + changes it is building are pushed to the configured Git server (at + least at time it is building them). + + When 'include_local_changes' is True, Morph will create a temporary + branch in the repo including any local changes. If the definitions.git + repo is inside an old-style Morph system branch, it will create + temporary branches in all repos that have been marked with `morph + edit`. The branch is cleaned up when the context manager exits. The + 'user_name', 'user_email' and 'build_ref_prefix' settings must be + passed if a temporary build branch is created. + + FIXME: if not inside an old-style Morph system branch, the temporary + branch is redundant as Morph could just read the files from the disk + as-is. This requires changes to SourceResolver before it is possible. + + The 'push_local_changes' option isn't much use. You probably want to + use branch_with_local_changes() instead. It is present so that the + `morph build` command continues to honour the 'push-build-branches' + setting, but that was probably only useful for `morph distbuild` and + that now uses branch_with_local_changes(). + + The 'lrc' and 'rrc' parameters are local and remote Git repo caches. + Use morphlib.util.new_repo_caches() to obtain these. The 'cachedir' + parameter points to where Git repos are cached by Morph, + app.settings['cachedir'] tells you that. + + The 'update_repos' flag allows you to disable updating Git repos, to + honour app.settings['no-git-update']. If one of the refs in the build + graph is not available locally and update_repos is False, you will see + a morphlib.gitdir.InvalidRefError exception. + + The 'status_cb' function will be called if set to output progress and + status messages to the user. + + The function yields a morphlib.srcpool.SourcePool instance, which is + all you need to resolve cache keys, and construct a usable build graph. + See morphlib.buildcommand.BuildCommand.resolve_artifacts() for a way + of doing this. + + ''' + # FIXME: currently the way this function is implemented causes the + # `deploy` command to re-create a temporary build branch for each + # system that is deployed. This is a regression in terms of + # performance. But it seems to me that the sourcepool object should + # be able to contain multiple systems, and so the correct fix is to + # extend this function to handle multiple systems, rather than split + # up the 'process local changes' stage from the 'create source pool' + # stage. + if include_local_changes: + build_uuid = uuid.uuid4().hex + temporary_branch = DefinitionsRepo.branch_with_local_changes( + self, build_uuid, push=push_local_changes, + build_ref_prefix=build_ref_prefix, git_user_name=git_user_name, + git_user_email=git_user_email, status_cb=status_cb) + with temporary_branch as (repo_url, commit, original_ref): + yield morphlib.sourceresolver.create_source_pool( + lrc, rrc, repo_url, commit, [system_filename], + cachedir=cachedir, original_ref=original_ref, + update_repos=update_repos, status_cb=status_cb) + else: + if self.system_branch: + repo_url = self.systembranch.root_repository + else: + repo_url = self.get_remote('origin') + commit = self.resolve_ref_to_commit(ref) + + if status_cb: + status_cb(msg='Deciding on task order') + + yield morphlib.sourceresolver.create_source_pool( + lrc, rrc, repo_url, commit, [system_filename], + cachedir=cachedir, original_ref=ref, update_repos=update_repos, + status_cb=status_cb) + + def load_all_morphologies(self, loader): + mf = morphlib.morphologyfinder.MorphologyFinder(self) + for filename in (f for f in mf.list_morphologies() + if not self.is_symlink(f)): + text = mf.read_morphology(filename) + m = loader.load_from_string(text, filename=filename) + m.repo_url = self.remote_url + m.ref = self.HEAD + yield m + + def relative_path(self, path, cwd='.'): + '''Make 'path' relative to the top directory of this repo. + + If 'path' is a relative path, it is taken to be relative to the + current working directory. Thus, the result of this function will + be different depending on the value of os.getcwd(). + + If the given path is outside the repo, a PathOutsideRepo exception + is raised. + + ''' + def path_is_outside_repo(path): + return path.split(os.sep, 1)[0] == '..' + + absolute_path = os.path.abspath(path) + repo_relative_path = os.path.relpath(absolute_path, self.dirname) + + if path_is_outside_repo(repo_relative_path): + raise FileOutsideRepo(repo_relative_path, self) + + return repo_relative_path + + def relative_path_to_chunk(self, repo_url): + '''Return a sensible directory to check out repo_url. + + This will be a path in the directory that contains this definitions + repo, with its name based on 'repo_url'. + + ''' + # This is copied from systembranch._fabricate_git_directory_name(). + + # Parse the URL. If the path component is absolute, we assume + # it's a real URL; otherwise, an aliased URL. + parts = urlparse.urlparse(repo_url) + + if os.path.isabs(parts.path): + # Remove .git suffix, if any. + path = parts.path + if path.endswith('.git'): + path = path[:-len('.git')] + + # Add the domain name etc (netloc). Ignore any other parts. + # Note that we _know_ the path starts with a slash, so we avoid + # adding one here. + relative = '%s%s' % (parts.netloc, path) + else: + relative = repo_url + + # Replace colons with slashes. + relative = '/'.join(relative.split(':')) + + # Remove anyleading slashes, or os.path.join below will only + # use the relative part (since it's absolute, not relative). + relative = relative.lstrip('/') + + return os.path.join(os.path.dirname(self.dirname), relative) + + +class DefinitionsRepoWithApp(DefinitionsRepo): + '''Wrapper class for DefinitionsRepo that understands Morph settings. + + The DefinitionsRepo class does not require a morphlib.app.Application + instance to use it. However, this means you need to pass quite a lot + of parameters in. Code inside Morph can use this class instead to save + duplicating code. + + ''' + def __init__(self, app, *args, **kwargs): + DefinitionsRepo.__init__(self, *args, **kwargs) + self.app = app + + self._git_user_name = morphlib.git.get_user_name(app.runcmd) + self._git_user_email = morphlib.git.get_user_email(app.runcmd) + + self._lrc, self._rrc = morphlib.util.new_repo_caches(app) + + def branch_with_local_changes(self, uuid, push=False): + '''Equivalent to DefinitionsRepo.branch_with_local_changes().''' + + return DefinitionsRepo.branch_with_local_changes( + self, uuid, + push=(push or self.app.settings['push-build-branches']), + build_ref_prefix=self.app.settings['build-ref-prefix'], + git_user_name=self._git_user_name, + git_user_email=self._git_user_email, + status_cb=self.app.status,) + + def source_pool(self, ref, system_filename, + include_local_changes=False): + '''Equivalent to DefinitionsRepo.source_pool().''' + + return DefinitionsRepo.source_pool( + self, self._lrc, self._rrc, self.app.settings['cachedir'], + ref, system_filename, + include_local_changes=include_local_changes, + push_local_changes=self.app.settings['push-build-branches'], + build_ref_prefix=self.app.settings['build-ref-prefix'], + git_user_name=self._git_user_name, + git_user_email=self._git_user_email, + status_cb=self.app.status, + update_repos=(not self.app.settings['no-git-update'])) + + +def _system_branch(path): + '''Open an old-style Morph system branch in an old-style Morph workspace. + + Raises morphlib.workspace.NotInWorkspace or + morphlib.sysbranchdir.NotInSystemBranch if either workspace or + system-branch are not found. + + ''' + morphlib.workspace.open(path) + system_branch = morphlib.sysbranchdir.open_from_within(path) + return system_branch + + +def _local_definitions_repo(path, search_for_root, system_branch=None, + app=None): + '''Open a local Git repo containing Baserock definitions, at 'path'. + + Raises morphlib.gitdir.NoGitRepoError if there is no repo found at 'path'. + + ''' + if app: + gitdir = morphlib.definitions_repo.DefinitionsRepoWithApp( + app, path, search_for_root=search_for_root, + system_branch=system_branch) + else: + gitdir = morphlib.definitions_repo.DefinitionsRepo( + path, search_for_root=search_for_root, system_branch=system_branch) + return gitdir + + +def open(path, search_for_root=False, search_workspace=False, app=None): + '''Open the definitions.git repo at 'path'. + + Returns a DefinitionsRepo instance. + + If 'search_for_root' is True, this function will traverse up from 'path' + to find a .git directory, and assume that is the top of the Git repository. + If you are trying to find the repo based on the current working directory, + you should set this to True. If you are trying to find the repo based on a + path entered manually by the user, you may want to set this to False to + avoid confusion. + + If 'search_workspace' is True, this function will check if 'path' is inside + an old-style Morph workspace. If it is, there will be two changes to its + behaviour. First, the definitions.git will be returned even if 'path' is + inside a different repo, because the old-style Morph system branch will + identify which is the correct definitions.git repo. Second, the value + returned for HEAD will not be the ref checked out in the definitions.git + repo, but rather the ref that was passed to `morph checkout` or `morph + branch` when the system branch was originally checked out. This behaviour + may seem confusing if you are new to Morph, but in fact Morph forced users + to work this way for several years, so we need preserve this behaviour for + a while to avoid disrupting existing users. + + ''' + sb = None + + if search_workspace: + try: + sb = _system_branch(path) + except (morphlib.workspace.NotInWorkspace, + morphlib.sysbranchdir.NotInSystemBranch): + logging.debug('Did not find old-style Morph system branch') + + if sb: + path = sb.get_git_directory_name(sb.root_repository_url) + definitions_repo = _local_definitions_repo( + path=path, search_for_root=False, system_branch=sb, app=app) + logging.info('Opened definitions repo %s from Morph system branch %s', + definitions_repo, sb) + else: + try: + definitions_repo = _local_definitions_repo( + path, search_for_root=search_for_root, app=app) + except morphlib.gitdir.NoGitRepoError: + raise DefinitionsRepoNotFound() + logging.info('Opened definitions repo %s', definitions_repo) + + return definitions_repo diff --git a/morphlib/gitdir.py b/morphlib/gitdir.py index 9cb62e3b..8716da16 100644 --- a/morphlib/gitdir.py +++ b/morphlib/gitdir.py @@ -425,7 +425,7 @@ class GitDirectory(object): ''' - def __init__(self, dirname, search_for_root=False): + def __init__(self, dirname, search_for_root=False, allow_missing=False): '''Set up a GitDirectory instance for the repository at 'dirname'. If 'search_for_root' is set to True, 'dirname' may point to a @@ -440,7 +440,8 @@ class GitDirectory(object): self.dirname = dirname self.config = Config(config_file=None, runcmd=self._runcmd) - self._ensure_is_git_repo() + if not allow_missing: + self._ensure_is_git_repo() def __str__(self): return self.dirname diff --git a/morphlib/sysbranchdir.py b/morphlib/sysbranchdir.py index 3ca5a8cb..d23d9eea 100644 --- a/morphlib/sysbranchdir.py +++ b/morphlib/sysbranchdir.py @@ -46,12 +46,28 @@ class SystemBranchDirectory(object): def __init__(self, root_directory, root_repository_url, system_branch_name): - self.root_directory = os.path.abspath(root_directory) - self.root_repository_url = root_repository_url self.system_branch_name = system_branch_name + # The 'root repo' is the definitions repo. This attribute is named this + # way for historical reasons. + self.root_repository_url = root_repository_url + assert root_repository_url is not None + + # The 'root directory' is the parent directory of all checked-out + # repos. For example, the root directory of branch 'sam/test' in + # workspace '/src/ws' would be '/src/ws/sam/test' (at the time it was + # created by `morph branch` or `morph checkout`, anyway). + self.root_directory = os.path.abspath(root_directory) + self.config = morphlib.gitdir.Config(config_file=self._config_path) + # In order to handle newly-created system branch directories (and for + # the unit tests) we don't raise an error here if the definitions repo + # isn't cloned yet. Some methods won't work if it doesn't exist though. + definitions_repo_dir = self.get_git_directory_name(root_repository_url) + self.definitions_repo = morphlib.definitions_repo.DefinitionsRepo( + definitions_repo_dir, system_branch=self, allow_missing=True) + @property def _magic_path(self): return os.path.join(self.root_directory, '.morph-system-branch') @@ -106,9 +122,7 @@ class SystemBranchDirectory(object): return os.path.join(self.root_directory, relative) def relative_to_root_repo(self, path): # pragma: no cover - gitdirpath = self.get_git_directory_name(self.root_repository_url) - - return os.path.relpath(os.path.abspath(path), gitdirpath) + return self.definitions_repo.relative_path(path) def get_git_directory_name(self, repo_url): '''Return directory pathname for a given git repository. @@ -193,21 +207,8 @@ class SystemBranchDirectory(object): for dirname in morphlib.util.find_leaves(self.root_directory, '.git')) - # Not covered by unit tests, since testing the functionality spans - # multiple modules and only tests useful output with a full system - # branch, so it is instead covered by integration tests. def load_all_morphologies(self, loader): # pragma: no cover - gd_name = self.get_git_directory_name(self.root_repository_url) - gd = morphlib.gitdir.GitDirectory(gd_name) - mf = morphlib.morphologyfinder.MorphologyFinder(gd) - for filename in (f for f in mf.list_morphologies() - if not gd.is_symlink(f)): - text = mf.read_morphology(filename) - m = loader.load_from_string(text, filename=filename) - m.repo_url = self.root_repository_url - m.ref = self.system_branch_name - yield m - + return self.definitions_repo.load_all_morphologies(loader) def create(root_directory, root_repository_url, system_branch_name): diff --git a/without-test-modules b/without-test-modules index df1aa2dd..95f5c13e 100644 --- a/without-test-modules +++ b/without-test-modules @@ -61,3 +61,4 @@ distbuild/timer_event_source.py distbuild/worker_build_scheduler.py # Not unit tested, since it needs a full system branch morphlib/buildbranch.py +morphlib/definitions_repo.py -- cgit v1.2.1