debexpoをnハックするには

: subtitle

How to hack mentors.d.n

: author

Kentaro Hayashi

: institution

ClearCode Inc.

: content-source

TokyoDebian, 140th

: date

2016-06-25

: allotted-time

40m

: theme

.

自己紹介(1)

# image
# relative-height = 40
# src = https://pbs.twimg.com/profile_images/2290018079/cvcy12slbeva80jboxzf_400x400.png

自己紹介(2)

# image
# relative-height = 60
# src = images/track-points.png

参考画像の出典

# image
# relative-height = 80
# src = images/irasutoya.png

閑話休題

そろそろ本題へ

今日の話

今日の話

debexpoとは?

mentors.d.nとは?

# image
# relative-height = 80
# src = images/mentors.d.n.png

debexpoの由来

# blockquote
# title = https://workaround.org/project/debexpo
The new project was called "debexpo" because it was supposed to become an ((*expo*))sition for ((*Deb*))ian packages.

ゆるキャラも

# image
# relative-height = 80
# src = images/debexpo-mascot-zoom.png

debexpo概要

Pylonsn((‘note:www.pylonsproject.org/’))

debexpoの歴史(1)

debexpoの歴史(2)

debexpoの役割

ITP,RFSのおさらい

mentors.d.nの使いかた ITP編/RFS編

mentors.d.nのn使いかた ITP編(1)

mentors.d.nのn使いかた ITP編(2)

mentors.d.nのn使いかた RFS編(1)

mentors.d.nのn使いかた RFS編(2)

mentors.d.nオススメ

mentors.d.nオススメ

チェック結果がみれる

# image
# relative-height = 80
# src = images/qa-information.png

mentors.d.nオススメ

RFSのテンプレート生成

# image
# relative-height = 80
# src = images/view-rfs-template.png

今日の話

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

(再)mentors.d.nがnオススメな理由

(再)mentors.d.nがnオススメな理由

論より証拠

実際のRFS templateをお見せしよう

証拠物件(1)

# image
# relative-height = 80
# src = images/rfs-template-pithole.png

証拠物件(2)

# image
# relative-height = 70
# src = images/rfs-template-pithole2.png

編集すべき箇所

編集すべき箇所(1)

# image
# relative-width = 100
# src = images/rfs-template-fill-in1.png

編集すべき箇所(2)

# image
# relative-width = 100
# src = images/rfs-template-fill-in2.png

編集すべき箇所(3)

# image
# relative-width = 100
# src = images/rfs-template-fill-in3.png

編集すべき箇所(4)

# image
# relative-width = 100
# src = images/rfs-template-fill-in4.png

これで終わり?

編集すべき箇所(5)

# image
# relative-width = 100
# src = images/rfs-template-fill-in5.png

これでメールが出せる

先頭に埋めこまれたnスペース2つ

# image
# relative-width = 100
# src = images/rfs-template-pithole3.png

Q. なぜdebexpoをnハックするのか?

同じ思いの人はいた

# image
# relative-width = 100
# src = images/alioth-debexpo-313593-request.png

今日の話

あらすじ

特別なことは何も

よくあるフリーソフトウェアの修正

あらすじ

upstream探し(1)

# image
# relative-width = 100
# src = images/source-code-and-bugs.png

upstream探し(2)

# image
# relative-height = 80
# src = images/last-change-on-alioth.png

ちょっと不安に

upstream探し(3)

# image
# relative-height = 70
# src = images/last-change-on-github.png

upstream探し(4)

あらすじ

ドキュメント探し

あらすじ

まずは動かしてみる

まずはVirtualBoxで

Vagrantfileがアレ

# Every Vagrant virtual environment requires a box to build off of.
config.vm.box = "chef/debian-7.6"

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

PR#32で修正

# image
# relative-width = 100
# src = images/debexpo-pr32-use-latest-wheezy.png

起動してログインするまで

$ vagrant up --provision
$ vagrant ssh

vagrant sshしてnサーバーを起動

$ cd debexpo
$ . venv/bin/activate
$ paster serve development.ini

5000ポートでサーバー起動

# image
# relative-height = 80
# src = images/debexpo-on-localhost.png

ユーザーの追加(1)

ユーザーの追加(2)

