ruby_find_pkgsdeps (8095B)
1 #!/usr/bin/ruby -Eutf-8 2 # encoding: utf-8 3 # 4 # Find dependencies between ruby packages 5 # 6 # Must run inside a openwrt with all *ruby* packages installed 7 # 8 9 RUBY_SIMPLE_VERSION = RUBY_VERSION.split(".")[0..1].join(".") 10 failed = false 11 12 puts "Looking for installed ruby packages..." 13 packages=`opkg list-installed '*ruby*' | cut -d' ' -f 1`.split("\n") 14 15 puts "Looking for packages files..." 16 package_files=Hash.new { |h,k| h[k]=[] } 17 packages.each do 18 |pkg| 19 files=`opkg files "#{pkg}" | sed -e 1d`.split("\n") 20 package_files[pkg]=files if files 21 end 22 23 require_regex=/^require ["']([^"']+)["'].*/ 24 require_regex_ignore=/^require ([a-zA-Z\$]|["']$|.*\/$)/ 25 require_ignore=%w{drb/invokemethod16 foo rubygems/defaults/operating_system win32console java Win32API 26 builder/xchar json/pure simplecov win32/sspi rdoc/markdown/literals_1_8 enumerator win32/resolv rbtree 27 nqxml/streamingparser nqxml/treeparser xmlscan/parser xmlscan/scanner xmltreebuilder xml/parser xmlparser xml/encoding-ja xmlencoding-ja 28 iconv uconv win32ole gettext/po_parser gettext/mo libxml psych.jar psych_jars jar-dependencies thread minitest/proveit} 29 30 builtin_enc=[ 31 Encoding.find("ASCII-8BIT"), 32 Encoding.find("UTF-8"), 33 Encoding.find("UTF-7"), 34 Encoding.find("US-ASCII"), 35 ] 36 37 puts "Looking for requires in files..." 38 files_requires=Hash.new { |h,k| h[k]=[] } 39 packages.each do 40 |pkg| 41 package_files[pkg].each do 42 |file| 43 next if not File.file?(file) 44 45 if not file =~ /.rb$/ 46 if File.executable?(file) 47 magic=`head -c50 '#{file}' | head -1` 48 begin 49 if not magic =~ /ruby/ 50 next 51 end 52 rescue 53 next 54 end 55 else 56 next 57 end 58 end 59 #puts "Checking #{file}..." 60 File.open(file, "r") do 61 |f| 62 lineno=0 63 while line=f.gets() do 64 lineno+=1; encs=[]; requires=[]; need_encdb=false 65 66 line=line.chomp.gsub!(/^[[:blank:]]*/,"") 67 68 case line 69 when /^#.*coding *:/ 70 if lineno <= 2 71 enc=line.sub(/.*coding *: */,"").sub(/ .*/,"") 72 encs << Encoding.find(enc) 73 end 74 end 75 line.gsub!(/#.*/,"") 76 case line 77 when "__END__" 78 break 79 when /^require / 80 #puts "#{file}:#{line}" 81 if require_regex_ignore =~ line 82 #puts "Ignoring #{line} at #{file}:#{lineno} (REGEX)..." 83 next 84 end 85 if not require_regex =~ line 86 $stderr.puts "Unknown require: '#{line}' at file #{file}:#{lineno}" 87 failed=true 88 end 89 require=line.gsub(require_regex,"\\1") 90 require.gsub!(/\.(so|rb)$/,"") 91 92 if require_ignore.include?(require) 93 #puts "Ignoring #{line} at #{file}:#{lineno} (STR)..." 94 next 95 end 96 97 files_requires[file] += [require] 98 99 when /Encoding::/ 100 encs=line.scan(/Encoding::[[:alnum:]_]+/).collect {|enc| eval(enc) }.select {|enc| enc.kind_of? Encoding } 101 need_encdb=true 102 end 103 104 next if encs.empty? 105 required_encs = (encs - builtin_enc).collect {|enc| "enc/#{enc.name.downcase.gsub("-","_")}" } 106 required_encs << "enc/encdb" if need_encdb 107 108 files_requires[file] += required_encs 109 end 110 end 111 end 112 end 113 exit(1) if failed 114 115 # Add deps from .so 116 package_files.each do |(pkg,files)| files.each do |file| 117 case file 118 when /\/nkf\.so$/ 119 files_requires[file]= files_requires[file] + ["enc/encdb"] 120 end 121 end; end 122 123 puts "Grouping package requirements per package" 124 package_requires_files = Hash.new{|h,k| h[k] = Hash.new { |h2,k2| h2[k2] = [] } } 125 package_files.each do |(pkg,files)| 126 package_requires_files[pkg] 127 files.each do |file| 128 files_requires[file].each do |requires| 129 package_requires_files[pkg][requires] << file 130 end 131 end 132 end 133 134 weak_dependency=Hash.new { |h,k| h[k]=[] } 135 weak_dependency.merge!({ 136 "ruby-misc"=>["ruby-openssl","ruby-fiddle"], #securerandom.rb 137 "ruby-debuglib"=>["ruby-readline"], #debug.rb 138 "ruby-drb"=>["ruby-openssl"], #drb/ssl.rb 139 "ruby-irb"=>["ruby-rdoc", "ruby-readline"], #irb/cmd/help.rb 140 "ruby-gems"=>["ruby-openssl","ruby-io-console","ruby-webrick"], #rubygems/commands/cert_command.rb rubygems/user_interaction.rb rubygems/server.rb 141 "ruby-mkmf"=>["ruby-webrick"], #un.rb 142 "ruby-net"=>["ruby-openssl","ruby-io-console","ruby-zlib"], #net/*.rb 143 "ruby-optparse"=>["ruby-uri","ruby-datetime"], #optparse/date.rb optparse/uri.rb 144 "ruby-rake"=>["ruby-net","ruby-gems"], #rake/contrib/ftptools.rb /usr/bin/rake 145 "ruby-rdoc"=>["ruby-gems","ruby-readline","ruby-webrick", #/usr/bin/rdoc and others 146 "ruby-io-console"], #rdoc/stats/normal.rb 147 "ruby-webrick"=>["ruby-openssl"], #webrick/ssl.rb 148 "ruby-testunit"=>["ruby-io-console"], #gems/test-unit-3.1.5/lib/test/unit/ui/console/testrunner.rb 149 }) 150 151 puts "Preloading gems..." 152 Gem::Specification.all.each{ |x| gem x.name } 153 154 puts "Looking for package dependencies..." 155 package_provides = {} 156 package_dependencies = Hash.new { |h,k| h[k]=[] } 157 package_requires_files.each do 158 |(pkg,requires_files)| 159 160 requires_files.each do 161 |(require,files)| 162 if package_provides.include?(require) 163 found = package_provides[require] 164 else 165 found = package_files.detect {|(pkg,files)| files.detect {|file| $:.detect {|path| "#{path}/#{require}" == file.gsub(/\.(so|rb)$/,"") } } } 166 if not found 167 $stderr.puts "#{pkg}: Nothing provides #{require} for #{files.collect {|file| file.sub("/usr/lib/ruby/","") }.join(",")}" 168 failed = true 169 next 170 end 171 found = found.first 172 package_provides[require] = found 173 end 174 if weak_dependency[pkg].include?(found) 175 puts "#{pkg}: #{found} provides #{require} (weak depedendency ignored)" 176 else 177 puts "#{pkg}: #{found} provides #{require} for #{files.collect {|file| file.sub("/usr/lib/ruby/","") }.join(",")}" 178 package_dependencies[pkg] += [found] 179 end 180 end 181 end 182 if failed 183 puts "There is some missing requirements not mapped to files in packages." 184 puts "Please, fix the missing files or ignore them on require_ignore var" 185 exit(1) 186 end 187 # Remove self dependency 188 package_dependencies = Hash[package_dependencies.collect {|(pkg,deps)| [pkg,package_dependencies[pkg]=deps.uniq.sort - [pkg]]}] 189 package_dependencies.default = [] 190 191 puts "Expanding dependencies..." 192 begin 193 changed=false 194 package_dependencies.each do 195 |(pkg,deps)| 196 next if deps.empty? 197 deps_new = deps.collect {|dep| [dep] + package_dependencies[dep] }.inject([],:+).uniq.sort 198 if not deps == deps_new 199 puts "#{pkg}: #{deps.join(",")}" 200 puts "#{pkg}: #{deps_new.join(",")}" 201 package_dependencies[pkg]=deps_new 202 changed=true 203 end 204 end 205 end if not changed 206 207 puts "Removing redundant dependencies..." 208 package_dependencies.each do 209 |(pkg,deps)| 210 package_dependencies[pkg]=deps.uniq - [pkg] 211 end 212 213 puts "Checking for mutual dependencies..." 214 package_dependencies.each do 215 |(pkg,deps)| 216 if deps.include? pkg 217 $stderr.puts "#{pkg}: Cycle dependency detected! " 218 failed = true 219 end 220 end 221 exit(1) if failed 222 223 224 package_dependencies2=package_dependencies.dup 225 package_dependencies.each do 226 |(pkg,deps)| 227 228 # Ignore dependencies that are already required by another dependency 229 deps_clean = deps.reject {|dep_suspect| deps.detect {|dep_provider| 230 if package_dependencies[dep_provider].include?(dep_suspect) 231 puts "#{pkg}: #{dep_suspect} is already required by #{dep_provider}" 232 true 233 end 234 } } 235 236 if not deps==deps_clean 237 puts "before: #{deps.join(",")}" 238 puts "after: #{deps_clean.join(",")}" 239 package_dependencies2[pkg]=deps_clean 240 end 241 end 242 package_dependencies=package_dependencies2 243 244 puts "Checking current packages dependencies..." 245 ok=true 246 package_dependencies.each do 247 |(pkg,deps)| 248 current_deps=`opkg depends #{pkg} | sed -r -e '1d;s/^[[:blank:]]*//'`.split("\n") 249 current_deps.reject!{|dep| dep =~ /^lib/ } 250 current_deps -= ["ruby"] 251 252 extra_dep = current_deps - deps 253 $stderr.puts "Package #{pkg} does not need to depend on #{extra_dep.join(" ")} " if not extra_dep.empty? 254 missing_dep = deps - current_deps 255 $stderr.puts "Package #{pkg} needs to depend on #{missing_dep.join(" ")} " if not missing_dep.empty? 256 257 if not extra_dep.empty? or not missing_dep.empty? 258 $stderr.puts "define Package/#{pkg}" 259 $stderr.puts " DEPENDS:=ruby#{([""] +deps).join(" +")}" 260 ok=false 261 end 262 end 263 264 puts "All dependencies are OK." if ok 265 266 __END__