モヒカンメモ

髪色が定期的に変わることに定評のある(比較的)若者Webエンジニアの備忘録

Scalaで使えそうなメールライブラリの調査

Scalaでメール送りたくなってメールライブラリを探したのでまとめておく。

2019年になぜメールか

アプリのプッシュ通知やLINE@などの通知手段が普及した2019年でも、保存性やエビデンス、長文の書きやすさ、所有の証明といったの観点でメールという手段も無視出来ない。

探し方

以前テンプレートエンジンを探したときと観点は同じ。

blog.pinkumohikan.com

githubでそれっぽいキーワードで探して、

  • そこそこstarがついている (= みんなに使われている)
  • 定期的に新バージョンがリリースされている
  • contributorが一人じゃない

辺りの観点で、良さげなやつを見つける。

見つけたもの

ScalaにはEmail系のAPIは用意されてないっぽいので、Java用のライブラリを使う感じになる。軽く探して見つかったのは Apache Commons EmailSimple Java Mail の2つ。どちらもJava Mail APIのwrapperで、低レイヤー特有の難しい表現が減っていて使いやすそう。

1. Apache Commons Email

github.com

commons.apache.org

こんな感じに使うっぽい

val email = new SimpleEmail();
email.setHostName("smtp.googlemail.com");
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator("username", "password"));
email.setSSLOnConnect(true);
email.setFrom("user@gmail.com");
email.setSubject("TestMail");
email.setMsg("This is a test mail ... :-)");
email.addTo("foo@bar.com");
email.send();

Java感が強いな

特徴

  • HTML, TEXTメール両方対応
  • Apacheが出してるので安心感がある
  • Simple Java Mailよりもcontributor多い
  • SimpleEmailオブジェクトに送信設定とかメールそのものをガバっと持たせるスタイル
  • Apache-2.0ライセンス

2. Simple Java Mail

github.com

www.simplejavamail.org

こんな感じに使うっぽい

val email = EmailBuilder.startingBlank()
          .to("lollypop", "lolly.pop@somemail.com")
          .withSubject("hey")
          .withPlainText("Please view this email in a modern email client!")
          .buildEmail();

val mailer = MailerBuilder
          .withSMTPServer("smtp.host.com", 587, "user@host.com", "password")
          .withTransportStrategy(TransportStrategy.SMTP_TLS)
          .buildMailer();

mailer.sendMail(email);

特徴

  • HTML, TEXTメール両方対応
  • Apache Commons EmailよりもStarが多い
  • ドキュメントが読みやすい印象
  • MailerとEmailオブジェクトで別れていて、MailerへEmailを渡すスタイル
  • Apache-2.0ライセンス

個人的には、送信関連の設定はMailerに、emailそのものの関心はEmailに持たせるという関心の分離が出来ているSimple Java Mailのほうが好み。

自宅からメールが送れない?それOP25Bのせいかも

メールを送るシステムを開発していて、会社のネットワークからはメールが送れるのに、自宅やポケットWiFiからだとメールが送れないことがあります。例えば、メールを送ろうとすると No route to hostDestination host unreachable Request timed out が起きる場合です。

実は多くのISPでは野良メール送信を制限するために外向きのTCP 25番を閉じています。このせいで、自宅PCから会社メールサーバを使ってメールを送ろうとしたり、自前メールサーバからのメールが送れなかったりします。

OP25B (Outbound Port 25 Blocking)

電子メールは技術的にはTCP 25番で相手先のメールサーバにSMTPでお話すると誰でも送ることができます。2010年頃、メールの添付ファイルで感染するウイルスが大流行したり、SPAMメールの社会問題化がきっかけでOP25Bが始まりました。

www.so-net.ne.jp

ISPからしてみれば

  • TCP 25番を閉じることで、ユーザ端末から直でSPAMメールやウイルスメールを送られることを防げる
  • 別ポートでメール送信用サーバを用意してユーザに使わせれば、これまで通りメールサービスは提供できる

わけですね。

一見、「ISPを経由すればSPAM送れるから一緒じゃね?」って思いそうですが、ISPのメールサーバに記録が残るので通報があった際に追跡しやすいし、メールサーバにウイルス対策ソフトを入れることで早期にウイルス感染を検出して直接ユーザに連絡を入れること可能になるので大きな違いなわけです。

