summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2016-05-02 19:48:38 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2016-05-02 19:48:38 +0100
commitc6e09edc498cdbcb307f97e5f18861697558d6ce (patch)
tree80bd2e4b954106fcef8eb71164f1638a2aea7b5e
parentAdd a flexible extensible lexer (diff)
downloadgentoobrowse-api-c6e09edc498cdbcb307f97e5f18861697558d6ce.tar.bz2
gentoobrowse-api-c6e09edc498cdbcb307f97e5f18861697558d6ce.tar.xz
gentoobrowse-api-c6e09edc498cdbcb307f97e5f18861697558d6ce.zip
Add a dependency scanner/extracter
-rw-r--r--gentoobrowse-api/domain/portage-models.ice10
-rw-r--r--gentoobrowse-api/service/depend.cpp87
-rw-r--r--gentoobrowse-api/service/depend.h25
-rw-r--r--gentoobrowse-api/unittests/Jamfile.jam6
-rw-r--r--gentoobrowse-api/unittests/testDepend.cpp264
5 files changed, 392 insertions, 0 deletions
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<Category> Categories;
sequence<Package> Packages;
sequence<Ebuild> 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 <boost/algorithm/string/split.hpp>
+
+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<typename T, typename Y> IceUtil::Optional<T> iuo(const boost::optional<Y> & x)
+ {
+ if (x) {
+ return *x;
+ }
+ return IceUtil::Optional<T>();
+ }
+
+ template<typename T, typename Y> std::vector<T> split(const boost::optional<Y> & x)
+ {
+ std::vector<T> 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<std::string>(es->pattern->match(1)), // op
+ *es->pattern->match(2), // category
+ *es->pattern->match(3), // package
+ iuo<std::string>(es->pattern->match(8)), // version
+ iuo<std::string>(es->pattern->match(13)), // slot
+ split<std::string>(es->pattern->match(16)) // use
+ ));
+ } });
+ }
+
+ std::vector<Gentoo::DependencyPtr>
+ 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 <visibility.h>
+#include <istream>
+#include <vector>
+#include <portage-models.h>
+#include "utils/lexer.h"
+
+namespace Portage {
+ namespace Utils {
+ class Depend : Gentoo::Utils::Lexer {
+ private:
+ Depend();
+ Gentoo::StringList when;
+
+ public:
+ DLL_PUBLIC static std::vector<Gentoo::DependencyPtr> parse(const std::string &);
+ std::vector<Gentoo::DependencyPtr> 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 :
<define>ROOT=\"$(me)\"
;
+run
+ testDepend.cpp
+ : : :
+ <define>BOOST_TEST_DYN_LINK
+ <library>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 <boost/test/unit_test.hpp>
+
+#include <depend.h>
+
+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());
+}
+