読者です 読者をやめる 読者になる 読者になる

特定のファイルの git addとかがめんどうくさいのでなんとかする

ある程度編集したときに「あー、このファイルだけコミットしておきたい」みたいな状況ってあると思うんですよ。 他にも「このファイルだけHEADの状態に戻したい」とか「unstageしたい」みたいな。

でも例えばJavaだとpackage名が一緒なファイルがずらーっと並んでしまい、補完しようにも先頭が大体一緒で本当に面倒くさい。

残念ながらJavaをやめるという選択肢がないので、gitのサブコマンドを作って対応する。

ファイル一覧から特定のファイルをaddする - git add $file

#!/usr/bin/env bash

: ${GIT_FILTER_COMMAND:=fzf}

ls_modified_files() {
  echo '--- LABEL : tracked'
  git diff --name-only
}

ls_untracked_files() {
  echo '--- LABEL : untracked'
  git ls-files --others --exclude-standard
}

main() {
  local -r selected_file=$(cat <(ls_modified_files) <(ls_untracked_files) | $GIT_FILTER_COMMAND)

  if [[ -f "$selected_file" || -d "$selected_file" ]]; then
    git add "$selected_file"
  else
    echo 'Not found or Canceled' >&2
  fi
}

main

ファイル一覧から特定のファイルをHEADの状態に戻す- git checkout -- $file

#!/usr/bin/env bash

: ${GIT_FILTER_COMMAND:=fzf}

ls_staged_files() {
  echo '--- LABEL : staged'
  git diff --name-only --staged
}

ls_modified_files() {
  echo '--- LABEL : modified'
  git diff --name-only
}

main() {
  local -r selected_file=$(cat <(ls_staged_files) <(ls_modified_files) | $GIT_FILTER_COMMAND)

  if [[ -f "$selected_file" || -d "$selected_file" ]]; then
    git checkout -- "$selected_file"
  else
    echo 'Not found or Canceled' >&2
  fi
}

main

ファイル一覧から特定のファイルをunstageする - git reset --$file

#!/usr/bin/env bash

: ${GIT_FILTER_COMMAND:=fzf}

ls_staged_files() {
  echo '--- LABEL : staged'
  git diff --name-only --staged
}

main() {
  local -r selected_file=$(cat <(ls_staged_files) | $GIT_FILTER_COMMAND)

  if [[ -f "$selected_file" || -d "$selected_file" ]]; then
    git reset -- "$selected_file"
  else
    echo 'Not found or Canceled' >&2
  fi
}

main

まだtrackしてないディレクトリの内部までほじくるとかはキャンセル処理とかが面倒なのでやってないけれど、余裕で可能だと思います。

おまけ

ファイル名を git-hoge としてPATH配下に認識させておくとgit hogeで起動できる。(サブコマンド)
拡張子をつけてエディタのファイル補完を適用したいなら、シンボリックリンクで対応すればいいと思います。

Homebrewで特定バージョンのFormulaをインストールする

mongodb を 3.4.1 から 3.2.11 にしたかったのでやってみた。
homebrew-versionsはdeprecatedだし、あんまり使いたくないなーと思ってたので使わずに。

Env

brew -v
# Homebrew 1.1.8-64-gc507222                                                                    
# Homebrew/homebrew-core (git revision 35fb7; last commit 2017-01-29)

Workflow

# Try to find the commit id
brew log --author=brew-test-bot@googlegroups.com mongodb
# Search 3.2.11 and copy the commit id (COMMIT_ID_3_2_11)

# Move to formula manager
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"

# Change the revision of the formula you wanna install
git checkout $COMMIT_ID_3_2_11 Formula/mongodb.rb

# Stop the service if needed
brew services stop mongodb

# Unlink the current formula
brew unlink mongodb

# Install the version you changed
brew install mongodb

# Check the installed formula
ls "$(brew --repo)../Cellar/mongodb/"

# Back to the latest commit
git reset -- Formula/mongodb.rb # To unstage the formula.
git checkout -- Formula/mongodb.rb

# Restart the service if needed
brew services start mongodb

3つの正規表現を知らないとハマるヨ

古来の正規表現 = 標準正規表現、basic regular expression、BRE

ダン正規表現 = 拡張正規表現、extended regular expression、ERE

独自にさらに拡張された拡張正規表現 = 長いので、超拡張正規表現とします (ちなみにもう正規言語の域を超えた)

の3種類が存在するのだけれど、みんなあまり気にしていない気がする。

BRE と ERE の違い

