CocoaPods dependency tree
In the last part I mentioned about one new 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.
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 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)
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 .
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.
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 .
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.
PODS: - Moya/Core (13.0.1): # Consider only the main Moya dependency - Alamofire (~> 4.1) - Result # Skip without version - Alamofire (4.8.2)
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.
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)
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
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.
• Alamofire • Moya • Network
How to use it?
I posted the final solution on GithubGist. Also I added detailed usage help.
••• 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)
Result
- The problem was solved;
- A tree
plantedpainted; - 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.
CocoaPods dependency tree#cocoapods #ruby #tools #tech #treehttps://t.co/R9Ymre44W1 pic.twitter.com/MfRM5QvNcx
— Ну Слаааава (@swiftyfinch) June 21, 2020