- Глобальная установка: генерация ссылок и запуск исполняемых файлов
- Что происходит при локальной установке
- Выводы
Многие пакеты — это приложения командной строки, еще их называют cli-утилитами. Пользователи по-разному взаимодействуют с ними: запускают команды, передают аргументы и опции, выводят результат. Все взаимодействие происходит интерактивным образом через терминал. Для запуска файлов из командной строки в Composer существует секция bin конфигурационного файла composer.json. Рассмотрим на примере:
"bin": ["bin/php-package"]
Эта запись означает, что при установке пакета в операционной системе будет создан файл с именем php-package. Это не просто файл, а символическая ссылка. Запуск этого файла-ссылки приведет к запуску файла вашего проекта по адресу bin/php-package.
Как можно заметить, имя ссылки задается именем файла и совпадает с ним. Также обратите внимание, что ссылок может быть множество — столько, сколько вы сами укажете в секции bin.
Месторасположение символической ссылки и способ ее запуска из командной строки различаются в зависимости от способа установки пакета:
- Локального
- Глобального с командой global— например,composer global vendor/package
Рассмотрим каждый случай отдельно.
Глобальная установка: генерация ссылок и запуск исполняемых файлов
При глобальной установке пакета Composer создает символические ссылки в каталоге $HOME/.composer/vendor/bin. Другими словами, при создании ссылок в домашнюю директорию пользователя, от имени которого запускалась установка пакета, будет добавлен каталог .composer/vendor/bin со ссылками. Это каталог по умолчанию, но путь к нему нам надо самостоятельно прописать в переменной окружения PATH. После этого мы можем запускать приложение по имени символической ссылки из командной строки, находясь в любой точке файловой системы. Так происходит, потому что при поиске исполняемых файлов командная оболочка ищет их последовательно по всем путям, прописанным в переменной окружения PATH.
В зависимости от версии Composer директория по умолчанию может различаться. Кроме того, это значение можно конфигурировать. Чтобы посмотреть, в какую конкретно директорию composer складывает ссылки на исполняемые файлы, можно воспользоваться командой composer global config bin-dir --absolute:
composer global config bin-dir --absolute
Changed current directory to /home/hex/.composer
/home/hex/.composer/vendor/bin
Посмотреть содержание переменной окружения PATH в вашей системе можно с помощью команды echo:
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/hex/.composer/vendor/bin/
Пример
Давайте создадим и опубликуем пакет, который для краткости и наглядности будет очень простым. Этот пакет будет состоять всего из двух исполняемых файлов, запуск которых выведет приветствие и прощание с Хекслетом.
Структура проекта:
ls -al
drwxrwxr-x 2 hex hex 4096 Jul  1 04:32 .
drwxrwxr-x 3 hex hex 4096 Jul  1 04:21 ..
-rw-rw-r-- 1 hex hex  225 Jul  1 04:31 composer.json
-rw-rw-r-- 1 hex hex    0 Jul  1 04:32 sayBye
-rw-rw-r-- 1 hex hex    0 Jul  1 04:32 sayHi
Содержимое исполняемого файла sayHi:
#!/usr/bin/env php
<?php
print_r("Hello, Hexlet!\n");
Содержимое исполняемого файла sayBye:
#!/usr/bin/env php
<?php
print_r("Bye-bye! See you later, Hexlet!\n");
Содержимое конфигурационного файла composer.json:
cat composer.json
{
    "name": "hex/small-talk-with-hexlet",
    "description": "Small talk with Hexlet",
    "keywords": ["hexlet", "php", "composer"],
    "license": "MIT",
    "bin": [
        "./sayHi",
        "./sayBye"
    ]
}
Обсудим исполняемые файлы немного подробнее:
- Чтобы запускать файлы из командной строки, пользователь должен иметь право на выполнение этого файла (атрибут x)
- Если исполняемый файл содержит код, то надо указать интерпретатор, который будет исполнять этот код при запуске исполняемого файла. Это делается с помощью шебанга. В примере выше мы указали php в качестве интерпретатора, а путь к нему задали с помощью специальной утилиты env. Мы решили не указывать абсолютный путь, потому что в разных системах php может находиться по совершенно разным путям
В итоге, мы подготовили пакет. После публикации он становится доступен для установки под именем hex/small-talk-with-hexlet.
Теперь установим этот пакет в систему глобально. Но сначала убедимся, что никаких символических ссылок в директории не существует:
composer global config bin-dir --absolute
Changed current directory to /home/hex/.composer
/home/hex/.composer/vendor/bin
ls -al /home/hex/.composer/vendor/bin | grep say
Здесь с помощью фильтра grep мы попытались найти файлы, содержащие в своем имени строчку "say" (как наши ссылки в секции bin). Поиск не дал результатов, потому что до установки пакета таких файлов нет.
Далее глобально устанавливаем пакет в систему:
Теперь воспользуемся grep и снова проверим директорию установки исполняемых файлов:
ls -al /home/hex/.composer/vendor/bin | grep say
lrwxrwxrwx  1 hex hex   36 Jul  1 07:45 sayBye -> ../hex/small-talk-with-hexlet/sayBye
lrwxrwxrwx  1 hex hex   35 Jul  1 07:45 sayHi -> ../hex/small-talk-with-hexlet/sayHi
Как и ожидалось, в этом каталоге находятся символические ссылки — об этом свидетельствует первый символ l, определяющий тип файла в строке атрибутов файла lrwxrwxrwx. Эти ссылки можно запускать из любой точки файловой системы:
sayHi
Hello, Hexlet!
sayBye
Bye-bye! See you later, Hexlet!
cd /media/ # Перейдем в другой каталог
sayHi # Выполняем команду
Hello, Hexlet!
sayBye # Выполняем команду
Bye-bye! See you later, Hexlet!
Из примера видно, что мы можем успешно запускать одни и те же команды из разных директорий. Причины, по которым это происходит, мы подробно обсуждали выше.
Что происходит при локальной установке
В подавляющем большинстве случаев разработчики устанавливают пакеты не глобально, а локально. При такой установке пакеты привязываются к конкретному проекту и размещаются внутри его каталога по пути ./vendor/. При этом ссылки на исполняемые файлы устанавливаемых пакетов Composer размещает в каталоге ./vendor/bin.
Ссылки на исполняемые файлы локально установленных пакетов заточены под использование в скриптах, в секции scripts конфигурационного файла composer.json. Для этого существует особенный синтаксис. Эту тему мы проходили в уроке, посвященном скриптам.
Естественно, к символическим ссылкам можно также обратиться напрямую, указав нужный путь. Давайте рассмотрим это на примере, подключив к нашему разрабатываемому проекту small-talk-with-hexlet пакет PHP_CodeSniffer:
composer require --dev "squizlabs/php_codesniffer=*"
Для примера возьмем команду composer require --dev some_package. Если установить пакет с флагом --dev в корневом каталоге проекта, он автоматически добавится в зависимости проекта, то есть в секцию require-dev файла composer.json. Этой возможностью мы и воспользовались.
Посмотрим, какие новые файлы появились в директории проекта:
ls -al
drwxrwxr-x 4 hex hex 4096 Jul  1 08:11 .
drwxrwxr-x 3 hex hex 4096 Jul  1 04:21 ..
drwxrwxr-x 8 hex hex 4096 Jul  1 07:06 .git
-rw-rw-r-- 1 hex hex  286 Jul  1 08:10 composer.json
-rw-rw-r-- 1 hex hex 3388 Jul  1 08:11 composer.lock
-rwxrwxr-x 1 hex hex   73 Jul  1 04:46 sayBye
-rwxrwxr-x 1 hex hex   56 Jul  1 04:45 sayHi
drwxrwxr-x 5 hex hex 4096 Jul  1 08:11 vendor
Как и ожидалось, появился каталог ./vendor, в котором лежит код подключенного пакета и других пакетов, от которых он зависит.
Как узнать место, где Composer хранит ссылки на исполняемые файлы локально подключаемых пакетов? Это можно сделать с помощью команды composer config bin-dir.
Обратите внимание, что здесь нет команды global. В нашем случае это каталог ./vendor/bin. Заглянем в него:
ls -al vendor/bin/
drwxrwxr-x 2 hex hex 4096 Jul  1 08:11 .
drwxrwxr-x 5 hex hex 4096 Jul  1 08:11 ..
lrwxrwxrwx 1 hex hex   43 Jul  1 08:11 phpcbf -> ../squizlabs/php_codesniffer/scripts/phpcbf
lrwxrwxrwx 1 hex hex   42 Jul  1 08:11 phpcs -> ../squizlabs/php_codesniffer/scripts/phpcs
В коде выше видно, что при установке PHP_CodeSniffer добавилось два исполняемых файла для запуска разных программ. Давайте запустим phpcs. Это линтер — утилита, которая проверяет код на соответствие стандартам:
./vendor/bin/phpcs --standard=PSR12 sayHi sayBye
Программа отработала корректно и завершилась молча — без дополнительного вывода отчета об ошибках. Так произошло, потому что в наших файлах не было никаких нарушений оформления кода.
Затем была попытка запустить исполняемый файл из командной строки только по имени, но она привела к неудаче — bash: phpcs: command not found. Командная оболочка просто не нашла файл — при глобальной установке все было бы по-другому.
Выводы
В этом уроке мы рассмотрели общие принципы и отдельные нюансы работы Composer с исполняемыми файлами проекта. Важно отметить, что эти принципы характерны для большинства других пакетных менеджеров из разных языков — например, менеджера пакетов Node.js в JavaScript. Если в будущем вам придется столкнуться с чем-то подобным, вам будет намного проще.
Пример глобальной установки пакета:
Самостоятельная работа
- Установите утилиту phploc глобально
- В проекте php-package запустите анализ количества строк
- В проекте hexlet-php также запустите phploc и сравните результаты анализа обоих проектов
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.