Update to the new parse_user_package_dep_spec.
[paludis-scripts.git] / gimme.rb
1 #!/usr/bin/ruby
2 # vim: set sw=4 sts=4 et tw=80 :
3 # $Id$
4
5 %w{Paludis getoptlong}.each {|x| require x}
6
7 include Paludis
8
9 $0 = File.basename $0
10 Log.instance.log_level = LogLevel::Warning
11 Log.instance.program_name = $0
12
13 EQUAL = 0
14 PACKAGE = 1
15 TILDE = 2
16
17 class PackageID
18     def my_string(style, show_repo)
19         repo = show_repo ? "::#{repository_name}" : ''
20         case style
21         when EQUAL
22             "=#{name}-#{version}:#{slot}#{repo}"
23         when TILDE
24             "~#{name}-#{version.remove_revision}:#{slot}#{repo}"
25         when PACKAGE
26             "#{name}#{repo}"
27         end
28     end
29 end
30
31 def write_file(arr, file, base)
32     output = base
33     arr.each {|x| output += "\n#{x}"}
34     if @subdir
35         dir = "#{file}.d"
36         file = "#{dir}/#{@spec.to_s.gsub('/','_')}.conf"
37     end
38
39     if @pretend
40         puts "\n# #{file}"
41         puts output
42     else
43         if (@subdir && !File.directory?("#{@config_dir}/#{dir}"))
44             puts "#{dir} is not a directory. Either specify \"--use-subdir no\" or create #{dir}"
45             exit 1
46         else
47             File.open("#{@config_dir}/#{file}",'a') {|file| file.puts output}
48         end
49     end
50 end
51
52 def collect_highest_versions(dl)
53     seen = {}
54     dl.each do |entry|
55         next unless entry.kind == DepListEntryKind::Masked
56         pid = entry.package_id
57         seen[pid.name] ||= {}
58         seen[pid.name][:version] ||= VersionSpec.new('0')
59         if pid.version > seen[pid.name][:version]
60             seen[pid.name][:version] = pid.version
61             seen[pid.name][:dle] = entry
62         end
63     end
64
65     out = []
66     seen.each_value {|v| out << v[:dle]}
67     return out
68 end
69
70 opts = GetoptLong.new(
71     [ '--help',                   '-h',  GetoptLong::NO_ARGUMENT ],
72     [ '--version',                '-V',  GetoptLong::NO_ARGUMENT ],
73     [ '--log-level',                     GetoptLong::REQUIRED_ARGUMENT ],
74     [ '--environment',            '-E',  GetoptLong::REQUIRED_ARGUMENT ],
75     [ '--match-type',             '-m',  GetoptLong::REQUIRED_ARGUMENT ],
76     [ '--pretend',                '-p',  GetoptLong::NO_ARGUMENT ],
77     [ '--override-masks',         '-o',  GetoptLong::REQUIRED_ARGUMENT ],
78     [ '--use-subdir',             '-s',  GetoptLong::REQUIRED_ARGUMENT ],
79     [ '--include-repository-name',       GetoptLong::REQUIRED_ARGUMENT ])
80
81 envspec = ''
82 @match_type = TILDE
83 @pretend = false
84 @repository = false
85 @subdir = false
86 @masks = nil;
87
88 dlomf = DepListOverrideMasksFunctions.new
89
90 opts.each do | opt, arg |
91     case opt
92     when '--help'
93         puts "Usage: " + $0 + " [options] target"
94         puts
95         puts "Options:"
96         puts "  --help                     Display a help message"
97         puts "  --version                  Display libpaludis version"
98         puts
99         puts "  --pretend                  Display changes instead of changing files"
100         puts "  --log-level level          Set log level (debug, qa, warning, silent)"
101         puts "  --environment env          Environment specification (class:suffix, both parts optional, class must be 'paludis' if specified)" if @gt020
102         puts "  --match-type type          Set match type (equal, tilde (default), package)"
103         puts "  --include-repository-name  Include repository name in DepSpec (yes (default), no)"
104         puts "  --override-masks list      List of masks to override, seperated by \",\", default is all"
105         puts "                                license"
106         puts "                                tilde_keywords"
107         puts "                                unkeyworded"
108         puts "                                repository_masks"
109         puts "  --use-subdir               Write files to conf.d dirs (yes, no (default))"
110         exit 0
111
112     when '--version'
113         puts "#{$0} (libpaludis version: #{Paludis::Version})"
114         exit 0
115
116     when '--log-level'
117         case arg
118         when 'debug'
119             Log.instance.log_level = LogLevel::Debug
120         when 'qa'
121             Log.instance.log_level = LogLevel::Qa
122         when 'warning'
123             Log.instance.log_level = LogLevel::Warning
124         when 'silent'
125             Log.instance.log_level = LogLevel::Silent
126         else
127             $stderr.puts "Bad --log-level value " + arg
128             exit 1
129         end
130
131     when '--environment'
132             envspec = arg
133
134     when '--match-type'
135         case arg
136         when 'package'
137             @match_type = PACKAGE
138         when 'equal'
139             @match_type = EQUAL
140         when 'tilde'
141             @match_type = TILDE
142         else
143             $stderr.puts "Bad --match-type value #{arg}"
144             exit 1
145         end
146
147     when '--include-repository-name'
148         case arg
149         when 'yes'
150             @repository = true
151         when 'no'
152             @repository = false
153         else
154             $stderr.puts "Bad --include-repository-name value #{arg}"
155             exit 1
156         end
157
158     when '--override-masks'
159         @masks = arg
160
161     when '--use-subdir'
162         case arg
163         when 'yes'
164             @subdir = true
165         when 'no'
166             @subdir = false
167         else
168             $stderr.puts "Bad --use-subdir value #{arg}"
169             exit 1
170         end
171
172     when '--pretend'
173         @pretend = true
174
175     end
176 end
177
178 if ARGV.length != 1
179     puts "Please specify exactly 1 target"
180     exit 1
181 end
182
183 target = ARGV.first
184
185 if (envspec || "") =~ /^(?:paludis)?(?::(.*))?$/ then
186     env = Paludis::PaludisEnvironment.new($1 || "")
187     @config_dir = env.config_dir
188 else
189     $stderr.puts "#$0: --environment must specify class 'paludis'"
190     exit 1
191 end
192
193 if @masks.nil?
194     dlomf.bind(:tilde_keywords, env)
195     dlomf.bind(:unkeyworded, env)
196     dlomf.bind(:repository_masks)
197     dlomf.bind(:license)
198 else
199     @masks.scan(/\w+/) do |mask|
200         mask_sym = mask.to_sym
201         case mask_sym
202         when :tilde_keywords, :unkeyworded
203             dlomf.bind(mask_sym, env)
204         when :repository_masks, :license
205             dlomf.bind(mask_sym)
206         else
207             $stderr.puts "Unrecognised --override-masks option: #{mask}"
208             exit 1
209         end
210     end
211 end
212
213
214 db = env.package_database
215
216 @spec = nil
217
218 unless target.include? ?/
219     @spec = env.set(target)
220     @spec = parse_user_package_dep_spec(db.fetch_unique_qualified_package_name(target), []) if @spec.nil?
221 else
222     @spec = parse_user_package_dep_spec(target, [])
223 end
224
225 dl = DepList.new(env, DepListOptions.new)
226 dl.options.override_masks = dlomf
227
228 begin
229     dl.add(@spec, env.default_destinations)
230 rescue AllMaskedError
231     bad_spec = $!.query
232     pids = db.query(Query::Matches.new(parse_user_package_dep_spec(bad_spec,[])) & Query::SupportsInstallAction.new(), QueryOrder::OrderByVersion)
233     if pids.empty?
234         puts "No versions of #{bad_spec} are available."
235     else
236         puts "I'm not allowed to unmask #{bad_spec}: Masks are:"
237         pids.each do |pid|
238             print "#{pid}: Masked by: "
239             reasons = []
240             pid.masks.each do |reason|
241                 if reason.instance_of? UnacceptedMask
242                     if reason.unaccepted_key.instance_of? MetadataKeywordNameSetKey
243                         reasons << 'keyword'
244                     end
245                 elsif reason.instance_of? RepositoryMask
246                     reasons << 'repository'
247                 end
248             end
249             puts reasons.join(', ')
250         end
251     end
252     exit 1
253 end
254
255 keywords = []
256 unmask = []
257 #license = []
258 collect_highest_versions(dl).each do |entry|
259     reasons = entry.package_id.masks
260     repo = db.fetch_repository(entry.package_id.repository_name)
261     e_spec = entry.package_id.my_string(@match_type, @repository)
262     reasons.each do |reason|
263         if reason.instance_of? UnacceptedMask
264             key = reason.unaccepted_key
265             if key.instance_of? MetadataKeywordNameSetKey
266                 my_arch = repo.profile_variable("ARCH")
267                 kw = reason.unaccepted_key.value
268                 if kw.empty?
269                     my_arch = '*'
270                 elsif kw.include?("~#{my_arch}")
271                     my_arch = "~#{my_arch}"
272                 else
273                     my_arch = kw.first
274                     my_arch += (my_arch[0] == ?~ ? " #{my_arch[1..-1]}" : '')
275                 end
276                 keywords <<(e_spec + " #{my_arch}")
277             end
278         elsif reason.instance_of? RepositoryMask
279             unmask << e_spec
280         end
281     end
282 end
283
284 output_base = "\n# Added by #{$0} for #{target}"
285 output_base += "\n" + ('#' * (output_base.length-1))
286
287 write_file(keywords, 'keywords.conf', output_base) unless keywords.empty?
288 write_file(unmask, 'package_unmask.conf', output_base) unless unmask.empty?
289 #write_file(license, 'license.conf', output_base) unless license.empty?
290