どうすればメールが送れるか?

利用するメールサーバがサブミッションポート (TCP 587番) を提供している場合

メール送信時のメールサーバのポートをTCP 25番の代わりにTCP 587番を使う設定にすると、メールを送れるようになります。

$ git diff
diff --git a/.env.default b/.env.default
index e08cad1..f5d901a 100644
--- a/.env.default
+++ b/.env.default
@@ -1,2 +1,2 @@
 MAIL_HOST=mail.pinkumohikan.om
-MAIL_PORT=25
+MAIL_PORT=587

利用するメールサーバがサブミッションポート (TCP 587番) を提供していない場合

端的に、そのメールサーバを使ってメールを送ることはできません。

僕はだいたいそういう場合、Gmailアカウントを取得してGmailの提供しているメールサーバ (Gmail SMTP サーバー) を使ったりします。そもそもTCP 25番を提供していないというのがトラップを未然に防いでいてポイント高い。

support.google.com

ちなみに、ご存知の通りGoogleはセキュリティに厳しいのでVPSとかからメール送ろうとすると不審なリクエストと見なされてrejectされることもよくある。送信数の制限も厳しいので、本番用途では使わないこと。

自前メールサーバを使いたい場合

OP25Bの影響で相手先メールサーバとの直接通信ができないので、ISPの提供するメールサーバなどに代理でメールを送ってもらう必要があります。

自宅メールサーバ -> (TCP 25番) -> 相手先メールサーバ

という感じの構図から、

自宅メールサーバ -> (TCP 587番) -> ISPメールサーバ -> (TCP 25番) -> 相手先メールサーバ

という構図になるイメージです。

詳細な設定方法は割愛しますが、postfixだったら relayhost あたりの設定がキーワードです。

MySQLに投げられたすべてのSQLクエリをロギングする

概要

クエリビルダやORMが生成するクエリを確認したいなどの理由で、MySQLに投げられたクエリを確認したくなることがある

そういうときは、MySQLのクエリログ (general_log) と言う設定をONにすることによって、すべてのクエリをログに吐かせることができる

dev.mysql.com

5.2.3 一般クエリーログ 一般クエリーログは、mysqld の実行内容の一般的な記録です。サーバーは、クライアントが接続または接続解除したときに情報をこのログに書き込み、クライアントから受け取った各 SQL ステートメントをログに記録します。一般クエリーログは、クライアント側でエラーが疑われるとき、クライアントが mysqld に送信した内容を正確に知りたい場合に非常に役立つことがあります。

やってみる

1. 現在の設定を確認する

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.16    |
+-----------+
1 row in set (0.00 sec)

mysql> show variables like 'general_log%';
+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log      | OFF                             |
| general_log_file | /var/lib/mysql/3a9a8fa16e7a.log |
+------------------+---------------------------------+
2 rows in set (0.00 sec)

デフォルトではOFFになっている。この状態で クエリが投げられてもロギングされない

root@3a9a8fa16e7a:/# ls -alh /var/lib/mysql/3a9a8fa16e7a.log
ls: cannot access '/var/lib/mysql/3a9a8fa16e7a.log': No such file or directory

2. ONにしてみる

mysql> set global general_log = on;
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation

このユーザには権限がなかったので、グローバル設定を書き換える権限のあるユーザでログインしなおして再チャレンジ

mysql> set global general_log = on;
Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'general_log%';
+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log      | ON                              |
| general_log_file | /var/lib/mysql/3a9a8fa16e7a.log |
+------------------+---------------------------------+
2 rows in set (0.01 sec)

クエリログの設定をONにしたところ即座にログファイルが作られた

root@3a9a8fa16e7a:/# ls -alh /var/lib/mysql/3a9a8fa16e7a.log
-rw-r----- 1 root root 256  5月 25 17:17 /var/lib/mysql/3a9a8fa16e7a.log

3. ロギングされるか確かめる

適当にクエリを投げてみる

mysql> select 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.01 sec)
root@3a9a8fa16e7a:/# tail /var/lib/mysql/3a9a8fa16e7a.log
/usr/sbin/mysqld, Version: 8.0.16 (MySQL Community Server - GPL). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
2019-05-25T08:17:19.278525Z    26 Query show variables like 'general_log%'
2019-05-25T08:18:11.802232Z    25 Query select 1

