@@ -1,92 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
import string, re, subprocess | |||
from config.irc_config import * | |||
s, send, say, action, notice, join = None, None, None, None, None, None | |||
def check_triggers(cmds, act, nick, ident, host, chan, msg = None): | |||
global s, send, say, action, notice, join # set commands as globals so we can use them in other functions | |||
s, send, say, action, notice, join = cmds # unpack commands | |||
if act == "join": | |||
pass | |||
if act == "msg_private": | |||
pass | |||
if act == "msg_public": | |||
pass | |||
if act == "msg": | |||
if msg == "!test": | |||
cmd_test(nick, chan) | |||
if msg.startswith("!git"): | |||
cmd_git(nick, host, chan, msg) | |||
def get_args(msg): # get command arguments | |||
args = msg.strip().split(' ') # strip out extra whitespace and split the message into a list | |||
while '' in args: # remove any empty arguments | |||
args.remove('') | |||
return args[1:] # remove the command itself | |||
def cmd_test(nick, chan): # bot test | |||
say(chan, "Hey \x02%s\x0F!" % nick) | |||
def cmd_git(nick, host, chan, msg): # commands to interface with the bot's git repository | |||
if host not in ADMINS: | |||
say(chan, "\x02%s\x0F: you must be a bot admin to use this command." % nick) | |||
return | |||
args = get_args(msg) | |||
if not args: | |||
say(chan, "\x02%s\x0F: no arguments provided." % nick) | |||
return | |||
if args[0] == "help": # display all commands | |||
cmds = ["\x0303branch\x0301 (show current branch)", "\x0303branches\x0301 (show all branches)", | |||
"\x0303checkout\x0301 (switch branches)", "\x0303pull\x0301 (update current branch)"] | |||
cmds = ', '.join(cmds) | |||
say(chan, "\x02%s\x0F: sub-commands are: %s" % (nick, cmds)) | |||
elif args[0] == "branch": # get our current branch | |||
branch = subprocess.check_output(['git', 'name-rev', '--name-only', 'HEAD'], stderr=subprocess.STDOUT) # git name-rev --name-only HEAD | |||
branch = branch[:-1] # strip newline | |||
say(chan, "\x02%s\x0F: currently on branch \x0302%s\x0301." % (nick, branch)) | |||
elif args[0] == "branches": # get list of branches | |||
branches = subprocess.check_output(['git', 'branch'], stderr=subprocess.STDOUT) # git branch | |||
branches = branches[:-1] # strip newline | |||
branches = branches.replace('\n* ', ', ') # cleanup extraneous characters | |||
branches = branches.replace('* ', ' ') | |||
branches = branches.replace('\n ', ', ') | |||
branches = branches.strip() | |||
say(chan, "\x02%s\x0F: branches: \x0302%s\x0301." % (nick, branches)) | |||
elif args[0] == "checkout": # switch branches | |||
try: | |||
branch = args[1] | |||
except IndexError: # no branch name provided | |||
say(chan, "\x02%s\x0F: switch to which branch?" % nick) | |||
return | |||
try: | |||
result = subprocess.check_output(['git', 'checkout', branch], stderr=subprocess.STDOUT) # git checkout our_branch | |||
if "Already on" in result: | |||
say(chan, "\x02%s\x0F: already on \x0302%s\x0301!" % (nick, branch)) | |||
else: | |||
say(chan, "\x02%s\x0F: switched to branch \x0302%s\x0301." % (nick, branch)) | |||
except subprocess.CalledProcessError: # git couldn't switch branches | |||
say(chan, "\x02%s\x0F: branch \x0302%s\x0301 does not exist!" % (nick, branch)) | |||
elif args[0] == "pull": # pull from remote repository | |||
branch = subprocess.check_output(['git', 'name-rev', '--name-only', 'HEAD'], stderr=subprocess.STDOUT) # git name-rev --name-only HEAD | |||
branch = branch[:-1] # strip newline | |||
say(chan, "\x02%s\x0F: pulling from remote (currently on \x0302%s\x0301)..." % (nick, branch)) | |||
result = subprocess.check_output(['git', 'pull']) # pull from remote | |||
if "Already up-to-date." in result: | |||
say(chan, "\x02%s\x0F: done; no new changes." % nick) | |||
else: | |||
say(chan, "\x02%s\x0F: done; new changes merged." % nick) | |||
else: | |||
say(chan, "\x02%s\x0F: unknown argument: \x0303%s\x0301." % (nick, args[0])) |
@@ -2,73 +2,62 @@ | |||
## Imports | |||
import socket, string, re | |||
from actions import * | |||
from config.irc_config import * | |||
from config.secure_config import * | |||
def send(msg): # send a message 'msg' to the server | |||
s.send(msg + "\r\n") | |||
print " %s" % msg | |||
def say(target, msg): # send a private message 'msg' to 'target' | |||
send("PRIVMSG %s :%s" % (target, msg)) | |||
def action(target, msg): # send a message as an action | |||
say(target,"%sACTION %s%s" % (chr(1), msg, chr(1))) | |||
def notice(target, msg): # send a notice 'msg' to 'target' | |||
send("NOTICE %s :%s" % (target, msg)) | |||
def join(chan): # join channel 'chan' | |||
send("JOIN %s" % chan) | |||
cmds = (s, send, say, action, notice, join) # pack up commands | |||
from irc import triggers | |||
from irc.actions import * | |||
from irc.data import * | |||
def main(): | |||
readbuffer = str() | |||
data = [s, send, say, notice, join] | |||
read_buffer = str() | |||
while 1: | |||
readbuffer = readbuffer + s.recv(1024) | |||
temp = string.split(readbuffer, "\n") | |||
readbuffer = temp.pop() | |||
read_buffer = read_buffer + actions.sock.recv(1024) | |||
temp = string.split(read_buffer, "\n") | |||
read_buffer = temp.pop() | |||
for line in temp: | |||
line2 = string.split(string.rstrip(line)) | |||
line = string.split(string.rstrip(line)) | |||
data = Data() | |||
if line2[1] == "JOIN": | |||
nick, ident, host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line2[0])[0] | |||
chan = line2[2][1:] | |||
if line[1] == "JOIN": | |||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||
data.chan = line[2][1:] | |||
check_triggers(cmds, "join", nick, ident, host, chan) # check if there's anything we can respond to, and if so, respond | |||
triggers.check(actions, data, "join") # check if there's anything we can respond to, and if so, respond | |||
if line2[1] == "PRIVMSG": | |||
nick, ident, host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line2[0])[0] | |||
msg = ' '.join(line2[3:])[1:] | |||
chan = line2[2] | |||
if line[1] == "PRIVMSG": | |||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||
data.msg = ' '.join(line[3:])[1:] | |||
data.chan = line[2] | |||
if chan == NICK: # if line2[2] is us, this is a privmsg to us, so set 'chan' as the nick of the sender | |||
chan = nick | |||
check_triggers(cmds, "msg_private", nick, ident, host, chan, msg) # only respond if it's a private message | |||
if data.chan == NICK: # this is a privmsg to us, so set 'chan' as the nick of the sender | |||
data.chan = data.nick | |||
triggers.check(actions, data, "msg_private") # only respond if it's a private message | |||
else: | |||
check_triggers(cmds, "msg_public", nick, ident, host, chan, msg) # only respond if it's a public (channel) message | |||
triggers.check(actions, data, "msg_public") # only respond if it's a public (channel) message | |||
check_triggers(cmds, "msg", nick, ident, host, chan, msg) # check for general messages | |||
triggers.check(actions, data, "msg") # check for general messages | |||
if msg == "!restart": # hardcode the !restart command (we can't return from within actions.py) | |||
if host in ADMINS: | |||
if data.msg == "!restart": # hardcode the !restart command (we can't return from within actions.py) | |||
if data.host in ADMINS: | |||
return True | |||
if line2[0] == "PING": # If we are pinged, pong back to the server | |||
send("PONG %s" % line2[1]) | |||
if line[0] == "PING": # If we are pinged, pong back to the server | |||
actions.send("PONG %s" % line[1]) | |||
if line2[1] == "376": | |||
if NS_AUTH: | |||
say("NickServ", "IDENTIFY %s %s" % (NS_USER, NS_PASS)) | |||
for this_chan in CHANS: # join all of our startup channels | |||
join(this_chan) | |||
if line[1] == "376": | |||
if NS_AUTH: # if we're supposed to auth to nickserv, do that | |||
actions.say("NickServ", "IDENTIFY %s %s" % (NS_USER, NS_PASS)) | |||
for chan in CHANS: # join all of our startup channels | |||
actions.join(chan) | |||
if __name__ == "__main__": | |||
s = socket.socket() | |||
s.connect((HOST, PORT)) | |||
send("NICK %s" % NICK) | |||
send("USER %s %s bla :%s" % (IDENT, HOST, REALNAME)) | |||
sock = socket.socket() | |||
sock.connect((HOST, PORT)) | |||
actions = Actions(sock) | |||
actions.send("NICK %s" % NICK) | |||
actions.send("USER %s %s bla :%s" % (IDENT, HOST, REALNAME)) | |||
main() |
@@ -0,0 +1,29 @@ | |||
# -*- coding: utf-8 -*- | |||
# Actions/commands to interface with IRC. | |||
class Actions: | |||
def __init__(self, sock): | |||
"""actions/commands to interface with IRC""" | |||
self.sock = sock | |||
def send(self, msg): | |||
"""send data to the server""" | |||
self.sock.send(msg + "\r\n") | |||
print " %s" % msg | |||
def say(self, target, msg): | |||
"""send a message""" | |||
self.send("PRIVMSG %s :%s" % (target, msg)) | |||
def action(self, target, msg): | |||
"""send a message as an action""" | |||
self.say(target,"%sACTION %s%s" % (chr(1), msg, chr(1))) | |||
def notice(self, target, msg): | |||
"""send a notice""" | |||
self.send("NOTICE %s :%s" % (target, msg)) | |||
def join(self, chan): | |||
"""join a channel""" | |||
self.send("JOIN %s" % chan) |
@@ -0,0 +1,12 @@ | |||
# -*- coding: utf-8 -*- | |||
# A class to store data from an individual line received on IRC. | |||
class Data: | |||
def __init__(self): | |||
"""store data from an individual line received on IRC""" | |||
self.chan = None | |||
self.nick = None | |||
self.ident = None | |||
self.host = None | |||
self.msg = None |
@@ -0,0 +1,127 @@ | |||
# -*- coding: utf-8 -*- | |||
# Commands to interface with the bot's git repository. | |||
import shlex, subprocess | |||
from config.irc_config import * | |||
actions, data = None, None | |||
args = None | |||
def call(a, d): | |||
global actions, data | |||
actions, data = a, d | |||
if not check_user_is_admin(): | |||
return | |||
args = get_args() | |||
if not check_has_args(): | |||
return | |||
if args[0] == "help": | |||
do_help() | |||
elif args[0] == "branch": | |||
do_branch() | |||
elif args[0] == "branches": | |||
do_branches() | |||
elif args[0] == "checkout": | |||
do_checkout() | |||
elif args[0] == "pull": | |||
do_pull() | |||
else: | |||
unknown_arg() # they asked us to do something we don't know | |||
def get_args(): | |||
"""get command arguments""" | |||
args = data.msg.strip().split(' ') # strip out extra whitespace and split the message into a list | |||
while '' in args: # remove any empty arguments | |||
args.remove('') | |||
return args[1:] # remove the command itself | |||
def check_user_is_admin(): | |||
"""check if the user is a bot admin (and can use this command, as a result)""" | |||
if data.host not in ADMINS: | |||
actions.say(data.chan, "\x02%s\x0F: you must be a bot admin to use this command." % data.nick) | |||
return False | |||
return True | |||
def check_has_args(): | |||
"""check if they provided arguments along with the !git command""" | |||
if not args: | |||
actions.say(data.chan, "\x02%s\x0F: no arguments provided." % data.nick) | |||
return False | |||
return True | |||
def exec_shell(command): | |||
"""execute a shell command and get the output""" | |||
command = shlex.split(command) | |||
result = subprocess.check_output(command, stderr=subprocess.STDOUT) | |||
return result | |||
def do_help(): | |||
"""display all commands""" | |||
help = ["\x0303branch\x0301 (show current branch)", "\x0303branches\x0301 (show all branches)", | |||
"\x0303checkout\x0301 (switch branches)", "\x0303pull\x0301 (update current branch)"] | |||
help = ', '.join(help) | |||
actions.say(data.chan, "\x02%s\x0F: sub-commands are: %s" % (data.nick, help)) | |||
def do_branch(): | |||
"""get our current branch""" | |||
branch = exec_shell("git name-rev --name-only HEAD") | |||
branch = branch[:-1] # strip newline | |||
actions.say(data.chan, "\x02%s\x0F: currently on branch \x0302%s\x0301." % (data.nick, branch)) | |||
def do_branches(): | |||
"""get list of branches""" | |||
branches = exec_shell("git branch") | |||
branches = branches[:-1] # strip newline | |||
branches = branches.replace('\n* ', ', ') # cleanup extraneous characters | |||
branches = branches.replace('* ', ' ') | |||
branches = branches.replace('\n ', ', ') | |||
branches = branches.strip() | |||
actions.say(data.chan, "\x02%s\x0F: branches: \x0302%s\x0301." % (data.nick, branches)) | |||
def do_checkout(): | |||
"""switch branches""" | |||
try: | |||
branch = args[1] | |||
except IndexError: # no branch name provided | |||
actions.say(chan, "\x02%s\x0F: switch to which branch?" % data.nick) | |||
return | |||
try: | |||
result = exec_shell("git checkout %s" % branch) | |||
if "Already on" in result: | |||
actions.say(data.chan, "\x02%s\x0F: already on \x0302%s\x0301!" % (data.nick, branch)) | |||
else: | |||
actions.say(data.chan, "\x02%s\x0F: switched to branch \x0302%s\x0301." % (data.nick, branch)) | |||
except subprocess.CalledProcessError: # git couldn't switch branches | |||
actions.say(data.chan, "\x02%s\x0F: branch \x0302%s\x0301 does not exist!" % (data.nick, branch)) | |||
def do_pull(): | |||
"""pull from remote repository""" | |||
branch = exec_shell("git name-rev --name-only HEAD") | |||
branch = branch[:-1] # strip newline | |||
actions.say(data.chan, "\x02%s\x0F: pulling from remote (currently on \x0302%s\x0301)..." % (data.nick, branch)) | |||
result = exec_shell("git pull") | |||
if "Already up-to-date." in result: | |||
actions.say(data.chan, "\x02%s\x0F: done; no new changes." % data.nick) | |||
else: | |||
actions.say(data.chan, "\x02%s\x0F: done; new changes merged." % data.nick) | |||
def unknown_arg(): | |||
actions.say(data.chan, "\x02%s\x0F: unknown argument: \x0303%s\x0301." % (data.nick, args[0])) |
@@ -0,0 +1,20 @@ | |||
# -*- coding: utf-8 -*- | |||
# A simple command to test the bot. | |||
import random | |||
actions, data = None, None | |||
def call(a, d): | |||
global actions, data | |||
actions, data = a, d | |||
choices = ("say_hi()", "say_sup()") | |||
exec random.choice(choices) | |||
def say_hi(): | |||
actions.say(data.chan, "Hey \x02%s\x0F!" % data.nick) | |||
def say_sup(): | |||
actions.say(data.chan, "'sup \x02%s\x0F?" % data.nick) |
@@ -0,0 +1,21 @@ | |||
# -*- coding: utf-8 -*- | |||
# Check what events on IRC we can respond to. | |||
from irc.commands import test, git | |||
def check(actions, data, hook): | |||
if hook == "join": | |||
pass | |||
if hook == "msg_private": | |||
pass | |||
if hook == "msg_public": | |||
pass | |||
if hook == "msg": | |||
if data.msg == "!test": | |||
test.call(actions, data) | |||
if data.msg.startswith("!git"): | |||
git.call(actions, data) |