Edited at

macOSでお手軽Mastodon開発

せっかくの連休なので、さっくりと、Mastodonの改造をやってみたいと思います。こっちには連休無いけどな!この記事では、macOSでざっくりと開発環境を整え、Mastodonのコードを取得してmacOSで走らせられるようにして、特にフロントエンドに改造を加えて、GitHubにプルリクエストを送ってみます。macOSでビルドの難しいライブラリへの依存を取り除くことで、依存しない部分の改造を簡単にできるようにします。

この記事は、Mastodon Golden Week Calendarの4月30日の記事です。平成最後の日だ!昨日は、にし さんによる「おかげさまで、まちトドンは2周年」、明日は、ライスには塩を さんによる「ちいさなMastodonサーバの素人管理人が考える、いくつかのこと」です。

この記事の内容は2019年4月下旬にmacOS 10.13.6 High Sierraで確認しました。


開発環境の準備

Mastodonのビルドと稼働に必要なパッケージ類を用意しておきます。手元の使い込んだ環境で執筆していますので、この項には書いていないけれども必要なものもあるかもしれません。足りないものに気づいた方はお知らせいただけるとうれしいです。

Mastodonに必要なサービスとしてPostgreSQLとRedisがあります。ローカルに入れちゃいましょう。手元では、Postgresp.app 2.1.6でPostgreSQL 10.7が走っています。RedisはHomebrewで入れたredis-server 5.0.4が走っています。

Mastodonのビルドと稼働に必要なパッケージはHomebrewで入れてしまいます。

$ brew install git rbenv yarn redis

rbenvのために下記の行を~/.bash_profileに追加しておきます。

$ cat <<_END >> ~/.bash_profile

PATH="
$HOME/.rbenv/bin:$PATH"
eval "
$(rbenv init -)"
_END

必要なRubyのバージョンはMastodonの.ruby-versionファイルに書いてありますので、コードをcloneしてきてからインストールします。


コードの準備

個人的には、アップストリームのレポジトリをGitHubでforkしてきて自分のレポジトリからクローンしてくるのが好みです。自分のforkのmasterはアップストリームのmasterをおっかけ、ブランチで自分用の改造をします。

GitHubにログインして https://github.com/tootsuite/mastodon から右上のForkボタンを押し、自分のレポジトリとしてforkして、自分のforkからClone or downloadボタンを押してSSHあるいはHTTPSのURLをコピーしてきてcloneします。さらに、アップストリームをupstreamリモートとして設定しておくと後々便利です。fetchしてリリース版のタグも手元に置いておきます。

$ git clone git@github.com:GitHubユーザー名/mastodon.git

$ cd mastodon
$ git remote add upstream https://github.com/tootsuite/mastodon.git
$ git fetch upstream

次に、macOS上でMastodonを起動できるようにするため、ファイルを書き換えます。ブランチを作成して作業を進めましょう。ここではmasterあるいはリリースタグからlocal-devel-macosというブランチを作成します。ブランチ名は好みで決めちゃってください。リリース版から改造を始めたい場合には、タグをチェックアウトしてからブランチを作成します。

(Masterから改造をする場合)

$ git checkout -b local-devel-macos

(リリース版をもとに改造をする場合)

$ git checkout v2.8.0

$ git checkout -b local-devel-macos

今回はdevelopment環境で作業を進めます。環境変数を設定するファイルを作っておきます。ここではcommitしていませんが、commitしておいて別の環境にクローンして使い回すのも良いかもしれません。

$ cat <<_END > .env.dev

RAILS_ENV=development
NODE_ENV=development
_END

cld3 gemはprotobuf-compilerパッケージを必要として、macOSではビルドが面倒です。今回はトゥートの言語の自動検出はあきらめて、利用しないようにします。

$ patch -p1 << _END

diff --git a/Gemfile b/Gemfile
index 6fe97412b..bb78a7844 100644
--- a/Gemfile
+++ b/Gemfile
@@ -29,7 +29,6 @@ gem 'browser'
gem 'charlock_holmes', '~> 0.7.6'
gem 'iso-639'
gem 'chewy', '~> 5.0'
-gem 'cld3', '~> 3.2.4'
gem 'devise', '~> 4.6'
gem 'devise-two-factor', '~> 3.0'