便宜上、左を拡張正規表現であるEREにしており、違う部分だけを抜粋(したつもり

ERE BRE 用途 代替表現
| unsupported OR 表現 I don’t know
+ unsupported 1文字以上の繰り返し \{1,\}
? unsupported 0 or 1文字 \{,1\}
() \(\) グループ化
{n,m} \{n,m\} n文字以上、m文字以下の繰り返し

であれば、詳しくは以下のコマンドを叩いて、読んでみると面白いです。(Macでしか確認していません)

man re_format

超拡張表現との比較が非常に多くなり、色々と面倒なので割愛するけれど、例として POSIX クラスを挙げておく。
e.g. 超拡張表現では POSIXクラスを [:space:] として表せるが、BRE、ERE共に [[:space:]] としなければならない。

それぞれの違いを例示してみる

他に詳しく違いを並べる時間もないので、例を出して「色々知っておかないとどはまりするかもよ」ということを以下で、備忘録という意図も含めて書いておきたい。
拡張正規表現は大体のプログラミング言語で扱われていて便利な分、尚更違いを知っておくべきである。

2つの例を用意する。

1つ、Mac で private ipを引くために、sed を使って ifconfig からぶっこ抜くことを考える。 2つ、axyzaopqalmn という文字列から aから始まり、aで終わる文字列 にマッチさせることを考える。

Mac で private ip を引く時の表現の違い

まずは1つ目。

一応 ifconfig の usage を超簡潔に示す。

ifconfig [interface name] inet

これで対応する interface の inet が出て来る。以下が出力例。

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet xxx.xx.x.xxx netmask 0xfffffxxx broadcast xxx.xx.x.255

ここからぶっこ抜くために、全体マッチさせてipの部分で置換することを考える。 (ifconfig en0 inet|tail -1 を流し込むとする。)
たくさん思いつきますね?

# BSD sed
sed 's/[[:blank:]][[:blank:]]*inet \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'

# BSD sed with modern regexp
sed -E 's/[[:blank:]]+inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1/g'

# BSD sed
sed 's/[[:blank:]][[:blank:]]*inet \([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/g'

# BSD sed with modern regexp
sed -E 's/[[:blank:]]+inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/g'

# BSD sed
sed 's/[[:blank:]]\{1,\}inet \(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*/\1/g'

# BSD sed with modern regexp
sed -E 's/[[:blank:]]+inet (([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/g'

( :digit: は長すぎるので使っていません )

BRE vs ERE で、グループ記法 ()、繰り返し記法 {n,m}、1以上繰り返し + の有無辺りに違いが見て取れる。

拡張正規表現を使ってみる with ジャバ

String parttern = "\s+inet ((\d{1,3}\.){3}\d{1,3}).*";
// replace the matched string with 1st group

メタ文字が使えてスッキリ。

axyzaopqalmn という文字列から aから始まり、aで終わる文字列 にマッチさせる時の表現の違い

(面倒くさいのでEREを使います)

特に条件を指定していないので、2つ出来るはず。(最長マッチ、最短マッチ)

echo 'axyzaopqalmn' | sed -E 's/a.+a/ここだよ/' # 最長
echo 'axyzaopqalmn' | sed -E 's/a[^a]+a/ここだよ/' # 最短

拡張正規表現ならば最長マッチは変わらないのだけれど、最短マッチは

a.+?a

で表せる。

結論

拡張正規表現しか知らないと sed とかで組むときにその人の発想が柔軟かどうかみたいな話になってしまうので 拡張正規表現の記法がどんなもののエイリアス(正確な表現ではないのだけれど)になっているか を知っておくべきだと思う。
勿論表現限界のせいで実現できないものも存在するので、知っておいた方がいい。シェル芸人になりたいなら尚更である。

例えば否定後読みなどは JavaScript (Chromium上) ですら1年前に実装されたばかりである。

https://codereview.chromium.org/1418963009

Tips

  • シェルスクリプト内ではBREの方が安全な場合もあるので、BREのみで表現可能であればBREでいいのかもしれない。 e.g.) 変数展開の文字をエスケープし忘れるなどが減る
  • 大体のコマンドは -E オプションでEREを使えるので、EREで表現可能であれば移植性も考えてEREでよい。
  • どうしてもEREでもだめだというなら perlruby にコマンドレベルで委譲するべき。問題ないのであればスクリプト全体をその言語にする必要はない
  • ある言語で定義した正規表現が別の言語だとそのまま使えない場合、バリデーションの統一に支障が出ることを念頭に置く。e.g.) サーバーサイドで定義したバリデーション用正規表現をクライアントで用いるケース

