Gentoo Archives: gentoo-commits

From: Sven Eden <sven.eden@×××.de>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/ufed:master commit in: /
Date: Fri, 01 Feb 2013 10:49:51
Message-Id: 1359300671.87db82c8424435b99effd98a4a12f39c8b6796d8.yamakuzure@gentoo
1 commit: 87db82c8424435b99effd98a4a12f39c8b6796d8
2 Author: Sven Eden <sven.eden <AT> gmx <DOT> de>
3 AuthorDate: Sun Jan 27 15:31:11 2013 +0000
4 Commit: Sven Eden <sven.eden <AT> gmx <DOT> de>
5 CommitDate: Sun Jan 27 15:31:11 2013 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/ufed.git;a=commit;h=87db82c8
7
8 Merged the functionality to build the global use flag hash into
9 Portage.pm.
10 Portage.pm has been reorganized and is a "real" modules now as
11 described in perlmod and perlmodlib. The data gathering is now done
12 in INIT, thus ufed never executes unless the data gathering was
13 successful.
14 Further the data layout has been rewritten to allow to gather more
15 information about packages and use flag states. This data is not
16 fully processed, as the internal data handling of the ncurses
17 interface has to be rewritten to handle this data.
18 These changes were neccessary to allow the addition of more filters
19 and to allow the addition of a per-package view, triggered by
20 command line arguments.
21 As this is much like a rewrite, this commit will get me either a big
22 clap on the back or I'll be tarred and feathered soon...
23
24 ---
25 Portage.pm | 778 ++++++++++++++++++++++++++++++++++++++++++++++--------------
26 ufed.pl.in | 229 +++++++++++--------
27 2 files changed, 731 insertions(+), 276 deletions(-)
28
29 diff --git a/Portage.pm b/Portage.pm
30 index 92f5495..8b91e4b 100644
31 --- a/Portage.pm
32 +++ b/Portage.pm
33 @@ -7,69 +7,213 @@ package Portage;
34 use strict;
35 use warnings;
36
37 -my %environment;
38 -$environment{$_}={} for qw(USE); # INCREMENTALS, except we only need USE
39 -
40 -our @portagedirs;
41 -our %packages;
42 -our @profiles;
43 -our %use_masked_flags;
44 -our %make_defaults_flags;
45 -our %default_flags;
46 -our %make_conf_flags;
47 -our %archs;
48 -our %all_flags;
49 -our $eprefix;
50 -
51 -sub get_eprefix;
52 -sub have_package;
53 -sub merge;
54 -sub merge_env;
55 -sub noncomments;
56 -sub norm_path;
57 -sub read_archs;
58 -sub read_make_conf;
59 -sub read_make_defaults;
60 -sub read_make_globals;
61 -sub read_packages;
62 -sub read_profiles;
63 -sub read_sh;
64 -sub read_use_mask;
65 -
66 -get_eprefix;
67 -read_packages;
68 -read_profiles;
69 -read_use_mask;
70 -read_make_globals;
71 -read_make_defaults;
72 -read_make_conf;
73 -read_archs;
74 -
75 -my $lastorder;
76 -for(reverse split /:/, $environment{USE_ORDER} || "env:pkg:conf:defaults:pkginternal:env.d") {
77 - if($_ eq 'defaults') {
78 - merge(\%default_flags, \%make_defaults_flags);
79 - merge(\%all_flags, \%make_defaults_flags);
80 - } elsif($_ eq 'conf') {
81 - merge(\%all_flags, \%make_conf_flags);
82 +BEGIN {
83 + use Exporter ();
84 +
85 + our @ISA = qw(Exporter);
86 + our %EXPORT_TAGS = ();
87 + our @EXPORT_OK = ();
88 +}
89 +
90 +
91 +# --- public members ---
92 +
93 +# $use_flags - hashref that represents the combined and
94 +# consolidated data about all valid use flags
95 +# Layout of $use_flags->{flag_name}:
96 +# {count} = number of different description lines
97 +# Note: +1 for the list of affected packages, and +1 for each descriptionless package with settings differing from global.
98 +# {global} = hashref for the global paramters if the flag has a description in use.desc, otherwise undefined
99 +# ->{affected} = List of packages that are affected but have no own description
100 +# ->{conf} = The flag is disabled (-1), enabled (1) or not set (0) in make.conf
101 +# ->{default} = The flag is disabled (-1), enabled (1) or not set (0) by default
102 +# ->{descr} = Global description
103 +# ->{forced} = The flag is globally force enabled (and masked) (0,1)
104 +# ->{installed} = At least one affected package is installed (0,1)
105 +# ->{masked} = The flag is globally masked (0,1)
106 +# Note: When a flag is forced, {masked} is set to one, but can be reset to 0 by any later use.mask file.
107 +# {"local"}->{package} = hashref for per package settings
108 +# ->{descr} = Description from use.local.desc or empty if there is no individual description
109 +# Note: Packages without description are only listed here if their settings differ from the global
110 +# ->{forced} = The flag is explicitly unforced (-1), default (0) or explicitly force enabled (1) for this package
111 +# ->{installed} = This package is installed
112 +# ->{masked} = The flag is explicitly unmasked (-1), default (0) or explicitly masked (1) for this package
113 +# ->{package} = The flag is explicitly disabled (-1), default (0) or explicitly enabled (1) for this package.
114 +# Note: This is a combination of the ebuilds IUSE and the installation PKGUSE and only set for installed packages.
115 +our $use_flags;
116 +
117 +# $used_make_conf - path of the used make.conf
118 +our $used_make_conf = "";
119 +
120 +# --- private members ---
121 +my %_environment = ();
122 +my $_EPREFIX = "";
123 +my @_profiles = ();
124 +# $_use_temp - hashref that represents the current state of
125 +# all known flags. This is for data gathering, the public
126 +# $use_flags is generated out of this by _gen_use_flags()
127 +# Layout of $_use_temp->{flag_name}:
128 +# {global} = conf hash for global settings
129 +# {"local"}-> {package} = conf hash for per package settings
130 +# global and per package settings:
131 +# ->{conf} Is either disabled, left alone or enabled by make.conf (-1, 0, 1)
132 +# ->{default} Is either disabled, left alone or enabled by make.defaults (-1, 0, 1)
133 +# ->{descr} Description from use.desc ({global}) or use.local.desc {cat/pkg} (string)
134 +# ->{forced} Is force enabled (implies {masked}=1) in any *use.force
135 +# For packages this is only set to -1 (explicitly unforced) or +1 (explicitly forced). 0 means "left alone".
136 +# ->{installed} Has one installed package ({global}) or is installed {cat/pkg} (0,1)
137 +# ->{masked} Is masked by any *use.mask (0,1)
138 +# For packages this is only set to -1 (explicitly unmasked) or +1 (explicitly masked). 0 means "left alone".
139 +# ->{package} Is either disabled, left alone or enabled by its ebuild (IUSE) or by user package.use (PKGUSE) (-1, 0, 1)
140 +
141 +my $_use_temp = undef;
142 +my $_use_template = {
143 + conf => 0,
144 + "default" => 0,
145 + descr => "",
146 + forced => 0,
147 + installed => 0,
148 + masked => 0,
149 + "package" => 0
150 +};
151 +
152 +# --- public methods ---
153 +
154 +# --- private methods ---
155 +sub _add_flag;
156 +sub _add_temp;
157 +sub _determine_eprefix;
158 +sub _determine_make_conf;
159 +sub _determine_profiles;
160 +sub _final_cleaning;
161 +sub _gen_use_flags;
162 +sub _merge;
163 +sub _merge_env;
164 +sub _noncomments;
165 +sub _norm_path;
166 +sub _read_archs;
167 +sub _read_descriptions;
168 +sub _read_make_conf;
169 +sub _read_make_defaults;
170 +sub _read_make_globals;
171 +sub _read_packages;
172 +sub _read_sh;
173 +sub _read_use_force;
174 +sub _read_use_mask;
175 +
176 +# --- Package initialization ---
177 +INIT {
178 + $_environment{$_} = {} for qw{USE};
179 + _determine_eprefix;
180 + _determine_make_conf;
181 + _determine_profiles;
182 + _read_make_globals;
183 + _read_make_defaults;
184 + _read_make_conf;
185 +
186 + # Now with the defaults loaded, a check is in order
187 + # whether the set USE_ORDER is supported:
188 + defined($_environment{USE_ORDER})
189 + or die("Unable to determine USE_ORDER!\nSomething is seriously broken!\n");
190 + my $lastorder = "";
191 + my @use_order = reverse split /:/, $_environment{USE_ORDER};
192 + for my $order(@use_order) {
193 + if($order eq 'defaults') {
194 + _read_make_defaults
195 + } elsif($order eq 'conf') {
196 + _read_make_conf
197 + } else {
198 + next;
199 + }
200 + $lastorder = $order;
201 + }
202 + $lastorder eq 'conf'
203 + or die("Sorry, USE_ORDER without make.conf overriding global"
204 + . " USE flags are not currently supported by ufed.\n");
205 +
206 + _read_packages;
207 + _read_use_force; ## Must be before _read_use_mask to not
208 + _read_use_mask; ## unintentionally unmask explicitly masked flags.
209 + _read_archs;
210 + _read_descriptions;
211 + _final_cleaning;
212 + _gen_use_flags;
213 +}
214 +
215 +# --- public methods implementations ---
216 +
217 +
218 +# --- private methods implementations ---
219 +
220 +# Add a flag to $use_flags and intialize it with the given
221 +# description hash key.
222 +# Parameter 1: flag
223 +# Parameter 2: Keyword "global" or the package name
224 +# Parameter 3: description hash key
225 +sub _add_flag
226 +{
227 + my ($flag, $pkg, $descKey) = @_;
228 +
229 + if ($descKey =~ /^\[(.*)\](-?\d+):(-?\d+):(-?\d+):(-?\d+):(-?\d+):(-?\d+)$/ ) {
230 + my ($descr, $conf, $default, $forced, $installed, $masked, $package)
231 + = ($1, $2, $3, $4, $5, $6, $7);
232 + my %data = ();
233 +
234 + $data{descr} = $descr;
235 + $data{forced} = $forced;
236 + $data{installed} = $installed;
237 + $data{masked} = $masked;
238 + $data{"package"} = $package;
239 + if ("global" eq "$pkg") {
240 + $data{affected} = [];
241 + $data{conf} = $conf;
242 + $data{"default"} = $default;
243 + %{$use_flags->{$flag}{global}} = %data;
244 + } else {
245 + %{$use_flags->{$flag}{"local"}{$pkg}} = %data;
246 + }
247 + ++$use_flags->{$flag}{count};
248 +
249 +
250 } else {
251 - next;
252 + die ("\n\"$flag\" ($pkg) Description Hash Key\n \"$descKey\"\nis illegal!\n");
253 }
254 - $lastorder = $_;
255 +
256 + return;
257 }
258 -if($lastorder ne 'conf') {
259 - die "Sorry, USE_ORDER without make.conf overriding global USE flags are not currently supported by ufed.\n";
260 +
261 +
262 +# Add a flag to $_use_temp if it does not exist
263 +# Parameter 1: flag
264 +# Parameter 2: Keyword "global" or "category/package"
265 +sub _add_temp
266 +{
267 + my ($flag, $pkg) = @_;
268 + my $isAdded = 0;
269 +
270 + (defined($flag) && length($flag))
271 + or return;
272 +
273 + if ("global" eq $pkg) {
274 + defined ($_use_temp->{$flag}{global})
275 + or %{$_use_temp->{$flag}{global}} = %$_use_template;
276 + } else {
277 + defined ($_use_temp->{$flag}{"local"}{$pkg})
278 + or %{$_use_temp->{$flag}{"local"}{$pkg}} = %$_use_template;
279 + }
280 +
281 + return;
282 }
283
284
285 # Determine the value for EPREFIX and save it
286 -# in $eprefix. This is done using 'portageq'.
287 +# in $_EPREFIX. This is done using 'portageq'.
288 # Other output from portageq is printed on
289 # STDERR.
290 # No parameters accepted.
291 -sub get_eprefix {
292 +sub _determine_eprefix {
293 my $tmp = "/tmp/ufed_$$.tmp";
294 - $eprefix = qx{portageq envvar EPREFIX 2>$tmp};
295 + $_EPREFIX = qx{portageq envvar EPREFIX 2>$tmp};
296 die "Couldn't determine EPREFIX from Portage" if $? != 0;
297
298 if ( -s $tmp ) {
299 @@ -80,24 +224,163 @@ sub get_eprefix {
300 }
301 -e $tmp and unlink $tmp;
302
303 - chomp($eprefix);
304 + chomp($_EPREFIX);
305 + return;
306 +}
307 +
308 +
309 +# determine which make.conf to use
310 +# and save the result in $used_make_conf
311 +sub _determine_make_conf
312 +{
313 + $used_make_conf = "${_EPREFIX}/etc/portage/make.conf";
314 + (! -r $used_make_conf)
315 + and $used_make_conf = "${_EPREFIX}/etc/make.conf";
316 + return;
317 +}
318 +
319 +
320 +# read /etc/make.profile and /etc/portage/make.profile and
321 +# analyze the complete profile tree using the found parent
322 +# files. Add all found paths to @profiles.
323 +# No parameters accepted.
324 +sub _determine_profiles
325 +{
326 + my $mp = readlink "${_EPREFIX}/etc/portage/make.profile";
327 + defined($mp)
328 + or $mp = readlink "${_EPREFIX}/etc/make.profile";
329 +
330 + # make.profile is mandatory and must be a link
331 + defined($mp)
332 + or die "${_EPREFIX}/etc\{,/portage\}/make.profile is not a symlink\n";
333 +
334 + # Start with the linked path, it is the deepest profile child.
335 + @_profiles = _norm_path('/etc', $mp);
336 + for (my $i = -1; $i >= -@_profiles; $i--) {
337 + for(_noncomments("${_profiles[$i]}/parent")) {
338 + splice(@_profiles, $i, 0, _norm_path(${_profiles[$i]}, $_));
339 + }
340 + }
341 + return;
342 +}
343 +
344 +
345 +# This method does a final cleanup of $_use_temp
346 +# Everything that is to be done _after_ all
347 +# configs are parsed goes in here.
348 +# No parameters accepted
349 +sub _final_cleaning
350 +{
351 + # The "disable all" flag is truncated to '*' by the parsing, but it
352 + # has to read '-*'.
353 + _add_temp("-*", "global");
354 +
355 + $_use_temp->{'-*'}{global}{descr} = "{Never enable any flags other than those specified in make.conf}";
356 + $_use_temp->{'-*'}{global}{conf} = 0; ## Can never be -1
357 +
358 + # Set it from the truncated config:
359 + if (defined($_use_temp->{'*'}{global})) {
360 + $_use_temp->{'*'}{global}{conf} > 0
361 + and $_use_temp->{'-*'}{global}{conf} = 1;
362 + }
363 +
364 + # The following use flags are dangerous and must no be
365 + # available using ufed:
366 + for my $flag ("*", "boostrap", "build") {
367 + defined($_use_temp->{"$flag"}) and delete($_use_temp->{"$flag"});
368 + }
369 +
370 return;
371 }
372
373
374 -# returns the content of %packages for the given
375 -# scalar or undef.
376 -# Parameter 1: Package to test of the form <category>/<name>
377 -sub have_package {
378 - my ($cp) = @_;
379 - return $packages{$cp};
380 +# Once $_use_temp is ready, this method builds
381 +# the final $use_flags hashref.
382 +# No parameters accepted
383 +sub _gen_use_flags
384 +{
385 + for my $flag (keys %$_use_temp) {
386 + my %descCons = ();
387 + my $flagRef = $_use_temp->{$flag}; ## Shortcut
388 + my $hasGlobal= (defined($flagRef->{global}) && length($flagRef->{global}{descr})) ? 1 : 0;
389 + my $lCount = $hasGlobal;
390 + my $gDesc = "";
391 + my $gKey = "";
392 + my $gRef = $flagRef->{global};
393 + my $pDesc = "";
394 + my $pKey = "";
395 + my $pRef = undef;
396 +
397 + # Build the description consolidation hash
398 + if ($hasGlobal) {
399 + $gDesc = $gRef->{descr};
400 + $gKey = sprintf("[%s]%d:%d:%d:%d:%d:%d", $gDesc, $gRef->{conf}, $gRef->{"default"},
401 + $gRef->{forced}, $gRef->{installed}, $gRef->{masked}, $gRef->{"package"});
402 + $descCons{$gKey}{global} = 1;
403 + }
404 + for my $pkg (sort keys %{$flagRef->{"local"}}) {
405 + $pRef = $flagRef->{"local"}{$pkg};
406 +
407 + if (length($pRef->{descr})) {
408 + ## This package has an individual description:
409 + $pDesc = "$pRef->{descr}";
410 + $pKey = sprintf("[%s]%d:%d:%d:%d:%d:%d", $pDesc, $pRef->{conf}, $pRef->{"default"},
411 + $pRef->{forced}, $pRef->{installed}, $pRef->{masked}, $pRef->{"package"});
412 + $descCons{$pKey}{$pkg} = 1;
413 + ++$lCount;
414 + }
415 + ## TODO : Add affected packages that have no own description
416 + # once the interface can handle them. These can be used for
417 + # the package filtering per command line arguments later.
418 + } ## End of walking through a flags package list
419 +
420 + # Skip if there was nothing consolidated
421 + next unless($lCount);
422 +
423 + # Add the content of $descCons to $use_flags:
424 + $use_flags->{$flag}{count} = 0;
425 +
426 + # The global data has to be added first:
427 + if (length($gKey)) {
428 + _add_flag($flag, "global", $gKey);
429 +
430 + # TODO : Add affected packages once they can be hanlded. See above TODO.
431 + }
432 +
433 + # Then the "local" flag descriptions
434 + # TODO : Add affected packages that have diffeent settings once they can be handled.
435 + for my $key (sort keys %descCons) {
436 + next if ($key eq $gKey);
437 +
438 + # Generate the package list with same description and flags,
439 + # but not for more than 5 packages
440 + my $packages = "";
441 + my $pkgCount = 0;
442 + for my $pkg (sort keys %{$descCons{$key}}) {
443 + length($packages) and $packages .= ", ";
444 + $packages .= $pkg;
445 + if (++$pkgCount == 5) {
446 + _add_flag($flag, $packages, $key);
447 + $packages = "";
448 + $pkgCount = 0;
449 + }
450 + }
451 +
452 + # Add the last result if there is something left
453 + $pkgCount and _add_flag($flag, $packages, $key);
454 + }
455 +
456 + delete $_use_temp->{$flag};
457 + } ## End of walking through $_use_temp flags
458 +
459 + return;
460 }
461
462
463 # merges two hashes into the first.
464 # Parameter 1: reference of the destination hash
465 # Parameter 2: reference of the source hash
466 -sub merge {
467 +sub _merge {
468 my ($dst, $src) = @_;
469 %{$dst} = () if(exists $src->{'*'});
470 $dst->{$_} = $src->{$_} for(keys %$src);
471 @@ -106,12 +389,12 @@ sub merge {
472
473
474 # Splits content of the source hash at spaces and
475 -# merges its contents into %environment.
476 +# merges its contents into %_environment.
477 # Parameter 1: reference of the hash to merge
478 -sub merge_env {
479 +sub _merge_env {
480 my ($src) = @_;
481 - for(keys %environment) {
482 - if(ref $environment{$_} eq 'HASH') {
483 + for(keys %_environment) {
484 + if(ref $_environment{$_} eq 'HASH') {
485 if(exists $src->{$_}) {
486 my %split;
487 for(split ' ', $src->{$_}) {
488 @@ -120,13 +403,13 @@ sub merge_env {
489 $split{$_} = !$off;
490 }
491 $src->{$_} = { %split };
492 - merge(\%{$environment{$_}}, \%{$src->{$_}});
493 + _merge(\%{$_environment{$_}}, \%{$src->{$_}});
494 }
495 }
496 }
497 for(keys %$src) {
498 - if(ref $environment{$_} ne 'HASH') {
499 - $environment{$_} = $src->{$_};
500 + if(ref $_environment{$_} ne 'HASH') {
501 + $_environment{$_} = $src->{$_};
502 }
503 }
504 return;
505 @@ -136,7 +419,7 @@ sub merge_env {
506 # returns a list of all lines of a given file
507 # that are no pure comments
508 # Parameter 1: filename
509 -sub noncomments {
510 +sub _noncomments {
511 my ($fname) = @_;
512 my @result;
513 local $/;
514 @@ -154,7 +437,7 @@ sub noncomments {
515 # Parameter 1: base path
516 # Parameter 2: sub path
517 # return: normalized base path / normalized sub path
518 -sub norm_path {
519 +sub _norm_path {
520 my ($base, $path) = @_;
521 my @pathcomp = ($path !~ m!^/! && split(m!/!, $base), split(m!/!, $path));
522 for(my $i=0;;$i++) {
523 @@ -176,118 +459,217 @@ sub norm_path {
524 }
525
526
527 -# reads all arch.list in all profiles sub directories
528 -# of found @portagedirs and saves the found architectures
529 -# in %arch
530 +# reads all found arch.list and erase all found archs
531 +# from $_use_temp. Archs are not setable.
532 # No parameters accepted
533 -sub read_archs {
534 - for my $dir(@portagedirs) {
535 - for(noncomments "$dir/profiles/arch.list") {
536 - $archs{$_} = 1;
537 +sub _read_archs {
538 + for my $dir(@_profiles) {
539 + next unless (-r "$dir/arch.list");
540 + for my $arch (_noncomments("$dir/arch.list")) {
541 + defined($_use_temp->{$arch})
542 + and delete($_use_temp->{$arch});
543 }
544 }
545 return;
546 }
547
548
549 -# read /etc/make.conf and/or /etc/portage/make.conf and
550 -# merge set USE flags into %make_conf_flags. Additionally
551 -# all set portage directories (plus overlays) are recorded
552 -# in @portagedirs.
553 -# No parameters accepted.
554 -sub read_make_conf {
555 - my %oldEnv = read_sh("$eprefix/etc/make.conf");
556 - my %newEnv = read_sh("$eprefix/etc/portage/make.conf");
557 - merge (\%oldEnv, \%newEnv);
558 - merge (\%make_conf_flags,\ %{$oldEnv{USE}}) if exists $oldEnv{USE};
559 - @portagedirs = $environment{PORTDIR};
560 - push @portagedirs, split ' ', $environment{PORTDIR_OVERLAY} if defined $environment{PORTDIR_OVERLAY};
561 +# reads all use.desc and use.local.desc and updates
562 +# $_use_temp accordingly.
563 +# No parameters accepted
564 +sub _read_descriptions
565 +{
566 + for my $dir(@_profiles) {
567 + if (-r "$dir/use.desc") {
568 + for(_noncomments("$dir/use.desc")) {
569 + my ($flag, $desc) = /^(.*?)\s+-\s+(.*)$/ or next;
570 +
571 + _add_temp($flag, "global");
572 +
573 + $_use_temp->{$flag}{global}{descr} = $desc;
574 + }
575 + } ## End of having a use.desc file
576 +
577 + if (-r "$dir/use.local.desc") {
578 + for(_noncomments("$dir/use.local.desc")) {
579 + my ($pkg, $flag, $desc) = /^(.*?):(.*?)\s+-\s+(.*)$/ or next;
580 +
581 + # Here we do not explicitly add a {global} part,
582 + # some flags are local only.
583 + _add_temp($flag, $pkg);
584 +
585 + $_use_temp->{$flag}{"local"}{$pkg}{descr} = $desc;
586 + }
587 + } ## End of having a use.local.desc file
588 + } ## End of looping the profiles
589 return;
590 }
591
592
593 -# read all found make.defaults files and merge their flags
594 -# into %make_default_flags.
595 +# read make.conf and record the state of all set use
596 +# flags.
597 +# Additionally add all set portage directories (plus
598 +# overlays) to @_profiles.
599 +# The last added profile directory, if it exists, is
600 +# /etc/portage/profile to allow recognition of user
601 +# overrides.
602 # No parameters accepted.
603 -sub read_make_defaults {
604 - for my $dir(@profiles) {
605 - my %env = read_sh "$dir/make.defaults";
606 - merge (\%make_defaults_flags, \%{$env{USE}}) if exists $env{USE};
607 +sub _read_make_conf {
608 + my %oldEnv = _read_sh("${_EPREFIX}/etc/make.conf");
609 + my %newEnv = _read_sh("${_EPREFIX}/etc/portage/make.conf");
610 + _merge (\%oldEnv, \%newEnv);
611 +
612 + # Note the conf state of the read flags:
613 + for my $flag ( keys %{$oldEnv{USE}}) {
614 +
615 + _add_temp($flag, "global");
616 +
617 + $oldEnv{USE}{$flag}
618 + and $_use_temp->{$flag}{global}{conf} = 1
619 + or $_use_temp->{$flag}{global}{conf} = -1;
620 }
621 +
622 + # Add PORTDIR and overlays to @_profiles
623 + defined ($_environment{PORTDIR})
624 + and push @_profiles, "$_environment{PORTDIR}/profiles"
625 + or die("Unable to determine PORTDIR!\nSomething is seriously broken here!\n");
626 + defined ($_environment{PORTDIR_OVERLAY})
627 + and push @_profiles,
628 + map { my $x=$_; $x =~ s/^\s*(\S+)\s*$/$1\/profiles/mg ; $x }
629 + split('\n', $_environment{PORTDIR_OVERLAY});
630 + -e "${_EPREFIX}/etc/portage/profile"
631 + and push @_profiles, "${_EPREFIX}/etc/portage/profile";
632 + return;
633 +}
634 +
635 +
636 +# read all found make.defaults and non-user package.use files
637 +# and merge their values into env.
638 +# TODO : use USE_EXPAND to add Expansion parsing. The most
639 +# important of these are set with sane defaults here,
640 +# too.
641 +# No parameters accepted.
642 +sub _read_make_defaults {
643 + for my $dir(@_profiles) {
644 + if (-r "$dir/make.defaults") {
645 + my %env = _read_sh("$dir/make.defaults");
646 +
647 + # Note the conf state of the read flags:
648 + for my $flag ( keys %{$env{USE}}) {
649 + _add_temp($flag, "global");
650 +
651 + $env{USE}{$flag}
652 + and $_use_temp->{$flag}{global}{"default"} = 1
653 + or $_use_temp->{$flag}{global}{"default"} = -1;
654 + }
655 + }
656 + } ## End of looping through the profiles
657 return
658 }
659
660
661 # read all found make.globals and merge their
662 -# settings into %environment.
663 +# settings into %environment. This is done to
664 +# get the final "PORTDIR" and "USE_ORDER"
665 # No parameters accepted
666 -sub read_make_globals {
667 - for my $dir(@profiles, "$eprefix/usr/share/portage/config") {
668 - read_sh "$dir/make.globals";
669 +sub _read_make_globals {
670 + for my $dir(@_profiles, "${_EPREFIX}/usr/share/portage/config") {
671 + _read_sh("$dir/make.globals");
672 }
673 return;
674 }
675
676
677 -# Analyze EPREFIX/var/db/pkg and note all installed
678 -# packages in %packages.
679 +# Analyze EPREFIX/var/db/pkg and analyze all installed
680 +# packages. We need to know what they use (IUSE) and what
681 +# has been set when they where emerged (PKGUSE).
682 # No parameters accepted.
683 -sub read_packages {
684 - die "Couldn't read $eprefix/var/db/pkg\n" unless opendir my $pkgdir, "$eprefix/var/db/pkg";
685 +sub _read_packages {
686 + my $pkgdir = undef;
687 + opendir($pkgdir, "${_EPREFIX}/var/db/pkg")
688 + or die "Couldn't read ${_EPREFIX}/var/db/pkg\n";
689 +
690 + # loop through all categories in pkgdir
691 while(my $cat = readdir $pkgdir) {
692 next if $cat eq '.' or $cat eq '..';
693 - next unless opendir my $catdir, "$eprefix/var/db/pkg/$cat";
694 + my $catdir = undef;
695 + opendir($catdir, "${_EPREFIX}/var/db/pkg/$cat")
696 + or next;
697 +
698 + # loop through all openable directories in cat
699 while(my $pkg = readdir $catdir) {
700 next if $pkg eq '.' or $pkg eq '..';
701 - my @provide = ();
702 - my @use = ();
703 + my @puse = ();
704 + my @iuse = ();
705
706 # Load PROVIDE
707 - ## FIXME: There is no file "PROVIDE" anywhere, at least on my system!
708 - if(open my $provide, '<', "$eprefix/var/db/pkg/$cat/$pkg/PROVIDE") {
709 - local $/;
710 - @provide = split ' ', <$provide>;
711 - close $provide;
712 - }
713 + #Update: Deprecated, this file is gone
714 + #if(open my $provide, '<', "$eprefix/var/db/pkg/$cat/$pkg/PROVIDE") {
715 + # local $/;
716 + # @provide = split ' ', <$provide>;
717 + # close $provide;
718 + #}
719
720 # Load USE
721 - if(open my $use, '<', "$eprefix/var/db/pkg/$cat/$pkg/USE") {
722 + # Update: deprecated, this file is no longer useful. read IUSE and PKGUSE instead
723 + #if(open my $use, '<', "$eprefix/var/db/pkg/$cat/$pkg/USE") {
724 + # local $/;
725 + # @use = split ' ', <$use>;
726 + # close $use;
727 + #}
728 +
729 + # Load IUSE to learn which use flags the package in this version knows
730 + my $fiuse = "${_EPREFIX}/var/db/pkg/$cat/$pkg/IUSE";
731 + if(open my $use, '<', $fiuse) {
732 + local $/;
733 + @iuse = split ' ', <$use>;
734 + close $use;
735 + }
736 +
737 + # Load PKGUSE to learn which use flags have been set when this package was emerged
738 + my $fpuse = "${_EPREFIX}/var/db/pkg/$cat/$pkg/PKGUSE";
739 + if(open my $use, '<', $fpuse) {
740 local $/;
741 - @use = split ' ', <$use>;
742 + @puse = split ' ', <$use>;
743 close $use;
744 }
745
746 # could be shortened, but make sure not to strip off part of the name
747 $pkg =~ s/-\d+(?:\.\d+)*\w?(?:_(?:alpha|beta|pre|rc|p)\d*)?(?:-r\d+)?$//;
748 - $packages{"$cat/$pkg"} = 1;
749 + $pkg = $cat . "/" . $pkg;
750 +
751 + # Now save the knowledge gained (if any) in $_use_temp:
752 + for my $flag (@iuse) {
753 + my $eState = $flag =~ s/^\+// || 0;
754 + my $dState = $flag =~ s/^-// || 0;
755 +
756 + _add_temp($flag, "global");
757 + _add_temp($flag, $pkg);
758 +
759 + $_use_temp->{$flag}{"local"}{$pkg}{"package"} = $eState ? 1 : $dState ? -1 : 0;
760 + $_use_temp->{$flag}{"local"}{$pkg}{installed} = 1;
761 + $_use_temp->{$flag}{global}{installed} = 1;
762 + } ## End of looping IUSE
763 + for my $flag (@puse) {
764 + my $state = $flag =~ s/^-// || 0;
765 +
766 + if ( defined($_use_temp->{$flag}{global})
767 + && defined($_use_temp->{$flag}{$pkg})) {
768 + $state and $_use_temp->{$flag}{"local"}{$pkg}{"package"} = -1
769 + or $_use_temp->{$flag}{"local"}{$pkg}{"package"} = 0;
770 +
771 + } # enable if output is wanted!
772 + #else {
773 + # ## This can happen if a package was installed with a flag
774 + # ## that is gone. (Seen with sys-fs/ntfs3g-2012.1.15-r1 to
775 + # ## sys-fs/ntfs3g-2012.1.15-r2 and use flag "extras". Gone,
776 + # ## but still listed in PKGUSE)
777 + # printf STDERR "DEBUG: '%s' found in\n '%s'\n but not in\n '%s'\n",
778 + # $flag, $fpuse, $fiuse;
779 + # ## No need to break, though...
780 + #}
781 + } ## End of looping PKGUSE
782
783 - # FIXME: What is this supposed to achieve?
784 - # Currently this does nothing as there is no PROVIDE anywhere,
785 - # but even if it were, there is nothing really done at all with
786 - # @use.
787 - for(my $i=0; $i<@provide; $i++) {
788 - my $pkg = $provide[$i];
789 - next if $pkg eq '(' || $pkg eq ')';
790 - if($pkg !~ s/\?$//) {
791 - $pkg =~ s/-\d+(?:\.\d+)*\w?(?:_(?:alpha|beta|pre|rc|p)\d*)?(?:-r\d+)?$//;
792 - $packages{$pkg} = 1;
793 - } else {
794 - my $musthave = $pkg !~ s/^!//;
795 - my $have = 0;
796 - for(@use) {
797 - if($pkg eq $_)
798 - { $have = 1; last }
799 - }
800 - if($musthave != $have) {
801 - my $level = 0;
802 - for($i++;$i<@provide;$i++) {
803 - $level++ if $provide[$i] eq '(';
804 - $level-- if $provide[$i] eq ')';
805 - last if $level==0;
806 - }
807 - }
808 - }
809 - }
810 }
811 closedir $catdir;
812 }
813 @@ -296,32 +678,13 @@ sub read_packages {
814 }
815
816
817 -# read /etc/make.profile and /etc/portage/make.profile
818 -# and analyze the complete profile tree using the found
819 -# parent files. Add all found paths to @profiles.
820 -# No parameters accepted.
821 -sub read_profiles {
822 - $_ = readlink "$eprefix/etc/make.profile";
823 - $_ = readlink "$eprefix/etc/portage/make.profile" if not defined $_;
824 - die "$eprefix/etc\{,/portage\}/make.profile is not a symlink\n" if not defined $_;
825 - @profiles = norm_path '/etc', $_;
826 - for (my $i = -1; $i >= -@profiles; $i--) {
827 - for(noncomments "$profiles[$i]/parent") {
828 - splice @profiles, $i, 0, norm_path $profiles[$i], $_;
829 - }
830 - }
831 - push @profiles, "$eprefix/etc/portage/profile";
832 - return;
833 -}
834 -
835 -
836 # reads the given file and parses it for key=value pairs.
837 # "source" entries are added to the file and parsed as
838 # well. The results of the parsing are merged into
839 # %environment.
840 # Parameter 1: The path of the file to parse.
841 # In a non-scalar context the function returns the found values.
842 -sub read_sh {
843 +sub _read_sh {
844 my ($fname) = @_;
845 my $BLANK = qr{(?:[ \n\t]+|#.*)+}; # whitespace and comments
846 my $IDENT = qr{([^ \\\n\t'"{}=#]+)}; # identifiers
847 @@ -337,7 +700,7 @@ sub read_sh {
848 eval {
849 for(;;) {
850 /\G$BLANK/gc;
851 - last if pos == length;
852 + last if ((pos || 0) == (length || 0));
853 /\G$IDENT/gc or die;
854 my $name = $1;
855 /\G$BLANK/gc;
856 @@ -386,33 +749,88 @@ sub read_sh {
857 };
858 die "Parse error in $fname\n" if $@;
859 }
860 - merge_env(\%env);
861 + _merge_env(\%env);
862 return %env if wantarray;
863 return;
864 }
865
866
867 +# read all enforced flags from all found use.force
868 +# and package.use.force files. Save the found
869 +# masks in %use_flags.
870 +# No parameters accepted.
871 +sub _read_use_force {
872 + for my $dir(@_profiles) {
873 + if (-r "$dir/use.force") {
874 + # use.force can enforce and mask specific flags
875 + for my $flag (_noncomments("$dir/use.force") ) {
876 + my $state = $flag =~ s/^-// || 0;
877 +
878 + _add_temp($flag, "global");
879 +
880 + $_use_temp->{$flag}{global}{masked} = !$state;
881 + $_use_temp->{$flag}{global}{forced} = !$state;
882 + }
883 + } ## End of having a use.force file
884 +
885 + if (-r "$dir/package.use.force") {
886 + # package.use.force can enforce or unforce flags per package
887 + for(_noncomments("$dir/package.use.force") ) {
888 + my($pkg, @flags) = split;
889 + for my $flag (@flags) {
890 + my $state = $flag =~ s/^-// || 0;
891 +
892 + _add_temp($flag, "global");
893 + _add_temp($flag, $pkg);
894 +
895 + if ($state) {
896 + $_use_temp->{$flag}{"local"}{$pkg}{masked} = -1; ## explicitly unmasked and
897 + $_use_temp->{$flag}{"local"}{$pkg}{forced} = -1; ## explicitly unforced
898 + } else {
899 + $_use_temp->{$flag}{"local"}{$pkg}{masked} = 1; ## explicitly masked and
900 + $_use_temp->{$flag}{"local"}{$pkg}{forced} = 1; ## explicitly enforced
901 + }
902 + }
903 + }
904 + } ## End of having a package.use.force file
905 + } ## End of looping through the profiles
906 + return;
907 +}
908 +
909 +
910 # read all masked flags from all found use.mask
911 # and package.use.mask files. Save the found
912 -# masks in %use_masked_flags.
913 +# masks in %use_flags.
914 # No parameters accepted.
915 -sub read_use_mask {
916 - for my $dir(@profiles) {
917 - -r "$dir/use.mask" or next;
918 - for(noncomments "$dir/use.mask") {
919 - my $off = s/^-//;
920 - $use_masked_flags{$_} = { '' => !$off };
921 - }
922 - for(noncomments "$dir/package.use.mask") {
923 - my($pkg, @flags) = split;
924 - for(@flags) {
925 - my $off = s/^-//;
926 -
927 - $use_masked_flags{$_}{''} ||= 0;
928 - $use_masked_flags{$_}{$pkg} = !$off;
929 +sub _read_use_mask {
930 + for my $dir(@_profiles) {
931 + if (-r "$dir/use.mask") {
932 + # use.mask can enable or disable masks
933 + for my $flag (_noncomments("$dir/use.mask") ) {
934 + my $state = $flag =~ s/^-// || 0;
935 +
936 + _add_temp($flag, "global");
937 +
938 + $_use_temp->{$flag}{global}{masked} = !$state;
939 }
940 - }
941 - }
942 + } ## End of having a use.mask file
943 +
944 + if (-r "$dir/package.use.mask") {
945 + # package.use.mask can enable or disable masks per package
946 + for(_noncomments("$dir/package.use.mask") ) {
947 + my($pkg, @flags) = split;
948 + for my $flag (@flags) {
949 + my $state = $flag =~ s/^-// || 0;
950 +
951 + _add_temp($flag, "global");
952 + _add_temp($flag, $pkg);
953 +
954 + $state and $_use_temp->{$flag}{"local"}{$pkg}{masked} = -1; ## explicitly unmasked
955 + $state or $_use_temp->{$flag}{"local"}{$pkg}{masked} = 1; ## explicitly masked
956 + }
957 + }
958 + } ## End of having a package.use.mask file
959 + } ## End of looping through the profiles
960 return;
961 }
962
963
964 diff --git a/ufed.pl.in b/ufed.pl.in
965 index 9b072b7..299c79d 100644
966 --- a/ufed.pl.in
967 +++ b/ufed.pl.in
968 @@ -17,52 +17,51 @@ my $interface = 'ufed-curses';
969 # . " --read-var-info=yes"
970 # . " XX_libexecdir@/ufed-curses 2>/tmp/ufed_memcheck.log";
971
972 -my %use_descriptions;
973 +# no longer needed
974 +# my %use_descriptions;
975
976 sub finalise;
977 sub flags_dialog;
978 -sub read_use_descs;
979 sub save_flags;
980
981 -delete $Portage::all_flags{'*'};
982 -
983 -read_use_descs;
984 -
985 -delete @use_descriptions{qw(bootstrap build)};
986 -
987 -$Portage::make_conf_flags{'-*'} = 1
988 - if defined $Portage::make_conf_flags{'*'}
989 - && !$Portage::make_conf_flags{'*'};
990 -
991 -for(keys %Portage::all_flags) {
992 - @{$use_descriptions{$_}} = "[(Unknown)] g"
993 - if not exists $use_descriptions{$_};
994 -}
995 -@{$use_descriptions{'-*'}} = '[Never enable any flags other than those specified in make.conf] g';
996 -
997 -for(@Portage::archs) {
998 - delete $Portage::default_flags{$_};
999 - delete $Portage::all_flags{$_};
1000 - delete $use_descriptions{$_};
1001 -}
1002 -for my $flag (keys %Portage::use_masked_flags) {
1003 - my $masked = 1;
1004 - for my $mask (values %{$Portage::use_masked_flags{$flag}}) {
1005 - last if not($masked &&= $mask);
1006 - }
1007 - if($masked) {
1008 - if (defined($use_descriptions{$flag})) {
1009 - for (my $i = 0; $i < scalar @{$use_descriptions{$flag}}; ++$i) {
1010 - $use_descriptions{$flag}->[$i] =~ s/ [lg]$/ m/ ;
1011 - $use_descriptions{$flag}->[$i] =~ s/ L$/ M/ ;
1012 - }
1013 - } else {
1014 - delete $use_descriptions{$flag};
1015 - delete $Portage::default_flags{$flag};
1016 - delete $Portage::all_flags{$flag};
1017 - }
1018 - }
1019 -}
1020 +# deprecated, the functionality is merged into Portage.pm
1021 +# delete $Portage::all_flags{'*'};
1022 +# read_use_descs;
1023 +# @use_descriptions{qw(bootstrap build)};
1024 +#
1025 +#$Portage::make_conf_flags{'-*'} = 1
1026 +# if defined $Portage::make_conf_flags{'*'}
1027 +# && !$Portage::make_conf_flags{'*'};
1028 +#
1029 +#for(keys %Portage::all_flags) {
1030 +# @{$use_descriptions{$_}} = "[(Unknown)] g"
1031 +# if not exists $use_descriptions{$_};
1032 +#}
1033 +#@{$use_descriptions{'-*'}} = '[Never enable any flags other than those specified in make.conf] g';
1034 +#
1035 +#for(@Portage::archs) {
1036 +# delete $Portage::default_flags{$_};
1037 +# delete $Portage::all_flags{$_};
1038 +# delete $use_descriptions{$_};
1039 +#}
1040 +#for my $flag (keys %Portage::use_masked_flags) {
1041 +# my $masked = 1;
1042 +# for my $mask (values %{$Portage::use_masked_flags{$flag}}) {
1043 +# last if not($masked &&= $mask);
1044 +# }
1045 +# if($masked) {
1046 +# if (defined($use_descriptions{$flag})) {
1047 +# for (my $i = 0; $i < scalar @{$use_descriptions{$flag}}; ++$i) {
1048 +# $use_descriptions{$flag}->[$i] =~ s/ [lg]$/ m/ ;
1049 +# $use_descriptions{$flag}->[$i] =~ s/ L$/ M/ ;
1050 +# }
1051 +# } else {
1052 +# delete $use_descriptions{$flag};
1053 +# delete $Portage::default_flags{$flag};
1054 +# delete $Portage::all_flags{$flag};
1055 +# }
1056 +# }
1057 +#}
1058
1059 flags_dialog;
1060
1061 @@ -111,16 +110,52 @@ sub flags_dialog {
1062 my $outTxt = "";
1063
1064 # Write out flags
1065 - for my $flag (sort { uc $a cmp uc $b } keys %use_descriptions) {
1066 + for my $flag (sort { uc $a cmp uc $b } keys %$Portage::use_flags) {
1067 + my $conf = $Portage::use_flags->{$flag}; ## Shortcut
1068 + my $state = "g";
1069 $outTxt .= sprintf ("%s %s (%s%s) %d\n", $flag,
1070 - defined($Portage::make_conf_flags{$flag})
1071 - ? $Portage::make_conf_flags{$flag} ? 'on' : 'off' : 'def',
1072 - exists($Portage::make_defaults_flags{$flag})
1073 - ? $Portage::make_defaults_flags{$flag} ? '+' : '-' : ' ',
1074 - exists($Portage::make_conf_flags{$flag})
1075 - ? $Portage::make_conf_flags{$flag} ? '+' : '-' : ' ',
1076 - scalar @{$use_descriptions{$flag}} );
1077 - $outTxt .= sprintf ("%s\n", $_) for(@{$use_descriptions{$flag}});
1078 + defined($conf->{global}{conf}) ?
1079 + $conf->{global}{conf} > 0 ? 'on' :
1080 + $conf->{global}{conf} < 0 ? 'off' : 'def' : 'def',
1081 + defined($conf->{global}{"default"}) ?
1082 + $conf->{global}{"default"} > 0 ? '+' :
1083 + $conf->{global}{"default"} < 0 ? '-' : ' ' : ' ',
1084 + defined($conf->{global}{conf}) ?
1085 + $conf->{global}{conf} > 0 ? '+' :
1086 + $conf->{global}{conf} < 0 ? '-' : ' ' : ' ',
1087 + $conf->{count});
1088 +
1089 + # Print global description first (if available)
1090 + if (defined($conf->{global}) && length($conf->{global}{descr})) {
1091 + if ($conf->{global}{installed}) {
1092 + $conf->{global}{masked} and $state = "M";
1093 + $conf->{global}{masked} or $state = "G";
1094 + } else {
1095 + $conf->{global}{masked} and $state = "m";
1096 + }
1097 + $outTxt .= "[" . $conf->{global}{descr} . "] $state\n";
1098 +
1099 + # Then print the list of affected packages that have no own entry
1100 + for my $afLst (@{$conf->{global}{affected}}) {
1101 + (defined($afLst) && length($afLst))
1102 + and $outTxt .= "($afLst) [Affected by global flag setting] $state\n";
1103 + }
1104 + }
1105 +
1106 + # Finally print the local description lines
1107 + for my $pkg (sort keys %{$conf->{"local"}}) {
1108 + $state = "l";
1109 + if ($conf->{"local"}{$pkg}{installed}) {
1110 + $state = "L";
1111 + if ($conf->{global}{masked}) {
1112 + $conf->{"local"}{$pkg}{masked} > -1 and $state = "M";
1113 + $conf->{"local"}{$pkg}{masked} < 0 and $state = "L";
1114 + }
1115 + } elsif ($conf->{global}{masked}) {
1116 + $conf->{"local"}{$pkg}{masked} > -1 and $state = "m";
1117 + }
1118 + $outTxt .= sprintf("(%s) [%s] %s\n", $pkg, $conf->{"local"}{$pkg}{descr}, $state);
1119 + }
1120 }
1121
1122 # Some overlays (like sunrise) use UTF-8 characters in their
1123 @@ -155,52 +190,54 @@ sub flags_dialog {
1124 return;
1125 }
1126
1127 -# Build the global %use_descriptions hash.
1128 -# Parsed files are:
1129 -# 1. PORTDIR/profiles/use.desc
1130 -# 2. PORTDIR/profiles/use.local.desc
1131 -# No parameters accepted.
1132 -# @todo : The local descriptions must be written in a different
1133 -# way (how?) to allow the wanted filtering/distinction
1134 -# between global/local flags.
1135 -sub read_use_descs {
1136 - my %_use_descriptions;
1137 - for my $dir(@Portage::portagedirs) {
1138 - for(Portage::noncomments "$dir/profiles/use.desc") {
1139 - my ($flag, $desc) = /^(.*?)\s+-\s+(.*)$/ or next;
1140 - $_use_descriptions{$flag}{$desc} = 1;
1141 - }
1142 - }
1143 - my %_use_local_descriptions;
1144 - for my $dir(@Portage::portagedirs) {
1145 - for(Portage::noncomments "$dir/profiles/use.local.desc") {
1146 - my ($pkg, $flag, $desc) = /^(.*?):(.*?)\s+-\s+(.*)$/ or next;
1147 - $_use_local_descriptions{$flag}{$desc}{$pkg} = 1;
1148 - }
1149 - }
1150 - # Record all global flags first, their description is printed first
1151 - # in the ncurses interface as well.
1152 - for my $key (sort keys %_use_descriptions) {
1153 - for my $desc (sort keys %{$_use_descriptions{$key}}) {
1154 - push @{$use_descriptions{$key}}, "[" . $desc . "] g";
1155 - }
1156 - }
1157 -
1158 - # Add local flags
1159 - for my $key (sort keys %_use_local_descriptions) {
1160 - for my $desc (sort keys %{$_use_local_descriptions{$key}}) {
1161 - my $flagPrefix = "l";
1162 - my @pkgs = ();
1163 - for my $pkg (sort keys %{$_use_local_descriptions{$key}{$desc}}) {
1164 - $flagPrefix = "L" if (Portage::have_package($pkg));
1165 - push @pkgs, $pkg;
1166 - }
1167 - local $"=", ";
1168 - push @{$use_descriptions{$key}}, sprintf("(%s) [%s] %s", "@pkgs", $desc, $flagPrefix);
1169 - }
1170 - }
1171 - return;
1172 -}
1173 +# Deprecated, the funcionality is merged into Portage.pm.
1174 +#
1175 +## Build the global %use_descriptions hash.
1176 +## Parsed files are:
1177 +## 1. PORTDIR/profiles/use.desc
1178 +## 2. PORTDIR/profiles/use.local.desc
1179 +## No parameters accepted.
1180 +## @todo : The local descriptions must be written in a different
1181 +## way (how?) to allow the wanted filtering/distinction
1182 +## between global/local flags.
1183 +#sub read_use_descs {
1184 +# my %_use_descriptions;
1185 +# for my $dir(@Portage::portagedirs) {
1186 +# for(Portage::noncomments "$dir/profiles/use.desc") {
1187 +# my ($flag, $desc) = /^(.*?)\s+-\s+(.*)$/ or next;
1188 +# $_use_descriptions{$flag}{$desc} = 1;
1189 +# }
1190 +# }
1191 +# my %_use_local_descriptions;
1192 +# for my $dir(@Portage::portagedirs) {
1193 +# for(Portage::noncomments "$dir/profiles/use.local.desc") {
1194 +# my ($pkg, $flag, $desc) = /^(.*?):(.*?)\s+-\s+(.*)$/ or next;
1195 +# $_use_local_descriptions{$flag}{$desc}{$pkg} = 1;
1196 +# }
1197 +# }
1198 +# # Record all global flags first, their description is printed first
1199 +# # in the ncurses interface as well.
1200 +# for my $key (sort keys %_use_descriptions) {
1201 +# for my $desc (sort keys %{$_use_descriptions{$key}}) {
1202 +# push @{$use_descriptions{$key}}, "[" . $desc . "] g";
1203 +# }
1204 +# }
1205 +#
1206 +# # Add local flags
1207 +# for my $key (sort keys %_use_local_descriptions) {
1208 +# for my $desc (sort keys %{$_use_local_descriptions{$key}}) {
1209 +# my $flagPrefix = "l";
1210 +# my @pkgs = ();
1211 +# for my $pkg (sort keys %{$_use_local_descriptions{$key}{$desc}}) {
1212 +# $flagPrefix = "L" if (Portage::have_package($pkg));
1213 +# push @pkgs, $pkg;
1214 +# }
1215 +# local $"=", ";
1216 +# push @{$use_descriptions{$key}}, sprintf("(%s) [%s] %s", "@pkgs", $desc, $flagPrefix);
1217 +# }
1218 +# }
1219 +# return;
1220 +#}
1221
1222 # Write given list of flags back to make.conf if
1223 # the file has not been changed since reading it.