There's an echo in my head

日々のメモ。

gitが自動解決できずに発生したTSVファイルのコンフリクトを可能な限り解決するfix_tsv_conflictを作った

作った。

github.com

ゲームのマスターデータをTSVファイルで管理していると、内容自体は衝突していないのに同時に同じ箇所に書き足したということで衝突してしまうことがある。あとはエディタの設定で末尾の空白スペークが消えてしまったとか。そういった単純なコンフリクトをこのコマンドは自動で解決してくれる。

使い方は二つあって、一つ目は

fix_tsv_conflict <目的のTSVファイル>

とするとどこを解決したか、もしくは解決できなかったかを標準エラーに書き出し、最終的な結果を標準出力に書き出す。もう一つは、-oオプションをつけることで標準出力に書き出さず直接ファイルを書き換える。

fix_tsv_conflict -o <目的のTSVファイル>

このコマンドが使える前提として、行の先頭に整数値を使ったidカラムがあることがあるので要注意。

コンフリクトの解決方針としては次のようにしている。

  • コンフリクトしたブロックごとに解決する、一行でも解決できなければコンフリクトした状態のまま残す
  • idカラムがユニークになるように残す
  • idカラムが同じで末尾の空のカラム数が異なるだけ場合は、総カラム数に近い方を残す
    • コンフリクトの解決が目的なので、空のカラム数の調整は行わない

ruby gemなので、gem installして使う。

gem install fix_tsv_conflict

今回初めてRefinementsを使ったけど、Travisで複数のRubyバージョンをまわしていたらバージョン間のRefinementsの対応の違いによってちょこちょこ落ちることがあった。新しいバージョンほど適用できる範囲が増えているので着実に進化しているのだなと感じた。

あと今回、データは標準出力に、通知は標準エラーにというのを意識して実装した。このコマンド自体は実際は-oオプションで直接上書きするのであまり関係ないかもしれないけど、他のツールをパイプして使ったりログを記録したりとかやっているとどちらに出力するかで自動化やモニタリングのしやすさが変わるのを最近感じている。

複数のgit-pr-release用のトークンを発行する方法

1台目のマシンでgit-pr-releaseを叩いて認証すると、2台目のマシンでgit-pr-releaseで叩いたときに同一ユーザの認証に失敗する。

GET https://api.github.com/repos/<your>/<product>/pulls/<number>: 401 - Bad credentials // See: https://developer.github.com/v3 (Octokit::Unauthorized)

これは1台目の認証でGitHub上にgit-pr-releaseという名前のトークンが発行されたために、2台目の認証で同名のトークンの発行に失敗するためである。

なので複数台のマシンでgit-pr-releaseを使いたい場合には

  1. 1台目でgit-pr-releaseを叩いて認証する
  2. トークンの一覧からgit-pr-releaseというトークンの名前を変更する
  3. 2台目でgit-pr-releaseを叩いて認証する

というように、新しいマシンで認証するまえに発行済のトークンの名前を変更しておけば良い。

ちなみに再認証したい場合には~/.gitconfigにある次のようなセクションを削除もしくはコメントアウトしておけば良い。

[pr-release]                 
  token = <your token>

JMeterのシナリオにコマンドライン引数でパラメータを渡す

個別には-Jもしくは--jmeterpropertyオプションで渡す。

$ jmeter -n -t <path/to/jmx> -Jfoo=bar

渡されたオプションは__P関数を使って埋め込む。

${__P(foo)}
もしくは
${__P(foo,デフォルト値)}

複数ある場合にはファイルにまとめて記述して-qもしくは--addpropオプションで指定することもできる。

$ cat some.properties
# this is comment
foo=bar

$ jmeter -n -t <path/to/jmx> -q some.properties

シナリオ作成・動作確認用のローカル環境と実際にテストする環境とで接続先を切り替えたいといったときには、ファイルにホスト名やポート名をまとめておくと楽そう。

MySQLで実際にINSERTされたレコード数

INSERT INTO animals (id,name) 
VALUES (1,"dog"),(2,"cat"), ...
ON DUPLICATE KEY UPDATE name = VALUES(name)

みたいなクエリで重複することなく新規にINSERTされたレコード数は、VALUES句の要素数ROW_COUNT()とから算出できる。

