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