diff options
-rw-r--r-- | DEPENDENCIES | 4 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | examples/compact | 2 | ||||
-rw-r--r-- | src/plugins/ii.py | 142 | ||||
-rw-r--r-- | src/plugins/inotify.py | 7 |
5 files changed, 153 insertions, 3 deletions
diff --git a/DEPENDENCIES b/DEPENDENCIES index 72ca15f..9103596 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -15,7 +15,8 @@ OPTIONAL RUNTIME DEPENDENCIES: python-pytz: for timezone support python-sysv-ipc: for ropty example iputils: for ping support - inotify-tools: for inotify support + inotify-tools: for ii and inotify support + ii: for ii support alarm: for limiting the time of a file search in locks findutils: for file search in locks graphicsmagick: for image support @@ -23,6 +24,7 @@ OPTIONAL RUNTIME DEPENDENCIES: file: for image support librsvg: for image support solar-python>=2.5: for solar data + pdeath: for automatic killing of child processes on exit BUILD DEPENDENCIES: @@ -23,7 +23,6 @@ List of plugins to implement: e-mail Identify active and visible windows natural disaster reports - IRC /proc/interrupts /proc/net/sockstat /proc/net/sockstat6 diff --git a/examples/compact b/examples/compact index 6ba9fe7..0ae737d 100644 --- a/examples/compact +++ b/examples/compact @@ -110,7 +110,7 @@ def pdeath(signal, *command): path = os.environ['PATH'].split(':') for p in path: p += '/pdeath' - if os.access(p, os.F_OK | os.X_OK, effective_ids = True): + if os.access(p, os.X_OK, effective_ids = True): return (p, signal, *command) except: pass diff --git a/src/plugins/ii.py b/src/plugins/ii.py new file mode 100644 index 0000000..5ffb266 --- /dev/null +++ b/src/plugins/ii.py @@ -0,0 +1,142 @@ +# -*- python -*- +''' +xpybar – xmobar replacement written in python +Copyright © 2014, 2015, 2016 Mattias Andrée (maandree@member.fsf.org) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +''' + + +class II: + ''' + IRC interface, requires a running instance of ii <https://git.suckless.org/ii> + ''' + + + def __init__(self, channel, prefix = None): + ''' + Constructor + + @param channel:str The name of the server or the name of the + server followed by a slash and the name of + the channel including the she + @param prefix:str? The argument associated with ii's -i flag + ''' + import pwd, os + if prefix is None: + prefix = pwd.getpwuid(os.getuid()).pw_dir + '/irc' + self.infile = '%s/%s/in' % (prefix, channel) + self.outfile = '%s/%s/out' % (prefix, channel) + self.log = [] + self.time = '0000-00-00 00:00 ' + + + def write(self, text): + ''' + Write to the channel + + @param text:str The message or command + ''' + text = (text + '\n').encode('utf-8') + with open(self.infile, 'wb') as file: + file.write(text) + file.flush() + + + def read(self): + ''' + Fetch new messages from the channel + + @return :list<str> List of new messages + ''' + with open(self.outfile, 'rb') as file: + text = file.read() + text = text.decode('utf-8', 'replace').split('\n')[:-1] + i = 0 + for line in text: + if line[:17] >= self.time: + break + i += 1 + text = text[i:] + i = 0 + while i < len(text) and i < len(self.log): + if text[i] != self.log[i]: + break + i += 1 + text = text[i:] + if len(text) == 0: + return text + last = text[-1][:17] + if last == self.time: + self.log.extend(text) + return text + self.log = [] + self.time = last + i = 0 + for line in text: + if line[:17] == self.time: + break + i += 1 + self.log = text[i:] + return text + + + def wait(self, timeout = None): + ''' + Wait until more messages are available + + @param timeout:int? The number of seconds to wait + before return unconditionally + ''' + import os + command = ['inotifywait', '-e', 'close_write,modify'] + if timeout is not None: + command += ['-t', str(int(timeout + 0.5))] + command += ['--', self.outfile] + if 'PATH' in os.environ: + path = os.environ['PATH'].split('.') + for p in path: + p += '/pdeath' + if os.access(p, os.X_OK, effective_ids = True): + command = [p, 'HUP'] + command + break + spawn_read(*command) + + + @staticmethod + def list_channels(prefix = None): + ''' + Fetch a list of all joined servers and channels + + @param prefix:str? The argument associated with ii's -i flag + @return :list<list> List of servers and channels + ''' + import pwd, os + if prefix is None: + prefix = pwd.getpwuid(os.getuid()).pw_dir + '/irc' + ret = [] + def isfifo(f): + try: + return os.path.stat.S_ISFIFO(os.stat('f').st_mode) + except: + return False + def recurse(d): + fs = os.listdir(d) + for f in fs: + f = d + '/' + f + if os.path.isfile(f + '/out') and isfifo(f + '/in'): + ret.append(f[len(prefix) + 1:]) + recurse(prefix) + return ret + diff --git a/src/plugins/inotify.py b/src/plugins/inotify.py index f92db48..84b24e9 100644 --- a/src/plugins/inotify.py +++ b/src/plugins/inotify.py @@ -51,6 +51,13 @@ class Inotify: command.append('-e') command.append(event) command += list(arguments) + if 'PATH' in os.environ: + path = os.environ['PATH'].split('.') + for p in path: + p += '/pdeath' + if os.access(p, os.X_OK, effective_ids = True): + command = [p, 'HUP'] + command + break def start(): with LineReader(spawn(*command)) as reader: while True: |