投げたクエリはちゃんとログファイルに書かれていた🎉

補足 (1)

本番環境でクエリログを取る場合、下記に注意すること

  • ログのぶんだけディスクを食うし、ディスクI/Oが増えるぶんパフォーマンスも劣化する
  • 機微情報を扱うクエリが投げられる場合、ログにも機微情報が乗るのでログファイルは慎重に扱う

補足 (2)

デフォルトではgeneral logはファイルに吐き出されるが、 log_output という変数を変更することで吐き出し先をテーブルに変更することもできる

mysql> set global log_output = "table";

log_output

"[skip ci]" とコミットメッセージに書くと、CIをスキップできる

TravisCIやCircleCIを使ってCI/CDするのはだいぶメジャーになりましたね。

ドキュメントのみの更新時やwipのときなど、「git commitはしておきたいけどCIは走らせなくて良いだよな〜」というときありますよね。

そういうとき [skip ci] とコミットメッセージに含めておくとCIをskip出来て便利です。他にもいくつかバリエーションが有るので、手に馴染むものを使えば良さそう。

参考資料

TravisCI

docs.travis-ci.com

If you don’t want to run a build for a particular commit for any reason, you may instruct Travis CI to skip building this commit via a command in the commit message.

The command should be one of the following forms:

[ skip]

or

[skip ]

where is either ci, travis, travis ci, travis-ci, or travisci. For example,

[skip travis] Update README

CircleCI

circleci.com

By default, CircleCI automatically builds a project whenever you push changes to a version control system (VCS). You can override this behavior by adding a [ci skip] or [skip ci] tag anywhere in a commit’s title or description.

ゆるゆる無限LTというクレイジーイベントへ参加してLT3本やってきた

自分もワイワイしている若者ものづくりコミュニティ Oysters主催、ゆるゆる無限LTというクレイジーイベントへ参加した。

oysters.connpass.com

会場はウィルゲートさん提供。サンクス!

f:id:pinkumohikan:20190513195525j:plain
雰囲気

無限LTとwはwww

他の人の LT を聞きながら、LT の資料を作る。 それを繰り返すことで、1日にたくさん LT の経験をしようという会です。

一言で言うと、LT中毒者の集いですね(雑)

話したこと

自己紹介てきなやつ

  • 我はpinkumohikanだぞ!崇めよ
  • サバゲと、ボウリングと、仮想通貨自動売買はいいぞ!

たくさんメール送るのは大変だぞ

  • まだまだ伝達手段としてメールは無視出来ないぞ
    • 長文送りたいとかエビデンスの観点ではまだ代わりは無い
  • 何も考えずにたくさんメール送ったら、全然届かないぞ (スパムフィルタ)
    • 送信者認証、IP/ドメインレピュテーション、etc...
  • おとなしくSendGridとかSESとかのSaaS使うのがよし
    • SDK使えばOP25Bとかの制約も受けないし!
  • Google Postmaster Toolが便利
    • 迷惑メール通報率や、IP/ドメインレピュテーションの確認ができる

ちゃんとサードパーティ製パッケージのバージョンアップやるんだぞ

f:id:pinkumohikan:20190513195026j:plain
オーディエンスを煽る我

スライドはテンション上がったら上げます(あげないやつ)

もっと様子が気になるぞ?

さとだいさんが写真取ってくれたので見るべし

あとは、タグを追うべし

twitter.com

感想

真面目なネタから、技術ネタ、大根おろしの辛さの研究みたいなぶっ飛んでるネタまで聞けてたのしかった(小学生並みの感想)

MySQL8をバージョンアップしたら起動しなくなった

背景

  • 個人プロダクト用にMySQL8を運用していて定期的にバージョンアップを行っている
  • 8.0.14 から 8.0.16 にマイナーバージョンアップしたところMySQLが起動しなくなった 💀

f:id:pinkumohikan:20190502141209p:plain

調査と対応

おもむろにstartしてみる

$ sudo systemctl start mysql
Job for mysql.service failed because the control process exited with error code.
See "systemctl status mysql.service" and "journalctl -xe" for details.

ですよね〜〜〜

素直にprocessのログを見る

