Rabbit Slide Show

debexpo(mentors.d.n)をハックするには

2016-06-25

Description

2016年6月25日に渋谷dotsで開催された、東京Debian勉強会の発表資料です。

Text

Page: 1

debexpoを
ハックするには
How to hack mentors.d.n
Kentaro Hayashi
ClearCode Inc.
TokyoDebian, 140th
2016-06-25

Page: 2

自己紹介(1)
Twitter/GitHub: @kenhys
所属: トラックポイント・ソフトドーム派

Page: 3

自己紹介(2)
トラックポイント・ソフトドーム派

Page: 4

参考画像の出典
http://www.irasutoya.com/

Page: 5

閑話休題
そろそろ本題へ

Page: 6

今日の話
debexpoとは?
なぜdebexpoをハックする必要が?
どうやってハックしたのか?

Page: 7

今日の話
debexpoとは?
なぜdebexpoをハックする必要が?
どうやってハックしたのか?

Page: 8

debexpoとは?
mentors.d.nを支えるウェブアプリケーション
リポジトリ名がdebexpo

Page: 9

mentors.d.nとは?
http://mentors.debian.net

Page: 10

debexpoの由来
The new project was called "debexpo"
because it was supposed to become an
exposition for Debian packages.
[ 「 https://workaround.org/project/debexpo 」より引用 ]

Page: 11

ゆるキャラも
名前は不明。知っていたら教えてください。

Page: 12

debexpo概要
Python製
Pylonsフレームワーク採用
テンプレートエンジンはMako

Page: 13

Pylons
http://www.pylonsproject.org/
Railsっぽいフレームワーク
2011年にメンテナンスモード入り
後継はPyramidに

Page: 14

debexpoの歴史(1)
2003年
最初はPerlで書かれていた
その後、Pythonで書き直し

Page: 15

debexpoの歴史(2)
2008年
Google SoCで開発が進む
2009-2010年
http://expo.debian.net/ 運用開始
2011年 そしてmentors.d.nへ

Page: 16

debexpoの役割
ITP,RFSのためのアップロード先
non-DDはパッケージを直接アップロードできない
スポンサーが必要

Page: 17

ITP,RFSのおさらい
mentors.d.nの使いかた ITP編/RFS編

Page: 18

mentors.d.nの
使いかた ITP編(1)
パッケージをDebianにもっていきたい
ITPのメールをsubmit@bugs.d.oへ
パッケージをmentors.d.nにdput

Page: 19

mentors.d.nの
使いかた ITP編(2)
RFSのメールをsubmit@bugs.d.oへ
レビュー & 修正 & dput
DDによるupload

Page: 20

mentors.d.nの
使いかた RFS編(1)
upstreamの新リリース
追従してパッケージをdput
RFSのメールをsubmit@bugs.d.oへ

Page: 21

mentors.d.nの
使いかた RFS編(2)
レビュー & 修正 & dput
DDによるupload

Page: 22

mentors.d.nオススメ
パッケージのチェックもしてくれる
RFSのテンプレートも生成してくれる

Page: 23

mentors.d.nオススメ
パッケージのチェックもしてくれる
RFSのテンプレートも生成してくれる

Page: 24

チェック結果がみれる
lintianの警告とか

Page: 25

mentors.d.nオススメ
パッケージのチェックもしてくれる
RFSのテンプレートも生成してくれる

Page: 26

RFSのテンプレート生成
あとはメールするだけ(※)

Page: 27

今日の話
debexpoとは?
なぜdebexpoをハックする必要が?
どうやってハックしたのか?

Page: 28

mentors.d.n
が
オススメな理
由

Page: 29

(再)mentors.d.nが
オススメな理由
RFSテンプレート生成
あとはメールを出すだけ

Page: 30

(再)mentors.d.nが
オススメな理由
RFSテンプレート生成
あとはメールを出すだけ
と言ったが、あれは嘘だ

Page: 31

論より証拠
実際のRFS templateをお見せしよう

Page: 32

証拠物件(1)
[fill in]の文字がちらほら

Page: 33

証拠物件(2)
ほかにも穴埋めが必要

Page: 34

編集すべき箇所
いくつかあるので紹介

Page: 35

編集すべき箇所(1)
Subject:に種別を書け

Page: 36

編集すべき箇所(2)
Severity:を書け

Page: 37

編集すべき箇所(3)
Upstream,URL,License:を書け

Page: 38

編集すべき箇所(4)
Changelogを書け

Page: 39

これで終
わり?

Page: 40

編集すべき箇所(5)
さりげなく埋めこまれたhelloとexample.com

Page: 41

これでメー
ルが出せる

Page: 42

先頭に埋めこまれた
スペース2つ
コマンドメールであることを思いだそう
もちろんエラーになります

Page: 43

Q. なぜdebexpoを
ハックするのか?
A. RFSテンプレートの残念っぷりをどうにかした
い

Page: 44

同じ思いの人はいた
Aliothのtrackerで4年も前に通った道

Page: 45

今日の話
debexpoとは?
なぜdebexpoをハックする必要が?
どうやってハックしたのか?

Page: 46

あらすじ
upstream探し
ドキュメント探し
まずは動かしてみる
あたりをつけて修正
そしてPRへ

Page: 47

特別なことは何も
よくあるフリーソフトウェアの修正

Page: 48

あらすじ
upstream探し
ドキュメント探し
まずは動かしてみる
あたりをつけて修正
そしてPRへ

Page: 49

upstream探し(1)
mentors.d.n下部にリンクがきちんとある
aliothをみればいいとわかる

Page: 50

upstream探し(2)
最近はコミットがない

Page: 51

ちょっと不安に
よく使われているならそこそこメンテされている
イメージ
実際にはそうでもなかった

Page: 52

upstream探し(3)
GitHubのほうが実は新しい
https://github.com/debexpo/debexpo

Page: 53

upstream探し(4)
aliothがmaster
https://alioth.debian.org/projects/debexpo/
GitHubのをマージという運用

Page: 54

あらすじ
upstream探し
ドキュメント探し
まずは動かしてみる
あたりをつけて修正
そしてPRへ

Page: 55

ドキュメント探し
docs/*にドキュメントが整備
docs/installing.rstを参照
リンク先が404なこともあるので注意

Page: 56

あらすじ
upstream探し
ドキュメント探し
まずは動かしてみる
あたりをつけて修正
そしてPRへ

Page: 57

まずは動かしてみる
セットアップ方法は3種
既存システムにインストール
virtualenvでインストール
VirtualBoxでインストール

Page: 58

まずはVirtualBoxで
環境を分けたいのでVirtualBoxを選択

Page: 59

Vagrantfileがアレ
# Every Vagrant virtual environment requires a box to build off of.
config.vm.box = "chef/debian-7.6"
Debian 7.6 (2014年7月12日)?
Debian 7.10でてるよ?

Page: 60

vagrant upしてみると
% vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'chef/debian-7.6' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
The box 'chef/debian-7.6' could not be found or
could not be accessed in the remote catalog. If this is a private
box on HashiCorp's Atlas, please verify you're logged in via
`vagrant login`. Also, please double-check the name. The expanded
URL and error message are shown below:
URL: ["https://atlas.hashicorp.com/chef/debian-7.6"]
Error: The requested URL returned error: 404 Not Found
boxが見つからなくてコケる

Page: 61

PR#32で修正
Bento projectに移行していたせいだった

Page: 62

起動してログインするまで
$ vagrant up --provision
$ vagrant ssh
よくあるやりかた

Page: 63

vagrant sshして
サーバーを起動
$ cd debexpo
$ . venv/bin/activate
$ paster serve development.ini

Page: 64

5000ポートでサーバー起動
ブラウザでアクセス可能に

Page: 65

ユーザーの追加(1)
方法は2つある
ブラウザ経由で追加
JSONで追加

Page: 66

ユーザーの追加(2)
ブラウザ経由で追加

Page: 67

ユーザーの追加(3)
JSONで追加するなら
{
"realname":"Hayashi Kentaro",
"password":"password",
"email":"hayashi@clear-code.com"
}

Page: 68

ユーザーの追加(4)
追加用のスクリプトを利用
$ python ./bin/user_importer.py \
-i development.ini -u user.json

Page: 69

アカウントの有効化
verification (ログインに必要)
dmup (アップロードに必要)

Page: 70

verificationの設定
verificationを空にする
メールの確認をバイパス

Page: 71

DMUP?
マシン使用ポリシーのこと

Page: 72

dmupの設定
dmupフィールドを更新
同意したことにする

Page: 73

.dput.cfの設定をする
[debexpo]
fqdn = localhost:5000
incoming = /upload/kenhys@gmail.com/password
method = http
allow_unsigned_uploads = 0
アップロードの準備をする

Page: 74

試しにパッケージを
アップロード
Uploading to debexpo (via http to localhost:5000):
Uploading groonga_6.0.2-1.dsc:
Upload failed: 500 Internal Server Error
500 Internal Server Error

Page: 75

さっそくバグを踏む
あるべきディレクトリがないというオチ

Page: 76

PR#34で修正
ちゃんとディレクトリを作る

Page: 77

PR出して気づいた怖い話
最後にテストが通ったの8ヶ月前

Page: 78

なぜか?
Travis-CIの環境の変化
しばらくコミットされてないので誰も気づかない

Page: 79

PR#38で修正
テストが通るように

Page: 80

PR#37で修正
Python2.6でCIはもういいんじゃ

Page: 81

パッケージのとりこみ
$ ./bin/debexpo_importer.py \
-c /tmp/debexpo/growl-for-linux_0.8.5-1_source.changes \
-i development.ini --skip-gpg-check --skip-email
インポートスクリプト実行

Page: 82

とりこみできずに
Traceback
Traceback (most recent call last):
File "./bin/debexpo_importer.py", line 60, in
i.main()
File "/home/vagrant/debexpo/debexpo/importer/importer.py", line 473, in main
gpg = get_gnupg()
File "/home/vagrant/debexpo/debexpo/lib/utils.py", line 119, in get_gnupg
return gnupg.GnuPG(config['debexpo.gpg_path'],
File "/home/vagrant/debexpo/venv/local/lib/python2.7/site-packages/paste/registry.py", line 146, in getitem
return self._current_obj()[key]
KeyError: 'debexpo.gpg_path'

Page: 83

PR#39で修正
オプションを正しく解釈するように

Page: 84

パッケージリスト
リストアップされるように

Page: 85

あらすじ
upstream探し
ドキュメント探し
まずは動かしてみる
あたりをつけて修正
そしてPRへ

Page: 86

ディレクトリ構成
config
controllers
cronjobs
importer
i18n
lib
model
plugins
public
templates
tests

Page: 87

手がかりはURL
知りたいのはこのリンク

Page: 88

こんなリンク先
http://localhost:5000/sponsors/rfs-howto/
xxxx

Page: 89

コントローラを探す
def rfs_howto(self, packagename = None):
c.package = None
c.package_dir = None
if packagename:
package = meta.session.query(Package)
.filter_by(name=packagename).first()
if package:
c.package = package
c.package_dir = get_package_dir(package.name)
return render('/sponsor/rfs_howto.mako')
controllers/sponsor.py

Page: 90

テンプレートを見る
Package: sponsorship-requests
Severity: normal [important for RC bugs, wishlist for new packages]
Dear mentors,
%if c.package:
I am looking for a sponsor for my package "${ c.package.name }"
%else:
I am looking for a sponsor for my package "hello":
%endif
templates/sponsor/rfs_howto.mako

Page: 91

やりたいこと
RFSテンプレートから
[fill in]撲滅
mailto:リンクの生成

Page: 92

当初の目論見
${ c.package.name }とかあるぞ
テンプレートを書き換えればいいのでは?

Page: 93

無理で
した

Page: 94

なぜか?
必要なメタ情報を保持していない
持ってないものは表示できない orz...
ないならかき集めればいいじゃない

Page: 95

収集するにはどうすればい
いか
インポートの処理の流れを把握する
どのタイミングで収集すべきか知る
不足している情報は何かを知る

Page: 96

インポート処理の流れ(1)
dputでmentors.d.nへアップロード
インポート前処理
パッケージのインポート処理

Page: 97

インポート処理の流れ(2)
もう少し詳しく言うと
dputしたファイルは/tmp/debexpo/pubへ保存
インポート前処理で/tmp/debexpoヘ移動
orig.tar.gzがなかったりするとrejectメール

Page: 98

インポート処理の流れ(3)
もう少し詳しく言うと
インポート処理で/tmp/debexpo/filesへ移動
/tmp/debexpo/files以下
pool
dist
git

Page: 99

収集すべきデータは?
現状、メタ情報はどう保持されているのかを把握
する
テーブルを覗いてみよう

Page: 100

主要なテーブル
主なものは3つ
packages
package_versions
package_info

Page: 101

packagesテーブル
パッケージのマスターテーブル
名前や説明などのメタ情報を保持

Page: 102

packagesテーブル
sqlite> .schema packages
CREATE TABLE packages (
id INTEGER NOT NULL,
name TEXT NOT NULL,
user_id INTEGER,
description TEXT,
watch_counter INTEGER,
download_counter INTEGER,
needs_sponsor INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id)
);

Page: 103

package_versions
テーブル
パッケージの版管理
何度もアップロードすると増加

Page: 104

package_versions
テーブル
sqlite> .schema package_versions
CREATE TABLE package_versions (
id INTEGER NOT NULL,
package_id INTEGER,
version TEXT NOT NULL,
maintainer TEXT NOT NULL,
section TEXT NOT NULL,
distribution TEXT NOT NULL,
qa_status INTEGER NOT NULL,
component TEXT NOT NULL,
priority TEXT,
closes TEXT,
uploaded DATETIME NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(package_id) REFERENCES packages (id)
);

Page: 105

package_infoテーブル
プラグインの適用結果を管理
メタ情報を保持

Page: 106

package_infoテーブル
sqlite> .schema package_info
CREATE TABLE package_info (
id INTEGER NOT NULL,
package_version_id INTEGER,
from_plugin VARCHAR(200) NOT NULL,
outcome VARCHAR(200) NOT NULL,
data TEXT,
severity INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(package_version_id) REFERENCES package_versions (id)
);

Page: 107

package_infoテーブル
from_plugin
どのプラグインか
outcome
説明文(エラーメッセージ)
data
JSONデータ

Page: 108

package_infoの例
sqlite> select * from package_info;
1|1|native|Package is not native|{"native": false}|1
2|1|maintaineremail|"Maintainer" email is the same as the uploader|{
"user-email":
"hayashi@clear-code.com",
"uploader-emails": [],
"maintainer-email": "hayashi@clear-code.com",
"user-is-maintainer": true
}|1
3|1|debianqa|Package is already in Debian|{
"nmu": false,
"in-debian": true,
"is-debian-maintainer": true
}|1

Page: 109

やりたいこと
RFSテンプレートから
[fill in]撲滅
mailto:リンクの生成

Page: 110

修正方針
プラグインで追加のメタ情報を収集
メール用のテンプレート追加
詳細ページでメタ情報を表示しつつmailto:リンク
生成

Page: 111

プラグイン?
debexpoはプラグインで機能拡張する
パッケージのチェックもプラグインを組み合わせ
て実現

Page: 112

プラグインの作り方
docs/writing_plugins.rst

Page: 113

プラグインの雛形
class FooPlugin(BasePlugin):
def test_xxx(self):
self.passed(outcome, data, severity)
or
self.failed(outcome, data, severity)
plugin = FooPlugin
debexpo/plugins/foo.py

Page: 114

プラグインいろいろ
% wc -l debexpo/plugins/*.py
99 debexpo/plugins/buildsystem.py
67 debexpo/plugins/changeslist.py
141 debexpo/plugins/closedbugs.py
85 debexpo/plugins/controlfields.py
185 debexpo/plugins/debianqa.py
85 debexpo/plugins/diffclean.py
63 debexpo/plugins/distribution.py
123 debexpo/plugins/getorigtarball.py
116 debexpo/plugins/lintian.py
100 debexpo/plugins/maintaineremail.py
69 debexpo/plugins/native.py
77 debexpo/plugins/notuploader.py
86 debexpo/plugins/removepackage.py
60 debexpo/plugins/ubuntuversion.py
110 debexpo/plugins/watchfile.py

Page: 115

プラグインの適用方法
設定ファイル(.ini)で制御
インポート前処理
QA処理
Debian入りした時
インポート処理後

Page: 116

プラグインを設定(1)
debexpo.plugins.post_upload
インポート前処理で適用
getorigtarballプラグイン

Page: 117

プラグインを設定(2)
debexpo.plugins.qa
QA処理で適用
lintianプラグイン

Page: 118

プラグインを設定(3)
debexpo.plugins.post_upload_to_debian
パッケージがDebian入りしたときに適用
removepackageプラグイン

Page: 119

プラグインを設定(4)
debexpo.plugins.post_successful_upload
インポート処理後に適用
changeslistプラグイン

Page: 120

プラグインの書きかた
なんとなくわかったのでいざ実践へ

Page: 121

やったこと
プラグインの処理を実装
プラグインを適用
mailto用テンプレート追加
rfstemplateのデータを表示

Page: 122

プラグインの処理を実装
debexpo/plugins/rfstemplate.pyを実装
実質100行ないくらい
debian/changelogやdebian/controlから抽出
deb822, copyrightモジュールを活用

Page: 123

プラグインを適用
debexpo.plugins.qa = ... rfstemplate ...
development.iniに設定

Page: 124

mailto用テンプレート追
加
%if c.rfstemplate:
Upstream Author :
* URL
:
* License
:
%else:
Upstream Author :
* URL
:
* License
:
%endif
${ c.rfstemplate['upstream-author'] }
${ c.rfstemplate['upstream-url'] }
${ c.rfstemplate['upstream-license'] }
[fill in name and email of upstream]
[fill in URL of upstreams web site]
[fill in]
debexpo/templates/sponsor/
rfs_template.mako

Page: 125

rfstemplateの
データを表示
if latest:
rfstemplate = meta.session.query(PackageInfo)
.filter_by(package_version_id=latest.id)
.filter_by(from_plugin='rfstemplate').first()
if rfstemplate:
c.rfstemplate = json.loads(rfstemplate.data)
c.mailbody = render('/sponsor/rfs_template.mako')
return render('/sponsor/rfs_howto.mako')
debexpo/controllers/sponsor.py

Page: 126

実際に
デモ

Page: 127

成果物をPR#35で出した
https://github.com/debexpo/debexpo/pull/35

Page: 128

PR#35の経過(1)
May 4
@olasdさんから好意的な反応
May 14
どうなった?とつついてみるも反応なし

Page: 129

PR#35の経過(2)
May 21
Debian勉強会でまだマージされてない話をする
あれやこれやでしばし放置

Page: 130

PR#35の経過(3)
June 19
@paulproteusさんをつついてみる
June 19
20日にみれるかもと@paulproteusさんから反応あ
り

Page: 131

PR#35の経過(4)
どうもDebConf16待ち

Page: 132

まとめ
debexpoとはmentors.d.nのこと
RFSテンプレートが残念だったので改善した
そのうちマージされる(多分)ので乞御期待

Page: 133

補足
マージへ向けた懸念事項
mentors.d.nは運用環境がwheezyらしい
wheezyのままならrejectされるかも
実装したプラグインがwheezyでは動かない(0.1.23以
降が必要)
wheezyではpython-debianが古い(0.1.21)
jessieなら0.1.27なので動作する

Page: 134

会場からのフィードバック
メールのリンクをもっと目立たせたほうがよいの
では
=> その通りなので直しておきたい

Other slides

DebConf20 DebConf20
2020-08-25