あんパン

こしあん派

自作のgitサブコマンドをzshで補完する

普段の暮らしでは自作のgitサブコマンドを作って便利に使っている。

masawada.hatenablog.jp

masawada.hatenablog.jp

のだけど、通常そのままではzshの補完が効かず、全て打つかhistoryから呼び出すかする必要があった。不便だしさすがに何か方法あるだろうな〜と探っていたところ発見したのでご紹介。

A better solution is to create a function _git-foo() to handle specific completion for that command. This also allows you to add command-specific completion as well. Place such a function inside an autoloaded #compdef file and you should be all set. You can add a description to such a function by adding a line matching

#description DESCRIPTION

as the second line in the file. See Completion/Debian/Command/_git-buildpackage in the Zsh sources for an example.

zsh/_git at master · zsh-users/zsh · GitHub

ふむふむ。つまり、通常の補完ファイルと同様に _git-foo のような命名でファイルを置くとよいとのこと。詳しくは Completion/Debian/Command/_git-buildpackage を見ると分かりそう。

#compdef git-buildpackage
#description build Debian packages from a git repository

_arguments \
  '--version[show program version number and exit]' \
  '--help[show help message and exit]' \
  '--git-ignore-new[build with uncommitted changes in the source tree]' \
...

zsh/_git-buildpackage at master · zsh-users/zsh · GitHub

なるほど2行目に #description を書くと補完時に表示されるようだった。_arguments を使えば引数の補完もできる。

補完のファイルは $fpath に列挙されているパスに存在している必要がある。自分は $HOME/.zsh/completion に置くことにした。

fpath=($HOME/.zsh/completion $fpath)
autoload -Uz compinit && compinit

これで試しに $HOME/.zsh/completion/_git-delete-branches を置くと…

$ git de
delete-branches - Delete selected branches (peco required)
describe        - show most recent tag that is reachable from a commit

動いた! ずっと不便だな〜と思っていたのではやいところやっておけばよかった。

CloudFrontにLambda@EdgeでBasic認証をかけて、originのS3にファイルを追加したらSlackにURLを通知する

この記事で書いたとおり、CloudFrontにLambda@EdgeでBasic認証をかけて、originのS3にファイルを追加したらSlackにURLを通知する仕組みを整えた。

github.com

repoをcloneしてきてCDKでdeployしたら同じ環境を作ることができる。

@aws-cdk/aws-lambda-nodejs はこれまで使ったことなかったのだけど、parcelでバンドルとかうまくやってくれて、 .ts ファイルをポン置きするだけでLambdaにデプロイしてくれて最高に便利。JSだと依存の管理がムズいしGoで書くのがいいかな〜となってGoでちまちま書くことが多かったけど、何も考えずにTypeScriptで書くでもよくなったことで手札が増えて嬉しい。

Basic認証は最初はCloudFront Functionsを使ってみようかと思っていたのだけど、結構制約が厳しそうなのでLambda@Edgeにした。Lambda@Edgeを明示的に使ったのは初めて(Next.jsをAmplifyでSSRしたときに暗黙的には使ってはいた)で、Lambda@Edgeも環境変数渡せなかったりとかいろいろ制約あるんだな〜ということを学んだ。CloudFront Functionsはこれ。

aws.amazon.com

今回はISUCONで便利に使ったけど、結構汎用的に使えるはずなのでよければどうぞ。

ISUCON11予選参加して敗退した

敗退した。一番高いスコアが42296で、その後ずるずる落ちて最終的には33586で終えた。

という話をしてメンバー募集したところ、 id:papixid:stefafafan といっちょやりますかということになり、天下n品というチームでISUCON11に参加した。お二人は同僚かつ友人であり、関係値マックスの状態から走れたと思う。早速来年どうやっていきますかね〜という話もしている。

練習とか

ツイートの通りこれまではお祭り的な気分で参加してたけど、ちゃんと動き方とか考えて改善していけるといいだろうなーということを2,3年前から思っていた。なので、今回はチームを組んでからちまちま練習して初動を決めたりツールの確認とかをしていた。

  • 定時後に過去問の環境を作って初動〜作戦考えるくらいまでをやる
  • 土日のどちらかで集まって8時間かけて完走する
  • ドキュメントを整備する・今後の動き方を考える

みたいなのをそれぞれ何度かやった。まだ粗はあるものの、初動はかなりうまく動けていたと思う。ドキュメントはScrapboxに残してて、GitHubのIssueとかは使わなかった。repoは練習ごとに作りたいので、チーム固定するならScrapboxに残す方が一覧性が高いと思う。

過去問の環境整備するのはTerraformの定義用意してくれてるrepoがあり、これを使った。