$ sudo journalctl -xe
...
Apr 26 00:39:17 $hostname sudo[5013]: $username : TTY=pts/0 ; PWD=/home/$username ; USER=root ; COMMAND=/bin/systemctl start mysql
Apr 26 00:39:17 $hostname sudo[5013]: pam_unix(sudo:session): session opened for user root by $username(uid=0)
Apr 26 00:39:17 $hostname systemd[1]: Starting MySQL Community Server...
-- Subject: Unit mysql.service has begun start-up
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
--
-- Unit mysql.service has begun starting up.
Apr 26 00:39:17 $hostname audit[5067]: AVC apparmor="STATUS" operation="profile_replace" info="same as current profile, skipping" profile="unconfined" name="/usr/sbin/mysqld" pid=5067 comm="apparmor_parser"
Apr 26 00:39:17 $hostname kernel: audit: type=1400 audit(1556206757.959:27): apparmor="STATUS" operation="profile_replace" info="same as current profile, skipping" profile="unconfined" name="/usr/sbin/mysqld" pid=5067 comm="a
Apr 26 00:39:19 $hostname trace-agent[945]: 2019-04-26 00:39:19 JST | TRACE | INFO | (pkg/trace/agent/service.go:63 in Run) | total number of tracked services: 0
Apr 26 00:39:23 $hostname systemd[1]: mysql.service: Main process exited, code=exited, status=1/FAILURE
Apr 26 00:39:23 $hostname systemd[1]: mysql.service: Failed with result 'exit-code'.
Apr 26 00:39:23 $hostname sudo[5013]: pam_unix(sudo:session): session closed for user root
Apr 26 00:39:23 $hostname systemd[1]: Failed to start MySQL Community Server.
-- Subject: Unit mysql.service has failed
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
--
-- Unit mysql.service has failed.
--
-- The result is RESULT.
...

うーん、何も分からない(キレ気味)

MySQLのログを見る

$ sudo less /var/log/mysql/error.log
...
2019-04-25T15:41:12.267479Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.16) starting as process 6246
2019-04-25T15:41:13.263343Z 4 [System] [MY-013381] [Server] Server upgrade from '80015' to '80016' started.
2019-04-25T15:41:15.448593Z 4 [ERROR] [MY-013384] [Server] Could not create server upgrade info file at '/var/lib/mysql/'.
2019-04-25T15:41:15.454470Z 0 [ERROR] [MY-013380] [Server] Failed to upgrade server.
2019-04-25T15:41:15.455397Z 0 [ERROR] [MY-010119] [Server] Aborting
2019-04-25T15:41:17.137374Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.16)  MySQL Community Server - GPL.

Could not create server upgrade info file at '/var/lib/mysql/'.

このあたりが怪しそう

おもむろにlsしてみる

$ ls -alh /var/lib/mysql/
...
drwxr-x---  2 mysql mysql 4.0K Apr 26 00:41  mysql
-rw-r-----  1 mysql mysql  56M Apr 26 00:41  mysql.ibd
-rw-r--r--  1 root  root     6 Apr 13 00:08  mysql_upgrade_info
drwxr-x---  2 mysql mysql 4.0K Apr 26 00:28  performance_schema
-rw-------  1 mysql mysql 1.7K Sep 30  2018  private_key.pem
...

一個だけroot所有なファイルが有るぞ...!?

mysql_upgrade_infoは本来rootじゃなくてmysql所有であるべきものっぽいので、所有者をmysqlに変えたら直るんじゃね?

$ sudo chown mysql:mysql mysql_upgrade_info
$ sudo systemctl start mysql
$ sudo systemctl status mysql
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2019-04-26 00:51:50 JST; 3s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 11526 ExecStartPre=/usr/share/mysql-8.0/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 11578 (mysqld)
   Status: "SERVER_OPERATING"
    Tasks: 38 (limit: 1110)
   CGroup: /system.slice/mysql.service
           └─11578 /usr/sbin/mysqld

おかえり

MySQLのログを見ても、バージョンアップ成功してそう

$ sudo less /var/log/mysql/error.log
...
2019-04-25T15:51:39.763174Z 4 [System] [MY-013381] [Server] Server upgrade from '80015' to '80016' started.
2019-04-25T15:51:42.308523Z 4 [System] [MY-013381] [Server] Server upgrade from '80015' to '80016' completed.
...

