Ignore python USE_EXPAND variables
[portpeek.git] / portpeek
1 #!/usr/bin/python
2 #
3 # Copyright 2006 Mike Pagano
4 # Distributed under the terms of the GNU General Public License v2
5 #
6 # $Header$
7 # Author: Mike Pagano <mpagano@gentoo.org>
8 #
9 # Portions written ripped from
10 # - equery, by Karl Trygve Kalleberg <karltk@gentoo.org>
11 # - gentoolkit.py, by Karl Trygve Kalleberg <karltk@gentoo.org>
12 # - portage.py
13 # - emerge
14 #
15 #
16
17 __author__ = "Michael Pagano"
18 __email__ = "mpagano@gentoo.org"
19 __version__ = "2.1.25"
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             for current_package in pkgs:
534
535                 # on wildcard scenario, return False if one package is installed
536                 if current_package.is_installed():
537                     check_useflags(current_package,line)
538                     return False
539         check_pkg = (check_pkg.rsplit(':',1))[0]
540         if ((orig_pkg_name.find("<=") >=0)
541             or (orig_pkg_name.find("<")>=0)
542             or (orig_pkg_name.find(">=") >=0)
543             or (orig_pkg_name.find(">") >=0)):
544
545             query = Query(check_pkg)
546             pkgs = []
547             try:
548                 pkgs = query.smart_find(True,True,True,True,False,True)
549             except errors.GentoolkitException as err:
550                 print_output(debug,portage.output.blue("parse_package_use: Package " + check_pkg + " not found."))
551                 return False
552
553             if (pkgs != None):
554                 pkg_length = len(pkgs)
555             for current_package in pkgs:
556                 # on wildcard scenario, return False if one package is installed
557                 if (orig_pkg_name.find("<=") >=0):
558                     if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 1) or \
559                         (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 0):
560                         if current_package.is_installed():
561                             check_useflags(current_package,line)
562                         return False
563                 else:
564                     if (orig_pkg_name.find("<") >=0):
565                         if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 1):
566                             if current_package.is_installed():
567                                 check_useflags(current_package,line)
568                             return False
569                 if (orig_pkg_name.find(">=") >=0):
570                     while (check_pkg[0] in atom_check):
571                         check_pkg = check_pkg[1:]
572
573                     result = pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv)))
574                     if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == -1) or \
575                         (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == 0):
576                         if current_package.is_installed():
577                             check_useflags(current_package,line)
578                         return False
579                 else:
580                     if (orig_pkg_name.find(">") >=0):
581                         if (pkgcmp(pkgsplit(check_pkg),pkgsplit(str(current_package.cpv))) == -1 ):
582                             if current_package.is_installed():
583                                 check_useflags(current_package,line)
584                             return False
585         else:
586             # look for any version of check_pkg installed as there is
587             # no version specified in package.use
588
589             package_exists = portage.portdb.xmatch("match-all", check_pkg)
590             if package_exists:
591                 # get all package versions
592                 query = Query(check_pkg)
593                 pkgs = []
594                 try:
595                     pkgs = query.smart_find(True,True,True,True,False,True)
596                 except errors.GentoolkitException as err:
597                     print_output(debug,portage.output.blue("Package " + check_pkg + " not found."))
598
599                 if (pkgs != None and len(pkgs)>0):
600                     pkg_length = len(pkgs)
601
602                     # go through each package version for a specific
603                     # version found above
604                     # if one line check returns all ok, we don't need
605                     #to check the rest. One slot could have different
606                     #use flags than another
607                     if (has_atom == False):
608                         check_useflags_all_versions(pkgs, line, check_pkg)
609                         package_installed = check_for_any_installed_version(pkgs)
610                         current_package = None
611
612                         #for current_package in pkgs:
613                         #    if current_package.is_installed():
614                         #        check_useflags(current_package,line)
615                         #        package_installed = True
616                         #        if (invalid_flag_found == False):
617                         #            break;
618                     else:
619                         # go through each package version for a specific version found above
620                         for current_package in pkgs:
621                             if (not has_asterick and not atom_check):
622                                 if (str(current_package.cpv) == check_pkg):
623                                     if not current_package.is_installed():
624                                         print_output(info,portage.output.yellow("\n" + orig_pkg_name + ": ") + portage.output.red("Not Installed"),current_package)
625                                         if "package.keywords" in filename:
626                                             stable_list.append(check_pkg)
627                                         if "package.accept_keywords" in filename:
628                                             stable_listNg.append(check_pkg)
629                                         unmask_list.append(check_pkg)
630                                         if "package.use" in filename:
631                                             valid_flag_list = []
632                                             valid_flag_list.insert(0,current_package);
633                                             use_flag_dict[line] = valid_flag_list
634                                             check_for_change = use_flag_dict[line]
635                                         return True
636                                     else:
637                                         check_useflags(current_package,line)
638                                         return False
639                             else:
640                                 if current_package.is_installed():
641                                     check_useflags(current_package,line)
642                                     return False
643
644
645                         # if we are here, we have a =<category>/package-PN* and none of them are installed
646                         print_output(info,portage.output.yellow("\n" + orig_pkg_name + ": ") +
647                             portage.output.red("Not Installed"),current_package)
648                         if "package.keywords" in filename:
649                             stable_list.append(check_pkg)
650                         if "package.accept_keywords" in filename:
651                             stable_listNg.append(check_pkg)
652                         unmask_list.append(check_pkg)
653                         if "package.use" in filename:
654                             valid_flag_list = []
655                             valid_flag_list.insert(0,current_package);
656                             use_flag_dict[line] = valid_flag_list
657                             check_for_change = use_flag_dict[line]
658                         return True
659             else:
660                 print (portage.output.red ("\nPackage: " + fields[0] + " not found. Please check " + filename + " to validate entry"))
661                 if "package.keywords" in filename:
662                     stable_list.append(check_pkg)
663                 if "package.accept_keywords" in filename:
664                     stable_listNg.append(check_pkg)
665                 unmask_list.append(check_pkg)
666                 if "package.use" in filename:
667                     valid_flag_list = []
668                     #valid_flag_list.insert(0,current_package);
669                     valid_flag_list.insert(0,fields[0]);
670                     use_flag_dict[line] = valid_flag_list
671                     check_for_change = use_flag_dict[line]
672                 return True
673
674     if (package_installed == False):
675         print_output(info,portage.output.yellow("\n" + orig_pkg_name + ": ") + portage.output.red(" Not Installed"))
676
677         if "package.keywords" in filename:
678             stable_list.append(check_pkg)
679         if "package.accept_keywords" in filename:
680             stable_listNg.append(check_pkg)
681         if "package.use" in filename:
682             valid_flag_list = []
683             valid_flag_list.insert(0,display_pkg_name);
684             use_flag_dict[line] = valid_flag_list
685             check_for_change = use_flag_dict[line]
686
687         unmask_list.append(check_pkg)
688         return True
689
690     return False
691
692
693
694
695 # skip the file if portpeek-skip found in a comment
696 # you can put this in the middle of a file and it will
697 #skip all entrie below it, this is useful to speed things
698 #up by not checking ~kde versions, for example
699 def skipFile (line, filename):
700     if ( (line == None) or (filename == None)):
701         return False
702
703     if line.find("portpeek-skip") >= 0:
704         return True
705
706     return False
707
708 # parts blatantly stolen from equery
709 # if pure is true, then get "true" mask status that is
710 # not affected by entries in /etc/portage/package.*
711 def _get_mask_status(pkg, pure):
712     pkgmask = 0
713
714     if (pkg == None):
715         return 0
716
717     if pkg.is_masked():
718         pkgmask = pkgmask + 3
719
720     if pure:
721         try:
722             keywords = portage.portdb.aux_get(str(pkg.cpv), ["KEYWORDS"])
723             keywords = keywords[0].split()
724         except KeyError:
725             # cpv does not exist
726             return 0
727     else:
728         keywords = pkg.environment("KEYWORDS").split()
729
730     # first check for stable arch, stop there if it is found
731     if settings["ARCH"] in keywords:
732         return 0
733
734     if "~" + settings["ARCH"] in keywords:
735         pkgmask = pkgmask + 1
736     elif "-*" in keywords or "-" + settings["ARCH"] in keywords:
737         pkgmask = pkgmask + 2
738
739     return pkgmask
740
741 def is_pkg_package_masked(cpv):
742
743     print_output(debug,portage.output.blue("is_pkg_package_masked called: " + cpv))
744     settings2 = portage.config(local_config=False)
745     portdb2 = portage.portdbapi(None, settings)
746
747     mask_reason_list = None
748
749     try:
750         for mask_reason_list in portage.getmaskingstatus(cpv, settings2, portdb=portdb2):
751             return True
752     except:
753         return False
754
755     return False
756
757 # filter out keywords for archs other than the current one
758 def filter_keywords(keywords):
759     filtered_keywords = ""
760
761     #for key in key_list:
762     for key in keywords:
763         key = key.replace("[", '')
764         key = key.replace("]", "")
765         key = key.replace(",", "")
766         arch=settings["ARCH"]
767
768         # remove '~' from key for comparison
769         key_comparison = key.lstrip('~')
770         if key_comparison == arch:
771             if len(filtered_keywords) != 0:
772                 filtered_keywords = filtered_keywords + " "
773             filtered_keywords = filtered_keywords + key
774         elif "-*" in key:
775             if len(filtered_keywords) != 0:
776                 filtered_keywords = filtered_keywords + " "
777             filtered_keywords = filtered_keywords + key
778
779
780     return filtered_keywords
781
782
783 # this function takes in a package with no cpv
784 # and returns True if any version is masked
785 def is_any_cpv_keyword_masked(package_name):
786     print_output(debug,portage.output.blue("inside is_any_cpv_keyword_masked: " + package_name))
787
788     query = Query(package_name, True)
789
790     packages = []
791     try:
792         packages = query.smart_find(True,True,True,True,False,True)
793     except errors.GentoolkitException as err:
794         print_output(debug,portage.output.blue("Package " + package_name + " not found."))
795
796     for package in packages:
797         if is_pkg_package_masked(package.cpv):
798             print_output(debug,portage.output.blue("Package " + package.cpv + " is masked."))
799             return True
800
801     print_output(debug,portage.output.blue("Package " + package_name + ". No masked versions."))
802     return False
803
804 # we need to know if the package is masked
805 # by being present in the package.mask file
806 # as opposed to masked by keyword.
807 # if it's not, then we can remove from package.unmask
808 def is_any_cpv_file_masked(package_name):
809
810     print_output(debug,portage.output.blue("is_any_cpv_file_masked called: " + package_name))
811     settings2 = portage.config(local_config=False)
812     portdb2 = portage.portdbapi(None, settings)
813
814     mask_reason_list = None
815
816     try:
817         for mask_reason_list in portage.getmaskingstatus(package_name, settings2, portdb=portdb2):
818             print_output(debug,portage.output.blue("Mask Reason is " + mask_reason_list))
819             if (mask_reason_list == 'package.mask'):
820                 return True
821     except:
822         return False
823
824     return False
825
826
827
828 # check to see if we have a stable release
829 # in our package.* files that we can remove
830 def check_for_stable_release(pkg):
831     if not is_pkg_package_masked(str(pkg.cpv)):
832         status = _get_mask_status(pkg, True)
833         if status == 0:
834             return True
835     return False
836
837 #print version info
838 def print_version():
839     # Print the version of this tool to the console.
840     print (__productname__ + "(" + __version__ + ") - " + \
841         __description__)
842     print ("Author(s): " + __author__)
843
844 # function to go through a ~cp without a version
845 # and set for removal from file if no masked package version exists
846 def check_tilde_masked_pkg(package_name, filename):
847     ebuild_output=""
848     variable_version = ""
849
850     orig_package_name = package_name
851     package_name = package_name.replace('~','')
852
853     print_output(debug,portage.output.blue("check_tilde_maskd_pkg: orig_package-name is " + orig_package_name))
854     print_output(debug,portage.output.blue("check_tilde_maskd_pkg: package_name is " + package_name))
855
856     query = Query(package_name, True)
857
858     packages = []
859     try:
860         packages = query.smart_find(True,True,True,True,False,True)
861     except errors.GentoolkitException as err:
862         print_output(debug,portage.output.blue("Package " + package_name + " not found."))
863
864     no_versions_installed = True
865     for package in packages:
866         if package.is_installed():
867             no_versions_installed = False
868
869     if (no_versions_installed == True):
870         ebuild_output = portage.output.yellow("\n" + package_name + ": ") + portage.output.red("Not Installed")
871         if "package.unmask" in filename:
872             unmask_list.append(orig_package_name)
873         if "package.keywords" in filename:
874             stable_list.append(orig_package_name)
875         if "package.accept_keywords" in filename:
876             stable_listNg.append(orig_package_name)
877         print (ebuild_output + portage.output.brown(" : " + filename))
878
879         return
880
881     # get all packages matching cat/package
882     if (packages != None):
883         for current_package in packages:
884             print_output(debug,portage.output.blue("check_tilde_maskd_pkg: current_package is " + str(current_package.cpv)))
885             print_output(debug,portage.output.blue("comparing " + package_name + " to " + str(current_package.cpv)))
886             if (pkgcmp(pkgsplit(package_name),pkgsplit(str(current_package.cpv))) <=0 ):
887             #if (pkgcmp(package_name, str(current_package.cpv)) <= 0):
888                 packageObj = gentoolkit.package.Package(str(current_package.cpv))
889                 if (packageObj == None):
890                     # we could not create a package object
891                     return
892
893                 if "package.unmask" in filename:
894                     #if (is_pkg_package_masked(str(current_package.cpv))):
895                     if (is_any_cpv_file_masked(str(current_package.cpv))):
896                         # package was found as masked
897                         return
898                     else:
899                         # package is not masked
900                         unmask_list.append(str(current_package.cpv))
901                         ebuild_output = portage.output.yellow(str(current_package.cpv) + ": ") + portage.output.green("Not package masked")
902                         print_output(info,ebuild_output, package, filename)
903                         return
904                 else:
905                     if (is_pkg_package_masked(str(current_package.cpv))):
906                         # package was found as masked
907                         return
908         else:
909             # at this point we have no packages >= ~cpv that are masked, present for removal
910             # package does not have any masked versions
911             ebuild_output = portage.output.green(package_name + " has no masked versions")
912
913             if "package.unmask" in filename:
914                 unmask_list.append(orig_package_name)
915             if "package.keywords" in filename:
916                 stable_list.append(orig_package_name)
917             if "package.accept_keywords" in filename:
918                 stable_listNg.append(orig_package_name)
919             print_output(info,ebuild_output, package, filename)
920
921 #helper function to print avail pks when version does not exist
922 def show_all_versions(pkg, filename):
923
924     # is package masked
925     is_package_masked = False
926     pkgArr = portage.pkgsplit(pkg)
927
928     if pkgArr is None or len(pkgArr) == 0:
929         return
930
931     # determine if category/package is masked
932     package = pkgArr[0]
933
934     operator = portage.dep.Atom(pkg).operator
935     if operator is not None:
936         package = package[len(operator):]
937
938     # package is category/package and pkg is category/package-version
939     # is category/package-version we are checking package masked?
940     #if portage.settings.pmaskdict.has_key(package):
941     pmaskdict = settings._mask_manager._pmaskdict
942     if package in pmaskdict:
943         pkg_list = pmaskdict.get(package)
944         # iterate through list array looking for pkg
945         for pkg_check in pkg_list:
946             operator = portage.get_operator(pkg_check)
947             if operator is None:
948                 if pkg_check == package:
949                     is_package_masked = True
950
951     query = Query(package)
952
953     all_pkgs = []
954
955     try:
956         all_pkgs = query.smart_find(True,True,True,True,False,True)
957     except errors.GentoolkitException as err:
958         print_output(debug,portage.output.blue("Package " + package + " not found."))
959
960     for current_package in all_pkgs:
961         keywords = "%s" % (current_package.environment("KEYWORDS").split())
962         keywords = filter_keywords(keywords)
963         keywords = "[%s]" % (keywords)
964         ebuild = current_package.ebuild_path()
965         if ebuild:
966             pkgmask = _get_mask_status(current_package, True)
967             if is_package_masked:
968                 print (portage.output.red("Available: " + str(current_package.cpv) + " [M] Keywords: " + keywords))
969             elif pkgmask > 4:
970                 print (portage.output.red("Available: " + str(current_package.cpv) + " [M] Keywords: " + keywords))
971             elif pkgmask == 4 or pkgmask == 1:
972                 print (portage.output.brown("Available: " + str(current_package.cpv) + " Keywords: " + keywords))
973             else:
974                 print (portage.output.green("Available: " + str(current_package.cpv) + " Keywords: " + keywords))
975                 if "package.keywords" in filename:
976                     stable_list.append(str(current_package.cpv))
977                 if "package.accept_keywords" in filename:
978                     stable_listNg.append(str(current_package.cpv))
979
980
981 def get_useflags(package):
982     iuse = get_iuse(package.cpv)
983     return iuse
984
985 def check_useflags_all_versions(pkgs, line, check_pkgs):
986
987     global useremove_display, invalid_flag_found
988     invalid_flag_found = False
989     has_use_expand_flags=False
990     original_line = line
991
992     print_output(debug,portage.output.blue("ENTERED check_useflags_all_versions: " + check_pkgs))
993
994     # get all USE_EXPAND in array
995     use_expand_list = settings.get('USE_EXPAND', '').split()
996     use_expand_list.sort()
997
998     for use_expand in use_expand_list:
999         index = line.find(use_expand)
1000         if ( index != -1 ):
1001             has_use_expand_flags=True
1002             save_use_expand=line[index:]
1003             line = line[:index]
1004             break;
1005
1006     potential_invalid_flag = []
1007     valid_flag_list = []
1008     for package in pkgs:
1009
1010         # if package not installed, move on
1011         if (not package.is_installed()):
1012             continue;
1013
1014         print_output(debug,portage.output.blue("check_useflags_all_versions: package: " + package.cpv))
1015         if ((package is None) or (package == "")):
1016             return
1017
1018         useflag_removal_display=""
1019
1020         if (len(line) <= 0):
1021             return
1022
1023         list2 = get_useflags(package)
1024
1025         for uf in list2:
1026             print_output(debug,portage.output.blue(("use found " + uf)))
1027
1028         iuse_string = package.use()
1029         iuse = iuse_string.split(" ")
1030
1031         for uflag in list2:
1032             iuse.append(uflag)
1033
1034         for iuse_item in iuse:
1035             print_output(debug,portage.output.blue(("iuse_item is " + iuse_item)))
1036
1037         useflags_fromfile = line.replace("\t", " ").split(" ")
1038
1039         #for useflags_fromfile_item in useflags_fromfile:
1040         #    print_output(debug,portage.output.blue(("useflags_fromfile_item is " + useflags_fromfile_item)))
1041
1042         package_string = useflags_fromfile.pop(0)
1043         print_output(debug,portage.output.blue(("package_string is " + package_string)))
1044
1045         clean_useflags_list = []
1046         # remove + or -
1047         atom = "-+"
1048
1049         #clean list from portage of + or -
1050         clean_iuse = []
1051         for item in iuse:
1052             if item[0] in atom:
1053                 clean_iuse.append(item[1:])
1054             else:
1055                 clean_iuse.append(item)
1056
1057         for original_flag in useflags_fromfile:
1058             if (original_flag is None or original_flag == ""):
1059                 continue
1060             flag = original_flag
1061             if original_flag[0] in atom:
1062                 flag = original_flag[1:]
1063             if flag not in clean_iuse:
1064                 print_output(debug,portage.output.blue(("found invalid flag: " + flag)))
1065
1066                 # only add to invalid list if it's not in valid list
1067                 try:
1068                     index = valid_flag_list.index(original_flag)
1069                 except ValueError as error:
1070
1071                     try:
1072                        index = potential_invalid_flag.index(original_flag)
1073                     except ValueError:
1074                        print_output(debug,portage.output.blue(original_flag + " not found for " + package.cpv))
1075                        potential_invalid_flag.append(original_flag)
1076
1077             else:
1078                 print_output(debug,portage.output.blue(("found valid flag: " + flag)))
1079                 try:
1080                     index = valid_flag_list.index(original_flag)
1081                 except ValueError as error:
1082                     valid_flag_list.append(original_flag)
1083
1084                 try:
1085                     index = potential_invalid_flag.index(original_flag)
1086                     potential_invalid_flag.remove(original_flag)
1087                 except ValueError as error:
1088                     continue
1089
1090
1091     # if potential_invalid_flag list is empty, we are done
1092     if (len(potential_invalid_flag) <= 0):
1093         return
1094
1095     invalid_flag_found = True
1096
1097     # build sentence
1098     invalid_flags = ""
1099     verb = "is"
1100     for inv_flag in potential_invalid_flag:
1101         if (len(invalid_flags) > 0):
1102             invalid_flags += ","
1103             verb = "are"
1104         invalid_flags += inv_flag
1105
1106     # if there are no valid flags at all, we remove the line
1107     if ( (len(valid_flag_list) == 0) and (has_use_expand_flags == False)):
1108         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"))
1109         useremove_display += "Removing line: " + original_line + "\n"
1110         use_flag_dict[original_line] = ""
1111         return
1112
1113     # if there are values in potential_invalid_flag, we need to remove them
1114
1115     if (len(potential_invalid_flag) > 0):
1116         removal_text = "use flags: "
1117     else:
1118         removal_text = "use flag: "
1119
1120     if ( ((len(valid_flag_list) > 0)) or (has_use_expand_flags == True)):
1121         useremove_display += "Removing " + removal_text + invalid_flags + " for package " + check_pkgs + "\n"
1122         print (portage.output.yellow(removal_text) +  portage.output.red(invalid_flags) + portage.output.yellow(" " + verb + " invalid for " + str(package.cpv)))
1123
1124     valid_flag_list.insert(0,package_string);
1125
1126     if (has_use_expand_flags == True):
1127         valid_flag_list.append(save_use_expand)
1128
1129     if (len(potential_invalid_flag) > 0):
1130         use_flag_dict[original_line] = valid_flag_list
1131
1132     return valid_flag_list
1133
1134 def check_useflags(package,line):
1135
1136     global useremove_display, invalid_flag_found
1137     invalid_flag_found = False
1138
1139     print_output(debug,portage.output.blue("check_useflags: package: " + package.cpv))
1140     if ((package is None) or (package == "")):
1141         return
1142
1143     useflag_removal_display=""
1144
1145     if (len(line) <= 0):
1146         return
1147
1148     iuse = get_useflags(package)
1149
1150     #for iuse_item in iuse:
1151     #    print_output(debug,portage.output.blue(("iuse_item is " + iuse_item)))
1152
1153     useflags_fromfile = line.replace("\t", " ").split(" ")
1154     #for useflags_fromfile_item in useflags_fromfile:
1155     #    print_output(debug,portage.output.blue(("useflags_fromfile_item is " + useflags_fromfile_item)))
1156
1157     package_string = useflags_fromfile.pop(0)
1158     print_output(debug,portage.output.blue(("package_string is " + package_string)))
1159
1160     clean_useflags_list = []
1161     # remove + or -
1162     atom = "-+"
1163
1164     #clean list from portage of + or -
1165     clean_iuse = []
1166     for item in iuse:
1167         if item[0] in atom:
1168             clean_iuse.append(item[1:])
1169         else:
1170             clean_iuse.append(item)
1171
1172     valid_flag_list = []
1173     for original_flag in useflags_fromfile:
1174         if (original_flag is None or original_flag == ""):
1175             continue
1176         flag = original_flag
1177         if original_flag[0] in atom:
1178             flag = original_flag[1:]
1179         if flag not in clean_iuse:
1180             print_output (info,portage.output.red("use flag: " + flag + " is invalid for : " + str(package.cpv)))
1181             useflag_removal_display += "Removing use flag: " + flag + " for package " + str(package.cpv)
1182             invalid_flag_found = True
1183         else:
1184             valid_flag_list.append(original_flag)
1185
1186     # if valid_flag_list is empty, there are no valid flags
1187     if ( (len(valid_flag_list) > 0) and (len(useflag_removal_display) >0)):
1188         useremove_display += useflag_removal_display + "\n"
1189     elif ( len(valid_flag_list) == 0):
1190         useremove_display += "No valid use flags found for package " + str(package.cpv) + ". Removing line: " + line + "\n"
1191         if ( invalid_flag_found != True):
1192             print_output (info,portage.output.red("No valid use flags found for package " + str(package.cpv)))
1193         invalid_flag_found = True
1194
1195     valid_flag_list.insert(0,package_string);
1196     if (invalid_flag_found == True):
1197         use_flag_dict[line] = valid_flag_list
1198
1199     return valid_flag_list
1200
1201
1202 def clean_useflagsFile(filename):
1203
1204     if "--fix-confirm" in cmdline:
1205         if (confirmFix() == False):
1206             return
1207
1208     display_line = ""
1209     removed_list = []
1210
1211     try:
1212         # determine if filename is a directory
1213         if os.path.isdir(filename):
1214             # get listing of directory
1215             filenames = os.listdir(filename)
1216             for file_name in filenames:
1217                 clean_useflagsFile(filename+os.path.sep+file_name)
1218             return
1219         else:
1220             #go through stable array and remove line if found
1221             for line in fileinput.input(filename,inplace =1):
1222                 itemFound = False
1223                 line = line.strip()
1224
1225                 # make sure line is not empty and do not remove commented out lines
1226                 if len(line) <= 0:
1227                     print("")
1228                     continue
1229                 elif line.find("#") == 0:
1230                     print (line)
1231                     continue
1232
1233                 check_for_change = ""
1234                 use_flag_dict.get(line,"")
1235                 try:
1236                     check_for_change = use_flag_dict[line]
1237                     removed_list.append(line)
1238                     if ( len(check_for_change) > 1):
1239                         print (" ".join(check_for_change))
1240                 except KeyError as error:
1241                     print (line)
1242
1243             fileinput.close()
1244     except OSError as error:
1245         print (portage.output.red("Modify/Read access to file: " + filename + " failed: " + format(error)))
1246
1247     if (len(removed_list) > 0):
1248         print ("\n")
1249         for package in removed_list:
1250             print (portage.output.red("Removing from: ") + portage.output.yellow(filename + ": Invalid use flag(s) from ")  + portage.output.green(package) + "\n")
1251
1252     return
1253
1254 def handle_if_overlay(package):
1255     overlay_text = ""
1256     global print_overlay_flag,using_gentoo_as_overlay
1257
1258     if (using_gentoo_as_overlay):
1259         return overlay_text
1260
1261     print_overlay_flag = True
1262
1263     ebuild_path,overlay_path = porttree.dbapi.findname2(str(package.cpv))
1264     index = -1
1265     try:
1266         index = overlay_list.index(overlay_path)
1267     except ValueError as error:
1268         overlay_list.append(overlay_path)
1269         index = overlay_list.index(overlay_path)
1270
1271     overlay_text = " [%s]" % (str(index+1))
1272
1273     return overlay_text
1274
1275 # if the overlay_text was displayed to the user
1276 # we need to display the string at the end
1277 # this array will store the overlays to be displayed
1278 def print_overlay_text():
1279
1280     global print_overlay_flag
1281
1282     if (not print_overlay_flag):
1283         return
1284
1285     if (len(overlay_list) <= 0):
1286         return
1287
1288     index = 1
1289     for x in overlay_list:
1290         print (portage.output.turquoise("[" + str(index) + "] ") + x)
1291         index = index + 1
1292
1293     print ("\n")
1294
1295 #helper function to print output
1296 def print_output(log_level,output_string, package=None, filename=None):
1297
1298     global logLevel
1299
1300     if package != None:
1301         if (package.is_overlay()):
1302             output_string = "%s%s" % (output_string,portage.output.turquoise(handle_if_overlay(package)))
1303             #output_string = output_string + portage.output.turquoise(handle_if_overlay(package))
1304         else:
1305             if filename != None:
1306                 output_string = "%s%s" % (output_string,portage.output.brown(" : " + filename))
1307                 #output_string = output_string + portage.output.brown(" : " + filename)
1308
1309     if (log_level <= logLevel):
1310         print (output_string)
1311
1312 # remove stabled files that are no longer needed from package.keywords
1313 # or package.mask
1314 # includes support for etc/portage/package.keywords/<whatever>/package.keywords
1315 def cleanFile (filename):
1316
1317     removeDups = []
1318     removed_list = []
1319
1320     if "--fix-confirm" in cmdline:
1321         if (confirmFix() == False):
1322             return
1323
1324     # if the file or directory does not exist
1325     # exit out
1326     if (os.path.exists(filename) == False):
1327         return
1328
1329     if "package.keywords" in filename:
1330         if ( len(stable_list) == 0):
1331             return
1332         removeDups = stable_list
1333     elif "package.accept_keywords" in filename:
1334         if ( len(stable_listNg) == 0):
1335             return
1336         removeDups = stable_listNg
1337     else:
1338         if ( len(unmask_list) == 0):
1339             return
1340         removeDups = unmask_list
1341
1342     removedDict = {}
1343
1344     try:
1345         # determine if filename is a directory
1346         if os.path.isdir(filename):
1347             # get listing of directory
1348             filenames = os.listdir(filename)
1349             for file_name in filenames:
1350                 cleanFile(filename+os.path.sep+file_name)
1351             return
1352         else:
1353             #go through stable array and remove line if found
1354             for line in fileinput.input(filename,inplace =1):
1355                 itemFound = False
1356                 line = line.strip()
1357
1358                 # make sure line is not empty and do not remove commented out lines
1359                 if len(line) <= 0:
1360                     print("")
1361                     continue
1362                 elif line.find("#") == 0:
1363                     print (line)
1364                     continue
1365
1366                 for item in removeDups:
1367                     if item in line:
1368                         removed_list.append(item)
1369                         removedDict[filename] = item
1370                         itemFound = True
1371                         removeDups.pop(removeDups.index(item))
1372                         break
1373                 if (itemFound == False):
1374                     print (line)
1375             fileinput.close()
1376     except OSError as error:
1377         print (portage.output.red("Modify/Read access to file: " + filename + " failed: " + format(error)))
1378
1379     if (len(removed_list) > 0):
1380         print ("\n")
1381         for package in removed_list:
1382             print (portage.output.red("Removing from: ") + portage.output.yellow(filename) + ": " + portage.output.green(package) + "\n")
1383
1384 # ask the user if they want to fix their files
1385 # and remove unneeded entries
1386 # Return true if they say yes and False if they say no
1387 def confirmFix():
1388
1389     global fix_asked,fix_confirm
1390
1391     if (fix_asked == True):
1392         return fix_confirm
1393
1394     # only ask if we actually have anything to check
1395     if ( (len(stable_list) == 0) and
1396           (len(stable_listNg) == 0) and
1397           (len(unmask_list) == 0) and
1398           (invalid_flag_found == False) and
1399           (len(use_flag_dict) == 0)):
1400         fix_confirm = True
1401         return fix_confirm
1402
1403     fix_asked = True
1404
1405     valid = {"yes":"yes",   "y":"yes",
1406              "no":"no",     "n":"no"}
1407
1408     prompt = portage.output.bold("Remove entries from files [") + portage.output.green("y") + "/" + portage.output.red("n") + portage.output.bold("]") + " "
1409
1410     while 1:
1411         sys.stdout.write('\n' + prompt)
1412         choice = input().lower()
1413         if choice == '':
1414             fix_confirm = False
1415             break
1416         elif choice in valid.keys():
1417             if (choice == 'y' or choice == 'yes'):
1418                 fix_confirm = True
1419                 break
1420             else:
1421                 fix_confirm = False
1422                 break
1423         else:
1424             sys.stdout.write("Please respond with 'yes' or 'no' "\
1425                              "(or 'y' or 'n').\n")
1426
1427     return fix_confirm
1428
1429
1430 def check_for_any_installed_version(pkgs):
1431
1432     for package in pkgs:
1433         if (package.is_installed()):
1434             return True
1435
1436     return False
1437
1438 # main
1439 if __name__ == "__main__":
1440
1441     if len(sys.argv) == 1:
1442         print_usage()
1443         sys.exit(1)
1444
1445     # soooooo stolen from emerge
1446     tmpcmdline = sys.argv[1:]
1447
1448     for cmd in tmpcmdline:
1449         if cmd[0:1] == "-" and cmd[1:2] != "-":
1450             for cmd_item in cmd[1:]:
1451                 if cmd_item in mappings:
1452                     if mappings[cmd_item] in cmdline:
1453                         print ()
1454                         print ("*** Warning: Redundant use of ", mappings[cmd_item])
1455                     else:
1456                         cmdline.append(mappings[cmd_item])
1457                 else:
1458                     print ("!!! Error: -"+cmd_item+" is an invalid option.")
1459                     sys.exit(-1)
1460         else:
1461             cmdline.append(cmd)
1462
1463     #parse long options
1464     for cmd in cmdline:
1465         if len(cmd)>=2 and cmd[0:2]=="--":
1466             try:
1467                 i = options.index(cmd)
1468                 continue
1469             except ValueError:
1470                 print ("!!! Error: -"+cmd+" is an invalid option.")
1471                 sys.exit(-1)
1472
1473     if "--changes-only" in cmdline:
1474         cmdline.remove("--changes-only")
1475         show_changes_only_flag = True
1476
1477     if "--removable-only" in cmdline:
1478         cmdline.remove("--removable-only")
1479         show_removable_only_flag = True
1480
1481     if "--debug" in cmdline:
1482         logLevel = debug
1483
1484     if "--no-color" in cmdline:
1485         portage.output.nocolor()
1486
1487     if "--tilde-check" in cmdline:
1488         tilde=1
1489
1490     if "--version" in cmdline:
1491         print_version()
1492         sys.exit(0)
1493
1494     if "--fix-confirm" in cmdline:
1495         if '--fix' not in cmdline:
1496             cmdline.append("--fix")
1497
1498     if "--all" in cmdline:
1499         tmpcmdline = ["--all"]
1500         if "--fix" in cmdline:
1501             tmpcmdline.append("--fix")
1502             if "--fix-confirm" in cmdline:
1503                 tmpcmdline.append("--fix-confirm")
1504                 fix_confirm = False
1505         cmdline=tmpcmdline
1506
1507     if "--help" in cmdline:
1508         print_usage()
1509         sys.exit(0)
1510
1511     if (show_changes_only_flag and show_removable_only_flag):
1512         print ("Please select only one of --show-removable (-r) or --changes-only")
1513         print ("Use --help for more info.")
1514         sys.exit(0)
1515
1516     for cmd in cmdline:
1517         if cmd == "--keyword":
1518             print (portage.output.bold("\npackage.keywords:"))
1519             get_recursive_info(USER_CONFIG_PATH + "/package.keywords")
1520             if "--fix" in cmdline:
1521                 cleanFile(USER_CONFIG_PATH + "/package.keywords")
1522             print (portage.output.bold("Done\n"))
1523             print (portage.output.bold("\npackage.accept_keywords:"))
1524             get_recursive_info(USER_CONFIG_PATH + "/package.accept_keywords")
1525             if "--fix" in cmdline:
1526                 cleanFile(USER_CONFIG_PATH + "/package.accept_keywords")
1527             print (portage.output.bold("Done\n"))
1528         elif cmd == "--unmask":
1529             print (portage.output.bold("\npackage.unmask:"))
1530             checking_package_unmask = True
1531             get_recursive_info(USER_CONFIG_PATH + "/package.unmask")
1532             checking_package_unmask = False
1533             if "--fix" in cmdline:
1534                 cleanFile(USER_CONFIG_PATH + "/package.unmask")
1535         elif cmd == "--mask":
1536             checking_package_mask = True
1537             print (portage.output.bold("\npackage.mask:"))
1538             get_recursive_info(USER_CONFIG_PATH + "/package.mask")
1539             print (portage.output.bold("Done\n"))
1540             checking_package_mask = False
1541             if "--fix" in cmdline:
1542                 cleanFile(USER_CONFIG_PATH + "/package.mask")
1543         elif cmd == "--package-use":
1544             print (portage.output.bold("\npackage.use:"))
1545             processing_package_use = True
1546             get_recursive_info(USER_CONFIG_PATH + "/package.use")
1547             if "--fix" in cmdline:
1548                 cleanFile(USER_CONFIG_PATH + "/package.use")
1549                 clean_useflagsFile(USER_CONFIG_PATH + "/package.use")
1550             print (portage.output.bold("Done\n"))
1551         elif cmd == "--all":
1552             print (portage.output.bold("\npackage.keywords:"))
1553             get_recursive_info(USER_CONFIG_PATH + "/package.keywords")
1554             print (portage.output.bold("\npackage.accept_keywords:"))
1555             get_recursive_info(USER_CONFIG_PATH + "/package.accept_keywords")
1556             print (portage.output.bold("\npackage.unmask:"))
1557             checking_package_unmask = True
1558             get_recursive_info(USER_CONFIG_PATH + "/package.unmask")
1559             checking_package_unmask = False
1560             checking_package_mask = True
1561             print (portage.output.bold("\npackage.mask:"))
1562             get_recursive_info(USER_CONFIG_PATH + "/package.mask")
1563             print (portage.output.bold("\npackage.use:"))
1564             processing_package_use = True
1565             get_recursive_info(USER_CONFIG_PATH + "/package.use")
1566             if "--fix" in cmdline:
1567                 cleanFile(USER_CONFIG_PATH + "/package.keywords")
1568                 cleanFile(USER_CONFIG_PATH + "/package.accept_keywords")
1569                 cleanFile(USER_CONFIG_PATH + "/package.unmask")
1570                 cleanFile(USER_CONFIG_PATH + "/package.use")
1571                 cleanFile(USER_CONFIG_PATH + "/package.mask")
1572                 clean_useflagsFile(USER_CONFIG_PATH + "/package.use")
1573             print (portage.output.bold("\nDone\n"))
1574
1575     print_overlay_text()
1576
1577     if len(cmdline) == 0:
1578         if show_changes_only_flag or show_removable_only_flag:
1579             if (show_changes_only_flag):
1580                 print (portage.output.green("-c") + " or " + portage.output.green("--changes-only") + " must be accompanied by one of the following:")
1581             else:
1582                 print (portage.output.green("-r") + " or " + portage.output.green("--removable-only") + " must be accompanied by one of the following:")
1583
1584             print ("     " + portage.output.yellow("-k") + " or " + portage.output.yellow("--keyword"))
1585             print ("     " + portage.output.yellow("-u") + " or " + portage.output.yellow("--unmask"))
1586             print ("     " + portage.output.yellow("-m") + " or " + portage.output.yellow("--mask"))
1587             print ("     " + portage.output.yellow("-a") + " or " + portage.output.yellow("--all"))
1588
1589             print_usage()