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