summaryrefslogtreecommitdiff
path: root/gitnoti.py
blob: 854d1e302f7b0720624e2ac93d516e75a29cdbd3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python

import git, os, sys
from optparse import OptionParser
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol
from twisted.internet.task import LoopingCall

parser = OptionParser()
parser.add_option('-s', '--host')
parser.add_option('-n', '--nick', default = 'git')
parser.add_option('-d', '--dir')
parser.add_option('-c', '--channel')
parser.add_option('-i', '--interval', type = 'int', default = 30)

(options, args) = parser.parse_args()

if not options.host or not options.dir or not options.channel or not options.nick:
	parser.print_help()
	sys.exit(1)

root = options.dir

repos = None

def repo_commit_msg(repo, commit):
	stat = '%d files,' % commit.stats.total['files']
	stat += ' \00305--%d\017' % commit.stats.total['deletions']
	stat += ' \00303++%d\017' % commit.stats.total['insertions']
	msg = '\002%s\002 pushed to \002%s\002 by \002%s\002 (%s) %s' % (
		os.path.splitext(os.path.basename(repo.path))[0],
		commit.id_abbrev,
		commit.committer.name if commit.author.name == commit.committer.name else '%s/%s' % (commit.committer.name, commit.author.name),
		stat,
		commit.summary
	)
	return msg

def check_repos(bot):
	global repos
	repo_paths = [x for x in os.listdir(root) if x.endswith('.git')]
	if not repos:
		repos = [[git.Repo('%s/%s' % (root, x)), None] for x in repo_paths]
		bot.gitmsg('Repos initialized: %s' % (', '.join([os.path.splitext(os.path.basename(x[0].path))[0] for x in repos])))
	else:
		old_paths = [os.path.basename(x[0].path) for x in repos]
		new_paths = [x for x in repo_paths if not x in old_paths]
		del_paths = [x for x in old_paths if not x in repo_paths]
		del_repos = [x for x in repos if os.path.basename(x[0].path) in del_paths]
		if del_repos:
			bot.gitmsg('Removed repo%s: %s' % ('' if len(del_paths) == 1 else '', ', '.join([os.path.splitext(x)[0] for x in del_paths])))
		for i in del_repos:
			repos.remove(i)
		new_added = []
		for i in new_paths:
			try:
				r = git.Repo('%s/%s' % (root, i))
				repos.append([r, None])
				new_added.append(i)
			except:
				pass
		if new_added:
			bot.gitmsg('New repo%s: %s' % ('' if len(new_added) == 1 else 's', ', '.join([os.path.splitext(x)[0] for x in new_added])))

	for i, v in enumerate(repos):
		repo = v[0]
		if not repo.heads: # No commits
			continue
		last = v[1]
		if last == None:
			last = repo.heads[0].commit.id
			repos[i][1] = last
		nlast = repo.heads[0].commit
		if last and nlast.id != last:
			msg = repo_commit_msg(repo, nlast)
			bot.gitmsg(msg)
			repos[i][1] = nlast.id

class Bot(irc.IRCClient):
	nickname = options.nick

	def gitmsg(self, msg):
		self.say(options.channel, msg)

	def signedOn(self):
		self.join(options.channel)
		self.repeater = LoopingCall(check_repos, self)
		self.repeater.start(options.interval)

	def privmsg(self, user, channel, message):
		private = channel == self.nickname
		nick = user.split('!')[0]
		target = nick if private else channel
		messagelist = message.split()
		if len(messagelist) < 2:
			return
		if messagelist[0].startswith(self.nickname):
			cmd = messagelist[1].lower()
			if cmd == 'list':
				s = 'Repos: %s' % ', '.join([os.path.splitext(os.path.basename(x[0].path))[0] for x in repos])
				self.msg(target, s)
			elif cmd == 'last':
				repo = messagelist[2].lower() if len(messagelist) > 2 else None
				if not repo:
					self.msg(target, 'Which repo?')
					return
				repo = [r for r in repos if os.path.basename(r[0].path).startswith(repo)]
				if len(repo) == 1:
					r = repo[0][0]
					msg = repo_commit_msg(r, r.heads[0].commit)
					self.msg(target, msg)
				elif len(repo) == 0:
					self.msg(target, 'No repo found.')
				else:
					self.msg(target, 'Ambiguous name: %s' % (', '.join([os.path.basename(x[0].path) for x in repos])))

class BotFactory(protocol.ReconnectingClientFactory):
	protocol = Bot

if __name__ == '__main__':
	f = BotFactory()
	reactor.connectTCP(options.host, 6667, f)
	reactor.run()