fzfをつかってRailsのmigrationを実行しやすくする
イントロ
Railsのmigationを実行する機会はそこまで多くはないと思うのですが、
generateしてつくったあとにVERSIONの選択が意外と面倒だったりします。
以前の記事
でgit statusをfzfのpreviewやbindを使って操作しやすくしましたが、
railsのmigration管理もpreviewとbindと親和性が高いなと思い作ってみました。
fish shell の function
以下のようなfish の function を作成しています。
function migrate if test ! -d 'db/migrate' echo 'Go to Rails Root' return end set -l out (ls -1 db/migrate | grep -v -e '^\.' | \ fzf --exit-0 \ --preview="bat --color=always db/migrate/{}" \ --expect=ctrl-u,ctrl-d,ctrl-r,ctrl-m \ --header='C-u: up, C-d: down, C-r: redo, C-m(Enter): edit' \ ) [ $status != 0 ]; and commandline -f repaint; and return if string length -q -- $out set -l key $out[1] set -l time (echo $out[2] | awk -F '_' '{ print $1 }') echo $key if test $key = 'ctrl-u' commandline "./bin/rails db:migrate:up VERSION=$time" else if test $key = 'ctrl-d' commandline "./bin/rails db:migrate:down VERSION=$time" else if test $key = 'ctrl-r' commandline "./bin/rails db:migrate:redo VERSION=$time" else if test $key = 'ctrl-m' commandline "$EDITOR db/migrate/$out[2]" end commandline -f execute end end
操作方法
functionを登録してコマンドを実行するとfzf が起動します。
$ migrate
migrate:up migrate:down migrate:redo を key bind しているので
バージョンを指定してアクションを決めて実行することができます。
これで少し便利になりました。
previewにはbatコマンドを使っていますが、headなどでもいいかと思います。
よかったら使ってみてください。
brewのformulaアップグレード時の依存関係のアップグレードによる弊害に対応する
イントロ
googlerをアップグレードしたところopensslのバージョンがあがって
他のツールが壊れてしまったのを戻す作業をした履歴です。
困ってる人の役に当てればと思います。
エラーと調査
ことの始まりは
$ brew upgrade googler
googlerの新しいバージョンがでてるからupgradeしました。
==> Upgrading 1 outdated package: googler 3.7.1 -> 4.0_1 ==> Upgrading googler 3.7.1 -> 4.0_1 ==> Installing dependencies for googler: openssl@1.1, xz and python@3.8 ==> Installing googler dependency: openssl@1.1 ==> Downloading https://homebrew.bintray.com/bottles/openssl@1.1-1.1.1f.mojave.bottle.tar.gz ==> Downloading from https://akamai.bintray.com/25/25ab844d2f14fc85c7f52958b4b89bdd2965bbd9c557445829eff6473f238744?__gda__=exp=1586836802~hmac=b9c5e50d09 6a9d953daac8c75 ######################################################################## 100.0% ==> Pouring openssl@1.1-1.1.1f.mojave.bottle.tar.gz ==> Caveats A CA file has been bootstrapped using certificates from the system keychain. To add additional certificates, place .pem files in /usr/local/etc/openssl@1.1/certs and run /usr/local/opt/openssl@1.1/bin/c_rehash openssl@1.1 is keg-only, which means it was not symlinked into /usr/local, because macOS provides LibreSSL. If you need to have openssl@1.1 first in your PATH run: echo 'set -g fish_user_paths "/usr/local/opt/openssl@1.1/bin" $fish_user_paths' >> ~/.config/fish/config.fish For compilers to find openssl@1.1 you may need to set: set -gx LDFLAGS "-L/usr/local/opt/openssl@1.1/lib" set -gx CPPFLAGS "-I/usr/local/opt/openssl@1.1/include" For pkg-config to find openssl@1.1 you may need to set: set -gx PKG_CONFIG_PATH "/usr/local/opt/openssl@1.1/lib/pkgconfig" ==> Summary 🍺 /usr/local/Cellar/openssl@1.1/1.1.1f: 8,057 files, 18MB ==> Installing googler dependency: xz ==> Downloading https://homebrew.bintray.com/bottles/xz-5.2.5.mojave.bottle.tar.gz ==> Downloading from https://akamai.bintray.com/44/44483961b5d2b535b0ece1936c9d40b4bc7d9c7281646cca0fb476291ab9d4dc?__gda__=exp=1586836818~hmac=45f8f52462 3d23ee5d13f2dad ######################################################################## 100.0% ==> Pouring xz-5.2.5.mojave.bottle.tar.gz 🍺 /usr/local/Cellar/xz/5.2.5: 92 files, 1.1MB ==> Installing googler dependency: python@3.8 ==> Downloading https://homebrew.bintray.com/bottles/python@3.8-3.8.2.mojave.bottle.tar.gz ==> Downloading from https://akamai.bintray.com/51/511b4f2c3993f000516938ed0700936c8a7d8c054b5171fa733ac7d344291c30?__gda__=exp=1586836821~hmac=0271b874c6 5db4ee2c7f66f1d ######################################################################## 100.0% ==> Pouring python@3.8-3.8.2.mojave.bottle.tar.gz ==> /usr/local/Cellar/python@3.8/3.8.2/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cellar/python@3.8/3.8. 2/bin --install ==> /usr/local/Cellar/python@3.8/3.8.2/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cellar/python@3.8/3.8. 2/bin --install ==> /usr/local/Cellar/python@3.8/3.8.2/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cellar/python@3.8/3.8. 2/bin --install ==> Caveats Python has been installed as /usr/local/opt/python@3.8/bin/python3 You can install Python packages with /usr/local/opt/python@3.8/bin/pip3 install <package> They will install into the site-package directory /usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages
brew upgrade すると
dependencyになっている formula がアップグレードされます。
openssl も バージョンアップされてしまいます。
以前もこの問題で python がアップグレードしてパスが変更されてしまいいろいろ動作できないソフトがあって困ったことがありました。
今回も気づかず
暫くして
rails cをしてみたところ以下のようなエラーに
$ rails c /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `requir e': dlopen(/rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local /opt/openssl/lib/libssl.1.0.0.dylib (LoadError) Referenced from: /rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle Reason: image not found - /rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle
あれ?
起動しない
LoadErrorになっている。
opensslのライブラリが参照できなくなっている
opensslのバージョンが上がっていることに気づく
エラー内容をGoogleで調べているとライブラリを読み込ませると動く模様
mysql2をインストールしたときに参照しているopensslを参照できないようなので
一旦mysql2は削除して入れ直すことに
$ brew info openssl
を確認すると
set -gx LDFLAGS "-L/usr/local/opt/openssl@1.1/lib" set -gx CPPFLAGS "-I/usr/local/opt/openssl@1.1/include"
とあり、ライブラリのパスが確認できます。
bindle 時に利用できるように以下のように config に設定します。
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
mysql2を入れ直すためアンインストールします。
$ bundle exec gem uninstall mysql2
再度インストール
$ bundle install
起動してみます。
$ rails c
インストール時にはライブラリを参照してくれてそうだけどエラーは解消しませんでした。
/rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `requir e': dlopen(/rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (LoadError) Referenced from: /usr/local/opt/mysql/lib/libmysqlclient.20.dylib Reason: image not found - /rails_project/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle
rails cでライブラリの古い方を見てしまうようです。
PATHなどを確認して古いopensslのライブラリを参照しないようにしてますが
いろいろ調べてるがこれ以上はわからない状態でした。
opensslのインストール先を確認
$ brew --prefix openssl /usr/local/opt/openssl@1.1
PATHに古いopensslが残っていて古いバージョンを参照していました。
$ which openssl
/usr/local/opt/openssl/bin/openssl
PATHの設定を見直して新しいバージョンを参照させて、再度bundleしなおしても駄目でした。
お手上げ感があったのですが、
mysql2.bundleがイマイチよくわかっておらず調べていると
どうもmysql自体のインストール時に参照するライブラリを決め打ちしてそうということがわかり
一旦mysqlを停止してみました。
$ sudo mysql.server stop Password: dyld: Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib Referenced from: /usr/local/Cellar/mysql/5.7.17/bin/my_print_defaults Reason: image not found Shutting down MySQL ... SUCCESS!
あら、rails c したときと同じようなエラーが、、、
起動もできなくなったので、
opensslのバージョンを戻すことに
brew で uninstall すると 依存関係のあるformulaが多いので怒られるが
--ignore-dependenciesをつけるとアンインストールできます。
$ brew uninstall --ignore-dependencies openssl Uninstalling /usr/local/Cellar/openssl@1.1/1.1.1f... (8,057 files, 18MB)
古いopensslのライブラリをインストールする
$ brew install https://github.com/tebelorg/Tump/releases/download/v1.0.0/openssl.rb Updating Homebrew...
これで1.0.2tがインストールされた。
(他のやりかたでインストールできるかもしれないが調べきれてない。)
mysqlを起動してみる
$ sudo mysql.server start
Starting MySQL
.. SUCCESS!
起動できた!
bundle configの内容をバージョンダウンしたopensslに合わせる(戻す)
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"
再度mysql2を入れ直す
$ bundle exec gem uninstall mysql2
$ bundle install
まとめ
結局opensslのバージョンを一旦戻すことにした。
おそくらbrew upgrade で影響のある formula を上げていけばいいのだが、
上げたくないものもあるので、悩ましいところ。
brew で formula の依存関係を確認することができる。
brew deps コマンドが使える
今回のgooglerの場合だと以下の通り
$ brew deps --tree googler googler └── python@3.8 ├── gdbm ├── openssl@1.1 ├── readline ├── sqlite │ └── readline └── xz
ということで python経由でopensslのバージョンアップがされてしまったと気付ける。
逆にopensslがどのformulaが利用してるかというと以下のように uses オプションが使える。
$ brew uses --installed openssl asdf glib imagemagick mysql python@3.8 shared-mime-info vim docutils gnupg libevent poco rbenv tmux erlang gnutls libheif python ruby unbound
またautoupgradeさせない方法もあった。
$ brew pin openssl
というようにするとバージョンが固定されるようです。 解除するには
$ brew unpin openssl
とすると解除できます。
積極的に活用しようと思います。
RailsのRubyバージョンを2.7.0から2.7.1に上げる
いつものようにRailsのRubyバージョンを上げていこうかと思います。
まずはruby-buildの最新化します。
$ brew upgrade ruby-build
rubyをrbenvで管理しているのでrbenvで2.7.1をビルドします。
$ rbenv install 2.7.1
Rails root の.ruby-version を 2.7.1 に変更
$ ruby -v ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin18]
$ bundle --version Bundler version 2.1.4
Gemfileのrubyのバージョンを変更
ruby '2.7.1'
.ruby-versionとGemfileのバージョンをあわせてbundle installします。
$ bundle install
rails c を起動するとエラーが表示されました。
Traceback (most recent call last): 15: from bin/rails:3:in `<main>' 14: from bin/rails:3:in `require_relative' 13: from /rails_project/config/boot.rb:4:in `<top (required)>' 12: from /rails_project/config/boot.rb:4:in `require' 11: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `<top (required)>' 10: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `require_relative' 9: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `<top (required)>' 8: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `require_relative' 7: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `<top (required)>' 6: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `require_relative' 5: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `<top (required)>' 4: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/explicit_require.rb:41:in `with_gems' 3: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `block in <top (required)>' 2: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `require' 1: from /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:9:in `<top (required)>' /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:9:in `require': cannot load such file -- msgpack/2.7/msgpack (LoadError) 16: from bin/rails:3:in `<main>' 15: from bin/rails:3:in `require_relative' 14: from /rails_project/config/boot.rb:4:in `<top (required)>' 13: from /rails_project/config/boot.rb:4:in `require' 12: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `<top (required)>' 11: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `require_relative' 10: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `<top (required)>' 9: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `require_relative' 8: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `<top (required)>' 7: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `require_relative' 6: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `<top (required)>' 5: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/explicit_require.rb:41:in `with_gems' 4: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `block in <top (required)>' 3: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `require' 2: from /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:8:in `<top (required)>' 1: from /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:11:in `rescue in <top (required)>' /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:11:in `require': incompatible library version - /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack/msgpack.bundle (LoadError) 16: from bin/rails:3:in `<main>' 15: from bin/rails:3:in `require_relative' 14: from /rails_project/config/boot.rb:4:in `<top (required)>' 13: from /rails_project/config/boot.rb:4:in `require' 12: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `<top (required)>' 11: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `require_relative' 10: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `<top (required)>' 9: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `require_relative' 8: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `<top (required)>' 7: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `require_relative' 6: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `<top (required)>' 5: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/explicit_require.rb:40:in `with_gems' 4: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/explicit_require.rb:44:in `rescue in with_gems' 3: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `block in <top (required)>' 2: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `require' 1: from /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:9:in `<top (required)>' /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:9:in `require': cannot load such file -- msgpack/2.7/msgpack (LoadError) 17: from bin/rails:3:in `<main>' 16: from bin/rails:3:in `require_relative' 15: from /rails_project/config/boot.rb:4:in `<top (required)>' 14: from /rails_project/config/boot.rb:4:in `require' 13: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `<top (required)>' 12: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/setup.rb:2:in `require_relative' 11: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `<top (required)>' 10: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap.rb:4:in `require_relative' 9: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `<top (required)>' 8: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache.rb:74:in `require_relative' 7: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `<top (required)>' 6: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/explicit_require.rb:40:in `with_gems' 5: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/explicit_require.rb:44:in `rescue in with_gems' 4: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `block in <top (required)>' 3: from /rails_project/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/store.rb:4:in `require' 2: from /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:8:in `<top (required)>' 1: from /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:11:in `rescue in <top (required)>' /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack.rb:11:in `require': incompatible library version - /rails_project/vendor/bundle/ruby/2.7.0/gems/msgpack-1.3.3/lib/msgpack/msgpack.bundle (LoadError)
msgpackの参照してるライブラリで参照エラーになってしまうようです。
私の場合はbundle install の際に path を vendor/bundle に設定しているので、
vendor/bundle/ruby/2.7.0 配下を削除して bundle install しなおします。
今回の2.7.1の場合, patchバージョン変更のため2.7.0のディレクトリがそのまま使われるようです。
Dockerなどでvendor配下を共有している場合も同様の事象に遭遇する可能性があるので
一旦削除して再インストールすると良いかもしれなれないです。
bundle upgrade の helpをみてみると options --ruby の項目があり
--ruby Update the locked version of Ruby to the current version of Ruby.
と記載されていたので、 試してみたのですが 同様のエラーになって動作しなかったので使い方が違いそうです。
テストがある方は rails testなどでテストして動作確認してください。
$ rails test
ghコマンドとfzfコマンドのbind、previewを使って開発フローを見直す
概要
よく利用するコマンドが洗練されている方がいいのですが、
時間をかけて修正する大変でなかなか重い腰が上がらないです。
基本的にGitHubを使っての開発が多いのですが、 コマンドライン(以下CLI)とブラウザの行き来が多いです。
pecoを使っていたのですが、 fzfのpreviewが便利そうだったので previewを使いつつghと連携して改善してみました。 調べているうちにfzfのbindも便利そうなので使ってみました。
フローの概要
改善前のフロー
既存のissue prを確認するフロー
- (ブラウザ) PullRequest(以下PR)を確認
- (ブラウザ) PRからブランチを確認
- (CLI) ブランチをチェックアウト
- (CLI) コード修正、動作確認
- (CLI) git add/commit/push
- (ブラウザ) PRを確認
新規に開発するフロー
改善後のフロー
既存のissue prを確認する場合
- (CLI) PullRequest(以下PR)を確認 (CLI)
- (CLI) PRのブランチをチェックアウト(CLI)
- (CLI) コード修正、動作確認
- (CLI) git add/commit/push
- (ブラウザ) PRを確認
新規に開発する場合
改善した点
gh
がissue, PRの一覧確認ができるので
fzf
と組み合わせてブラウザの確認をCLIに変更します。
最後のPR確認はブラウザで画像をアップすることもあるのでCLIへの移行は難しそうです。
使用したコマンドのバージョン
command | version |
---|---|
gh | 0.6.4 |
fish | 3.1.0 |
git | 2.26.0 |
fzf | 0.21.0 |
コマンド別の修正内容
改善のためにfish shellのfunctionを作成しています。 作成したfunctionは以下の3通りです。
- issue確認のfunction
- PR確認のfunction
- git statusのfunction
issue確認のfunction
実際にfunctionを見ていきましょう。
function fzf_git_issue set -l query (commandline --current-buffer) if test -n $query set fzf_query --query "$query" end set -l base_command gh issue list --limit 100 set -l bind_commands "ctrl-a:reload($base_command --state all)" set bind_commands $bind_commands "ctrl-o:reload($base_command --state open)" set bind_commands $bind_commands "ctrl-c:reload($base_command --state closed)" set -l bind_str (string join ',' $bind_commands) set -l out ( \ command $base_command | \ fzf $fzf_query \ --prompt='Open issue list >' \ --preview "gh issue view {1}" \ --bind $bind_str \ --header='C-a: all, C-o: open, C-c: closed' \ ) if test -z $out return end set -l issue_id (echo $out | awk '{ print $1 }') commandline "gh issue view -w $issue_id" commandline -f execute end
gh
を使ってopenなissueリストを一覧化してfzfに食わせています。
fzf
のpreview で gh issue view
の内容を表示しています。
基本的にはCLIから確認し詳細を確認して、Enterでブラウザが開きます。
デフォルトではopenのissueだけを確認できるようにしておき、
issueのステータスがclosedを確認したい場合はCtrl-c
で一覧をリフレッシュしています。
同様にすべてのステータスを確認したい場合はCtrl-a
でリフレッシュしています。
選択したissueでEnterするとブラウザで確認できるようにしています。
PRの確認function
PRの確認も基本的にissueと同じように作っています。
function fzf_git_pull_request set -l query (commandline --current-buffer) if test -n $query set fzf_query --query "$query" end set -l base_command gh pr list --limit 100 set -l bind_commands "ctrl-a:reload($base_command --state all)" set bind_commands $bind_commands "ctrl-o:reload($base_command --state open)" set bind_commands $bind_commands "ctrl-c:reload($base_command --state closed)" set bind_commands $bind_commands "ctrl-g:reload($base_command --state merged)" set bind_commands $bind_commands "ctrl-a:reload($base_command --state all)" set -l bind_str (string join ',' $bind_commands) set -l out ( \ command $base_command | \ fzf $fzf_query \ --prompt='Select Pull Request>' \ --preview="gh pr view {1}" \ --expect=ctrl-k,ctrl-m \ --header='enter: open in browser, C-k: checkout, C-a: all, C-o: open, C-c: closed, C-g: merged, C-a: all' \ ) if test -z $out return end set -l pr_id (echo $out[2] | awk '{ print $1 }') if test $out[1] = 'ctrl-k' commandline "gh pr checkout $pr_id" commandline -f execute else if test $out[1] = 'ctrl-m' commandline "gh pr view --web $pr_id" commandline -f execute end end
ghをつかってPRの一覧を取得しています。
こちらもデフォルトだとステータスがopenのものに絞られている為、
マージ済みものも確認する場合はCtrl-g
で表示し直していたりします。
PRの場合は特にマージ済みの情報を見たくなったりしているので初期コマンドをallで確認してもいいかもしれないです。
件数は使っているうちに変更したくなるやもしれませんが
デフォルトだと30件なので一旦は100件にしています。
ここで
Ctrl-k
で gh pr checkout <PRのid>
を使ってcheckoutできます。
このコマンドは便利ですね。gh 様々です。
ブラウザでPRを確認してbranch名をコピーしてブランチの切り替えをやる作業をスムーズにすることができます。
git statusのfunction
git status
をgst
としてaliasに設定していたのですが、
fzfのpreview、bindを組み合わせて改善しています。
function gst --description 'git status -s' if ! is_git_dir return end set -l base_command git status -s set -l bind_reload "reload($base_command)" set -l bind_commands "ctrl-a:execute-silent(git add {2})+$bind_reload" set bind_commands $bind_commands "ctrl-u:execute-silent(git restore --staged {2})+$bind_reload" set -l bind_str (string join ',' $bind_commands) set -l out (command $base_command | \ fzf --preview="git diff {2}" \ --expect=ctrl-m,ctrl-r,ctrl-v,ctrl-c \ --bind $bind_str \ --header='C-a: add, C-u: unstage, C-c: commit, C-m(Enter): mv, C-r: rm, C-v: edit' \ ) [ $status != 0 ]; and commandline -f repaint; and return if string length -q -- $out set -l key $out[1] set -l file (echo $out[2] | awk -F ' ' '{ print $NF }') if test $key = 'ctrl-m' commandline -f repaint commandline "git mv $file " else if test $key = 'ctrl-r' commandline "git rm $file " commandline -f execute else if test $key = 'ctrl-v' commandline "$EDITOR $file" commandline -f execute else if test $key = 'ctrl-c' commandline "git commit -v" commandline -f execute else commandline -f repaint end end end
git status -s の結果を fzf に食わせています。
preview には git diff <選択ファイル>
で差分内容が表示されます。
fzfのbindでいくつかのコマンドを設定しています。
Ctrl-a
で git add <選択ファイル>
して fzf をリフレッシュしています。
Ctrl-u
で git restore --staged <選択ファイル>
して fzf をリフレッシュしています。
Ctrl-c
で git commit -v
します。
この3つの操作で基本的にcommitまで持っていくようにしています。
あとgit status
の内容を見ていてdiffなどから修正したいことがあったので、
Ctrl-v
で エディタでのファイル編集を呼び出しています。私の場合はnvimになります。
付属としてgit rm/mvを用意していますが、おらくgit statusする前にコマンド打ちたくなりそうかな思われます。
まとめ
fzfのpreviewは他の人のブログを確認すると有効に利用している人を多々見かけます。 すべてをCLIで収めるのは難しかと思いますが、極力CLIで済ませることができそうです。
特にbindはブログに記載している人を見かけてなかったので これを見て利用してくれる方が出てくれば嬉しい限りです。
続 iTerm2でHexコードを送ってfishでCmd+[とCmd+]をディレクトリの戻る進むに対応させる
概要
以前の記事でfishのbindを利用して対応しました。
このbindによってペーストが壊れてしまい対応が難しいとわかったので
別の方法でiTerm2を使って対応しました。
経緯
ここで貼り付けた文字列が壊れると質問したのですが
bind \e\[ 'do something'
がbindで設定を禁止させるべきかもと回答を頂きました。
現状では設定しなのがよいとのことなので、
fishで既にprevd-or-backward-wordがbindされているキーを
iTerm2で入力したCmd+[と]を別のキーとして入力することにしてみました。
設定
fishのbind確認
fishでnextd-or-forward-wordがbindされているキーを確認してみましょう。
$ bind --key | grep nextd-or-forward-word bind --preset \e\eOC nextd-or-forward-word bind --preset \e\e\[C nextd-or-forward-word bind --preset \eO3C nextd-or-forward-word bind --preset \e\[3C nextd-or-forward-word bind --preset \e\[1\;3C nextd-or-forward-word bind --preset \e\[1\;9C nextd-or-forward-word
次にprevd-or-backward-wordを確認します。
$ bind --key | grep prevd-or-backward-word bind --preset \e\eOD prevd-or-backward-word bind --preset \e\e\[D prevd-or-backward-word bind --preset \eO3D prevd-or-backward-word bind --preset \e\[3D prevd-or-backward-word bind --preset \e\[1\;3D prevd-or-backward-word bind --preset \e\[1\;9D prevd-or-backward-word
今回はAlt+←と→でディレクトリの行き来ができるとわかったので活用したいと思います。 Alt+← が \e[1\;3D で Alt+→ が \e[1\;3C です。
これを踏まえてiTerm2の設定を行います。
いくつか設定されていますが、このままだと何が設定されているのかよくわからない状態です。
iTerm2の設定
Cmd+[と]は他のキーに割り当ててもよいので
既にバインドされているキーに割り当ててしまいましょう。
iTerm2のPreferencesからProfilesのタブを選択して
Keysのタブを選択します。ここまでは以前と同じです。
fishにはbindするキーを確認するコマンド fish_key_reader があります。
Alt+← を確認すると
$ fish_key_reader Press a key hex: 1B char: \c[ (or \e) ( 0.144 ms) hex: 5B char: [ ( 0.084 ms) hex: 31 char: 1 ( 0.130 ms) hex: 3B char: ; ( 0.130 ms) hex: 33 char: 3 ( 0.077 ms) hex: 44 char: D bind \e\[1\;3D 'do something'
Alt+→を確認すると
$ fish_key_reader Press a key hex: 1B char: \c[ (or \e) ( 0.122 ms) hex: 5B char: [ ( 0.118 ms) hex: 31 char: 1 ( 0.032 ms) hex: 3B char: ; ( 0.056 ms) hex: 33 char: 3 ( 0.159 ms) hex: 43 char: C bind \e\[1\;3C 'do something'
1B 5B 31 3B 33 44
1B 5B 31 3B 33 43
だとわかるのでiTerm2に設定します。 こんな感じです。
まとめ
これらの設定で対応ディレクトリ移動が少し快適になりました。
fishで今後 "\e[" のbindは禁止されるかもしれませんが
いい方法で解決してくれると嬉しいです。
参考URL
fishでCmd+[とCmd+]を使って移動したディレクトリに移動する
こちら記事を書いたのですが、設定するとペーストが壊れてしまう事象が発生してしまいました。 事象が解消してから設定することをおすすめします。
概要
Macでブラウザの戻る進むを Cmd+[ と Cmd+] で行うのと同じように
Slackのチャネルの戻る進むを Cmd+[ と Cmd+] で行うのと同じように
fishでのディレクトリの移動を Cmd+[ と Cmd+] で行いたい。
fish
config の設定
bind \e\[ prevd-or-backward-word bind \e\] nextd-or-forward-word
configに上記を追加します。
\eはEscです。
ここではCmdではないです。本来であればCmd+[をそのまま認識させたいのですが、
やり方がなさそうなので、Escにしています。
別のなにかに置き換えていても問題ないです。
今回はこのようにしています。
prevd-or-backward-wordとは
次にprevd-or-backward-wordの中身を確認しておきます。
(※ ここは読み飛ばしてもらっても問題ないです。)
function prevd-or-backward-word set -l cmd (commandline) if test -z "$cmd" prevd commandline -f repaint else commandline -f backward-word end end
コマンドが入力状態をチェックして入力されてなかったら
prevdを発行して再描画しています。
prevdは以前にいたディレクトリへ移動するコマンドです。
backward-wordは1文字戻るコマンドです。入力中の場合は一文字戻るようにしているようです。
やりたいことだけだと
prevd commandline -f repaint
ここの処理だけです。
このコマンドを別途切り出してもfunctionにしてもいいのですが、
今回はprevd-or-backward-wordが既に実装されているのでこれを使うことにしました。
iTerm2の設定
最近はiTerm2のショートカットが勝手に起動して少し使いづらさを感じていて移行しようか迷い中ですが、 今回はiTerm2の設定です。
Cmd+[とCmd+]を入力してEsc+[とEsc+]に変換する設定を追加しています。
iTerm2のPreferencesからProfilesのタブを選択して
Profileを選択(私の場合はDefault)
Keysのタブを選択して一覧の下にある+ボタンを押して設定を追加します。
Keyboard ShortcutにはCmd[を設定してActionにSend Escape Sequenceを設定して Esc + [ を設定すればOKです。
まとめ
これでCmd+[とCmd+]で戻ることができます。
..を押すことが度々ありますが、これでCmd+[で快適になりそうです。
ディレクトリ..での移動が多い人はやってみてはどうでしょうか。
Qiitaの記事をmarkdownファイルで保存する
概要
Qiitaの退会がいて既にみれなくなっている記事もあるかと思いますが、
ストックしてたい記事がなくなるととても残念です。
まだ公開されているものはlocalに保存しておくのも手ではないでしょうか。
やりかた
qiita.com
こちらを参考にして保存したい記事のURLを取得してファイルに保存しておきます。
今回はqiita_urls.txtをつくり、
取得したいURLをファイルに複数行設定して以下のコマンドを実行しました。
cat qiita_urls.txt | xargs -n1 -I{} bash -c "curl -sS {}.md > \$(echo {} | awk -F / '{print \$NF}').md"
簡単ですね。
まとめ
これで一旦保持したい記事はローカルに残すことができそうです。