なぜ mysql_upgrade_info がroot所有になっちゃったのかは謎だけど、原因が2週間前の操作によるものである可能性が高くてもう追えないし、ログを順に辿っていけば解決出来る問題だったのでひとまずこれにて。

Scalaで使うテンプレートエンジンの検討 (Scalate、Twirl、Beard)

Scalaでテンプレートエンジン使いたくなったので調べた。

www.scala-lang.org

探し方

GitHubでホスティングされているホットなものを探す。

github.com

こういうのを探すときは、

  • そこそこstarがついている (= みんなに使われている)
  • 定期的に新バージョンがリリースされている
  • contributorが一人じゃない

辺りを確認しておくのがオススメ。 そうしておけば、突然ライブラリが消滅したり、時代に取り残されて渋々他のライブラリへの移行を余儀なくされる、みたいな悲しいことを回避出来る確率が上がる。

見つけたもの

探し方 で触れた観点を持って良さげだなと思ったは次の3つ。

1. Scalate

github.com

Mustache、Jade、Scaml、SSPと複数の表記方法をサポートしている。 テンプレートエンジンって「こういう風にかけ!」と表記方法をビシッと指定されているものしか使ったことがなかったが、複数の表記方法から手に馴染むものを選べるのは嬉しいんじゃないだろうか。

とは言えいくつかはHTML特化の表記方法なので「メール本文とかPush通知の文面とかもテンプレート管理したいんじゃー」という場合は、選択肢としてはMustacheかSSP表記のいずれかになる。オススメはSSPで、テンプレート変数が未定義だった場合にはランタイムで怒ってくれる。Mustacheはしれっとブランクになってしまうのでそれに気づかず事故りやすそう。

2. Twirl

github.com

有名な モリモリ フルスタック系フレームワークplayのテンプレートエンジン。 SBT Pluginとして追加する感じで、templateをコンパイルしてくれるのでテンプレート変数の過不足が無くなるのが良い。 テンプレート変数が未定義だった場合に Scalate * SSP だとランタイムで気付けるが、Twirlだとコンパイル時点で気づける。

機能的は良いんだけど、コンパイルオプションで fatal-warningswarn-unused-import を有効にしていると、 TwirlKeys.templateImports := Nil を設定するハックをしないと unused import で怒られて使えないのが難点。

github.com

3. Beard

github.com

ScalateとTwirlに比べるとstarが少ないが、表記方法はMustacheベースで手に馴染みやすい印象。 Last releaseが2016/4で、2019/4/5現在新し目なIssueも無いのでメンテは活発では無さそうな感はある。

その他

今回はJava用のテンプレートエンジンは探してないけど、そっちも探せば他にも良さげなものはあるかも。

他にオススメあったら教えて下さい。

CircleCIでdockerを使うときはバージョン指定を忘れないこと

学び

CircleCI上でdockerを動かすとデフォルトではバージョン17.09っていう化石エンジンで動いてしまうので気をつけるべし。

背景

とあるOSSアプリ のCIをCircleCIでしようと思って悪戦苦闘していたら、こういうリプを貰った。

「そんなバナナw 今は2019年だぜJK?w」と思って確認したら、本当だったw

f:id:pinkumohikan:20190321233825p:plain

ログ: https://circleci.com/gh/pinkumohikan/sunfish/21

新しいdocker engineを使う

積極的に新しいバージョンを使っていきましょうね、ということで

circleci.com

を参考に、こんな感じでバージョンを指定する。

f:id:pinkumohikan:20190321234645p:plain

すると、指定したバージョンでdocker engineが動くことが確認できた。

f:id:pinkumohikan:20190321234722p:plain

ログ: https://circleci.com/gh/pinkumohikan/sunfish/24

めでたし、めでたし。

ちなみに

指定可能なdocker engineのバージョンはここから選べる。

download.docker.com

Docker for Macが路頭に迷わないようにたくさんメモリを食べられるようにする

こんにちは。

軽量でポータブルな開発&実行環境としてDockerが人気ですね。 僕は数年前までは開発環境にはもっぱらVagrantを使っていたのですが、最近は仕事でもプライベートでもDockerしか使ってないです。

f:id:pinkumohikan:20190209144001p:plain