数分で環境が出来上がるのでたいへんありがたく使わせてもらった。本番もAWSだったので、AWSコンソール触る練習にもなったと思う。まあ業務で毎日のように使ってるのでAWSコンソール使ってて新たな発見があったかというとそうでもなかったけど、、

使ったツールとか

言語的には全員Perlの習熟度が一番高いのだけど、APMを使いたくなったときに他の言語の方がライブラリが充実してて都合がよかろうし、Goでいきますかね〜ということでGoにした。いま考えるとPerlでも良かった気もする。というのも、最終的に両方とも使わなかったため。Goでmake通ってればまあいけるやろという気持ちになれた点は良かった。

最初はNew Relicを使ってみようということで入れる練習をしていたのだけど、Goの習熟度がそこまで高くなくどんなフレームワークがやってくるか分からない(echo以外が来たら太刀打ちできなそう)、Segmentとか切れるのは便利そうだけどあんまり時間がないISUCONでそこまで見られるかというとそうでもなさそうということで、本番3日前くらいに相談してalpとpt-query-digestだけで挑むことにした。なので、あまり凝った解析はしていない。せいぜいログ取りを自動化してホスト名、時刻、ブランチ名、コミットハッシュが分かるファイル名にするくらい。

あとは生成したらS3に置いて、Lambda@EdgeでBASIC認証をかけたCloudFrontを通して確認できるようにした。S3にログを送りつけるとLambdaでSlackに通知が飛ぶ。

f:id:masawada:20210822183516p:plain

作るのはCDKでやっていて、repoは以下に置いた。

デプロイスクリプトもある程度自動化していまいるブランチをデプロイしたり、mainブランチが更新されてたらデプロイ前に落ちるようにしたりくらいはしていた。

他のメンバーがどうかは知らないけど個人的にはtmux-xpanesを便利に使っていて、MariaDBのconfigをsymlinkにしてrepoに置いて動かなくなったのでsymlinkをやめて直接tmux-xpanesで全台書き換えてデプロイとか、全台で sudo journalctl -f とかしていた。

github.com

当日やったこと

  • 10:06 CloudFormationで環境構築完了してSSHの情報(Public IP, Private IP, ssh_config)をScrapboxに転記、ベンチ投げる
    • 初期スコアは1718
  • 10:30 ログ取りまわりの設定
  • 11:00 マニュアル読み終える
    • この時点で理解はしてない、というか今もしてなくて今年のマニュアルめっちゃ丁寧だったけどめっちゃ難しかったと思う
    • それとも日本語読んで理解する力が落ちてるのか…?
  • 11:30 デプロイスクリプト用意してデプロイしたら全台アプリケーションが落ちたので直してベンチ入れた、alpとpt-quer-digestかけた
    • Makefileがなくてmakeできてなかったり、なぜかバイナリが書き変わってなかったりしたのでMakefile作って make clean && make するようにした
  • 12:10 作戦会議してざっとあたりをつける
  • 12:50 1, 2をバックエンドにして3をDBにする
    • スコアは27312
  • 13:00 このあたりからMariaDBにアイコン画像を保存するのやめてファイルに書き出すやつやりはじめる
    • ついでにassetsもNginxから配信
  • 16:00 ここらへんで画像の分離完成
    • アイコンの配信と POST /api/isu だけNginxが載ってる方に寄せて片方のホストだけでファイルを保存するようにして、配信はX-Accel-Redirectを使ってユーザ認証してからNginxから画像を返すようにした
    • 最初ホスト上のRubyで書き出すかと思ってやったところ久々すぎてGemfile.lockがないとbundle installできない?? みたいなエラーが出てよくわからなかったりMariaDBだからなのかlibmysqlclient-devがなくてnative extensionsがビルドできなかったりして大変だったので手元にデータもってきてDocker上で書き出してホストに戻すみたいなことやってた
    • あとjia_isu_uuidが使えない?のか椅子の登録時にInternal Server Errorが返ってきて10分くらい悩んでたけど、マニュアル見たところ開発ではホストの5000番で立ってるJIA API Mockを使えと書いてあったので手で初期化したら登録できるようになった
    • ここでやったのはあんまり伸びなくて、なぜかというとアイコンのGETリクエストがそんなに多くなかったから…
      • ちゃんとalp見ようなという話だし、ちゃんとマニュアル読もうなという話でもある
  • 16:30 このあたりでやっぱりgetConditionなんとかしないとねということになってジョブキューに逃してみる? みたいな話をしてfireworq使い初めた
    • スコア全然上がらないし正直1.5時間くらいでできる気がしてなかったので諦めモードに入りつつ、まあやってみるかということで開始した
    • が、Goの習熟度が低いことが仇となってJSONをMarshalするときにうまくいかずタイムアップしてしまった
      • 普段全然使わない言語でいくとダメなことが分かったので慣れていく必要がありそう

