Handle slot in package.use
[portpeek.git] / portpeek
1 #!/usr/bin/python
2 #
3 # Copyright 2006 Mike Pagano
4 # Distributed under the terms of the GNU General Public License v2
5 #
6 # $Header$
7 # Author: Mike Pagano <mpagano@gentoo.org>
8 #
9 # Portions written ripped from 
10 # - equery, by Karl Trygve Kalleberg <karltk@gentoo.org>
11 # - gentoolkit.py, by Karl Trygve Kalleberg <karltk@gentoo.org>
12 # - portage.py
13 # - emerge
14 #
15 #
16
17 __author__ = "Michael Pagano"
18 __email__ = "mpagano@gentoo.org"
19 __version__ = "2.1.16"
20 __productname__ = "portpeek"
21 __description__ = "Displays user unmasked ebuilds and installable options from the portage tree"
22
23 import sys, os, portage, fileinput, re, gentoolkit
24 from gentoolkit.versionmatch import VersionMatch,errors
25 from portage.const import USER_CONFIG_PATH
26 from portage.versions import catpkgsplit,pkgcmp,pkgsplit
27 from portage.exception import InvalidAtom
28 from gentoolkit.cpv import CPV
29 from gentoolkit.query import Query
30 from gentoolkit.flag import get_iuse
31
32 # support python 2
33 try:
34     input = raw_input
35 except NameError:
36     pass
37
38 porttree = portage.db[portage.root]["porttree"]
39 settings = portage.config(clone=portage.settings)
40 #settings = portage.config(local_config=False)
41
42 show_changes_only_flag = False
43 checking_package_unmask = False
44 checking_package_mask = False
45 print_overlay_flag = False
46 info = 0
47 debug = 1
48 logLevel = info
49 show_removable_only_flag = False
50 stable_list = []
51 stable_listNg = [] # handle package.accept_keywords
52 unmask_list = []
53 tilde = 0
54 processing_package_use = False
55 using_gentoo_as_overlay = False
56 overlay_list = []
57 fix_confirm = True
58 fix_asked = False
59 use_flag_dict = {}
60 useremove_display = ""
61 invalid_flag_found = False
62
63 try:
64     PORTAGE_CONFIGROOT
65 except NameError:
66     PORTAGE_CONFIGROOT="/"
67
68 USER_CONFIG_PATH=PORTAGE_CONFIGROOT + USER_CONFIG_PATH
69
70 #parameters
71 options = [
72 "--keyword",
73 "--unmask",
74 "--mask",
75 "--all",
76 "--changes-only",
77 "--version",
78 "--version",
79 "--help",
80 "--removable-only",
81 "--debug",
82 "--fix", 
83 "--tilde-check",
84 "--no-color",
85 "--package-use",
86 "--fix-confirm"
87 ]
88
89 mappings = {
90 "k":"--keyword",
91 "u":"--unmask",
92 "m":"--mask",
93 "a":"--all",
94 "c":"--changes-only",
95 "V":"--version",
96 "v":"--version",
97 "h":"--help",
98 "r":"--removable-only",
99 "d":"--debug",
100 "f":"--fix", 
101 "t":"--tilde-check",
102 "n":"--no-color",
103 "s":"--package-use",
104 "q":"--fix-confirm"
105 }
106
107 cmdline = []
108 overlays = [settings["PORTDIR_OVERLAY"]]
109
110 def print_usage():
111     # Print full usage information for this tool to the console.
112     print ("\nUsage: " + portage.output.turquoise(__productname__) +  portage.output.yellow(" command "))
113     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [ options ]") +  portage.output.yellow(" command "))
114     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-c]") + portage.output.yellow(" [akmu]"))
115     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-r]") + portage.output.yellow(" [akmu]"))
116     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-f]") + portage.output.yellow(" [akmu]"))
117     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-F]") + portage.output.yellow(" [akmu]"))
118     print (portage.output.yellow(" command ") + " can be ")
119     print (portage.output.yellow(" -a, --all") + "       - show all matches")
120     print (portage.output.yellow(" -k, --keyword") + "       - show matches from package.keywords and package.accept_keywords only")
121     print (portage.output.yellow(" -m, --mask") + "      - show matches from package.mask only")
122     print (portage.output.yellow(" -u, --unmask") + "        - show matched from package.unmask only")
123     print (portage.output.yellow(" -s, --package.use") + "   - show matches from package.use only")
124     
125     print (portage.output.yellow(" -f, --fix") + "       - will remove the stabled and invalid packages without asking for confirmation")
126     print (portage.output.yellow(" -q, --confirm-fix") +"    - will remove the stabled and invalid packages asking for confirmation before doing so")
127     print (portage.output.yellow(" -h, --help") + "      - display this message")
128     print (portage.output.yellow(" -d, --debug") + "         - display more verbose output for debugging")
129     print (portage.output.yellow(" -V, --version") + "       - display version info")
130     print (portage.output.green("options") + " are ")
131     print (portage.output.green(" -c, --changes-only") + \
132         "   - show all matches that have upgrade option, use with " + \
133         "<" + portage.output.yellow(" k ") + "|" + portage.output.yellow(" u ") + \
134         "|" + portage.output.yellow(" m ") + "|" + \
135         portage.output.yellow(" a ") + ">")
136     print (portage.output.green(" -n, --no-color") + \
137         "   - suppress color output")
138     print (portage.output.green(" -r, --removable-only") + \
139         "   - show all matches that can be removed from package files, use with " + \
140         "<" + portage.output.yellow(" k ") + "|" + portage.output.yellow(" u ") + \
141         "|" + portage.output.yellow(" m ") + "|" + \
142         portage.output.yellow(" a ") + ">\n")
143
144 def get_keywords(package, var):
145     mytree = porttree
146     filtered_keywords = ""
147     try:
148         keywords = package.environment("KEYWORDS").split()
149     except KeyError as error:
150         print ("!!! Portpeek caught Exception:" + format(error))
151         print ("!!! This package/version seems to be no longer available, " + \
152         "please check and update/unmerge it") 
153         return "Not Available/Deprecated"
154     
155     #filtered_keywords = filter_keywords(keywords[0])
156     filtered_keywords = filter_keywords(keywords)
157     return filtered_keywords
158
159
160
161 # this is the main function for portpeek
162 # TODO comment this code!
163 def parse_line(line, filename):     
164     global info,debug,using_gentoo_as_overlay
165
166     using_gentoo_as_overlay = False
167     pkgs = None
168     ebuild_output = ""
169     check_pkg = ""
170     not_installed_pkgs = 0
171     pkg_length = 0
172     atom_check="<>=~"
173     original_line = line
174     has_asterick = False
175
176     # if the line has special characters, we need to make sure the original line is used for matching
177     special_line = False
178
179     pattern=r'[<>:*]'
180
181     if ( (re.search(pattern,line) != None) ):
182         special_line = True
183
184     if ( line.find("*") > 0 ) or ( line.find("<") >= 0 ):
185         has_asterick = True
186
187     print_output(debug,portage.output.blue("Analyzing line: " + line))
188
189     diffs_found = False
190     display_done = False
191
192     fields = line.replace("\t", " ").split(" ")
193
194     if len(fields) > 0:
195         #if the line does not start with an atom such as (= or >), do not validate 
196         #status as this tool is for check specific versions and not entire packages 
197         # a ~cpv should be handled like an =cpv if requested bythe parameter -t
198         check_pkg = fields[0] # this should be one of <>=~
199         orig_pkg_name = check_pkg
200         overlay_index = check_pkg.find("::")
201         if ( overlay_index >= 0):
202             overlay_list = check_pkg.rsplit("::")
203             if (len(overlay_list) > 0):
204                 overlay_name = overlay_list[1]
205                 if (overlay_name == "gentoo"):
206                     using_gentoo_as_overlay = True
207             check_pkg = check_pkg[0:check_pkg.find("::")]
208
209         if check_pkg[0] not in atom_check:
210
211             # if this is package_unmask, then check the non-atom containing package to see if any version is masked
212
213             if (checking_package_unmask == True):
214                 
215                 print_output(debug,portage.output.blue("check_pkg is " + check_pkg + " found"))
216                 if (is_any_cpv_keyword_masked(check_pkg) == False):
217                     print_output(info,portage.output.red("No masked versions of " + check_pkg + " found. Tagged for removal."))
218                     unmask_list.append(str(check_pkg))
219             return
220         if (tilde == 1):
221             if check_pkg[0] in "~":
222                 check_tilde_masked_pkg(check_pkg, filename)
223                 return
224
225         # determine if the package exists
226         try:
227             package_exists = portage.portdb.xmatch("match-all", fields[0])
228         except InvalidAtom:
229             package_exists = False
230
231         if package_exists:
232             # return a Package List based on the cpv
233             query = Query(check_pkg)
234             #query = Query(fields[0])
235             pkgs = []
236
237             try:
238                 pkgs = query.smart_find(True,True,True,True,False,True)
239             except errors.GentoolkitException as err:
240                 pass
241
242             if (pkgs != None):
243                 pkg_length = len(pkgs)
244                 not_installed_pkgs = 0
245                 display_done = False
246
247                 # go through each package version for a specific version found above
248                 for current_package in pkgs:
249                     if not current_package.is_installed():
250
251                         # we have found a package that is in our file, but not installed
252                         not_installed_pkgs = not_installed_pkgs + 1
253
254                         # check to see if specific version of pkg is not installed 
255                         # and display if true
256                         check_pkg = fields[0]
257                         if check_pkg[0] in atom_check:
258                             check_pkg = check_pkg[1:]
259
260                         if (check_pkg == str(current_package.cpv)):
261                             if (not checking_package_mask):
262                                 # package is not installed
263                                 print_output(info,portage.output.yellow("\n" + orig_pkg_name + ": ") + portage.output.red("Not Installed") , current_package, filename)
264                                 if "package.keywords" in filename:
265                                     stable_list.append(str(current_package.cpv))
266                                 if "package.accept_keywords" in filename:
267                                     stable_listNg.append(str(current_package.cpv))
268                                 unmask_list.append(str(current_package.cpv))
269                             else:
270                                 # package is masked, and not installed, this is normal use of package.mask
271                                 print_output(info,portage.output.green("" + orig_pkg_name + ": ") + portage.output.yellow("Package Masked"),current_package, filename)
272                             display_done = True
273                         continue
274
275                     # package is installed
276                     # retrieve the keywords for a file
277                     keywords = "%s" % (get_keywords(current_package,"KEYWORDS").split())
278                     if (keywords.find("Available/Deprecated") >= 0):
279                         continue
280
281                     #retrieve the mask status of a specific package
282                     pkgmask = _get_mask_status(current_package, False)
283
284                     #determine if installed package is unmasked, if so, display keywords as green
285                     stable = check_for_stable_release(current_package)
286
287                     # do not display if keywords don't exist
288                     if keywords == "[]":
289                         continue
290
291                     if stable:
292                         if ( not has_asterick): # if it has an asterick, then we don't remove
293                             ebuild_output = portage.output.green("Installed: ") + \
294                                 portage.output.turquoise(orig_pkg_name) + \
295                                 portage.output.green("  Keywords " + keywords)
296                             if "package.unmask" in filename:
297                                 unmask_list.append(str(current_package.cpv))
298                             if "package.keywords" in filename:
299                                 stable_list.append(str(current_package.cpv))
300                             if "package.accept_keywords" in filename:
301                                 stable_listNg.append(str(current_package.cpv))
302                     else:
303                         if (not show_removable_only_flag):
304                             if (not checking_package_unmask):
305                                 ebuild_output = portage.output.green("Installed: ") + \
306                                 portage.output.turquoise(orig_pkg_name) + \
307                                 portage.output.yellow("  Keywords " + keywords) 
308                         else:
309                             ebuild_output = portage.output.yellow(str(current_package.cpv))
310
311                     # check package.unmask
312                     if (checking_package_unmask):
313                         if (not is_any_cpv_file_masked(str(current_package.cpv))):
314
315                             # package is in package.unmask unnecessarily
316                             ebuild_output = portage.output.yellow("\n" + orig_pkg_name  + ": ") + portage.output.green("Not package masked")
317                             if "package.unmask" in filename:
318                                 unmask_list.append(str(current_package.cpv))
319                                 print_output (info, "" +  ebuild_output,None, filename)
320                                 continue
321
322                     # print once
323                     ebuild_search_key_printed = False
324                     if ( not has_asterick): # if it has an asterick, then we don't remove
325                         if stable:
326                             diffs_found = False
327                             ebuild_search_key_printed = True
328                             print_output(info,"\n" + ebuild_output,current_package, filename)
329                         elif not show_changes_only_flag and not show_removable_only_flag:
330                             diffs_found = False
331                             ebuild_search_key_printed = True
332                             print_output(info,"\n" + ebuild_output,current_package)
333
334                     # go through all versions of a package
335                     query = Query(current_package.category + "/" + current_package.name)
336
337                     all_pkgs = []
338
339                     try:
340                         all_pkgs = query.smart_find(True,True,True,True,False,True)
341                     except errors.GentoolkitException as err:
342                         print_output(debug,portage.output.blue("Package " + current_package.category + "/" + current_package.name + " not found."))
343
344                     for a_package in all_pkgs:
345                         if not a_package.is_installed():
346                             # a_package is not installed
347                             pkgmask = _get_mask_status(a_package, False)
348                             # print status line of package we are now checking
349                             print_output(debug,portage.output.blue("Checking package: " + str(a_package.cpv) +".pkgmask is " + str(pkgmask)))
350                             # if package versions are different
351                             if (VersionMatch(CPV(current_package.cpv)).match(CPV(a_package.cpv))):
352                                 diffs_found = True
353                                 keylist = a_package.environment("KEYWORDS")
354                                 keywords = "%s" % (filter_keywords(keylist)).split()
355                                 #if a_package is masked
356                                 if pkgmask > 0 and not show_removable_only_flag:
357                                     if show_changes_only_flag and not ebuild_search_key_printed:
358                                         print_output (info, "\n" +  ebuild_output, current_package)
359                                         ebuild_search_key_printed = True
360                                         check_for_stable_release(current_package)
361                                     if (pkgmask >= 3):
362                                         print_output (info,portage.output.red("Available: " + str(a_package.cpv) + " [M] Keywords: " + keywords),a_package)
363                                     else:
364                                         print_output (info,portage.output.brown("Available: " + str(a_package.cpv) + " Keywords: " + keywords),a_package)
365                                 else:
366                                     if show_changes_only_flag and not ebuild_search_key_printed:
367                                         print_output (info,"\n" + ebuild_output,current_package)
368                                         ebuild_search_key_printed = True
369                                         print_output(info,portage.output.green("Available: " + str(a_package.cpv) + " Keywords: " + keywords),a_package)
370                 #else:
371                     #print (portage.output.red ("\nCannot find package: " + check_pkg))
372
373                 # if package does not exist, and current_package is None
374                 # then make package using fields[0]
375
376                 # display if pkg/cat is not installed (missing version)
377                 if not_installed_pkgs ==  pkg_length:
378                     if not display_done:
379                         if (not checking_package_mask):
380                             print_output(info,portage.output.yellow("\n" + fields[0] + ": ") + portage.output.red("Not Installed"),current_package)
381                             if "package.keywords" in filename:
382                                 if (special_line == False):
383                                     stable_list.append(str(current_package.cpv))
384                                 else:
385                                     stable_list.append(original_line)
386                             if "package.accept_keywords" in filename:
387                                 if (special_line == False):
388                                     stable_listNg.append(str(current_package.cpv))
389                                 else:
390                                     stable_listNg.append(original_line)
391                             if (special_line == False):
392                                 unmask_list.append(str(current_package.cpv))
393                             else:
394                                 unmask_list.append(original_line)
395                         else:
396                             print_output (info,portage.output.green("\n" + str(current_package.cpv) + ": ") + portage.output.yellow("Package Masked"),current_package)
397         else:
398             diffs_found = True
399             print (portage.output.red ("\nPackage: " + fields[0] + " not found. Please check " + filename + " to validate entry"))
400             if "package.keywords" in filename:
401                 stable_list.append(fields[0])
402             if "package.accept_keywords" in filename:
403                 stable_listNg.append(fields[0])
404             unmask_list.append(fields[0])
405             show_all_versions(fields[0], filename)
406     current_package = ""
407
408     return diffs_found
409
410 # adding support for etc/portage/package.keywords/<whatever>/package.keywords
411 def get_recursive_info(filename):
412
413     # determine if filename is a directory
414     if os.path.isdir(filename):
415         # get listing of directory
416         filenames = os.listdir(filename)
417         for file_name in filenames:
418             get_recursive_info(filename+os.path.sep+file_name)
419     else:   
420         get_info(filename)
421
422 def get_info(filename):
423
424     diffs_found = False
425     no_file = False
426     filedescriptor = None
427
428     try:
429         filedescriptor = open(filename)
430         for line in filedescriptor.readlines():
431             line = line.strip()
432             if len(line) <= 0:
433                 continue
434             elif line.find("#") >= 0:
435                 # found '#' remove comment
436                 if (skipFile(line,filename)):
437                     return
438                 line = line[0:line.find("#")]
439                 line = line.strip()
440                 if len(line) <= 0:
441                     continue
442             if (processing_package_use == False):
443                 diffs_found = parse_line(line, filename)
444             else:
445                 # process package.use
446                 diffs_found = parse_package_use(line,filename)
447     except IOError:
448         print (portage.output.red("Could not find file " + filename))
449         no_file = True
450
451     if not diffs_found and no_file:
452         print (portage.output.brown("No ebuild options found."))
453
454     # close file
455     if (filedescriptor != None):
456         filedescriptor.close()
457
458 # parse the package.use file and look for packages
459 # not installed
460 def parse_package_use(line, filename):
461
462     global info,debug
463     print_output(debug,portage.output.blue("parse_package_use: Line: " + line))
464     pkgs = None
465     check_pkg = ""
466     pkg_length = 0
467     atom_check="<>="
468     any_version = False
469     has_atom = True
470
471     diffs_found = False
472     package_installed = False
473     fields = line.replace("\t", " ").split(" ")
474     less_than = False
475     less_than_or_equal = False
476
477     if len(fields) > 0:
478         check_pkg = fields[0] # this could be one of <>=
479         orig_pkg_name = check_pkg
480         if check_pkg[0] not in atom_check:
481             has_atom = False
482         else:
483             if check_pkg[0] == '<':
484                 less_than = True;
485                 if check_pkg[1] == '=':
486                     less_than_or_equal = True
487
488             check_pkg = check_pkg[1:]
489             if check_pkg[0] in atom_check:
490                 check_pkg = check_pkg[1:]
491
492
493         # if there is a wildcard, check to make sure at least one
494         # of the packages is installed
495         if check_pkg.find("/*") >= 0:
496             query = Query(check_pkg)
497             pkgs = []
498             try:
499                 pkgs = query.smart_find(True,True,True,True,False,True)
500             except errors.GentoolkitException as err:
501                 print_output(debug,portage.output.blue("parse_package_use: Package " + check_pkg + " not found."))
502                 return False
503
504             if (pkgs != None):
505                 pkg_length = len(pkgs)
506             for current_package in pkgs:
507                 # on wildcard scenario, return False if one package is installed
508                 if current_package.is_installed():
509                     check_useflags(current_package,line)
510                     return False
511         check_pkg = (check_pkg.rsplit(':',1))[0]
512         
513         if ((orig_pkg_name.find("<=") >=0) or (orig_pkg_name.find("<")>=0) or (orig_pkg_name.find(">=") >=0) or (orig_pkg_name.find(">") >=0)):
514             query = Query(check_pkg)
515             pkgs = []
516             try:
517                 pkgs = query.smart_find(True,True,True,True,False,True)
518             except errors.GentoolkitException as err:
519                 print_output(debug,portage.output.blue("parse_package_use: Package " + check_pkg + " not found."))
520                 return False
521
522             if (pkgs != None):
523                 pkg_length = len(pkgs)
524             for current_package in pkgs:
525                 # on wildcard scenario, return False if one package is installed
526                 if (orig_pkg_name.find("<=") >=0):
527                     if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) <= 0):
528                         if current_package.is_installed():
529                             check_useflags(current_package,line)
530                         return False
531                 else:
532                     if (orig_pkg_name.find("<") >=0):
533                         if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) < 0):
534                             if current_package.is_installed():
535                                 check_useflags(current_package,line)
536                             return False
537                 if (orig_pkg_name.find(">=") >=0):
538                     if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 0) or (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 2):
539                         if current_package.is_installed():
540                             check_useflags(current_package,line)
541                         return False
542                 else:
543                     if (orig_pkg_name.find(">") >=0):
544                         if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 2):
545                             if current_package.is_installed():
546                                 check_useflags(current_package,line)
547                             return False
548         else:
549             # look for any version of check_pkg installed as there is 
550             # no version specified in package.use
551             package_exists = portage.portdb.xmatch("match-all", check_pkg)
552             if package_exists:
553                 # get all package versions
554                 query = Query(check_pkg)
555                 pkgs = []
556                 try:
557                     pkgs = query.smart_find(True,True,True,True,False,True)
558                 except errors.GentoolkitException as err:
559                     print_output(debug,portage.output.blue("Package " + check_pkg + " not found."))
560     
561                 if (pkgs != None):
562                     pkg_length = len(pkgs)
563     
564                     # go through each package version for a specific 
565                     # version found above
566                     # if one line check returns all ok, we don't need 
567                     #to check the rest. One slot could have different 
568                     #use flags than another
569                     if (has_atom == False):
570                         check_useflags_all_versions(pkgs, line, check_pkg)
571                         package_installed = check_for_any_installed_version(pkgs)
572                         current_package = None
573
574                         #for current_package in pkgs:
575                         #    if current_package.is_installed():
576                         #        check_useflags(current_package,line)
577                         #        package_installed = True
578                         #        if (invalid_flag_found == False):
579                         #            break;
580                     else: 
581                         # go through each package version for a specific version found above
582                         for current_package in pkgs:
583                             if (str(current_package.cpv) == check_pkg):
584                                 if not current_package.is_installed():
585                                     print_output(info,portage.output.yellow("\n" + orig_pkg_name + ": ") + portage.output.red("Not Installed"),current_package)
586                                     if "package.keywords" in filename:
587                                         stable_list.append(check_pkg)
588                                     if "package.accept_keywords" in filename:
589                                         stable_listNg.append(check_pkg)
590                                     unmask_list.append(check_pkg)
591                                     if "package.use" in filename:
592                                         valid_flag_list = []
593                                         valid_flag_list.insert(0,current_package);
594                                         use_flag_dict[line] = valid_flag_list
595                                         check_for_change = use_flag_dict[line]
596                                     return True
597                                 else:
598                                     check_useflags(current_package,line)
599                                     return False
600             else:
601                 print (portage.output.red ("\nPackage: " + fields[0] + " not found. Please check " + filename + " to validate entry"))
602                 if "package.keywords" in filename:
603                     stable_list.append(check_pkg)
604                 if "package.accept_keywords" in filename:
605                     stable_listNg.append(check_pkg)
606                 unmask_list.append(check_pkg)
607                 if "package.use" in filename:
608                     valid_flag_list = []
609                     #valid_flag_list.insert(0,current_package);
610                     valid_flag_list.insert(0,fields[0]);
611                     use_flag_dict[line] = valid_flag_list
612                     check_for_change = use_flag_dict[line]
613                 return True
614
615     if (package_installed == False):
616         # package does not exists
617         print_output(info,portage.output.yellow("\n" + orig_pkg_name + ": ") + portage.output.red(" Not Installed"),current_package)
618         if "package.keywords" in filename:
619             stable_list.append(check_pkg)
620         if "package.accept_keywords" in filename:
621             stable_listNg.append(check_pkg)
622         if "package.use" in filename:
623             valid_flag_list = []
624             valid_flag_list.insert(0,current_package);
625             use_flag_dict[line] = valid_flag_list
626             check_for_change = use_flag_dict[line]
627
628         unmask_list.append(check_pkg)
629         return True
630
631     return False
632
633
634
635
636 # skip the file if portpeek-skip found in a comment
637 # you can put this in the middle of a file and it will
638 #skip all entrie below it, this is useful to speed things
639 #up by not checking ~kde versions, for example
640 def skipFile (line, filename):
641     if ( (line == None) or (filename == None)):
642         return False
643
644     if line.find("portpeek-skip") >= 0:
645         return True
646
647     return False
648
649 # parts blatantly stolen from equery
650 # if pure is true, then get "true" mask status that is
651 # not affected by entries in /etc/portage/package.*
652 def _get_mask_status(pkg, pure):
653     pkgmask = 0
654
655     if (pkg == None):
656         return 0
657
658     if pkg.is_masked():
659         pkgmask = pkgmask + 3
660
661     if pure:
662         try:
663             keywords = portage.portdb.aux_get(str(pkg.cpv), ["KEYWORDS"])
664             keywords = keywords[0].split()
665         except KeyError:
666             # cpv does not exist
667             return 0
668     else:
669         keywords = pkg.environment("KEYWORDS").split()
670
671     # first check for stable arch, stop there if it is found
672     if settings["ARCH"] in keywords:
673         return 0
674
675     if "~" + settings["ARCH"] in keywords:
676         pkgmask = pkgmask + 1
677     elif "-*" in keywords or "-" + settings["ARCH"] in keywords:
678         pkgmask = pkgmask + 2
679     
680     return pkgmask
681
682 def is_pkg_package_masked(cpv):
683
684     print_output(debug,portage.output.blue("is_pkg_package_masked called: " + cpv))
685     settings2 = portage.config(local_config=False)
686     portdb2 = portage.portdbapi(None, settings)
687
688     mask_reason_list = None
689     
690     try:
691         for mask_reason_list in portage.getmaskingstatus(cpv, settings2, portdb=portdb2):
692             return True
693     except:
694         return False
695
696     return False
697
698 # filter out keywords for archs other than the current one
699 def filter_keywords(keywords):
700     filtered_keywords = ""
701
702     #for key in key_list:
703     for key in keywords:
704         key = key.replace("[", '')
705         key = key.replace("]", "")
706         key = key.replace(",", "")
707         arch=settings["ARCH"]
708
709         # remove '~' from key for comparison
710         key_comparison = key.lstrip('~')
711         if key_comparison == arch:
712             if len(filtered_keywords) != 0:
713                 filtered_keywords = filtered_keywords + " "
714             filtered_keywords = filtered_keywords + key
715         elif "-*" in key:
716             if len(filtered_keywords) != 0:
717                 filtered_keywords = filtered_keywords + " "
718             filtered_keywords = filtered_keywords + key
719
720
721     return filtered_keywords
722
723
724 # this function takes in a package with no cpv
725 # and returns True if any version is masked
726 def is_any_cpv_keyword_masked(package_name):
727     print_output(debug,portage.output.blue("inside is_any_cpv_keyword_masked: " + package_name))
728
729     query = Query(package_name, True)
730
731     packages = []
732     try:
733         packages = query.smart_find(True,True,True,True,False,True)
734     except errors.GentoolkitException as err:
735         print_output(debug,portage.output.blue("Package " + package_name + " not found."))
736
737     for package in packages:
738         if is_pkg_package_masked(package.cpv):
739             print_output(debug,portage.output.blue("Package " + package.cpv + " is masked."))
740             return True
741
742     print_output(debug,portage.output.blue("Package " + package_name + ". No masked versions."))
743     return False
744
745 # we need to know if the package is masked
746 # by being present in the package.mask file
747 # as opposed to masked by keyword.
748 # if it's not, then we can remove from package.unmask
749 def is_any_cpv_file_masked(package_name):
750
751     print_output(debug,portage.output.blue("is_any_cpv_file_masked called: " + package_name))
752     settings2 = portage.config(local_config=False)
753     portdb2 = portage.portdbapi(None, settings)
754
755     mask_reason_list = None
756
757     try:
758         for mask_reason_list in portage.getmaskingstatus(package_name, settings2, portdb=portdb2):
759             print_output(debug,portage.output.blue("Mask Reason is " + mask_reason_list))
760             if (mask_reason_list == 'package.mask'):
761                 return True
762     except:
763         return False
764
765     return False
766
767
768
769 # check to see if we have a stable release
770 # in our package.* files that we can remove
771 def check_for_stable_release(pkg):
772     if not is_pkg_package_masked(str(pkg.cpv)):
773         status = _get_mask_status(pkg, True)
774         if status == 0:
775             return True
776     return False
777
778 #print version info
779 def print_version():
780     # Print the version of this tool to the console.
781     print (__productname__ + "(" + __version__ + ") - " + \
782         __description__)
783     print ("Author(s): " + __author__)
784
785 # function to go through a ~cp without a version
786 # and set for removal from file if no masked package version exists
787 def check_tilde_masked_pkg(package_name, filename):
788     ebuild_output=""
789     variable_version = ""
790
791     orig_package_name = package_name
792     package_name = package_name.replace('~','')
793
794     print_output(debug,portage.output.blue("check_tilde_maskd_pkg: orig_package-name is " + orig_package_name))
795     print_output(debug,portage.output.blue("check_tilde_maskd_pkg: package_name is " + package_name))
796
797     query = Query(package_name, True)
798
799     packages = []
800     try:
801         packages = query.smart_find(True,True,True,True,False,True)
802     except errors.GentoolkitException as err:
803         print_output(debug,portage.output.blue("Package " + package_name + " not found."))
804
805     no_versions_installed = True
806     for package in packages:
807         if package.is_installed():
808             no_versions_installed = False
809
810     if (no_versions_installed == True):
811         ebuild_output = portage.output.yellow("\n" + package_name + ": ") + portage.output.red("Not Installed")
812         if "package.unmask" in filename:
813             unmask_list.append(orig_package_name)
814         if "package.keywords" in filename:
815             stable_list.append(orig_package_name)
816         if "package.accept_keywords" in filename:
817             stable_listNg.append(orig_package_name)
818         print (ebuild_output + portage.output.brown(" : " + filename))
819
820         return
821
822     # get all packages matching cat/package
823     if (packages != None):
824         for current_package in packages:
825             print_output(debug,portage.output.blue("check_tilde_maskd_pkg: current_package is " + str(current_package.cpv)))
826             print_output(debug,portage.output.blue("comparing " + package_name + " to " + str(current_package.cpv)))
827             if (pkgcmp(pkgsplit(package_name),pkgsplit(str(current_package.cpv))) <=0 ):
828             #if (pkgcmp(package_name, str(current_package.cpv)) <= 0):
829                 packageObj = gentoolkit.package.Package(str(current_package.cpv))
830                 if (packageObj == None):
831                     # we could not create a package object
832                     return
833
834                 if "package.unmask" in filename:
835                     #if (is_pkg_package_masked(str(current_package.cpv))):
836                     if (is_any_cpv_file_masked(str(current_package.cpv))):
837                         # package was found as masked
838                         return
839                     else:
840                         # package is not masked
841                         unmask_list.append(str(current_package.cpv))
842                         ebuild_output = portage.output.yellow(str(current_package.cpv) + ": ") + portage.output.green("Not package masked")
843                         print_output(info,ebuild_output, package, filename)
844                         return
845                 else:
846                     if (is_pkg_package_masked(str(current_package.cpv))):
847                         # package was found as masked
848                         return 
849         else:
850             # at this point we have no packages >= ~cpv that are masked, present for removal
851             # package does not have any masked versions
852             ebuild_output = portage.output.green(package_name + " has no masked versions")
853             
854             if "package.unmask" in filename:
855                 unmask_list.append(orig_package_name)
856             if "package.keywords" in filename:
857                 stable_list.append(orig_package_name)
858             if "package.accept_keywords" in filename:
859                 stable_listNg.append(orig_package_name)
860             print_output(info,ebuild_output, package, filename)
861
862 #helper function to print avail pks when version does not exist
863 def show_all_versions(pkg, filename):
864
865     # is package masked
866     is_package_masked = False
867     pkgArr = portage.pkgsplit(pkg)
868
869     if pkgArr is None or len(pkgArr) == 0:
870         return
871
872     # determine if category/package is masked 
873     package = pkgArr[0]
874
875     operator = portage.dep.Atom(pkg).operator
876     if operator is not None:
877         package = package[len(operator):]
878
879     # package is category/package and pkg is category/package-version
880     # is category/package-version we are checking package masked?
881     #if portage.settings.pmaskdict.has_key(package):
882     pmaskdict = settings._mask_manager._pmaskdict
883     if package in pmaskdict:
884         pkg_list = pmaskdict.get(package)
885         # iterate through list array looking for pkg
886         for pkg_check in pkg_list:
887             operator = portage.get_operator(pkg_check)
888             if operator is None:
889                 if pkg_check == package:
890                     is_package_masked = True
891
892     query = Query(package)
893
894     all_pkgs = []
895
896     try:
897         all_pkgs = query.smart_find(True,True,True,True,False,True)
898     except errors.GentoolkitException as err:
899         print_output(debug,portage.output.blue("Package " + package + " not found."))
900
901     for current_package in all_pkgs:
902         keywords = "%s" % (current_package.environment("KEYWORDS").split())
903         keywords = filter_keywords(keywords)
904         keywords = "[%s]" % (keywords)
905         ebuild = current_package.ebuild_path()
906         if ebuild:
907             pkgmask = _get_mask_status(current_package, True)
908             if is_package_masked:
909                 print (portage.output.red("Available: " + str(current_package.cpv) + " [M] Keywords: " + keywords))
910             elif pkgmask > 4:
911                 print (portage.output.red("Available: " + str(current_package.cpv) + " [M] Keywords: " + keywords))
912             elif pkgmask == 4 or pkgmask == 1:
913                 print (portage.output.brown("Available: " + str(current_package.cpv) + " Keywords: " + keywords))
914             else:
915                 print (portage.output.green("Available: " + str(current_package.cpv) + " Keywords: " + keywords))
916                 if "package.keywords" in filename:
917                     stable_list.append(str(current_package.cpv))
918                 if "package.accept_keywords" in filename:
919                     stable_listNg.append(str(current_package.cpv))
920
921
922 def get_useflags(package):
923     iuse = get_iuse(package.cpv)
924     return iuse
925
926 def check_useflags_all_versions(pkgs, line, check_pkgs):
927
928     global useremove_display, invalid_flag_found 
929     invalid_flag_found = False
930    
931     print_output(debug,portage.output.blue("ENTERED check_useflags_all_versions: " + check_pkgs))
932
933     potential_invalid_flag = []
934     valid_flag_list = []
935     for package in pkgs:
936
937         # if package not installed, move on
938         if (not package.is_installed()):
939             continue;
940
941         print_output(debug,portage.output.blue("check_useflags_all_versions: package: " + package.cpv))
942         if ((package is None) or (package == "")):
943             return
944
945         useflag_removal_display=""
946
947         if (len(line) <= 0):
948             return
949
950         list2 = get_useflags(package)
951
952         for uf in list2:
953             print_output(debug,portage.output.blue(("use found " + uf)))
954  
955         iuse_string = package.use()
956         iuse = iuse_string.split(" ")
957
958         for uflag in list2:
959             iuse.append(uflag)
960
961         for iuse_item in iuse:
962             print_output(debug,portage.output.blue(("iuse_item is " + iuse_item)))
963
964         useflags_fromfile = line.replace("\t", " ").split(" ")
965
966         #for useflags_fromfile_item in useflags_fromfile:
967         #    print_output(debug,portage.output.blue(("useflags_fromfile_item is " + useflags_fromfile_item)))
968
969         package_string = useflags_fromfile.pop(0)
970         print_output(debug,portage.output.blue(("package_string is " + package_string)))
971     
972         clean_useflags_list = []
973         # remove + or -
974         atom = "-+"
975     
976         #clean list from portage of + or -
977         clean_iuse = []
978         for item in iuse:
979             if item[0] in atom:
980                 clean_iuse.append(item[1:])
981             else:
982                 clean_iuse.append(item)
983     
984         for original_flag in useflags_fromfile:
985             if (original_flag is None or original_flag == ""):
986                 continue
987             flag = original_flag
988             if original_flag[0] in atom:
989                 flag = original_flag[1:]
990             if flag not in clean_iuse:
991                 print_output(debug,portage.output.blue(("found invalid flag: " + flag)))
992
993                 # only add to invalid list if it's not in valid list
994                 try:
995                     index = valid_flag_list.index(original_flag)
996                 except ValueError as error:
997
998                     try:
999                        index = potential_invalid_flag.index(original_flag)
1000                     except ValueError:
1001                        print_output(debug,portage.output.blue(original_flag + " not found for " + package.cpv))
1002                        potential_invalid_flag.append(original_flag)
1003
1004             else:
1005                 print_output(debug,portage.output.blue(("found valid flag: " + flag)))
1006                 try:
1007                     index = valid_flag_list.index(original_flag)
1008                 except ValueError as error:
1009                     valid_flag_list.append(original_flag)
1010
1011                 try:
1012                     index = potential_invalid_flag.index(original_flag)
1013                     potential_invalid_flag.remove(original_flag)
1014                 except ValueError as error:
1015                     continue
1016
1017
1018     # if potential_invalid_flag list is empty, we are done
1019     if (len(potential_invalid_flag) <= 0):
1020         return
1021
1022     invalid_flag_found = True
1023
1024     # build sentence
1025     invalid_flags = ""
1026     verb = "is"
1027     for inv_flag in potential_invalid_flag:
1028         if (len(invalid_flags) > 0):
1029             invalid_flags += ","
1030             verb = "are"
1031         invalid_flags += inv_flag
1032
1033     # if there are no valid flags at all, we remove the line
1034     if ( len(valid_flag_list) == 0):
1035         print_output (info,portage.output.red("No valid use flags found for package: " + str(package.category) + "/" + str(package.name) + ". Invalid flag(s) found: " + invalid_flags +  "\n"))
1036         useremove_display += "Removing line: " + line + "\n"
1037         use_flag_dict[line] = ""
1038         return
1039
1040     # if there are values in potential_invalid_flag, we need to remove them
1041
1042     if (len(potential_invalid_flag) > 0):
1043         removal_text = "use flags: "
1044     else:
1045         removal_text = "use flag: "
1046
1047     if ( (len(valid_flag_list) > 0)):
1048         useremove_display += "Removing " + removal_text + invalid_flags + " for package " + check_pkgs + "\n"
1049         print (portage.output.yellow(removal_text) +  portage.output.red(invalid_flags) + portage.output.yellow(" " + verb + " invalid for " + str(package.cpv)))
1050
1051     valid_flag_list.insert(0,package_string);
1052
1053     if (len(potential_invalid_flag) > 0):
1054         use_flag_dict[line] = valid_flag_list
1055         
1056     return valid_flag_list
1057
1058 def check_useflags(package,line):
1059
1060     global useremove_display, invalid_flag_found 
1061     invalid_flag_found = False
1062
1063     print_output(debug,portage.output.blue("check_useflags: package: " + package.cpv))
1064     if ((package is None) or (package == "")):
1065         return
1066
1067     useflag_removal_display=""
1068
1069     if (len(line) <= 0):
1070         return
1071
1072     iuse = get_useflags(package)
1073
1074     #for iuse_item in iuse:
1075     #    print_output(debug,portage.output.blue(("iuse_item is " + iuse_item)))
1076
1077     useflags_fromfile = line.replace("\t", " ").split(" ")
1078     #for useflags_fromfile_item in useflags_fromfile:
1079     #    print_output(debug,portage.output.blue(("useflags_fromfile_item is " + useflags_fromfile_item)))
1080
1081     package_string = useflags_fromfile.pop(0)
1082     print_output(debug,portage.output.blue(("package_string is " + package_string)))
1083
1084     clean_useflags_list = []
1085     # remove + or -
1086     atom = "-+"
1087
1088     #clean list from portage of + or -
1089     clean_iuse = []
1090     for item in iuse:
1091         if item[0] in atom:
1092             clean_iuse.append(item[1:])
1093         else:
1094             clean_iuse.append(item)
1095
1096     valid_flag_list = []
1097     for original_flag in useflags_fromfile:
1098         if (original_flag is None or original_flag == ""):
1099             continue
1100         flag = original_flag
1101         if original_flag[0] in atom:
1102             flag = original_flag[1:]
1103         if flag not in clean_iuse:
1104             print_output (info,portage.output.red("use flag: " + flag + " is invalid for : " + str(package.cpv)))
1105             useflag_removal_display += "Removing use flag: " + flag + " for package " + str(package.cpv)
1106             invalid_flag_found = True
1107         else:
1108             valid_flag_list.append(original_flag)
1109
1110     # if valid_flag_list is empty, there are no valid flags
1111     if ( (len(valid_flag_list) > 0) and (len(useflag_removal_display) >0)):
1112         useremove_display += useflag_removal_display + "\n"
1113     elif ( len(valid_flag_list) == 0):
1114         useremove_display += "No valid use flags found for package " + str(package.cpv) + ". Removing line: " + line + "\n"
1115         if ( invalid_flag_found != True):
1116             print_output (info,portage.output.red("No valid use flags found for package " + str(package.cpv)))
1117         invalid_flag_found = True
1118
1119     valid_flag_list.insert(0,package_string);
1120     if (invalid_flag_found == True):
1121         use_flag_dict[line] = valid_flag_list
1122
1123     return valid_flag_list
1124
1125
1126 def clean_useflagsFile(filename):
1127
1128     if "--fix-confirm" in cmdline:
1129         if (confirmFix() == False):
1130             return
1131     
1132     display_line = ""
1133     removed_list = []
1134
1135     try:
1136         # determine if filename is a directory
1137         if os.path.isdir(filename):
1138             # get listing of directory
1139             filenames = os.listdir(filename)
1140             for file_name in filenames:
1141                 clean_useflagsFile(filename+os.path.sep+file_name)
1142             return
1143         else:
1144             #go through stable array and remove line if found
1145             for line in fileinput.input(filename,inplace =1):
1146                 itemFound = False
1147                 line = line.strip()
1148
1149                 # make sure line is not empty and do not remove commented out lines
1150                 if len(line) <= 0:
1151                     continue
1152                 elif line.find("#") == 0:
1153                     print (line)
1154                     continue
1155
1156                 check_for_change = ""
1157                 use_flag_dict.get(line,"")
1158                 try:
1159                     check_for_change = use_flag_dict[line]
1160                     removed_list.append(line)
1161                     if ( len(check_for_change) > 1):
1162                         print (" ".join(check_for_change))
1163                 except KeyError as error:
1164                     print (line)
1165
1166             fileinput.close()
1167     except OSError as error:
1168         print (portage.output.red("Modify/Read access to file: " + filename + " failed: " + format(error)))
1169
1170     if (len(removed_list) > 0):
1171         print ("\n")
1172         for package in removed_list:
1173             print (portage.output.red("Removing from: ") + portage.output.yellow(filename + ": Invalid use flag(s) from ")  + portage.output.green(package) + "\n")
1174
1175     return
1176
1177 def handle_if_overlay(package):
1178     overlay_text = ""
1179     global print_overlay_flag,using_gentoo_as_overlay
1180
1181     if (using_gentoo_as_overlay):
1182         return overlay_text
1183
1184     print_overlay_flag = True
1185
1186     ebuild_path,overlay_path = porttree.dbapi.findname2(str(package.cpv))
1187     index = -1
1188     try:
1189         index = overlay_list.index(overlay_path)
1190     except ValueError as error:
1191         overlay_list.append(overlay_path)
1192         index = overlay_list.index(overlay_path)
1193
1194     overlay_text = " [%s]" % (str(index+1))
1195
1196     return overlay_text
1197
1198 # if the overlay_text was displayed to the user
1199 # we need to display the string at the end 
1200 # this array will store the overlays to be displayed
1201 def print_overlay_text():
1202    
1203     global print_overlay_flag
1204     
1205     if (not print_overlay_flag):
1206         return
1207     
1208     if (len(overlay_list) <= 0):
1209         return
1210
1211     index = 1
1212     for x in overlay_list:
1213         print (portage.output.turquoise("[" + str(index) + "] ") + x)
1214         index = index + 1
1215     
1216     print ("\n")
1217
1218 #helper function to print output
1219 def print_output(log_level,output_string, package=None, filename=None):
1220     
1221     global logLevel
1222
1223     if package != None:
1224         if (package.is_overlay()):
1225             output_string = "%s%s" % (output_string,portage.output.turquoise(handle_if_overlay(package)))
1226             #output_string = output_string + portage.output.turquoise(handle_if_overlay(package))
1227         else:
1228             if filename != None:
1229                 output_string = "%s%s" % (output_string,portage.output.brown(" : " + filename))
1230                 #output_string = output_string + portage.output.brown(" : " + filename)
1231
1232     if (log_level <= logLevel):
1233         print (output_string)
1234
1235 # remove stabled files that are no longer needed from package.keywords
1236 # or package.mask
1237 # includes support for etc/portage/package.keywords/<whatever>/package.keywords
1238 def cleanFile (filename):
1239
1240     removeDups = []
1241     removed_list = []
1242
1243     if "--fix-confirm" in cmdline:
1244         if (confirmFix() == False):
1245             return
1246
1247     # if the file or directory does not exist
1248     # exit out
1249     if (os.path.exists(filename) == False):
1250         return
1251     
1252     if "package.keywords" in filename:
1253         if ( len(stable_list) == 0):
1254             return
1255         removeDups = stable_list
1256     elif "package.accept_keywords" in filename:
1257         if ( len(stable_listNg) == 0):
1258             return
1259         removeDups = stable_listNg
1260     else:
1261         if ( len(unmask_list) == 0):
1262             return
1263         removeDups = unmask_list
1264
1265     removedDict = {}
1266
1267     try:
1268         # determine if filename is a directory
1269         if os.path.isdir(filename):
1270             # get listing of directory
1271             filenames = os.listdir(filename)
1272             for file_name in filenames:
1273                 cleanFile(filename+os.path.sep+file_name)
1274             return
1275         else:   
1276             #go through stable array and remove line if found
1277             for line in fileinput.input(filename,inplace =1):
1278                 itemFound = False
1279                 line = line.strip()
1280
1281                 # make sure line is not empty and do not remove commented out lines
1282                 if len(line) <= 0:
1283                     continue
1284                 elif line.find("#") == 0:
1285                     print (line)
1286                     continue
1287
1288                 for item in removeDups:
1289                     if item in line:
1290                         removed_list.append(item)
1291                         removedDict[filename] = item
1292                         itemFound = True
1293                         removeDups.pop(removeDups.index(item))
1294                         break
1295                 if (itemFound == False):
1296                     print (line)
1297             fileinput.close()
1298     except OSError as error:
1299         print (portage.output.red("Modify/Read access to file: " + filename + " failed: " + format(error)))
1300     
1301     if (len(removed_list) > 0):
1302         print ("\n")
1303         for package in removed_list:
1304             print (portage.output.red("Removing from: ") + portage.output.yellow(filename) + ": " + portage.output.green(package) + "\n")
1305
1306 # ask the user if they want to fix their files
1307 # and remove unneeded entries
1308 # Return true if they say yes and False if they say no
1309 def confirmFix():
1310     
1311     global fix_asked,fix_confirm
1312
1313     if (fix_asked == True):
1314         return fix_confirm
1315
1316     # only ask if we actually have anything to check
1317     if ( (len(stable_list) == 0) and 
1318           (len(stable_listNg) == 0) and
1319           (len(unmask_list) == 0) and
1320           (invalid_flag_found == False) and 
1321           (len(use_flag_dict) == 0)):
1322         fix_confirm = True
1323         return fix_confirm
1324
1325     fix_asked = True 
1326
1327     valid = {"yes":"yes",   "y":"yes", 
1328              "no":"no",     "n":"no"}
1329    
1330     prompt = portage.output.bold("Remove entries from files [") + portage.output.green("y") + "/" + portage.output.red("n") + portage.output.bold("]") + " "
1331
1332     while 1:
1333         sys.stdout.write('\n' + prompt)
1334         choice = input().lower()
1335         if choice == '':
1336             fix_confirm = False
1337             break
1338         elif choice in valid.keys():
1339             if (choice == 'y' or choice == 'yes'):
1340                 fix_confirm = True
1341                 break
1342             else:
1343                 fix_confirm = False
1344                 break 
1345         else:
1346             sys.stdout.write("Please respond with 'yes' or 'no' "\
1347                              "(or 'y' or 'n').\n")
1348
1349     return fix_confirm
1350
1351
1352 def check_for_any_installed_version(pkgs):
1353     
1354     for package in pkgs:
1355         if (package.is_installed()):
1356             return True
1357
1358     return False
1359
1360 # main
1361 if __name__ == "__main__":
1362
1363     if len(sys.argv) == 1:
1364         print_usage()
1365         sys.exit(1)
1366
1367     # soooooo stolen from emerge
1368     tmpcmdline = sys.argv[1:]
1369
1370     for cmd in tmpcmdline:
1371         if cmd[0:1] == "-" and cmd[1:2] != "-":
1372             for cmd_item in cmd[1:]:
1373                 if cmd_item in mappings:
1374                     if mappings[cmd_item] in cmdline:
1375                         print ()
1376                         print ("*** Warning: Redundant use of ", mappings[cmd_item])
1377                     else:
1378                         cmdline.append(mappings[cmd_item])
1379                 else:
1380                     print ("!!! Error: -"+cmd_item+" is an invalid option.")
1381                     sys.exit(-1)
1382         else:
1383             cmdline.append(cmd)
1384
1385     #parse long options
1386     for cmd in cmdline:
1387         if len(cmd)>=2 and cmd[0:2]=="--":
1388             try:
1389                 i = options.index(cmd)
1390                 continue
1391             except ValueError:
1392                 print ("!!! Error: -"+cmd+" is an invalid option.")
1393                 sys.exit(-1)
1394
1395     if "--changes-only" in cmdline:
1396         cmdline.remove("--changes-only")
1397         show_changes_only_flag = True
1398
1399     if "--removable-only" in cmdline:
1400         cmdline.remove("--removable-only")
1401         show_removable_only_flag = True
1402
1403     if "--debug" in cmdline:
1404         logLevel = debug
1405
1406     if "--no-color" in cmdline:
1407         portage.output.nocolor()
1408
1409     if "--tilde-check" in cmdline:
1410         tilde=1
1411
1412     if "--version" in cmdline:
1413         print_version()
1414         sys.exit(0)
1415
1416     if "--fix-confirm" in cmdline:
1417         if '--fix' not in cmdline:
1418             cmdline.append("--fix")
1419     
1420     if "--all" in cmdline:
1421         tmpcmdline = ["--all"]
1422         if "--fix" in cmdline:
1423             tmpcmdline.append("--fix")
1424             if "--fix-confirm" in cmdline:
1425                 tmpcmdline.append("--fix-confirm")
1426                 fix_confirm = False
1427         cmdline=tmpcmdline      
1428
1429     if "--help" in cmdline:
1430         print_usage()
1431         sys.exit(0)
1432     
1433     if (show_changes_only_flag and show_removable_only_flag):
1434         print ("Please select only one of --show-removable (-r) or --changes-only")
1435         print ("Use --help for more info.")
1436         sys.exit(0)
1437         
1438     for cmd in cmdline:
1439         if cmd == "--keyword":
1440             print (portage.output.bold("\npackage.keywords:"))
1441             get_recursive_info(USER_CONFIG_PATH + "/package.keywords")
1442             if "--fix" in cmdline:
1443                 cleanFile(USER_CONFIG_PATH + "/package.keywords")
1444             print (portage.output.bold("Done\n"))
1445             print (portage.output.bold("\npackage.accept_keywords:"))
1446             get_recursive_info(USER_CONFIG_PATH + "/package.accept_keywords")
1447             if "--fix" in cmdline:
1448                 cleanFile(USER_CONFIG_PATH + "/package.accept_keywords")
1449             print (portage.output.bold("Done\n"))
1450         elif cmd == "--unmask": 
1451             print (portage.output.bold("\npackage.unmask:"))
1452             checking_package_unmask = True
1453             get_recursive_info(USER_CONFIG_PATH + "/package.unmask")
1454             checking_package_unmask = False
1455             if "--fix" in cmdline:
1456                 cleanFile(USER_CONFIG_PATH + "/package.unmask")
1457         elif cmd == "--mask":
1458             checking_package_mask = True
1459             print (portage.output.bold("\npackage.mask:"))
1460             get_recursive_info(USER_CONFIG_PATH + "/package.mask")
1461             print (portage.output.bold("Done\n"))
1462             checking_package_mask = False
1463             if "--fix" in cmdline:
1464                 cleanFile(USER_CONFIG_PATH + "/package.mask")
1465         elif cmd == "--package-use":
1466             print (portage.output.bold("\npackage.use:"))
1467             processing_package_use = True
1468             get_recursive_info(USER_CONFIG_PATH + "/package.use")
1469             if "--fix" in cmdline:
1470                 cleanFile(USER_CONFIG_PATH + "/package.use")
1471                 clean_useflagsFile(USER_CONFIG_PATH + "/package.use")
1472             print (portage.output.bold("Done\n"))
1473         elif cmd == "--all":
1474             print (portage.output.bold("\npackage.keywords:"))
1475             get_recursive_info(USER_CONFIG_PATH + "/package.keywords")
1476             print (portage.output.bold("\npackage.accept_keywords:"))
1477             get_recursive_info(USER_CONFIG_PATH + "/package.accept_keywords")
1478             print (portage.output.bold("\npackage.unmask:"))
1479             checking_package_unmask = True
1480             get_recursive_info(USER_CONFIG_PATH + "/package.unmask")
1481             checking_package_unmask = False
1482             checking_package_mask = True
1483             print (portage.output.bold("\npackage.mask:"))
1484             get_recursive_info(USER_CONFIG_PATH + "/package.mask")
1485             print (portage.output.bold("\npackage.use:"))
1486             processing_package_use = True
1487             get_recursive_info(USER_CONFIG_PATH + "/package.use")
1488             if "--fix" in cmdline:
1489                 cleanFile(USER_CONFIG_PATH + "/package.keywords")
1490                 cleanFile(USER_CONFIG_PATH + "/package.accept_keywords")
1491                 cleanFile(USER_CONFIG_PATH + "/package.unmask")
1492                 cleanFile(USER_CONFIG_PATH + "/package.use")
1493                 cleanFile(USER_CONFIG_PATH + "/package.mask")
1494                 clean_useflagsFile(USER_CONFIG_PATH + "/package.use")
1495             print (portage.output.bold("\nDone\n"))
1496
1497     print_overlay_text()
1498
1499     if len(cmdline) == 0:
1500         if show_changes_only_flag or show_removable_only_flag:
1501             if (show_changes_only_flag):
1502                 print (portage.output.green("-c") + " or " + portage.output.green("--changes-only") + " must be accompanied by one of the following:")
1503             else:
1504                 print (portage.output.green("-r") + " or " + portage.output.green("--removable-only") + " must be accompanied by one of the following:")
1505
1506             print ("     " + portage.output.yellow("-k") + " or " + portage.output.yellow("--keyword"))
1507             print ("     " + portage.output.yellow("-u") + " or " + portage.output.yellow("--unmask"))
1508             print ("     " + portage.output.yellow("-m") + " or " + portage.output.yellow("--mask"))
1509             print ("     " + portage.output.yellow("-a") + " or " + portage.output.yellow("--all"))
1510
1511             print_usage()
1512