Slackbot for ELOG

import os
import re

import pyinotify

from pyslack import SlackClient    # pip install pyslack-real

wm = pyinotify.WatchManager()
mask = pyinotify.IN_CLOSE_WRITE

URL = 'http://elog.km3net.de'
# LOGBOOK_PATH = '/home/elog/elog'
LOGBOOK_PATH = '/usr/local/elog/logbooks'
BOTNAME = 'ELOG'
DEFAULT_DESTINATION = '#elog'
DESTINATIONS = {
    'Operations_IT': '#operations_it',
    'Operations_FR': '#operations_fr',
    #    'Qualification': '#elog',
    #    'DOM_Integration': '#elog',
    #    'DU_Integration': '#elog',
    #    'DAQ_Readout': '#elog',
    #    'Electronics': '#elog',
    #    'Analysis': '#elog',
    'Computing and Software': '#software',
}

slack = SlackClient("YOUR_SLACK_API_TOKEN_HERE")


class ElogEntry(object):
    def __init__(self, logbook, msg_id=None):
        self.logbook = logbook
        self.id = msg_id
        self.header = {}
        self.content = ''

    @property
    def author(self):
        return self._lookup('Author')

    @property
    def type(self):
        return self._lookup('Type')

    @property
    def subject(self):
        return self._lookup('Subject')

    @property
    def url(self):
        escaped = re.sub(r"[\s_]+", '+', self.logbook)
        return URL + '/' + escaped + '/' + str(self.id)

    def _lookup(self, key):
        try:
            return self.header[key]
        except KeyError:
            return "Unknown"

    def __repr__(self):
        return (
            "ELOG entry from *{0.author}* in *{0.logbook}* (_{0.type}_):\n"
            "*{0.subject}*\n{1}...\n<{0.url}>".format(
                self, self.content[:150]
            )
        )


class ElogEntryBundle(object):
    def __init__(self, pathname):
        self.logbook = dirname(pathname)

        with open(pathname) as input_file:
            self.entries = self._parse_entries(input_file)

    @property
    def newest_entry(self):
        return self.entries[-1]

    def _parse_entries(self, input_file, msg_id=None):
        if msg_id is None:
            line = input_file.readline()
            if not line.startswith('$@MID@$:'):
                raise ValueError("Not an ELOG-entry file!")
            msg_id = int(line.split(':')[1])

        entry = ElogEntry(self.logbook, msg_id)
        for line in input_file:
            if line.startswith(40 * '='):
                break
            parameter, value = re.findall(r'([^:.]*): (.*)', line)[0]
            entry.header[parameter] = value
        for line in input_file:
            if line.startswith('$@MID@$:'):
                msg_id = int(line.split(':')[1])
                return [entry] + self._parse_entries(input_file, msg_id)
            else:
                entry.content += line
        return [entry]


class EventHandler(pyinotify.ProcessEvent):
    def my_init(self):
        self.logged_ids = []

    def process_IN_CLOSE_WRITE(self, event):
        if not self._is_valid_filetype(event.pathname):
            print("Not a valid filetype: {0}".format(event.pathname))
            return

        try:
            elog_bundle = ElogEntryBundle(event.pathname)
            elog_entry = elog_bundle.newest_entry
        except ValueError:
            print("Could not parse '{0}'. Ignoring...".format(event.pathname))
            return

        try:
            destination = DESTINATIONS[elog_entry.logbook]
        except KeyError:
            print(
                "No destination for logbook '{0}'. Using only default...".
                format(elog_entry.logbook)
            )
            destination = None
        finally:
            if elog_entry.id in self.logged_ids:
                return    # For now skip, since it often duplicates!
                pre = 'Updated '
            else:
                pre = ''
                self.logged_ids.append(elog_entry.id)
            message = pre + str(elog_entry)
            print(42 * "#")
            print("Filename: " + event.name)
            print("Elog Entry ID: " + str(elog_entry.id))
            print(42 * "-")
            print(message)
            print(42 * "/")
            if destination:
                slack.chat_post_message(destination, message, username=BOTNAME)
            # else:
            slack.chat_post_message(
                DEFAULT_DESTINATION, message, username=BOTNAME
            )

    def _is_valid_filetype(self, path):
        return path.endswith('.log')


def dirname(filepath):
    return os.path.basename(os.path.dirname(filepath))


handler = EventHandler()
notifier = pyinotify.Notifier(wm, handler)
wdd = wm.add_watch(LOGBOOK_PATH, mask, rec=True)

notifier.loop()

Total running time of the script: ( 0 minutes 0.000 seconds)

Gallery generated by Sphinx-Gallery