1 # Copyright (c) 2009, Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 from webkitpy.common.system.executive import Executive
40 from webkitpy.common.system.platforminfo import PlatformInfo
43 _log = logging.getLogger(__name__)
50 def __init__(self, platforminfo=None):
51 # We cannot get the PlatformInfo object from a SystemHost because
52 # User is part of SystemHost itself.
53 self._platforminfo = platforminfo or PlatformInfo(sys, platform, Executive())
55 # FIXME: These are @classmethods because bugzilla.py doesn't have a Tool object (thus no User instance).
57 def prompt(cls, message, repeat=1, raw_input=raw_input):
59 while (repeat and not response):
61 response = raw_input(message)
65 def prompt_password(cls, message, repeat=1):
66 return cls.prompt(message, repeat=repeat, raw_input=getpass.getpass)
69 def prompt_with_multiple_lists(cls, list_title, subtitles, lists, can_choose_multiple=False, raw_input=raw_input):
73 for i in range(len(subtitles)):
74 print "\n" + subtitles[i]
77 print "%2d. %s" % (item_index, item)
78 cumulated_list += lists[i]
79 return cls._wait_on_list_response(cumulated_list, can_choose_multiple, raw_input)
82 def _wait_on_list_response(cls, list_items, can_choose_multiple, raw_input):
84 if can_choose_multiple:
85 response = cls.prompt("Enter one or more numbers (comma-separated) or ranges (e.g. 3-7), or \"all\": ", raw_input=raw_input)
86 if not response.strip() or response == "all":
91 for value in re.split("\s*,\s*", response):
92 parts = value.split('-')
94 indices += range(int(parts[0]) - 1, int(parts[1]))
96 indices.append(int(value) - 1)
97 except ValueError, err:
100 return [list_items[i] for i in indices]
103 result = int(cls.prompt("Enter a number: ", raw_input=raw_input)) - 1
104 except ValueError, err:
106 return list_items[result]
109 def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
112 for item in list_items:
114 print "%2d. %s" % (i, item)
115 return cls._wait_on_list_response(list_items, can_choose_multiple, raw_input)
117 def edit(self, files):
118 editor = os.environ.get("EDITOR") or "vi"
119 args = shlex.split(editor)
120 # Note: Not thread safe: http://bugs.python.org/issue2320
121 subprocess.call(args + files)
123 def page(self, message):
124 pager = os.environ.get("PAGER") or "less"
126 # Note: Not thread safe: http://bugs.python.org/issue2320
127 child_process = subprocess.Popen([pager], stdin=subprocess.PIPE)
128 child_process.communicate(input=message)
132 def confirm(self, message=None, default=DEFAULT_YES, raw_input=raw_input):
134 message = "Continue?"
135 choice = {'y': 'Y/n', 'n': 'y/N'}[default]
136 response = raw_input("%s [%s]: " % (message, choice))
139 return response.lower() == 'y'
141 def can_open_url(self):
145 except webbrowser.Error, e:
148 def open_url(self, url):
149 if not self.can_open_url():
150 _log.warn("Failed to open %s" % url)