├── PodTree.rb ├── Preview.png └── README.md /PodTree.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | # Created by Vyacheslav Khorkov on 17.07.2020. 4 | # Copyright © 2020 Vyacheslav Khorkov. All rights reserved. 5 | 6 | require 'set' 7 | 8 | # Constants 9 | OUTPUT_BULLET = "•" 10 | OUTPUT_BULLET_COLORS = [9, 3, 2, 75, 99] 11 | 12 | # Help information 13 | HELP_COMMANDS = ["-h", "--help", "help"] 14 | def putsHelp() 15 | puts "Tiny utility for visualise Pod dependencies tree.".colorize(2) 16 | puts "Skips subspecs and pods without versions.".colorize(2) 17 | puts "Help options: #{HELP_COMMANDS}" 18 | puts " • 1st argument will be used as root Pod".colorize(3) 19 | puts " • 2nd one is path to Podfile (pwd by default)\n".colorize(3) 20 | puts "ruby PodTree.rb A Podfile.lock".colorize(3) 21 | puts "Podfile.lock:".colorize(2) + " Output:".colorize(2) 22 | margin = " " 23 | puts "- A (1.0.0)" + margin + "•".colorize(9) + " A" 24 | puts "- B (1.0.0):" + margin + " •".colorize(3) + " D" 25 | puts " - A (= 1.0.0)" + margin + "•".colorize(2) + " C" 26 | puts " - C (= 1.0.0)" + margin + " •".colorize(75) + " B" 27 | puts " - D (= 1.0.0)" + margin + "•".colorize(2) + " E" 28 | puts "- C (1.0.0):" 29 | puts " - A (= 1.0.0)" 30 | puts " - D (= 1.0.0)" 31 | puts "- D (1.0.0):" 32 | puts " - A (= 1.0.0)" 33 | puts "- E (1.0.0):" 34 | puts " - A (= 1.0.0)" 35 | puts " - D (= 1.0.0)" 36 | end 37 | 38 | # Class describing Pod 39 | class Pod 40 | attr_reader :name, :parents, :children 41 | def initialize(name) 42 | @name = name 43 | @parents = Set.new; @children = Set.new 44 | end 45 | end 46 | 47 | # Parsing 48 | def parsePodfile(pod_file) 49 | currentPod = nil 50 | pods = Hash.new 51 | File.readlines(pod_file).each do |line| 52 | next if line.start_with?("PODS:") 53 | break if line.start_with?("DEPENDENCIES:") 54 | 55 | if line.start_with?(" -") # Parents 56 | parts = line.split(" ") 57 | name = parts[1].split("/")[0] 58 | 59 | unless pods.has_key?(name) 60 | pods[name] = Pod.new(name) 61 | end 62 | currentPod = pods[name] 63 | elsif line.start_with?(" -") # Childs 64 | parts = line.split(" ") 65 | next if parts.count == 2 # Skip without version 66 | name = parts[1].split("/")[0] 67 | 68 | unless pods.has_key?(name) 69 | pods[name] = Pod.new(name) 70 | end 71 | pods[name].parents.add(currentPod) 72 | currentPod.children.add(pods[name]) 73 | end 74 | end 75 | return pods 76 | end 77 | 78 | # Create dependecies tree 79 | def buildTree(pods, pod_name) 80 | root = Pod.new(pod_name) 81 | last = { root.name => root } 82 | 83 | names = pods[pod_name].parents.map { |pod| pod.name }.to_set 84 | names.delete(pod_name) 85 | while !names.empty? do 86 | step = Set.new 87 | 88 | # Calculate step 89 | names.each { |name| 90 | podNames = pods[name].children.map { |pod| pod.name }.to_set 91 | podNames.delete(name) # Remove subspecs intersection 92 | if podNames.intersection(names).empty? 93 | step.add(name) 94 | end 95 | } 96 | if step.empty? 97 | STDERR.puts("Can't build a step.".colorize(9)) 98 | exit(false) 99 | end 100 | 101 | # Build tree level 102 | new = Hash.new 103 | step.each { |name| 104 | pods[name].children.each { |pod| 105 | if last.has_key?(pod.name) 106 | newPod = Pod.new(name) 107 | last[pod.name].children.add(newPod) 108 | new[name] = newPod 109 | end 110 | } 111 | } 112 | last = new 113 | names.subtract(step) 114 | end 115 | return root 116 | end 117 | 118 | # Colorize output 119 | class String 120 | def colorize(color_code) 121 | "\e[38;5;#{color_code}m#{self}\e[0m" 122 | end 123 | end 124 | 125 | # Output tree recursively 126 | def putsTree(root, level = 0, bullet, colors) 127 | if level != 0 128 | prefix = " " * (level - 1) + bullet 129 | color = colors[(level - 1) % colors.count] 130 | puts prefix.colorize(color) + " " + root.name 131 | end 132 | root.children.each { |pod| 133 | putsTree(pod, level + 1, bullet, colors) 134 | } 135 | end 136 | 137 | # === Main === 138 | # Check if 1st argument is help 139 | if HELP_COMMANDS.include?ARGV[0] 140 | putsHelp() 141 | exit(false) 142 | end 143 | 144 | # Get input arguments 145 | POD_NAME = ARGV[0] 146 | POD_FILE = ARGV[1] || "Podfile.lock" 147 | 148 | # Parse Podfile 149 | PODS = parsePodfile(POD_FILE) 150 | unless PODS.has_key?(POD_NAME) 151 | STDERR.puts("Can't find pod name.".colorize(9)) 152 | putsHelp() 153 | exit(false) 154 | end 155 | 156 | # Build and output tree 157 | TREE = buildTree(PODS, POD_NAME) 158 | putsTree(TREE, 1, OUTPUT_BULLET, OUTPUT_BULLET_COLORS) 159 | -------------------------------------------------------------------------------- /Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftyfinch/PodTree/25841781f65e0e86068cac5b56f5b19c1bf8d3ed/Preview.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 🌳 Tiny utility for visualising [#CocoaPods](https://github.com/CocoaPods/CocoaPods) dependencies tree.\ 4 | More information [here](https://swiftyfinch.github.io/en/2020-06-20-pod-tree/). 5 | 6 | ## Author 7 | 8 | Vyacheslav Khorkov\ 9 | Twitter: [@SwiftyFinch](https://twitter.com/swiftyfinch)\ 10 | Blog: [swiftyfinch.github.io](https://swiftyfinch.github.io/en)\ 11 | Feel free to contact me 📮 12 | --------------------------------------------------------------------------------