# image
# relative-height = 80
# src = images/debexpo-sign-me-up.png

ユーザーの追加(3)

ユーザーの追加(4)

アカウントの有効化

verificationの設定

# image
# relative-width = 90
# src = images/update-verification.png

DMUP?

# image
# relative-width = 50
# src = images/debexpo-dmup.png

dmupの設定

# image
# relative-width = 90
# src = images/update-dmup.png

.dput.cfの設定をする

[debexpo]
fqdn = localhost:5000
incoming = /upload/kenhys@gmail.com/password
method = http
allow_unsigned_uploads = 0

試しにパッケージをnアップロード

Uploading to debexpo (via http to localhost:5000):
Uploading groonga_6.0.2-1.dsc:
Upload failed: 500 Internal Server Error

さっそくバグを踏む

# image
# relative-width = 90
# src = images/find-a-debexpo-bug.png

PR#34で修正

# image
# relative-width = 100
# src = images/debexpo-pr34-incoming-directory.png

PR出して気づいた怖い話

# image
# relative-width = 100
# src = images/broken-ci-since-8month-ago.png

なぜか?

PR#38で修正

# image
# relative-width = 100
# src = images/debexpo-pr38-broken-ci.png

PR#37で修正

# image
# relative-width = 100
# src = images/debexpo-pr37-drop-py26.png

パッケージのとりこみ

$ ./bin/debexpo_importer.py \
-c /tmp/debexpo/growl-for-linux_0.8.5-1_source.changes \
-i development.ini --skip-gpg-check --skip-email

とりこみできずにnTraceback

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'

PR#39で修正

# image
# relative-width = 100
# src = images/debexpo-pr39-skip-gpg.png

パッケージリスト

# image
# relative-width = 80
# src = images/debexpo-package-list.png

あらすじ

ディレクトリ構成

config
controllers
cronjobs
importer
i18n
lib
model
plugins
public
templates
tests

手がかりはURL

# image
# relative-height = 80
# src = images/debexpo-investigate-rfs-template-link.png

こんなリンク先

コントローラを探す

# enscript python
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')

テンプレートを見る

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

やりたいこと

当初の目論見

無理でした

なぜか?

収集するにはどうすればいいか

インポート処理の流れ(1)

インポート処理の流れ(2)

インポート処理の流れ(3)

収集すべきデータは?

主要なテーブル

packagesテーブル

packagesテーブル

# enscript sql
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)
);

package_versionsnテーブル

package_versionsnテーブル

# enscript sql
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)
);

package_infoテーブル

package_infoテーブル

# enscript sql
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)
);

package_infoテーブル

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

package_infoの例

# enscript sql
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

やりたいこと

修正方針

プラグイン?

プラグインの作り方

プラグインの雛形

# enscript python
class FooPlugin(BasePlugin):

  def test_xxx(self):
    self.passed(outcome, data, severity)
    or
    self.failed(outcome, data, severity)
plugin = FooPlugin

プラグインいろいろ

% 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

プラグインの適用方法

プラグインを設定(1)

プラグインを設定(2)

プラグインを設定(3)

プラグインを設定(4)

プラグインの書きかた

なんとなくわかったのでいざ実践へ

やったこと

プラグインの処理を実装

プラグインを適用

debexpo.plugins.qa = ... rfstemplate ...

mailto用テンプレート追加

%if c.rfstemplate:
  Upstream Author : ${ c.rfstemplate['upstream-author'] }
* URL             : ${ c.rfstemplate['upstream-url'] }
* License         : ${ c.rfstemplate['upstream-license'] }
%else:
  Upstream Author : [fill in name and email of upstream]
* URL             : [fill in URL of upstreams web site]
* License         : [fill in]
%endif

rfstemplateのnデータを表示

# enscript python
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')

実際にデモ

成果物をPR#35で出した

# image
# relative-width = 60
# src = images/debexpo-pr35.png

((‘tag:x-small’))github.com/debexpo/debexpo/pull/35

PR#35の経過(1)

PR#35の経過(2)

PR#35の経過(3)

PR#35の経過(4)

# image
# relative-width = 100
# src = images/debexpo-pr35-paulproteus.png

まとめ

補足

会場からのフィードバック