Кэш Brew строит с помощью travis ci

У меня есть сборка Travis CI osx с зависимостью brew, которая должна быть построена из источника.

Я знаю, что у Travis есть функция cache, но у нее нет документации о том, как кэшировать brew сборки или выходы.

Любая идея о том, как кэшировать пакет brew в travis?

Ответ 1

Здесь есть 3 отдельные, слабо связанные проблемы:

  • Кеш скачал бутылки
  • Кэш-бутылки локального производства
  • Cache Homebrew метаданные

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


Кеш скачал бутылки

  • Добавьте $HOME/Library/Caches/Homebrew в кэш Travis (на самом деле этот путь должен быть brew --cache с помощью brew --cache но вы не можете вызвать его здесь, не так ли)

    cache:
      directories:
        - $HOME/Library/Caches/Homebrew
    
  • Запустите brew cleanup на этапе before_cache - в противном случае кэш будет расти бесконечно, по мере выпуска новых версий пакетов.

    before_cache:
      - brew cleanup
    

Кэш-бутылки локального производства

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

Это в дополнение к предыдущему разделу. При использовании без него сохраняйте локальные флаконы где-нибудь за пределами кэша Homebrew на этапе установки и добавляйте их в кэш под соответствующими именами на этапе запуска ниже.

  • При установке:

    • Проверяйте зависимости пакетов с помощью brew deps рекурсивно
      • Если бутылка для пакета недоступна для вашей среды (нет (bottled) в выводе brew info <pkg>), включите зависимости для сборки с помощью --include-build
    • Для каждого из пакетов и зависимостей,

      • Если он уже установлен (brew list --versions <pkg> успешно) и последняя версия (отсутствует в brew outdated), пропустите его
      • Если имеется более старая версия, на следующих этапах вам необходимо установить новую версию вместе со старой:
        • brew unlink старую версию, если она не только для бочонка (нет [keg-only] в выводе brew info)
        • Вызвать всю brew install с --force
      • Если бутылка доступна, просто brew install ее
      • Если бутылка недоступна,

        • Постройте и установите его в следующей последовательности:

          brew install --build-bottle <pkg>
          brew bottle --json <pkg>
          brew uninstall --ignore-dependencies <pkg>
          brew install <bottle>
          

          (Кажется, нет никакого официального способа получить имена полученной бутылки и файла JSON. Я взял имя бутылки из вывода brew bottle и вывел из него имя файла JSON.)

        • Добавьте информацию о бутылке в формулу упаковки

          brew bottle --merge --write <json file>
          
        • Сохраните файл бутылки в кэш Travis под соответствующим именем, заданным brew --cache <pkg>

          • Делайте это только после добавления информации о бутылке - в противном случае вы получите путь к исходному пакету.
          • (Homebrew также создает символические ссылки на загруженные файлы в $HOME/Library/Caches/Homebrew. Вам не нужно этого делать.)
        • Сохраните файл JSON для дальнейшего использования. Не забудьте добавить его местоположение в кэш Travis.
  • При запуске:

    • Сделайте brew update если вы собираетесь
    • Просмотрите сохраненные файлы .json. Для каждого из них проверьте, подходит ли локальная бутылка (сравнивая версии и номера перестроений; вы можете проанализировать выходные brew info --json=v1 <pkg> и brew info --json=v1 <bottle> для этих данных.).
      • Удалите кэшированную бутылку и .json, если нет
        • Поскольку в этот момент вы не сможете найти путь к бутылке с brew --cache, вам необходимо сохранить его самостоятельно.Символьные ссылки не сохраняются в кэше Трэвиса на момент написания этой статьи, поэтому я использовал обычные файлы с путями.
      • Повторно добавьте информацию о бутылке в формулу, как указано выше, если да
        • Также маловероятно, что они изменят URL-адрес загрузки в формуле без изменения версии - тогда ожидаемое кэшированное имя бутылки изменится, поскольку хэш в нем является хешем URL-адреса загрузки.Чтобы учесть это, проверьте, brew --cache <pkg> ли brew --cache <pkg> на вашу бутылку после добавления информации.
  • На before_cache :

    • Если вы используете brew cleanup из предыдущего раздела, сохраните локально созданные файлы бутылок из кэша, прежде чем запускать его, потому что cleanup может удалить те, которые не были нужны в этот раз. После cleanup восстановите те, которые были удалены.

Cache Homebrew метаданные

