Package entropy :: Module output

Source Code for Module entropy.output

  1  #!/usr/bin/python 
  2  ''' 
  3      # DESCRIPTION: 
  4      # Text formatting and colouring tools 
  5   
  6      Copyright 1998-2004 Gentoo Foundation 
  7      # $Id: output.py 4906 2006-11-01 23:55:29Z zmedico $ 
  8      Copyright (C) 2007-2008 Fabio Erculiani 
  9   
 10      This program is free software; you can redistribute it and/or modify 
 11      it under the terms of the GNU General Public License as published by 
 12      the Free Software Foundation; either version 2 of the License, or 
 13      (at your option) any later version. 
 14   
 15      This program is distributed in the hope that it will be useful, 
 16      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18      GNU General Public License for more details. 
 19   
 20      You should have received a copy of the GNU General Public License 
 21      along with this program; if not, write to the Free Software 
 22      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 23  ''' 
 24   
 25  import sys, os 
 26  import curses 
 27  from entropy.const import etpUi 
 28  from entropy.exceptions import IncorrectParameter 
 29  from entropy.i18n import _ 
 30  stuff = {} 
 31  stuff['cols'] = 30 
 32  try: 
 33      curses.setupterm() 
 34      stuff['cols'] = curses.tigetnum('cols') 
 35  except: 
 36      pass 
 37  stuff['cleanline'] = "" 
