hotoolong's blog

プログラムのことやエンジニアリングに関することを記事にしています。

(5/29-6/11) Kindle本 ビジネス書キャンペーン【最大50%OFF】

5月29日(金)~ 6月11日(木)にかけてビジネス書キャンペーンが開催されています。
いつものようにpickupしていきたいと思います。

pickup

グロースハック

  • リーン・スタートアップ ムダのない起業プロセスでイノベーションを生みだす (¥990)

  • Hacking Growth グロースハック完全読本 (¥1,100)

テスト

  • はじめて学ぶソフトウェアのテスト技法 (¥1,320)

コンピュータ基礎

  • コンピュータはなぜ動くのか 知っておきたいハードウエア&ソフトウエアの基礎知識 (¥1,320)

デザイン

  • 突破するデザイン (¥1,100)

突破するデザイン

突破するデザイン

組織

  • OKR(オーケーアール) (¥825)

自己研鑽

  • すべての知識を「20字」でまとめる 紙1枚!独学法 (¥770)

  • 脳を最適化すれば能力は2倍になる 仕事の精度と速度を脳科学的にあげる方法 (¥763)

  • イシューからはじめよ ― 知的生産の「シンプルな本質」 (¥990)

  • すべての仕事は10分で終わる マルチタスクでも仕事がたまらない究極の方法 (¥770)

  • SOFT SKILLS ソフトウェア開発者の人生マニュアル (¥1,540)

まとめ

ひさびさのビジネス書のキャンペーンなのでこのタイミングで購入されるのはどうでしょうか。
他の書籍が気になる方はこちらのリンクからどうぞ!

(4/22-5/7) 理工系定番テキストフェア

イントロ

Kindleのセール情報です。 今回は理工系定番テキストフェアです。 機械学習、統計情報に関する書籍が何点かあります。

pickup

  • 実践Data Scienceシリーズ RとStanではじめる ベイズ統計モデリングによるデータ分析入門 (KS情報科学専門書) (¥2,310)

まとめ

割引率はそこまで高くはないですが、
良本が安くなっているタイミングで買っておくのは良いのではないでしょうか。 他の書籍が気になる方はこちら)のリンクからどうぞ!

fzfをつかってRailsのmigrationを実行しやすくする

イントロ

Railsのmigationを実行する機会はそこまで多くはないと思うのですが、
generateしてつくったあとにVERSIONの選択が意外と面倒だったりします。

以前の記事

hotoolong.hatenablog.com

で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

f:id:hotoolong:20200420002914g:plain
migration

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がイマイチよくわかっておらず調べていると

qastack.jp

どうも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

とすると解除できます。
積極的に活用しようと思います。

(4/10-4/23) コンピューター・ITキャンペーン 【40%OFF以上】

イントロ

Kindleのセール情報です。 今回はコンピューター・ITキャンペーンです。

SBクリエイティブから出版されているものは以前のポイントセールに引き続き登場してます。

pickup

  • デザイン入門教室[特別講義] 確かな力を身に付けられる ~学び、考え、作る授業~ (Design &IDEA) (¥1,018)

  • HTML5&CSS3デザイン 現場の新標準ガイド フロントエンドエンジニアのための必須知識と実践 (¥1,645)

  • UX × Biz Book 顧客志向のビジネス・アプローチとしてのUXデザイン(固定レイアウト版) (¥1,540)

  • Vue.jsのツボとコツがゼッタイにわかる本 (¥1,337)

  • 新・明解C言語 実践編 (¥1,265)

新・明解C言語 実践編

新・明解C言語 実践編

  • 明快入門 C スーパービギナー編 (林晴比古実用マスターシリーズ) (¥880)

  • C言語クイック入門&リファレンス 林晴比古実用マスターシリーズ (¥1,430)

  • 明快入門 Java (林晴比古実用マスターシリーズ) (¥1,540)

  • 暗号技術入門 第3版 秘密の国のアリス (¥1,650)

  • 人工知能と友だちになれる?:もし、隣の席の子がロボットだったら…マンガでわかるAIと生きる未来 (子供の科学★ミライサイエンス) (¥660)

  • 基礎からきっちり覚える 機械語入門 (¥1,760)

基礎からきっちり覚える 機械語入門

基礎からきっちり覚える 機械語入門

  • CAREER SKILLS ソフトウェア開発者の完全キャリアガイド (¥1,834)

  • プログラミングの心理学 【25周年記念版】 (¥1,430)

TCP/IP の基礎

TCP/IP の基礎

  • 作者:Gene
  • 発売日: 2011/02/23
  • メディア: Kindle

  • 恋するプログラム―Rubyでつくる人工無脳 (Mynavi Advanced Library) (¥1,815)

  • Linux/UNIX入門 第3版 (林晴比古実用マスターシリーズ) (¥2,090)

  • 標準テキスト CentOS 7 構築・運用・管理パーフェクトガイド (¥2,310)

まとめ

過去の良本があるので安くなっているタイミングで買っておくのは良いのではないでしょうか。 他の書籍が気になる方はこちらのリンクからどうぞ!

RailsのRubyバージョンを2.7.0から2.7.1に上げる

いつものようにRailsRubyバージョンを上げていこうかと思います。

まずは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の確認
  • (CLI) ブランチを作成
  • (CLI) コード修正、動作確認
  • (CLI) git add/commit/push
  • (ブラウザ) PRを作成

改善後のフロー

既存のissue prを確認する場合

  • (CLI) PullRequest(以下PR)を確認 (CLI)
  • (CLI) PRのブランチをチェックアウト(CLI)
  • (CLI) コード修正、動作確認
  • (CLI) git add/commit/push
  • (ブラウザ) PRを確認

新規に開発する場合

  • (CLI) issueの確認
  • (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に食わせています。
fzfpreviewgh 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-kgh pr checkout <PRのid> を使ってcheckoutできます。
このコマンドは便利ですね。gh 様々です。
ブラウザでPRを確認してbranch名をコピーしてブランチの切り替えをやる作業をスムーズにすることができます。

git statusのfunction

git statusgstとして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-agit add <選択ファイル> して fzf をリフレッシュしています。
Ctrl-ugit restore --staged <選択ファイル> して fzf をリフレッシュしています。
Ctrl-cgit commit -v します。
この3つの操作で基本的にcommitまで持っていくようにしています。

あとgit statusの内容を見ていてdiffなどから修正したいことがあったので、
Ctrl-v で エディタでのファイル編集を呼び出しています。私の場合はnvimになります。

付属としてgit rm/mvを用意していますが、おらくgit statusする前にコマンド打ちたくなりそうかな思われます。

まとめ

fzfのpreviewは他の人のブログを確認すると有効に利用している人を多々見かけます。 すべてをCLIで収めるのは難しかと思いますが、極力CLIで済ませることができそうです。

特にbindはブログに記載している人を見かけてなかったので これを見て利用してくれる方が出てくれば嬉しい限りです。