Дерево зависимостей CocoaPods
В прошлой части я упомянул об одной идее . Недавно мне потребовалось определить порядок поднятия зависимостей CocoaPods в рабочем проекте. В этом посте я расскажу как сделать это с помощью Ruby.
Цель
Есть большой проект со своим репозиторием зависимостей. Нужно поднять минорную или мажорную версию к примеру, Alamofire.
- Скорее всего от такой популярной библиотеки зависит много других подов. Чтобы поднять версию в проекте, необходимо поднять версию Alamofire во всех зависимостях;
- Все это усложняется тем, что под может не напрямую зависеть от Alamofire, а косвенно через другие зависимости;
- Поднимать версии зависимостей нужно в определенной последовательности. Иначе ничего не выйдет;
- У каждой зависимости может быть свой отдельный репозиторий. Из-за этого неудачная попытка поднять версию может затянуться;
- CocoaPods показывает только одну ошибку несовместимости версий:
••• pods installIn Podfile: Core (~> 2.1.4) was resolved to 2.1.4, which depends on Network (~> 2.0.1) Authorization (~> 1.1.3) was resolved to 1.1.3, which depends on Network (~> 1.1.0)
Идея
Давайте напишем небольшую утилиту, которой в качестве аргумента будем указывать имя пода. Затем она разберется в какой последовательности нужно поднимать версии зависимостей. И в конце, для наглядности нарисует нам простое дерево .
Для этого нам нужно:
- Найти все зависимости (к счастью, они уже есть в Podfile.lock);
- Построить дерево зависимостей;
- Построить поддерево, корнем которого будет указанный под;
- Нарисовать это дерево.
Ниже я очень поверхностно опишу идею работы такой утилиты. Если у вас останутся вопросы, то смело задавайте их мне в Twitter. Также я не претендую на оптимальное решение и буду рад если вы предложите улучшение.
Выбор языка
Для решения этой задачи я выбрал язык Ruby.
- Он проще чем Bash;
- Утилиту можно легко отредактировать и запустить;
- Не нужно компилировать;
- Также можно использовать через Fastlane .
Разбор Podfile.lock
Для начала нам нужно разобрать часть Podfile.lock. Пропускаем все зависимости без версий, так как их поднимать не надо. Все зависимости вида Moya/Core считаем одной зависимостью Moya. И затем строим дерево.
Рассмотрим небольшой пример. Получаем дерево с корнем Alamofire. У корня один ребенок Moya. Также ребенок знает, что его родитель Alamofire.
PODS: - Moya/Core (13.0.1): # Учитываем лишь основное название Moya - Alamofire (~> 4.1) - Result # Пропускаем без версии - Alamofire (4.8.2)
Шаг за шагом
Когда дерево готово, нам нужно построить в нем поддерево с указанным подом в корне. Для этого сначала определим всех родителей указанного пода. Затем будем рассматривать детей каждого родителя и пытаться найти пересечение детей и остальных родителей. Если пересечения нет, то это означает у нас нет блокирующих зависимостей.
Другими словами, мы можем поднять версию у рассмотренного родителя на первом шаге. Затем исключаем таких родителей и повторяем поиск уже второго шага. И так далее.
Рассмотрим простой пример. Родители Alamofire: Moya и Network. У Network есть ребенок Moya, который пересекается с родителями. А у Moya пересечения нет. Поэтому на первый шаг попадет Moya, а на второй Network.
PODS: - Alamofire (1.0.0) - Network (1.0.0): - Moya (= 1.0.0) - Alamofire (= 1.0.0) - Moya (1.0.0): - Alamofire (= 1.0.0)
Дерево из шагов
Чтобы построить дерево, нужно после определения всех зависимостей для текущего шага рассмотреть детей у каждой зависимости. Найти таких детей, которые были определены на предыдущем шаге. Они станут родителями для рассматриваемой зависимости.
И снова небольшой пример. Воспользуемся данными из секции выше. Alamofire в корне. Затем на первом шаге у нас Moya, так как её ребенком является Alamofire и он есть на прошлом шаге (в корне). Затем Network, так как у него два ребенка Alamofire и Moya. Но только Moya находится на предыдущем шаге.
Alamofire ➡︎ Moya ➡︎ Network
Рисуем
Задача уже решена, но осталось нарисовать дерево. Для этого будем спускаться от корня вниз. На каждом шаге перебираем всех детей и запускаемся от них рекурсивно. И добавим немного красок.
• Alamofire • Moya • Network
Как использовать
Финальное решение я выложил на GithubGist. Также я добавил подробную справку по использованию.
••• ruby PodTree.rb helpTiny utility for visualise Pod dependencies tree.Skips subspecs and pods without versions.Help options: ["-h", "--help", "help"] • 1st argument will be used as root Pod • 2nd one is path to Podfile (pwd by default)
ruby PodTree.rb A Podfile.lockPodfile.lock: Output:- A (1.0.0) • A- B (1.0.0): • D - A (= 1.0.0) • C - C (= 1.0.0) • B - D (= 1.0.0) • E- C (1.0.0): - A (= 1.0.0) - D (= 1.0.0)- D (1.0.0): - A (= 1.0.0)- E (1.0.0): - A (= 1.0.0) - D (= 1.0.0)
Результат
- Проблема решена;
- Дерево
посаженонарисовано; - Рад был поделиться решением с вами;
- Напишите мне, если у вас есть вопросы или идеи по улучшению.
Всем спасибо за внимание! Надеюсь пост вам понравился. А на этом пока всё.
Начинаю проходить Last of Us 2 и скоро буду смотреть WWDC 2020 .
💬 Пожалуйста, оставьте любой фидбек в этом твите.
Это поможет мне улучшить посты и продолжить писать новые.
Опубликовал новый пост
— Ну Слаааава (@swiftyfinch) June 20, 2020
Дерево зависимостей CocoaPods#cocoapods #ruby #tools #tech #treehttps://t.co/DwtJ4T6hHe pic.twitter.com/WbWCT5gMJI