_END
$ patch -p1 << _END
diff --git a/Gemfile.lock b/Gemfile.lock
index 66fc8d1f4..4144eea11 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -143,8 +143,6 @@ GEM
elasticsearch (>= 2.0.0)
elasticsearch-dsl
chunky_png (1.3.10)
- cld3 (3.2.4)
- ffi (>= 1.1.0, < 1.11.0)
climate_control (0.2.0)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
@@ -673,7 +671,6 @@ DEPENDENCIES
capybara (~> 3.18)
charlock_holmes (~> 0.7.6)
chewy (~> 5.0)
- cld3 (~> 3.2.4)
climate_control (~> 0.2)
concurrent-ruby
derailed_benchmarks
_END
$ patch -p1 << _END
diff --git a/app/lib/language_detector.rb b/app/lib/language_detector.rb
index 1e90af42d..e24ad8c7c 100644
--- a/app/lib/language_detector.rb
+++ b/app/lib/language_detector.rb
@@ -6,10 +6,6 @@ class LanguageDetector
WORDS_THRESHOLD = 4
RELIABLE_CHARACTERS_RE = /[
\p{Hebrew}\p{Arabic}\p{Syriac}\p{Thaana}\p{Nko}\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}]+/m

- def initialize
- @identifier = CLD3::NNetLanguageIdentifier.new(1, 2048)
- end
-
def detect(text, account)
input_text = prepare_text(text)

@@ -19,7 +15,7 @@ class LanguageDetector
end

def language_names
- @language_names = CLD3::TaskContextParams::LANGUAGE_NAMES.map { |name| iso6391(name.to_s).to_sym }.uniq
+ []
end

private
@@ -51,9 +47,7 @@ class LanguageDetector
end

def detect_language_code(text)
- return if unreliable_input?(text)
- result = @identifier.find_language(text)
- iso6391(result.language.to_s).to_sym if result.reliable?
+ return nil
end

def iso6391(bcp47)
_END
$ git commit -am 'Remove dependency to cld3'

idn-ruby gemはlibidn11パッケージを必要とします。開発時には国際化ドメイン名の取り扱いは不要ですので、利用しないようにします。

$ patch -p1 <<_END

diff --git a/Gemfile b/Gemfile
index 34d042f7c..0bc305870 100644
--- a/Gemfile
+++ b/Gemfile
@@ -53,7 +53,6 @@ gem 'http', '~> 3.3'
gem 'http_accept_language', '~> 2.1'
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2', submodules: true
gem 'httplog', '~> 1.3'
-gem 'idn-ruby', require: 'idn'
gem 'kaminari', '~> 1.1'
gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.2', require: 'mime/types/columnar'
diff --git a/Gemfile.lock b/Gemfile.lock
index 4144eea11..dad4bd382 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -280,7 +280,6 @@ GEM
rails-i18n
rainbow (>= 2.2.2, < 4.0)
terminal-table (>= 1.5.1)
- idn-ruby (0.1.0)
ipaddress (0.8.3)
iso-639 (0.2.8)
jaro_winkler (1.5.2)
@@ -695,7 +694,6 @@ DEPENDENCIES
http_parser.rb (~> 0.6)!
httplog (~> 1.2)
i18n-tasks (~> 0.9)
- idn-ruby
iso-639
json-ld (~> 3.0)
json-ld-preloaded (~> 3.0)
_END
$ git commit -am 'Remove dependency to idn-ruby'


アプリケーションのビルド

Mastodonで利用するバージョンのRubyを用意します。

$ rbenv install $(cat .ruby-version)

$ gem install bundler

foreman Gemがあるとアプリケーションの起動が楽です。

$ gem install foreman

RAILS_ENVNODE_ENV環境変数を設定しておいて、gemsとnodeモジュールをインストールします。

$ source .env.dev

$ bundle install --path=vendor/bundle
$ yarn install