ちなみに正規表現エンジンの勉強がしたいなら以下の本がとてもオススメ。読み物としてもなかなかおもしろいです。

VectorDrawableをプレビューするChrome Extensionを作った

弊社では弱いネットワークや容量の小さい端末が普及しているような国にアプリを配布していることもあり、リソースを出来る限りVectorDrawableに置き換えています。

SVGファイルを自動でVectorDrawableに変換し、取り込んで利用しているのですが、今までxmlを見るだけでは以下の問題点がありました。

  • 稀に表示が崩れるものがあり、QA時点で発覚するとデザイナーへの負荷が大きくなる。
  • 色指定が異なることに気付けない。
  • Export名のミスによる上書きに気付けない。

つまり全ては VectorDrawableを読める人が少ない という問題点に帰結します。 いちいち手元に落として一個ずつAndroid Studioでプレビューするのも・・・ということもあり、題の通り Github上でVectorDrawableを見るChrome Extensionを作成しました。

f:id:jmatsu:20170110120701j:plain

chrome.google.com

現在、

に対応しています。

ソースコード

MITライセンスで公開しているので、ご自由にどうぞ。

jmatsu/vector-drawable-previewer

Chrome ExtensionのContent ScriptをTypeScriptで書くのは初めてだったので、見苦しい部分もあると思いますがそのときはPRをください。

おまけ

SVGからVector Drawableへの変換やこのツールについて、kyobashi.dex#4 で発表する予定です。

rmp-quipper.connpass.com

Special Thanks

アイコン作成 : @manse

adbがUSB接続端末を認識しないとき、複数起動していたadbプロセスを適当に1個killしたらadbが復活した・・・という備忘録

OpenSTFのために adb tcpip 7xxx とか色々をガンガン叩いたあと、USBデバッグをしようとしたら端末を認識しない。
adb kill-server をしても駄目。

f:id:jmatsu:20161225230656j:plain

まあこのエラーメッセージの感じ、adbプロセスがusbを向いていないんだろう・・・と推測。

適当にgrepをかけたら大量に生きていたので、プロセス番号が違うけどとりあえず上からkillしてみよう・・・とすると、
一個目を殺したらVysorが起動。つまりはそのまま認知するようになった。(一応エラーで出てたプロセス番号は一番下のものだったんだけど・・・)

f:id:jmatsu:20161225231204j:plain

プロセス数に数があるんだろうか? ならstart-server成功しないで欲しいなぁ・・・

メモ

usb接続に設定されたadbプロセスを調べる方法を見つける

ベルギーで食べたCarbonnades flamandes à la Chimayを再現する

今年の11月頭にベルギー旅行へ行き、以下のお店へ行ってきた。

www.tripadvisor.jp

B級グルメっぽい感じで、最高に美味しかった。ちなみにカードは使えず、メインが15~20ユーロ、酒ガブガブ飲んで一人辺り50ユーロとかだった。
滞在中に2夜連続突撃し、自分は2夜連続でソーセージを食べたのだけれど、友人の頼んだ Carbonnades flamandes à la Chimay(シメイビールの牛肉煮込み) も中々美味しかったので再現してみようとした。

Chimay、としか書いてなかったのでどの銘柄か分からないが、王道のシメイ・ブルーは使っているだろう。
カシスのような果物由来の香りがあったので、ルージュも使ってるのかな・・・と思ったけどメニューにはシメイ・ブルーしかなかった。
ブラウンシュガーもなかったし、面白がって似非Sirop de Liegeを作って果物の甘みと酸味を足してみることにした。

材料

材料名 分量 備考(サイズ等)
牛肉角切り 700g 4cm角程度
玉ねぎ 2個 大玉
シメイ・ブルー 3本 330ml/本
ヒューガルデン・ホワイト 1本 330ml/本
バター 30g + 20g 内訳 : 玉ねぎ炒める用 + 牛肉にまぶす用
小麦粉 大さじ3杯 薄力粉
ローリエ 2枚 マイバスで買いました
ブイヨン 1欠片 コンソメでもOK
塩・こしょう 適量 胡椒は粗挽きよりパウダーがいいです
りんごジュース 80ml 100%のもの。似非Sirop de Liege用
オレンジ・マーマレードジャム 大さじ 1/2 似非Sirop de Liege用

前準備

  • シメイ・ブルー は冷蔵庫で冷やしておく。
  • 牛肉 は常温で15分ほど放置しておく。
  • ヒューガルデン・ホワイト を開け、飲み始める。

