【PHP】pre/post-install-cmdはcomposer.lockが無いと動かない

記事内に広告が含まれていることがあります。

pre/post-install-cmdはcomposerで使用できる便利なイベントで、composer installした時に自動で実行することが可能。

そのためGitHubでリポジトリを共有してチーム開発する場合、初期に行いたいセットアップを含めておけば自動的に環境構築が行なえます。

今回GitHooksを利用して無駄なコミットを防ぐためのシェルスクリプトを書いたのでチームでcomposer install時に使えるようにと色々調べていたら、composer.lockファイルが無いとpre/post-install-cmdが動かないことが分かったのでメモしておきます。

  • このケースではcomposer updateでpre/post-update-cmdを使用する
  • pre/post-autoload-dumpを使用してもOK
  • composer installはcomposer.lockからパッケージをインストールするコマンド
  • composer updateはcomposer.jsonからパッケージをインストールするコマンド
スポンサーリンク
スポンサーリンク

新規プロジェクトでまだcomposer.lockが無い場合

まず前提として、このケースは「新規のプロジェクトを作成している段階でまだcomposer.lockファイルが生成されていない」という場合に限ります。

例えば既にプロジェクトがあり、GitHub等でcomposer.jsonと共にcomposer.lockが含まれている場合は再現されません。

「composer.lockファイルが無い」という点がキーになります。

JavaScriptで使うnpmやyarnの場合、外部ライブラリを使うケースが非常に多いです。

特にReactでの開発がデファクトスタンダードになっている今、バニラJSだけで開発を進めるケースのほうがレアですよね。

反面PHPは特にWordPress周りの場合、ほとんど外部ライブラリを使うことがありません。

僕も後述するPHP CodeSnifferやWordPressのコーディング規約、PHP Compatibilityぐらいしか使わないのでcomposer.jsonは毎回コピペして一気にcomposer installしている状況です。

期待する動作

例えば以下のようなcomposer.jsonを用意します。

{
    "require-dev": {
        "squizlabs/php_codesniffer": "*",
        "wp-coding-standards/wpcs": "*",
        "phpcompatibility/php-compatibility": "*"
    },
    "scripts": {
        "post-install-cmd": [
            "echo test message"
        ]
    }
}

require-devにいくつかパッケージを指定しており、scriptsにpost-install-cmdとしてechoコマンドを仕込んでいます。

当然「test message」がcomposerのパッケージインストール終了後に出力される事を期待しています。

しかし実際には以下のようなログが表示されます。

