at_yasu's blog

ロード的なことを

Bazaar の Hook

Bazaarでhookを使う方法。結論的に言えば、Pluginとしてスクリプトを書くようです。

作成

BazaarのPluginなので、Pythonで書いてやる必要があります。例として、pushした時に起動するhookで、pushされたらそれぞれの情報を出力します。

BazaarのPluginは、「bzrlib/plugins」や「~/.bazaar/plugins」、ないしは環境変数「BZR_PLUGIN_PATH」で指定された場所になります。

#!/usr/bin/python
# -*- coding:utf-8 -*-

from bzrlib import branch

def post_push_hook (p):
    print "source_branch: %s" % (p.source_branch)
    print "target_branch: %s" % (p.target_branch)
    print "master_branch: %s" % (p.master_branch)
    print "local_branch:  %s" % (p.local_branch)
    print "old_revno:     %d" % (p.old_revno)
    print "old_revid:     %s" % (p.old_revid)
    print "new_revno:     %d" % (p.new_revno)
    print "new_revid:     %s" % (p.new_revid)

branch.Branch.hooks.install_named_hook('post_push', post_push_hook, 'My Post_push hook')


実行例

[yasui@negro: ~/tmp/hook-aaa][13:02] $ bzr push
cannot import name filters
Unable to load plugin 'keywords' from '/Volumes/home/Users/yasui/.bazaar/plugins'
Using saved push location: /Volumes/home/Users/yasui/tmp/hook-test/
source_branch: BzrBranch6('file:///Volumes/home/Users/yasui/tmp/hook-aaa/')
target_branch: BzrBranch6('file:///Volumes/home/Users/yasui/tmp/hook-test/')
master_branch: BzrBranch6('file:///Volumes/home/Users/yasui/tmp/hook-test/')
local_branch:  None
old_revno:     1
old_revid:     a.yasui@gmail.com-20090306040137-eexjtm38fyjsjspy
new_revno:     2
new_revid:     a.yasui@gmail.com-20090306040240-v242pm9ibjz3b52i
All changes applied successfully.
Pushed up to revision 2.
[yasui@negro: ~/tmp/hook-aaa][13:02] $

作成

hookのタイプは色々あるようで、代表的な例として。

  • open
  • post_push
  • post_pull
  • post_commit
  • commit_message_template


一つのファイルで全て済ます場合は、「プラグイン名.py」、複数のファイルを使う場合は「プラグイン名/__init__.py」に書けというとの事。

注意点

だいたい何かをミスしていれば警告してくれます。ただしファイル名に「-」を付けるのはだめなようで。作成したら「bzr hook」でテストをするのが良いようです。

それと私が読んでいるサイトは、hazaarでhazaar-ngとの違いが私自身がついていません。ご了承をば。

[python][twitter] Twitterとおしゃべり

Twitterとおしゃべりするクラスを作ったので。

使用例

継承して機能を追加させます。例:

class userTimelineTwitter (twitter):
	""" タイムラインを取得する """
	def user_timeline(self):
		url = 'http://twitter.com/statuses/user_timeline.json'
		code,msg = self.sendTwitter(url, {})
		return json.read(msg)

tw = userTimelineTwitter()
msg = tw.user_timeline()
for lists in msg:
	for info in lists:
		print "%s:%s" % (info,lists[info])


パスワードなどが設定ファイルで保存されず、直接プログラムから指定する場合。

tw = userTimelineTwitter(email='...', pass='...')
msg = tw.user_timeline()
for lists in msg:
	for info in lists:
		print "%s:%s" % (info,lists[info])


あんまりテストしていないから、挙動はあやしいかも。ごめんね。

クラスのソース

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os
import sys
import urllib2, urllib

try:
	import json
except:
	print "This system is not support json. Please must be install Python-Json "\
		  "<http://pypi.python.org/pypi/python-json/>"
	sys.exit(1)

try:
	import yaml
except:
	print "This system is not support yaml. You can install to PyYAML if you wanna"\
		  "<http://pyyaml.org/>"
	print "The PyYaml are using configure file."

class twitter:
	""" Talk to Twitter <http://twitter.com/> class.
	
I read to <http://watcher.moe-nifty.com/memo/docs/twitterAPI13.txt>

(c) a.yasui <a.yasui@gmail.com>
	"""
	
	def __init__ (self, conf='.twitter.yaml', email='', passwd=''):
		self.__home__ = os.path.abspath(os.getenv('HOME'))
		self.__conf__ = os.path.join(self.__home__, conf)
		self.__user__ = email
		self.__pass__ = passwd
		self.loadConf()

	def loadConf (self, conf=''):
		self.__conf__ = conf and os.path.join(self.__home__, conf)\
							 or self.__conf__
		
		if not os.path.exists(self.__conf__) :
			if not self.__user__ and not self.__pass__:
				print "Error: configure file is not found: %s" % (self.__conf__)
				sys.exit(1)
			else:
				return
		
		fname, type = (".".join(self.__conf__.split(".")[0:-1]),
						self.__conf__.split(".")[-1])
		flagment = dict()
		
		if type == 'yaml':
			flagment = yaml.load(open(self.__conf__).read())
		elif type == 'json':
			flagment = json.read(open(self.__conf__).read())
		else:
			print "Error: configure file type '%s' are not support" % (type)
			sys.exit(1)
		
		if 'email' in flagment and 'password' in flagment:
			self.setUserAndPassword(**flagment)
		else:
			print "Error: not found to email and password in configure file."
			sys.exit(1)

	def setUserAndPassword (self, email, password):
		self.__user__ = email
		self.__password__ = password
	
	def sendTwitter (self, url, param, type="GET"):
		auth = self.auther()
		u = None
		if not type in ['GET','POST']:
			print "Error: unknown HTTP method %s" % (type)
			sys.exit(1)
		
		p = urllib.urlencode(param)
		try:
			op = urllib2.build_opener(auth)
			urllib2.install_opener(op)
			if type == 'GET':
				u = urllib2.urlopen("%s?%s" % (url, p))
			else:
				u = urllib2.urlopen(url, p)
		except urllib2.HTTPError, e:
			return (e.errno, e.message)
		return (200, u.read())

	def auther (self):
		auth_handler = urllib2.HTTPBasicAuthHandler()
		if not self.__user__ or not self.__password__:
			if self.__mustlogin__:
				print "Error: The user or password is not set yet."
				sys.exit(1)
			else:
				return None
		auth_handler.add_password('Twitter API', 'https://twitter.com/',
								self.__user__, self.__password__)
		return auth_handler

class updateTwitter (twitter):
	def setStatus (self, status):
		if len(status):
			self.__status__ = status

	def update (self, status=''):
		url = 'https://twitter.com/statuses/update.json'
		if not status:
			self.setStatus(status)
		code, msg = self.sendTwitter(url, {'status':self.__status__}, 'POST')
		if code == 200:
			print "update ok"
		else:
			print msg

class userTimelineTwitter (twitter):
	""" タイムラインを取得する """
	def user_timeline(self):
		url = 'http://twitter.com/statuses/user_timeline.json'
		code,msg = self.sendTwitter(url, {})
		return json.read(msg)

def main():
	tw = userTimelineTwitter()
	msg = tw.user_timeline()
	for lists in msg:
		for info in lists:
			print "%s:%s" % (info,lists[info])

if __name__ == '__main__':
	main()