VALUES句の要素数values_count、発行直後のROW_COUNT()の返り値がrow_countのとき、新規にINSERTされたレコード数inserted_countと重複によって更新されたレコード数updated_countの間には次の関係が成り立つ。

inserted_count + updated_count = values_count
inserted_count + 2 * updated_count = row_count

この連立方程式を解くと

inserted_count = 2 * values_count - row_count
updated_count = row_count - values_count

となる。

よって重複することなく新規にINSERTされたレコード数は2 * VALUES句の要素数 - ROW_COUNT()で決まる。

参考

Travis CIでbundlerのキャッシュが効いていなかった

会社で開発しているRailsアプリケーションをTravis CIで回しているんだけど、bundlerでインストールされるgemのキャッシュが効いておらずログにこんな出力が出ていた。

store build cache
$ bundle clean
Cleaning all the gems on your system is dangerous! If you're sure you want to remove every system gem not in this bundle, run `bundle clean --force`.
0.00s
1.60schanges detected, packing new archive
FAILED: tar -Pzcf /home/travis/.casher/push.tgz 
tar: Cowardly refusing to create an empty archive
Try `tar --help' or `tar --usage' for more information.
uploading archive
failed to upload cache
curl: Can't open '/home/travis/.casher/push.tgz'!
curl: try 'curl --help' or 'curl --manual' for more information

よくよく調べてみると

の2つが原因のようだった。.travis.ymlでいうとこんな感じ。

install:
  # --path指定が無いのでrvmのグローバル領域にインストールされる
  - cd $TRAVIS_BUILD_DIR/rails_root && bundle install --jobs=3 --retry=3
cache:
  # デフォルトの$TRAVIS_BUILD_DIR/vendor/bundleにインストールされるものとしてキャッシュしようとする
  bundler: true

なのでbundlerでのインストール先とキャッシュ対象を明示的に指定することで解決した。

install:
  - cd $TRAVIS_BUILD_DIR/rails_root && bundle install --jobs=3 --retry=3 --path vendor/bundle
cache:
  directories:
    - rails_root/vendor/bundle

本当はちゃんとbundle cleanで古くなったgemを削除しないと徐々にキャッシュサイズが大きくなるらしいけど、ひとまずはこれで。

参考

github.com

capistrano-pending v0.2.0をリリースした

https://rubygems.org/gems/capistrano-pending/versions/0.2.0

Capistranoプラグイン方式がv3.7から大きく変わって:scm変数が非推奨になり、さらにv4.0からは消されるらしく、その対応のため。といってもいただいたPRの挙動を確認しただけだけど。

github.com

仕組みが変わるのはメンテする側からすると厄介だけど、見た感じフックする方法やデフォルト値の設定のタイミングなどが整備されるみたいなので良さげな感じ。あと:scmが消えるというのも、Capistrano本体はリモート実行のフレームワークという側面が強くなって正統進化してるように見受けられる。

しかし今回の対応では英語でやりとりされてるニュアンスや、Capistrano自体の挙動やらがなかなか理解できなくて戸惑うことが多かった。

launchdで動かしてるmemcachedのログを取る

homebrewでインストールしてるのでlaunchdに読ませてるplistは~/Library/LaunchAgents/homebrew.mxcl.memcached.plistにある。

下記にコメントしたあたりをよしなに記載する。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>homebrew.mxcl.memcached</string>
  <key>KeepAlive</key>
  <true/>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/opt/memcached/bin/memcached</string>
    <string>-l</string>
    <string>localhost</string>
    <string>-v</string> <!-- どれだけ詳細な情報を出すか。sshみたいにvvもvvvも指定できるがvvの時点で通信内容が吐かれるので今回はvに留める -->
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>WorkingDirectory</key>
  <string>/usr/local</string>
  <key>StandardOutPath</key> <!-- 標準出力の出力先 -->
  <string>/usr/local/var/log/memcached.log</string>
  <key>StandardErrorPath</key> <!-- 標準エラーの出力先 -->
  <string>/usr/local/var/log/memcached.log</string>
</dict>
</plist>

あとは上記を再読込する。

launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist

参考

このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。