Кэш пакетов для Composer

Sep 25, 2017 14:54 · 899 words · 5 minute read satis composer

При современном подходе к разработке проектов не обойтись без менеджера пакетов — в случаe с разработкой на PHP это Composer. В данной статье пойдёт речь о настройке локального кэша пакетов для Composer.

Решать данную задачу будем с помощью Satis (естественно в docker-контейнере) — давайте разберемся!

Проблема заключается в частой установке одних и тех же пакетов. Каждая новая установка проекта, это обращение к packagist.org для нахождения источников зависимостей вашего пакета, зависимостей зависимостей и т.д. и скачивание необходимых пакетов. Конечно, у Composer есть встроенный кэш, но он хранится в ~/.composer/cache, индивидуален для каждого пользователя и не доступен для других разработчиков, QA и окружений разработки.

Satis — статическое хранилище Composer пакетов, ультра-легкая версия Packagist, которая также может быть использована для размещения приватных пакетов вашей компании.

Поднимать локальную версию хранилища пакетов будем с помощью docker-контейнера, сам контейнер будет запускаться с помощью файла docker-compose.yml следующего содержания:

version: "2"
services:
  satis:
    image: ealebed/satis:1.0
    container_name: satis
    hostname: satis
    volumes:
      - "/srv/satis/COMPOSER_CACHE:/root/.composer"
      - "/srv/satis/satis.json:/app/config.json"
      - "/srv/satis/dist:/satisfy/web/dist"
      - "/srv/satis/include:/satisfy/web/include"
    environment:
      CRONTAB_FREQUENCY: "*/10 * * * *"
      VIRTUAL_HOST: satis.lc
    ports:
      - 3333:3000
      - 8181:80

Перед запуском docker-контейнера в каталоге /srv/satis/www на хост-машине создаем конфигурационный файл satis.json примерно с таким содержимым:

{
    "name": "Satis",
    "homepage": "http://satis.lc:8181",
    "archive": {
        "directory": "dist",
        "format": "zip",
        "skip-dev": false
    },
    "repositories": [
    {
      "type": "composer",
      "url": "https://packagist.org"
    }
  ],
    "require": {
        "league/fractal": "^0.15.0",
        "psr/container": "^1.0",
        "roave/security-advisories": "dev-master",
        "zendframework/zend-component-installer": "^1.0 || ^0.7.0",
        "zendframework/zend-config-aggregator": "^0.2.0",
        "zendframework/zend-expressive": "^2.0.2",
        "zendframework/zend-expressive-fastroute": "^2.0",
        "zendframework/zend-expressive-helpers": "^4.0",
        "zendframework/zend-http": "^2.6",
        "zendframework/zend-log": "^2.9",
        "zendframework/zend-servicemanager": "^3.3",
        "zendframework/zend-stdlib": "^3.1",
        "phpunit/phpunit": "^6.0.8 || ^5.7.15",
        "squizlabs/php_codesniffer": "^2.8.1",
        "zfcampus/zf-development-mode": "^3.1",
        "zendframework/zend-expressive-tooling": "^0.3.2"
    },
    "require-dependencies": true
}

Здесь:

  • name: имя локального хранилища;
  • homepage: линк по которому будет доступна /srv/satis/web директория;
  • archive.directory: путь где будут храниться пакеты;
  • archive.format: сжимаем пакеты для экономии места;
  • archive.skip-dev: пропускать ли дев пакеты. Если мы хотим полностью избавиться от зависимости от packagist.org, github, bitbucket и т.д. то ставим false;
  • repositories: список хранилищ, их может быть несколько. Можно указывать прямые линки пакетов на github и т.д;
  • { "type": "composer", "url": "https://packagist.org" }: указываем оригинальное для Composer хранилище пакетов — Packagist;
  • require: список пакетов кэш которых мы хотим использовать в своих проектах — здесь список значительно сокращен;
  • require-dependencies: нужно ли скачивать зависимости зависимостей. Опять же, для полной независимости ставим true;

Теперь, находясь в каталоге с конфигурационным файлом docker-compose.yml выполняем команду:

docker-compose up -d