(Опять же, полный код слишком длинный, поэтому приведем алгоритм.)
Если вы запустите brew update --verbose (и убедитесь, что в .travis.yml или в настройках проекта Travis нет секретных переменных - brew печатает много сообщений о состоянии, только если stdout является tty) - вы увидите, что именно составляет Самостоятельная операция Homebrew - то, что вы должны кешировать:

  • Вытягивание (фактически, rebase по умолчанию) в несколько путей, которые на самом деле являются репозиториями git:
    • /usr/local/Homebrew - сам доморощенный
    • /usr/local/Homebrew/Library/Taps/*/* - установленные taps
  • Проходя через краны и кеш и перенося устаревшие биты. Поскольку содержимое кэша Travis добавляется в существующую структуру каталогов, а не заменяет ее, во второй раз могут возникать странные действия и ошибки, вызванные файлами, которые были удалены как часть обновления, но снова присутствуют в новой виртуальной машине. Те, которые я засвидетельствовал:
    • всегда будет пытаться перенести Taps/caskroom/homebrew-cask на Taps/homebrew/homebrew-cask, создав копию в Taps/homebrew/homebrew-cask/homebrew-cask.В случае кэширования эта копия вызовет сообщение "ошибка: файл существует" при следующем запуске.
    • всегда будет пытаться импортировать множество не зафиксированных файлов в Taps/homebrew/homebrew-versions

Итак, действия будут:

  • Добавьте /usr/local/Homebrew в кэш Travis

    • добавление /usr/local/Cellar и /usr/local/opt оказалось плохой идеей: во-первых, они слишком велики, что приводит к превышению времени ожидания при создании и загрузке кэша; во-вторых, это небезопасно, postinstall сценарии после установки могут влиять на другие произвольные части системы, поэтому каждый раз следует устанавливать новые версии пакетов из (кэшированных) бутылок, а не кэшировать результат. В любом случае установка бутылки занимает всего несколько секунд.
  • Перед brew update : очистите базу кодов Homebrew

    • Удалите Taps/caskroom/homebrew-cask если существует Taps/homebrew/homebrew-cask
    • Найти все git репо под /usr/local/Homebrew (find -type d -name.git, получить dirname результата) и запустить git clean -fxd в каждом, чтобы избавиться от остатков Трэвиса
    • Очистите кэш Homebrew от остатков также с помощью brew cleanup (если вы используете его в сочетании с предыдущим разделом, см. Там о дополнительных операциях) - в противном случае вы получите много ошибок при brew update в разделе "Перенос записей кэша".." этап.
  • При brew update :

    • brew update --merge этого используйте brew update --merge - он автоматически разрешит любые возможные конфликты с вашими локальными коммитами с информацией о бутылке
  • При повторном добавлении локальных бутылок (при использовании в сочетании с предыдущим разделом):

    • Не добавляйте информацию о бутылке в формулу, если она там уже есть
    • Если версия пакета изменилась и информация о вашей бутылке присутствует в формуле, удалите ее из формулы и git commit. Нет стандартного способа сделать это, поэтому вам придется проанализировать и отредактировать файл формулы с помощью скрипта и удалить соответствующую строку из таблицы bottle do. Путь к файлу формул определяется формулой brew formula <pkg>.
  • При установке:

    • При использовании сторонних метчиков всегда проверяйте, установлен ли этот тап:

      brew tap | grep -qxF <tap> || brew tap <tap>
      
      • Поскольку символические ссылки не сохраняются в кэше Travis, контакты, скорее всего, не будут запомнены. Но проверять их тоже не повредит:

        brew tap --list-pinned | grep -qxF <tap> || brew tap-pin <tap>
        
  • На before_cache :

    • Удалите Taps/homebrew/homebrew-cask/homebrew-cask если он существует

Ответ 2

Вы можете добавить каталог brew cache в тайники travis:

cache:
  directories:
    - $HOME/Library/Caches/Homebrew

Насколько я знаю, travis не поддерживает кэширование homebrew из коробки.

Ответ 3

Для кеширования фактических скомпилированных зависимостей, а не кеширования исходных тарболлов или кеширования объектных файлов, добавление каталогов Cellar и opt соответствующих пакетов в кеш и использование соответствующей проверки before_install работает нормально.

Вы также можете добавить все /usr/local/Cellar/ и /usr/local/opt/, но это добавит все установленные пакеты homebrew, а не только те, которые вам нужны.

Пример из проекта, который зависит от openssl, libevent и check:

cache:
  directories:
    - /usr/local/Cellar/openssl
    - /usr/local/opt/openssl
    - /usr/local/Cellar/libevent
    - /usr/local/opt/libevent
    - /usr/local/Cellar/check
    - /usr/local/opt/check
before_install:
  - test -d /usr/local/opt/openssl/lib  || { rmdir /usr/local/opt/openssl; brew install openssl; }
  - test -d /usr/local/opt/libevent/lib || { rmdir /usr/local/opt/libevent; brew install libevent; }
  - test -d /usr/local/opt/check/lib    || { rmdir /usr/local/opt/check; brew install check; }

rmdir необходим потому, что TravisCI создает кэшированные каталоги, если они не существуют, и brew install не удается, если /usr/local/opt/$package является каталогом (в отличие от линка к конкретной установленной версии в погребе). По той же причине test тесты для подкаталога, а не для основного каталога пакета.

Обратите внимание, что для этого подхода требуется, чтобы ваш собственный проект мог подобрать зависимости, установленные в /usr/local/opt.

Ответ 4

Homebrew позволяет вам строить из источника:

brew install --build-from-source [package-name]

Если вы хотите кэшировать свой домородок для Трэвиса, единственный способ, которым я видел, как это сделать, - создать застежку-версию зависимостей homebrew, которые вы хотите похож на этот пример, travis.yml

Ответ 5

Следующее должно кэшировать результаты компилятора:

cache:
  ccache: true
  directories:
    - $HOME/Library/Caches/Homebrew

В OSX Travis в настоящее время, похоже, не отправляет ccache по умолчанию = > Перед использованием ccache также необходимо выполнить следующее:

before_install: 
  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update        ; fi
   - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache; fi

По правде говоря, завершенная сборка по-прежнему не кэшируется. Но результаты сборки каждого отдельного таймерного запуска, который ведет туда, так что по крайней мере большие части процесса сборки могут рассчитываться как "кэшированные" впоследствии.

Ответ 6

Чтобы кэшировать метаданные brew update, вам нужно только кэшировать папки .git в /usr/local/Homebrew

successful 'brew update' cache

Конфигурация Travis для всех остальных читающих:

cache:
  directories:
    - $HOME/Library/Caches/Homebrew
    - /usr/local/Homebrew
before_cache:
  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew cleanup; fi
# Credit https://discourse.brew.sh/t/best-practice-for-homebrew-on-travis-brew-update-is-5min-to-build-time/5215/9
# Cache only .git files under "/usr/local/Homebrew" so "brew update" does not take 5min every build
  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then find /usr/local/Homebrew \! -regex ".+\.git.+" -delete; fi