% composer install           
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 3 installs, 0 updates, 0 removals
  - Locking phpcompatibility/php-compatibility (9.3.5)
  - Locking squizlabs/php_codesniffer (3.6.0)
  - Locking wp-coding-standards/wpcs (2.3.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
  - Installing squizlabs/php_codesniffer (3.6.0): Extracting archive
  - Installing phpcompatibility/php-compatibility (9.3.5): Extracting archive
  - Installing wp-coding-standards/wpcs (2.3.0): Extracting archive
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files

どこにも「test message」が出力されていません。

pre/post-install-cmdをcomposer installで実行する対策

不審に思って既にパッケージは入っていますが、再度composer installを叩いてみました。

% composer install
> echo test message
test message
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files

なんと、出力されていますね・・・!

ここで次の仮説が立てられます。

  1. 初回のcomposer installでは実行されない
  2. vendorディレクトリが無いから実行されない
  3. composer.lockファイルが無いから実行されない
  4. 2と3両方

そこでとりあえず手っ取り早く、vendorディレクトリを削除して再度composer installを叩いてみました。

% rm -rf vendor
% composer install
> echo test message
test message
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 3 installs, 0 updates, 0 removals
  - Installing squizlabs/php_codesniffer (3.6.0): Extracting archive
  - Installing phpcompatibility/php-compatibility (9.3.5): Extracting archive
  - Installing wp-coding-standards/wpcs (2.3.0): Extracting archive
Generating autoload files

出力されていますね。

次はvendorディレクトリを残したまま、composer.lockファイルを削除して試してみます。

% rm composer.lock 
% composer install
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 3 installs, 0 updates, 0 removals
  - Locking phpcompatibility/php-compatibility (9.3.5)
  - Locking squizlabs/php_codesniffer (3.6.0)
  - Locking wp-coding-standards/wpcs (2.3.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files

出力されていません。

つまりcomposer.lockファイルが無いとpre/post-install-cmdは動かないということになります。

composerのパッケージインストール系のコマンドおさらい

ここで改めてcomposerコマンドを整理してみます、結論から言えばそもそも僕の使用方法が間違っていました。

composerのインストール関連コマンド

composerにはインストールに関連するコマンドが全部で3つあります。

composer install

今回使用したコマンドがこのcomposer installですが、このコマンドはcomposer.lockからパッケージをインストールするコマンドです。

つまりそもそもcomposer.lockが存在している前提で使用すべきコマンドです。

composer require

新規にパッケージをインストールするコマンドで、npm installのような役割のコマンドです。

なにかパッケージをCLIからインストールする場合はcomposer requireを使うと覚えておけばOK。

composer update

composer updateはcomposer.jsonを元にパッケージをインストールするコマンドです。

つまり今回のような「新規プロジェクトを作成し、最初にcomposer.jsonに記述したパッケージをインストールする=composer.lockがまだ無い」というような場合はこのコマンドを使うのが正しいようです。

composer.jsonを元にcomposer.lockを生成する正しい手順なので、pre/post-install-cmdをpre/post-update-cmdに切り替えればきちんと動作します。

composer updateでpre/post-update-cmdを試す

それでは実際にcomposer updateコマンドで想定したように動くか確認してみます。

composer.jsonは以下のように修正しました。

{
    "require-dev": {
        "squizlabs/php_codesniffer": "*",
        "wp-coding-standards/wpcs": "*",
        "phpcompatibility/php-compatibility": "*"
    },
    "scripts": {
        "post-update-cmd": [
            "echo test message"
        ]
    }
}

8行目をpost-update-cmdに編集してあります。

# composer.lockとvendorディレクトリが無いことを確認
% ls -la
total 16
drwxr-xr-x@  5 braveryk7  staff  160 10 10 13:38 .
drwxr-xr-x@ 16 braveryk7  staff  512 10 10 13:33 ..
drwxr-xr-x@  9 braveryk7  staff  288 10 10 05:33 .git
-rw-r--r--   1 braveryk7  staff   22 10  9 23:36 .gitignore
-rw-r--r--   1 braveryk7  staff  393 10 10 15:14 composer.json

# composer update実行
% composer update
Loading composer repositories with package information
Updating dependencies
Lock file operations: 3 installs, 0 updates, 0 removals
  - Locking phpcompatibility/php-compatibility (9.3.3)
  - Locking squizlabs/php_codesniffer (3.6.0)
  - Locking wp-coding-standards/wpcs (2.3.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
  - Installing squizlabs/php_codesniffer (3.6.0): Extracting archive
  - Installing phpcompatibility/php-compatibility (9.3.3): Extracting archive
  - Installing wp-coding-standards/wpcs (2.3.0): Extracting archive
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
> echo test message
test message

# composer.lockとvendorディレクトリが正常に生成されている
braveryk7@braveryk7s-MacBook-Pro ghtest % ls -la 
total 32
drwxr-xr-x@  7 braveryk7  staff   224 10 10 16:27 .
drwxr-xr-x@ 16 braveryk7  staff   512 10 10 13:33 ..
drwxr-xr-x@  9 braveryk7  staff   288 10 10 05:33 .git
-rw-r--r--   1 braveryk7  staff    22 10  9 23:36 .gitignore
-rw-r--r--   1 braveryk7  staff   393 10 10 15:14 composer.json
-rw-r--r--   1 braveryk7  staff  7586 10 10 16:27 composer.lock
drwxr-xr-x   8 braveryk7  staff   256 10 10 16:27 vendor

ばっちり想定したようにcomposer.lockファイルとvendorディレクトリが生成され、test messageが表示されていますね!

npmと同じように「installで大丈夫でしょ」と思って曖昧に使ってしまっていんたんですが、composerコマンドは以下のように使い分けると良さそうです。

composer updatecomposer.lockファイルが存在しない時
composer installcomposer.lockファイルが存在する時(GitHubからcloneしてきた等)
composer require新しくパッケージをインストールしたい時

公式リファレンスにも各種イベントについて記載がある

ここまで書いておいてアレですが、実は公式ドキュメント「Scripts – Composer」に各種イベントについて記述があります。

pre-install-cmd: occurs before the install command is executed with a lock file present.

post-install-cmd: occurs after the install command has been executed with a lock file present.

pre-update-cmd: occurs before the update command is executed, or before the install command is executed without a lock file present.

post-update-cmd: occurs after the update command has been executed, or after the install command has been executed without a lock file present.

https://getcomposer.org/doc/articles/scripts.md#command-events

これを見る限り、composer installコマンドを叩いた時にcoposer.lockファイルが無い場合はcomposer updateが実行されるようです(composer.lockがない場合、実質的にcomposer updateのエイリアスになっている)

試してみましょう。

composer.jsonは先程と同じようにpost-update-cmdを記述しています。

# composer.lockとvendorディレクトリが無いことを確認
% ls -la
total 16
drwxr-xr-x@  5 braveryk7  staff  160 10 10 17:42 .
drwxr-xr-x@ 16 braveryk7  staff  512 10 10 13:33 ..
drwxr-xr-x@  9 braveryk7  staff  288 10 10 05:33 .git
-rw-r--r--   1 braveryk7  staff   22 10  9 23:36 .gitignore
-rw-r--r--   1 braveryk7  staff  389 10 10 17:40 composer.json

# composer.lockが無い状態でpost-update-cmdを記述してcomposer installを実行
% composer install
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 3 installs, 0 updates, 0 removals
  - Locking phpcompatibility/php-compatibility (9.3.5)
  - Locking squizlabs/php_codesniffer (3.6.0)
  - Locking wp-coding-standards/wpcs (2.3.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
  - Installing squizlabs/php_codesniffer (3.6.0): Extracting archive
  - Installing phpcompatibility/php-compatibility (9.3.5): Extracting archive
  - Installing wp-coding-standards/wpcs (2.3.0): Extracting archive
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
> echo test message
test message

なんと、composer installを叩いたらpost-update-cmdが実行されました。

という事でやはりcomposer installはcomposer.lockファイルが存在しない場合composer updateを実行するということは間違いなさそうです。

つまりcomposer.lockファイルがない場合、pre/post-install-cmdが実行されないのはcomposer updateコマンドが実行されているからでしょう。

composerのpre/post-install or update-cmdのベストプラティクス

ここまで見てきたように、基本的には新規プロジェクトを作成する時に同時にコマンド一発で色々処理を走らせたい場合はpre/post-update-cmdを指定するのが良さそうです。

ただし先述したように既存のプロジェクトのリポジトリをクローンして環境再現をする場合はcomposer.lockが存在すると思うので、この場合composer installを使うことになり当然pre/post-install-cmdが実行されます。

どちらの場合も実行したい場合には冗長ではありますが、pre/post-install-cmdとpre/post-update-cmdどちらも指定しておくのが一番でしょうか・・・。

pre/post-autoload-dumpを指定する

少しハック的ですが、composer installまたはcomposer update時には必ずcomposer dump-autoloadが実行されます。

それを利用して、composer dump-autoloadのイベントであるpre/post-autoload-dumpを指定するのも一つの手です。

{
    "require-dev": {
        "squizlabs/php_codesniffer": "*",
        "wp-coding-standards/wpcs": "*",
        "phpcompatibility/php-compatibility": "*"
    },
    "scripts": {
        "post-autoload-dump": [
            "echo test message"
        ]
    }
}

これでcomposer update時も動きますし、composer.lockが無い時のcomposer install時も動きます。

【PHP】pre/post-install-cmdはcomposer.lockが無いと動かない まとめ

色んなサイトで情報を集めましたが、「最初はとりあえずcomposer installをする」のような書かれ方をすることが多く誤った認識でとりあえず使っている方が多いかも知れません、事実僕もそうでした笑。

しかし実際にはcomposer.lockファイルが存在しない場合、composer installコマンドを叩いて実際に実行されるコマンドはcomposer updateでした。

composerはPHPを使った開発に無くてはならない便利なパッケージ管理が行えますが、しっかり理解して使うと更に便利に使えるのでこの辺の知識はぜひ覚えておきたいですね!

スポンサーリンク
Web
スポンサーリンク
\この記事いいね!と思ったらシェアしてね/
スポンサーリンク
L'7 Records

コメント

タイトルとURLをコピーしました