Postgres.appでPostgreSQLが起動しているのを確かめたら、データベースを初期化してアセットを用意します。

$ bundle exec rails db:setup

$ bundle exec rails assets:precompile


赤いMastodonの起動

PostgreSQLが起動しているのを確認したらRedisも起動して、

$ redis-server

他の端末でMastodonを起動します。

$ foreman start -e .env.dev -f Procfile.dev

http://localhost:3000/ からMastodonにアクセスします。development環境のMastodonはfaviconが赤いんですよ!

Screen Shot 2019-04-27 at 4.06.13 PM.png

この状態で、すでにadminとしてログインできるようになっています。メールアドレスは、admin@localhost:3000、パスワードは、db/seeds.rbファイルから探してみてください。

$ grep password db/seeds.rb


改造してみる

このようにしてforeman startで起動したwebpack-dev-serverが、Reacut/Reduxの変更については、ファイルの更新とともにブラウザがリロードして表示に反映してくれます。便利な時代だねえ!リロードしてくれないような変更は、foremanCtrl-Cで停止して再起動、そして、ブラウザでリロードするなどして確かめます。

あとは心の赴くままにコードを触って遊びましょう!例えば下記のような変更を施すと団子をクリックして絵文字を選択できるようになります。

Screen Shot 2019-04-27 at 4.29.34 PM.png

$ patch -p1 <<_END

diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dr
opdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dro
pdown.js
index c1429c756..1ab1df137 100644
--- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.
js
+++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.
js
@@ -357,8 +357,8 @@ class EmojiPickerDropdown extends React.PureComponent {
<div ref={this.setTargetRef} className='emoji-button' title={title} ari
a-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
<img
className={classNames('emojione', { 'pulse-loading': active && loading })}
- alt='🙂'
- src={`
${assetHost}/emoji/1f602.svg`}
+ alt='🍡'
+ src={`
${assetHost}/emoji/1f361.svg`}
/>
</div>
_END
$ git commit -am 'Use dango for emoji picker button'

Happy Hacking!


プルリクエストを送る

改造がうまくいったら、アップストリームに反映してみんなに使ってもらえるようにするのもうれしいです。でも、今回の改造では、うれしいのは筆者だけなのでプルリクエスト先は自分のレポジトリにしておきますね。

ローカルのMastodonはCtrl-Cで停止しておきます。

筆者のぼっちインスタンスはzunda-ninja-master-on-herokuというブランチで動いています。今回はこのブランチにマージできるようにレポジトリを準備していきます。

まず開発に使っていたブランチからプルリクエスト用の新しいブランチを作ります。

$ git checkout -b use-dango-for-emoji-picker

ブランチの分岐元をマージ先に変更します。エディタが起動するので、macOSで起動できるようにするなどプルリクエストに不要なコミットはdropし、必要なコミットはsquashしてまとめてしまうのが良いでしょう。

$ git rebase -i zunda-ninja-master-on-heroku

今回は下記のようになりました。

drop c8786e988 Remove dependency to cld3

drop 3a6a65a8a Remove dependency to idn-ruby
pick 63e4d15af Use dango for emoji picker button

GitHubにpushしたらプルリクエストを作成できます。

$ git push -u origin use-dango-for-emoji-picker

GitHubでの操作は直感的ですが、プルリクエストを送る先を間違えないように注意します。Compare & pull requestボタンを押して、

Screen Shot 2019-04-27 at 5.02.29 PM.png

マージ先のレポジトリを選択し、

Screen Shot 2019-04-27 at 5.04.08 PM.png

マージ先のブランチを選択し、

Screen Shot 2019-04-27 at 5.05.23 PM.png

プルリクエストの内容を書いてCreate pull requestボタンを押します。

Screen Shot 2019-04-27 at 5.06.32 PM.png

これで、プルリクエストのできあがり!マージしてデプロイすれば、いつものMastodonにも今回の改造が反映されます。楽しいな♪

なお、特にバックエンドの改造の場合には、テストを走らせて通るのを確認しておくのも大事かもしれません。

以上、せっかくの連休なのでMastodonを改造したくなった方はご参考まで!