38 -def setcols():
39 stuff['cleanline'] = "" 40 count = stuff['cols'] 41 while count: 42 stuff['cleanline'] += ' ' 43 count -= 1
44 setcols() 45 stuff['cursor'] = False 46 stuff['ESC'] = chr(27) 47 48 havecolor=1 49 global dotitles 50 dotitles=1 51 52 esc_seq = "\x1b[" 53 54 g_attr = {} 55 g_attr["normal"] = 0 56 57 g_attr["bold"] = 1 58 g_attr["faint"] = 2 59 g_attr["standout"] = 3 60 g_attr["underline"] = 4 61 g_attr["blink"] = 5 62 g_attr["overline"] = 6 # Why is overline actually useful? 63 g_attr["reverse"] = 7 64 g_attr["invisible"] = 8 65 66 g_attr["no-attr"] = 22 67 g_attr["no-standout"] = 23 68 g_attr["no-underline"] = 24 69 g_attr["no-blink"] = 25 70 g_attr["no-overline"] = 26 71 g_attr["no-reverse"] = 27 72 # 28 isn't defined? 73 # 29 isn't defined? 74 g_attr["black"] = 30 75 g_attr["red"] = 31 76 g_attr["green"] = 32 77 g_attr["yellow"] = 33 78 g_attr["blue"] = 34 79 g_attr["magenta"] = 35 80 g_attr["cyan"] = 36 81 g_attr["white"] = 37 82 # 38 isn't defined? 83 g_attr["default"] = 39 84 g_attr["bg_black"] = 40 85 g_attr["bg_red"] = 41 86 g_attr["bg_green"] = 42 87 g_attr["bg_yellow"] = 43 88 g_attr["bg_blue"] = 44 89 g_attr["bg_magenta"] = 45 90 g_attr["bg_cyan"] = 46 91 g_attr["bg_white"] = 47 92 g_attr["bg_default"] = 49 93 94 95 # make_seq("blue", "black", "normal")
96 -def color(fg, bg="default", attr=["normal"]):
97 mystr = esc_seq[:] + "%02d" % g_attr[fg] 98 for x in [bg]+attr: 99 mystr += ";%02d" % g_attr[x] 100 return mystr+"m"
101 102 103 104 codes={} 105 codes["reset"] = esc_seq + "39;49;00m" 106 107 codes["bold"] = esc_seq + "01m" 108 codes["faint"] = esc_seq + "02m" 109 codes["standout"] = esc_seq + "03m" 110 codes["underline"] = esc_seq + "04m" 111 codes["blink"] = esc_seq + "05m" 112 codes["overline"] = esc_seq + "06m" # Who made this up? Seriously. 113 114 ansi_color_codes = [] 115 for x in xrange(30, 38): 116 ansi_color_codes.append("%im" % x) 117 ansi_color_codes.append("%i;01m" % x) 118 119 rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00', 120 '0x55FF55', '0xAA5500', '0xFFFF55', '0x0000AA', '0x5555FF', '0xAA00AA', 121 '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF'] 122 123 for x in xrange(len(rgb_ansi_colors)): 124 codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x] 125 126 del x 127 128 codes["black"] = codes["0x000000"] 129 codes["darkgray"] = codes["0x555555"] 130 131 codes["red"] = codes["0xFF5555"] 132 codes["darkred"] = codes["0xAA0000"] 133 134 codes["green"] = codes["0x55FF55"] 135 codes["darkgreen"] = codes["0x00AA00"] 136 137 codes["yellow"] = codes["0xFFFF55"] 138 codes["brown"] = codes["0xAA5500"] 139 140 codes["blue"] = codes["0x5555FF"] 141 codes["darkblue"] = codes["0x0000AA"] 142 143 codes["fuchsia"] = codes["0xFF55FF"] 144 codes["purple"] = codes["0xAA00AA"] 145 146 codes["turquoise"] = codes["0x55FFFF"] 147 codes["teal"] = codes["0x00AAAA"] 148 149 codes["white"] = codes["0xFFFFFF"] 150 codes["lightgray"] = codes["0xAAAAAA"] 151 152 codes["darkteal"] = codes["turquoise"] 153 codes["darkyellow"] = codes["brown"] 154 codes["fuscia"] = codes["fuchsia"] 155 codes["white"] = codes["bold"] 156 157 # Colors from /sbin/functions.sh 158 codes["GOOD"] = codes["green"] 159 codes["WARN"] = codes["yellow"] 160 codes["BAD"] = codes["red"] 161 codes["HILITE"] = codes["teal"] 162 codes["BRACKET"] = codes["blue"] 163 164 # Portage functions 165 codes["INFORM"] = codes["darkgreen"] 166 codes["UNMERGE_WARN"] = codes["red"] 167 codes["MERGE_LIST_PROGRESS"] = codes["yellow"] 168
169 -def xtermTitle(mystr, raw=False):
170 if dotitles and "TERM" in os.environ and sys.stderr.isatty(): 171 myt=os.environ["TERM"] 172 legal_terms = ["xterm","Eterm","aterm","rxvt","screen","kterm","rxvt-unicode","gnome"] 173 if myt in legal_terms: 174 if not raw: 175 mystr = "\x1b]0;%s\x07" % mystr 176 try: 177 sys.stderr.write(mystr) 178 except UnicodeEncodeError: 179 sys.stderr.write(mystr.encode('utf-8')) 180 sys.stderr.flush()
181 182 default_xterm_title = None 183
184 -def xtermTitleReset():
185 global default_xterm_title 186 if default_xterm_title is None: 187 prompt_command = os.getenv('PROMPT_COMMAND') 188 if prompt_command == "": 189 default_xterm_title = "" 190 elif prompt_command is not None: 191 from entropy.tools import getstatusoutput 192 default_xterm_title = getstatusoutput(prompt_command)[1] 193 else: 194 pwd = os.getenv('PWD','') 195 home = os.getenv('HOME', '') 196 if home != '' and pwd.startswith(home): 197 pwd = '~' + pwd[len(home):] 198 default_xterm_title = '\x1b]0;%s@%s:%s\x07' % ( 199 os.getenv('LOGNAME', ''), 200 os.getenv('HOSTNAME', '').split('.', 1)[0], 201 pwd) 202 xtermTitle(default_xterm_title, raw=True)
203
204 -def notitles():
205 "turn off title setting" 206 global dotitles 207 dotitles=0
208
209 -def nocolor():
210 "turn off colorization" 211 os.environ['ETP_NO_COLOR'] = "1" 212 global havecolor 213 havecolor=0
214 215 nc = os.getenv("ETP_NO_COLOR") 216 if nc: 217 nocolor() 218
219 -def resetColor():
220 return codes["reset"]
221
222 -def colorize(color_key, text):
223 if etpUi['mute']: 224 return text 225 global havecolor 226 if havecolor: 227 return codes[color_key] + text + codes["reset"] 228 return text
229
230 -def bold(text):
231 return colorize("bold", text)
232
233 -def white(text):
234 return colorize("white", text)
235
236 -def teal(text):
237 return colorize("teal", text)
238
239 -def turquoise(text):
240 return colorize("turquoise", text)
241
242 -def darkteal(text):
243 return colorize("darkteal", text)
244
245 -def fuscia(text):
246 return colorize("fuscia", text)
247
248 -def fuchsia(text):
249 return colorize("fuchsia", text)
250
251 -def purple(text):
252 return colorize("purple", text)
253
254 -def blue(text):
255 return colorize("blue", text)
256
257 -def darkblue(text):
258 return colorize("darkblue", text)
259
260 -def green(text):
261 return colorize("green", text)
262
263 -def darkgreen(text):
264 return colorize("darkgreen", text)
265
266 -def yellow(text):
267 return colorize("yellow", text)
268
269 -def brown(text):
270 return colorize("brown", text)
271
272 -def darkyellow(text):
273 return colorize("darkyellow", text)
274
275 -def red(text):
276 return colorize("red", text)
277
278 -def darkred(text):
279 return colorize("darkred", text)
280
281 -def create_color_func(color_key):
282 def derived_func(*args): 283 newargs = list(args) 284 newargs.insert(0, color_key) 285 return colorize(*newargs)
286 return derived_func 287
288 -def enlightenatom(atom):
289 out = atom.split("/") 290 return blue(out[0])+"/"+red(out[1])
291 298 def orig_myfunc_desc(x): 299 return x 300 301 try: 302 i = args.index("--help") 303 del args[i] 304 command = args.pop(0) 305 except ValueError: 306 command = None 307 except IndexError: 308 command = None 309 section_found = False 310 search_depth = 1 311 312 313 for item in data: 314 myfunc = orig_myfunc 315 myfunc_desc = orig_myfunc_desc 316 317 if not item: 318 if command == None or section_found: 319 writechar("\n") 320 else: 321 n_ident = item[0] 322 name = item[1] 323 n_d_ident = item[2] 324 desc = item[3] 325 if command != None: 326 #print "searching ",name, command, n_ident, search_depth 327 if name == command and n_ident == search_depth: 328 try: 329 command = args.pop(0) 330 search_depth = n_ident + 1 331 except IndexError: 332 command = "##unused_from_now_on" 333 section_found = True 334 indent_level = n_ident 335 elif section_found: 336 if n_ident <= indent_level: 337 return 338 else: 339 continue 340 341 if n_ident == 0: 342 writechar(" ") 343 # setup identation 344 while n_ident > 0: 345 n_ident -= 1 346 writechar("\t") 347 n_ident = item[0] 348 349 # write name 350 if n_ident == 0: 351 myfunc = darkgreen 352 elif n_ident == 1: 353 myfunc = blue 354 myfunc_desc = darkgreen 355 elif n_ident == 2: 356 if not name.startswith("--"): 357 myfunc = red 358 myfunc_desc = brown 359 elif n_ident == 3: 360 myfunc = darkblue 361 myfunc_desc = purple 362 try: 363 print myfunc(name), 364 except UnicodeEncodeError: 365 print myfunc(name.encode('utf-8')), 366 367 # write desc 368 if desc: 369 while n_d_ident > 0: 370 n_d_ident -= 1 371 writechar("\t") 372 try: 373 print myfunc_desc(desc), 374 except UnicodeEncodeError: 375 print myfunc_desc(desc.encode('utf-8')), 376 writechar("\n") 377
378 -def reset_cursor():
379 if havecolor: 380 sys.stdout.write(stuff['ESC'] + '[2K') 381 flush_stdouterr()
382
383 -def flush_stdouterr():
384 sys.stdout.flush() 385 sys.stderr.flush()
386 406 426 446 448 if etpUi['mute']: 449 return 450 writechar("\r") 451 try: 452 print msg 453 except UnicodeEncodeError: 454 print msg.encode('utf-8') 455 flush_stdouterr() 456
457 -def writechar(char):
458 if etpUi['mute']: 459 return 460 try: 461 sys.stdout.write(char) 462 sys.stdout.flush() 463 except IOError, e: 464 if e.errno == 32: 465 return 466 raise
467
468 -def readtext(request, password = False):
469 xtermTitle(_("Entropy needs your attention")) 470 if password: 471 from getpass import getpass 472 try: 473 text = getpass(request+" ") 474 except UnicodeEncodeError: 475 text = getpass(request.encode('utf-8')+" ") 476 else: 477 try: 478 print request,"", 479 except UnicodeEncodeError: 480 print request.encode('utf-8'),"", 481 flush_stdouterr() 482 text = my_raw_input() 483 return text
484
485 -def my_raw_input(txt = ''):
486 if txt: 487 try: 488 print darkgreen(txt), 489 except UnicodeEncodeError: 490 print darkgreen(txt.encode('utf-8')), 491 flush_stdouterr() 492 response = '' 493 while 1: 494 y = sys.stdin.read(1) 495 if y in ('\n','\r',): break 496 response += y 497 flush_stdouterr() 498 return response
499
500 -class TextInterface:
501 502 # @input text: text to write 503 # @input back: write on on the same line? 504 # @input importance: 505 # values: 0,1,2,3 (latter is a blocker - popup menu on a GUI env) 506 # used to specify information importance, 0<important<2 507 # @input type: 508 # values: "info, warning, error" 509 # 510 # @input count: 511 # if you need to print an incremental count ( 100/250...101/251..) 512 # just pass count = [first integer,second integer] or even a tuple! 513 # @input header: 514 # text header (decoration?), that's it 515 # 516 # @input footer: 517 # text footer (decoration?), that's it 518 # 519 # @input percent: 520 # if percent is True: count will be treating as a percentual count[0]/count[1]*100 521 # 522 # feel free to reimplement this
523 - def updateProgress(self, text, header = "", footer = "", back = False, importance = 0, type = "info", count = [], percent = False):
524 if (etpUi['quiet']) or (etpUi['mute']): 525 return 526 527 flush_stdouterr() 528 529 myfunc = print_info 530 if type == "warning": 531 myfunc = print_warning 532 elif type == "error": 533 myfunc = print_error 534 535 count_str = "" 536 if count: 537 if len(count) > 1: 538 if percent: 539 count_str = " ("+str(round((float(count[0])/count[1])*100,1))+"%) " 540 else: 541 count_str = " (%s/%s) " % (red(str(count[0])),blue(str(count[1])),) 542 if importance == 0: 543 myfunc(header+count_str+text+footer, back = back, flush = False) 544 elif importance == 1: 545 myfunc(header+count_str+text+footer, back = back, flush = False) 546 elif importance in (2,3): 547 myfunc(header+count_str+text+footer, back = back, flush = False) 548 549 flush_stdouterr()
550 551 # @input question: question to do 552 # 553 # @input importance: 554 # values: 0,1,2 (latter is a blocker - popup menu on a GUI env) 555 # used to specify information importance, 0<important<2 556 # 557 # @input responses: 558 # list of options whose users can choose between 559 # 560 # feel free to reimplement this
561 - def askQuestion(self, question, importance = 0, responses = ["Yes","No"]):
562 563 colours = [green, red, blue, darkgreen, darkred, darkblue, brown, purple] 564 colours += colours[:] 565 if len(responses) > len(colours): 566 raise IncorrectParameter("IncorrectParameter: %s = %s" % (_("maximum responses length"),len(colours),)) 567 try: 568 print darkgreen(question), 569 except UnicodeEncodeError: 570 print darkgreen(question.encode('utf-8')), 571 flush_stdouterr() 572 try: 573 while True: 574 xtermTitle(_("Entropy got a question for you")) 575 flush_stdouterr() 576 response = my_raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ") 577 flush_stdouterr() 578 for key in responses: 579 # An empty response will match the first value in responses. 580 if response.upper() == key[:len(response)].upper(): 581 xtermTitleReset() 582 return key 583 ''' 584 try: 585 print "%s '%s'" % (_("I cannot understand"),response,), 586 except UnicodeEncodeError: 587 print "%s '%s'" % (_("I cannot understand"),response.encode('utf-8'),), 588 ''' 589 flush_stdouterr() 590 except (EOFError, KeyboardInterrupt): 591 print "%s." % (_("Interrupted"),) 592 xtermTitleReset() 593 raise SystemExit(100) 594 xtermTitleReset() 595 flush_stdouterr()
596 597 ''' 598 @ title: title of the input box 599 @ input_parameters: [ 600 ('identifier 1','input text 1',input_verification_callback,False), 601 ('password','Password',input_verification_callback,True), 602 ('item_3',('checkbox','Checkbox option (boolean request) - please choose',),input_verification_callback,True), 603 ('item_4',('combo',('Select your favorite option',['option 1', 'option 2', 'option 3']),),input_verification_callback,True), 604 ('item_4',('list',('Setup your list',['default list item 1', 'default list item 2']),),input_verification_callback,True) 605 ] 606 @ cancel_button: show cancel button ? 607 @ output: dictionary as follows: 608 {'identifier 1': result, 'identifier 2': result} 609 '''
610 - def inputBox(self, title, input_parameters, cancel_button = True):
611 results = {} 612 if title: 613 try: 614 print title 615 except UnicodeEncodeError: 616 print title.encode('utf-8') 617 flush_stdouterr() 618 619 def option_chooser(option_data): 620 mydict = {} 621 counter = 1 622 option_text, option_list = option_data 623 self.updateProgress(option_text) 624 for item in option_list: 625 mydict[counter] = item 626 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),) 627 self.updateProgress(txt) 628 counter += 1 629 while 1: 630 myresult = readtext("%s:" % (_('Selected number'),)).decode('utf-8') 631 try: 632 myresult = int(myresult) 633 except ValueError: 634 continue 635 selected = mydict.get(myresult) 636 if selected != None: 637 return myresult, selected
638 639 def list_editor(option_data, can_cancel, callback): 640 641 def selaction(): 642 self.updateProgress('') 643 self.updateProgress(darkred(_("Please select an option"))) 644 if can_cancel: 645 self.updateProgress(" ("+blue("-1")+") "+darkred(_("Discard all"))) 646 self.updateProgress(" ("+blue("0")+") "+darkgreen(_("Confirm"))) 647 self.updateProgress(" ("+blue("1")+") "+brown(_("Add item"))) 648 self.updateProgress(" ("+blue("2")+") "+darkblue(_("Remove item"))) 649 self.updateProgress(" ("+blue("3")+") "+darkgreen(_("Show current list"))) 650 # wait user interaction 651 self.updateProgress('') 652 action = readtext(darkgreen(_("Your choice (type a number and press enter):"))+" ") 653 return action
654 655 mydict = {} 656 counter = 1 657 valid_actions = [0,1,2,3] 658 if can_cancel: valid_actions.insert(0,-1) 659 option_text, option_list = option_data 660 txt = "%s:" % (blue(option_text),) 661 self.updateProgress(txt) 662 663 for item in option_list: 664 mydict[counter] = item 665 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),) 666 self.updateProgress(txt) 667 counter += 1 668 669 def show_current_list(): 670 for key in sorted(mydict): 671 txt = "[%s] %s" % (darkgreen(str(key)), blue(mydict[key]),) 672 self.updateProgress(txt) 673 674 while 1: 675 try: 676 action = int(selaction()) 677 except (ValueError,TypeError,): 678 self.updateProgress(_("You don't have typed a number."), type = "warning") 679 continue 680 if action not in valid_actions: 681 self.updateProgress(_("Invalid action."), type = "warning") 682 continue 683 if action == -1: 684 raise KeyboardInterrupt 685 elif action == 0: 686 break 687 elif action == 1: 688 while 1: 689 try: 690 s_el = readtext(darkred(_("String to add:"))+" ") 691 if not callback(s_el): 692 raise ValueError 693 mydict[counter] = s_el 694 counter += 1 695 except (ValueError,): 696 self.updateProgress(_("Invalid string."), type = "warning") 697 continue 698 break 699 show_current_list() 700 continue 701 elif action == 2: 702 while 1: 703 try: 704 s_el = int(readtext(darkred(_("Element number to remove:"))+" ")) 705 if s_el not in mydict: 706 raise ValueError 707 del mydict[s_el] 708 except (ValueError,TypeError,): 709 self.updateProgress(_("Invalid element."), type = "warning") 710 continue 711 break 712 show_current_list() 713 continue 714 elif action == 3: 715 show_current_list() 716 continue 717 break 718 719 mylist = [mydict[x] for x in sorted(mydict)] 720 return mylist 721 722 for identifier, input_text, callback, password in input_parameters: 723 while 1: 724 use_cb = True 725 try: 726 if isinstance(input_text,tuple): 727 myresult = False 728 input_type, data = input_text 729 if input_type == "checkbox": 730 answer = self.askQuestion(data) 731 if answer == "Yes": myresult = True 732 elif input_type == "combo": 733 myresult = option_chooser(data) 734 elif input_type == "list": 735 use_cb = False 736 myresult = list_editor(data, cancel_button, callback) 737 else: 738 myresult = readtext(input_text+":", password = password).decode('utf-8') 739 except (KeyboardInterrupt,EOFError,): 740 if not cancel_button: # use with care 741 continue 742 return None 743 valid = True 744 if use_cb: 745 valid = callback(myresult) 746 if valid: 747 results[identifier] = myresult 748 break 749 return results 750 751 # useful for reimplementation 752 # in this wait you can send a signal to a widget (total progress bar?)
753 - def cycleDone(self):
754 return
755
756 - def setTitle(self, title):
757 xtermTitle(title)
758
759 - def setTotalCycles(self, total):
760 return
761
762 - def outputInstanceTest(self):
763 return
764
765 - def nocolor(self):
766 nocolor()
767
768 - def notitles(self):
769 notitles()
770