def _offer_to_store_credentials_in_keyring(self, username, password): if not self._keyring: return if not User().confirm("Store password in system keyring?", User.DEFAULT_NO): return self._keyring.set_password(self.host, username, password)
def test_prompt_when_exceeded_repeats(self): self.repeatsRemaining = 2 def mock_raw_input(message): self.repeatsRemaining -= 1 return None self.assertIsNone(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input))
def _builder_to_analyze(self): statuses = self._tool.buildbot.builder_statuses() choices = [status["name"] for status in statuses] chosen_name = User.prompt_with_list("Which builder to analyze:", choices) for status in statuses: if status["name"] == chosen_name: return (self._tool.buildbot.builder_with_name(chosen_name), status["built_revision"])
def test_prompt_when_exceeded_repeats(self): self.repeatsRemaining = 2 def mock_raw_input(message): self.repeatsRemaining -= 1 return None self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), None)
def create_bug( self, bug_title, bug_description, component=None, diff=None, patch_description=None, cc=None, blocked=None, assignee=None, mark_for_review=False, mark_for_commit_queue=False, ): self.authenticate() _log.info('Creating bug with title "%s"' % bug_title) self.browser.open(config_urls.bug_server_url + "enter_bug.cgi?product=WebKit") self.browser.select_form(name="Create") component_items = self.browser.find_control("component").items component_names = map(lambda item: item.name, component_items) if not component: component = "New Bugs" if component not in component_names: component = User.prompt_with_list("Please pick a component:", component_names) self.browser["component"] = [component] if cc: self.browser["cc"] = cc if blocked: self.browser["blocked"] = unicode(blocked) if not assignee: assignee = self.username if assignee and not self.browser.find_control("assigned_to").disabled: self.browser["assigned_to"] = assignee self.browser["short_desc"] = bug_title self.browser["comment"] = bug_description if diff: # _fill_attachment_form expects a file-like object # Patch files are already binary, so no encoding needed. assert isinstance(diff, str) patch_file_object = StringIO.StringIO(diff) commit_flag = CommitQueueFlag.mark_for_nothing if mark_for_commit_queue: commit_flag = CommitQueueFlag.mark_for_commit_queue self._fill_attachment_form( patch_description, patch_file_object, mark_for_review=mark_for_review, commit_flag=commit_flag, is_patch=True, ) response = self.browser.submit() bug_id = self._check_create_bug_response(response.read()) _log.info("Bug %s created." % bug_id) _log.info("%sshow_bug.cgi?id=%s" % (config_urls.bug_server_url, bug_id)) return bug_id
def create_bug(self, bug_title, bug_description, component=None, diff=None, patch_description=None, cc=None, blocked=None, assignee=None, mark_for_review=False, mark_for_commit_queue=False): self.authenticate() log('Creating bug with title "%s"' % bug_title) if self.dryrun: log(bug_description) # FIXME: This will make some paths fail, as they assume this returns an id. return self.browser.open(config_urls.bug_server_url + "enter_bug.cgi?product=WebKit") self.browser.select_form(name="Create") component_items = self.browser.find_control('component').items component_names = map(lambda item: item.name, component_items) if not component: component = "New Bugs" if component not in component_names: component = User.prompt_with_list("Please pick a component:", component_names) self.browser["component"] = [component] if cc: self.browser["cc"] = cc if blocked: self.browser["blocked"] = unicode(blocked) if not assignee: assignee = self.username if assignee and not self.browser.find_control("assigned_to").disabled: self.browser["assigned_to"] = assignee self.browser["short_desc"] = bug_title self.browser["comment"] = bug_description if diff: # _fill_attachment_form expects a file-like object # Patch files are already binary, so no encoding needed. assert (isinstance(diff, str)) patch_file_object = StringIO.StringIO(diff) self._fill_attachment_form( patch_description, patch_file_object, mark_for_review=mark_for_review, mark_for_commit_queue=mark_for_commit_queue, is_patch=True) response = self.browser.submit() bug_id = self._check_create_bug_response(response.read()) log("Bug %s created." % bug_id) log("%sshow_bug.cgi?id=%s" % (config_urls.bug_server_url, bug_id)) return bug_id
def check_confirm(self, expected_message, expected_out, default, user_input): def mock_raw_input(message): self.assertEqual(expected_message, message) return user_input out = User().confirm(default=default, input_func=mock_raw_input) self.assertEqual(expected_out, out)
def test_prompt_repeat(self): self.repeatsRemaining = 2 def mock_raw_input(message): self.repeatsRemaining -= 1 if not self.repeatsRemaining: return UserTest.example_user_response return None self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), UserTest.example_user_response)
def test_warn_if_application_is_xcode(self): output = OutputCapture() user = User() output.assert_outputs(self, user._warn_if_application_is_xcode, ["TextMate"]) output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Applications/TextMate.app"]) output.assert_outputs(self, user._warn_if_application_is_xcode, ["XCode"]) # case sensitive matching xcode_warning = "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\".\n" output.assert_outputs(self, user._warn_if_application_is_xcode, ["Xcode"], expected_stdout=xcode_warning) output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Developer/Applications/Xcode.app"], expected_stdout=xcode_warning)
def read_credentials(self): username, password = self._credentials_from_environment() # FIXME: We don't currently support pulling the username from one # source and the password from a separate source. if not username or not password: username, password = self._credentials_from_git() if not username or not password: username, password = self._credentials_from_keychain(username) if username and not password and self._keyring: password = self._keyring.get_password(self.host, username) if not username: username = User.prompt("%s login: "******"%s password for %s: " % (self.host, username)) self._offer_to_store_credentials_in_keyring(username, password) return (username, password)
def test_prompt_when_exceeded_repeats(self): self.repeats_remaining = 2 def mock_raw_input(_): self.repeats_remaining -= 1 return None self.assertIsNone( User.prompt('input', repeat=self.repeats_remaining, input_func=mock_raw_input))
def _builder_to_explain(self): builder_statuses = self.tool.buildbot.builder_statuses() red_statuses = [status for status in builder_statuses if not status["is_green"]] print "%s failing" % (pluralize("builder", len(red_statuses))) builder_choices = [status["name"] for status in red_statuses] # We could offer an "All" choice here. chosen_name = User.prompt_with_list("Which builder to diagnose:", builder_choices) # FIXME: prompt_with_list should really take a set of objects and a set of names and then return the object. for status in red_statuses: if status["name"] == chosen_name: return (self.tool.buildbot.builder_with_name(chosen_name), status["built_revision"])
def __init__(self): self.executable = sys.executable self.executive = Executive() self.filesystem = FileSystem() self.user = User() self.platform = PlatformInfo(sys, platform, self.filesystem, self.executive) self.stdin = sys.stdin self.stdout = sys.stdout self.stderr = sys.stderr self.environ = os.environ
def test_prompt_repeat(self): self.repeats_remaining = 2 def mock_raw_input(_): self.repeats_remaining -= 1 if not self.repeats_remaining: return 'example user response' return None self.assertEqual( User.prompt('input', repeat=self.repeats_remaining, input_func=mock_raw_input), 'example user response')
def create_bug(self, bug_title, bug_description, component=None, diff=None, patch_description=None, cc=None, blocked=None, mark_for_review=False, mark_for_commit_queue=False): self.authenticate() log('Creating bug with title "%s"' % bug_title) if self.dryrun: log(bug_description) return self.browser.open(self.bug_server_url + "enter_bug.cgi?product=WebKit") self.browser.select_form(name="Create") component_items = self.browser.find_control('component').items component_names = map(lambda item: item.name, component_items) if not component: component = "New Bugs" if component not in component_names: component = User.prompt_with_list("Please pick a component:", component_names) self.browser["component"] = [component] if cc: self.browser["cc"] = cc if blocked: self.browser["blocked"] = unicode(blocked) self.browser["short_desc"] = bug_title self.browser["comment"] = bug_description if diff: # _fill_attachment_form expects a file-like object # Patch files are already binary, so no encoding needed. assert(isinstance(diff, str)) patch_file_object = StringIO.StringIO(diff) self._fill_attachment_form( patch_description, patch_file_object, mark_for_review=mark_for_review, mark_for_commit_queue=mark_for_commit_queue) response = self.browser.submit() bug_id = self._check_create_bug_response(response.read()) log("Bug %s created." % bug_id) log("%sshow_bug.cgi?id=%s" % (self.bug_server_url, bug_id)) return bug_id
def commit_with_message(self, message, username=None): if self.dryrun: # Return a string which looks like a commit so that things which parse this output will succeed. return "Dry run, no commit.\nCommitted revision 0." svn_commit_args = ["svn", "commit"] if not username and not self.has_authorization_for_realm(): username = User.prompt("%s login: "******"You need to specify the username on %s to perform the commit as." % self.svn_server_host) if username: svn_commit_args.extend(["--username", username]) svn_commit_args.extend(["-m", message]) # FIXME: Should this use cwd=self.checkout_root? return run_command(svn_commit_args, error_handler=commit_error_handler)
def prompt_for_bug_title_and_comment(self): bug_title = User.prompt("Bug title: ") print "Bug comment (hit ^D on blank line to end):" lines = sys.stdin.readlines() try: sys.stdin.seek(0, os.SEEK_END) except IOError: # Cygwin raises an Illegal Seek (errno 29) exception when the above # seek() call is made. Ignoring it seems to cause no harm. # FIXME: Figure out a way to get avoid the exception in the first # place. pass comment_text = "".join(lines) return (bug_title, comment_text)
def __init__(self, path): MultiCommandTool.__init__(self) self._path = path self.wakeup_event = threading.Event() self.bugs = Bugzilla() self.buildbot = BuildBot() self.executive = Executive() self._irc = None self.user = User() self._scm = None self._checkout = None self.status_server = StatusServer() self.codereview = Rietveld(self.executive)
def commit_with_message(self, message, username=None, git_commit=None, squash=None): # squash and git-commit are not used by SVN. if self.dryrun: # Return a string which looks like a commit so that things which parse this output will succeed. return "Dry run, no commit.\nCommitted revision 0." svn_commit_args = ["svn", "commit"] if not username and not self.has_authorization_for_realm(): username = User.prompt("%s login: "******"You need to specify the username on %s to perform the commit as." % self.svn_server_host) if username: svn_commit_args.extend(["--username", username]) svn_commit_args.extend(["-m", message]) # FIXME: Should this use cwd=self.checkout_root? return run_command(svn_commit_args, error_handler=commit_error_handler)
def run_prompt_test(inputs, expected_result, can_choose_multiple=False): def mock_raw_input(message): return inputs.pop(0) with OutputCapture() as captured: actual_result = User.prompt_with_list( 'title', ['foo', 'bar'], can_choose_multiple=can_choose_multiple, raw_input=mock_raw_input) self.assertEqual(captured.stdout.getvalue(), 'title\n 1. foo\n 2. bar\n') self.assertEqual(actual_result, expected_result) self.assertEqual(len(inputs), 0)
def run_prompt_test(inputs, expected_result, can_choose_multiple=False): def mock_raw_input(message): return inputs.pop(0) with OutputCapture() as captured: actual_result = User.prompt_with_multiple_lists( 'title', ['subtitle1', 'subtitle2'], [['foo', 'bar'], ['foobar', 'barbaz', 'foobaz']], can_choose_multiple=can_choose_multiple, raw_input=mock_raw_input, ) self.assertEqual( captured.stdout.getvalue(), 'title\n\nsubtitle1\n 1. foo\n 2. bar\n\nsubtitle2\n 3. foobar\n 4. barbaz\n 5. foobaz\n', ) self.assertEqual(actual_result, expected_result) self.assertEqual(len(inputs), 0)
def test_confirm(self): test_cases = ( (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, 'y')), (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'n')), (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, '')), (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'q')), (("Continue? [y/N]: ", True), (User.DEFAULT_NO, 'y')), (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'n')), (("Continue? [y/N]: ", False), (User.DEFAULT_NO, '')), (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'q')), ) for test_case in test_cases: expected, inputs = test_case def mock_raw_input(message): self.assertEqual(expected[0], message) return inputs[1] result = User().confirm(default=inputs[0], raw_input=mock_raw_input) self.assertEqual(expected[1], result)
class Credentials(object): def __init__(self, host, git_prefix=None, executive=None, cwd=os.getcwd()): self.host = host self.git_prefix = "%s." % git_prefix if git_prefix else "" self.executive = executive or Executive() self.cwd = cwd def _credentials_from_git(self): return [ Git.read_git_config(self.git_prefix + "username"), Git.read_git_config(self.git_prefix + "password") ] def _keychain_value_with_label(self, label, source_text): match = re.search("%s\"(?P<value>.+)\"" % label, source_text, re.MULTILINE) if match: return match.group('value') def _is_mac_os_x(self): return platform.mac_ver()[0] def _parse_security_tool_output(self, security_output): username = self._keychain_value_with_label("^\s*\"acct\"<blob>=", security_output) password = self._keychain_value_with_label("^password: "******"/usr/bin/security", "find-internet-password", "-g", "-s", self.host, ] if username: security_command += ["-a", username] log("Reading Keychain for %s account and password. " "Click \"Allow\" to continue..." % self.host) try: return self.executive.run_command(security_command) except ScriptError: # Failed to either find a keychain entry or somekind of OS-related # error occured (for instance, couldn't find the /usr/sbin/security # command). log("Could not find a keychain entry for %s." % self.host) return None def _credentials_from_keychain(self, username=None): if not self._is_mac_os_x(): return [username, None] security_output = self._run_security_tool(username) if security_output: return self._parse_security_tool_output(security_output) else: return [None, None] def read_credentials(self): username = None password = None try: if Git.in_working_directory(self.cwd): (username, password) = self._credentials_from_git() except OSError, e: # Catch and ignore OSError exceptions such as "no such file # or directory" (OSError errno 2), which imply that the Git # command cannot be found/is not installed. pass if not username or not password: (username, password) = self._credentials_from_keychain(username) if not username: username = User.prompt("%s login: "******"%s password for %s: " % (self.host, username)) return [username, password]
def test_warn_if_application_is_xcode(self): user = User() with OutputCapture() as captured: user._warn_if_application_is_xcode('TextMate') user._warn_if_application_is_xcode('/Applications/TextMate.app') user._warn_if_application_is_xcode('XCode') self.assertEqual(captured.stdout.getvalue(), '') with OutputCapture() as captured: user._warn_if_application_is_xcode('Xcode') user._warn_if_application_is_xcode( '/Developer/Applications/Xcode.app') self.assertEqual( captured.stdout.getvalue(), 'Instead of using Xcode.app, consider using EDITOR=\"xed --wait\".\n' * 2, )
def __init__(self, port_name=None, options=None, executive=None, user=None, filesystem=None, config=None, **kwargs): # These are default values that should be overridden in a subclasses. self._name = port_name or self.port_name # Subclasses may append a -VERSION (like mac-leopard) or other qualifiers. self._operating_system = 'mac' self._version = '' self._architecture = 'x86' self._graphics_type = 'cpu' # FIXME: Ideally we'd have a package-wide way to get a # well-formed options object that had all of the necessary # options defined on it. self.options = options or DummyOptions() self.executive = executive or Executive() self.user = user or User() self.filesystem = filesystem or system.filesystem.FileSystem() self.config = config or port_config.Config(self.executive, self.filesystem) # FIXME: Remove all of the old "protected" versions when we can. self._options = self.options self._executive = self.executive self._filesystem = self.filesystem self._user = self.user self._config = self.config self._helper = None self._http_server = None self._websocket_server = None self._http_lock = None # FIXME: Why does this live on the port object? # Python's Popen has a bug that causes any pipes opened to a # process that can't be executed to be leaked. Since this # code is specifically designed to tolerate exec failures # to gracefully handle cases where wdiff is not installed, # the bug results in a massive file descriptor leak. As a # workaround, if an exec failure is ever experienced for # wdiff, assume it's not available. This will leak one # file descriptor but that's better than leaking each time # wdiff would be run. # # http://mail.python.org/pipermail/python-list/ # 2008-August/505753.html # http://bugs.python.org/issue3210 self._wdiff_available = None # FIXME: prettypatch.py knows this path, why is it copied here? self._pretty_patch_path = self.path_from_webkit_base( "Websites", "bugs.webkit.org", "PrettyPatch", "prettify.rb") self._pretty_patch_available = None self.set_option_default('configuration', self.default_configuration()) self._test_configuration = None self._multiprocessing_is_available = (multiprocessing is not None) self._results_directory = None