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.

265 lines
7.4 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}
  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"], #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", #rubygems/commands/cert_command.rb rubygems/user_interaction.rb
  115. "ruby-minitest", "ruby-webrick"], #rubygems/test_case.rb rubygems/server.rb
  116. "ruby-mkmf"=>["ruby-webrick"], #un.rb
  117. "ruby-net"=>["ruby-openssl","ruby-io-console","ruby-zlib"], #net/*.rb
  118. "ruby-optparse"=>["ruby-uri","ruby-datetime"], #optparse/date.rb optparse/uri.rb
  119. "ruby-rake"=>["ruby-net","ruby-testunit","ruby-gems"], #rake/contrib/ftptools.rb rake/runtest.rb /usr/bin/rake
  120. "ruby-rdoc"=>["ruby-gems","ruby-readline","ruby-webrick",
  121. "ruby-minitest"], #/usr/bin/rdoc and others
  122. "ruby-testunit"=>["ruby-gems", "ruby-io-console"], #test/unit/parallel.rb test/unit.rb
  123. "ruby-webrick"=>["ruby-openssl"], #webrick/ssl.rb
  124. })
  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}: Nobody 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. exit(1) if failed
  153. package_dependencies.each do
  154. |(pkg,deps)|
  155. package_dependencies[pkg]=deps.uniq.sort - [pkg]
  156. end
  157. puts "Expanding dependencies..."
  158. begin
  159. changed=false
  160. package_dependencies.each do
  161. |(pkg,deps)|
  162. next if deps.empty?
  163. deps_new = deps.collect {|dep| [dep] + package_dependencies[dep] }.inject([],:+).uniq.sort
  164. if not deps == deps_new
  165. puts "#{pkg}: #{deps.join(",")}"
  166. puts "#{pkg}: #{deps_new.join(",")}"
  167. package_dependencies[pkg]=deps_new
  168. changed=true
  169. end
  170. end
  171. end if not changed
  172. puts "Checking for mutual dependencies..."
  173. package_dependencies.each do
  174. |(pkg,deps)|
  175. if deps.include? pkg
  176. $stderr.puts "#{pkg}: Cycle dependency detected! "
  177. failed = true
  178. end
  179. end
  180. exit(1) if failed
  181. puts "Removing redundant dependencies..."
  182. package_dependencies.each do
  183. |(pkg,deps)|
  184. package_dependencies[pkg]=deps.uniq - [pkg]
  185. end
  186. package_dependencies2=package_dependencies.dup
  187. package_dependencies.each do
  188. |(pkg,deps)|
  189. # Ignore dependencies that are aready required by another dependency
  190. deps_clean = deps.reject {|dep_suspect| deps.detect {|dep_provider|
  191. if package_dependencies[dep_provider].include?(dep_suspect)
  192. puts "#{pkg}: #{dep_suspect} is already required by #{dep_provider}"
  193. true
  194. end
  195. } }
  196. if not deps==deps_clean
  197. puts "before: #{deps.join(",")}"
  198. puts "after: #{deps_clean.join(",")}"
  199. package_dependencies2[pkg]=deps_clean
  200. end
  201. end
  202. package_dependencies=package_dependencies2
  203. puts "Checking current packages dependencies..."
  204. ok=true
  205. package_dependencies.each do
  206. |(pkg,deps)|
  207. current_deps=`opkg depends #{pkg} | sed -r -e '1d;s/^[[:blank:]]*//'`.split("\n")
  208. current_deps.reject!{|dep| dep =~ /^lib/ }
  209. current_deps -= ["ruby"]
  210. extra_dep = current_deps - deps
  211. $stderr.puts "Package #{pkg} does not need to depend on #{extra_dep.join(" ")} " if not extra_dep.empty?
  212. missing_dep = deps - current_deps
  213. $stderr.puts "Package #{pkg} need to depend on #{missing_dep.join(" ")} " if not missing_dep.empty?
  214. if not extra_dep.empty? or not missing_dep.empty?
  215. $stderr.puts "define Package/#{pkg}"
  216. $stderr.puts " DEPENDS:=ruby#{([""] +deps).join(" +")}"
  217. ok=false
  218. end
  219. end
  220. puts "All dependencies are OK." if ok
  221. __END__
  222. puts RUBY_VERSION, RUBY_PLATFORM
  223. puts 123
  224. puts Object.contants
  225. #RUBY_VER=2.1
  226. #RUBY_ARCH=i486-linux-gnu
  227. #RUBYLIB=/usr/lib/ruby/$RUBY_VER/
  228. #RUBYLIB_A=/usr/lib/ruby/$RUBY_ARCH/$RUBY_VER/