aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--install.txt6
-rwxr-xr-xirkerd5
-rw-r--r--irkerd.service6
-rwxr-xr-xirkerhook.py67
-rw-r--r--irkerhook.xml3
6 files changed, 66 insertions, 23 deletions
diff --git a/Makefile b/Makefile
index ce8a1de..5b1cb87 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ irkerhook.html: irkerhook.xml
irk.1: irk.xml
xmlto man irk.xml
irk.html: irk.xml
- xmlto html-nochunks irkerhook.xml
+ xmlto html-nochunks irk.xml
install.html: install.txt
asciidoc -o install.html install.txt
diff --git a/install.txt b/install.txt
index c1a8f5a..93c20bb 100644
--- a/install.txt
+++ b/install.txt
@@ -47,6 +47,12 @@ inside the firewall, so that repository hooks can reach port 6659.
The file org.catb.irkerd.plist is a Mac OS/X plist that can be
installed to launch irkerd as a boot-time service on that system.
+irker.service is a systemd unit that can run irkerd as a boot-time
+service on systems that support systemd. This is configured to
+run irkerd under a seperate user account (irker), so this needs to
+be setup before starting irker, or the unit needs to be modified
+to use a different user.
+
== Installing irkerhook.py ==
Under git, a call to irkerhook.py should be installed in the update
diff --git a/irkerd b/irkerd
index 65c831b..d41a82c 100755
--- a/irkerd
+++ b/irkerd
@@ -197,7 +197,7 @@ class IRCClient():
def handle_event(self, connection, event):
with self.mutex:
h = self.event_handlers
- th = sorted(h.get("all_events", []) + h.get(event.type, []))
+ th = h.get("all_events", []) + h.get(event.type, [])
for handler in th:
handler(connection, event)
@@ -664,7 +664,8 @@ class Connection:
LOG.debug(traceback.format_exc())
finally:
# Make sure we don't leave any zombies behind
- self.connection.close()
+ if self.connection:
+ self.connection.close()
def live(self):
"Should this connection not be scavenged?"
return self.status != "expired"
diff --git a/irkerd.service b/irkerd.service
index d19378b..4e75ae2 100644
--- a/irkerd.service
+++ b/irkerd.service
@@ -2,11 +2,15 @@
# Distributed under the terms of the BSD LICENSE
[Unit]
-Description=irker daemon
+Description=Internet Relay Chat (IRC) notification daemon
Requires=network.target
+Documentation=man:irkerd(8) man:irkerhook(1) man:irk(1)
[Service]
+User=irker
ExecStart=/usr/bin/irkerd
+User=irker
[Install]
WantedBy=multi-user.target
+Alias=irker.service
diff --git a/irkerhook.py b/irkerhook.py
index 9768eac..b4893fd 100755
--- a/irkerhook.py
+++ b/irkerhook.py
@@ -18,12 +18,14 @@
# does not override it.
#
# SPDX-License-Identifier: BSD-2-Clause
+from __future__ import print_function, absolute_import
+
default_server = "localhost"
IRKER_PORT = 6659
# The default service used to turn your web-view URL into a tinyurl so it
# will take up less space on the IRC notification line.
-default_tinyifier = "http://tinyurl.com/api-create.php?url="
+default_tinyifier = u"http://tinyurl.com/api-create.php?url="
# Map magic urlprefix values to actual URL prefixes.
urlprefixmap = {
@@ -33,7 +35,7 @@ urlprefixmap = {
}
# By default, ship to the freenode #commits list
-default_channels = "irc://chat.freenode.net/#commits"
+default_channels = u"irc://chat.freenode.net/#commits"
#
# No user-serviceable parts below this line:
@@ -41,14 +43,25 @@ default_channels = "irc://chat.freenode.net/#commits"
version = "2.17"
-import os, sys, socket, urllib2, subprocess, locale, datetime, re
+import os, sys, socket, subprocess, locale, datetime, re
from pipes import quote as shellquote
try:
+ from urllib2 import urlopen, HTTPError
+except ImportError:
+ from urllib.error import HTTPError
+ from urllib.request import urlopen
+
+try:
import simplejson as json # Faster, also makes us Python-2.5-compatible
except ImportError:
import json
+if sys.version_info.major == 2:
+ string_type = unicode
+else:
+ string_type = str
+
try:
getstatusoutput = subprocess.getstatusoutput
except AttributeError:
@@ -56,7 +69,10 @@ except AttributeError:
getstatusoutput = commands.getstatusoutput
def do(command):
- return unicode(getstatusoutput(command)[1], locale.getlocale()[1] or 'UTF-8').encode(locale.getlocale()[1] or 'UTF-8')
+ if sys.version_info.major == 2:
+ return string_type(getstatusoutput(command)[1], locale.getlocale()[1] or 'UTF-8')
+ else:
+ return getstatusoutput(command)[1]
class Commit:
def __init__(self, extractor, commit):
@@ -72,7 +88,14 @@ class Commit:
self.author_date = None
self.commit_date = None
self.__dict__.update(extractor.__dict__)
- def __unicode__(self):
+
+ if sys.version_info.major == 2:
+ # Convert __str__ to __unicode__ for python 2
+ self.__unicode__ = self.__str__
+ # Not really needed, but maybe useful for debugging
+ self.__str__ = lambda x: x.__unicode__().encode('utf-8')
+
+ def __str__(self):
"Produce a notification string from this commit."
if self.urlprefix.lower() == "none":
self.url = ""
@@ -81,12 +104,12 @@ class Commit:
webview = (urlprefix % self.__dict__) + self.commit
try:
# See it the url is accessible
- res = urllib2.urlopen(webview)
+ res = urlopen(webview)
if self.tinyifier and self.tinyifier.lower() != "none":
try:
# Didn't get a retrieval error on the web
# view, so try to tinyify a reference to it.
- self.url = urllib2.urlopen(self.tinyifier + webview).read()
+ self.url = urlopen(self.tinyifier + webview).read()
try:
self.url = self.url.decode('UTF-8')
except UnicodeError:
@@ -95,14 +118,16 @@ class Commit:
self.url = webview
else:
self.url = webview
- except IOError as e:
+ except HTTPError as e:
if e.code == 401:
# Authentication error, so we assume the view is valid
self.url = webview
else:
self.url = ""
+ except IOError:
+ self.url = ""
res = self.template % self.__dict__
- return unicode(res, 'UTF-8') if not isinstance(res, unicode) else res
+ return string_type(res, 'UTF-8') if not isinstance(res, string_type) else res
class GenericExtractor:
"Generic class for encapsulating data from a VCS."
@@ -237,10 +262,10 @@ class GitExtractor(GenericExtractor):
self.channels = do("git config --get irker.channels")
self.email = do("git config --get irker.email")
self.tcp = do("git config --bool --get irker.tcp")
- self.template = do("git config --get irker.template") or '%(bold)s%(project)s:%(reset)s %(green)s%(author)s%(reset)s %(repo)s:%(yellow)s%(branch)s%(reset)s * %(bold)s%(rev)s%(reset)s / %(bold)s%(files)s%(reset)s: %(logmsg)s %(brown)s%(url)s%(reset)s'
+ self.template = do("git config --get irker.template") or u'%(bold)s%(project)s:%(reset)s %(green)s%(author)s%(reset)s %(repo)s:%(yellow)s%(branch)s%(reset)s * %(bold)s%(rev)s%(reset)s / %(bold)s%(files)s%(reset)s: %(logmsg)s %(brown)s%(url)s%(reset)s'
self.tinyifier = do("git config --get irker.tinyifier") or default_tinyifier
self.color = do("git config --get irker.color")
- self.urlprefix = do("git config --get irker.urlprefix") or "gitweb"
+ self.urlprefix = do("git config --get irker.urlprefix") or u"gitweb"
self.cialike = do("git config --get irker.cialike")
self.filtercmd = do("git config --get irker.filtercmd")
# These are git-specific
@@ -432,6 +457,10 @@ extractors = [GitExtractor, HgExtractor, SvnExtractor]
# VCS-dependent code ends here
+def convert_message(message):
+ """Convert the message to bytes to send to the socket"""
+ return message.encode(locale.getlocale()[1] or 'UTF-8') + b'\n'
+
def ship(extractor, commit, debug):
"Ship a notification for the specified commit."
metadata = extractor.commit_factory(commit)
@@ -439,7 +468,7 @@ def ship(extractor, commit, debug):
# This is where we apply filtering
if extractor.filtercmd:
cmd = '%s %s' % (shellquote(extractor.filtercmd),
- shellquote(json.dumps(metadata.__dict__)))
+ shellquote(json.dumps(metadata.__dict__)))
data = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read()
try:
metadata.__dict__.update(json.loads(data))
@@ -464,10 +493,10 @@ def ship(extractor, commit, debug):
# purposes the commit text is more important. If it's still too long
# there's nothing much can be done other than ship it expecting the IRC
# server to truncate.
- privmsg = unicode(metadata)
+ privmsg = string_type(metadata)
if len(privmsg) > 510:
metadata.files = ""
- privmsg = unicode(metadata)
+ privmsg = string_type(metadata)
# Anti-spamming guard. It's deliberate that we get maxchannels not from
# the user-filtered metadata but from the extractor data - means repo
@@ -479,7 +508,7 @@ def ship(extractor, commit, debug):
# Ready to ship.
message = json.dumps({"to": channels, "privmsg": privmsg})
if debug:
- print message
+ print(message)
elif channels:
try:
if extractor.email:
@@ -501,16 +530,16 @@ Subject: irker json
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((extractor.server or default_server, IRKER_PORT))
- sock.sendall(message + "\n")
+ sock.sendall(convert_message(message))
finally:
sock.close()
else:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- sock.sendto(message + "\n", (extractor.server or default_server, IRKER_PORT))
+ sock.sendto(convert_message(message), (extractor.server or default_server, IRKER_PORT))
finally:
sock.close()
- except socket.error, e:
+ except socket.error as e:
sys.stderr.write("%s\n" % e)
if __name__ == "__main__":
@@ -521,7 +550,7 @@ if __name__ == "__main__":
if arg == '-n':
notify = False
elif arg == '-V':
- print "irkerhook.py: version", version
+ print("irkerhook.py: version", version)
sys.exit(0)
elif arg.startswith("--repository="):
repository = arg[13:]
diff --git a/irkerhook.xml b/irkerhook.xml
index 2f068d2..d6f7b51 100644
--- a/irkerhook.xml
+++ b/irkerhook.xml
@@ -174,6 +174,9 @@ are available as %() substitutions.</para>
</varlistentry>
</variablelist>
+<para>irkerhook.py will run under both python 2 and python 3, but it does
+not support mercurial repositories under python 3 yet.</para>
+
<refsect2 id="git"><title>git</title>
<para>Under git, the normal way to invoke this hook (from within the