Сборник рецептов Formula
Formula — это написанное на Ruby определение пакета. Его можно создать с помощью brew create <URL>, где <URL> — zip- или tar-архив, установить с помощью brew install <formula> и отладить с помощью brew install --debug --verbose <formula>. В Formula используется API класса Formula, предоставляющий различные вспомогательные средства, специфичные для Homebrew.
- Терминология Homebrew
- Введение
-
Основные инструкции
- Получение URL
- Укажите
homepage - Укажите
license - Проверьте систему сборки
- Проверьте зависимости
- Указание других Formula в качестве зависимостей
- Указание конфликтов с другими Formula
- Ревизии Formula
- Изменения схемы версий
- Повторная проверка зависимостей
- Указание компонентов macOS в качестве зависимостей
- Указание гемов, модулей Python, проектов Go и т. д. в качестве зависимостей
- Зависимости Ruby Gem
- Зависимости Python
- Все остальные случаи
- Установка Formula
- Добавление теста в Formula
- Руководства
- Предостережения
- Кратко об именовании
- Проверка Formula
- Создание коммита
- Отправка изменений
- Вспомогательные инструменты
- Патчи
-
Продвинутые приемы работы с Formula
- Обработка различных конфигураций системы
- Блоки
livecheck - Исключение Formula из автоматического обновления версий
- Стратегии загрузки по URL
- Нестабильные версии (
head) - Выбор компилятора
- Простое перемещение файлов
- Операции на уровне файлов
- Изменение shebang в скрипте
- Добавление необязательных шагов
- Выполнение команд после установки
- Обработка файлов, которые должны сохраняться при обновлении Formula
- Файлы служб
- Использование переменных окружения
- Устаревание и отключение Formula
- Обновление Formula
- Устранение неполадок в новых Formula
- Как начать заново (сбросить изменения до состояния upstream)
Терминология Homebrew
| термин | описание | пример |
|---|---|---|
| formula | Определение пакета Homebrew, выполняющее сборку из исходного кода upstream | /opt/homebrew/Library/Taps/homebrew/homebrew-core/Formula/f/foo.rb |
| cask | Определение пакета Homebrew, устанавливающее предварительно скомпилированные бинарные файлы, собранные и подписанные upstream | /opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/b/bar.rb |
| prefix | путь, по которому установлен Homebrew | /opt/homebrew |
| keg | целевой каталог установки конкретной версии formula | /opt/homebrew/Cellar/foo/0.1 |
| rack | каталог, содержащий один или несколько версионированных keg | /opt/homebrew/Cellar/foo |
| keg-only | formula считается keg-only, если для неё не создаётся символическая ссылка в prefix Homebrew | formula openjdk |
| opt prefix | символическая ссылка на активную версию keg | /opt/homebrew/opt/foo |
| Cellar | каталог, содержащий один или несколько именованных rack | /opt/homebrew/Cellar |
| Caskroom | каталог, содержащий один или несколько именованных cask | /opt/homebrew/Caskroom |
| tap | каталог (обычно также репозиторий Git) с Formula, cask и/или внешними командами | /opt/homebrew/Library/Taps/homebrew/homebrew-core |
| bottle | предварительно собранный keg, помещаемый в rack в Cellar вместо сборки из исходного кода upstream | qt--6.5.1.ventura.bottle.tar.gz |
| tab | информация о keg, например о том, был ли он установлен из bottle или собран из исходного кода | /opt/homebrew/Cellar/foo/0.1/INSTALL_RECEIPT.json |
| Brew Bundle | декларативный интерфейс для Homebrew | brew 'myservice', restart_service: true |
| Brew Services | команда Homebrew для управления фоновыми службами | brew services start myservice |
Введение
Homebrew использует Git для хранения Formula и участия в разработке проекта.
Начиная с Homebrew 4.0.0, Formula загружаются в формате JSON с сайта https://formulae.brew.sh. Этот сайт автоматически обновляется по расписанию заданием Homebrew/formulae.brew.sh на основе ветки по умолчанию репозитория Homebrew/homebrew-core.
Homebrew устанавливает Formula в Cellar по пути $(brew --cellar), а затем создаёт символические ссылки на часть установленного содержимого в prefix по пути $(brew --prefix) (например, /opt/homebrew), чтобы другие программы могли видеть, что происходит. Советуем выполнить brew ls для нескольких keg в вашем Cellar, чтобы увидеть, как всё организовано.
Пакеты устанавливаются согласно их Formula. Ознакомьтесь с простой Formula, например brew edit etl (или etl.rb), либо с более сложной, например brew edit git (или git.rb).
Основные инструкции
Перед началом обязательно выполните brew update. Это позволит убедиться, что ваша установка Homebrew является репозиторием Git.
Чтобы создавать или редактировать Formula локально, сначала нужно подключить tap homebrew/core, если вы ещё этого не делали. Эта команда клонирует репозиторий Git Homebrew/homebrew-core в $(brew --repository homebrew/core). Во время разработки также нужно задать HOMEBREW_NO_INSTALL_FROM_API=1 в окружении оболочки или перед любыми командами install, reinstall или upgrade, чтобы принудительно заставить brew использовать локальный репозиторий вместо API.
Перед отправкой новой Formula убедитесь, что ваш пакет:
- соответствует всем требованиям к приемлемым Formula
- ещё не включён в Homebrew (проверьте
brew search <formula>) - ещё не ожидает слияния (проверьте список запросов на слияние)
- по-прежнему поддерживается upstream (то есть не требует обширного исправления патчами)
- имеет стабильную версию с тегом (то есть это не просто репозиторий GitHub без версий)
- проходит все тесты
brew audit --new --formula <formula>
Перед отправкой новой Formula ознакомьтесь с нашими правилами участия в проекте.
Получение URL
Запустите brew create, указав URL исходного tar-архива:
brew create https://example.com/foo-0.1.tar.gz
Эта команда создаёт $(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/f/foo.rb и открывает его в вашем EDITOR.
Передача --ruby или --python заполнит различные значения по умолчанию, часто полезные для проектов, написанных на этих языках.
Если brew вывела Warning: Version cannot be determined from URL на этапе create, необходимо явно добавить в Formula правильный version, а затем сохранить Formula.
Homebrew попытается определить имя Formula по её URL. Если это не удастся, имя можно указать вручную с помощью brew create <URL> --set-name <name>.
Укажите homepage
Мы не принимаем Formula без homepage!
Если доступен SSL/TLS (https), предпочтительно указать homepage с его использованием.
Постарайтесь кратко описать назначение Formula в desc, опираясь на сведения с homepage. Обратите внимание, что при выводе перед desc автоматически добавляется имя Formula.
Укажите license
Мы не принимаем новые Formula в Homebrew/homebrew-core без license!
Мы принимаем только Formula, использующие лицензию, соответствующую Рекомендациям Debian по свободному программному обеспечению (DFSG), либо переданные в общественное достояние в соответствии с рекомендациями DFSG для программного обеспечения в общественном достоянии.
Используйте идентификатор лицензии из списка лицензий SPDX, например license "BSD-2-Clause", или укажите license :public_domain для программного обеспечения в общественном достоянии.
Используйте :any_of, :all_of или :with для описания сложных выражений лицензий. :any_of следует использовать, если пользователь может выбрать лицензию. :all_of следует использовать, если пользователь обязан использовать все лицензии. :with следует использовать для указания допустимого исключения SPDX. Добавьте + к идентификатору, чтобы указать, что Formula может распространяться на условиях более поздних версий той же лицензии.
Примеры сложных выражений лицензий в Formula Homebrew приведены в рекомендациях по лицензированию.
Проверьте систему сборки
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --interactive foo
Теперь вы увидите новое приглашение командной строки, а tar-архив будет распакован во временную изолированную среду.
Проверьте README пакета. Устанавливается ли пакет с помощью ./configure, cmake или чего-то ещё? Удалите закомментированные строки cmake, если пакет использует ./configure.
Проверьте зависимости
В README, вероятно, указаны зависимости, и Homebrew или macOS, скорее всего, уже включают их. Проверить зависимости Homebrew можно с помощью brew search. Вот некоторые распространённые зависимости, входящие в macOS:
libexpatlibGLlibiconvlibpcaplibxml2pythonruby
Есть и множество других; полный список можно найти в /usr/lib.
Как правило, мы стараемся не дублировать системные библиотеки и сложные инструменты в основном репозитории Homebrew, но некоторые широко используемые инструменты всё же дублируем.
Особые исключения — OpenSSL и LibreSSL. Программы, использующие любую из этих библиотек, должны собираться с соответствующей версией, поставляемой Homebrew. BrewTestBot предупредит об этом на этапе audit после установки, если обнаружит, что это не было сделано.
Для Homebrew/homebrew-core сохраняйте зависимости минимальными и соответствующими контексту. Отдавайте предпочтение зависимостям, необходимым для сборки, тестирования или удовлетворения текущих зависимостей основного репозитория, и не добавляйте необязательные возможности upstream, требующие больших рекурсивных деревьев зависимостей. Если Formula должна поддерживать как лёгкую сборку по умолчанию, так и максимально полную сборку, сопровождающие могут предпочесть отдельную Formula *-full. См. политику в отношении зависимостей в руководстве сопровождающего Homebrew/homebrew-core.
Важно: $(brew --prefix)/bin НЕ входит в PATH во время установки Formula. Если зависимости нужны на этапе сборки, их необходимо указать, и brew добавит их в PATH или создаст Requirement.
Указание других Formula в качестве зависимостей
class Foo < Formula # ... depends_on "httpd" => [:build, :test] depends_on xcode: ["9.3", :build] depends_on arch: :x86_64 depends_on "jpeg" depends_on macos: :sonoma depends_on "pkgconf" depends_on "readline" => :recommended depends_on "gtk+" => :optional # ... end
String (например, "jpeg") задаёт зависимость от Formula.
Symbol (например, :xcode) задаёт Requirement, ограничивающее установку системами, отвечающими определённым критериям. Эти критерии могут обеспечиваться одной или несколькими Formula, cask либо другим программным обеспечением, установленным в системе (например, Xcode). Для некоторых Requirement также можно указать строку или символ с минимальной версией, от которой зависит Formula.
depends_on :macos на верхнем уровне помечает Formula как предназначенную только для macOS. depends_on macos: :sonoma на верхнем уровне помечает Formula как предназначенную только для macOS и задаёт минимальную совместимую версию macOS. depends_on maximum_macos: :ventura на верхнем уровне помечает Formula как предназначенную только для macOS и задаёт самую новую совместимую версию macOS. depends_on :linux на верхнем уровне помечает Formula как предназначенную только для Linux. Если Formula поддерживает и macOS, и Linux, но требует определённую версию macOS, укажите требование к версии macOS внутри on_macos.
Hash (например, =>) добавляет сведения о зависимости. Если передана строка или символ, значением может быть одно или несколько из следующего:
-
:buildозначает, что зависимость нужна только на этапе сборки, поэтому её можно не устанавливать при установке из bottle или при выводе отсутствующих зависимостей с помощьюbrew missing. -
:testозначает, что зависимость нужна только при запускеbrew test. -
:optional(не допускается вHomebrew/homebrew-core) создаёт неявный параметрwith-fooдля Formula. Это означает, что приdepends_on "foo" => :optionalпользователю нужно передать--with-foo, чтобы использовать эту зависимость. -
:recommended(не допускается вHomebrew/homebrew-core) создаёт неявный параметрwithout-foo: зависимость включена по умолчанию, и для её отключения пользователь должен передать--without-foo. Описание по умолчанию можно переопределить с помощью синтаксисаoption(в этом случае объявлениеoptionдолжно предшествовать зависимости):
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"
-
"<option-name>"(не допускается вHomebrew/homebrew-core) требует, чтобы зависимость была собрана с указанным параметром.
Указание конфликтов с другими Formula
Иногда между Formula возникает непреодолимый конфликт, который нельзя обойти или устранить с помощью keg_only.
Хороший пример незначительного конфликта — Formula mbedtls, которая поставляет и компилирует исполняемый файл «Hello World». Очевидно, что он не является необходимым для работы mbedtls. Поскольку конфликт с популярной Formula GNU hello был бы чрезмерной мерой, мы просто удаляем его в процессе установки.
pdftohtml — пример серьёзного конфликта: каждая из перечисленных Formula поставляет бинарный файл с одинаковым именем, необходимый для работы, поэтому предпочтительно использовать conflicts_with.
Как правило, к conflicts_with следует прибегать лишь в крайнем случае. Это довольно грубый инструмент.
Синтаксис для конфликта, который невозможно обойти:
conflicts_with "blueduck", because: "yellowduck also ships a duck binary"
Ревизии Formula
В Homebrew мы иногда принимаем обновления Formula, не содержащие изменений версии. К ним относятся обновления ресурсов, новые патчи или исправления уязвимостей в Formula.
Иногда такие обновления требуют принудительной повторной компиляции самой Formula или зависящих от неё Formula, чтобы гарантировать их дальнейшую корректную работу или устранить уязвимость. Такая принудительная перекомпиляция называется revision и указывается под блоком homepage/url/sha256/license.
Если зависимая Formula не собирается с новой версией своей зависимости, ей необходимо присвоить revision. Пример такого сбоя приведён в этом отчёте о проблеме, а его исправление — в соответствующем запросе на слияние.
revision также используются для Formula, переходящих с системного OpenSSL на OpenSSL, поставляемый Homebrew, без других изменений в Formula. Это позволяет не подвергать пользователей потенциальным уязвимостям устаревшего OpenSSL. Пример приведён в этом коммите.
compatibility_version
Используйте compatibility_version, чтобы зафиксировать, остаётся ли обновление Formula совместимым с уже собранными зависимыми Formula. Homebrew сохраняет эти сведения в табах установленных пакетов, чтобы при последующих установках и обновлениях не пересобирать зависимости без необходимости, если установленная зависимость по-прежнему считается совместимой. Это позволяет сократить количество обновлений зависимостей, необходимых пользователям, и избежать ненужных изменений revision зависимых Formula.
Увеличивайте compatibility_version на 1, если обновление Formula требует увеличения revision у любой рекурсивной зависимой Formula в том же запросе на слияние. Если пересборка нужна лишь некоторым зависимым Formula, всё равно увеличьте compatibility_version; увеличивать revision следует только тем зависимым Formula, которые действительно нужно пересобрать.
Не изменяйте compatibility_version при обновлениях, не требующих увеличения revision зависимых Formula. Это значение не должно уменьшаться и должно увеличиваться только на 1 за раз.
Используйте brew bump-compatibility-version для автоматического увеличения compatibility_version.
brew audit проверяет эту взаимосвязь в обоих направлениях. Если значение compatibility_version Formula увеличивается, в том же запросе на слияние значение revision хотя бы одной рекурсивной зависимой Formula также должно увеличиться на 1. Если значение revision Formula увеличивается из-за того, что изменилась версия рекурсивной зависимости, эта зависимость должна увеличить своё compatibility_version на 1.
Эти проверки основаны на изменениях revision зависимых Formula в запросе на слияние, а не на общем анализе ABI. Homebrew не может автоматически обнаружить все нарушения совместимости, не выявляемые проверками связей или Formula, поэтому сопровождающим может потребоваться вручную увеличить compatibility_version и revision зависимых Formula, если они знают, что нужна пересборка.
Изменения схемы версий
Иногда схемы версий Formula меняются так, что прямое сравнение двух версий перестаёт давать правильный результат. Например, проект может использовать версию 13, а затем решить перейти на 1.0.0. Поскольку по умолчанию наша система версионирования преобразует 13 в 13.0.0, в таком случае требуется вмешательство.
Если схема версий Formula не распознаёт новую версию как более новую, ей необходимо присвоить version_scheme. Пример можно найти в этом запросе на слияние.
Повторная проверка зависимостей
Если у вас установлено много Formula, легко не заметить распространённую зависимость. Повторно проверить, с какими библиотеками связана бинарная программа, можно с помощью команды otool (возможно, потребуется использовать xcrun otool):
$ otool -L /opt/homebrew/bin/ldapvi
/opt/homebrew/bin/ldapvi:
/opt/homebrew/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/opt/homebrew/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/opt/homebrew/lib/libglib-2.0.0.dylib (compatibility version 4201.0.0, current version 4201.0.0)
/opt/homebrew/opt/gettext/lib/libintl.8.dylib (compatibility version 10.0.0, current version 10.2.0)
/opt/homebrew/opt/readline/lib/libreadline.6.dylib (compatibility version 6.0.0, current version 6.3.0)
/opt/homebrew/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) Указание компонентов macOS в качестве зависимостей
Если зависимость от Formula требуется на всех платформах, но в macOS её может обеспечить встроенный компонент, укажите её с помощью uses_from_macos. В Linux она действует как depends_on, а в macOS игнорируется, если только система не старше необязательного параметра since:.
Например, чтобы требовать Formula bzip2 в Linux и использовать встроенный bzip2 в macOS:
uses_from_macos "bzip2"
Чтобы требовать Formula perl только при сборке или тестировании в Linux:
uses_from_macos "perl" => [:build, :test]
Чтобы требовать Formula curl в Linux и в macOS до версии 12:
uses_from_macos "curl", since: :monterey
Указание гемов, модулей Python, проектов Go и т. д. в качестве зависимостей
Homebrew не упаковывает уже упакованные библиотеки для конкретных языков. Их следует устанавливать непосредственно из gem/cpan/pip и т. д.
Зависимости Ruby Gem
Предпочтительный способ установки зависимостей gem — использовать bundler вместе с Gemfile.lock проекта upstream. Для этого upstream должен выполнять проверки в своём Gemfile.lock. Если этого не происходит, рекомендуется сообщить об этой проблеме и попросить добавить такие проверки. Если он у проекта есть, всё делается так:
ENV["GEM_HOME"] = libexec system "bundle", "install", "--without", "development"
Затем можно собрать и установить сам проект:
system "gem", "build", "<project>.gemspec"
system "gem", "install", "--ignore-dependencies", "<project>-#{version}.gem" А установить бинарные файлы и изменить их строки shebang можно так:
bin.install libexec/"bin/<bin>"
bin.env_script_all_files(libexec/"bin", GEM_HOME: ENV.fetch("GEM_HOME", nil)) Зависимости Python
Для Python в качестве зависимостей мы используем resource; их можно создавать автоматически. Команда brew update-python-resources <formula> автоматически добавит в Formula необходимые секции resource для зависимостей вашего приложения на Python. Обратите внимание: brew update-python-resources автоматически запускается командой brew create, если передан параметр --python. Если brew update-python-resources не может определить правильные секции resource, хорошей альтернативой может стать сторонний инструмент homebrew-pypi-poet.
Все остальные случаи
Если ничего не помогло, используйте resource для всех остальных языковых зависимостей. Для этого необходимо указать URL конкретной версии и контрольную сумму sha256 для обеспечения безопасности. Пример:
class Foo < Formula
# ...
url "https://example.com/foo-1.0.tar.gz"
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 — пример удачной реализации этого подхода в Formula. В результате пользователю не нужно использовать pip или Python: достаточно запустить jrnl.
Установка Formula
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug foo
Если сборка завершится неудачно, --debug предложит открыть интерактивную оболочку, чтобы вы могли выяснить причину проблемы.
Проверьте начало вывода, например ./configure. Некоторые скрипты configure не распознают, например, --disable-debug. Если вы видите предупреждение об этом, удалите параметр из Formula.
Добавление теста в Formula
Добавьте корректный тест в блок test do Formula. Его будут запускать brew test foo и BrewTestBot.
Блок test do автоматически создаёт временный каталог и переходит в него; после выполнения он удаляется. Получить доступ к этому Pathname можно с помощью функции testpath. Внутри блока test do переменной окружения HOME присваивается значение testpath.
Нам нужны тесты, которым не требуется ввод данных пользователем и которые проверяют базовую функциональность приложения. Например, foo build-foo input.foo — хороший тест, а foo --version и foo --help (несмотря на их широкое распространение) — плохие тесты. Однако плохой тест лучше, чем отсутствие теста.
Пример хорошего теста можно найти в формуле cmake. Она записывает простой файл CMakeLists.txt в каталог тестирования, а затем вызывает CMake для генерации Makefiles. Этот тест проверяет, что CMake, например, не завершается с ошибкой сегментации при базовой работе.
Проверить, что результат соответствует ожиданиям, можно с помощью assert_equal или assert_match для результатов утверждений формулы, как в этом примере из формулы envv:
assert_equal "mylist=A:C; export mylist", shell_output("#{bin}/envv del mylist B").strip Также можно проверить, что выходной файл был создан:
assert_path_exists testpath/"output.txt"
Несколько рекомендаций для конкретных случаев:
- Если формула представляет собой библиотеку, скомпилируйте и запустите простой код, который с ней связывается. Его можно взять из документации или примеров исходного кода вышестоящего проекта. Хороший пример — тест формулы
tinyxml2: он записывает небольшой исходный файл C++ в каталог тестирования, компилирует и связывает его с библиотекой tinyxml2, а затем проверяет, что получившаяся программа успешно запускается. - Если формула предназначена для графической программы, попробуйте найти функцию, которая работает только из командной строки, например преобразование формата, чтение или отображение файла конфигурации и т. п.
- Если программное обеспечение не может работать без учетных данных или для его запуска требуется виртуальная машина, экземпляр Docker и т. п., можно попробовать подключиться с недействительными учетными данными (или без них) и убедиться, что операция завершается ожидаемой ошибкой. Это предпочтительнее имитации зависимости.
- Homebrew включает ряд стандартных тестовых файлов, в том числе множество образцов изображений, звуков и документов в различных форматах. Путь к тестовому файлу можно получить, например, с помощью
test_fixtures("test.svg"). - Если для теста нужен файл, которого нет среди стандартных тестовых файлов, его можно установить из репозитория исходного кода на этапе
testс помощью блокаresource, например:
test do
resource "testdata" do
url "https://example.com/input.foo"
sha256 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
end
resource("testdata").stage do
assert_match "OK", shell_output("#{bin}/foo build-foo input.foo")
end
end - Если двоичный файл записывает данные только в
stderr, для проверок можно перенаправитьstderrвstdoutс помощьюshell_output. Например:
test do
assert_match "Output on stderr", shell_output("#{bin}/formula-program 2>&1", 2)
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: /opt/homebrew/lib/ruby/gems/3.4.0/bin You may want to add this to your PATH.
Несколько слов об именовании
Называйте формулу так, как проект представляет свой продукт. То есть pkgconf, а не pkgconfig; sdl_mixer, а не sdl-mixer или sdlmixer.
Единственное исключение — названия вроде «Apache Ant». Apache добавляет слово «Apache» ко всему, но мы называем формулу ant. Мы включаем этот префикс только в таких случаях, как gnuplot (потому что это часть названия) и gnu-go (потому что все называют его «GNU Go», никто не называет его просто «Go»). Слово «Go» слишком распространено, и существует слишком много его реализаций.
Если вы не уверены в названии, проверьте главную страницу проекта, его страницу в Википедии и название, используемое в Debian.
Если в Homebrew уже есть формула с названием foo, мы обычно не принимаем запросы на замену этой формулы чем-либо другим, что тоже называется foo. Это помогает избежать путаницы и неожиданностей для пользователей.
Если у двух формул совпадают названия вышестоящих проектов, например AESCrypt и AES Crypt, более новая формула обычно должна изменить свое название, чтобы избежать конфликта с существующей формулой.
Если вы всё ещё не уверены, просто создайте коммит. Мы применим какое-нибудь произвольное правило и примем решение 😉.
При импорте классов Homebrew подключает формулу, а затем создает экземпляр класса. Для этого Homebrew предполагает, что имя формулы можно напрямую преобразовать в имя класса с помощью regexp. Правила просты:
-
foo-bar.rb=>FooBar -
foobar.rb=>Foobar
Таким образом, при изменении имени класса необходимо также переименовать файл. Имена файлов должны быть записаны строчными буквами, а имена классов — в соответствующем строгом формате CamelCase. Например, формулы gnu-go и sdl_mixer становятся классами GnuGo и SdlMixer, даже если часть их названия является аббревиатурой.
Чтобы добавить псевдонимы, создайте символические ссылки в каталоге Aliases в корне tap.
Проверка формулы
Можно запустить brew audit --strict --online, чтобы проверить соответствие формул стандартам оформления Homebrew, которые в общих чертах основаны на руководстве по стилю Ruby. Команда audit выдает предупреждения о пробелах в конце строк, рекомендуемых URL для определенных источников и многих других проблемах оформления. Если исправить эти предупреждения до создания коммита, работа всех участников пойдет намного быстрее.
Для новых формул, отправляемых в Homebrew, следует запускать brew audit --new --formula foo. Эту команду выполняет BrewTestBot для новых отправок в рамках автоматизированного процесса сборки и тестирования; она выявляет больше потенциальных проблем, чем стандартная проверка.
Используйте brew info и проверьте, правильно ли Homebrew определил версию по URL. Если нет, явно укажите version.
Создание коммита
Всё построено на Git, поэтому внести свой вклад просто:
brew update # required in more ways than you think (initialises the Homebrew/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/HEAD git add Formula/f/foo.rb git commit
Общепринятый стандарт сообщений коммитов Git таков:
- первая строка — краткое описание коммита длиной не более 50 символов
- затем две (2) пустые строки,
- после чего следует подробное описание коммита.
В Homebrew мы требуем указывать в начале название формулы, например: foobar 7.3 (new formula).
Это может показаться чрезмерно кратким, но вы обнаружите, что необходимость кратко описать коммит помогает делать изменения атомарными и лаконичными. Если вы не можете описать его в 50–80 символах, вероятно, вы пытаетесь объединить два коммита в один. Более подробно об этом можно прочитать в отличной статье Тима Поупа в блоге: Заметка о сообщениях коммитов Git.
Обязательный формат сообщения коммита для простых обновлений версий — foobar 7.3, а для исправлений — foobar: fix flibble matrix.. Объедините свои коммиты в один, используя этот формат сообщения, иначе наш процесс автоматического объединения коммитов заменит ваш PR.
Укажите в сообщении коммита ссылку на все относящиеся к делу задачи GitHub, например Closes #12345. История Homebrew — первое место, куда заглянут будущие участники, пытаясь разобраться в текущем состоянии интересующих их формул.
Отправка изменений
Теперь осталось отправить коммит на GitHub.
Если вы еще не создали форк Homebrew, перейдите в репозиторий Homebrew/homebrew-core и нажмите кнопку Fork.
Если вы уже создали форк Homebrew на GitHub, отправить изменения можно вручную (только убедитесь, что вы получали изменения из ветки по умолчанию Homebrew/homebrew-core):
git push https://github.com/myname/homebrew-core/ <what-you-named-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
Стандартные аргументы
Для любой формулы, использующей одну из известных систем сборки, при компиляции следует передавать аргументы, обеспечивающие соответствие сборки стандартам Homebrew. Они собраны в набор методов std_*_args. Подробную информацию о каждом из этих методов можно найти в документации по API класса Formula.
Большинство этих методов принимают параметры для настройки результата. Например, чтобы задать префикс установки libexec для configure или cmake:
system "./configure", *std_configure_args(prefix: libexec) system "cmake", "-S", ".", "-B", "build", *std_cmake_args(install_prefix: libexec)
Методы std_*_args, а также передаваемые ими аргументы:
std_cabal_v2_args
"--jobs=#{ENV.make_jobs}"
"--max-backjumps=100000"
"--install-method=copy"
"--installdir=#{bin}" std_cargo_args
"--locked"
"--root=#{root}"
"--path=#{path}" std_cmake_args
"-DCMAKE_INSTALL_PREFIX=#{install_prefix}"
"-DCMAKE_INSTALL_LIBDIR=#{install_libdir}"
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_FIND_FRAMEWORK=#{find_framework}"
"-DCMAKE_VERBOSE_MAKEFILE=ON"
"-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=#{HOMEBREW_LIBRARY_PATH}/cmake/trap_fetchcontent_provider.cmake"
"-Wno-dev"
"-DBUILD_TESTING=OFF" std_configure_args
"--disable-debug"
"--disable-dependency-tracking"
"--prefix=#{prefix}"
"--libdir=#{libdir}" std_go_args
"-trimpath"
"-o=#{output}" Он также предоставляет удобный способ задать -ldflags, -gcflags и -tags. См. примеры в формулах babelfish и wazero.
std_meson_args
"--prefix=#{prefix}"
"--libdir=#{lib}"
"--buildtype=release"
"--wrap-mode=nofallback" std_npm_args
"-ddd"
"--global"
"--build-from-source"
"--cache=$(brew --cache)/npm_cache"
"--prefix=#{libexec}" std_pip_args
"--verbose" "--no-deps" "--no-binary=:all:" "--ignore-installed" "--no-compile"
std_zig_args
"--prefix"
prefix
"--release=#{release_mode}"
"-Doptimize=Release#{release_mode}"
"--summary"
"all"
"-Dcpu=#{Hardware.zig_cpu(ENV.effective_arch)}" release_mode — это символ, принимающий только значения :fast, :safe и :small (по умолчанию используется :fast).
bin.install "foo"
В некоторых формулах можно встретить подобный код. Он перемещает файл foo в каталог bin формулы (/opt/homebrew/Cellar/pkg/0.1/bin) и делает его исполняемым (chmod 0555 foo). Доступны переменные для наиболее распространенных путей к каталогам.
Также можно переименовать файл во время установки. Это может пригодиться, чтобы добавить префикс к двоичным файлам, которые в противном случае конфликтовали бы с другой формулой, или удалить расширение файла. Например, чтобы установить foo.py в каталог bin формулы (/opt/homebrew/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, попробуйте передать их в качестве аргументов в make, а не использовать change_make_var! внутри inreplace:
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
# ...
patch do
url "https://example.com/example_patch.diff"
sha256 "85cc828a96735bdafcf29eb6291ca91bac846579bcef7308536e0c875d6c81d7"
end
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.
Аннотации к патчам
Для внешних и file патчей можно указать type и то, что они resolve. Эти аннотации доступны в brew info --json и API формул для последующих инструментов, например генераторов SBOM и сканеров уязвимостей; на применение патча они не влияют.
type описывает происхождение патча с использованием терминологии pedigree.patches из спецификации CycloneDX.
:backport берет код из более новой версии того же программного обеспечения и применяет его к более старой версии, поставляемой Homebrew. Сюда попадает большинство патчей на основе коммитов вышестоящего проекта. Например, innoextract применяет коммит вышестоящего проекта, который исправляет сборку с CMake 4 до следующего выпуска:
patch do url "https://github.com/dscharrer/innoextract/commit/83d0bf4365b09ddd17dddb400ba5d262ddf16fb8.patch?full_index=1" sha256 "fe5299d1fdea5c66287aef2f70fee41d86aedc460c5b165da621d699353db07d" type :backport end
:cherry_pick выборочно применяет коммит вышестоящего проекта, который не относится к строго более новой ветке выпуска, например исправление, существующее только в ветке сопровождения или выпуска. gecode переносит поддержку Qt 6 из ветки release/6.3.0 вышестоящего проекта, а не из master:
patch do url "https://github.com/Gecode/gecode/commit/c0ca0e5f4406099be22f87236ea8547c2f31ded3.patch?full_index=1" sha256 "233b266a943c0619b027b4cb19912e2a8c9d1f8e4323a3627765cb32b47c59fe" type :cherry_pick end
Если вы сомневаетесь, что выбрать — :backport или :cherry_pick, — отдавайте предпочтение :backport для всего, что взято из актуальной ветки разработки вышестоящего проекта.
:unofficial — это патч, созданный не сопровождающими вышестоящего проекта, например исправление сборки, специфичное для Homebrew или дистрибутива. Как и все патчи Homebrew, патч :unofficial, если это возможно, следует сообщить вышестоящему проекту и/или отправить туда. unzip содержит набор патчей, поддерживаемый Debian, поскольку вышестоящий проект Info-ZIP больше не выпускает новые версии:
patch do
url "https://archive.ubuntu.com/ubuntu/pool/main/u/unzip/unzip_6.0-28ubuntu4.1.debian.tar.xz"
sha256 "d123c8e6972dbdd17ba1a4920fb57ed2ede9237dbae149dcbf55df829c77baf3"
type :unofficial
apply "patches/04-handle-pkware-verification-bit.patch",
"patches/05-fix-uid-gid-handling.patch",
"patches/13-remove-build-date.patch"
end resolves указывает, что именно исправляет патч: один или несколько идентификаторов CVE (CVE-YYYY-NNNN), идентификаторов GHSA (GHSA-xxxx-xxxx-xxxx) или URL задач/PR. Идентификаторы CVE также автоматически определяются по url патча, путям apply и file, поэтому CVE-2016-2399.patch в стиле Debian распознается и без явного resolves.
patch do url "https://deb.debian.org/debian/pool/main/libq/libquicktime/libquicktime_1.2.4-12.debian.tar.xz" sha256 "e5b5fa3ec8391b92554d04528568d04ea9eb5145835e0c246eac7961c891a91a" type :backport resolves "CVE-2016-2399", "CVE-2017-9122" apply "patches/CVE-2016-2399.patch", "patches/CVE-2017-9122_et_al.patch" end
Для исправлений сборки, не связанных с безопасностью, укажите URL задачи или PR вышестоящего проекта:
patch do url "https://github.com/dscharrer/innoextract/commit/264c2fe6b84f90f6290c670e5f676660ec7b2387.patch?full_index=1" sha256 "f968a9c0521083dd4076ce5eed56127099a9c9888113fc50f476b914396045cc" type :backport resolves "https://github.com/dscharrer/innoextract/pull/169" end
Создание diff-файла
HOMEBREW_NO_INSTALL_FROM_API=1 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, чтобы убедиться, что патч не изменен, например из-за удаления пробелов или изменения отступов.
Дополнительные приемы работы с формулами
Полный список методов, доступных в формуле, см. в документации по API класса Formula. Если что-то непонятно, обычно можно разобраться, просмотрев каталог $(brew --repository homebrew/core) с помощью grep. Если вы считаете, что это поможет другим, отправьте запрос на включение изменений, чтобы дополнить этот документ!
Обработка различных конфигураций системы
Часто для формул требуются разные зависимости, ресурсы, патчи, конфликты, устаревшие версии или статусы keg_only в зависимости от операционной системы и архитектуры. В таких случаях компоненты можно поместить внутрь блоков on_macos, on_linux, on_arm или on_intel. Например, вот как добавить gcc в качестве зависимости только для Linux:
on_linux do depends_on "gcc" end
Компоненты также можно объявить для конкретных версий macOS или диапазонов версий. Например, чтобы объявить зависимость только для Sequoia, поместите вызов depends_on внутрь блока on_sequoia. Добавьте параметр :or_older или :or_newer к методу on_sequoia, чтобы добавить зависимость для всех версий macOS, удовлетворяющих условию. Например, чтобы добавить gettext как зависимость для сборки в Sequoia и всех более поздних версиях macOS, используйте:
on_sequoia :or_newer do depends_on "gettext" => :build end
Иногда зависимость требуется для некоторых версий macOS и для Linux. В таких случаях можно использовать специальный метод on_system:
on_system :linux, macos: :sonoma_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.arm?иHardware::CPU.intel?возвращаютtrueилиfalseв зависимости от архитектуры -
MacOS.versionвозвращает текущую версию macOS. Используйте==,<=или>=для сравнения с символами, соответствующими версиям macOS (например,if MacOS.version >= :tahoe)
Пример можно найти в формуле icoutils.
Блоки 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.
Исключение формулы из автоматического обновления
По умолчанию все новые формулы в репозитории Homebrew/homebrew-core автоматически обновляются. Это означает, что дальнейшие обновления обрабатываются автоматически заданиями Homebrew CI, и участникам не нужно отправлять запросы на включение изменений.
Иногда по той или иной причине формулу нужно исключить из этого списка. Для этого в определение формулы добавляют метод no_autobump!; параметр because: должен содержать причину. Он принимает строку или символ, соответствующий одной из предустановленных причин. Например:
no_autobump! because: :bumped_by_upstream
Полный список допустимых символов можно найти в NO_AUTOBUMP_REASONS_LIST.
Дополнительную информацию об автоматическом обновлении см. в документации Autobump.
Стратегии загрузки по URL
При разборе URL загрузки Homebrew автоматически определяет тип указанного ресурса — архив (например, tarball или zip) либо репозиторий системы контроля версий (например, Git, Subversion или Mercurial) — и выбирает подходящую стратегию загрузки. Для некоторых стратегий можно указать дополнительные параметры, влияющие на загружаемые данные. Например, чтобы получить исходный код формулы и определить ее номер версии по определенному тегу в репозитории Git (это полезно для пакетов, использующих подмодули Git), укажите url с параметрами :tag и :revision, например:
class Foo < Formula
# ...
url "https://github.com/some/package.git",
tag: "v1.6.2",
revision: "344cd2ee3463abab4c16ac0f9529a846314932a2"
end При загрузке из репозитория Subversion или Mercurial укажите отдельно revision и version:
class Bar < Formula # ... url "https://svn.code.sf.net/p/package/code/stable", revision: "4687" version "12.1.8" end
Чтобы загрузить определенные ревизии внешних репозиториев Subversion, укажите revisions:
class Baz < Formula
# ...
url "svn://source.something.org/package/trunk/",
revisions: { trunk: "22916", "libsomething" => "31045" }
version "7.2.11"
end Если стратегию невозможно определить автоматически, укажите, какую из встроенных стратегий загрузки Homebrew следует использовать, с помощью параметра using:. Например:
class Nginx < Formula desc "HTTP(S) server and reverse proxy, and IMAP/POP3 proxy server" homepage "https://nginx.org/" url "https://nginx.org/download/nginx-1.23.2.tar.gz", using: :homebrew_curl sha256 "a80cc272d3d72aaee70aa8b517b4862a635c0256790434dbfc4d618a999b0b46" head "https://hg.nginx.org/nginx/", using: :hg end
Homebrew предлагает следующие анонимные стратегии загрузки.
значение using: | стратегия загрузки | требования |
|---|---|---|
:bzr | загрузка из репозитория Bazaar |
должен быть установлен breezy |
:curl | загрузка с помощью curl (по умолчанию) | |
:cvs | загрузка из репозитория CVS |
должен быть установлен cvs |
:fossil | загрузка из репозитория Fossil |
должен быть установлен fossil |
:git | загрузка из репозитория Git |
должен быть установлен git |
:hg | загрузка из репозитория Mercurial |
должен быть установлен hg |
:homebrew_curl | загрузка с помощью установленного через Homebrew curl
|
должен быть установлен curl |
:nounzip | загрузка без распаковки | |
:post | загрузка с помощью curl методом POST |
data: хеш параметров
|
:svn | загрузка из репозитория Subversion |
должен быть установлен svn |
Если вам нужно лучше контролировать способ загрузки и подготовки файлов, можно создать собственную стратегию загрузки и указать ее с помощью параметра :using:
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 Нестабильные версии (head)
В формулах можно указать альтернативный источник загрузки исходного кода вышестоящего проекта из ветки разработки или самой актуальной версии (например, master/main/trunk) с помощью head. Его можно активировать, передав --HEAD при установке. Этот источник задается так же, как url, но для загрузки из репозиториев систем контроля версий действуют дополнительные правила:
- Для репозиториев Git обязательно указывать
branch:. Если репозиторий очень большой, укажитеonly_path, чтобы ограничить извлечение одним путем.
head "<https://github.com/some/package.git>", branch: "main"
-
Для загрузки из ветки Mercurial, отличной от «default», необходимо указать
branch:. -
Для репозиториев Subversion можно указать
trust_cert: true, чтобы пропустить интерактивные запросы подтверждения сертификата. -
Для репозиториев CVS можно указать
module:, чтобы получить определенный модуль.
URL, а также зависимости и ресурсы, относящиеся к head, можно объединить в блоке head do.
class Foo < Formula
# ...
head do
url "https://hg.sr.ht/~user/foo", using: :hg, branch: "develop"
depends_on "pkgconf" => :build
resource "package" do
url "https://github.com/other/package.git", branch: "main"
end
end
end Проверить, выполняется ли сборка head, можно с помощью build.head? в методе install.
Выбор компилятора
Иногда пакет не удается собрать с определенным компилятором. Поскольку в последних версиях Xcode компилятор GCC больше не поставляется, мы не можем просто принудительно использовать GCC. Вместо этого следует объявить об этом с помощью DSL-метода fails_with. Корректно составленный блок fails_with описывает последнюю известную версию компилятора, вызывающую сбой компиляции, а также причину сбоя. Например:
fails_with :clang do
build 211
cause "Miscompilation resulting in segfault on queries"
end
fails_with :gcc do
version "5" # fails with GCC 5.x and earlier
cause "Requires C++17 support"
end
fails_with gcc: "7" do
version "7.1" # fails with GCC 7.0 and 7.1 but not 7.2, or any other major GCC version
cause <<-EOS
warning: dereferencing type-punned pointer will break strict-aliasing rules
Fixed in GCC 7.2, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42136
EOS
end Для :clang параметр build принимает целое число (это число можно найти в выводе brew --config), а :gcc принимает либо только version, где строкой указывается последняя проблемная версия GCC, либо аргумент с номером основной версии в сочетании с version, чтобы задать определенный диапазон выпусков GCC. Параметр cause принимает строку; для улучшения читаемости и добавления более подробной документации рекомендуется использовать heredoc.
Объявления fails_with можно использовать с любым из :gcc, :llvm и :clang. Homebrew использует эту информацию для выбора работающего компилятора, если он доступен.
Простое перемещение файлов
При выполнении кода функции установки текущим рабочим каталогом становится распакованный tarball. Поэтому можно просто переместить нужные файлы:
prefix.install "file1", "file2"
Или всё содержимое:
prefix.install Dir["output/*"]
Или только файлы верхнего уровня tarball, например README, LICENSE и т. д.:
prefix.install_metafiles
Как правило, мы предпочитаем, чтобы вы указывали конкретные файлы или каталоги, которые нужно установить, вместо установки всего содержимого.
Переменные для путей к каталогам
| имя | путь по умолчанию | пример |
|---|---|---|
HOMEBREW_PREFIX | совпадает с результатом $(brew --prefix)
| /opt/homebrew |
etc | #{HOMEBREW_PREFIX}/etc | /opt/homebrew/etc |
pkgetc | #{HOMEBREW_PREFIX}/etc/#{name} | /opt/homebrew/etc/foo |
var | #{HOMEBREW_PREFIX}/var | /opt/homebrew/var |
prefix | #{HOMEBREW_PREFIX}/Cellar/#{name}/#{version} | /opt/homebrew/Cellar/foo/0.1 |
opt_prefix | #{HOMEBREW_PREFIX}/opt/#{name} | /opt/homebrew/opt/foo |
bin | #{prefix}/bin | /opt/homebrew/Cellar/foo/0.1/bin |
opt_bin | #{opt_prefix}/bin | /opt/homebrew/opt/foo/bin |
doc | #{prefix}/share/doc/#{name} | /opt/homebrew/Cellar/foo/0.1/share/doc/foo |
include | #{prefix}/include | /opt/homebrew/Cellar/foo/0.1/include |
opt_include | #{opt_prefix}/include | /opt/homebrew/opt/foo/include |
info | #{prefix}/share/info | /opt/homebrew/Cellar/foo/0.1/share/info |
lib | #{prefix}/lib | /opt/homebrew/Cellar/foo/0.1/lib |
opt_lib | #{opt_prefix}/lib | /opt/homebrew/opt/foo/lib |
libexec | #{prefix}/libexec | /opt/homebrew/Cellar/foo/0.1/libexec |
opt_libexec | #{opt_prefix}/libexec | /opt/homebrew/opt/foo/libexec |
man | #{prefix}/share/man | /opt/homebrew/Cellar/foo/0.1/share/man |
man[1-8] | #{prefix}/share/man/man[1-8] | /opt/homebrew/Cellar/foo/0.1/share/man/man[1-8] |
sbin | #{prefix}/sbin | /opt/homebrew/Cellar/foo/0.1/sbin |
opt_sbin | #{opt_prefix}/sbin | /opt/homebrew/opt/foo/sbin |
share | #{prefix}/share | /opt/homebrew/Cellar/foo/0.1/share |
opt_share | #{opt_prefix}/share | /opt/homebrew/opt/foo/share |
pkgshare | #{prefix}/share/#{name} | /opt/homebrew/Cellar/foo/0.1/share/foo |
opt_pkgshare | #{opt_prefix}/share/#{name} | /opt/homebrew/opt/foo/share/foo |
elisp | #{prefix}/share/emacs/site-lisp/#{name} | /opt/homebrew/Cellar/foo/0.1/share/emacs/site-lisp/foo |
opt_elisp | #{opt_prefix}/share/emacs/site-lisp/#{name} | /opt/homebrew/opt/foo/share/emacs/site-lisp/foo |
frameworks | #{prefix}/Frameworks | /opt/homebrew/Cellar/foo/0.1/Frameworks |
opt_frameworks | #{opt_prefix}/Frameworks | /opt/homebrew/opt/foo/Frameworks |
kext_prefix | #{prefix}/Library/Extensions | /opt/homebrew/Cellar/foo/0.1/Library/Extensions |
bash_completion | #{prefix}/etc/bash_completion.d | /opt/homebrew/Cellar/foo/0.1/etc/bash_completion.d |
fish_completion | #{prefix}/share/fish/vendor_completions.d | /opt/homebrew/Cellar/foo/0.1/share/fish/vendor_completions.d |
fish_function | #{prefix}/share/fish/vendor_functions.d | /opt/homebrew/Cellar/foo/0.1/share/fish/vendor_functions.d |
zsh_completion | #{prefix}/share/zsh/site-functions | /opt/homebrew/Cellar/foo/0.1/share/zsh/site-functions |
zsh_function | #{prefix}/share/zsh/site-functions | /opt/homebrew/Cellar/foo/0.1/share/zsh/site-functions |
pwsh_completion | #{prefix}/share/pwsh/completions | /opt/homebrew/Cellar/foo/0.1/share/pwsh/completions |
buildpath | временный рабочий каталог во время сборок | /private/tmp/foo-20250205-69197-po5981/foo-0.1 |
testpath | временный рабочий каталог во время тестов | /private/tmp/foo-test-20250205-84567-4hfs9m |
Их можно использовать, например, в таком коде:
bin.install Dir["output/*"]
чтобы переместить исполняемые файлы в нужное место в Cellar, и:
man.mkpath
чтобы создать структуру каталогов для расположения страниц руководства.
Для установки страниц руководства в определённые места используйте man1.install "foo.1", "bar.1", man2.install "foo.2" и т. д.
Варианты opt_ создают пути, которые остаются неизменными при обновлениях; это может быть полезно, например, для замены версионированных путей в файлах:
inreplace lib/"pkgconfig/zlib.pc", prefix, opt_prefix
Обратите внимание, что в контексте Homebrew libexec зарезервирован для внутреннего использования формулой и поэтому не создаёт символическую ссылку в HOMEBREW_PREFIX.
Операции с файлами
Можно использовать файловые утилиты, предоставляемые Ruby FileUtils. Они включены в класс Formula, поэтому для их использования не нужен префикс FileUtils..
Создавая символические ссылки, обязательно убедитесь, что они относительные. Так проще создать переносимый бутылочный архив. Например, чтобы создать символическую ссылку в bin на исполняемый файл в libexec, используйте:
bin.install_symlink libexec/"name"
вместо:
ln_s libexec/"name", bin
Символические ссылки, созданные методом install_symlink, гарантированно являются относительными. ln_s создаёт относительную символическую ссылку только при передаче относительного пути.
Несколько других утилит для Ruby Pathname упрощают некоторые распространённые операции.
- Чтобы выполнить несколько операций в каталоге, поместите их в блок
cd <path> do:
cd "src" do
system "./configure", "--disable-debug", "--prefix=#{prefix}"
system "make", "install"
end - Чтобы сделать доступными один или несколько исполняемых файлов, спрятанных в
libexecили в пакете macOS.app, используйтеwrite_exec_scriptилиwrite_jar_script:
bin.write_exec_script Dir[libexec/"bin/*"] bin.write_exec_script prefix/"Package.app/Contents/MacOS/package" bin.write_jar_script libexec/jar_file, "jarfile", java_version: "11"
- Для исполняемых файлов, которым для правильной работы требуется задать одну или несколько переменных окружения, используйте
write_env_scriptилиenv_script_all_files:
(bin/"package").write_env_script libexec/"package", PACKAGE_ROOT: libexec
bin.env_script_all_files(libexec/"bin", PERL5LIB: ENV.fetch("PERL5LIB", nil)) Изменение шебанга скрипта
Некоторые формулы устанавливают исполняемые скрипты, написанные на интерпретируемом языке, например Python или Perl. Homebrew предоставляет метод rewrite_shebang для изменения шебанга скрипта. Он заменяет исходный путь к интерпретатору скрипта на путь к интерпретатору, от которого зависит формула. Это гарантирует использование правильного интерпретатора при выполнении. Это не требуется, если с этим уже справляется система сборки (например, часто это происходит с pip или ExtUtils::MakeMaker Perl).
Например, формула icdiff использует эту утилиту. Обратите внимание, что утилиту необходимо включить в формулу; например, для Python нужно использовать include Language::Python::Shebang.
Добавление необязательных шагов
Примечание: option-ы запрещены в Homebrew/homebrew-core, поскольку CI их не тестирует.
Чтобы добавить option:
class Yourformula < Formula # ... url "https://example.com/yourformula-1.0.tar.gz" sha256 "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1" # ... option "with-ham", "Description of the option" option "without-spam", "Another description" depends_on "bar" => :recommended depends_on "foo" => :optional # automatically adds a with-foo option # automatically adds a without-bar option # ... end
А чтобы определить действие 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. Примеры приведены в формуле альтернативного ffmpeg.
option-ы, которые не являются build.with? или build.without?, следует объявлять устаревшими с помощью deprecated_option. Исторический пример приведён в формуле wget.
Выполнение команд после установки
Шаги инициализации, которые не обязательно являются частью процесса установки, можно разместить в блоке post_install, например команды настройки или создания каталога данных. Этот блок можно повторно выполнить отдельно с помощью brew postinstall <formula>.
Для простой подготовки файлов используйте post_install_steps. Эти шаги хранятся в JSON API и не требуют выполнения кода Ruby формулы. Блок post_install_steps может содержать только вызовы поддерживаемых шагов с литеральными аргументами. В нём нельзя вызывать более широкий DSL формул или произвольный код Ruby.
class Foo < Formula
# ...
url "https://example.com/foo-1.0.tar.gz"
post_install_steps do
mkdir_p "log/foo"
touch "foo/state"
mv "default.conf", "foo/default.conf"
ln_s "cert.pem", "foo/cert.pem", source_base: :relative
end
# ...
end Формула может определять либо post_install_steps, либо post_install, но не оба варианта.
Шаги подготовки файлов
mkdir, mkdir_p и touch по умолчанию используют пути относительно var. Для move, mv, move_children, symlink, ln_s и ln_sf исходные и целевые пути по умолчанию задаются относительно prefix. Используйте base:, source_base: или target_base:, если шагу нужен другой путь формулы, например pkgetc; для источников относительных символических ссылок используйте source_base: :relative.
-
mkdir: создать один каталог; пример:mkdir "log/foo". -
mkdir_p: создать каталог и все отсутствующие родительские каталоги; пример:mkdir_p "log/foo". -
touch: создать файл или обновить его временную метку; пример:touch "foo/state". -
move: переместить один файл или каталог; пример:move "default.conf", "foo/default.conf". -
mv: псевдоним дляmove; пример:mv "default.conf", "foo/default.conf". -
move_children: переместить содержимое одного каталога в другой; пример:move_children "defaults", "foo/defaults". -
symlink: создать символическую ссылку; пример:symlink "cert.pem", "foo/cert.pem", source_base: :relative. -
ln_s: псевдоним дляsymlink; пример:ln_s "cert.pem", "foo/cert.pem", source_base: :relative. -
ln_sf: создать символическую ссылку или заменить существующую; пример:ln_sf "cert.pem", "foo/cert.pem", source_base: :relative.
Шаги для конфигурации по умолчанию и шаблонов
write создаёт файл конфигурации или данных по умолчанию из литерального содержимого. По умолчанию он использует тот же базовый путь, что и другие шаги подготовки файлов; передайте base: (например, base: :etc), чтобы указать другой путь формулы. По умолчанию write не перезаписывает существующий файл, поэтому изменения пользователя сохраняются при обновлениях; передайте overwrite: true, чтобы всегда заменять файл.
-
write: записать литеральное содержимое в файл, если он ещё не существует; пример:write "foo.conf", "key = value", base: :etc. -
writeсoverwrite: true: всегда заменять файл; пример:write "foo/version", "1.0", overwrite: true.
В конце добавляется символ перевода строки, если содержимое ещё не заканчивается им, поэтому записанные файлы завершаются переводом строки, как того требует POSIX.
В содержимом можно использовать фиксированный набор tokens that are expanded at install time so paths are not hardcoded into the JSON API:, ,, ,, ,, and. Любые другие `` остаются без изменений, поэтому литеральные фигурные скобки никогда не переписываются. Используйте токены вместо интерполяции Ruby, например write "foo.conf", "prefix = ", base: :etc.
Шаги перестроения данных рабочего стола и кэшей
Эти шаги перестраивают общие данные рабочего стола и кэшей с помощью инструментов, поддерживаемых Homebrew.
-
compile_gsettings_schemas: скомпилировать схемы GSettings вshare/glib-2.0/schemas. -
gio_querymodules: перестроить кэш модулей GIO вlib/gio/modules. -
gdk_pixbuf_query_loaders: обновить кэш загрузчиков GDK Pixbuf. -
gtk_update_icon_cache: обновить кэш значков GTKhicolor. -
update_mime_database: перестроить общую базу данных MIME вshare/mime. -
update_desktop_database: перестроить базу данных записей рабочего стола вshare/applications.
class Foo < Formula
# ...
url "https://example.com/foo-1.0.tar.gz"
def post_install
rm pkgetc/"cert.pem" if File.exist?(pkgetc/"cert.pem")
pkgetc.install_symlink Formula["ca-certificates"].pkgetc/"cert.pem"
end
# ...
end В приведённом выше примере формула libressl заменяет стандартный список сертификатов символической ссылкой на список из формулы ca-certificates.
Обработка файлов, которые должны сохраняться при обновлении формулы
Например, гемы Ruby 1.9 следует устанавливать в var/lib/ruby/, чтобы при обновлении Ruby не приходилось переустанавливать гемы. Обычно этого можно добиться с помощью символических ссылок или (в идеале) параметра configure.
Другой пример — файлы конфигурации, которые не следует перезаписывать при обновлении пакета. Если после установки вы обнаружили, что файлы конфигурации, которые должны сохраняться, не копируются, а связываются символическими ссылками из Cellar в $(brew --prefix)/etc/, это часто можно исправить, передав соответствующий аргумент скрипту configure пакета. Этот аргумент зависит от скрипта configure и/или Makefile конкретного пакета; например, это может быть: --sysconfdir=#{etc}
Файлы служб
Добавить в формулу файлы plist для launchd и службы systemd, чтобы brew services мог их обнаружить, можно двумя способами:
Файл службы, предоставляемый пакетом
Если пакет уже предоставляет файл службы, его можно установить в каталог prefix и указать по имени:
service do
name macos: "custom.launchd.name",
linux: "custom.systemd.name"
end Для поиска файла внутри Homebrew к имени службы launchd добавляется .plist, а к имени службы systemd — .service.
Файл службы, определённый формулой
Если формула не предоставляет файл службы, его можно создать с помощью следующего блока:
# 1. An individual command
service do
run opt_bin/"script"
end
# 2. A command with arguments
service do
run [opt_bin/"script", "--config", etc/"dir/config.yml"]
end
# 3. OS specific commands (If you omit one, the service file won't get generated for that OS.)
service do
run macos: [opt_bin/"macos_script", "standalone"],
linux: var/"special_linux_script"
end Методы блока службы
В этой таблице перечислены параметры, которые можно задавать в блоке service. Внутри блока службы необходимо определить поле run или name. Если name определено без run, Homebrew не пытается изменять файл службы, предоставленный пакетом, согласно этим полям. Поле run указывает выполняемую команду, предписывает Homebrew создать файл описания службы на основе параметров блока и поэтому обязательно для использования полей, отличных от name и require_root.
| метод | по умолчанию | macOS | Linux | описание |
|---|---|---|---|---|
run | - | да | да | выполняемая команда: массив аргументов или путь |
run_type | :immediate | да | да | тип службы: :immediate, :interval или :cron
|
interval | - | да | да | задаёт интервал запуска; требуется для типа :interval |
cron | - | да | да | задаёт время запуска; требуется для типа :cron |
keep_alive | false | да | да | задаёт условия, при которых служба будет поддерживать процесс в рабочем состоянии |
launch_only_once | false | да | да | указывает, следует ли запускать команду только один раз |
require_root | false | да | да | указывает, требуется ли службе доступ root. Если значение истинно, Homebrew в некоторых случаях предлагает использовать sudo, но не требует этого |
environment_variables | - | да | да | хеш переменных для установки |
working_dir | - | да | да | рабочий каталог |
root_dir | - | да | да | каталог, используемый как chroot для процесса |
input_path | - | да | да | путь, используемый как входные данные процесса |
log_path | - | да | да | путь для записи stdout |
error_log_path | - | да | да | путь для записи stderr |
restart_delay | - | да | да | число секунд задержки перед перезапуском процесса |
throttle_interval | - | да | не действует | минимальное время ожидания перед запусками (значение по умолчанию в macOS — 10) |
process_type | - | да | не действует | тип управляемого процесса: :background, :standard, :interactive или :adaptive
|
macos_legacy_timers | - | да | не действует | таймеры, созданные заданиями launchd, объединяются, если задано иное |
sockets | - | да | не действует | сокет, создаваемый как точка доступа к службе |
nice | - | да | да | приоритет планирования по умолчанию (уровень nice): от -20 (наивысший) до 19 (наинизший). Примечание: для отрицательных значений nice (более высокий приоритет) необходимо установить require_root: true. |
name | - | да | да | хеш с именем службы launchd в macOS и/или именем службы systemd в Linux. Если имя не задано, Homebrew создаёт имя файла службы по умолчанию |
Для служб, которые должны оставаться активными после запуска, можно использовать 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
Переменные окружения можно задать с помощью хеша. Для PATH предусмотрен вспомогательный метод 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
Параметры keep_alive
Стандартные параметры поддерживают службу в активном состоянии независимо от её состояния и обстоятельств:
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 successful_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
Формат sockets
Метод sockets принимает описание сокета в формате <type>://<host>:<port>.
-
type:udpилиtcp -
host: хост, на котором будет работать сокет, например0.0.0.0 -
port: номер порта, который должен прослушивать сокет
Обратите внимание, что по умолчанию сокеты доступны через адреса IPv4 и IPv6.
Если нужен только один сокет и его имя не имеет значения (по умолчанию используется listeners):
service do run [opt_bin/"beanstalkd", "test"] sockets "tcp://127.0.0.1:80" end
Если требуется несколько сокетов и/или нужно указать имя:
service do run [opt_bin/"beanstalkd", "test"] sockets http: "tcp://0.0.0.0:80", https: "tcp://0.0.0.0:443" end
Использование переменных окружения
В Homebrew есть несколько уровней фильтрации переменных окружения, влияющих на то, какие переменные доступны формулам.
Во-первых, общее окружение, в котором работает Homebrew, фильтруется, чтобы загрязнение окружения не приводило к сбоям сборок из исходного кода. В частности, при этом процессе сохраняются только выбранные переменные, а также переменные с префиксом HOMEBREW_. Конкретная реализация находится в bin/brew.
Второй уровень фильтрации удаляет конфиденциальные переменные окружения (например, учётные данные: ключи, пароли или токены), чтобы вредоносные подпроцессы не могли получить к ним доступ. В результате такие переменные не попадают в код Ruby формулы, поскольку фильтруются до его вызова. Конкретная реализация находится в методе ENV.clear_sensitive_environment!.
Итак, любые переменные окружения, предназначенные для использования формулой, должны соответствовать этим правилам фильтрации, чтобы быть доступными.
Установка переменных окружения во время установки
Можно устанавливать переменные окружения в блоках install или test формулы с помощью ENV["VARIABLE_NAME"] = "VALUE". Пример приведён в формуле csound.
Переменные окружения также можно временно установить с помощью метода with_env; все переменные, определённые при вызове этого метода, по завершении блока вернут исходные значения. Пример приведён в формуле gh.
Кроме того, для многих распространённых операций установки и получения переменных окружения доступны вспомогательные методы ENV, например:
-
ENV.cxx11— компилировать с включёнными возможностями C++11 -
ENV.deparallelize— компилировать только с одним заданием за раз; передайте блок, чтобы метод влиял только на определённые шаги установки -
ENV.O0,ENV.O1,ENV.O3— задать определённый уровень оптимизации компилятора (по умолчанию: macOS:-Os, Linux:-O2) -
ENV.runtime_cpu_detection— учитывать формулы, которые определяют возможности CPU во время выполнения -
ENV.append_to_cflags— добавить значение сразу вCFLAGSCXXFLAGSOBJCFLAGSOBJCXXFLAGS -
ENV.prepend_create_path— создать путь и добавить его в начало существующего списка путей -
ENV.remove— удалить строку из значения переменной окружения -
ENV.delete— удалить переменную окружения
Полный список приведён в документации модулей SharedEnvExtension и Superenv.
Объявление формулы устаревшей и её отключение
Дополнительные сведения о том, как и когда объявлять формулу, cask или код Homebrew устаревшими либо отключать их, приведены в документации «Объявление устаревшим, отключение и удаление».
Обновление формул
Когда выходит новая версия программы, используйте brew bump-formula-pr для автоматического обновления url и sha256, удаления всех строк revision и отправки pull request. Дополнительную информацию см. в документации «Как открыть pull request в Homebrew».
Устранение неполадок с новыми формулами
Сбои при определении версии
Homebrew пытается автоматически определить version по адресу url, чтобы избежать дублирования. Если у архива необычное имя, возможно, потребуется указать version вручную.
Проблемы с make-файлами
Если make-файл проекта не выполняется параллельно, попробуйте отключить параллельное выполнение, добавив следующие строки в метод install формулы:
ENV.deparallelize system "make" # separate compilation and installation steps system "make", "install"
Если это поможет, создайте issue в upstream-проекте, чтобы мы могли исправить проблему для всех.
Всё ещё не работает?
Посмотрите, как это делают MacPorts и Fink:
brew search --macports foo brew search --fink foo
Примечания о Superenv
superenv — это наша «сверхсреда», изолирующая сборки путём удаления /usr/local/bin и всех пользовательских PATH, не необходимых для сборки. Это нужно потому, что пользовательские PATH часто содержат данные, нарушающие сборки. superenv также удаляет некорректные флаги из команд, передаваемых в clang/gcc, и добавляет другие (например, все зависимости keg_only добавляются во флаги -I и -L).
Если при локальной сборке новой формулы в Homebrew возникают ошибки Operation not permitted, это означает, что новая формула попыталась записать данные на диск за пределами области песочницы. В macOS это ограничение обеспечивает sandbox-exec.
Fortran
Некоторым программам требуется компилятор Fortran. Это можно указать, добавив в формулу depends_on "gcc".
MPI
Для пакетов, которым требуется MPI, следует использовать OpenMPI, добавив в формулу depends_on "open-mpi", а не MPICH. Эти пакеты конфликтуют и предоставляют одинаковые стандартизированные интерфейсы. Выбор реализации по умолчанию и требование её использования позволяют программам связываться с несколькими библиотеками, зависящими от MPI, без неожиданных несовместимостей из-за различий сред выполнения MPI.
Библиотеки линейной алгебры
Пакеты, которым требуются интерфейсы линейной алгебры BLAS/LAPACK, должны подключать OpenBLAS, добавив depends_on "openblas" и (если сборка выполняется с помощью CMake) передав -DBLA_VENDOR=OpenBLAS в CMake, а не используя фреймворк Accelerate от Apple или стандартную эталонную реализацию lapack. Реализация BLAS/LAPACK от Apple устарела и может вызывать проблемы, которые сложно отлаживать. Эталонная формула lapack вполне подходит, хотя она активно не поддерживается и не оптимизируется.
Как начать заново (сбросить до состояния основного репозитория)
Навели настоящий беспорядок в Git и теперь не можете создать коммит, который хотите отправить нам? Возможно, стоит начать всё с чистого листа. Ваши изменения в ветке Homebrew main можно сбросить, выполнив:
git checkout -f main git reset --hard origin/HEAD
© 2009–present Homebrew contributors
Licensed under the BSD 2-Clause License.
https://docs.brew.sh/Formula-Cookbook