You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
7.5 KiB

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