From 55c6f816f6f4ec7563c4f8ba0d44ebbcf7c40bf4 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 2 May 2016 19:48:38 +0100 Subject: Add a dependency scanner/extracter --- gentoobrowse-api/domain/portage-models.ice | 10 ++ gentoobrowse-api/service/depend.cpp | 87 ++++++++++ gentoobrowse-api/service/depend.h | 25 +++ gentoobrowse-api/unittests/Jamfile.jam | 6 + gentoobrowse-api/unittests/testDepend.cpp | 264 +++++++++++++++++++++++++++++ 5 files changed, 392 insertions(+) create mode 100644 gentoobrowse-api/service/depend.cpp create mode 100644 gentoobrowse-api/service/depend.h create mode 100644 gentoobrowse-api/unittests/testDepend.cpp diff --git a/gentoobrowse-api/domain/portage-models.ice b/gentoobrowse-api/domain/portage-models.ice index ca018e8..f281aea 100644 --- a/gentoobrowse-api/domain/portage-models.ice +++ b/gentoobrowse-api/domain/portage-models.ice @@ -79,6 +79,16 @@ module Gentoo { StringList urls; }; + class Dependency { + StringList when; + optional(1) string op; + string category; + string package; + optional(2) string version; + optional(3) string slot; + StringList use; + }; + sequence Categories; sequence Packages; sequence Ebuilds; diff --git a/gentoobrowse-api/service/depend.cpp b/gentoobrowse-api/service/depend.cpp new file mode 100644 index 0000000..f93787e --- /dev/null +++ b/gentoobrowse-api/service/depend.cpp @@ -0,0 +1,87 @@ +#include "depend.h" +#include + +const Glib::ustring WhenUse_Begin("\\s*(!?[[:alnum:]-_]+)\\?\\s*\\(\\s*"); +const Glib::ustring WhenUse_End("\\s*\\)\\s*"); +const Glib::ustring Or_Begin("\\s*\\|\\|\\s*\\(\\s*"); +const Glib::ustring Or_Group("\\s*\\(\\s*"); +const Glib::ustring Or_End("\\s*\\)\\s*"); +const Glib::ustring AtomSpec("\\s*" + "([[:punct:]]+)?" // op + "([[:alnum:]-]+)\\/" // cat + "(((-?[[:alpha:]]+[[:digit:]]+)|[[:alpha:]_+]|(-[[:alpha:]]))+)" // package + "(-([0-9][.0-9]*[[:alpha:]]?\\*?(_(alpha|beta|pre|rc|p))?[[:digit:]]*(-r[[:digit:]]+)?))?" // version + "(:([^/ []+(\\/[^ []+)?))?" // slot + "(\\[([^]]+)\\])?\\s*"); // use + +const std::string InWhen("InWhen"); +const std::string InOr("InOr"); + +namespace Portage { + namespace Utils { + template IceUtil::Optional iuo(const boost::optional & x) + { + if (x) { + return *x; + } + return IceUtil::Optional(); + } + + template std::vector split(const boost::optional & x) + { + std::vector rtn; + if (x) { + boost::algorithm::split(rtn, *x, [](auto c) { return c == ','; }); + std::sort(rtn.begin(), rtn.end()); + } + return rtn; + } + + Depend::Depend() + { + // use? ( + rules.push_back({ { InitialState, InWhen, InOr }, regex(WhenUse_Begin), [this](auto es) { + es->pushState(InWhen); + when.push_back(*es->pattern->match(1)); + } }); + // ) + rules.push_back({ { InWhen }, regex(WhenUse_End), [this](auto es) { + es->popState(); + when.pop_back(); + } }); + // || ( + rules.push_back({ { InitialState, InWhen, InOr }, regex(Or_Begin), [this](auto es) { + es->pushState(InOr); + } }); + // || ( + rules.push_back({ { InOr }, regex(Or_Group), [this](auto es) { + es->pushState(InOr); + } }); + // ) + rules.push_back({ { InOr }, regex(Or_End), [this](auto es) { + es->popState(); + } }); + // [op]some-cat/package[-version][:slot][uses] + rules.push_back({ { InitialState, InWhen, InOr }, regex(AtomSpec), [this](auto es) { + ds.push_back(new Gentoo::Dependency( + when, + iuo(es->pattern->match(1)), // op + *es->pattern->match(2), // category + *es->pattern->match(3), // package + iuo(es->pattern->match(8)), // version + iuo(es->pattern->match(13)), // slot + split(es->pattern->match(16)) // use + )); + } }); + } + + std::vector + Depend::parse(const std::string & s) + { + Depend d; + d.extract(s.c_str(), s.length()); + return d.ds; + } + } +} + diff --git a/gentoobrowse-api/service/depend.h b/gentoobrowse-api/service/depend.h new file mode 100644 index 0000000..3acae7f --- /dev/null +++ b/gentoobrowse-api/service/depend.h @@ -0,0 +1,25 @@ +#ifndef GENTOOBROWSE_SERVICE_DEPEND_H +#define GENTOOBROWSE_SERVICE_DEPEND_H + +#include +#include +#include +#include +#include "utils/lexer.h" + +namespace Portage { + namespace Utils { + class Depend : Gentoo::Utils::Lexer { + private: + Depend(); + Gentoo::StringList when; + + public: + DLL_PUBLIC static std::vector parse(const std::string &); + std::vector ds; + }; + } +} + +#endif + diff --git a/gentoobrowse-api/unittests/Jamfile.jam b/gentoobrowse-api/unittests/Jamfile.jam index 6c5ca2d..71aa67c 100644 --- a/gentoobrowse-api/unittests/Jamfile.jam +++ b/gentoobrowse-api/unittests/Jamfile.jam @@ -42,6 +42,12 @@ lib testCommon : ROOT=\"$(me)\" ; +run + testDepend.cpp + : : : + BOOST_TEST_DYN_LINK + testCommon + : testDepend ; run testMaintenance.cpp diff --git a/gentoobrowse-api/unittests/testDepend.cpp b/gentoobrowse-api/unittests/testDepend.cpp new file mode 100644 index 0000000..15b4cf3 --- /dev/null +++ b/gentoobrowse-api/unittests/testDepend.cpp @@ -0,0 +1,264 @@ +#define BOOST_TEST_MODULE TestDepend +#include + +#include + +BOOST_AUTO_TEST_CASE( simple1 ) +{ + auto ds = Portage::Utils::Depend::parse("sys-libs/readline"); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + BOOST_REQUIRE(!ds[0]->op); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline"); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( simple2 ) +{ + auto ds = Portage::Utils::Depend::parse("sys-libs/readline sys-apps/portage"); + BOOST_REQUIRE_EQUAL(ds.size(), 2); + BOOST_REQUIRE(!ds[0]->op); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline"); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); + BOOST_REQUIRE(!ds[1]->op); + BOOST_REQUIRE_EQUAL(ds[1]->category, "sys-apps"); + BOOST_REQUIRE_EQUAL(ds[1]->package, "portage"); + BOOST_REQUIRE(ds[1]->when.empty()); + BOOST_REQUIRE(!ds[1]->version); + BOOST_REQUIRE(!ds[1]->slot); + BOOST_REQUIRE(ds[1]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( simple2when1 ) +{ + auto ds = Portage::Utils::Depend::parse("sys-libs/readline !maybe? ( sys-apps/portage ) other/package"); + BOOST_REQUIRE_EQUAL(ds.size(), 3); + BOOST_REQUIRE(!ds[0]->op); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline"); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); + BOOST_REQUIRE(!ds[1]->op); + BOOST_REQUIRE_EQUAL(ds[1]->category, "sys-apps"); + BOOST_REQUIRE_EQUAL(ds[1]->package, "portage"); + BOOST_REQUIRE_EQUAL(ds[1]->when.size(), 1); + BOOST_REQUIRE_EQUAL(ds[1]->when[0], "!maybe"); + BOOST_REQUIRE(!ds[2]->op); + BOOST_REQUIRE_EQUAL(ds[2]->category, "other"); + BOOST_REQUIRE_EQUAL(ds[2]->package, "package"); + BOOST_REQUIRE(ds[2]->when.empty()); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( simple2when2 ) +{ + auto ds = Portage::Utils::Depend::parse("sys-libs/readline !maybe? ( and? ( sys-apps/portage ) not/this ) other/package"); + BOOST_REQUIRE_EQUAL(ds.size(), 4); + BOOST_REQUIRE(!ds[0]->op); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline"); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[1]->op); + BOOST_REQUIRE_EQUAL(ds[1]->category, "sys-apps"); + BOOST_REQUIRE_EQUAL(ds[1]->package, "portage"); + BOOST_REQUIRE_EQUAL(ds[1]->when.size(), 2); + BOOST_REQUIRE_EQUAL(ds[1]->when[0], "!maybe"); + BOOST_REQUIRE_EQUAL(ds[1]->when[1], "and"); + BOOST_REQUIRE(!ds[1]->version); + BOOST_REQUIRE_EQUAL(ds[2]->category, "not"); + BOOST_REQUIRE_EQUAL(ds[2]->package, "this"); + BOOST_REQUIRE_EQUAL(ds[2]->when.size(), 1); + BOOST_REQUIRE_EQUAL(ds[2]->when[0], "!maybe"); + BOOST_REQUIRE(!ds[2]->version); + BOOST_REQUIRE(!ds[3]->op); + BOOST_REQUIRE_EQUAL(ds[3]->category, "other"); + BOOST_REQUIRE_EQUAL(ds[3]->package, "package"); + BOOST_REQUIRE(!ds[3]->version); + BOOST_REQUIRE(ds[3]->when.empty()); +} + +BOOST_AUTO_TEST_CASE( op ) +{ + auto ds = Portage::Utils::Depend::parse(" !sys-libs/readline "); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + BOOST_REQUIRE(ds[0]->op); + BOOST_REQUIRE_EQUAL(*ds[0]->op, "!"); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline"); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(ds[0]->when.empty()); +} + +BOOST_AUTO_TEST_CASE( version1 ) +{ + auto ds = Portage::Utils::Depend::parse(" =sys-libs/readline-3 "); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + BOOST_REQUIRE(ds[0]->op); + BOOST_REQUIRE_EQUAL(*ds[0]->op, "="); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline"); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "3"); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( version2 ) +{ + auto ds = Portage::Utils::Depend::parse(" =sys-libs/readline2-3 "); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + BOOST_REQUIRE(ds[0]->op); + BOOST_REQUIRE_EQUAL(*ds[0]->op, "="); + BOOST_REQUIRE_EQUAL(ds[0]->category, "sys-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "readline2"); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "3"); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( special ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0 "); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + BOOST_REQUIRE(ds[0]->op); + BOOST_REQUIRE_EQUAL(*ds[0]->op, ">"); + BOOST_REQUIRE_EQUAL(ds[0]->category, "x11-libs"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "Gtk+"); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0"); + BOOST_REQUIRE(ds[0]->when.empty()); +} + +BOOST_AUTO_TEST_CASE( versionSuffix ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0_alpha "); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0_alpha"); +} + +BOOST_AUTO_TEST_CASE( versionSuffixNum ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0_alpha43 "); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0_alpha43"); +} + +BOOST_AUTO_TEST_CASE( versionSuffixNumRev ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0_alpha43-r33 "); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0_alpha43-r33"); +} + +BOOST_AUTO_TEST_CASE( versionLetter ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0g "); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0g"); +} + +BOOST_AUTO_TEST_CASE( versionRange ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0* "); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0*"); +} + +BOOST_AUTO_TEST_CASE( versionSlot ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0:foo"); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0"); + BOOST_REQUIRE(ds[0]->slot); + BOOST_REQUIRE_EQUAL(ds[0]->slot, "foo"); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( slot ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+:foo"); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(ds[0]->slot); + BOOST_REQUIRE_EQUAL(ds[0]->slot, "foo"); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( versionSlotSubSlot ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+-2.0.0:foo/bar"); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "2.0.0"); + BOOST_REQUIRE(ds[0]->slot); + BOOST_REQUIRE_EQUAL(ds[0]->slot, "foo/bar"); + BOOST_REQUIRE(ds[0]->use.empty()); +} + +BOOST_AUTO_TEST_CASE( slotUse ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+:foo[bar,baz]"); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(ds[0]->slot); + BOOST_REQUIRE_EQUAL(ds[0]->slot, "foo"); + BOOST_REQUIRE_EQUAL(ds[0]->use.size(), 2); + BOOST_REQUIRE_EQUAL(ds[0]->use[0], "bar"); + BOOST_REQUIRE_EQUAL(ds[0]->use[1], "baz"); +} + +BOOST_AUTO_TEST_CASE( use ) +{ + auto ds = Portage::Utils::Depend::parse(" >x11-libs/Gtk+[moo,cow]"); + BOOST_REQUIRE(!ds[0]->version); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE_EQUAL(ds[0]->use.size(), 2); + BOOST_REQUIRE_EQUAL(ds[0]->use[0], "cow"); + BOOST_REQUIRE_EQUAL(ds[0]->use[1], "moo"); +} + +BOOST_AUTO_TEST_CASE( aorb ) +{ + auto ds = Portage::Utils::Depend::parse(" || ( cat/a cat/b ) "); + BOOST_REQUIRE_EQUAL(ds.size(), 2); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(ds[1]->when.empty()); +} + +BOOST_AUTO_TEST_CASE( deepor ) +{ + auto ds = Portage::Utils::Depend::parse(" || ( ( cat/c cat/d ) ( cat/a cat/b ) ) "); + BOOST_REQUIRE_EQUAL(ds.size(), 4); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(ds[1]->when.empty()); + BOOST_REQUIRE(ds[2]->when.empty()); + BOOST_REQUIRE(ds[3]->when.empty()); +} + +BOOST_AUTO_TEST_CASE( annoyed1 ) +{ + auto ds = Portage::Utils::Depend::parse(" !<=app-emulation/emul-linux-x86-baselibs-20140508-r1 "); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + BOOST_REQUIRE(ds[0]->op); + BOOST_REQUIRE_EQUAL(*ds[0]->op, "!<="); + BOOST_REQUIRE_EQUAL(ds[0]->category, "app-emulation"); + BOOST_REQUIRE_EQUAL(ds[0]->package, "emul-linux-x86-baselibs"); + BOOST_REQUIRE(ds[0]->version); + BOOST_REQUIRE_EQUAL(*ds[0]->version, "20140508-r1"); + BOOST_REQUIRE(ds[0]->when.empty()); + BOOST_REQUIRE(!ds[0]->slot); + BOOST_REQUIRE(ds[0]->use.empty()); +} + -- cgit v1.2.3