Riji + Daiku + Travis CI で GitHub Pages を運用する

まとめ

やりたいこと

「 markdown で記事を書く」「 commit する」「 GitHub に push する」で blog が更新できるようになること

具体的な手順

GitHub Pages を作る

今回は monmon.github.io に作ることにした(ユーザページと呼ばれるやつで [https://github.com/monmon/monmon.github.io:title=.github.io] のリポジトリ作ってmaster branch にpushするやつ )。

設定方法は GitHub Pages のサイトにあるのでその通りやれば良い。

Riji を使うための前準備をする

今回は Travis で publish したい(静的ファイルを作りたい)ので Carton で Riji をインストールする。


0. まず、Carton が入ってない場合には cpanm で入れる

cpanm Carton


1. cpanfile に Riji を書く(ついでに後々必要になる Daiku も)

% cat > cpanfile
requires 'Riji';
requires 'Daiku';


2. Carton でインストール

carton install

これでlocalディレクトリが作れる


3. アーキテクチャの関係上、 Travis で改めて carton install するので、local ディレクトリはgitignoreしちゃう

echo local >> .gitignore

ここまでで一旦commitする


前準備はここまで。簡単。

Riji を使う

RijiPerl で作られた blog ツールで、「 markdown で記事を書く」「 commit する」「その記事を HTML ファイルとして吐き出す」というお手軽作業で記事更新できるもの。
チュートリアルがわかりやすいのでそれをそのまま倣ってていくだけで使える。


1. 事前作業で Riji が使えるようになっているので、まずは setup

carton exec riji setup --force

既にlocalディレクトリがあるので --force が必要


2. 念のためページが見れるか確認

carton exec riji server

表示できれば一旦OK


3. 今後、新しい記事を書くときは以下を叩くだけでOK

carton exec riji new-entry


Rijiについてはこれでおしまい。簡単。

Daiku を使う

DaikuRake みたいなやつの Perl 版。
.travis.yml にズラズラ書くよりも Rake 使ってやるのが良さそうなので Daiku も一緒にインストールすることにした(というか、使ったことないので何となく使ってみたかった)。

Daiku の使い方は Daiku and Daikufile are now production ready | おそらくはそれさえも平凡な日々sample を見るとざっくりわかる。


今回 Daiku で必要な作業は以下の3つ。

  1. master branch を checkout する
    • Travis は最新 commit を checkout してテストをまわすわけだけど、 Riji は publish 用の branch かチェックしている( git symbolic-ref HEAD の値を確認している)ため master に切り替える
  2. publish する
  3. publish したものを git に push する( blog の更新)


ということで、それぞれ以下のようになった。


1. master branch を checkout する

desc 'git を masterに変える';
task checkout_master => sub {
    my ($task, @args) = @_;
    sh qw(git checkout master);
};


2. publish する

desc '記事を作る';
task publish => sub {
    my ($task, @args) = @_;
    sh qw(carton exec riji publish);
};


3. publish したものを git に push する( blog の更新)

desc '作られた記事を github に push';
task push_github => sub {
    my ($task, @args) = @_;


    sh qw(git add -A);
    sh qw(git commit -m), 'Update blog on Travis';


    # Token が出力されないように --quiet & 2> /dev/null
    sh "git push --quiet https://$ENV{GH_TOKEN}\@github.com/monmon/monmon.github.io master 2> /dev/null";
};

最後の--quiet と 2> /dev/null はPersonal access tokenの値が Travis の出力結果に表示されないためのもの。ここだけ文字列で渡している理由は標準エラーにリダイレクトするため( sh は IPC::System::Simple なので、リストで渡してもシェル起動せず、標準エラーを /dev/null にリダイレクト利するためには文字列渡してリダイレクトさせないといけない…んだと思う)。


Daiku についてはここまで。簡単。

Travis を使う

Travis CI はCIサービスで、GitHub に push したらテストまわしたり、必要なシェル実行してくれるやつ。
Perl + Travis CI + Coveralls (PrePANの対応) - $shibayu36->blog; を見て Perl 設定の参考にした。


ここでやることは以下の3つ。

  1. TravisGitHub Pages のリポジトリに push されたものをテストするように設定する
  2. Travisリポジトリに push できるように secure を作る
    • GH_TOKEN をそのまま .travis.yml に書いちゃうと誰でもリポジトリに push できるようになってしまうため secure ってのを作る
  3. Travis の作業内容を .travis.yml に書く


ということで、細かい内容は以下。


1. TravisGitHub Pages のリポジトリに push されたものをテストするように設定する

これは Accountsのページ に行って GitHub Pages のリポジトリを ON にするだけでおしまい


2. Travisリポジトリに push できるように secure を作る

gem install travis
travis encrypt -r <owner>/<repo> "GH_TOKEN=<GitHub  Personal access token>" 

僕の場合なら / のところは monmon/monmon.github.io


3. .travis.yml を書く

language: perl
perl:
  - "5.18"

(5.16 だと Getopt::Long のバージョンが 2.38 でDaiku の求めるバージョンより低くてハマったのでサクッと5.18にしました)

  • branch は master しか使わないので
branches:
  only:
      - master
  • blog 生成部分は Daiku を使うだけ
before_install:
  - cpanm Carton
install:
  - 'carton install --deployment'
before_script:
  - carton exec daiku setup
script:
  - carton exec daiku publish
after_success:
  - '[ "$TRAVIS_BRANCH" == "master" ] && [ "$GH_TOKEN" ] && carton exec daiku push_blog_to_github'
  • 最後に GitHub に push できるように設定するだけ
env:
  global:
    - GIT_COMMITTER_NAME="monmon"
    - GIT_COMMITTER_EMAIL="lesamoureuses@gmail.com"
    - GIT_AUTHOR_NAME="monmon"
    - GIT_AUTHOR_EMAIL="lesamoureuses@gmail.com"
    - secure: "RpupCpR1J/p+JIqdJ7WUk13NnA1LgpxqVPjHpY18XSTrKZy6YAEtzPu3aVqARFFN40iipiyxSCm93mzOSWwdl9FUyV//ythOCSpF3fs9NKSP/9HilGb8x3yIbpastRML2m1voSYmuR5IKOELc4axVEVapYenUoCVlVhcZ0oVXkM="

(COMMITTER と AUTHOR どちらかだけだとダメで両方書かないといけなかったんだけどどこにそのことが書いてあるのか探せなかった)

.travis.ymlのsyntax checkについては Travis が用意している Lint を使えば良いです(日本語が入ってた場合にLintはグリーンだけど Travis 上ではエラーになるとパターンがあってハマったけど)。


Travis についてはここまで。簡単。

できあがり

ということで、できた blog が http://monmon.github.io/blog/ です!
超いろんな所でハマったけど、それらを乗り越えて作ることができました!

最後に

やってみて重要だなと思ったことはネタを作ってからスピーカー登録しようとしてもスピーカー枠は埋まってるということでした!

diffで差分の行を'> 'をつけずにそのまま表示するにはold-line-format、new-line-format、unchanged-line-formatを使う

ログファイルに欠損があって「新しいファイルにだけある行を表示したいなぁ」というよくある要望がでまして。


今までは

diff old new | perl -nle 's/> // and print $_'

みたいなことして表示してたんだけど「きっともっと楽な方法あるよね」と思いman diffしてみることに。
comm使えばできるけどsortしなくちゃなのでやめました)


んで、new-line-formatというのを見つけたのだけど、これをやっても「新しい行全て」が表示されてしまい「あれれー!」となる。

--new-line-format=FORMAT
       if-then-else 形式で、 2 番目のファイルだけにある行の出力に FORMAT を用いる。


最後の方まで読むと例が書いてあって"unchanged-line-formatも一緒に使えば良い"ということがわかりました。

--unchanged-line-format=FORMAT
       if-then-else 形式で、両方のファイルに共通な行の出力に FORMAT を用いる。


つまり、以下のように「new-lineを%Lで改行あり表示しつつ、変更してないやつは''で非表示にして握りつぶす」とやれば良い。

diff --new-line-format='%L' --unchanged-line-format='' old new


もし、oldの方の差分もあって一緒に出したいなら、

diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' a.txt b.txt

とやれば良いですね。

% cat a.txt
1
2
3
4
5

% cat b.txt
2
4
6

% diff a.txt b.txt
1d0
< 1
3d1
< 3
5c3
< 5
---
> 6

% diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' a.txt b.txt
1
3
5
6

【解決済】gitで、あるコミット時のソースコードを、ちらっとlessとかで見たい場合のコマンドって、なにかしら?diffはいらないの。

git

2013-12-20 15:02 追記

速攻で解決した。インターネット素晴らしい。


元記事

という発言があって、twitterで以下のやり取りをしました。



「確かに一時的にgit coでファイル取り出すことあるけどもっと楽な方法あるのかなぁ?」と探したもののググる力が足りず、最後にgistで書いた以下のような力技になりました。



ただ、適当実装だし、再発明してる感じもするので既にあるなら知りたいところ。
どうすると良いんでしょうか?

会議室名がオシャレ過ぎて覚えられない君へ #vgadvent2013

f:id:lesamoureuses:20131213202642j:plain

この記事はVOYAGE GROUP エンジニアブログ : Advent Calendar 2013の14日目の記事になります。
ちょっとハマってて気が付いたら日付が変わってました。


さて、去年のAdvent Calendarは社内図書館のOASISの本の整理の話を書いたので、「今年も会社の話で何かないかなぁ」とネタを探してました。

会議室の名前と場所が覚えられない


はじめに会議室の地図の写真を載せましたが弊社、会議室の名前がオシャレ過ぎて覚えられません。
どのくらい覚えにくいのかを理解できるようにいくつか紹介します。


まず、いつも #ajiting で飲んでるAJITOは大丈夫。デカいし入口だし覚えやすいです。
f:id:lesamoureuses:20131213235814j:plain


畳があるジパング。ふむ、これはまだ覚えやすい。
f:id:lesamoureuses:20131213235628j:plain


段ボール素材のアトランティス。こっからもうキツいですね。これはもう「段ボール部屋」と呼んじゃってます。
f:id:lesamoureuses:20131213235707j:plain


レムリア。「糸がたくさんの部屋」みたいな感じで呼ぶ。
f:id:lesamoureuses:20131214012137j:plain


ユーラシア。「何かアノすごく茂ってる所」
f:id:lesamoureuses:20131213235728j:plain


こんな感じでいろんな会議室があるんですが、とにかく名前から場所を思い出すのがつらいわけです。
(わかりづらいが故に僕らは会議室の場所をひねり出すため脳内メモリにあった仕事用記憶を一回スワップ領域に追い出すだなんていう煩わしい作業をしなければならないわけですよ!!!!)

覚えられないなら覚えなければ良い


ということで、覚えなくて済むようにAcme::VOYAGEGROUP::ConferenceRoomというモジュールを作りました。


インストールはcpanmでサクッと。

cpanm Acme::VOYAGEGROUP::ConferenceRoom


インストールするとconference_roomというコマンドが使えるようになるので引数に会議室の名前を入れるだけです。


たとえばzipang。
f:id:lesamoureuses:20131215030718p:plain
おぉ!わかりやすいですね!


次にajito。赤くなってるのが大変わかりやすくて良いですね!
f:id:lesamoureuses:20131215030829p:plain


大文字の方がしっくりくるってこともあるので大文字にも対応しました。
f:id:lesamoureuses:20131215030939p:plain


「まぁでも普段カタカナ使うよね」ってこともあるかもなのでカタカナも。
f:id:lesamoureuses:20131215031008p:plain


せっかくだからひらがなも。
f:id:lesamoureuses:20131215031049p:plain


「うーん、どうせだったら出力はJSONがいいなぁ」と言われる可能性も考えて第2引数にjsonと渡すことでjson出力できるようにもしました。
f:id:lesamoureuses:20131215031206p:plain


これで昨日覚えたjqでもアクセスできますね!!!
f:id:lesamoureuses:20131215032355p:plain


「jsonあるならXMLもあるべきなんじゃないの?」ってことでXMLも。
f:id:lesamoureuses:20131215032534p:plain


最後に「せっかくだからMessagePackでのデータのやりとりも考えるべきなのでは?」ということでMessagePackにも対応しました。
f:id:lesamoureuses:20131215032718p:plain



以上です!
Acme::VOYAGEGROUP::ConferenceRoom、総じて便利ですね!!!これでもう会議室の場所を覚える必要はありません!!!

まとめ

  • 本エントリでは弊社の会議室名のオシャレさについて言及しました。
  • ギリギリになって書き始めるとハマって日付が変わるということについて言及しました。


明日はアラビア語の学習環境を整えることで著名@hagino3000 さんです!もしかするとアラビア語でのpostになるかもしれませんね!

正規表現のx修飾子を使い、かつ、"ム"を指定するとTest::MinimumVersionでrequires 5.017009になる

2014-01-03 追記

これ、PPIx::Regexpのせいだった。
「ム」を16進数表示すると\x{E3}\x{83}\x{A0}になり、この最後のA0がWhitespeceと見なされてx修飾子と一緒になると

'perl_version_introduced' => '5.017009'

となる。
https://rt.cpan.org/Ticket/Display.html?id=91798

(でも、そもそもx修飾子使ってた所でsyntax変わらないからversionは元のままでいいんじゃないかな?)
x修飾子の動きが変わったのは5.17.9だからperl_version_introducedとしては合ってるのか。

元記事

5.8で動くようなコードでminil distを実行したらなぜかrequires 5.017009のエラーが出て「えー!何でー!」となりハマりました。


試しに5.17.9のperldeltaを見てみたんですが、そこに関わるようなコードを書いてなさそうで良くわからなくて断念。


とりあえずどんどんコード削除していった結果、最小の再現コードが作れました。

「ム」と「x修飾子」を使うと起こる。

で、もう一度5.17.9のperldelta見た感じ、ここの部分に当たるんじゃないかなと推測。
ただ「/xの空白の話だし、ムはU+30E0だからここかどうかは確実じゃないなぁ」とも思いまして。


ここでふとCompiler::Lexer をつかって Perl::MinimumVersion::Fast をかいてみた - blog.64p.orgを思い出して、Test::MinimumVersion::Fastを使って試してみたらエラーになりませんでした。


ここまでわかった所でその後どうしていいかわからないのでとりあえずメモ。


正規表現のx修飾子を使い、かつ、"ム"を指定するとTest::MinimumVersionでrequ ...

tmuxでanyenv(*env)で*env/shimsがsystemのPATHより前に読まれてsystemが使われてしまう対処

anyenvを使っているんですが、

/usr/local/heroku/bin
/Users/monmon/.anyenv/envs/rbenv/bin
/Users/monmon/.anyenv/envs/plenv/bin
/Users/monmon/.anyenv/envs/rbenv/shims
/Users/monmon/.anyenv/envs/plenv/shims
/Users/monmon/.anyenv/bin
/Users/monmon/local/bin
/Users/monmon/bin
/usr/local/sbin
/usr/local/bin
/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin

のようなPATHがtmuxを起動すると

/usr/local/heroku/bin
/Users/monmon/.anyenv/envs/rbenv/bin
/Users/monmon/.anyenv/envs/plenv/bin
/Users/monmon/.anyenv/bin
/Users/monmon/local/bin
/Users/monmon/bin
/usr/local/sbin
/usr/local/bin
/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
/usr/local/heroku/bin
/Users/monmon/.anyenv/envs/rbenv/bin
/Users/monmon/.anyenv/envs/plenv/bin
/Users/monmon/.anyenv/bin
/Users/monmon/local/bin
/Users/monmon/bin
/usr/local/sbin
/Users/monmon/.anyenv/envs/rbenv/shims
/Users/monmon/.anyenv/envs/plenv/shims

のようになってshimsが

/usr/local/bin
/usr/bin

より前に読まれてしまい、plenvのperlではなくsystemのperlが使われてしまいます(typeset -U path PATHはしてない状態)。


で、自分の環境だけの話なのかなぁと思ったら
http://konboi.hatenablog.com/entry/2013/12/12/213931
みたいなのも見つけて

rbenv works by inserting a directory of shims at the front of your PATH:
~/.rbenv/shims:/usr/local/bin:/usr/bin:/bin


Understanding Shims

ってのも見て「どうしたらいいんだろう?」と中身見てみた。


結果、anyenvだけの話ではないのだけど、~/.anyenv/libexec/anyenv-init内の

102   echo "$(${ENV_ROOT}/bin/${env} init -)"

の所で、初めに実行された時には

export PATH=/Users/monmon/.anyenv/envs/plenv/shims:/Users/monmon/.anyenv/bin:/Users/monmon/local/bin:/Users/monmon/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

なんですが、tmuxを起動した時にもう一度実行された時には

source /Users/monmon/.anyenv/envs/plenv/libexec/../completions/plenv.zsh

になるので、shimsをPATHに入れるタイミングが初めにしかなく、shimsがsystemより前になってしまう。


ということで、結果的に良いか分からないけど、shimsをPATHで読み込むようにしました。

-  ANYENV_ADD_PATH="${ENV_ROOT}/bin:${ANYENV_ADD_PATH}"
+  ANYENV_ADD_PATH="${ENV_ROOT}/bin:${ENV_ROOT}/shims:${ANYENV_ADD_PATH}"

https://github.com/monmon/anyenv/commit/5e976cd66904b8e4771f1aca8ed4b32ab43de80d


こうすることで、tmux使ってない場合には

/Users/monmon/.anyenv/envs/rbenv/bin
/Users/monmon/.anyenv/envs/rbenv/shims
/Users/monmon/.anyenv/envs/plenv/bin
/Users/monmon/.anyenv/envs/plenv/shims
/Users/monmon/.anyenv/envs/rbenv/shims
/Users/monmon/.anyenv/envs/plenv/shims

となってしまって良いのか悪いのかわからないけど、僕はtypeset -U path PATHでPATHの重複消しているのでいいかなと思いました。
これ、anyenvだけの問題ではないと思うのでもっといい解決方法あるんじゃないかなと思ったんだけど探せませんでした。

「Minillaをインストールしようと思ったらテストが通らない!><」と思ったら~/.gitignoreのせいでした

家でサクッとインストールできたはずなのに会社で以下のようなエラーが出て「あれー!」となりました。

===(      49;1  0/?  0/?  1/? )=========================================Use of uninitialized value in string eq at /Users/no-kumagai/.cpanm/work/1386851499.15174/Minilla-v0.11.0/blib/lib/Minilla/ReleaseTest.pm line 49.

        #   Failed test at t/filegatherer.t line 32.
        #          got: '.gitmodules,META.json,README,foo,libfoo/foo.c'
        #     expected: '.dot/dot,.gitignore,.gitmodules,META.json,README,foo,libfoo/foo.c,xtra/.dot,xtra/.dotdir/dot'
        # Looks like you failed 1 test of 1.

    #   Failed test 'include_dotfiles'
    #   at t/filegatherer.t line 33.
Use of uninitialized value in string eq at /Users/no-kumagai/.cpanm/work/1386851499.15174/Minilla-v0.11.0/blib/lib/Minilla/ReleaseTest.pm line 49.
===(      50;2  0/?  0/?  2/? )=========================================    # Looks like you failed 1 test of 3.

#   Failed test 'FileGatherer'
#   at t/filegatherer.t line 45.
# Looks like you failed 1 test of 2.
t/filegatherer.t ................... Dubious, test returned 1 (wstat 256, 0x100)

で、コケた結果見たらわかるとおり.(ドットファイル)でこけてる。
単純に~/.gitignoreに

.*

が入ってたからだけでした(ドットファイルはとりあえず弾いて必要なやつだけ追加できるようにする派です)。