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