CocoaPods dependency tree tree

3 min

In the last part I mentioned about one new idea idea. Recently, I needed to sort out the order of bumping CocoaPods dependencies in a working project. In this post, I will describe how you can do it using Ruby.

aim Goal

There is a huge project with its CocoaPods dependency repository. You need to bump the minor or major version, for example, Alamofire.

  • Most likely, many other pods depend on such a popular library. To bump the version in the project, it is necessary to bump the Alamofire version in all dependencies;
  • Also, there can be a lot of indirect Alamofire dependencies;
  • Need to bump dependencies versions in a certain sequence. Otherwise, nothing will come of it;
  • Each dependency can have a separate repository. Because of this, an unsuccessful attempt to bump the version may be delayed;
  • CocoaPods shows only one version incompatibility error:
pods install
In 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)

idea Idea

Let's write a tiny utility and will pass as an argument the name of the pod. Then it will figure out in what order to bump the dependencies versions. And in the end, for clarity, this utility will draw a simple tree tree.

For this we need to do:

  • Find all the dependencies (fortunately, they are already in Podfile.lock);
  • Build a dependency tree;
  • Build a subtree which root will be specified as argument pod;
  • Draw this tree.

Below I will lightly describe the idea of ​​how such utility works. If you still have questions, feel free to ask me on Twitter. Also, I do not pretend to have the optimal solution and I am open for your improvement suggestions.

ruby Language

To solve this problem, I chose Ruby language.

  • It is easier than Bash from last posts;
  • The utility can be easily edited and run;
  • No need to compile;
  • Also, it can be used through Fastlane rocket.

bricks Parsing Podfile.lock

First, we need to parse the part of Podfile.lock. We skip all dependencies without versions since they do not need to be bumped. All sub dependencies of the form Moya/Core are considered as one dependency Moya. And then we build a tree.

Let's look at an easy example. We get the tree with the root Alamofire. The root has one child Moya. Also, the child knows that his parent Alamofire.

- Moya/Core (13.0.1): # Consider only the main Moya dependency
- Alamofire (~> 4.1)
- Result # Skip without version
- Alamofire (4.8.2)

map Step by step

When the main tree is built, we need to find out a subtree with the specified pod in the root. To do this, we first determine all parents of the specified pod. Then we will consider the children of each parent and try to find the intersection of the children and the rest of the parents. If there is no intersection, then this means we have no blocking dependencies.

In other words, we can bump the version from the considered parent in the first step. Then exclude such parents and repeat the search for the second step. And so on.

Let's look at a simple example. The parents of Alamofire: Moya and Network. Network has a child Moya which crosses with parents. And Moya has no intersection. So, the first step will contain Moya and the second Network.

- Alamofire (1.0.0)
- Network (1.0.0):
- Moya (= 1.0.0)
- Alamofire (= 1.0.0)
- Moya (1.0.0):
- Alamofire (= 1.0.0)

tree Steps tree

After found out all the dependencies for the current step, need to consider the children of each dependency. Find children which were determined in the previous step. They will become parents for the current dependency.

And again let's look at a small example. We will use the data from the section above. Alamofire at the root. Then at the first step, we have Moya, because it has child Alamofire and it was at the last step (in the root). Then Network, because it has two children Alamofire and Moya. But only Moya was in the previous step.

Alamofire ➡︎ Moya ➡︎ Network

draw Let's draw

The main task has already been solved, but it remains to draw a tree. Let's go down from the root. Look at each child and start from it recursively. And also add some paints.


rocket How to use it?

I posted the final solution on GithubGist. Also I added detailed usage help.

ruby PodTree.rb help
Tiny 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.lock
Podfile.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)

party Result

  • The problem was solved;
  • A tree tree planted painted;
  • I was glad to share this solution with you;
  • Twit me if you have questions or improvement ideas.

Thank you all for your attention! I hope you enjoyed the post. And that's all for now.
I'm starting to play Last of Us 2 and going to watch WWDC 2020 soon.

💬 Please, leave some feedback in Twitter post.
It will help me improve posts and continue to publish new ones.