scripts/release/io.py
changeset 1981 8cfb054b73b2
equal deleted inserted replaced
1980:db7c98580008 1981:8cfb054b73b2
       
     1 #!/usr/bin/python2.5
       
     2 #
       
     3 # Copyright 2009 the Melange authors.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #   http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 
       
    17 from __future__ import with_statement
       
    18 
       
    19 """User prompting and file access utilities."""
       
    20 
       
    21 __authors__ = [
       
    22     # alphabetical order by last name, please
       
    23     '"David Anderson" <dave@natulte.net>',
       
    24     ]
       
    25 
       
    26 import error
       
    27 import log
       
    28 
       
    29 
       
    30 class Error(error.Error):
       
    31   pass
       
    32 
       
    33 
       
    34 class FileAccessError(Error):
       
    35   """An error occured while accessing a file."""
       
    36   pass
       
    37 
       
    38 
       
    39 def getString(prompt):
       
    40   """Prompt for and return a string."""
       
    41   prompt += ' '
       
    42   log.stdout.write(prompt)
       
    43   log.stdout.flush()
       
    44 
       
    45   response = sys.stdin.readline()
       
    46   log.terminal_echo(prompt + response.strip())
       
    47   if not response:
       
    48     raise error.AbortedByUser('Aborted by ctrl+D')
       
    49 
       
    50   return response.strip()
       
    51 
       
    52 
       
    53 def confirm(prompt, default=False):
       
    54   """Ask a yes/no question and return the answer.
       
    55 
       
    56   Will reprompt the user until one of "yes", "no", "y" or "n" is
       
    57   entered. The input is case insensitive.
       
    58 
       
    59   Args:
       
    60     prompt: The question to ask the user.
       
    61     default: The answer to return if the user just hits enter.
       
    62 
       
    63   Returns:
       
    64     True if the user answered affirmatively, False otherwise.
       
    65   """
       
    66   if default:
       
    67     question = prompt + ' [Yn]'
       
    68   else:
       
    69     question = prompt + ' [yN]'
       
    70   while True:
       
    71     answer = getString(question)
       
    72     if not answer:
       
    73       return default
       
    74     elif answer in ('y', 'yes'):
       
    75       return True
       
    76     elif answer in ('n', 'no'):
       
    77       return False
       
    78     else:
       
    79       log.error('Please answer yes or no.')
       
    80 
       
    81 
       
    82 def getNumber(prompt):
       
    83   """Prompt for and return a number.
       
    84 
       
    85   Will reprompt the user until a number is entered.
       
    86   """
       
    87   while True:
       
    88     value_str = getString(prompt)
       
    89     try:
       
    90       return int(value_str)
       
    91     except ValueError:
       
    92       log.error('Please enter a number. You entered "%s".' % value_str)
       
    93 
       
    94 
       
    95 def getChoice(intro, prompt, choices, done=None, suggest=None):
       
    96   """Prompt for and return a choice from a menu.
       
    97 
       
    98   Will reprompt the user until a valid menu entry is chosen.
       
    99 
       
   100   Args:
       
   101     intro: Text to print verbatim before the choice menu.
       
   102     prompt: The prompt to print right before accepting input.
       
   103     choices: The list of string choices to display.
       
   104     done: If not None, the list of indices of previously
       
   105       selected/completed choices.
       
   106     suggest: If not None, the index of the choice to highlight as
       
   107       the suggested choice.
       
   108 
       
   109   Returns:
       
   110     The index in the choices list of the selection the user made.
       
   111   """
       
   112   done = set(done or [])
       
   113   while True:
       
   114     print intro
       
   115     print
       
   116     for i, entry in enumerate(choices):
       
   117       done_text = ' (done)' if i in done else ''
       
   118       indent = '--> ' if i == suggest else '    '
       
   119       print '%s%2d. %s%s' % (indent, i+1, entry, done_text)
       
   120     print
       
   121     choice = getNumber(prompt)
       
   122     if 0 < choice <= len(choices):
       
   123       return choice-1
       
   124     log.error('%d is not a valid choice between %d and %d' %
       
   125               (choice, 1, len(choices)))
       
   126     print
       
   127 
       
   128 
       
   129 def fileToLines(path):
       
   130   """Read a file and return it as a list of lines."""
       
   131   try:
       
   132     with file(path) as f:
       
   133       return f.read().split('\n')
       
   134   except (IOError, OSError), e:
       
   135     raise FileAccessError(str(e))
       
   136 
       
   137 
       
   138 def linesToFile(path, lines):
       
   139   """Write a list of lines to a file."""
       
   140   try:
       
   141     with file(path, 'w') as f:
       
   142       f.write('\n'.join(lines))
       
   143   except (IOError, OSError), e:
       
   144     raise FileAccessError(str(e))