猫でもわかるWebプログラミングと副業

本業エンジニアリングマネージャー。副業Webエンジニア。Web開発のヒントや、副業、日常生活のことを書きます。

PHP の composer で remove する時にパッケージの依存関係も含めて remove したい

f:id:yoshiki_utakata:20181004212834j:plain

状況

  • composer.json に直接記述されているライブラリAがある。
  • ライブラリAが依存しているライブラリBがある。
  • ライブラリBが依存しているライブラリCがある。

このような状況の場合、 composer update すると、composer.lock にライブラリA, ライブラリB, ライブラリCが記述される。以後、 composer install するとこの3つのライブラリがinstallされる。

ライブラリAを使わなくなったので composer remove ライブラリA した結果、 composer.json からライブラリAは消えたが、 composer.lock ではライブラリB, ライブラリCが消えない。結果、 composer install すると、使われていないのにライブラリBとライブラリCがインストールされてしまう。どうはってこれらを composer.lock から消したらいいか。

composer remove --update-with-dependencies でもだめだった

composer remove ライブラリA --update-with-dependencies というコマンドがある。これを行うと、ライブラリAが依存していたライブラリにupdateがかかる。つまり、ライブラリBにupdateがかかり、もしライブラリBがどこでも使われていなかったら削除される筈なのだが...なぜか削除されない時がありました。

そもそも、 --update-with-depandencies は composer 1.0.0-beta2 から deprecated になっており、普通に `composer remove今回のように依存性をうまく解決できないことが多かったのかもしれない。

一番確実なのは composer.lock を作り直すことだが...

一番確実なのは、 composer.lock を消したうえで、 composer update することだ。これにより composer.lock 内に記述されている依存関係が綺麗になるので、ライブラリBとライブラリCは綺麗に消える。

ただ、バージョンが固定されておらず composer.lock を簡単に消せないことも

ただし、そう簡単に composer.lock を作り直すわけに行かない場合もあります。 composer.json でしっかりバージョンが固定されていればよいのですが、必ずしもそうとは限らないからです。例えば以下のような記述があるとします。

"myclabs/php-enum": "dev-master",
"guzzlehttp/guzzle": "~6.0"

こういった記述がされている場合、composer.lockを生成し直すと、php-enum は、新しいcomposer.lockを生成したときの最新のmasterのバージョンに変わってしまいますし、guzzleも5.x系のマイナーバージョンアップがされているとバージョンが変わってしまいます。

バージョンが変わってほしくないライブラリのバージョンが上がってしまうことにより、不具合が出現する可能性もあります。さらに、複数ライブラリのバージョンが上がってしまうとどれが原因で不具合が出たのかが不明になります。

ではどうすればいいのか

ではどうすればいいのか。結局は composer.lockを直接んで依存性を解決する しかありませんでした。

composer.lock を読む

composer.lock ですが、これも結局jsonですので読めないことはないです。記述についても、 composer.json に依存関係情報が追加されただけです。

  • ライブラリAがライブラリBに依存している
  • ライブラリBがライブラリCに依存している

という状況である今回、 composer.json にはライブラリAの名前が書いてあるだけです。composer.lockには以下の情報がかかれています。

  • ライブラリAが依存しているライブラリの名前とバージョン
  • ライブラリBが依存しているライブラリの名前とバージョン
  • ライブラリCが依存しているライブラリの名前とバージョン

記述が増えただけで書いてある内容は同じなので、頑張れば「どのライブラリからも使われていないライブラリ」を求めることができるのです。

どうやってそのライブラリをcomposer.lockから消すのか

では、ライブラリAを消したとします。 composer.lock を読むことで、ライブラリBが不要なことがわかりました。どうやって composer.lock からライブラリBの記述を消したらいいでしょう。もちろん直接 composer.lock を書き換えてもよいのですが、以下のコマンドで消すことができます。

composer update ライブラリB

このコマンドを叩くと、ライブラリBが使われていないことがわかった場合には、ライブラリBの情報を composer.lock から消してくれます。

具体的にやってみる

今回僕が遭遇した状況は以下のような状況でした。

  • jenssegers/agent というライブラリがあるのですが、これが今回不要になりました。*1
  • この jenssegers/agent ですが、 illuminate/support というライブラリに依存しています。
  • さらに illuminate/supportparagonie/random_compat というライブラリに依存しています。

このような場合は以下のようになります。

# jessegers/agent を削除
$ composer remove jenssegers/agent
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 0 updates, 2 removals
  - Removing jenssegers/agent (v2.3.3)
  - Removing mobiledetect/mobiledetectlib (2.8.22)
Writing lock file
Generating autoload files

# 依存しているが何故か消えないライブラリを消す

$ composer update illuminate/support
Package "illuminate/support" listed for update is not installed. Ignoring.
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 0 updates, 1 removal
  - Removing illuminate/support (dev-master c2f8d83)
Writing lock file
Generating autoload files

$ composer update paragonie/random_compat
Package "paragonie/random_compat" listed for update is not installed. Ignoring.
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 0 updates, 1 removal
  - Removing paragonie/random_compat (v1.x-dev 1115ffa)
Writing lock file
Generating autoload files

まとめ

  • composer remove XXXX で不要なパッケージを消すことができるが、稀に composer.lock から依存がうまく消えないことがある。
  • composer.lock を再生成すれば依存関係は綺麗になるが、 composer.json でバージョンをちゃんと固定していないと辛い
  • 結局 composer.lock を読んで頑張って解決した...