1 #!/usr/bin/ruby -Eutf-8
4 # Find dependencies between ruby packages
6 # Must run inside a openwrt with all *ruby* packages installed
9 RUBY_SIMPLE_VERSION
= RUBY_VERSION.split(".")[0..1].join(".")
12 puts
"Looking for installed ruby packages..."
13 packages
=`opkg list-installed '*ruby*' | cut -d' ' -f 1`.split("\n")
15 puts
"Looking for packages files..."
16 package_files
=Hash
.new
{ |h
,k
| h
[k
]=[] }
19 files
=`opkg files "#{pkg}" | sed -e 1d`.split("\n")
20 package_files
[pkg
]=files
if files
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 jar-dependencies
}
31 Encoding
.find("ASCII-8BIT"),
32 Encoding
.find("UTF-8"),
33 Encoding
.find("UTF-7"),
34 Encoding
.find("US-ASCII"),
37 puts
"Looking for requires in files..."
38 files_requires
=Hash
.new
{ |h
,k
| h
[k
]=[] }
41 package_files
[pkg
].each
do
43 next if not File
.file
?(file
)
46 if File
.executable
?(file
)
47 magic
=`head -c50 '#{file}' | head -1`
49 if not magic
=~
/ruby/
59 #puts "Checking #{file}..."
60 File
.open(file
, "r") do
63 while line
=f
.gets() do
64 lineno
+=1; encs
=[]; requires
=[]; need_encdb
=false
66 line
=line
.chomp
.gsub
!(/^[[:blank:]]*/,"")
71 enc
=line
.sub(/.*coding *: */,"").sub(/ .*/,"")
72 encs
<< Encoding
.find(enc
)
80 #puts "#{file}:#{line}"
81 if require_regex_ignore
=~ line
82 #puts "Ignoring #{line} at #{file}:#{lineno} (REGEX)..."
85 if not require_regex
=~ line
86 $stderr.puts
"Unknown require: '#{line}' at file #{file}:#{lineno}"
89 require=line
.gsub(require_regex
,"\\1")
90 require.gsub
!(/\.(so|rb)$/,"")
92 if require_ignore
.include?(require)
93 #puts "Ignoring #{line} at #{file}:#{lineno} (STR)..."
97 files_requires
[file
] += [require]
100 encs
=line
.scan(/Encoding::[[:alnum:]_]+/).collect
{|enc
| eval(enc
) }.select
{|enc
| enc
.kind_of
? Encoding
}
105 required_encs
= (encs
- builtin_enc
).collect
{|enc
| "enc/#{enc.name.downcase.gsub("-","_
")}" }
106 required_encs
<< "enc/encdb" if need_encdb
108 files_requires
[file
] += required_encs
116 package_files
.each
do |(pkg
,files
)| files
.each
do |file
|
119 files_requires
[file
]= files_requires
[file
] + ["enc/encdb"]
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
]
128 files_requires
[file
].each
do |requires
|
129 package_requires_files
[pkg
][requires
] << file
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
151 puts
"Preloading gems..."
152 Gem
::Specification.all
.each
{ |x
| gem x
.name
}
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
)|
160 requires_files
.each
do
162 if package_provides
.include?(require)
163 found
= package_provides
[require]
165 found
= package_files
.detect
{|(pkg
,files
)| files
.detect
{|file
| $
:.detect
{|path
| "#{path}/#{require}" == file
.gsub(/\
.(so
|rb
)$/,"") } } }
167 $stderr.puts
"#{pkg}: Nothing provides #{require}"
172 package_provides
[require] = found
174 if weak_dependency
[pkg
].include?(found
)
175 puts
"#{pkg}: #{found} provides #{require} (weak depedendency ignored)"
177 puts
"#{pkg}: #{found} provides #{require} for #{files.collect {|file| file.sub("/usr/lib
/ruby/","") }.join(",")}"
178 package_dependencies
[pkg
] += [found
]
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"
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
= []
191 puts
"Expanding dependencies..."
194 package_dependencies
.each
do
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
207 puts
"Removing redundant dependencies..."
208 package_dependencies
.each
do
210 package_dependencies
[pkg
]=deps
.uniq
- [pkg
]
213 puts
"Checking for mutual dependencies..."
214 package_dependencies
.each
do
217 $stderr.puts
"#{pkg}: Cycle dependency detected! "
224 package_dependencies2
=package_dependencies
.dup
225 package_dependencies
.each
do
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}"
236 if not deps
==deps_clean
237 puts
"before: #{deps.join(",")}"
238 puts
"after: #{deps_clean.join(",")}"
239 package_dependencies2
[pkg
]=deps_clean
242 package_dependencies
=package_dependencies2
244 puts
"Checking current packages dependencies..."
246 package_dependencies
.each
do
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"]
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
?
257 if not extra_dep
.empty
? or not missing_dep
.empty
?
258 $stderr.puts
"define Package/#{pkg}"
259 $stderr.puts
" DEPENDS:=ruby#{([""] +deps).join(" +")}"
264 puts
"All dependencies are OK." if ok