Этапы сборки SwiftLint с входными и выходными файлами Xcode

07 февраля 2023

Этот репозиторий содержит пример проекта, демонстрирующий, как настроить этапы сборки SwiftLint с помощью функции файлов ввода-вывода Xcode путем определения действия перед сборкой для создания списка входных файлов для SwiftLint. Эта настройка решает новое предупреждение, появившееся в Xcode 14:

warning build: Run script build phase 'SwiftLint' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase.

предупреждение сборки: запуск фазы сборки сценария ‘SwiftLint’ будет запускаться во время каждой сборки, поскольку он не указывает никаких выходных данных. Чтобы устранить это предупреждение, либо добавьте выходные зависимости на этапе сценария, либо настройте его для запуска в каждой сборке, сняв флажок “Based on dependency analysis” на этапе сценария.

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

Оглавление

  • Что такое SwiftLint?
  • Зачем использовать файлы ввода-вывода Xcode?
  • Настройка проекта
  • Как это работает
  • Как настроить это в своём проекте
  • Обнаруженные ошибки


Что такое SwiftLint?

SwiftLint — это инструмент статического анализа кода Swift, который помогает разработчикам применять стиль и соглашения в своих проектах. Его можно запустить как фазу сборки в Xcode, чтобы автоматически проверять наличие проблем с линтингом как часть процесса сборки.

Линтинг кода — это тип статического анализа, который часто используется для поиска проблемных паттернов или кода, который не соответствует определенным рекомендациям по стилю. Для большинства языков программирования существуют линтеры кода, и компиляторы иногда включают линтинг в процесс компиляции.

 

Зачем использовать файлы ввода-вывода Xcode?

Функция файлов ввода-вывода Xcode позволяет вам указать, какие файлы следует использовать в качестве входных данных для фазы сборки, а какие файлы должны быть сгенерированы в качестве выходных. Это может быть полезно при запуске таких инструментов, как SwiftLint, поскольку позволяет запускать фазу сборки только при изменении определённых входных файлов, а не запускать её каждый раз при сборке проекта. Это может значительно сократить время сборки, особенно для этапов сборки, выполнение которых занимает много времени.

 

Настройка проекта

Важно: проект компилируется только под управлением git, поскольку скрипты используют команды git. Это означает, что вам следует клонировать репозиторий, а не загружать его в виде ZIP-файла. В противном случае скрипт предварительной сборки завершится ошибкой.

Я настроил этапы сборки SwiftLint с файлами ввода-вывода Xcode и пользовательским скриптом предварительной сборки, выполнив следующие действия:

  • Настроил SwiftLint как “Build Phase”, как описано в документации SwiftLint.
  • Добавил новый скрипт сборки предварительного действия в разделе Edit Scheme -> Build -> Pre-actions под названием "Generate build phase file lists".
  • Выбрал свою схему в раскрывающемся меню "Provide build settings from"

 Скриншот 27.12.2022 в 16:30:17

  • Добавил следующий код для скрипта предварительной сборки:

cd $SOURCE_ROOT
${SOURCE_ROOT}/generate_swifttlint_filelist.sh

 

  • Добавил  файл скрипта generate_swifttlint_filelist.sh в проект.
  • Для всех трёх target (SwiftlintBuildPhase, SwiftlintBuildPhaseTests, SwiftlintBuildPhaseUITests) установил флажок "Based on dependency analysis" на этапе сборки SwiftLint.
  • Настроил списки входных файлов и выходные данные для каждого target на этапах сборки, используя соответствующий сгенерированный файл:

Скриншот 27 декабря 2022 г. в 16:43:23

  • Дважды нажал Cmd+U в проекте и проверил время сборки в Report Navigator (навигатор отчётов). Нажал Control+Option+Cmd+Enter, чтобы отобразить временную шкалу последних сборок и убедиться, что Xcode не запускал SwiftLint, когда ни один файл не изменился:

Скриншот 27 декабря 2022 г. в 16 51 59

  • Добавил новый файл .swift (или изменил файл .swift). Нажал Cmd+U ещё раз и убедился, что Xcode запускает SwiftLint только для target, в котором произошло изменение:

Скриншот 27.12.2022 в 17 01 50

 

 

Как это работает

Xcode требуется список входных файлов для этапа сборки SwiftLint, чтобы определить, когда запускать SwiftLint. Нам необходимо запускать SwiftLint всякий раз, когда мы меняем файл swift в текущем target или добавляем новый файл в проект. К сожалению, мы не можем определить папку как список входных файлов, поэтому мы должны определить список файлов с путями ко всем исходным файлам Swift. Поскольку список исходных файлов меняется, когда мы добавляем, удаляем или переименовываем файлы, нам необходимо динамически генерировать список входных файлов перед каждой сборкой. Это именно то, что делает generate_swifttlint_filelist.sh , который запускается как скрипт сборки перед действием.

Я добавил комментарии к файлу скрипта, но вот обзор того, что он делает:

  • Скрипт сравнивает текущий git diff с git diff из предыдущей сборки и определяет, были ли какие-либо изменения в списке файлов swift, например: added (добавлено), deleted (удалено) или renamed (переименовано).
  • Если со времени последней сборки произошли изменения, он генерирует новый список входных файлов для всех target.
  • Если нет изменений, он ничего не делает.
  • Скрипт создает список входных файлов (.xcfilelist) и список выходных файлов для каждого target, определенного в переменной swiftlint_dirs.
  • Скрипт генерирует эти файлы в папку/build/build_phases, которую git игнорирует.

 

 

Как настроить это в своем проекте

Следуйте настройке, определенной в Project setup . Всё, что вам нужно изменить, — это переменную swiftlint_dirs, соответствующую вашим исходным папкам, и настроить правильный список файлов ввода-вывода на этапе сборки SwiftLint вашего target. Вы также можете изменить расположение сгенерированных файлов.

 

 

Обнаруженные ошибки

В Xcode есть ошибка, связанная с обработкой общих xcschemes, где определён скрипт предварительного действия. Когда мы переключаем ветки между двумя ветками, в одной из которых определен скрипт предварительного действия, а в другой нет, он не обновляет изменения из новой ветки, но сохраняет старый. Это может вызвать ошибку в журналах сборки или сбой сборки. Перезапуск Xcode и отмена изменений в файле .xcodeproj решает эту проблему.
Эта проблема исчезнет, как только во всех ветвях появится новое определение сборки перед действие
 

Оригинал статьи

Содержание