aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SBoTools/README.md1
-rw-r--r--SBoTools/__init__.py48
-rw-r--r--SBoTools/config.py42
-rw-r--r--SBoTools/plugin.py177
-rw-r--r--SBoTools/test.py15
-rwxr-xr-xbin/sbodb.pl123
6 files changed, 406 insertions, 0 deletions
diff --git a/SBoTools/README.md b/SBoTools/README.md
new file mode 100644
index 0000000..a694e68
--- /dev/null
+++ b/SBoTools/README.md
@@ -0,0 +1 @@
+Provides Slackware package database lookups.
diff --git a/SBoTools/__init__.py b/SBoTools/__init__.py
new file mode 100644
index 0000000..fe66e85
--- /dev/null
+++ b/SBoTools/__init__.py
@@ -0,0 +1,48 @@
+###
+# Copyright (c) 2021, B. Watson
+# All rights reserved.
+#
+#
+###
+
+"""
+SlackTools: Provides Unix manpage lookups
+"""
+
+import sys
+import supybot
+from supybot import world
+
+# Use this for the version of this plugin.
+__version__ = "0.0.1"
+
+# XXX Replace this with an appropriate author or supybot.Author instance.
+__author__ = supybot.Author('B. Watson', 'Urchlay', 'yalhcru@gmail.com')
+
+# This is a dictionary mapping supybot.Author instances to lists of
+# contributions.
+__contributors__ = {}
+
+# This is a url where the most recent plugin package can be downloaded.
+__url__ = ''
+
+from . import config
+from . import plugin
+if sys.version_info >= (3, 4):
+ from importlib import reload
+else:
+ from imp import reload
+# In case we're being reloaded.
+reload(config)
+reload(plugin)
+# Add more reloads here if you add third-party modules and want them to be
+# reloaded when this plugin is reloaded. Don't forget to import them as well!
+
+if world.testing:
+ from . import test
+
+Class = plugin.Class
+configure = config.configure
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
diff --git a/SBoTools/config.py b/SBoTools/config.py
new file mode 100644
index 0000000..b13dc28
--- /dev/null
+++ b/SBoTools/config.py
@@ -0,0 +1,42 @@
+###
+# Copyright (c) 2021, B. Watson
+# All rights reserved.
+#
+#
+###
+
+from supybot import conf, registry
+try:
+ from supybot.i18n import PluginInternationalization
+ _ = PluginInternationalization('SBoTools')
+except:
+ # Placeholder that allows to run the plugin on a bot
+ # without the i18n module
+ _ = lambda x: x
+
+
+def configure(advanced):
+ # This will be called by supybot to configure this module. advanced is
+ # a bool that specifies whether the user identified themself as an advanced
+ # user or not. You should effect your configuration by manipulating the
+ # registry as appropriate.
+ from supybot.questions import expect, anything, something, yn
+ conf.registerPlugin('SBoTools', True)
+
+
+SBoTools = conf.registerPlugin('SBoTools')
+# This is where your configuration variables (if any) should go. For example:
+# conf.registerGlobalValue(SBoTools, 'someConfigVariableName',
+# registry.Boolean(False, _("""Help for someConfigVariableName.""")))
+
+conf.registerGlobalValue(SBoTools, 'dbpath',
+ registry.String("/home/slackfacts/supybot/SBoTools.sqlite3", _("""Path to sqite3 database.""")))
+
+conf.registerGlobalValue(SBoTools, 'maxresults',
+ registry.Integer(5, _("""Maximum number of results to send to client.""")))
+
+## conf.registerGlobalValue(SBoTools, 'slackpath',
+## registry.String("/data/mirrors/slackware/slackware64-14.2", _("""Filesystem path to Slackware mirror (NO trailing slash!)""")))
+##
+## conf.registerGlobalValue(SBoTools, 'baseurl',
+## registry.String("https://slackware.uk/slackware/slackware64-14.2", _("""Web URL of Slackware mirror (NO trailing slash!)""")))
diff --git a/SBoTools/plugin.py b/SBoTools/plugin.py
new file mode 100644
index 0000000..0e18e9d
--- /dev/null
+++ b/SBoTools/plugin.py
@@ -0,0 +1,177 @@
+###
+# Copyright (c) 2021, B. Watson
+# All rights reserved.
+#
+#
+###
+
+# TODO: add maintainer name/email to the DB.
+
+import os
+import glob
+import subprocess
+import sys
+import re
+import sqlite3
+
+from supybot import utils, plugins, ircutils, callbacks
+from supybot.commands import *
+import supybot.utils.minisix as minisix
+
+try:
+ from supybot.i18n import PluginInternationalization
+ _ = PluginInternationalization('SBoTools')
+except ImportError:
+ # Placeholder that allows to run the plugin on a bot
+ # without the i18n module
+ _ = lambda x: x
+
+class SBoTools(callbacks.Plugin):
+ """Provides SlackBuilds.org build searches"""
+ threaded = True
+
+ db = None
+ categories = None
+
+ def getMaxResults(self, msg):
+ maxresults = self.registryValue('maxresults')
+ if msg.channel is None:
+ # private message, increase limit
+ maxresults *= 5
+ return maxresults
+
+ def InitDB(self):
+ if self.db is None:
+ filename = self.registryValue('dbpath')
+ if(os.path.exists(filename)):
+ self.db = sqlite3.connect(filename)
+ return self.db
+
+ def getCategory(self, cat):
+ if self.categories is None:
+ self.categories = {}
+ db = self.InitDB();
+ cursor = db.cursor()
+ cursor.execute("select id, name from categories");
+ result = cursor.fetchall()
+ for (id, name) in result:
+ self.categories[name] = id
+
+ if cat in self.categories:
+ return self.categories[cat]
+ else:
+ return None
+
+ def sbosearch(self, irc, msg, args, tflag, terms):
+ """ [<category/>]<build> | [-t] <searchterm> [<searchterm> ...]>
+
+ Search the SlackBuilds.org build database. Case-insensitive
+ substring match. Without -t, does a search by name only. With
+ -t, searches names, descriptions, and tags. With multiple search
+ terms, results are ANDed together.
+ """
+
+ category = None
+ if(not tflag):
+ if(len(terms) > 1):
+ irc.error("only one search term allowed unless using -t flag", Raise=True)
+ t = terms[0].split('/',1)
+ if(len(t) != 1):
+ category = self.getCategory(t[0])
+ if(category is None):
+ irc.error("invalid category '" + t[0] + "'", Raise=True)
+ terms[0] = t[1]
+
+
+ db = self.InitDB();
+ cursor = db.cursor()
+ tags = False;
+
+ sql = "select distinct(b.id) from builds b, tags t "
+ sql += "where b.id = t.build_id"
+
+ if(category is not None):
+ sql += " and b.category=" + str(category) + " "
+
+ for (term) in terms:
+ tlike = "'%" + term.replace("'", "''") + "%'"
+ if(tflag):
+ sql += " and (b.name like " + tlike + " or b.descrip like " + tlike + " or t.tag like " + tlike + ")"
+ else:
+ sql += " and b.name like " + tlike
+
+ maxresults = self.getMaxResults(msg)
+ sql += " limit " + str(maxresults + 1)
+
+ cursor.execute(sql)
+ result = cursor.fetchall()
+ if(len(result) == 0):
+ irc.reply("no results found")
+ else:
+ lines = []
+ for (i) in result:
+ c2 = db.cursor()
+ c2.execute("select b.name, c.name from builds b, categories c where b.category=c.id and b.id=?", (i[0],))
+ xres = c2.fetchall();
+ if(len(result) == 1):
+ (name, cat) = xres[0]
+ #irc.reply("would be showing !sboinfo " + cat + "/" + name);
+ self.SBoInfo(irc, msg, cat + "/" + name)
+ return;
+ for (name, cat) in xres:
+ lines.append(cat + "/" + name)
+
+ if(len(result) > maxresults):
+ lines.append("[too many results, only showing first " + str(maxresults) + "]")
+ irc.replies(lines, joiner=' | ')
+
+ sbosearch = thread(wrap(sbosearch, [optional(('literal', ['-t'])), many('somethingWithoutSpaces')]))
+
+ def SBoInfo(self, irc, msg, catbuild):
+ category = None
+ build = None
+
+ t = catbuild.split('/',1)
+ if(len(t) == 1):
+ build = catbuild
+ else:
+ category = self.getCategory(t[0])
+ if(category is None):
+ irc.error("invalid category '" + t[0] + "'", Raise=True)
+ build = t[1]
+
+ db = self.InitDB();
+ cursor = db.cursor()
+ if(category is None):
+ cursor.execute("select b.id, b.name, c.name, b.descrip, b.version from builds b, categories c where b.category = c.id and b.name = ?", (build,))
+ else:
+ cursor.execute("select b.id, b.name, c.name, b.descrip, b.version from builds b, categories c where c.id = ? and b.category = c.id and b.name = ?", (category, build,))
+
+ result = cursor.fetchall()
+ if(len(result) == 0):
+ irc.reply("no results found")
+ else:
+ lines = []
+ for (bid, bname, cname, bdescrip, bversion) in result:
+ lines.append(cname + "/" + bname + " v" + bversion + ": " + bdescrip)
+ cursor.execute("select b.name from builds b, deps d where d.build_id=? and b.id=d.depends_on", (bid,))
+ depres = cursor.fetchall()
+ if(len(depres) != 0):
+ deps = ""
+ for (depname) in depres:
+ deps += depname[0] + " "
+ lines.append("deps: " + deps)
+
+ irc.replies(lines, joiner=' | ')
+
+ def sboinfo(self, irc, msg, args, catbuild):
+ """ [<category/>]<build>
+
+ Show detailed information about a SBo build. The argument must be
+ an exact match (this is not a search).
+ """
+ self.SBoInfo(irc, msg, catbuild)
+
+ sboinfo = thread(wrap(sboinfo, ['somethingWithoutSpaces']))
+
+Class = SBoTools
diff --git a/SBoTools/test.py b/SBoTools/test.py
new file mode 100644
index 0000000..14d770b
--- /dev/null
+++ b/SBoTools/test.py
@@ -0,0 +1,15 @@
+###
+# Copyright (c) 2021, B. Watson
+# All rights reserved.
+#
+#
+###
+
+from supybot.test import *
+
+
+class SlackToolsTestCase(PluginTestCase):
+ plugins = ('SlackTools',)
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
diff --git a/bin/sbodb.pl b/bin/sbodb.pl
new file mode 100755
index 0000000..bfd997e
--- /dev/null
+++ b/bin/sbodb.pl
@@ -0,0 +1,123 @@
+#!/usr/bin/perl -w
+
+# create SBo.sqlite3 database for SBo limnoria plugin.
+# requires SLACKBUILDS.txt and TAGS.txt from the SBo repo.
+# https://slackware.uk/slackbuilds.org/14.2/SLACKBUILDS.TXT
+# https://slackware.uk/slackbuilds.org/14.2/TAGS.txt
+
+print <<EOF;
+pragma journal_mode = memory;
+begin transaction;
+
+create table categories (
+ id integer primary key not null,
+ name varchar not null);
+
+create table builds (
+ id integer primary key not null,
+ name varchar not null,
+ descrip varchar not null,
+ category integer not null,
+ version varchar not null,
+ foreign key (category) references categories);
+
+create table deps (
+ build_id integer not null,
+ depends_on integer not null,
+ foreign key (build_id) references categories,
+ foreign key (depends_on) references categories);
+
+create table tags (
+ build_id integer not null,
+ tag varchar not null,
+ foreign key (build_id) references builds);
+
+create unique index t_idx on tags(build_id, tag);
+
+EOF
+
+$lastcat = 0;
+sub get_cat_id {
+ my $catname = shift;
+ if(!$catids{$catname}) {
+ $lastcat++;
+ print "insert into categories values($lastcat, '$catname');\n";
+ $catids{$catname} = $lastcat;
+ }
+ return $catids{$catname};
+}
+
+open $sbtxt, "<" . ($ARGV[0] || "SLACKBUILDS.TXT") or die $!;
+{
+ local $/ = '';
+ while(<$sbtxt>) {
+ my ($name, $cat, $ver, $deps, $desc,);
+ $deps = "";
+ chomp;
+ /^SLACKBUILD NAME:\s+(\S+)$/m and $name = $1;
+ /^SLACKBUILD LOCATION:\s+\.\/([^\/]*)\//m and $cat = $1;
+ /^SLACKBUILD VERSION:\s+(\S+)$/m and $ver = $1;
+ /^SLACKBUILD REQUIRES:\s+(\S.+)\n/m and $deps = $1;
+ /^SLACKBUILD SHORT DESCRIPTION:\s+(.+)$/m and $desc = $1;
+
+ if($desc =~ /^$name \((.+)\)$/) {
+ $desc = $1;
+ }
+
+ $desc =~ s/'/''/g;
+ $catid = get_cat_id($cat);
+ $buildcat{$name} = $catid;
+ $buildver{$name} = $ver;
+ $builddeps{$name} = $deps;
+ $builddesc{$name} = $desc;
+ push @builds, $name;
+ }
+}
+close $sbtxt;
+
+print "\n";
+
+$buildid = 0;
+for(@builds) {
+ $buildid++;
+ $buildids{$_} = $buildid;
+ print <<EOF;
+insert into builds values(
+ $buildid,
+ '$_',
+ '$builddesc{$_}',
+ $buildcat{$_},
+ '$buildver{$_}');
+
+EOF
+}
+
+for(keys %builddeps) {
+ my $bid = $buildids{$_};
+ my @d = split /\s+/, $builddeps{$_};
+ #warn "build $_ id $b, deps " . join(",", @d) . "\n";
+ for(@d) {
+ next if /%README%/;
+ print <<EOF;
+insert into deps values($bid, $buildids{$_});
+EOF
+ }
+}
+
+open $tagstxt, "<" . ($ARGV[1] || "TAGS.txt") or die $!;
+while(<$tagstxt>) {
+ my ($build, $t, @tags);
+ chomp;
+ next if /: No tags found for/;
+ ($build, $t) = /^([^:]*):\s+(.*)$/;
+ @tags = split /,/, $t;
+ for(@tags) {
+ next if /^\s*$/;
+ s/'/''/g;
+ print <<EOF;
+insert into tags values($buildids{$build}, '$_');
+EOF
+ }
+}
+
+print "commit;\n";