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