感想

本番でも初動をしっかりできたのはよかった。Goの習熟度が低かったところと、うまくボトルネックを見つけられなかったのは引き続きという感じで、特に後者が一番重要な競技だと思うので来年はいろいろ手札を用意して臨みたい。まずは11の復習をどこかでやりたい。

競技そのものとしては事前準備(CloudFormationと環境確認など)から当日までとても快適だった。ベンチでごたついていた? ぽいけど、幸か不幸か終盤はみんな伸び悩んでゴリゴリ実装していてあんまりベンチ走らせてなかったので煽りをうけることがあまりなかった。オープニングとクロージングがあったり、VTuber企画があったりとコンテンツ的にも楽しめてよかった。開催に関わっているみなさまありがとうございました。

追記: チームメンバーのブログ記事

stefafafan.hatenablog.com

Linuxデスクトップで壁紙を接続する無線LANのSSIDによって変える

ということをやっている。

壁紙は feh で設定していて無線LAN APのSSIDは iw で取得しているのでそれぞれインストールしておく必要がある。以下のスクリプトをどこかに置いておいて、systemdでresume時に読むunitファイルを書いたら都度壁紙が変わる。

#!/bin/bash

# select wallpapers by ssid
if ! type feh > /dev/null 2>&1; then
  exit 1;
fi
if ! type iw > /dev/null 2>&1; then
  exit 1;
fi

SSID=$(iw wlp3s0 info | grep ssid | awk '{ print $2 }')
[[ $SSID = '' ]] && SSID='default';

if [ -e "${HOME}/.wallpapers/${SSID}" ]; then
  WALLPAPER_DIR="${HOME}/.wallpapers/${SSID}"
else
  WALLPAPER_DIR="${HOME}/.wallpapers/default"
fi
WALLPAPER_PATH="${WALLPAPER_DIR}/$(ls ${WALLPAPER_DIR} | shuf -n 1)"
[[ ! -f $WALLPAPER_PATH ]] && exit;

feh --image-bg white --randomize --bg-max ${WALLPAPER_DIR}/*

$HOME/.wallpapers 以下にSSIDのディレクトリを掘っておいてSSIDに対応する画像を置いておく。SSIDが既知のものでない場合は default ディレクトリにフォールバックされるのでこちらには富士山の写真を入れておく。富士山でなくても良い。こうしておくと、自宅では萌絵(萌絵って久しく聞かないね)を設定しておいて出先で開かないといけなくなったときは富士山の写真とかにできる。

もっとも、最近は外に出ることがなくなったので活躍の場がない。

SKK-JISYO.jawikiをibus-skkで利用する

Linuxデスクトップをメインの端末にしてからこれまで2年ほどibus-skkを利用しており、辞書はSKK-JISYO.Lとユーザ辞書のみという状態で固有名詞に弱いことを不便に思っていた。都度ユーザ辞書に登録すれば良いが、それも面倒なのでWikipediaからSKK辞書を生成して利用できると便利そう。どうせ同じようなことを考えているひとはいるだろうと思って探したところ、tokuhiromさんが作られていた。しかもGitHub Actionsで定期的にビルドされているのである程度最新版のWikipediaに追従されている。最高です、ありがとうございます。

github.com

ということで、これをibus-skkで利用することにした。最初は $HOME/.config/ibus-skk/SKK-JISYO.jawiki に置いて辞書として登録したのだが、どうも使われていない様子。調べたところUTF-8の辞書を置くだけだとibus-skkが読んでくれていないようだった。

対処方法は以下の2つのいずれか。

  • Coding Cookie (;; -*- coding: utf-8 -*-) をファイルの先頭に挿入する
  • dconfで辞書のencodingを設定する

実際に両方とも試したところ、それぞれ辞書が使われるようになった。

辞書の取得と登録を自動化したいのでCoding Cookieを都度入れるのは面倒そう。生成時に含めるようにPull Requestを送るかどうかでいうと、いずれにせよ辞書の場所を設定したりその他の調整も自動化したいのでシェルスクリプトでdconfを叩いたら良いかという気持ちになりそのようにした。

$ dconf write /desktop/ibus/engine/skk/dictionaries "[..., 'file=/path/to/SKK-JISYO.jawiki,mode=readonly,type=file,encoding=UTF-8', ...]"

といった具合。作業前後に dconf read /desktop/ibus/engine/skk/dictionaries で様子を見ておくと良い。

内田真礼を一発で変換できて助かる。