Пособие по формулам
Формула — это определение пакета, написанное на Ruby. Она может быть создана с помощью brew create <URL>, где <URL> — это zip или tarball, установлена с помощью brew install <formula>, и отлажена с помощью brew install --debug --verbose <formula>. Формулы используют API формул, который предоставляет различные инструменты, специфичные для Homebrew.
Терминология Homebrew
| Термин | Описание | Пример |
|---|---|---|
| Формула | Определение пакета | /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/foo.rb |
| Keg | Префикс установки Формулы | /usr/local/Cellar/foo/0.1 |
| Только Keg | Формула является только Keg, если она не связана с префиксом Homebrew | Формула openjdk |
| Префикс opt | Символьная ссылка на активную версию Keg | /usr/local/opt/foo |
| Cellar | Здесь установлены все Keg | /usr/local/Cellar |
| Tap | Репозиторий Git формул и/или команд | /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core |
| Флакон (Bottle) | Предварительно собранный Keg, используемый вместо сборки из исходного кода | qt-4.8.4.catalina.bottle.tar.gz |
| Cask | Расширение Homebrew для установки приложений macOS | /Applications/MacDown.app/Contents/SharedSupport/bin/macdown |
| Brew Bundle | Расширение Homebrew для описания зависимостей | brew 'myservice', restart_service: true |
Введение
Homebrew использует Git для загрузки обновлений и внесения вклада в проект.
Homebrew устанавливается в Cellar, а затем создаёт символические ссылки на некоторые из установленных файлов в /usr/local, чтобы другие программы могли видеть, что происходит. Рекомендуется изучить brew ls несколько кегов в вашем каталоге Cellar, чтобы увидеть, как всё организовано.
Пакеты устанавливаются в соответствии с их формулами, которые находятся в /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula. Посмотрите простую, например, brew edit etl (или etl), или более сложную, например, brew edit git (или git).
Основные инструкции
Убедитесь, что вы выполнили brew update перед началом. Это превращает вашу установку Homebrew в репозиторий Git.
Перед отправкой новой формулы убедитесь, что ваш пакет:
- Соответствует всем требованиям Приемлемых формул
- Не существует уже в Homebrew (проверьте
brew search <formula>) - Не ожидает слияния (проверьте отслеживание задач)
- Ещё поддерживается разработчиками (т.е. не требует обширной доработки)
- Имеет стабильную, помеченную версию (т.е. не просто репозиторий GitHub без версий)
- Проходит все тесты
brew audit --new-formula <formula>
Перед отправкой новой формулы обязательно ознакомьтесь с нашими руководством по участию.
Получение URL
Выполните brew create с URL исходного tarball:
Это создаёт /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/foo.rb и открывает его в вашем EDITOR. Он будет выглядеть примерно так:
Если brew вывело Warning: Version cannot be determined from URL при выполнении шага create, вам потребуется явно добавить правильный version в формулу, а затем сохранить формулу.
Homebrew попытается угадать имя формулы по её URL. Если это не удастся, вы можете переопределить его с помощью brew create <URL> --set-name <name>.
Заполните homepage
Мы не принимаем формулы без homepage!
Предпочтителен SSL/TLS (https) homepage, если он доступен.
Попытайтесь кратко описать, что делает формула, на основе homepage в описании desc. Обратите внимание, что описание автоматически предваряется именем формулы.
Заполните license
Мы не принимаем новые формулы в Homebrew/homebrew-core без license!
Мы принимаем только формулы, использующие лицензию Debian Free Software Guidelines или выпущенные в общественное достояние в соответствии с Руководством DFSG по программному обеспечению общественного достояния.
Используйте идентификатор лицензии из SPDX License List, например, license "BSD-2-Clause", или используйте license :public_domain для программного обеспечения общественного достояния.
Используйте :any_of, :all_of или :with для описания сложных выражений лицензии. :any_of следует использовать, когда пользователь может выбрать используемую лицензию. :all_of следует использовать, когда пользователь должен использовать все лицензии. :with следует использовать для указания допустимого исключения SPDX. Добавьте + к идентификатору, чтобы указать, что формула может быть лицензирована в соответствии с более поздними версиями той же лицензии.
Посмотрите Руководство по лицензированию для примеров сложных выражений лицензии в формулах Homebrew.
Проверьте систему сборки
%%%CODE_BLOCK_51%%>Теперь вы находитесь в новой оболочке с распакованным tarball в временной песочнице.
Проверьте систему сборки пакета. Устанавливается ли пакет с помощью ./configure, cmake, или с помощью чего-то другого? Удалите закомментированные cmake строки, если пакет использует ./configure.
Проверка зависимостей
В README , вероятно, указаны зависимости, и Homebrew или macOS, скорее всего, уже имеют их. Вы можете проверить зависимости Homebrew с помощью brew search. Вот некоторые распространённые зависимости, которые поставляются с macOS:
libexpatlibGLlibiconvlibpcaplibxml2pythonruby
Есть и много других; проверьте /usr/lib на предмет их наличия.
Мы обычно стараемся не дублировать системные библиотеки и сложные инструменты в ядре Homebrew, но дублируем некоторые часто используемые инструменты.
Исключения составляют OpenSSL и LibreSSL. Для их использования необходимо использовать соответствующие библиотеки Homebrew, и наш бот Brew Test Bot в ходе пост-установки audit выдаст предупреждение, если обнаружит, что вы этого не сделали.
OpenSSL в Homebrew — keg_only, чтобы избежать конфликтов с системным, поэтому иногда формулам необходимо задавать переменные окружения или передавать специальные флаги конфигурации для поиска нашего OpenSSL. Вы можете увидеть этот механизм в формуле clamav. Обычно это не требуется, поскольку Homebrew настраивает нашу среду сборки keg_only, чтобы отдавать предпочтение поиску формул keg_only в первую очередь.
Важно: $(brew --prefix)/bin НЕ входит в PATH во время установки формулы. Если у вас есть зависимости во время сборки, вы должны их указать, и brew добавит их в PATH или создаст Requirement.
Указание других формул в качестве зависимостей
%%%CODE_BLOCK_76%%>Строка (например, "jpeg") определяет зависимость от формулы.
Символ (например, :xcode) определяет Requirement, который может быть выполнен одной или несколькими формулами, cask или другим системным программным обеспечением (например, Xcode).
Словарь (например, =>) добавляет информацию к зависимости. При заданном String или Symbol значение может быть одним или несколькими из следующих значений:
:buildозначает, что зависимость является зависимостью только во время сборки, поэтому её можно пропустить при установке из флакона или при отображении отсутствующих зависимостей с помощьюbrew missing.:testозначает, что зависимость требуется только при запускеbrew test.:optionalгенерирует неявный параметрwith-fooдля формулы. Это означает, что, учитываяdepends_on "foo" => :optional, пользователь должен передать--with-fooдля использования зависимости.:recommendedгенерирует неявный параметрwithout-foo, что означает, что зависимость включена по умолчанию, и пользователь должен передать--without-fooдля отключения этой зависимости. Описание по умолчанию можно переопределить с помощью обычного синтаксиса параметра (в этом случае объявление параметра должно предшествовать зависимости):option "with-foo", "Compile with foo bindings" # This overrides the generated description if you want to depends_on "foo" => :optional # Generated description would otherwise be "Build with foo support"
- Некоторые
Requirementтакже могут принимать строку, определяющую минимальную версию, от которой зависит формула.
Примечание: :optional и :recommended не разрешены в Homebrew/homebrew-core, так как не тестируются CI.
Указание конфликтов с другими формулами
Иногда между формулами возникает жёсткий конфликт, который нельзя избежать или обойти с помощью keg_only.
Хороший пример формулы для незначительного конфликта — mbedtls, которая предоставляет и компилирует исполняемый файл «Hello World». Это очевидно не является существенным для функционирования mbedtls, и конфликт с популярной формулой GNU hello будет избыточным, поэтому мы просто удаляем его во время установки.
pdftohtml предоставляет пример серьёзного конфликта, когда обе формулы предоставляют идентично названный бинарник, который необходим для функционирования, поэтому conflicts_with предпочтительнее.
Как общее правило, conflicts_with следует использовать в крайнем случае. Это довольно грубый инструмент.
Синтаксис конфликта, который нельзя обойти:
conflicts_with "blueduck", because: "yellowduck also ships a duck binary"
Ревизии формул
В Homebrew мы иногда принимаем обновления формул, которые не включают изменение версии. Это включает обновления ресурсов, новые патчи или исправление проблем безопасности в формуле.
Иногда эти обновления требуют принудительной перекомпиляции самой формулы или её зависимостей, чтобы гарантировать, что формулы продолжают работать как ожидается, или для устранения проблемы безопасности. Эта принудительная перекомпиляция известна как revision и вставляется в блок homepage/url/sha256.
Когда зависимость формулы терпит неудачу при новой версии этой зависимости, она должна получить revision. Пример такой неудачи можно увидеть здесь, а исправление — здесь.
revision также используются для формул, которые переходят с системного OpenSSL на OpenSSL, поставляемый Homebrew, без каких-либо других изменений в этой формуле. Это гарантирует, что пользователи не подвергнутся потенциальным проблемам безопасности устаревшего OpenSSL. Пример этого можно увидеть в этом коммите.
Изменения схемы версий
Иногда у формул есть схемы версий, которые меняются таким образом, что прямое сравнение двух версий больше не даёт правильного результата. Например, проект может иметь версию 13 и затем решить стать 1.0.0. Так как 13 по умолчанию переводится в 13.0.0 нашей системой управления версиями, это требует вмешательства.
Когда схема версий формулы не распознаёт новую версию как более новую, она должна получить version_scheme. Пример этого можно увидеть здесь.
Проверьте зависимости
Когда у вас уже установлено много формул, легко пропустить общую зависимость. Вы можете проверить, к каким библиотекам ссылается двоичный файл, с помощью команды otool (возможно, вам нужно использовать xcrun otool).
$ otool -L /usr/local/bin/ldapvi
/usr/local/bin/ldapvi:
/usr/local/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lib/libglib-2.0.0.dylib (compatibility version 4201.0.0, current version 4201.0.0)
/usr/local/opt/gettext/lib/libintl.8.dylib (compatibility version 10.0.0, current version 10.2.0)
/usr/local/opt/readline/lib/libreadline.6.dylib (compatibility version 6.0.0, current version 6.3.0)
/usr/local/lib/libpopt.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/System/Library/Frameworks/LDAP.framework/Versions/A/LDAP (compatibility version 1.0.0, current version 2.4.0)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0) Указание драгоценностей, модулей Python, проектов Go и т. д. в качестве зависимостей
Homebrew не упаковывает готовые библиотеки, специфичные для языка. Их следует устанавливать непосредственно из gem/cpan/pip и т. д.
Если вы устанавливаете приложение, используйте resource для всех зависимостей, специфичных для языка:
class Foo < Formula
resource "pycrypto" do
url "https://files.pythonhosted.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz"
sha256 "f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c"
end
def install
resource("pycrypto").stage { system "python", *Language::Python.setup_install_args(libexec/"vendor") }
end
end jrnl — пример формулы, которая хорошо это делает. В итоге пользователю не нужно использовать pip или Python, а только jrnl.
Для формул Python выполнение brew update-python-resources <formula> автоматически добавит необходимые resource-блоки зависимостей вашего приложения Python в формулу. Обратите внимание, что brew update-python-resources выполняется автоматически brew create, если вы передадите флаг --python. Если brew update-python-resources не может определить правильные resource-блоки, homebrew-pypi-poet — хорошая альтернативная сторонняя утилита, которая может помочь.
Установить формулу
brew install --build-from-source --verbose --debug foo
--debug попросит вас открыть интерактивную оболочку, если сборка завершится ошибкой, чтобы вы могли попытаться выяснить, что пошло не так.
Проверьте начало вывода, например, ./configure. Некоторые скрипты конфигурации не распознают, например, --disable-debug. Если вы видите предупреждение об этом, удалите опцию из формулы.
Добавление теста в формулу
Добавьте действительный тест в test do-блок формулы. Это будет выполнено brew test foo и ботом Brew Test.
test do-блок автоматически создаёт и переключается в временную директорию, которая удаляется после выполнения. Вы можете получить доступ к этому Pathname с помощью функции testpath. Переменная среды HOME устанавливается в testpath внутри test do-блока.
Мы хотим тесты, которые не требуют пользовательского ввода и проверяют основную функциональность приложения. Например, foo build-foo input.foo — хороший тест, а (несмотря на их широкое использование) foo --version и foo --help — плохие тесты. Однако плохой тест лучше, чем отсутствие теста вообще.
См. cmake для примера формулы с хорошим тестом. Формула записывает базовый файл CMakeLists.txt в тестовую директорию, затем вызывает CMake для генерации Make файлов. Этот тест проверяет, что CMake не, например, не завершается аварийно при базовой работе.
Вы можете проверить, что вывод соответствует ожидаемому, с помощью assert_equal или assert_match на выводе утверждений формулы, например, в этом примере из формулы envv:
assert_equal "mylist=A:C; export mylist", shell_output("#{bin}/envv del mylist B").strip Вы также можете проверить, был ли создан выходной файл:
assert_predicate testpath/"output.txt", :exist?
Некоторые советы для конкретных случаев:
- Если формула — библиотека, скомпилируйте и запустите небольшой код, который связывается с ней. Его можно взять из документации/примеров исходного кода upstream. Хороший пример —
tinyxml2, который записывает небольшой файл исходного кода C++ в тестовую директорию, компилирует и связывает его с библиотекой tinyxml2, а затем проверяет, что получившаяся программа выполняется успешно. - Если формула предназначена для программы с графическим интерфейсом, попробуйте найти какую-нибудь функцию, которая работает только в командной строке, например, преобразование форматов, чтение или отображение файла конфигурации и т. д.
- Если программное обеспечение не может работать без учетных данных или требует виртуальную машину, экземпляр Docker и т. д. для запуска, тестом может быть попытка подключиться с недействительными учетными данными (или без них) и подтвердить, что это происходит как ожидается. Это предпочтительнее, чем подделка зависимости.
- Homebrew поставляется с рядом стандартных тестовых фикстур, в том числе многочисленные образцы изображений, звуков и документов в различных форматах. Вы можете получить путь к тестовой фикстуре с помощью
test_fixtures("test.svg"). - Если ваш тест требует тестового файла, который не является стандартной тестовой фикстурой, вы можете установить его из репозитория источника во время фазы
testс помощью блока ресурсов, например, так:
resource("testdata") do
url "https://example.com/input.foo"
sha256 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
end
test do
resource("testdata").stage do
assert_match "OK", shell_output("#{bin}/foo build-foo input.foo")
end
end Справочники
Homebrew ожидает найти руководства в #{prefix}/share/man/..., а не в #{prefix}/man/....
Некоторые программы устанавливаются в man вместо share/man, поэтому проверьте вывод и добавьте "--mandir=#{man}" к строке ./configure, если необходимо.
Ограничения
В случае наличия специфических проблем с упаковкой Homebrew (по сравнению с тем, как программное обеспечение устанавливается из других источников), можно добавить блок caveats в формулу, чтобы предупредить пользователей. Это может указывать на нестандартные пути установки, пример из формулы ruby.
==> Caveats By default, binaries installed by gem will be placed into: /usr/local/lib/ruby/gems/bin You may want to add this to your PATH.
Несколько слов о наименовании
Называйте формулу так, как проект позиционирует продукт. Поэтому это pkg-config, а не pkgconfig; sdl_mixer, а не sdl-mixer или sdlmixer.
Единственным исключением являются такие вещи, как «Apache Ant». Apache добавляет «Apache» перед всем, но мы используем имя формулы ant. Мы включаем префикс только в таких случаях, как gnuplot (потому что это часть имени) и gnu-go (потому что все называют его «GNU Go», никто не называет его просто «Go»). Слово «Go» слишком распространено, и существует слишком много его реализаций.
Если вы не уверены в названии, проверьте его домашнюю страницу, страницу Wikipedia и как Debian это называет.
Если в Homebrew уже есть формула под названием foo, мы обычно не принимаем запросы на замену этой формулы чем-то другим, также имеющим имя foo. Это сделано для того, чтобы избежать как путаницы, так и неожиданных ожиданий пользователей.
Когда две формулы имеют одно и то же имя у upstream, например, AESCrypt и AES Crypt, более новая формула должна обычно адаптировать своё имя, чтобы избежать конфликтов с текущей формулой.
Если вы по-прежнему не уверены, просто сделайте коммит. Мы применим какое-то произвольное правило и примем решение 😉.
При импорте классов Homebrew потребует формулу, а затем создаст экземпляр класса. Это делается предполагая, что имя формулы может быть непосредственно преобразовано в имя класса, используя regexp. Правила просты:
-
foo-bar.rb=>FooBar -
foobar.rb=>Foobar
Таким образом, если вы измените имя класса, вы также должны переименовать файл. Имена файлов должны быть в нижнем регистре, а имена классов — строчным верблюжьим регистром (CamelCase), например, формулы gnu-go и sdl_mixer превратятся в классы GnuGo и SdlMixer, даже если часть их имени — аббревиатура.
Добавляйте псевдонимы, создавая символические ссылки в директории Aliases в корне репозитория.
Проверить формулу
Вы можете запустить brew audit --strict --online для проверки формул на соответствие стилю Homebrew. Команда audit включает предупреждения о хвостовых пробелах, предпочтительных URL-адресах для определённых хостов источников и многих других стилистических проблемах. Исправление этих предупреждений перед отправкой коммита сделает процесс намного быстрее для всех.
Новые формулы, отправляемые в Homebrew, должны запускать brew audit --new-formula foo. Эта команда выполняется ботом Brew Test Bot при новых отправлениях в рамках автоматизированного процесса сборки и тестирования и выявляет больше потенциальных проблем, чем стандартный аудит.
Используйте brew info и проверьте, правильно ли Homebrew определил версию по URL. Добавьте явное version, если нет.
Изменения
Всё построено на Git, поэтому внесение изменений легко:
brew update # required in more ways than you think (initialises the brew git repository if you don't already have it) cd "$(brew --repository homebrew/core)" # Create a new git branch for your formula so your pull request is easy to # modify if any changes come up during review. git checkout -b <some-descriptive-name> origin/master git add Formula/foo.rb git commit
Установленный стандарт для сообщений об изменениях Git:
- первая строка — краткое описание изменений, не более 50 символов
- две (2) пустые строки, а затем
- подробное объяснение изменений.
В Homebrew мы предпочитаем ставить имя формулы в начале, как в этом примере: foobar 7.3 (new formula). Это может показаться слишком коротким, но вы обнаружите, что принуждение к краткому описанию изменений поощряет атомарность и лаконичность. Если вы не можете описать изменения менее чем в 50-80 символах, вероятно, вы пытаетесь объединить два отдельных изменения в одно. Для более подробного объяснения, пожалуйста, прочитайте отличную статью Тима Попа, Заметка о сообщениях об изменениях Git.
Предпочтительный формат сообщений об изменениях для простых обновлений версий — foobar 7.3, а для исправлений — foobar: fix flibble matrix..
Убедитесь, что вы указали соответствующий вопрос в GitHub, например, Closes #12345 в сообщении об изменениях. История Homebrew — это первое, на что обратят внимание будущие участники, пытаясь понять текущее состояние формул, которые их интересуют.
Отправка
Теперь вам нужно отправить свои изменения в GitHub.
Если вы ещё не создали копию Homebrew, перейдите в репозиторий homebrew-core и нажмите кнопку «Сделать копию».
Если вы уже создали копию Homebrew в GitHub, то можете выполнить отправку вручную (просто убедитесь, что вы взяли последние изменения из ветки Homebrew/homebrew-core master):
git push https://github.com/myname/homebrew-core/ <what-you-called-your-branch>
Теперь откройте запрос на включение изменений.
- Одна формула на один коммит; один коммит на одну формулу.
- Избегайте объединяющих коммитов в запросе на включение.
Удобные инструменты
Сообщения
Для отображения информационных сообщений пользователю предоставляются три команды:
-
ohaiдля общей информации -
opooдля предупреждений -
odieдля сообщений об ошибках и немедленного выхода
Используйте odie при необходимости благополучно завершить выполнение формулы по любой причине. Например:
if build.head? lib_jar = Dir["cfr-*-SNAPSHOT.jar"] doc_jar = Dir["cfr-*-SNAPSHOT-javadoc.jar"] odie "Unexpected number of artifacts!" if (lib_jar.length != 1) || (doc_jar.length != 1) end
bin.install "foo"
Вы увидите что-то подобное в некоторых формулах. Это перемещает файл foo в каталог формулы bin (/usr/local/Cellar/pkg/0.1/bin) и делает его исполняемым (chmod 0555 foo).
Вы также можете переименовать файл во время процесса установки. Это может быть полезно для добавления префикса к бинарным файлам, которые в противном случае вызовут конфликты с другой формулой, или для удаления расширения файла. Например, чтобы установить foo.py в каталог формулы bin (/usr/local/Cellar/pkg/0.1/bin) просто как foo вместо foo.py, используйте:
bin.install "foo.py" => "foo"
inreplace
inreplace — удобная функция для редактирования файлов на месте. Например:
inreplace "path", before, after
before и after могут быть строками или регулярными выражениями. Используйте блочный формат, если вам нужно выполнить несколько замен в файле:
inreplace "path" do |s| s.gsub!(/foo/, "bar") s.gsub! "123", "456" end
Убедитесь, что вы изменяете s! Этот блок игнорирует возвращаемое значение.
inreplace следует использовать вместо патчей, когда требуется исправить что-то, что никогда не будет принято вверх по течению, например, заставить систему сборки программного обеспечения учитывать иерархию установки Homebrew. Если это касается как Homebrew, так и MacPorts (т.е. специфично для macOS), это следует преобразовать в патч, отправленный вверх по течению.
Если вам нужно изменить переменные в Makefile, вместо inreplace передайте их в качестве аргументов в make:
system "make", "target", "VAR2=value1", "VAR2=value2", "VAR3=values can have spaces"
system "make", "CC=#{ENV.cc}", "PREFIX=#{prefix}" Обратите внимание, что значения могут содержать неэкранированные пробелы, если используется многоаргументная форма system.
Патчи
Хотя patchы обычно следует избегать, иногда они временно необходимы.
При patchнии (например, при исправлении включения файлов заголовков, исправлении предупреждений компилятора и т. д.) первое, что нужно сделать, — проверить, знает ли проект вверх по течению о проблеме. Если нет, создайте отчет об ошибке и/или отправьте свой патч на включение. Иногда мы можем принять ваш патч, прежде чем он был отправлен вверх по течению, но, запустив процесс исправления проблемы вверх по течению, вы сократите время, в течение которого мы будем использовать этот патч.
Всегда обосновывайте patch комментарием в коде! В противном случае никто не будет знать, когда можно безопасно удалить патч или оставить его при обновлении формулы. Комментарий должен содержать ссылку на соответствующий(ие) вопрос(ы) вверх по течению.
Внешние patchы могут быть объявлены с использованием блоков в стиле ресурсов:
patch do url "https://example.com/example_patch.diff" sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7" end
Предполагается уровень обрезки -p1. Его можно переопределить с помощью символьного аргумента:
patch :p0 do url "https://example.com/example_patch.diff" sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7" end
patchы могут быть объявлены в блоках stable и head. Всегда используйте блок вместо условного оператора, т.е. stable do ... end вместо if build.stable? then ... end.
stable do
# some other things...
patch do
url "https://example.com/example_patch.diff"
sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7"
end
end Встроенные (КОНЕЦ) патчи могут быть объявлены следующим образом:
patch :DATA patch :p0, :DATA
с данными патча, включенными в конец файла:
__END__ diff --git a/foo/showfigfonts b/foo/showfigfonts index 643c60b..543379c 100644 --- a/foo/showfigfonts +++ b/foo/showfigfonts @@ -14,6 +14,7 @@ …
Патчи также могут быть встроены, передавая строку. Это позволяет предоставить несколько встроенных патчей, при этом только некоторые из них являются условными.
patch :p0, "..."
Во встроенных патчах строка «HOMEBREW_PREFIX» заменяется значением константы HOMEBREW_PREFIX перед применением патча.
Создание diff
brew install --interactive --git foo # (make some edits) git diff | pbcopy brew edit foo
Теперь просто вставьте в формулу после __END__. Вместо git diff | pbcopy, для некоторых редакторов git diff >> path/to/your/formula/foo.rb может помочь убедиться, что патч не изменяется, например, удаление пробелов, изменение отступов и т. д.
Расширенные приемы формул
Если что-то непонятно, вы обычно можете разобраться, grepив каталог $(brew --repository homebrew/core). Пожалуйста, отправьте запрос на включение изменений, чтобы дополнить этот документ, если вы считаете, что это будет полезно!
Обработка различных конфигураций системы
Часто формулы требуют различных зависимостей, ресурсов, патчей, конфликтов, устаревших функций или keg_only статусов на разных операционных системах и архитектурах. В этих случаях компоненты могут быть вложены в блоки on_macos, on_linux, on_arm или on_intel. Например, вот как добавить gcc в качестве зависимости только для Linux:
on_linux do depends_on "gcc" end
Компоненты также могут быть объявлены для конкретных версий macOS или диапазонов версий. Например, чтобы объявить зависимость только от High Sierra, вложите вызов depends_on в блок on_high_sierra. Добавьте параметр :or_older или :or_newer к методу on_high_sierra , чтобы добавить зависимость ко всем версиям macOS, которые соответствуют условию. Например, чтобы добавить gettext в качестве зависимости сборки для Mojave и всех последующих версий macOS, используйте:
on_mojave :or_newer do depends_on "gettext" => :build end
Иногда зависимость необходима для определенных версий macOS и для Linux. В этих случаях можно использовать специальный метод on_system:
on_system :linux, macos: :sierra_or_older do depends_on "gettext" => :build end
Для проверки нескольких условий вложены соответствующие блоки. Например, следующий код добавляет gettext зависимость сборки при использовании ARM и macOS:
on_macos do
on_arm do
depends_on "gettext" => :build
end
end Внутри def install и test do
Внутри def install и test do, не используйте эти on_* методы. Вместо этого используйте операторы if и следующие условные операторы:
-
OS.mac?иOS.linux?возвращаютtrueилиfalseв зависимости от операционной системы -
Hardware::CPU.intel?иHardware::CPU.arm?возвращаютtrueилиfalseв зависимости от архитектуры -
MacOS.versionвозвращает текущую версию macOS. Используйте==,<=или>=для сравнения со символами, соответствующими версиям macOS (например,if MacOS.version >= :mojave)
См. rust для примера.
livecheck блоки
Когда brew livecheck не может определить версии для формулы, мы можем управлять её поведением с помощью блока livecheck . Вот простой пример проверки страницы на наличие ссылок, содержащих имя файла, подобное example-1.2.tar.gz:
livecheck do url "https://www.example.com/downloads/" regex(/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.t/i) end
Для url/regex руководств и дополнительных примеров блоков livecheck обратитесь к brew livecheck документации. Для более технической информации о методах, используемых в блоке livecheck , пожалуйста, обратитесь к Livecheck документации по классу.
Нестабильные версии (head)
Формулы могут указывать альтернативный адрес загрузки для head проекта вверх по течению (master/trunk).
head
head URL (активированные передачей --HEAD) создают версию разработки. Указать её просто:
class Foo < Formula head "https://github.com/mxcl/lastfm-cocoa.git" end
Homebrew понимает git, svn, и hg URL и имеет способ указания репозиториев cvs в качестве URL. Вы можете проверить, собирается ли head с помощью build.head?.
Чтобы использовать определённый коммит, тег или ветку из репозитория, укажите head с :tag и :revision, :revision, или :branch опцией, например:
class Foo < Formula
head "https://github.com/some/package.git", revision: "090930930295adslfknsdfsdaffnasd13"
# or branch: "main" (the default is "master")
# or tag: "1_0_release", revision: "090930930295adslfknsdfsdaffnasd13"
end Выбор компилятора
Иногда пакет не удается собрать при использовании определенного компилятора. Поскольку в последних версиях Xcode компилятор GCC больше не включен, мы не можем просто принудительно использовать GCC. Вместо этого правильным способом объявления этого является метод DSL Xcode versions fails_with. Правильно составленный блок fails_with документирует последнюю версию компилятора, известную тем, что вызывает сбой компиляции, и причину сбоя. Например:
fails_with :clang do build 211 cause "Miscompilation resulting in segfault on queries" end
build принимает Fixnum (целое число; вы можете найти это число в выводе brew --config). cause принимает строку, и использование heredoc рекомендуется для повышения читабельности и позволит создать более полную документацию.
Объявления fails_with могут использоваться с любым из :gcc, :llvm, и :clang. Homebrew будет использовать эту информацию для выбора работающего компилятора (если он доступен).
Явное указание стратегии загрузки
Чтобы использовать одну из встроенных стратегий загрузки Homebrew, укажите флаг :using => в url или head. Например:
class Python3 < Formula homepage "https://www.python.org/" url "https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tar.xz" sha256 "b5b3963533768d5fc325a4d7a6bd6f666726002d696f1d399ec06b043ea996b8" head "https://hg.python.org/cpython", :using => :hg
Homebrew предлагает стратегии анонимной загрузки.
:using значение | стратегия загрузки |
|---|---|
:bzr | BazaarDownloadStrategy |
:curl | CurlDownloadStrategy |
:cvs | CVSDownloadStrategy |
:fossil | FossilDownloadStrategy |
:git | GitDownloadStrategy |
:hg | MercurialDownloadStrategy |
:nounzip | NoUnzipCurlDownloadStrategy |
:post | CurlPostDownloadStrategy |
:svn | SubversionDownloadStrategy |
Если вам требуется больший контроль над тем, как файлы загружаются и подготавливаются к установке, вы можете создать пользовательскую стратегию загрузки и указать ее с помощью параметра :using метода url:
class MyDownloadStrategy < SomeHomebrewDownloadStrategy
def fetch(timeout: nil, **options)
opoo "Unhandled options in #{self.class}#fetch: #{options.keys.join(", ")}" unless options.empty?
# downloads output to `temporary_path`
end
end
class Foo < Formula
url "something", :using => MyDownloadStrategy
end Просто перемещение некоторых файлов
Когда выполняется ваш код в функции установки, текущий рабочий каталог устанавливается в извлечённый архив.
Поэтому легко просто переместить некоторые файлы:
prefix.install "file1", "file2"
Или всё:
prefix.install Dir["output/*"]
В целом, мы хотели бы, чтобы вы указывали, какие файлы или каталоги необходимо установить, а не устанавливать всё.
Переменные для расположения каталогов
| Имя | Значение по умолчанию | Пример |
|---|---|---|
HOMEBREW_PREFIX | /usr/local | |
prefix | #{HOMEBREW_PREFIX}/Cellar/#{name}/#{version} | /usr/local/Cellar/foo/0.1 |
opt_prefix | #{HOMEBREW_PREFIX}/opt/#{name} | /usr/local/opt/foo |
bin | #{prefix}/bin | /usr/local/Cellar/foo/0.1/bin |
doc | #{prefix}/share/doc/#{name} | /usr/local/Cellar/foo/0.1/share/doc/foo |
include | #{prefix}/include | /usr/local/Cellar/foo/0.1/include |
info | #{prefix}/share/info | /usr/local/Cellar/foo/0.1/share/info |
lib | #{prefix}/lib | /usr/local/Cellar/foo/0.1/lib |
libexec | #{prefix}/libexec | /usr/local/Cellar/foo/0.1/libexec |
man | #{prefix}/share/man | /usr/local/Cellar/foo/0.1/share/man |
man[1-8] | #{prefix}/share/man/man[1-8] | /usr/local/Cellar/foo/0.1/share/man/man[1-8] |
sbin | #{prefix}/sbin | /usr/local/Cellar/foo/0.1/sbin |
share | #{prefix}/share | /usr/local/Cellar/foo/0.1/share |
pkgshare | #{prefix}/share/#{name} | /usr/local/Cellar/foo/0.1/share/foo |
elisp | #{prefix}/share/emacs/site-lisp/#{name} | /usr/local/Cellar/foo/0.1/share/emacs/site-lisp/foo |
frameworks | #{prefix}/Frameworks | /usr/local/Cellar/foo/0.1/Frameworks |
kext_prefix | #{prefix}/Library/Extensions | /usr/local/Cellar/foo/0.1/Library/Extensions |
zsh_function | #{prefix}/share/zsh/site-functions | /usr/local/Cellar/foo/0.1/share/zsh/site-functions |
fish_function | #{prefix}/share/fish/vendor_functions | /usr/local/Cellar/foo/0.1/share/fish/vendor_functions |
bash_completion | #{prefix}/etc/bash_completion.d | /usr/local/Cellar/foo/0.1/etc/bash_completion.d |
zsh_completion | #{prefix}/share/zsh/site-functions | /usr/local/Cellar/foo/0.1/share/zsh/site-functions |
fish_completion | #{prefix}/share/fish/vendor_completions.d | /usr/local/Cellar/foo/0.1/share/fish/vendor_completions.d |
etc | #{HOMEBREW_PREFIX}/etc | /usr/local/etc |
pkgetc | #{HOMEBREW_PREFIX}/etc/#{name} | /usr/local/etc/foo |
var | #{HOMEBREW_PREFIX}/var | /usr/local/var |
buildpath | Временный каталог где-то в вашей системе | /private/tmp/[formula-name]-0q2b/[formula-name] |
Эти переменные могут использоваться, например, в коде, таком как
bin.install Dir["output/*"]
для перемещения бинарных файлов в правильное место в Cellar, и
man.mkpath
для создания структуры каталогов для расположения руководства.
Чтобы установить man-страницы в определенные места, используйте man1.install "foo.1", "bar.1", man2.install "foo.2", и т.д.
Обратите внимание, что в контексте Homebrew libexec зарезервирован для использования формулой и, следовательно, не создает символьную ссылку в HOMEBREW_PREFIX.
Добавление необязательных шагов
Примечание: option не допускаются в Homebrew/homebrew-core, так как они не тестируются CI.
Если вы хотите добавить option:
class Yourformula < Formula ... option "with-ham", "Description of the option" option "without-spam", "Another description" depends_on "foo" => :optional # will automatically add a with-foo option ...
А затем определить действие, которое option производит:
if build.with? "ham" # note, no "with" in the option name (it is added by the build.with? method) end if build.without? "ham" # works as you'd expect. True if `--without-ham` was given. end
Имена option должны начинаться со слов with или without. Например, опция для запуска набора тестов должна называться --with-test или --with-check , а не --test, и опция для включения библиотеки общего использования --with-shared , а не --shared или --enable-shared.
option , которые не build.with? или build.without? должны быть помечены как устаревшие с помощью deprecated_option. См. wget для примера.
Операции на уровне файлов
Вы можете использовать утилиты для работы с файлами, предоставляемые Ruby’s FileUtils. Они включены в класс Formula, поэтому вам не нужен префикс FileUtils. для их использования.
При создании символьных ссылок обратите особое внимание на то, чтобы они были относительными ссылками. Это упрощает создание переносимого файла бутылки. Например, чтобы создать символьную ссылку в bin на исполняемый файл в libexec, используйте
bin.install_symlink libexec/"name"
а не:
ln_s libexec/"name", bin
Символьные ссылки, созданные install_symlink, гарантированно являются относительными. ln_s будет создавать только относительную символьную ссылку, если ей будет передан относительный путь.
Переписывание shebang скрипта
Некоторые формулы устанавливают исполняемые скрипты, написанные на интерпретируемых языках, таких как Python или Perl. Homebrew предоставляет метод rewrite_shebang для переписывания shebang скрипта. Это заменяет исходный путь интерпретатора скрипта на путь, от которого зависит формула. Это гарантирует, что в момент выполнения используется правильный интерпретатор. Это не требуется, если система сборки уже обрабатывает это (например, часто с Python pip или Perl ExtUtils::MakeMaker).
Например, формула icdiff использует такую утилиту. Обратите внимание, что необходимо включить утилиту в формулу, например, с Python нужно использовать include Language::Python::Shebang.
Обработка файлов, которые должны сохраняться при обновлении формулы
Например, пакеты Ruby 1.9 должны быть установлены в var/lib/ruby/, чтобы пакеты не приходилось переустанавливать при обновлении Ruby. Обычно это можно сделать с помощью трюков с символьными ссылками или (желательно) опцией конфигурации.
Другим примером являются конфигурационные файлы, которые не должны перезаписываться при обновлении пакета. Если после установки вы обнаружите, что файлы конфигурации, которые должны сохраниться, не копируются, а символьные ссылки в /usr/local/etc/ из Cellar, это часто можно исправить, передав соответствующий аргумент в скрипт конфигурации пакета. Этот аргумент будет отличаться в зависимости от скрипта конфигурации и/или Makefile данного пакета, но одним примером может быть: --sysconfdir=#{etc}
Файлы служб
Существует два способа добавления plist и системных служб в формулу, чтобы brew services смог их обнаружить:
- Если формула уже предоставляет файл, формула может установить его в префикс, как показано ниже.
prefix.install_symlink "file.plist" => "#{plist_name}.plist"
prefix.install_symlink "file.service" => "#{service_name}.service" - Если формула не предоставляет службу, вы можете сгенерировать её с помощью следующего блока.
service do run bin/"script" end
Методы блока службы
Есть много других параметров, которые вы можете задать в таком блоке, и в этой таблице вы найдёте все из них. Единственным обязательным полем в блоке service является поле run для указания того, что запустить.
| Метод | По умолчанию | macOS | Linux | Описание |
|---|---|---|---|---|
run | - | да | да | Команда для выполнения, массив с аргументами или путь |
run_type | :immediate | да | да | Тип службы, :immediate, :interval или :cron |
keep_alive | false | да | да | Нужно ли службе поддерживать процесс запущенным после выхода |
interval | - | да | да | Управление интервалом запуска, требуется для типа :interval |
cron | - | да | да | Управление временем срабатывания, требуется для типа :cron |
launch_only_once | false | да | да | Команда должна выполняться только один раз |
environment_variables | - | да | да | Хэш переменных для установки |
working_dir | - | да | да | Директория для работы |
root_dir | - | да | да | Директория для использования в качестве chroot для процесса |
input_path | - | да | да | Путь для использования в качестве входных данных для процесса |
log_path | - | да | да | Путь для записи stdout |
error_log_path | - | да | да | Путь для записи stderr |
restart_delay | - | да | да | Задержка перед перезапуском процесса |
process_type | - | да | no-op | Тип процесса для управления, :background, :standard, :interactive или :adaptive |
macos_legacy_timers | - | да | no-op | Таймеры, созданные заданиями launchd, объединяются, если это не установлено |
sockets | - | да | no-op | Сокет, созданный в качестве точки доступа к службе |
Для служб, которые запускаются и остаются активными, можно использовать по умолчанию run_type : следующим образом:
service do
run [opt_bin/"beanstalkd", "test"]
keep_alive true
run_type :immediate # This should be omitted since it's the default
end Если службе нужно запускаться по интервалу, используйте run_type :interval и укажите интервал:
service do
run [opt_bin/"beanstalkd", "test"]
run_type :interval
interval 500
end Если службе нужно запускаться в определённое время, используйте run_type :cron и укажите время с помощью синтаксиса crontab:
service do
run [opt_bin/"beanstalkd", "test"]
run_type :cron
cron "5 * * * *"
end Для переменных окружения можно указать хэш. Для пути есть вспомогательный метод std_service_path_env. Этот метод установит путь к #{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin, чтобы служба могла найти другие команды brew.
service do
run opt_bin/"beanstalkd"
environment_variables PATH: std_service_path_env
end Параметры KeepAlive
Стандартные параметры, поддержание активности независимо от статуса или обстоятельств
service do
run [opt_bin/"beanstalkd", "test"]
keep_alive true # or false
end То же самое, что выше, в виде хэша
service do
run [opt_bin/"beanstalkd", "test"]
keep_alive { always: true }
end Поддержание активности до выхода задания с не нулевым кодом возврата
service do
run [opt_bin/"beanstalkd", "test"]
keep_alive { succesful_exit: true }
end Поддержание активности только если задание аварийно завершилось
service do
run [opt_bin/"beanstalkd", "test"]
keep_alive { crashed: true }
end Поддержание активности, пока существует файл
service do
run [opt_bin/"beanstalkd", "test"]
keep_alive { path: "/some/path" }
end Формат сокетов
Метод сокетов принимает отформатированное определение сокета как <type>://<host>:<port>.
-
type:udpилиtcp -
host: Хост для запуска сокета. Например0.0.0.0 -
port: Порт, на котором сокет должен слушать.
Обратите внимание, что сокеты по умолчанию будут доступны по IPv4 и IPv6 адресам.
Использование переменных окружения
Homebrew имеет несколько уровней фильтрации переменных окружения, которые влияют на доступные формулам переменные.
Во-первых, общая среда, в которой работает Homebrew, фильтруется для предотвращения загрязнения среды, которое может нарушить сборку из исходных кодов (https://github.com/Homebrew/brew/issues/932). В частности, этот процесс фильтрует все, кроме указанных разрешенных переменных, но допускает переменные окружения, начинающиеся с HOMEBREW_. Конкретная реализация показана в bin/brew.
На втором уровне фильтрации удаляются чувствительные переменные окружения (например, учетные данные, такие как ключи, пароли или токены), чтобы избежать получения их вредоносными подпроцессами (https://github.com/Homebrew/brew/pull/2524). Это предотвращает попадание таких переменных в код Ruby формулы, так как они отфильтровываются до вызова формулы. Конкретная реализация показана в ENV.clear_sensitive_environment! методе.
Вы можете установить переменные окружения в методе install формулы с помощью ENV["VARIABLE_NAME"] = "VALUE". Пример можно увидеть в формуле gh. Временные переменные окружения также можно установить с помощью метода with_env; все переменные, определенные в вызове этого метода, будут восстановлены до исходных значений в конце блока. Пример можно увидеть в формуле csound.
Подводя итог, переменные окружения, используемые формулой, должны соответствовать этим правилам фильтрации, чтобы быть доступными.
Устаревание и отключение формулы
См. нашу документацию Об устаревании, отключении и удалении формул для получения дополнительной информации о том, как и когда устаревать или отключать формулу.
Обновление формул
В конечном итоге будет выпущена новая версия программного обеспечения. В этом случае вы должны обновить url и sha256. Вы можете использовать:
brew bump-formula-pr foo
Если строка revision существует вне любого блока bottle do, она должна быть удалена.
Оставьте блок bottle do ... end в неизменном виде; наша система CI обновит его при получении вашего изменения.
Проверьте, является ли обновляемая формула зависимостью для других формул, выполнив brew uses <formula>. Если это зависимость, запустите brew reinstall для всех зависимостей после её установки и проверьте правильность их работы.
Руководство по стилю
Homebrew стремится поддерживать последовательный стиль Ruby во всех формулах, в основном на основе Руководства по стилю Ruby. Другие формулы, возможно, ещё не были обновлены для соответствия этому руководству, но все новые должны быть.
- Порядок методов в формуле должен соответствовать другим формулам (например:
def installдолжен предшествоватьdef post_install). - Перед строкой
__END__необходима пустая строка.
Поиск и устранение неполадок для авторов новых формул
Ошибка определения версии
Homebrew пытается автоматически определить version из url для предотвращения дублирования. Если у архива необычное имя, вам может потребоваться вручную назначить version.
Плохие makefiles
Не все проекты имеют makefiles, которые будут работать параллельно, поэтому попробуйте депараллелить их, добавив эти строки в метод install.
ENV.deparallelize system "make" # separate make and make install steps system "make", "install"
Если это решит проблему, пожалуйста, откройте заявку, чтобы мы могли исправить её для всех.
Всё ещё не работает?
Посмотрите, что делают MacPorts и Fink:
brew search --macports foo brew search --fink foo
Примечания к Superenv
superenv — это наша «суперсреда», которая изолирует сборку, удаляя /usr/local/bin и все пользовательские PATH которые не являются необходимыми для сборки. Это делается, потому что пользовательские PATH часто содержат ненужные данные, которые нарушают сборку. superenv также удаляет плохие флаги из команд, переданных clang/gcc, и добавляет другие (например, все зависимости keg_only добавляются к флагам -I и -L).
Fortran
Некоторые программы требуют компилятор Fortran. Это можно указать, добавив depends_on "gcc" в формулу.
MPI
Формулы, требующие MPI, должны использовать OpenMPI, добавив depends_on "open-mpi" в формулу, а не MPICH. Эти пакеты имеют конфликты и предоставляют одинаковые стандартизированные интерфейсы. Выбор стандартной реализации и требование к его использованию позволяет программному обеспечению связываться с несколькими библиотеками, которые зависят от MPI, без создания непредвиденных несовместимостей из-за различных сред выполнения MPI.
Библиотеки линейной алгебры
По умолчанию пакеты, которые требуют интерфейсов BLAS/LAPACK линейной алгебры, должны связываться с OpenBLAS с помощью depends_on "openblas" и передачей -DBLA_VENDOR=OpenBLAS в CMake (применяется только к формулам на основе CMake), а не к Apple’s Accelerate framework или по умолчанию к реализации lapack. Apple’s реализация BLAS/LAPACK устарела и может привести к трудноотлаживаемым проблемам. Ссылка на lapack формулу приемлема, хотя она не активно поддерживается или настраивается. По этой причине формулы, требующие BLAS/LAPACK, должны связываться с OpenBLAS.
Как начать заново (сбросить до исходного master)
Вы создали реальный беспорядок в Git, который мешает вам создать нужный коммит, который вы хотите отправить нам? Вы можете рассмотреть возможность начать сначала. Ваши изменения могут быть сброшены до ветки Homebrew master путём выполнения:
git checkout -f master git reset --hard origin/master
© 2009–present Homebrew contributors
Licensed under the BSD 2-Clause License.
https://docs.brew.sh/Formula-Cookbook