diff --git a/src/lay/laySalt.cc b/src/lay/laySalt.cc index 9def56e49..001fc4354 100644 --- a/src/lay/laySalt.cc +++ b/src/lay/laySalt.cc @@ -56,6 +56,12 @@ Salt &Salt::operator= (const Salt &other) return *this; } +SaltGrains & +Salt::root () +{ + return m_root; +} + Salt::flat_iterator Salt::begin_flat () { @@ -146,13 +152,32 @@ Salt::add_collection_to_flat (SaltGrains &gg) namespace { -struct NameCompare +struct NameAndTopoIndexCompare { + NameAndTopoIndexCompare (const std::map &topo_index) + : mp_topo_index (&topo_index) + { + // .. nothing yet .. + } + bool operator () (lay::SaltGrain *a, lay::SaltGrain *b) const { + std::map::const_iterator ti_a = mp_topo_index->find (a->name ()); + std::map::const_iterator ti_b = mp_topo_index->find (b->name ()); + + // Reverse sorting by topological index as highest priority + if (ti_a != mp_topo_index->end () && ti_b != mp_topo_index->end ()) { + if (ti_a->second != ti_b->second) { + return ti_a->second > ti_b->second; + } + } + // TODO: UTF-8 support? return a->name () < b->name (); } + +private: + const std::map *mp_topo_index; }; } @@ -169,9 +194,41 @@ Salt::validate () m_grains_by_name.insert (std::make_pair ((*i)->name (), *i)); } + // Compute a set of topological indexes. Packages which serve depedencies of other packages have a higher + // topological index. Later we sort the packages by descending topo index to ensure the packages which are + // input to others come first. + + std::map topological_index; + for (std::map::const_iterator g = m_grains_by_name.begin (); g != m_grains_by_name.end (); ++g) { + topological_index.insert (std::make_pair (g->first, 0)); + } + + // NOTE: we allow max. 10 levels of dependencies. That should be sufficient. Limiting the levels of dependencies prevents + // infinite recursion due to faulty recursive dependencies. + for (int n = 0; n < 10; ++n) { + + bool any_updated = false; + + for (std::map::const_iterator g = m_grains_by_name.begin (); g != m_grains_by_name.end (); ++g) { + int index = topological_index [g->first]; + for (std::vector::const_iterator d = g->second->dependencies ().begin (); d != g->second->dependencies ().end (); ++d) { + std::map::iterator ti = topological_index.find (d->name); + if (ti != topological_index.end () && ti->second < index + 1) { + ti->second = index + 1; + any_updated = true; + } + } + } + + if (! any_updated) { + break; + } + + } + // NOTE: we intentionally sort after the name list has been built - this way // the first entry will win in the name to grain map. - std::sort (mp_flat_grains.begin (), mp_flat_grains.end (), NameCompare ()); + std::sort (mp_flat_grains.begin (), mp_flat_grains.end (), NameAndTopoIndexCompare (topological_index)); } } diff --git a/src/lay/laySalt.h b/src/lay/laySalt.h index c37766bfc..aef3da0ac 100644 --- a/src/lay/laySalt.h +++ b/src/lay/laySalt.h @@ -185,6 +185,13 @@ public: */ bool create_grain (const SaltGrain &templ, SaltGrain &target); + /** + * @brief Gets the root collection + * + * This method is provided for test purposes mainly. + */ + SaltGrains &root (); + signals: /** * @brief A signal triggered before one of the collections changed diff --git a/src/unit_tests/laySalt.cc b/src/unit_tests/laySalt.cc index 8edff9a14..7c5e6eb81 100644 --- a/src/unit_tests/laySalt.cc +++ b/src/unit_tests/laySalt.cc @@ -357,3 +357,45 @@ TEST (4) EXPECT_EQ (salt.grain_by_name ("b")->name (), "b"); EXPECT_EQ (salt.grain_by_name ("c/c/v")->name (), "c/c/v"); } + +TEST (5) +{ + lay::SaltGrains grains; + + lay::SaltGrain g1; + g1.set_name ("g1"); + lay::SaltGrain::Dependency dep; + dep.name = "g2"; + g1.dependencies ().push_back (dep); + dep.name = "g3"; + g1.dependencies ().push_back (dep); + grains.add_grain (g1); + + lay::SaltGrains g34; + + lay::SaltGrain g3; + g3.set_name ("g3"); + g34.add_grain (g3); + + lay::SaltGrain g4; + g4.set_name ("g4"); + g34.add_grain (g4); + + grains.add_collection (g34); + + lay::SaltGrain g2; + g2.set_name ("g2"); + dep.name = "g3"; + g2.dependencies ().push_back (dep); + grains.add_grain (g2); + + lay::Salt salt; + salt.root ().add_collection (grains); + + std::vector names; + for (lay::Salt::flat_iterator i = salt.begin_flat (); i != salt.end_flat (); ++i) { + names.push_back ((*i)->name ()); + } + + EXPECT_EQ (tl::join (names, ","), "g3,g2,g1,g4"); +}