準備

  1. 牛肉 に塩・こしょうを適度にして、軽く揉み、常温で放置。
  2. 玉ねぎ を2個とも縦に切り、繊維を断つように4~5mm程度の厚さでスライス。
  3. 前項のスライスした玉ねぎ をレンジでチンする

調理

1. スライスされた玉ねぎを炒める

フライパンにバター30gを入れ、準備3の玉ねぎを強火で炒める。
レンジでチンしたときに出た水分が半分ほどまでに減ったら次へ。

2. 牛肉を追加して蒸し焼きにする

準備1の牛肉 全体に小麦粉をまぶす。調理1 のフライパンに 準備1の牛肉 を追加し、混ぜ合わせる。
蓋をして、弱火よりの中火で15分ほど蒸し焼きにする。下記の写真のようになればOK。

3. シメイ・ブルーとローリエを入れて煮込む

シメイ・ブルー2本すべて入れ、ローリエ2枚を半分に折って入れる。蓋をして弱火よりの中火でコトコト1時間煮込む。
40分ほど経過したら次の手順をスタート。

4. 似非Sirop de Liege用を作る

小鍋に りんごジュース80mlオレンジジャム大さじ 1/2を入れて弱火よりの中火で水分を飛ばしていく。
大きさにもよるが、小鍋は傾けた方がよい。果物のカラメル的な感じなので、絶対になめない方がいい。大事なことなので二度言うが、絶対なめない方がいい。

5. 味を整える

似非Sirop de Liege を入れる。カラメルと同等なので、小鍋にスープを入れたら速攻で蓋をして伸ばす。蓋をしないと死ぬ。なお冷めると半端なく溶かしづらい。
ブイヨンも突っ込む。

この先、煮込みで水分を飛ばしていくので、少し薄いかな・・・という感覚が良い。圧力鍋の場合はちょうどいいくらいの味で。

塩加減 : 大体塩は足りないので、足す。
甘み : 特に足す必要はないが、足すならブラウンシュガー辺りがいいはず(知らない)。玉ねぎの甘みが出て来るのでいらないと思う。
スパイシーさ : 欲しいならブラックペッパーのホールを入れるといい。

6. 煮込む

ローリエは取る。蓋はせず、弱火でコトコト3時間ほど煮込む。水かさは半分を切るくらいになる。
圧力鍋の場合は低い方の圧力で1時間ほど圧力をかける。水かさはそこまで減らないので、圧が抜けたら30分くらい超弱火で水分を飛ばすとよい。

7. 味を再度整える

ここで塩加減が強かったり、甘みが強いと、ビールを足して煮込み直すなど難しい。

8. 完成

付け合せのフリットやマッシュポテトを添えて食べる。煮込んでる間に作りましょう。
バケットも美味しいけど、やっぱりフリットだと思う。

ごちそうさまでした。再現率は60%くらいだったけどまあいいんです。
次はシメイ・ルージュ入れて、あとブラックペッパーのホールを入れて煮込んでみよう。

付け合せの調理

フリット

材料名 分量 備考(サイズ等)
じゃがいも 2個 男爵いも
大量 適当
少々 粗塩

二度揚げで仕上げましょう。マヨネーズで食べると美味しいけど、この料理にはいらない。

マッシュポテト

材料名 分量 備考(サイズ等)
じゃがいも 2個 メイクイーン
バター 30g
牛乳 10ml 成分無調整
マヨネーズ 大さじ1杯 酸味少なめのものが良い
少々

ねっとり、しっとり系のマッシュポテトが最高に合う。

Hoegaarden White

Beer Advent Calendar 2016 - Adventar 23日目

今日の晩酌はベルギービールの中でも(色々あったことも)有名なHoegaarden White。

f:id:jmatsu:20161223213207j:plain

先日ベルギー旅行に行ったときにも飲んだんですが、聞いていた通りヒューガルデンというよりフーハールデンみたいな発音でした(注文はヒューガルデンで通りましたが)

f:id:jmatsu:20161223214628j:plain

王道というだけあって、コリアンダーオレンジピールの香りがいいですね。 ベルギービールの中では良心的なアルコール度数で、4.9%です。 日本でも簡単に手に入るので最高です。

Celis Whiteを作っているCelisが元々の製造者ですが、Breweryの火災に起因する経営難で、色々あって現在は別のビール会社が製造しています。 しかも製造者本人であるCelisが「かつての味じゃなくなった」みたいな発言をしているんですが、元々のHoegaardenの味自体を知らないので、飲んでみたかったなぁ。羨ましい。