Using GGem#ebuild_name to standardize gem names
[g-gem.git] / g-gem.rb
blob68d2d7325939f4f51c13bdad507b9d8bf194821e
1 require 'portage'
2 require 'depatom'
3 require 'ebuild'
5 module GGem
6   @@gri = nil
7   @@sources = nil
9   SHORTMAP = {
10     'p' => :pretend,
11     'h' => :help,
12     'v' => :verbose,
13   }
14   
15   LONGMAP = {
16     'prepend' => :pretend,
17     'verbose' => :verbose,
18     'help' => :help,
19     'generate' => :generate,
20     'madgen' => :mass_generate,
21   }
23   SPECIAL_MAPS = {
24     'BlueCloth' => 'bluecloth',
25     'KirbyBase' => 'kirbybase',
26     'libxml-ruby' => 'libxml',
27     'RedCloth' => 'redcloth',
28     'mega' => 'mega-modules',
29     'nano' => 'nano-methods',
30     'gettext' => 'ruby-gettext',
31     'snmp' => 'snmplib',
32     'ZenTest' => 'zentest',
33     'NGSLib-RFile' => 'ngslib-rfile',
34     'tRuTag' => 'trutag',
35   }
37   class << self
39     attr_accessor :options
41     def main
42       @options, packages = parse_opts(ARGV)
43       Portage.setup_overlay(options[:pretend] || options[:mass_generate])
45       if options[:mass_generate] == true
46         mass_generate
47         puts "Ebuilds are in #{Portage.rubydev_overlay}"
48         return
49       end
51       spec_groups = packages.map {|pkg| get_specs(pkg)}
52       all_specs = spec_groups.flatten
53       if all_specs.empty?
54         puts "No package found"
55         return
56       end
58       ebuilds = []
59       for spec in all_specs
60         puts "Create ebuild for #{spec.full_name}" if options[:verbose]
61         gem_ebuild = Ebuild.new(spec)
62         gem_ebuild.write
63         ebuilds << gem_ebuild
64       end
65       # No prepend, digest the ebuilds
66       if options[:pretend] == false
67         ebuilds.each {|ebuild| ebuild.execute('digest')}
68       end
69       # don't specify --generate, continue digest and emerge
70       if options[:generate] == false 
71         cmd = 'emerge '+gen_opts(options)+' '+spec_groups.map{|specs| GGem.ebuild_name(specs[0].name)}.join(' ')
72         puts cmd if options[:verbose]
73         system(cmd)
74       end
76       # don't clean up if --generate because overlay may be /tmp/*
77       if options[:generate] == true
78         puts "Ebuilds are in #{Portage.rubydev_overlay}"
79       else
80         Portage.cleanup
81       end
82     end
84     def get_specs(pkg)
85       specs = []
86       navigate(pkg.gem_name,pkg.gem_requirement) { |spec| specs << spec }
87       specs.reverse
88     end
90     def navigate(gem_name,gem_version = nil,&block)
91       if Portage.ebuild_exists(gem_name,gem_version)
92         puts "Ebuild for #{gem_name} exists" if options[:verbose]
93         return true 
94       end
95       # cache source_index_hash, no need to recheck it everytime
96       @@gri = Gem::RemoteInstaller.new if @@gri.nil?
97       @@sources = @@gri.source_index_hash if @@sources.nil?
98       version_requirement = gem_version.is_a?(Gem::Version::Requirement) ? gem_version : Gem::Version::Requirement.new(gem_version || ">= 0")
99       gem_spec = nil
100       for source_name,source in @@sources
101         specs = source.find_name(gem_name, version_requirement)
102         next if specs.nil? or specs.empty?
103         # ignore mswin32 platform
104         satisfied_specs = specs.find_all do |spec|
105           spec.platform == 'ruby' and
106             version_requirement.satisfied_by?(spec.version)
107         end
108         gem_spec = satisfied_specs[-1]
109         class << gem_spec
110           def local?() false; end
111           def set_source(source)
112             @source = source
113           end
114           def fetched_from
115             @source
116           end
117         end
118         gem_spec.set_source(source_name)
119         break
120       end
121       if gem_spec.nil?
122         puts "#{gem_name} not found"
123         return false
124       end
125       yield(gem_spec)
126       for dep in gem_spec.dependencies
127         navigate(dep.name, dep.requirement_list, &block)
128       end
129       true
130     end
132     def gen_opts(opts)
133       excludes = [:mass_generate, :generate]
134       opts.keys.map do |key|
135         opts[key] == true && !excludes.member?(key) ? "--#{key}" : ''
136       end.join(' ')
137     end
139     def parse_opts(argv)
140       opts = {
141         :pretend => false,
142         :generate => false,
143         :help => false,
144         :verbose => false,
145         :mass_generate => false
146       }
147       packages = []
148     
149       for arg in argv
150         if arg =~ /^-[^-]/
151           for i in 1..arg.length-1
152             if SHORTMAP.key? arg[i..i]
153               opts[SHORTMAP[arg[i..i]]] = true
154             else
155               puts "Unknown option '-#{arg[i..i]}'"
156             end
157           end
158         elsif arg =~ /^--/
159           if LONGMAP.key? arg[2..-1]
160             opts[LONGMAP[arg[2..-1]]] = true
161           else
162             puts "Unknown option '#{arg}'"
163           end
164         else
165           packages << DependencyAtom.new(arg)
166         end
167       end
168       return opts, packages
169     end
171     def mass_generate
172       @@gri = Gem::RemoteInstaller.new if @@gri.nil?
173       @@sources = @@gri.source_index_hash if @@sources.nil?
174       for source_name,source in @@sources
175         source.each do |full_name,spec|
176           if spec.platform == 'ruby'
177             puts full_name
178             class << spec
179               def local?() false; end
180               def set_source(source) @source = source end
181               def fetched_from() @source end
182             end
183             spec.set_source(source_name)
184             e = Ebuild.new(spec)
185             e.write
186           end
187         end
188       end
189     end
191     def ebuild_name(gem_name)
192       return SPECIAL_MAPS[gem_name] if SPECIAL_MAPS.key? gem_name
193       # Remove punctation
194       gem_name.gsub(/[_:.]+/,'-').
195         gsub(/([^-0-9A-Z])([A-Z])([a-z])/) { "#{$1}-#{$2}#{$3}" }. # split words
196         gsub(/([^-0-9A-Z])([A-Z])([a-z])/) { "#{$1}-#{$2}#{$3}" }. # split words again
197         gsub(/([A-Z]{2,})([A-Z][^A-Z-])/) { "#{$1}-#{$2}"}. # find acronyms
198         gsub(/([A-Z]{2,})-([A-Z])$/) {"#{$1}#{$2}"}. # recover wrong acronym breaking
199         downcase
200     end
201   end