При первом запуске контейнера будет скачаны и упакованы все зависимости (и их зависимости), указанные в секции "require": { }. Если их много, то процесс займет довольно продолжительное время, поэтому можно наблюдать за прогрессом с помощью команды:

docker logs -f satis

Пример вывода логов:

...
Dumping 'symfony/dependency-injection'.
Dumping 'symfony/yaml'.
wrote packages to /var/www/mirror/include/all$133181d2d1ff19075832276e1ade0a6499395e5d.json
Writing packages.json
Pruning include directories
Deleted /var/www/mirror/include/all$f77decc941e6a091ed3c3abe89dafd6343a053f3.json
Writing web view
Rather than invoking init scripts through /etc/init.d, use the service(8)
utility, e.g. service cron start

Since the script you are attempting to invoke has been converted to an
Upstart job, you may also use the start(8) utility, e.g. start cron

После скачивания и упаковки зависимостей в браузере открываем адрес, который указывали в homepage и проверяем список имеющихся пакетов

Теперь в проектах, для которых мы хотим использовать локальное хранилище пакетов, в файле composer.json вставляем:

{
    "repositories": [
        {
            "type": "composer",
            "url": "http://satis.lc:8181"
        }
    ]
}

В таком случае, нужные зависимости сначала будут браться из локального хранилища, а если их там нет — то из packagist.org. Запретить использование официального репозитория пакетов можно добавив такие строки в composer.json проекта:

{
    "repositories": [
        {
            "type": "composer",
            "url": "http://satis.lc:8181"
        },
        {
            "packagist":false
        }
    ]
}

Далее следует очистить индивидуальный кэш Composer и удалить файл composer.lock, после чего можно протестировать работоспособность созданного хранилища.

Несколько тестов (вывод сокращен).

  • Установка зависимостей из официального репозитория packagist.org:
time composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.
Package operations: 59 installs, 0 updates, 0 removals
  - Installing zendframework/zend-component-installer (0.7.1): Downloading (100%)         
  - Installing league/fractal (0.15.0): Downloading (100%)         
...
Generating autoload files

real	2m0.982s
user	0m2.460s
sys	0m0.496s
  • Установка зависимостей из локального satis-репозитория:
time composer install
Loading composer repositories with package information
Warning: Accessing satis.lc over http which is an insecure protocol.
Updating dependencies (including require-dev)
Package operations: 60 installs, 0 updates, 0 removals
  - Installing zendframework/zend-component-installer (0.7.1): Downloading (100%)         
  - Installing league/fractal (0.15.0): Downloading (100%)         
  ...
Writing lock file
Generating autoload files

real	0m12.749s
user	0m3.640s
sys	0m1.404s
  • Установка зависимостей при недоступном локальном репозитории (попытка подключиться к satis’у, после чего загрузка и установка из официального packagist.org):
time composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 60 installs, 0 updates, 0 removals
  - Installing zendframework/zend-component-installer (0.7.1): Warning: Accessing satis.lc over http which is an insecure protocol.
Downloading (failed)       
Downloading (failed)       
Downloading (failed)    Failed to download zendframework/zend-component-installer from dist: The "http://satis.lc:8181/dist/zendframework-zend-component-installer-700a22e4791daa1110be06f2fb055dc678d2b7ff-zip-5e33b1.zip" file could not be downloaded: failed to open stream: Connection refused
    Now trying to download from source
  - Installing zendframework/zend-component-installer (0.7.1): Cloning 700a22e479 from cache
  - Installing league/fractal (0.15.0): Downloading (100%)         
  - Installing zendframework/zend-config-aggregator (0.2.1): Downloading (failed)       
Downloading (failed)       
Downloading (failed)    Failed to download zendframework/zend-config-aggregator from dist: The "http://satis.lc:8181/dist/zendframework-zend-config-aggregator-633a0bf3030a68d2a71cb41a121ad930a52041ea-zip-84656d.zip" file could not be downloaded: failed to open stream: Connection refused
    Now trying to download from source
  - Installing zendframework/zend-config-aggregator (0.2.1): Cloning 633a0bf303 from cache
...
Generating autoload files

real	5m5.170s
user	0m22.544s
sys	0m4.496s

Также есть возможность обновлять локальный кэш для композера по крону или вручную, больше подробностей и готовый проект есть на github.

tweet Share