eclean: Fix pkg sorting to work with Python3
[gentoolkit.git] / pym / gentoolkit / eclean / output.py
1 #!/usr/bin/python
2
3 # Copyright 2003-2010 Gentoo Foundation
4 # Distributed under the terms of the GNU General Public License v2
5
6
7 from __future__ import print_function
8
9
10 import sys
11 import portage
12 from portage.output import *
13 from gentoolkit.pprinter import cpv, number, emph
14
15
16 class OutputControl(object):
17         """Outputs data according to predetermined options and handles any user
18         interaction.
19
20         @param options: dictionary of boolean options as determined in cli.py
21                         used here: interactive, pretend, quiet, accept_all, nocolor.
22         """
23
24         def __init__(self, options):
25                 if not options:
26                         # set some defaults
27                         self.options['interactive'] = False
28                         self.options['pretend'] = True
29                         self.options['quiet'] = False
30                         self.options['accept_all'] = False
31                         self.options['nocolor'] = False
32                 else:
33                         self.options = options
34                 self.set_colors("normal")
35
36         def set_colors(self, mode):
37                 """Sets the colors for the progress_controller
38                 and prettysize output
39
40                 @param mode: string, 1 of ["normal", "deprecated"]
41                 """
42                 if mode == "normal":
43                         self.pkg_color = cpv        # green
44                         self.numbers = number  # turquoise
45                         self.brace = blue
46                 elif mode == "deprecated":
47                         self.pkg_color = yellow
48                         self.numbers =  teal # darkgreen
49                         self.brace = blue
50
51         def einfo(self, message=""):
52                 """Display an info message depending on a color mode.
53
54                 @param message: text string to display
55
56                 @outputs to stdout.
57                 """
58                 if not  self.options['nocolor']:
59                         prefix = " "+green('*')
60                 else:
61                         prefix = ">>>"
62                 print(prefix,message)
63
64         def eprompt(self, message):
65                 """Display a user question depending on a color mode.
66
67                 @param message: text string to display
68
69                 @output to stdout
70                 """
71                 if not self.options['nocolor']:
72                         prefix = " "+red('>')+" "
73                 else:
74                         prefix = "??? "
75                 sys.stdout.write(prefix+message)
76                 sys.stdout.flush()
77
78         def prettySize(self, size, justify=False, color=None):
79                 """int -> byte/kilo/mega/giga converter. Optionally
80                 justify the result. Output is a string.
81
82                 @param size: integer
83                 @param justify: optional boolean, defaults to False
84                 @param color: optional color, defaults to green
85                                 as defined in portage.output
86
87                 @returns a formatted and (escape sequenced)
88                                 colorized text string
89                 """
90                 if color == None:
91                         color = self.numbers
92                 units = [" G"," M"," K"," B"]
93                 approx = 0
94                 # by using 1000 as the changeover, the integer portion
95                 # of the number will never be more than 3 digits long
96                 # but the true base 2 value of 1024 is used for the actual
97                 # calulation to maintain better accuracy.
98                 while len(units) and size >= 1000:
99                         approx = 1
100                         size = size / 1024.0
101                         units.pop()
102                 sizestr = "%.1f" %(round(size,1)) + units[-1]
103                 if justify:
104                         sizestr = " " + self.brace("[ ")  + \
105                                 color(sizestr.rjust(8)) + self.brace(" ]")
106                 return sizestr
107
108         def yesNoAllPrompt(self, message="Do you want to proceed?"):
109                 """Print a prompt until user answer in yes/no/all. Return a
110                 boolean for answer, and also may affect the 'accept_all' option.
111
112                 @param message: optional different input string from the default
113                                 message of: "Do you want to proceed?"
114                 @outputs to stdout
115                 @modifies class var options['accept_all']
116                 @rtype: bool
117                 """
118                 user_string="xxx"
119                 while not user_string.lower() in ["","y","n","a","yes","no","all"]:
120                         self.eprompt(message+" [Y/n/a]: ")
121                         user_string =  sys.stdin.readline().rstrip('\n')
122                         user_string = user_string.strip()
123                 if user_string.lower() in ["a","all"]:
124                         self.options['accept_all'] = True
125                 answer = user_string.lower() in ["","y","a","yes","all"]
126                 return answer
127
128         def progress_controller(self, size, key, clean_list, file_type):
129                 """Callback function for doCleanup. It outputs data according to the
130                 options configured.
131                 Alternatively it handles user interaction for decisions that are
132                 required.
133
134                 @param size: Integer of the file(s) size
135                 @param key: the filename/pkgname currently being processed
136                 @param clean_list: list of files being processed.
137                 """
138                 if not self.options['quiet']:
139                         # pretty print mode
140                         print(self.prettySize(size,True), self.pkg_color(key))
141                 elif self.options['pretend'] or self.options['interactive']:
142                         # file list mode
143                         for file_ in clean_list:
144                                 print(file_)
145                 if self.options['pretend']:
146                         return False
147                 elif not self.options['interactive'] \
148                         or self.options['accept_all'] \
149                         or self.yesNoAllPrompt("Do you want to delete this " + file_type + "?"):
150                         return True
151                 return False
152
153         def total(self, mode, size, num_files, verb, action):
154                 """outputs the formatted totals to stdout
155
156                 @param mode: sets color and message. 1 of ['normal', 'deprecated']
157                 @param size: total space savings
158                 @param num_files: total number of files
159                 @param verb: string eg. 1 of ["would be", "has been"]
160                 @param action: string eg 1 of ['distfiles', 'packages']
161                 """
162                 self.set_colors(mode)
163                 if mode =="normal":
164                         message="Total space from "+red(str(num_files))+" files "+\
165                                 verb+" freed in the " + action + " directory"
166                         print( " ===========")
167                         print( self.prettySize(size, True, red), message)
168                 elif mode == "deprecated":
169                         message = "Total space from "+red(str(num_files))+" package files\n"+\
170                                 "   Re-run the last command with the -D " +\
171                                 "option to clean them as well"
172                         print( " ===========")
173                         print( self.prettySize(size, True, red), message)
174
175         def list_pkgs(self, pkgs):
176                 """outputs the packages to stdout
177
178                 @param pkgs: dict. of {cat/pkg-ver: src_uri,}
179                 """
180                 indent = ' ' * 12
181                 keys = list(pkgs.keys())
182                 keys.sort()
183                 for key in keys:
184                         if pkgs[key]:
185                                 saved = ""
186                         else:
187                                 saved = " ...distfile name(s) not known/saved"
188                         print( indent,self.pkg_color(key) + saved)
189                 print()