c73a721514a3aa0adb8f8423957e52e592da1160
[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.0.1"
20 __productname__ = "portpeek"
21 __description__ = "Displays user unmasked ebuilds and installable options from the portage tree"
22
23 import sys, os, portage.output, string, fileinput
24
25
26 import gentoolkit,gentoolkit.helpers,gentoolkit.package,gentoolkit.versionmatch,gentoolkit.query
27 from gentoolkit import errors
28
29 from gentoolkit.versionmatch import VersionMatch
30 from portage.const import USER_CONFIG_PATH
31 from portage.versions import catpkgsplit,pkgcmp,pkgsplit
32 from portage import best
33 import portage.exception
34 from portage.exception import InvalidAtom
35 from gentoolkit.cpv import CPV
36 from gentoolkit.query import Query
37
38 porttree = portage.db[portage.root]["porttree"]
39 settings = portage.config(clone=portage.settings)
40
41 show_changes_only_flag = False
42 checking_package_unmask = False
43 checking_package_mask = False
44 print_overlay_flag = False
45 info = 0
46 debug = 1
47 logLevel = info
48 show_removable_only_flag = False
49 stable_list = []
50 unmask_list = []
51 tilde = 0
52 processing_package_use = False
53
54 try:
55     PORTAGE_CONFIGROOT
56 except NameError:
57     PORTAGE_CONFIGROOT="/"
58
59 USER_CONFIG_PATH=PORTAGE_CONFIGROOT + USER_CONFIG_PATH
60
61 #parameters
62 options = [
63 "--keyword",
64 "--unmask",
65 "--mask",
66 "--all",
67 "--changes-only",
68 "--version",
69 "--version",
70 "--help",
71 "--removable-only",
72 "--debug",
73 "--fix", 
74 "--tilde-check",
75 "--no-color",
76 "--package-use"
77 ]
78
79 mappings = {
80 "k":"--keyword",
81 "u":"--unmask",
82 "m":"--mask",
83 "a":"--all",
84 "c":"--changes-only",
85 "V":"--version",
86 "v":"--version",
87 "h":"--help",
88 "r":"--removable-only",
89 "d":"--debug",
90 "f":"--fix", 
91 "t":"--tilde-check",
92 "n":"--no-color",
93 "s":"--package-use"
94 }
95
96 cmdline = []
97 overlays = [settings["PORTDIR_OVERLAY"]]
98
99 if len(overlays) > 0:
100     overlay_list = overlays[0].split(" ")
101
102 def print_usage():
103     # Print full usage information for this tool to the console.
104     print ("\nUsage: " + portage.output.turquoise(__productname__) +  portage.output.yellow(" command "))
105     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [ options ]") +  portage.output.yellow(" command "))
106     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-c]") + portage.output.yellow(" [akmu]"))
107     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-r]") + portage.output.yellow(" [akmu]"))
108     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-f]") + portage.output.yellow(" [akmu]"))
109     print ("       " + portage.output.turquoise(__productname__) + portage.output.green(" [-F]") + portage.output.yellow(" [akmu]"))
110     print (portage.output.yellow(" command ") + " can be ")
111     print (portage.output.yellow(" -a, --all") + "       - show all matches")
112     print (portage.output.yellow(" -k, --keyword") + "       - show matches from package.keyword only")
113     print (portage.output.yellow(" -m, --mask") + "      - show matches from package.mask only")
114     print (portage.output.yellow(" -u, --unmask") + "        - show matched from package.unmask only")
115     
116     print (portage.output.yellow(" -f, --fix") + "       - will remove the stabled packages without asking for confirmation")
117     print (portage.output.yellow(" -h, --help") + "      - display this message")
118     print (portage.output.yellow(" -d, --debug") + "         - display more verbose output for debugging")
119     print (portage.output.yellow(" -V, --version") + "       - display version info")
120     print (portage.output.green("options") + " are ")
121     print (portage.output.green(" -c, --changes-only") + \
122         "   - show all matches that have upgrade option, use with " + \
123         "<" + portage.output.yellow(" k ") + "|" + portage.output.yellow(" u ") + \
124         "|" + portage.output.yellow(" m ") + "|" + \
125         portage.output.yellow(" a ") + ">")
126     print (portage.output.green(" -n, --no-color") + \
127         "   - suppress color output")
128     print (portage.output.green(" -r, --removable-only") + \
129         "   - show all matches that can be removed from package files, use with " + \
130         "<" + portage.output.yellow(" k ") + "|" + portage.output.yellow(" u ") + \
131         "|" + portage.output.yellow(" m ") + "|" + \
132         portage.output.yellow(" a ") + ">\n")
133
134 def get_keywords(package, var):
135     mytree = porttree
136     filtered_keywords = ""
137     try:
138         keywords = package.environment("KEYWORDS").split()
139     except (KeyError, error):
140         print ("!!! Portpeek caught Exception:", error)
141         print ("!!! This package/version seems to be no longer available, " + \
142         "please check and update/unmerge it") 
143         return "Not Available/Deprecated"
144     
145     #filtered_keywords = filter_keywords(keywords[0])
146     filtered_keywords = filter_keywords(keywords)
147     return filtered_keywords
148
149
150
151 # this is the main function for portpeek
152 # TODO comment this code!
153 def parse_line(line, filename):     
154     global info,debug
155     pkgs = None
156     ebuild_output = ""
157     check_pkg = ""
158     not_installed_pkgs = 0
159     pkg_length = 0
160     atom_check="<>="
161
162     print_output(debug,portage.output.blue("Analyzing line: " + line))
163         # determine if we are also check ~ prefixed code
164     if  (tilde == 1): 
165         atom_check="<>=~"
166
167     diffs_found = False
168     display_done = False
169
170     fields = line.replace("\t", " ").split(" ")
171     if len(fields) > 0:
172         #if the line does not start with an atom such as (= or >), do not validate 
173         #status as this tool is for check specific versions and not entire packages 
174         # a ~cpv should be handled like an =cpv if requested bythe parameter -t
175         check_pkg = fields[0] # this should be one of <>=~
176         if check_pkg[0] not in atom_check:
177             return
178         if (tilde == 1):
179             if check_pkg[0] in "~":
180                 check_tilde_masked_pkg(check_pkg, filename)
181                 return
182
183                 # determine if the package exists
184         try:
185             package_exists = portage.portdb.xmatch("match-all", fields[0])
186         except InvalidAtom:
187             package_exists = False
188
189         if package_exists:
190                         # return a Package List based on the cpv
191             query = Query(fields[0])
192             pkgs = query.smart_find(True,True,True,True,False,True)
193             if (pkgs != None):
194                 pkg_length = len(pkgs)
195                 not_installed_pkgs = 0
196                 display_done = False
197
198                                 # go through each package version for a specific version found above
199                 for current_package in pkgs:
200                     if not current_package.is_installed():
201
202                                                 # we have found a package that is in our file, but not installed
203                         not_installed_pkgs = not_installed_pkgs + 1
204
205                         # check to see if specific version of pkg is not installed 
206                         # and display if true
207                         check_pkg = fields[0]
208                         if check_pkg[0] in atom_check:
209                             check_pkg = check_pkg[1:]
210
211                         if (check_pkg == str(current_package.cpv)):
212                             if (not checking_package_mask):
213                                                                 # package is not instaleld
214                                 print_output(info,portage.output.green("\n" + str(current_package.cpv) + ": ") + portage.output.yellow("Not Installed") , current_package, filename)
215                                 stable_list.append(str(current_package.cpv))
216                                 unmask_list.append(str(current_package.cpv))
217                             else:
218                                                                 # package is masked, and not installed, this is normal use of package.mask
219                                 print_output(info,portage.output.green("" + str(current_package.cpv) + ": ") + portage.output.yellow("Package Masked"),current_package, filename)
220                             display_done = True
221                         continue
222
223                                         # package is installed
224                                         # retrieve the keywords for a file
225                     keywords = "%s" % (get_keywords(current_package,"KEYWORDS").split())
226                     if (keywords.find("Available/Deprecated") >= 0):
227                         continue
228
229                                         #retrieve the mask status of a specific package
230                     pkgmask = _get_mask_status(current_package, False)
231
232                     #determine if installed package is unmasked, if so, display keywords as green
233                     stable = check_for_stable_release(current_package)
234
235                     # do not display if keywords don't exist
236                     if keywords == "[]":
237                         continue
238
239                     if stable:
240                         ebuild_output = portage.output.green("Installed: ") + \
241                             portage.output.turquoise(str(current_package.cpv)) + \
242                             portage.output.green("  Keywords " + keywords)
243                         if "package.unmask" in filename:
244                             unmask_list.append(str(current_package.cpv))
245                         if "package.keywords" in filename:
246                             stable_list.append(str(current_package.cpv))
247                     else:
248                         if (not show_removable_only_flag):
249                             ebuild_output = portage.output.green("Installed: ") + \
250                                 portage.output.turquoise(str(current_package.cpv)) + \
251                                 portage.output.yellow("  Keywords " + keywords) 
252                         else:
253                             ebuild_output = portage.output.yellow(str(current_package.cpv))
254
255                                         # check package.unmask
256                     if (checking_package_unmask):
257                         if (not is_pkg_package_masked(str(current_package.cpv))):
258
259                                                         # package is in package.unmask unnecessarily
260                             ebuild_output = ebuild_output + ": " + portage.output.yellow("Not package masked")
261                             if "package.unmask" in filename:
262                                 unmask_list.append(str(current_package.cpv))
263                                 print_output (info, "" +  ebuild_output,None, filename)
264                                 continue
265
266                                         # print once
267                     ebuild_search_key_printed = False
268                     if stable:
269                         diffs_found = False
270                         ebuild_search_key_printed = True
271                         print_output(info,"\n" + ebuild_output,current_package, filename)
272                     elif not show_changes_only_flag and not show_removable_only_flag:
273                         diffs_found = False
274                         ebuild_search_key_printed = True
275                         print_output(info,"\n" + ebuild_output,current_package)
276
277                                         # go through all versions of a package
278                     query = Query(current_package.category + "/" + current_package.name)
279                     all_pkgs = query.smart_find(True,True,True,True,False,True)
280                     for a_package in all_pkgs:
281                         if not a_package.is_installed():
282                                                         # a_package is not installed
283                             pkgmask = _get_mask_status(a_package, False)
284                                                         # print status line of package we are now checking
285                             print_output(debug,portage.output.blue("Checking package: " + str(a_package.cpv) +".pkgmask is " + str(pkgmask)))
286                                                         # if package versions are different
287                             if (VersionMatch(CPV(current_package.cpv)).match(CPV(a_package.cpv))):
288                                 diffs_found = True
289                                 keylist = a_package.environment("KEYWORDS")
290                                 keywords = "%s" % (filter_keywords(keylist)).split()
291                                 #if a_package is masked
292                                 if pkgmask > 0 and not show_removable_only_flag:
293                                     if show_changes_only_flag and not ebuild_search_key_printed:
294                                         print_output (info, "\n" +  ebuild_output, current_package)
295                                         ebuild_search_key_printed = True
296                                         check_for_stable_release(current_package)
297                                     if (pkgmask >= 3):
298                                         print_output (info,portage.output.red("Available: " + str(a_package.cpv) + " [M] Keywords: " + keywords),a_package)
299                                     else:
300                                         print_output (info,portage.output.brown("Available: " + str(a_package.cpv) + " Keywords: " + keywords),a_package)
301                                 else:
302                                     if show_changes_only_flag and not ebuild_search_key_printed:
303                                         print_output (info,"\n" + ebuild_output,current_package)
304                                         ebuild_search_key_printed = True
305                                         print_output(info,portage.output.green("Available: " + str(a_package.cpv) + " Keywords: " + keywords),a_package)
306                 # display if pkg/cat is not installed (missing version)
307                 if not_installed_pkgs ==  pkg_length:
308                     if not display_done:
309                         if (not checking_package_mask):
310                             print_output(info,portage.output.green("\n" + fields[0] + ": ") + portage.output.yellow("Not Installed"),current_package)
311                             stable_list.append(str(current_package.cpv))
312                             unmask_list.append(str(current_package.cpv))
313                         else:
314                             print_output (info,portage.output.green("\n" + str(current_package.cpv) + ": ") + portage.output.yellow("Package Masked"),current_package)
315         else:
316             diffs_found = True
317             print (portage.output.red ("\nPackage: " + fields[0] + " not found. Please check " + filename + " to validate entry"))
318             stable_list.append(fields[0])
319             unmask_list.append(fields[0])
320             show_all_versions(fields[0])
321     current_package = ""
322
323     return diffs_found
324
325 # adding support for etc/portage/package.keywords/<whatever>/package.keywords
326 def get_recursive_info(filename):
327
328     # determine if filename is a directory
329     if os.path.isdir(filename):
330         # get listing of directory
331         filenames = os.listdir(filename)
332         for file_name in filenames:
333             get_recursive_info(filename+os.path.sep+file_name)
334     else:   
335         get_info(filename)
336
337 def get_info(filename):
338
339     diffs_found = False
340     no_file = False
341     filedescriptor = None
342
343     try:
344         filedescriptor = open(filename)
345         for line in filedescriptor.readlines():
346             line = line.strip()
347             if len(line) <= 0:
348                 continue
349             elif line.find("#") >= 0:
350                 # found '#' remove comment
351                 line = line[0:line.find("#")]
352                 line = line.strip()
353                 if len(line) <= 0:
354                     continue
355             if (processing_package_use == False):
356                 diffs_found = parse_line(line, filename)
357             else:
358                 # process package.use
359                 diffs_found = parse_package_use(line,filename)
360     except IOError:
361         print (portage.output.red("Could not find file " + filename))
362         no_file = True
363
364     if not diffs_found and no_file:
365         print (portage.output.brown("No ebuild options found."))
366
367     # close file
368     if (filedescriptor != None):
369         filedescriptor.close()
370
371 # parse the package.use file and look for packages
372 # not installed
373 def parse_package_use(line, filename):
374     global info,debug
375     pkgs = None
376     check_pkg = ""
377     pkg_length = 0
378     atom_check="<>="
379     any_version = False
380     has_atom = True
381
382     diffs_found = False
383     package_installed = False
384     fields = line.replace("\t", " ").split(" ")
385
386     if len(fields) > 0:
387         check_pkg = fields[0] # this could be one of <>=
388         if check_pkg[0] not in atom_check:
389             has_atom = False
390         else:
391             check_pkg = check_pkg[1:]
392
393         # look for any version of check_pkg installed as there is 
394         # no version specified in package.use
395         package_exists = portage.portdb.xmatch("match-all", check_pkg)
396         if package_exists:
397             # get all package versions
398             query = Query(check_pkg)
399             pkgs = query.smart_find(True,True,True,True,False,True)
400             if (pkgs != None):
401                 pkg_length = len(pkgs)
402
403                 # go through each package version for a specific version found above
404                 if (has_atom == False):
405                     for current_package in pkgs:
406                         if current_package.is_installed():
407                             package_installed = True
408                 else: 
409                     # go through each package version for a specific version found above
410                     for current_package in pkgs:
411                         if (str(current_package.cpv) == check_pkg):
412                             if not current_package.is_installed():
413                                 print_output(info,portage.output.green("\n" + check_pkg + ": ") + portage.output.yellow("Not Installed"),current_package)
414                                 stable_list.append(check_pkg)
415                                 unmask_list.append(check_pkg)
416                                 return True
417                             else:
418                                 return False
419         else:
420             print (portage.output.red ("\nPackage: " + fields[0] + " not found. Please check " + filename + " to validate entry"))
421             stable_list.append(check_pkg)
422             unmask_list.append(check_pkg)
423             return True
424         if (package_installed == False):
425             # package does not exists
426             print_output(info,portage.output.green("\n" + check_pkg + ": ") + portage.output.yellow("Not Installed"),current_package)
427             stable_list.append(check_pkg)
428             unmask_list.append(check_pkg)
429             return True
430
431     return False
432
433
434 # parts blatantly stolen from equery
435 # if pure is true, then get "true" mask status that is
436 # not affected by entries in /etc/portage/package.*
437 def _get_mask_status(pkg, pure):
438     pkgmask = 0
439
440     if (pkg == None):
441         return 0
442
443     if pkg.is_masked():
444         pkgmask = pkgmask + 3
445
446     if pure:
447         try:
448             keywords = portage.portdb.aux_get(str(pkg.cpv), ["KEYWORDS"])
449             keywords = keywords[0].split()
450         except KeyError:
451             # cpv does not exist
452             return 0
453     else:
454         keywords = pkg.environment("KEYWORDS").split()
455
456     # first check for stable arch, stop there if it is found
457     if settings["ARCH"] in keywords:
458         return 0
459
460     if "~" + settings["ARCH"] in keywords:
461         pkgmask = pkgmask + 1
462     elif "-*" in keywords or "-" + settings["ARCH"] in keywords:
463         pkgmask = pkgmask + 2
464     
465     return pkgmask
466
467 def is_pkg_package_masked(cpv):
468
469     mysplit = catpkgsplit(cpv)
470     if not mysplit:
471         raise ValueError("invalid CPV: %s" % cpv)
472     if not portage.portdb.cpv_exists(cpv):
473         raise KeyError("CPV %s does not exist" % cpv)
474     mycp = mysplit[0] + "/" + mysplit[1]
475
476     if mycp in settings.pmaskdict:
477         for package in settings.pmaskdict[mycp]:
478             if cpv in portage.portdb.xmatch("match-all", package):
479                 return True
480                 
481     return False    
482
483 # filter out keywords for archs other than the current one
484 def filter_keywords(keywords):
485     filtered_keywords = ""
486
487     #for key in key_list:
488     for key in keywords:
489         key = str.replace(key, "[", "")
490         key = str.replace(key, "]", "")
491         key = str.replace(key, ",", "")
492         arch=settings["ARCH"]
493         if key.rfind(arch) != -1:
494             if len(filtered_keywords) != 0:
495                 filtered_keywords = filtered_keywords + " "
496             filtered_keywords = filtered_keywords + key
497         elif "-*" in key:
498             if len(filtered_keywords) != 0:
499                 filtered_keywords = filtered_keywords + " "
500             filtered_keywords = filtered_keywords + key
501
502
503     return filtered_keywords
504
505 # check to see if we have a stable release
506 # in our package.* files that we can remove
507 def check_for_stable_release(pkg):
508     if not is_pkg_package_masked(str(pkg.cpv)):
509         status = _get_mask_status(pkg, True)
510         if status == 0:
511             return True
512     return False
513
514 #print version info
515 def print_version():
516     # Print the version of this tool to the console.
517     print (__productname__ + "(" + __version__ + ") - " + \
518         __description__)
519     print ("Author(s): " + __author__)
520
521 # function to go through a ~cp without a version
522 # and set for removal from file if no masked package version exists
523 def check_tilde_masked_pkg(package_name, filename):
524     ebuild_output=""
525     variable_version = ""
526
527     orig_package_name = package_name
528     package_name = package_name.replace('~','')
529
530     print_output(debug,portage.output.blue("check_tilde_maskd_pkg: orig_package-name is " + orig_package_name))
531     print_output(debug,portage.output.blue("check_tilde_maskd_pkg: package_name is " + package_name))
532
533     query = Query(package_name+"*", True)
534     packages = query.smart_find(True,True,True,True,False,True)
535     no_versions_installed = True
536     for package in packages:
537         if package.is_installed():
538             no_versions_installed = False
539
540     if (no_versions_installed == True):
541         ebuild_output = portage.output.green("\n" + package_name + ": ") + portage.output.yellow("Not Installed")
542         if "package.unmask" in filename:
543             unmask_list.append(orig_package_name)
544         if "package.keywords" in filename:
545             stable_list.append(orig_package_name)
546         print (ebuild_output + portage.output.brown(" : " + filename))
547
548         return
549
550     # get all packages matching cat/package
551     query = Query(package_name+"*", True)
552     pkgs = query.smart_find(True,True,True,True,False,True)
553     if (pkgs != None):
554         for current_package in pkgs:
555             print_output(debug,portage.output.blue("check_tilde_maskd_pkg: current_package is " + str(current_package.cpv)))
556             print_output(debug,portage.output.blue("comparing " + package_name + " to " + str(current_package.cpv)))
557             #if (compare_package_strings(package_name,str(current_package.cpv)) <=0):
558             if (pkgcmp(package_name, str(current_package.cpv)) <= 0):
559                 #if (pkgcmp(pkgsplit('test-1.0-r1'),pkgsplit('test-1.2-r3'))
560                 packageObj = gentoolkit.package.Package(str(current_package.cpv))
561                 if (packageObj == None):
562                     # we could not create a package object
563                     return
564                 pkgmask = _get_mask_status(packageObj, True)
565
566                 print_output(debug,portage.output.blue("check_tilde_maskd_pkg: current_package is " + str(current_package.cpv) + " and pkgmask is " + str(pkgmask)))
567
568                 if "package.unmask" in filename:
569                     if (pkgmask >= 3):
570                         # package was found as masked
571                         return 
572                     else:
573                         # package is not masked
574                         unmask_list.append(str(current_package.cpv))
575                         ebuild_output = portage.output.yellow(str(current_package.cpv)) + ": " + portage.output.yellow("Not package masked")
576                         print_output(info,ebuild_output, package, filename)
577                         return
578                 else:
579                     if (pkgmask >= 1):
580                         # package was found as masked
581                         return 
582                     else:
583                         # at this point we have no packages >= ~cpv that are masked, present for removal
584                         # package does not have any masked versions
585                         ebuild_output = portage.output.green(package_name + " has no masked versions")
586                         
587                         if "package.unmask" in filename:
588                             unmask_list.append(orig_package_name)
589                         if "package.keywords" in filename:
590                             stable_list.append(orig_package_name)
591                         print_output(info,ebuild_output, package, filename)
592
593 #helper function to print avail pks when version does not exist
594 def show_all_versions(pkg):
595
596     # is package masked
597     is_package_masked = False
598     pkgArr = portage.pkgsplit(pkg)
599
600     if pkgArr is None or len(pkgArr) == 0:
601         return
602
603     # determine if category/package is masked 
604     package = pkgArr[0]
605
606     operator = portage.dep.Atom(pkg).operator
607     if operator is not None:
608         package = package[len(operator):]
609
610     # package is category/package and pkg is category/package-version
611     # is category/package-version we are checking package masked?
612     #if portage.settings.pmaskdict.has_key(package):
613     if package in portage.settings.pmaskdict:
614         pkg_list = portage.settings.pmaskdict.get(package)
615         # iterate through list array looking for pkg
616         for pkg_check in pkg_list:
617             operator = portage.get_operator(pkg_check)
618             if operator is None:
619                 if pkg_check == package:
620                     is_package_masked = True
621
622     query = Query(package)
623
624     all_pkgs = []
625
626     try:
627         all_pkgs = query.smart_find(True,True,True,True,False,True)
628     except errors.GentoolkitException as err:
629         print_output(debug,portage.output.blue("Package " + package + " not found."))
630
631     for current_package in all_pkgs:
632         keywords = "%s" % (current_package.environment("KEYWORDS").split())
633         keywords = filter_keywords(keywords)
634         keywords = "[" + keywords + "]"
635         ebuild = current_package.ebuild_path()
636         if ebuild:
637             pkgmask = _get_mask_status(current_package, True)
638             if is_package_masked:
639                 print (portage.output.red("Available: " + str(current_package.cpv) + " [M] Keywords: " + keywords))
640             elif pkgmask > 4:
641                 print (portage.output.red("Available: " + str(current_package.cpv) + " [M] Keywords: " + keywords))
642             elif pkgmask == 4 or pkgmask == 1:
643                 print (portage.output.brown("Available: " + str(current_package.cpv) + " Keywords: " + keywords))
644             else:
645                 print (portage.output.green("Available: " + str(current_package.cpv) + " Keywords: " + keywords))
646                 stable_list.append(str(current_package.cpv))
647
648 def handle_if_overlay(package):
649     overlay_text = ""
650     global print_overlay_flag
651     print_overlay_flag = True
652
653     ebuild_path,overlay_path = porttree.dbapi.findname2(str(package.cpv))
654     index = -1
655     try:
656         index = overlay_list.index(overlay_path)
657     except (ValueError,error):
658         overlay_list.append(overlay_path)
659         index = overlay_list.index(overlay_path)
660
661     overlay_text = " [" + str(index+1) + "]"
662
663     return overlay_text
664
665 # if the overlay_text was displayed to the user
666 # we need to display the string at the end 
667 # this array will store the overlays to be displayed
668 def print_overlay_text():
669    
670     global print_overlay_flag
671     
672     if (not print_overlay_flag):
673         return
674     
675     if (len(overlay_list) <= 0):
676         return
677
678     index = 1
679     for x in overlay_list:
680         print (portage.output.turquoise("[" + str(index) + "] ") + x)
681         index = index + 1
682     
683     print ("\n")
684
685 #helper function to print output
686 def print_output(log_level,output_string, package=None, filename=None):
687     
688     global logLevel
689
690     if package != None:
691         if (package.is_overlay()):
692             output_string = output_string + portage.output.turquoise(handle_if_overlay(package))
693         else:
694             if filename != None:
695                 output_string = output_string + portage.output.brown(" : " + filename)
696
697     if (log_level <= logLevel):
698         print (output_string)
699
700 # remove stabled files that are no longer needed from package.keywords
701 # or package.mask
702 # includes support for etc/portage/package.keywords/<whatever>/package.keywords
703 def cleanFile (filename):
704     
705     removeDups = []
706     removed_list = []
707
708     # if the file or directory does not exist
709     # exit out
710     if (os.path.exists(filename) == False):
711             return
712     
713     if "package.keywords" in filename:
714         if ( len(stable_list) == 0):
715             return
716         for i in stable_list:
717             if not removeDups.count(i):
718                 removeDups.append(i)
719     else:
720         if ( len(unmask_list) == 0):
721             return
722         for i in unmask_list:
723             if not removeDups.count(i):
724                 removeDups.append(i)
725
726     removedDict = {}
727
728     try:
729         # determine if filename is a directory
730         if os.path.isdir(filename):
731             # get listing of directory
732             filenames = os.listdir(filename)
733             for file_name in filenames:
734                 cleanFile(filename+os.path.sep+file_name)
735         else:   
736             #go through stable array and remove line if found
737             for line in fileinput.input(filename,inplace =1):
738                 itemFound = False
739                 line = line.strip()
740
741                 # make sure line is not empty and do not remove commented out lines
742                 if len(line) <= 0:
743                     continue
744                 elif line.find("#") == 0:
745                     print (line)
746                     continue
747
748                 for item in removeDups:
749                     if item in line:
750                         dup_found = False
751                         for check_item in removed_list:
752                             if (check_item == item):
753                                 dup_found = True
754                         if (dup_found == False):
755                             removed_list.append(item)
756                             removedDict[filename] = item
757                             itemFound = True
758                 if (itemFound == False):
759                     print (line)
760             fileinput.close()
761     except (OSError,error):
762         print (portage.output.red("Modify/Read access to file: " + filename + " failed: ") ,error)
763     
764     if (len(removed_list) > 0):
765         print ("\n")
766         for package in removed_list:
767             print (portage.output.red("Removing from: ") + portage.output.yellow(filename) + ": " + portage.output.green(package) + "\n")
768
769
770 # thanks to Paul Varner (Fuzzyray)
771 #Returns the list ordered in the same way portage 
772 #would do with lowest version at the head of the list.
773 def sort_package_list(pkglist):
774     from gentoolkit.package import Package
775     pkglist.sort()
776     return pkglist
777             
778 # main
779 if __name__ == "__main__":
780
781     if len(sys.argv) == 1:
782         print_usage()
783         sys.exit(1)
784
785     # soooooo stolen from emerge
786     tmpcmdline = sys.argv[1:]
787
788     for cmd in tmpcmdline:
789         if cmd[0:1] == "-" and cmd[1:2] != "-":
790             for cmd_item in cmd[1:]:
791                 if cmd_item in mappings:
792                     if mappings[cmd_item] in cmdline:
793                         print ()
794                         print ("*** Warning: Redundant use of ", mappings[cmd_item])
795                     else:
796                         cmdline.append(mappings[cmd_item])
797                 else:
798                     print ("!!! Error: -"+cmd_item+" is an invalid option.")
799                     sys.exit(-1)
800         else:
801             cmdline.append(cmd)
802
803     #parse long options
804     for cmd in cmdline:
805         if len(cmd)>=2 and cmd[0:2]=="--":
806             try:
807                 i = options.index(cmd)
808                 continue
809             except (ValueError):
810                 print ("!!! Error: -"+cmd+" is an invalid option.")
811                 sys.exit(-1)
812
813     if "--changes-only" in cmdline:
814         cmdline.remove("--changes-only")
815         show_changes_only_flag = True
816
817     if "--removable-only" in cmdline:
818         cmdline.remove("--removable-only")
819         show_removable_only_flag = True
820
821     if "--debug" in cmdline:
822         logLevel = debug
823
824     if "--no-color" in cmdline:
825         portage.output.nocolor()
826
827     if "--tilde-check" in cmdline:
828         tilde=1
829
830     if "--version" in cmdline:
831         print_version()
832         sys.exit(0)
833     
834     if "--all" in cmdline:
835         tmpcmdline = ["--all"]
836         if "--fix" in cmdline:
837             tmpcmdline.append("--fix")
838         elif "--fixwithall" in cmdline:
839             tmpcmdline.append("--fixwithall")
840         cmdline=tmpcmdline      
841
842     if "--help" in cmdline:
843         print_usage()
844         sys.exit(0)
845     
846     if (show_changes_only_flag and show_removable_only_flag):
847         print ("Please select only one of --show-removable (-r) or --changes-only")
848         print ("Use --help for more info.")
849         sys.exit(0)
850         
851     for cmd in cmdline:
852         if cmd == "--keyword":
853             print (portage.output.bold("\npackage.keywords:"))
854             get_recursive_info(USER_CONFIG_PATH + "/package.keywords")
855             if "--fix" in cmdline:
856                 cleanFile(USER_CONFIG_PATH + "/package.keywords")
857             print (portage.output.bold("Done\n"))
858         elif cmd == "--unmask": 
859             print (portage.output.bold("\npackage.unmask:"))
860             checking_package_unmask = True
861             get_recursive_info(USER_CONFIG_PATH + "/package.unmask")
862             checking_package_unmask = False
863             if "--fix" in cmdline:
864                 cleanFile(USER_CONFIG_PATH + "/package.unmask")
865         elif cmd == "--mask":
866             checking_package_mask = True
867             print (portage.output.bold("\npackage.mask:"))
868             get_recursive_info(USER_CONFIG_PATH + "/package.mask")
869             print (portage.output.bold("Done\n"))
870             checking_package_mask = False
871             if "--fix" in cmdline:
872                 cleanFile(USER_CONFIG_PATH + "/package.mask")
873         elif cmd == "--package-use":
874             print (portage.output.bold("\npackage.use:"))
875             processing_package_use = True
876             get_recursive_info(USER_CONFIG_PATH + "/package.use")
877             if "--fix" in cmdline:
878                 cleanFile(USER_CONFIG_PATH + "/package.use")
879             print (portage.output.bold("Done\n"))
880         elif cmd == "--all":
881             print (portage.output.bold("\npackage.keywords:"))
882             get_recursive_info(USER_CONFIG_PATH + "/package.keywords")
883             print (portage.output.bold("\npackage.unmask:"))
884             checking_package_unmask = True
885             get_recursive_info(USER_CONFIG_PATH + "/package.unmask")
886             checking_package_unmask = False
887             checking_package_mask = True
888             print (portage.output.bold("\npackage.mask:"))
889             get_recursive_info(USER_CONFIG_PATH + "/package.mask")
890             print (portage.output.bold("\npackage.use:"))
891             processing_package_use = True
892             get_recursive_info(USER_CONFIG_PATH + "/package.use")
893             if "--fix" in cmdline:
894                 cleanFile(USER_CONFIG_PATH + "/package.keywords")
895                 cleanFile(USER_CONFIG_PATH + "/package.unmask")
896                 cleanFile(USER_CONFIG_PATH + "/package.use")
897                 cleanFile(USER_CONFIG_PATH + "/package.mask")
898             print (portage.output.bold("\nDone\n"))
899
900     print_overlay_text()
901
902     if len(cmdline) == 0:
903         if show_changes_only_flag or show_removable_only_flag:
904             if (show_changes_only_flag):
905                 print (portage.output.green("-c") + " or " + portage.output.green("--changes-only") + " must be accompanied by one of the following:")
906             else:
907                 print (portage.output.green("-r") + " or " + portage.output.green("--removable-only") + " must be accompanied by one of the following:")
908
909             print ("     " + portage.output.yellow("-k") + " or " + portage.output.yellow("--keyword"))
910             print ("     " + portage.output.yellow("-u") + " or " + portage.output.yellow("--unmask"))
911             print ("     " + portage.output.yellow("-m") + " or " + portage.output.yellow("--mask"))
912             print ("     " + portage.output.yellow("-a") + " or " + portage.output.yellow("--all"))
913
914             print_usage()
915