From 15128b94b496324a1c0afd6cbdd7fffbdaa18ba7 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 17 Jun 2021 01:58:33 -0400 Subject: Initial commit. --- Manpages/README.md | 1 + Manpages/__init__.py | 48 ++++++++++++++++++++++ Manpages/config.py | 36 +++++++++++++++++ Manpages/local/__init__.py | 1 + Manpages/plugin.py | 99 ++++++++++++++++++++++++++++++++++++++++++++++ Manpages/plugin.py.old | 98 +++++++++++++++++++++++++++++++++++++++++++++ Manpages/test.py | 15 +++++++ 7 files changed, 298 insertions(+) create mode 100644 Manpages/README.md create mode 100644 Manpages/__init__.py create mode 100644 Manpages/config.py create mode 100644 Manpages/local/__init__.py create mode 100644 Manpages/plugin.py create mode 100644 Manpages/plugin.py.old create mode 100644 Manpages/test.py (limited to 'Manpages') diff --git a/Manpages/README.md b/Manpages/README.md new file mode 100644 index 0000000..b12ae49 --- /dev/null +++ b/Manpages/README.md @@ -0,0 +1 @@ +Provides Unix manpage lookups diff --git a/Manpages/__init__.py b/Manpages/__init__.py new file mode 100644 index 0000000..c726c08 --- /dev/null +++ b/Manpages/__init__.py @@ -0,0 +1,48 @@ +### +# Copyright (c) 2021, B. Watson +# All rights reserved. +# +# +### + +""" +Manpages: 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/Manpages/config.py b/Manpages/config.py new file mode 100644 index 0000000..b0ab3ff --- /dev/null +++ b/Manpages/config.py @@ -0,0 +1,36 @@ +### +# Copyright (c) 2021, B. Watson +# All rights reserved. +# +# +### + +from supybot import conf, registry +try: + from supybot.i18n import PluginInternationalization + _ = PluginInternationalization('Manpages') +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('Manpages', True) + + +Manpages = conf.registerPlugin('Manpages') +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(Manpages, 'someConfigVariableName', +# registry.Boolean(False, _("""Help for someConfigVariableName."""))) + +conf.registerGlobalValue(Manpages, 'dbpath', + registry.String("/home/slackfacts/supybot/Manpages.sqlite3", _("""Path to sqite3 database."""))) + +conf.registerGlobalValue(Manpages, 'maxresults', + registry.Integer(5, _("""Maximum number of results to send to client."""))) diff --git a/Manpages/local/__init__.py b/Manpages/local/__init__.py new file mode 100644 index 0000000..e86e97b --- /dev/null +++ b/Manpages/local/__init__.py @@ -0,0 +1 @@ +# Stub so local is a module, used for third-party modules diff --git a/Manpages/plugin.py b/Manpages/plugin.py new file mode 100644 index 0000000..e3913d1 --- /dev/null +++ b/Manpages/plugin.py @@ -0,0 +1,99 @@ +### +# Copyright (c) 2021, B. Watson +# All rights reserved. +# +# +### + +import os +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('Manpages') +except ImportError: + # Placeholder that allows to run the plugin on a bot + # without the i18n module + _ = lambda x: x + + +class Manpages(callbacks.Plugin): + """Provides Unix manpage lookups""" + threaded = True + + db = None + + 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 + + # man() is a *very* limited subset of what the real + # man command does. Should maybe be called whatis instead, + # use the Aka plugin to create an alias: + # load Aka + # aka add whatis man $* + def man(self, irc, msg, args, sect_or_page, page): + """ [
|-k] + + Look up man pages and show their summaries. Without -k, searches + man pages by name (same as the OS "whatis" or "man -f" commands). + With -k, also searches descriptions (same as OS "man -k" or "apropos"). + With
, limits search to a single man section (otherwise all + sections are searched). + """ + + db = self.InitDB(); + if db is None: + irc.error("manpage database doesn't exist", Raise=True) + + maxresults = self.registryValue('maxresults') + if msg.channel is None: + # private message, increase limit + maxresults *= 5 + + cursor = db.cursor() + + errmsg = "No manual entry for " + + selectfrom = "select page, section, desc from whatis " + orderby = " order by section " + limit = " limit " + str(maxresults + 1) + " " + + if page is None: + cursor.execute(selectfrom + "where page glob ?" + orderby + limit, (sect_or_page,)) + errmsg = errmsg + sect_or_page + else: + if sect_or_page == "-k": + glob = "*" + page + "*" + cursor.execute(selectfrom + "where page glob ? or desc glob ? " + orderby + limit, (glob, glob)) + errmsg = "No man pages matching " + page + else: + cursor.execute(selectfrom + "where section=? and page glob ? " + orderby + limit, (sect_or_page, page)) + errmsg = errmsg + page + " in section " + sect_or_page + + result = cursor.fetchall() + + lines = [] + + if len(result) == 0: + irc.reply(errmsg) + else: + for (page, section, desc) in result: + lines.append(ircutils.bold(page + "(" + section + ")") + ": " + desc) + if(len(result) > maxresults): + lines.append("[too many results, only showing first " + str(maxresults) + "]") + irc.replies(lines, joiner=' | ') + + man = thread(wrap(man, ['somethingWithoutSpaces', optional('somethingWithoutSpaces')])) + +Class = Manpages diff --git a/Manpages/plugin.py.old b/Manpages/plugin.py.old new file mode 100644 index 0000000..b60b4dd --- /dev/null +++ b/Manpages/plugin.py.old @@ -0,0 +1,98 @@ +### +# Copyright (c) 2021, B. Watson +# All rights reserved. +# +# +### + +import os +import subprocess +import sys +import re + +from supybot import utils, plugins, ircutils, callbacks +from supybot.commands import * +import supybot.utils.minisix as minisix + +try: + from supybot.i18n import PluginInternationalization + _ = PluginInternationalization('Manpages') +except ImportError: + # Placeholder that allows to run the plugin on a bot + # without the i18n module + _ = lambda x: x + + +# The regex stuff is to turn this: +# ls (1) - list directory contents +# into this: +# ls(1) - list directory contents + +class Manpages(callbacks.Plugin): + """Provides Unix manpage and whereis lookups""" + threaded = True + + re_sub_spaces = re.compile(r"\s\s+") + re_sub_paren = re.compile(r"\s\(") + + def Command(self, irc, msg, args): + try: + with open(os.devnull) as null: + child = subprocess.Popen(args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=null) + except OSError as e: + irc.error('Man page lookup failed.', Raise=True) + (out, err) = child.communicate() + child.wait() + out = out + err + if minisix.PY3: + lines = [i.decode('utf-8').rstrip() for i in out.splitlines()] + lines = list(map(str, lines)) + else: + lines = out.splitlines() + lines = list(map(str.rstrip, lines)) + lines = filter(None, lines) + return lines + + # man() is a *very* limited subset of what the real + # man command does. Should maybe be called whatis instead, + # use the Aka plugin to create an alias: + # load Aka + # aka add whatis man $* + def man(self, irc, msg, args, sect_or_page, page): + """ Usage: man
, or man for all sections """ + + cmd = [ '/usr/bin/man', '-f' ] + + try: + sect = int(sect_or_page) + if page is None: + irc.error("Missing ", Raise=True) + else: + cmd.append("-s") + cmd.append(sect_or_page) + cmd.append(page) + except ValueError: + if page is None: + cmd.append(sect_or_page) + else: + irc.error("Invalid
", Raise=True) + + lines = self.Command(irc, msg, cmd) + + lines = [self.re_sub_spaces.sub(' ', i) for i in lines] + lines = [self.re_sub_paren.sub('(', i) for i in lines] + irc.replies(lines, joiner=' | ') + + man = thread(wrap(man, ['somethingWithoutSpaces', optional('somethingWithoutSpaces')])) + + # whereis() is a limited subset of the real whereis. + def whereis(self, irc, msg, args, name): + """ """ + lines = self.Command(irc, msg, [ '/usr/bin/whereis', name ]) + irc.replies(lines, joiner=' | ') + whereis = thread(wrap(whereis, ['somethingWithoutSpaces'])) + +Class = Manpages diff --git a/Manpages/test.py b/Manpages/test.py new file mode 100644 index 0000000..53e803a --- /dev/null +++ b/Manpages/test.py @@ -0,0 +1,15 @@ +### +# Copyright (c) 2021, B. Watson +# All rights reserved. +# +# +### + +from supybot.test import * + + +class ManpagesTestCase(PluginTestCase): + plugins = ('Manpages',) + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: -- cgit v1.2.3