Dockerは単純に捨てやすい開発環境という使い方もできるし、うまいこと作ると設定ファイルを差し替えたらすぐ本番で動かせるぞ、という使い方も出来ます。後者だと 12 factor appで言う 開発/本番一致 がしっかり出来て最高ですね。

さて、Dockerにはメモリ使用量の制限設定があり、それがネックになって開発中のプログラムの動きが鈍くなったり応答しなくなったことがあったので、誰かの役にたてばいいなと思ってメモリ使用量の増やし方をメモります。

1. Docker for Macへのメモリ使用量を確認する

まずは現状確認をしましょう。

Docker for MacのPreferencesを開きます。

f:id:pinkumohikan:20190209142106p:plain

f:id:pinkumohikan:20190209142123p:plain

次にAdvancedのタブを開き、Memoryの量を確認します。

f:id:pinkumohikan:20190209142158p:plain

メモリ使用量制限は2GBのようです。

2. 制限に引っかかっていることを確認する

プログラムの動きが鈍いのが本当にメモリ使用量制限のせいであるかを確認しましょう。

アクティビティモニタのメモリタブを開きます。

f:id:pinkumohikan:20190209142526p:plain

1.9Gぐらい使っているようですね。メモリ使用量制限の値が2GBだったので数字だけ見ると若干の余裕はありますが、瞬間的に引っかかって縮退した可能性が高そうです。

3. メモリ使用量制限の値を引き上げる

Docker for MacのPreferencesに戻って、2GBとなっていたところを引き上げます。いくらに引き上げるかは総メモリ量と他にどのぐらい同時作業するかによりますが、僕の場合はメモリ16GBマシンで同時に使うのはSlackとIntelliJぐらいなのでガツッと8GBにしました。

一度しか設定できないものではないので、これでもしほかが逼迫したら引き下げればいいよねぐらいの楽観です。

f:id:pinkumohikan:20190209142901p:plain

Apply & Restart を押して、dockerデーモンが上がってきたらdone。

4. プログラムがスムーズに動くようになったか確認する

すむーーーずになりました。

たまに起きていた動きがめちゃ遅になったり応答しなくなったりすることはなくなりました。やっぱりメモリやったんやな!

あとあと見たらdocker-composeでdb含む環境一式を立ち上げてバリバリ動いている状態だと4.7Gぐらいメモリ食ってたので、8GBっていう割り当ては妥当だった模様。

f:id:pinkumohikan:20190209143449p:plain

30日間brew cleanupしてなかったらbrew upgradeのついでに実行されるようになっていた

僕は仕事でもプライベートでも開発環境としてMacBookを使っているのですが、毎朝 brew upgrade コマンドを叩いています。今日は何が上がったかな?を確かめるのが日課です。これをせずにbrew installをした日にはたくさんのupgradeが走ってめちゃめちゃ待たされますからね・・・。

で、昨日おもむろに brew upgrade を叩いたら、やけに長いログが...。

$ brew upgrade
...
==> Upgrading 1 outdated package:
typescript 3.2.4 -> 3.3.1
==> Upgrading typescript
==> Downloading https://homebrew.bintray.com/bottles/typescript-3.3.1.high_sierr
######################################################################## 100.0%
==> Pouring typescript-3.3.1.high_sierra.bottle.tar.gz
🍺  /usr/local/Cellar/typescript/3.3.1: 86 files, 41.0MB
==> `brew cleanup` has not been run in 30 days, running now...
ずらずらずら.....

_人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人_

> brew cleanup has not been run in 30 days, running now... <

 ̄YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY^ ̄

どうやら、30日間brew cleanupしてなかったらbrew upgradeをトリガーに実行されるようになったらしい。

brewはinstallやupgradeするたびに以前のバージョンをキャッシュしておいてくれます。そのお蔭で「アッ、バージョンアップしたら動かない...!」というときにコマンド一つでバージョンを戻すことができます。

brew cleanup は、そのキャッシュを削除するコマンドです。ずっと前のバージョンを残していると使わない割にディスク食いますからね。

へーおもしろい変更だなと思って調べてみたら、この仕様になったのは brew v1.9.0 からっぽい。

github.com

このissueで自動的に brew cleanup を実行すべきでは?という議論がなされての結果らしい。

github.com

PRとしてはこれかな

github.com

HOMEBREW_NO_INSTALL_CLEANUPという環境変数でオプトアウトもできるらしい。