diff options
author | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2013-02-19 18:58:00 +0000 |
---|---|---|
committer | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2013-02-19 18:58:00 +0000 |
commit | 29b8977ac03ac9ce0c178ce6febd0a5f27288001 (patch) | |
tree | 523a32e1d5f4a373051d9272120d8a9c289da873 | |
parent | 24866984ce4c1e2e444ea4aaf2d4860c60ac617f (diff) | |
parent | eda18665e3fc652f95e9961a4edc46ec797aa4a9 (diff) | |
download | morph-29b8977ac03ac9ce0c178ce6febd0a5f27288001.tar.gz |
Merge branch 'liw/build-ordering'
-rw-r--r-- | morphlib/__init__.py | 1 | ||||
-rw-r--r-- | morphlib/artifact.py | 23 | ||||
-rw-r--r-- | morphlib/buildcommand.py | 51 | ||||
-rw-r--r-- | morphlib/buildorder.py | 117 | ||||
-rw-r--r-- | morphlib/buildorder_tests.py | 141 | ||||
-rw-r--r-- | morphlib/plugins/deploy_plugin.py | 3 | ||||
-rw-r--r-- | morphlib/plugins/graphing_plugin.py | 30 | ||||
-rw-r--r-- | morphlib/plugins/show_dependencies_plugin.py | 22 | ||||
-rw-r--r-- | tests/show-dependencies.stdout | 153 |
9 files changed, 134 insertions, 407 deletions
diff --git a/morphlib/__init__.py b/morphlib/__init__.py index 4446720e..271fa977 100644 --- a/morphlib/__init__.py +++ b/morphlib/__init__.py @@ -48,7 +48,6 @@ import artifactresolver import bins import buildcommand import buildenvironment -import buildorder import buildsystem import builder2 import cachedir diff --git a/morphlib/artifact.py b/morphlib/artifact.py index ccde11d4..3bb2a520 100644 --- a/morphlib/artifact.py +++ b/morphlib/artifact.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012 Codethink Limited +# Copyright (C) 2012, 2013 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 @@ -63,3 +63,24 @@ class Artifact(object): def __str__(self): # pragma: no cover return '%s|%s' % (self.source, self.name) + + def walk(self): # pragma: no cover + '''Return list of an artifact and its build dependencies. + + The artifacts are returned in depth-first order: an artifact + is returned only after all of its dependencies. + + ''' + + done = set() + + def depth_first(a): + for dep in a.dependencies: + for ret in depth_first(dep): + yield ret + if a not in done: + done.add(a) + yield a + + return list(depth_first(self)) + diff --git a/morphlib/buildcommand.py b/morphlib/buildcommand.py index 907676fa..27fec4da 100644 --- a/morphlib/buildcommand.py +++ b/morphlib/buildcommand.py @@ -48,8 +48,8 @@ class BuildCommand(object): 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) - order = self.compute_build_order(repo_name, ref, filename) - self.build_in_order(order) + artifact = self.get_artifact_object(repo_name, ref, filename) + self.build_in_order(artifact) self.app.status(msg='Build ends successfully', chatty=True) @@ -72,8 +72,9 @@ class BuildCommand(object): def new_repo_caches(self): return morphlib.util.new_repo_caches(self.app) - def compute_build_order(self, repo_name, ref, filename): - '''Compute build order for a triplet.''' + def get_artifact_object(self, repo_name, ref, filename): + '''Create an Artifact object representing the given triplet.''' + self.app.status(msg='Figuring out the right build order') self.app.status(msg='Creating source pool', chatty=True) @@ -96,9 +97,9 @@ class BuildCommand(object): artifact.cache_id = self.ckc.get_cache_id(artifact) self.app.status(msg='Computing build order', chatty=True) - order = morphlib.buildorder.BuildOrder(artifacts) + root_artifact = self._find_root_artifact(artifacts) - return order + return root_artifact def _validate_cross_morphology_references(self, srcpool): '''Perform validation across all morphologies involved in the build''' @@ -158,24 +159,30 @@ class BuildCommand(object): other.morphology['kind'], wanted)) - def build_in_order(self, order): + def _find_root_artifact(self, artifacts): + '''Find the root artifact among a set of artifacts in a DAG. + + It would be nice if the ArtifactResolver would return its results in a + more useful order to save us from needing to do this -- the root object + is known already since that's the one the user asked us to build. + + ''' + + maybe = set(artifacts) + for a in artifacts: + for dep in a.dependencies: + if dep in maybe: + maybe.remove(dep) + assert len(maybe) == 1 + return maybe.pop() + + def build_in_order(self, artifact): '''Build everything specified in a build order.''' self.app.status(msg='Building according to build ordering', 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) - for artifact in artifacts: - self.build_artifact(artifact) + for a in artifact.walk(): + self.build_artifact(a) def build_artifact(self, artifact): '''Build one artifact. @@ -287,7 +294,9 @@ class BuildCommand(object): self.app.status(msg='Fetching to local cache: ' 'artifact %(name)s', name=artifact.name) - copy(self.rac.get(artifact), self.lac.put(artifact)) + rac_file = self.rac.get(artifact) + lac_file = self.lac.put(artifact) + copy(rac_file, lac_file) if artifact.source.morphology.needs_artifact_metadata_cached: if not self.lac.has_artifact_metadata(artifact, 'meta'): diff --git a/morphlib/buildorder.py b/morphlib/buildorder.py deleted file mode 100644 index 39b53f05..00000000 --- a/morphlib/buildorder.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright (C) 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. - - -import cliapp -import collections - - -class CyclicDependencyChainError(cliapp.AppException): - - def __init__(self): - cliapp.AppException.__init__( - self, 'Cyclic dependency chain detected') - - -class BuildOrder: - - def __init__(self, artifacts): - self.artifacts = artifacts - - if artifacts: - sorting = self._compute_reverse_topological_sorting(artifacts) - self.groups = self._create_build_groups(sorting) - else: - self.groups = [] - - def _compute_reverse_topological_sorting(self, artifacts): - '''Computes a reverse topological sorting of the build graph. - - A reverse topological sorting basically is the result of a series of - breadth-first searches starting at each leaf node (artifacts with no - dependents). Artifacts are added to the sorting as soon as all their - dependents have been added. - - For more information, see - http://en.wikipedia.org/wiki/Topological_sorting. - - ''' - - # map artifacts to sets of satisfied dependents. this is to detect - # when we can actually add artifacts to the BFS queue. rather than - # dropping links between nodes, like most topological sorting - # algorithms do, we simply remember all satisfied dependents and - # check if all of them are met repeatedly - satisfied_dependents = {} - - # create an empty sorting - sorting = collections.deque() - - # create a set of leafs to start the DFS from - leafs = collections.deque() - for artifact in artifacts: - satisfied_dependents[artifact] = set() - if len(artifact.dependents) == 0: - leafs.append(artifact) - - while len(leafs) > 0: - # fetch a leaf artifact from the DFS queue - artifact = leafs.popleft() - - # add it to the sorting - sorting.append(artifact) - - # mark this dependency as resolved in dependent artifacts - for dependency in artifact.dependencies: - satisfied_dependents[dependency].add(artifact) - - # add the dependent blob as a leaf if all - # its dependents have been resolved - has = len(satisfied_dependents[dependency]) - needs = len(dependency.dependents) - if has == needs: - leafs.append(dependency) - - # if not all dependencies were resolved on the way, we - # have found at least one cyclic dependency - if len(sorting) < len(artifacts): - raise CyclicDependencyChainError() - - return sorting - - def _create_build_groups(self, sorting): - groups = collections.deque() - - if sorting: - # create the last group - group = [] - groups.append(group) - - # traverse the build graph in reverse topological order - for artifact in sorting: - # add artifact to a group that comes as late in the build order - # as possible; if the first group contains any dependents, - # add the artifact to a new group at the beginning of the order - for group in groups: - if not any([x in group for x in artifact.dependents]): - group.append(artifact) - break - else: - group = [] - group.append(artifact) - groups.appendleft(group) - break - - return groups diff --git a/morphlib/buildorder_tests.py b/morphlib/buildorder_tests.py deleted file mode 100644 index ab1a7e1c..00000000 --- a/morphlib/buildorder_tests.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright (C) 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. - - -import unittest - -import morphlib - - -class FakeSource(object): - pass - - -class BuildOrderTests(unittest.TestCase): - - def test_empty_list_results_in_no_groups_at_all(self): - order = morphlib.buildorder.BuildOrder([]) - self.assertEqual(len(order.groups), 0) - - def test_list_with_one_artifact_results_in_one_group(self): - chunk = FakeSource() - artifact = morphlib.artifact.Artifact(chunk, 'chunk') - - order = morphlib.buildorder.BuildOrder([artifact]) - - self.assertEqual(len(order.groups), 1) - self.assertEqual(order.groups[0], [artifact]) - - def test_list_with_two_unrelated_artifacts_results_in_one_group(self): - chunk1 = FakeSource() - artifact1 = morphlib.artifact.Artifact(chunk1, 'chunk1') - - chunk2 = FakeSource() - artifact2 = morphlib.artifact.Artifact(chunk2, 'chunk2') - - order = morphlib.buildorder.BuildOrder([artifact1, artifact2]) - - self.assertEqual(len(order.groups), 1) - self.assertEqual(order.groups[0], [artifact1, artifact2]) - - def test_list_with_two_dependent_artifacts_results_in_two_groups(self): - chunk1 = FakeSource() - artifact1 = morphlib.artifact.Artifact(chunk1, 'chunk1') - - chunk2 = FakeSource() - artifact2 = morphlib.artifact.Artifact(chunk2, 'chunk2') - artifact2.add_dependency(artifact1) - - order = morphlib.buildorder.BuildOrder([artifact1, artifact2]) - - self.assertEqual(len(order.groups), 2) - self.assertEqual(order.groups[0], [artifact1]) - self.assertEqual(order.groups[1], [artifact2]) - - def test_chain_of_three_dependent_artifacts_results_in_three_groups(self): - chunk1 = FakeSource() - artifact1 = morphlib.artifact.Artifact(chunk1, 'chunk1') - - chunk2 = FakeSource() - artifact2 = morphlib.artifact.Artifact(chunk2, 'chunk2') - artifact2.add_dependency(artifact1) - - chunk3 = FakeSource() - artifact3 = morphlib.artifact.Artifact(chunk3, 'chunk3') - artifact3.add_dependency(artifact2) - - order = morphlib.buildorder.BuildOrder( - [artifact1, artifact2, artifact3]) - - self.assertEqual(len(order.groups), 3) - self.assertEqual(order.groups[0], [artifact1]) - self.assertEqual(order.groups[1], [artifact2]) - self.assertEqual(order.groups[2], [artifact3]) - - def test_two_artifacts_depending_on_another_results_in_two_groups(self): - chunk1 = FakeSource() - artifact1 = morphlib.artifact.Artifact(chunk1, 'chunk1') - - chunk2 = FakeSource() - artifact2 = morphlib.artifact.Artifact(chunk2, 'chunk2') - artifact2.add_dependency(artifact1) - - chunk3 = FakeSource() - artifact3 = morphlib.artifact.Artifact(chunk3, 'chunk3') - artifact3.add_dependency(artifact1) - - order = morphlib.buildorder.BuildOrder( - [artifact1, artifact2, artifact3]) - - self.assertEqual(len(order.groups), 2) - self.assertEqual(order.groups[0], [artifact1]) - self.assertEqual(order.groups[1], [artifact2, artifact3]) - - def test_one_artifact_depending_on_two_others_results_in_two_groups(self): - chunk1 = FakeSource() - artifact1 = morphlib.artifact.Artifact(chunk1, 'chunk1') - - chunk2 = FakeSource() - artifact2 = morphlib.artifact.Artifact(chunk2, 'chunk2') - - chunk3 = FakeSource() - artifact3 = morphlib.artifact.Artifact(chunk3, 'chunk3') - artifact3.add_dependency(artifact1) - artifact3.add_dependency(artifact2) - - order = morphlib.buildorder.BuildOrder( - [artifact1, artifact2, artifact3]) - - self.assertEqual(len(order.groups), 2) - self.assertEqual(order.groups[0], [artifact1, artifact2]) - self.assertEqual(order.groups[1], [artifact3]) - - def test_detection_of_cyclic_dependency_chain(self): - chunk1 = FakeSource() - artifact1 = morphlib.artifact.Artifact(chunk1, 'chunk1') - - chunk2 = FakeSource() - artifact2 = morphlib.artifact.Artifact(chunk2, 'chunk2') - - chunk3 = FakeSource() - artifact3 = morphlib.artifact.Artifact(chunk3, 'chunk3') - - artifact1.add_dependency(artifact3) - artifact2.add_dependency(artifact1) - artifact3.add_dependency(artifact2) - - self.assertRaises(morphlib.buildorder.CyclicDependencyChainError, - morphlib.buildorder.BuildOrder, - [artifact1, artifact2, artifact3]) diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py index 79715e13..f9a345ff 100644 --- a/morphlib/plugins/deploy_plugin.py +++ b/morphlib/plugins/deploy_plugin.py @@ -100,11 +100,10 @@ class DeployPlugin(cliapp.Plugin): # Run the build. build_ref = build_repos[branch_root]['build-ref'] - order = build_command.compute_build_order( + artifact = build_command.get_artifact_object( build_branch_root, build_ref, system_name + '.morph') - artifact = order.groups[-1][-1] if push: self.other.delete_remote_build_refs(build_repos) diff --git a/morphlib/plugins/graphing_plugin.py b/morphlib/plugins/graphing_plugin.py index c719f6e4..8c4ea2ef 100644 --- a/morphlib/plugins/graphing_plugin.py +++ b/morphlib/plugins/graphing_plugin.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012 Codethink Limited +# Copyright (C) 2012, 2013 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 @@ -37,7 +37,7 @@ class GraphingPlugin(cliapp.Plugin): '%(repo_name)s %(ref)s %(filename)s', repo_name=repo_name, ref=ref, filename=filename) builder = morphlib.buildcommand.BuildCommand(self.app) - order = builder.compute_build_order(repo_name, ref, filename) + artifact = builder.get_artifact_object(repo_name, ref, filename) basename, ext = os.path.splitext(filename) dot_filename = basename + '.gv' @@ -53,17 +53,17 @@ class GraphingPlugin(cliapp.Plugin): with open(dot_filename, 'w') as f: f.write('digraph "%s" {\n' % basename) - for i, group in enumerate(order.groups): - for artifact in group: - f.write( - ' "%s" [shape=%s];\n' % - (artifact.name, - shape_name[artifact.source.morphology['kind']])) - for dep in artifact.dependencies: - if artifact.source.morphology['kind'] == 'stratum': - if dep.dependents == [artifact]: - f.write(dep_fmt % - (artifact.name, dep.name)) - else: - f.write(dep_fmt % (artifact.name, dep.name)) + for a in artifact.walk(): + f.write( + ' "%s" [shape=%s];\n' % + (a.name, + shape_name[a.source.morphology['kind']])) + for dep in a.dependencies: + if a.source.morphology['kind'] == 'stratum': + if dep.dependents == [a]: + f.write(dep_fmt % + (a.name, dep.name)) + else: + f.write(dep_fmt % (a.name, dep.name)) f.write('}\n') + diff --git a/morphlib/plugins/show_dependencies_plugin.py b/morphlib/plugins/show_dependencies_plugin.py index 13ec512a..e4e40311 100644 --- a/morphlib/plugins/show_dependencies_plugin.py +++ b/morphlib/plugins/show_dependencies_plugin.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012 Codethink Limited +# Copyright (C) 2012-2013 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 @@ -46,27 +46,19 @@ class ShowDependenciesPlugin(cliapp.Plugin): self.app.settings['cache-server'], repo_resolver) else: rrc = None + + build_command = morphlib.buildcommand.BuildCommand(self.app) # traverse the morphs to list all the sources for repo, ref, filename in self.app.itertriplets(args): morph = filename[:-len('.morph')] - pool = self.app.create_source_pool( - lrc, rrc, (repo, ref, filename)) - - resolver = morphlib.artifactresolver.ArtifactResolver() - artifacts = resolver.resolve_artifacts(pool) - self.app.output.write('dependency graph for %s|%s|%s:\n' % (repo, ref, morph)) - for artifact in sorted(artifacts, key=str): + + artifact = build_command.get_artifact_object(repo, ref, filename) + + for artifact in reversed(artifact.walk()): self.app.output.write(' %s\n' % artifact) for dependency in sorted(artifact.dependencies, key=str): self.app.output.write(' -> %s\n' % dependency) - order = morphlib.buildorder.BuildOrder(artifacts) - self.app.output.write('build order for %s|%s|%s:\n' % - (repo, ref, morph)) - for group in order.groups: - self.app.output.write(' group:\n') - for artifact in group: - self.app.output.write(' %s\n' % artifact) diff --git a/tests/show-dependencies.stdout b/tests/show-dependencies.stdout index e58f5285..84ed3ba6 100644 --- a/tests/show-dependencies.stdout +++ b/tests/show-dependencies.stdout @@ -1,54 +1,4 @@ dependency graph for test-repo|master|xfce-core: - test-repo|master|cairo|cairo - test-repo|master|dbus-glib|dbus-glib - -> test-repo|master|dbus|dbus - -> test-repo|master|glib|glib - test-repo|master|dbus|dbus - test-repo|master|exo|exo - -> test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|libxfce4util|libxfce4util - test-repo|master|fontconfig|fontconfig - test-repo|master|freetype|freetype - test-repo|master|garcon|garcon - -> test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|libxfce4util|libxfce4util - test-repo|master|gdk-pixbuf|gdk-pixbuf - -> test-repo|master|glib|glib - test-repo|master|glib|glib - test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|cairo|cairo - -> test-repo|master|dbus-glib|dbus-glib - -> test-repo|master|dbus|dbus - -> test-repo|master|fontconfig|fontconfig - -> test-repo|master|freetype|freetype - -> test-repo|master|gdk-pixbuf|gdk-pixbuf - -> test-repo|master|glib|glib - -> test-repo|master|gtk|gtk - -> test-repo|master|pango|pango - test-repo|master|gtk-xfce-engine|gtk-xfce-engine - -> test-repo|master|garcon|garcon - -> test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|libxfce4ui|libxfce4ui - -> test-repo|master|xfconf|xfconf - test-repo|master|gtk|gtk - -> test-repo|master|cairo|cairo - -> test-repo|master|gdk-pixbuf|gdk-pixbuf - -> test-repo|master|glib|glib - -> test-repo|master|pango|pango - test-repo|master|libxfce4ui|libxfce4ui - -> test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|xfconf|xfconf - test-repo|master|libxfce4util|libxfce4util - -> test-repo|master|gtk-stack|gtk-stack - test-repo|master|pango|pango - -> test-repo|master|fontconfig|fontconfig - -> test-repo|master|freetype|freetype - test-repo|master|thunar|thunar - -> test-repo|master|exo|exo - -> test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|libxfce4ui|libxfce4ui - test-repo|master|tumbler|tumbler - -> test-repo|master|gtk-stack|gtk-stack test-repo|master|xfce-core|xfce-core -> test-repo|master|exo|exo -> test-repo|master|garcon|garcon @@ -65,16 +15,24 @@ dependency graph for test-repo|master|xfce-core: -> test-repo|master|xfconf|xfconf -> test-repo|master|xfdesktop|xfdesktop -> test-repo|master|xfwm4|xfwm4 - test-repo|master|xfce4-appfinder|xfce4-appfinder + test-repo|master|gtk-xfce-engine|gtk-xfce-engine -> test-repo|master|garcon|garcon -> test-repo|master|gtk-stack|gtk-stack -> test-repo|master|libxfce4ui|libxfce4ui -> test-repo|master|xfconf|xfconf - test-repo|master|xfce4-panel|xfce4-panel - -> test-repo|master|exo|exo + test-repo|master|xfce4-appfinder|xfce4-appfinder -> test-repo|master|garcon|garcon -> test-repo|master|gtk-stack|gtk-stack -> test-repo|master|libxfce4ui|libxfce4ui + -> test-repo|master|xfconf|xfconf + test-repo|master|xfdesktop|xfdesktop + -> test-repo|master|gtk-stack|gtk-stack + -> test-repo|master|libxfce4ui|libxfce4ui + -> test-repo|master|xfconf|xfconf + test-repo|master|xfwm4|xfwm4 + -> test-repo|master|gtk-stack|gtk-stack + -> test-repo|master|libxfce4ui|libxfce4ui + -> test-repo|master|xfconf|xfconf test-repo|master|xfce4-session|xfce4-session -> test-repo|master|exo|exo -> test-repo|master|gtk-stack|gtk-stack @@ -85,49 +43,56 @@ dependency graph for test-repo|master|xfce-core: -> test-repo|master|gtk-stack|gtk-stack -> test-repo|master|libxfce4ui|libxfce4ui -> test-repo|master|xfconf|xfconf - test-repo|master|xfconf|xfconf - -> test-repo|master|gtk-stack|gtk-stack - -> test-repo|master|libxfce4util|libxfce4util - test-repo|master|xfdesktop|xfdesktop + test-repo|master|xfce4-panel|xfce4-panel + -> test-repo|master|exo|exo + -> test-repo|master|garcon|garcon -> test-repo|master|gtk-stack|gtk-stack -> test-repo|master|libxfce4ui|libxfce4ui - -> test-repo|master|xfconf|xfconf - test-repo|master|xfwm4|xfwm4 + test-repo|master|tumbler|tumbler + -> test-repo|master|gtk-stack|gtk-stack + test-repo|master|thunar|thunar + -> test-repo|master|exo|exo -> test-repo|master|gtk-stack|gtk-stack -> test-repo|master|libxfce4ui|libxfce4ui + test-repo|master|garcon|garcon + -> test-repo|master|gtk-stack|gtk-stack + -> test-repo|master|libxfce4util|libxfce4util + test-repo|master|exo|exo + -> test-repo|master|gtk-stack|gtk-stack + -> test-repo|master|libxfce4util|libxfce4util + test-repo|master|libxfce4ui|libxfce4ui + -> test-repo|master|gtk-stack|gtk-stack -> test-repo|master|xfconf|xfconf -build order for test-repo|master|xfce-core: - group: - test-repo|master|glib|glib - test-repo|master|freetype|freetype - test-repo|master|fontconfig|fontconfig - group: - test-repo|master|cairo|cairo - test-repo|master|gdk-pixbuf|gdk-pixbuf - test-repo|master|pango|pango - test-repo|master|dbus|dbus - group: - test-repo|master|gtk|gtk - test-repo|master|dbus-glib|dbus-glib - group: - test-repo|master|gtk-stack|gtk-stack - group: - test-repo|master|libxfce4util|libxfce4util - group: - test-repo|master|xfconf|xfconf - group: - test-repo|master|exo|exo - test-repo|master|libxfce4ui|libxfce4ui - test-repo|master|garcon|garcon - group: - test-repo|master|thunar|thunar - test-repo|master|tumbler|tumbler - test-repo|master|xfce4-panel|xfce4-panel - test-repo|master|xfce4-settings|xfce4-settings - test-repo|master|xfce4-session|xfce4-session - test-repo|master|xfwm4|xfwm4 - test-repo|master|xfdesktop|xfdesktop - test-repo|master|xfce4-appfinder|xfce4-appfinder - test-repo|master|gtk-xfce-engine|gtk-xfce-engine - group: - test-repo|master|xfce-core|xfce-core + test-repo|master|xfconf|xfconf + -> test-repo|master|gtk-stack|gtk-stack + -> test-repo|master|libxfce4util|libxfce4util + test-repo|master|libxfce4util|libxfce4util + -> test-repo|master|gtk-stack|gtk-stack + test-repo|master|gtk-stack|gtk-stack + -> test-repo|master|cairo|cairo + -> test-repo|master|dbus-glib|dbus-glib + -> test-repo|master|dbus|dbus + -> test-repo|master|fontconfig|fontconfig + -> test-repo|master|freetype|freetype + -> test-repo|master|gdk-pixbuf|gdk-pixbuf + -> test-repo|master|glib|glib + -> test-repo|master|gtk|gtk + -> test-repo|master|pango|pango + test-repo|master|dbus-glib|dbus-glib + -> test-repo|master|dbus|dbus + -> test-repo|master|glib|glib + test-repo|master|dbus|dbus + test-repo|master|gtk|gtk + -> test-repo|master|cairo|cairo + -> test-repo|master|gdk-pixbuf|gdk-pixbuf + -> test-repo|master|glib|glib + -> test-repo|master|pango|pango + test-repo|master|gdk-pixbuf|gdk-pixbuf + -> test-repo|master|glib|glib + test-repo|master|glib|glib + test-repo|master|pango|pango + -> test-repo|master|fontconfig|fontconfig + -> test-repo|master|freetype|freetype + test-repo|master|cairo|cairo + test-repo|master|fontconfig|fontconfig + test-repo|master|freetype|freetype |