def _run_security_tool(self, username=None): security_command = ["/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) return self.executive.run_command(security_command)
def _fetch_list_of_patches_to_process(self, options, args, tool): all_patches = [] for bug_id in args: patches = tool.bugs.fetch_reviewed_patches_from_bug(bug_id) log("%s found on bug %s." % (pluralize("reviewed patch", len(patches)), bug_id)) all_patches += patches return all_patches
def begin_work_queue(self): log("CAUTION: %s will discard all local changes in \"%s\"" % (self.name, self.tool.scm().checkout_root)) if self.options.confirm: response = raw_input("Are you sure? Type \"yes\" to continue: ") if (response != "yes"): error("User declined.") log("Running WebKit %s." % self.name)
def ensure_clean_working_directory(self, force): if not force and not self.working_directory_is_clean(): print self.run_command(self.status_command(), error_handler=ignore_error) raise ScriptError(message="Working directory has modifications, pass --force-clean or --no-clean to continue.") log("Cleaning working directory") self.clean_working_directory()
def create_bug_with_patch(self, bug_title, bug_description, component, patch_file_object, patch_description, cc, mark_for_review=False): self.authenticate() log('Creating bug with patch description "%s"' % patch_description) 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 or component not in component_names: component = self.prompt_for_component(component_names) self.browser['component'] = [component] self.browser['cc'] = cc self.browser['short_desc'] = bug_title if bug_description: log(bug_description) self.browser['comment'] = bug_description self.browser['description'] = patch_description self.browser['ispatch'] = ("1",) self.browser['flag_type-1'] = ('?',) if mark_for_review else ('X',) self.browser.add_file(patch_file_object, "text/plain", "%s.patch" % timestamp(), 'data') response = self.browser.submit() bug_id = self._check_create_bug_response(response.read()) log("Bug %s created." % bug_id) log(self.bug_server_url + "show_bug.cgi?id=" + bug_id) return bug_id
def ensure_clean_working_directory(self, force): if not force and not self.working_directory_is_clean(): print self.run_command(self.status_command(), raise_on_failure=False) error("Working directory has modifications, pass --force-clean or --no-clean to continue.") log("Cleaning working directory") self.clean_working_directory()
def authenticate(self): if self.authenticated: return if self.dryrun: log("Skipping log in for dry run...") self.authenticated = True return (username, password) = read_credentials() log("Logging in as %s..." % username) self.browser.open(self.bug_server_url + "index.cgi?GoAheadAndLogIn=1") self.browser.select_form(name="login") self.browser['Bugzilla_login'] = username self.browser['Bugzilla_password'] = password response = self.browser.submit() match = re.search("<title>(.+?)</title>", response.read()) # If the resulting page has a title, and it contains the word "invalid" assume it's the login failure page. if match and re.search("Invalid", match.group(1), re.IGNORECASE): # FIXME: We could add the ability to try again on failure. raise ScriptError("Bugzilla login failed: %s" % match.group(1)) self.authenticated = True
def ensure_clean_working_directory(self, force_clean): if not force_clean and not self.working_directory_is_clean(): print run_command(self.status_command(), error_handler=Executive.ignore_error) raise ScriptError(message="Working directory has modifications, pass --force-clean or --no-clean to continue.") log("Cleaning working directory") self.clean_working_directory()
def get_vkapi(login, pas, token=None): ''' Авторизируется по токену или логину и паролю ''' user_agent = random.choice( open('settings/user_agents.txt').read().splitlines()) if token != '': log('main Авторизируемся по токену') vka = vkauth(login, pas, token=token, captcha_handler=None, user_agent=user_agent) vkapi = vka.auth() else: log('main Авторизируемся') vka = vkauth(login, pas, captcha_handler=None, user_agent=user_agent) vkapi = vka.auth() if type(vkapi).__name__ != 'bool': pass else: logpr('Ошибка авторизации.') return vkapi
def credentials_from_keychain(username=None): if not is_mac_os_x(): return [username, None] command = "/usr/bin/security %s -g -s %s" % ("find-internet-password", Bugzilla.bug_server_host) if username: command += " -a %s" % username log('Reading Keychain for %s account and password. Click "Allow" to continue...' % Bugzilla.bug_server_host) keychain_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) value = keychain_process.communicate()[0] exit_code = keychain_process.wait() if exit_code: return [username, None] match = re.search('^\s*"acct"<blob>="(?P<username>.+)"', value, re.MULTILINE) if match: username = match.group('username') password = None match = re.search('^password: "******"', value, re.MULTILINE) if match: password = match.group('password') return [username, password]
def create_bug_with_patch(self, bug_title, bug_description, component, patch_file_object, patch_description, cc, mark_for_review=False): self.authenticate() log('Creating bug with patch description "%s"' % patch_description) 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 or component not in component_names: component = self.prompt_for_component(component_names) self.browser['component'] = [component] if cc: self.browser['cc'] = cc self.browser['short_desc'] = bug_title if bug_description: log(bug_description) self.browser['comment'] = bug_description self.browser['description'] = patch_description self.browser['ispatch'] = ("1",) self.browser['flag_type-1'] = ('?',) if mark_for_review else ('X',) self.browser.add_file(patch_file_object, "text/plain", "%s.patch" % timestamp(), 'data') 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 parse(data): if data.find("PRIVMSG") != -1: from_nick = data.split("PRIVMSG ", 1)[0].split("!")[0][1:] # who sent the PRIVMSG to_nick = data.split("PRIVMSG ", 1)[1].split(" :", 1)[0] # where did they send it text = data.split("PRIVMSG ", 1)[1].split(" :", 1)[1].strip() # what did it contain if source_checking_enabled and (from_nick not in allowed_sources and from_nick != admin): log("[>] Not from an allowed source. (source checking enabled)" ) return (False, "", "" ) # break and return nothing if message is invalid if to_nick == channel: source = "public" return_to = channel elif to_nick != channel: source = "private" return_to = from_nick log("[>] Content: %s, Source: %s, Return To: %s" % (text, source, return_to)) return (text, source, return_to) elif data.find("PING :", 0, 6) != -1: # was it just a ping? from_srv = data.split("PING :")[1].strip() # the source of the PING return ("PING", from_srv, from_srv) return (False, "", "") # break and return nothing if message is invalid
def authenticate(self): if self.authenticated: return if self.dryrun: log("Skipping log in for dry run...") self.authenticated = True return (username, password) = read_credentials() log("Logging in as %s..." % username) self.browser.open(self.bug_server_url + "index.cgi?GoAheadAndLogIn=1") self.browser.select_form(name="login") self.browser["Bugzilla_login"] = username self.browser["Bugzilla_password"] = password response = self.browser.submit() match = re.search("<title>(.+?)</title>", response.read()) # If the resulting page has a title, and it contains the word "invalid" assume it's the login failure page. if match and re.search("Invalid", match.group(1), re.IGNORECASE): # FIXME: We could add the ability to try again on failure. error("Bugzilla login failed: %s" % match.group(1)) self.authenticated = True
def run(self): self._begin_logging() self._delegate.begin_work_queue() while (self._delegate.should_continue_work_queue()): try: self._ensure_work_log_closed() work_item = self._delegate.next_work_item() if not work_item: self._sleep("No work item.") continue if not self._delegate.should_proceed_with_work_item(work_item): self._sleep("Not proceeding with work item.") continue # FIXME: Work logs should not depend on bug_id specificaly. # This looks fixed, no? self._open_work_log(work_item) try: self._delegate.process_work_item(work_item) except ScriptError, e: # Use a special exit code to indicate that the error was already # handled in the child process and we should just keep looping. if e.exit_code == self.handled_error_code: continue message = "Unexpected failure when landing patch! Please file a bug against bugzilla-tool.\n%s" % e.message_with_output() self._delegate.handle_unexpected_error(work_item, message) except KeyboardInterrupt, e: log("\nUser terminated queue.") return 1 except Exception, e: traceback.print_exc() # Don't try tell the status bot, in case telling it causes an exception. self._sleep("Exception while preparing queue: %s." % e)
def fetch_attachments_from_bug(self, bug_id): bug_url = self.bug_url_for_bug_id(bug_id, xml=True) log("Fetching: " + bug_url) page = urllib2.urlopen(bug_url) soup = BeautifulSoup(page) attachments = [] for element in soup.findAll('attachment'): attachment = {} attachment['bug_id'] = bug_id attachment['is_obsolete'] = (element.has_key('isobsolete') and element['isobsolete'] == "1") attachment['is_patch'] = (element.has_key('ispatch') and element['ispatch'] == "1") attachment['id'] = str(element.find('attachid').string) attachment['url'] = self.attachment_url_for_id(attachment['id']) attachment['name'] = unicode(element.find('desc').string) attachment['type'] = str(element.find('type').string) review_flag = element.find('flag', attrs={"name": "review"}) if review_flag and review_flag['status'] == '+': reviewer_email = review_flag['setter'] # We could lookup the full email address instead once we update full_name_from_bugzilla_name bugzilla_name = reviewer_email.split('@')[0] attachment['reviewer'] = self.full_name_from_bugzilla_name( bugzilla_name) attachments.append(attachment) return attachments
def _run_security_tool(self, username=None): security_command = ["/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) return self.executive.run_command(security_command)
def fetch_attachments_from_bug(self, bug_id): bug_url = self.bug_url_for_bug_id(bug_id, xml=True) log("Fetching: " + bug_url) page = urllib2.urlopen(bug_url) soup = BeautifulSoup(page) attachments = [] for element in soup.findAll("attachment"): attachment = {} attachment["bug_id"] = bug_id attachment["is_obsolete"] = element.has_key("isobsolete") and element["isobsolete"] == "1" attachment["is_patch"] = element.has_key("ispatch") and element["ispatch"] == "1" attachment["id"] = str(element.find("attachid").string) attachment["url"] = self.attachment_url_for_id(attachment["id"]) attachment["name"] = unicode(element.find("desc").string) attachment["type"] = str(element.find("type").string) review_flag = element.find("flag", attrs={"name": "review"}) if review_flag and review_flag["status"] == "+": reviewer_email = review_flag["setter"] # We could lookup the full email address instead once we update full_name_from_bugzilla_name bugzilla_name = reviewer_email.split("@")[0] attachment["reviewer"] = self.full_name_from_bugzilla_name(bugzilla_name) attachments.append(attachment) return attachments
def prompt_for_component(self, components): log("Please pick a component:") i = 0 for name in components: i += 1 log("%2d. %s" % (i, name)) result = int(raw_input("Enter a number: ")) - 1 return components[result]
def check_arguments_and_execute(self, options, args, tool=None): if len(args) < len(self.required_arguments): log("%s required, %s provided. Provided: %s Required: %s\nSee '%s help %s' for usage." % (pluralize("argument", len(self.required_arguments)), pluralize("argument", len(args)), "'%s'" % " ".join(args), " ".join(self.required_arguments), tool.name(), self.name)) return 1 return self.execute(options, args, tool) or 0
def _guess_reviewer_from_bug(self, bug_id): patches = self._tool.bugs.fetch_reviewed_patches_from_bug(bug_id) if len(patches) != 1: log("%s on bug %s, cannot infer reviewer." % (pluralize("reviewed patch", len(patches)), bug_id)) return None patch = patches[0] reviewer = patch["reviewer"] log("Guessing \"%s\" as reviewer from attachment %s on bug %s." % (reviewer, patch["id"], bug_id)) return reviewer
def execute(self, options, args, tool): self._prepare_to_process(options, args, tool) patches = self._fetch_list_of_patches_to_process(options, args, tool) # It's nice to print out total statistics. bugs_to_patches = self._collect_patches_by_bug(patches) log("Processing %s from %s." % (pluralize("patch", len(patches)), pluralize("bug", len(bugs_to_patches)))) for patch in patches: self._process_patch(patch, options, args, tool)
def run(self, state): if not self._options.obsolete_patches: return bug_id = state["bug_id"] patches = self._tool.bugs.fetch_patches_from_bug(bug_id) if not patches: return log("Obsoleting %s on bug %s" % (pluralize("old patch", len(patches)), bug_id)) for patch in patches: self._tool.bugs.obsolete_attachment(patch["id"])
def apply_reverse_diff(self, revision): # '-c -revision' applies the inverse diff of 'revision' svn_merge_args = [ 'svn', 'merge', '--non-interactive', '-c', '-%s' % revision, self._repository_url() ] log("WARNING: svn merge has been known to take more than 10 minutes to complete. It is recommended you use git for rollouts." ) log("Running '%s'" % " ".join(svn_merge_args)) self.run_command(svn_merge_args)
def _needs_commit_queue(patch): commit_queue_flag = patch.get("commit-queue") if (commit_queue_flag and commit_queue_flag == '+'): # If it's already cq+, ignore the patch. log("%s already has cq=%s" % (patch["id"], commit_queue_flag)) return False # We only need to worry about patches from contributers who are not yet committers. committer_record = CommitterList().committer_by_email(patch["attacher_email"]) if committer_record: log("%s committer = %s" % (patch["id"], committer_record)) return not committer_record
def add_cc_to_bug(self, bug_id, email_address_list): self.authenticate() log("Adding %s to the CC list for bug %s" % (email_address_list, bug_id)) if self.dryrun: return self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser["newcc"] = ", ".join(email_address_list) self.browser.submit()
def check_arguments_and_execute(self, options, args, tool=None): if len(args) < len(self.required_arguments): log("%s required, %s provided. Provided: %s Required: %s\nSee '%s help %s' for usage." % ( pluralize("argument", len(self.required_arguments)), pluralize("argument", len(args)), "'%s'" % " ".join(args), " ".join(self.required_arguments), tool.name(), self.name)) return 1 return self.execute(options, args, tool) or 0
def execute(self, options, args, tool): self._prepare_to_process(options, args, tool) patches = self._fetch_list_of_patches_to_process(options, args, tool) # It's nice to print out total statistics. bugs_to_patches = self._collect_patches_by_bug(patches) log("Processing %s from %s." % (pluralize( "patch", len(patches)), pluralize("bug", len(bugs_to_patches)))) for patch in patches: self._process_patch(patch, options, args, tool)
def run_and_handle_errors(self, tool, options, state=None): if not state: state = {} try: self._run(tool, options, state) except CheckoutNeedsUpdate, e: log("Commit failed because the checkout is out of date. Please update and try again.") log( "You can pass --no-build to skip building/testing after update if you believe the new commits did not affect the results." ) QueueEngine.exit_after_handled_error(e)
def run_and_handle_errors(self, tool, options, state=None): if not state: state = {} try: self._run(tool, options, state) except CheckoutNeedsUpdate, e: log("Commit failed because the checkout is out of date. Please update and try again." ) log("You can pass --no-build to skip building/testing after update if you believe the new commits did not affect the results." ) QueueEngine.exit_after_handled_error(e)
def post_comment_to_bug(self, bug_id, comment_text): self.authenticate() log("Adding comment to bug %s" % bug_id) if self.dryrun: log(comment_text) return self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser['comment'] = comment_text self.browser.submit()
def fetch_attachments_from_bug(self, bug_id): bug_url = self.bug_url_for_bug_id(bug_id, xml=True) log("Fetching: %s" % bug_url) page = urllib2.urlopen(bug_url) soup = BeautifulSoup(page) attachments = [] for element in soup.findAll('attachment'): attachment = self._parse_attachment_element(element, bug_id) attachments.append(attachment) return attachments
def fetch_attachments_from_bug(self, bug_id): bug_url = self.bug_url_for_bug_id(bug_id, xml=True) log("Fetching: " + bug_url) page = urllib2.urlopen(bug_url) soup = BeautifulSoup(page) attachments = [] for element in soup.findAll('attachment'): attachment = self._parse_attachment_element(element, bug_id) attachments.append(attachment) return attachments
def post_comment_to_bug(self, bug_id, comment_text): self.authenticate() log("Adding comment to bug %s" % bug_id) if self.dryrun: log(comment_text) return self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser["comment"] = comment_text self.browser.submit()
def run(self, state): if not self._options.close_bug: return # Check to make sure there are no r? or r+ patches on the bug before closing. # Assume that r- patches are just previous patches someone forgot to obsolete. patches = self._tool.bugs.fetch_patches_from_bug(state["patch"]["bug_id"]) for patch in patches: review_flag = patch.get("review") if review_flag == "?" or review_flag == "+": log("Not closing bug %s as attachment %s has review=%s. Assuming there are more patches to land from this bug." % (patch["bug_id"], patch["id"], review_flag)) return self._tool.bugs.close_bug_as_fixed(state["patch"]["bug_id"], "All reviewed patches have been landed. Closing bug.")
def reopen_bug(self, bug_id, comment_text): self.authenticate() log("Re-opening bug %s" % bug_id) log(comment_text) # Bugzilla requires a comment when re-opening a bug, so we know it will never be None. if self.dryrun: return self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser["bug_status"] = ["REOPENED"] self.browser["comment"] = comment_text self.browser.submit()
def reopen_bug(self, bug_id, comment_text): self.authenticate() log("Re-opening bug %s" % bug_id) log(comment_text) # Bugzilla requires a comment when re-opening a bug, so we know it will never be None. if self.dryrun: return self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser['bug_status'] = ['REOPENED'] self.browser['comment'] = comment_text self.browser.submit()
def _needs_commit_queue(patch): commit_queue_flag = patch.get("commit-queue") if (commit_queue_flag and commit_queue_flag == '+'): # If it's already cq+, ignore the patch. log("%s already has cq=%s" % (patch["id"], commit_queue_flag)) return False # We only need to worry about patches from contributers who are not yet committers. committer_record = CommitterList().committer_by_email( patch["attacher_email"]) if committer_record: log("%s committer = %s" % (patch["id"], committer_record)) return not committer_record
def execute(self, options, args, tool): bug_id = options.bug_id svn_revision = args and args[0] if svn_revision: if re.match("^r[0-9]+$", svn_revision, re.IGNORECASE): svn_revision = svn_revision[1:] if not re.match("^[0-9]+$", svn_revision): error("Invalid svn revision: '%s'" % svn_revision) needs_prompt = False if not bug_id or not svn_revision: needs_prompt = True (bug_id, svn_revision) = self._determine_bug_id_and_svn_revision(tool, bug_id, svn_revision) log("Bug: <%s> %s" % (tool.bugs.short_bug_url_for_bug_id(bug_id), tool.bugs.fetch_bug_dictionary(bug_id)["title"])) log("Revision: %s" % svn_revision) if options.open_bug: self._open_bug_in_web_browser(tool, bug_id) if needs_prompt: self._prompt_user_for_correctness(bug_id, svn_revision) bug_comment = bug_comment_from_svn_revision(svn_revision) if options.comment: bug_comment = "%s\n\n%s" % (options.comment, bug_comment) if options.update_only: log("Adding comment to Bug %s." % bug_id) tool.bugs.post_comment_to_bug(bug_id, bug_comment) else: log("Adding comment to Bug %s and marking as Resolved/Fixed." % bug_id) tool.bugs.close_bug_as_fixed(bug_id, bug_comment)
def post_comment_to_bug(self, bug_id, comment_text, cc=None): self.authenticate() log("Adding comment to bug %s" % bug_id) if self.dryrun: log(comment_text) return self.browser.open(self.bug_url_for_bug_id(bug_id)) self.browser.select_form(name="changeform") self.browser["comment"] = comment_text if cc: self.browser["newcc"] = ", ".join(cc) self.browser.submit()
def execute(self, options, args, tool): revision = args[0] bug_id = self._parse_bug_id_from_revision_diff(tool, revision) if options.complete_rollout: if bug_id: log("Will re-open bug %s after rollout." % bug_id) else: log("Failed to parse bug number from diff. No bugs will be updated/reopened after the rollout.") state = { "revision": revision, "bug_id": bug_id, } self._sequence.run_and_handle_errors(tool, options, state)
def _set_flag_on_attachment(self, attachment_id, flag_name, flag_value, comment_text, additional_comment_text): self.authenticate() if additional_comment_text: comment_text += "\n\n%s" % additional_comment_text log(comment_text) if self.dryrun: return self.browser.open(self.attachment_url_for_id(attachment_id, 'edit')) self.browser.select_form(nr=1) self.browser.set_value(comment_text, name='comment', nr=0) self._find_select_element_for_flag(flag_name).value = (flag_value,) self.browser.submit()
def execute(self, options, args, tool): revision = args[0] bug_id = self._parse_bug_id_from_revision_diff(tool, revision) if options.complete_rollout: if bug_id: log("Will re-open bug %s after rollout." % bug_id) else: log("Failed to parse bug number from diff. No bugs will be updated/reopened after the rollout." ) state = { "revision": revision, "bug_id": bug_id, } self._sequence.run_and_handle_errors(tool, options, state)
def _set_flag_on_attachment(self, attachment_id, flag_name, flag_value, comment_text, additional_comment_text): self.authenticate() if additional_comment_text: comment_text += "\n\n%s" % additional_comment_text log(comment_text) if self.dryrun: return self.browser.open(self.attachment_url_for_id(attachment_id, "edit")) self.browser.select_form(nr=1) self.browser.set_value(comment_text, name="comment", nr=0) self._find_select_element_for_flag(flag_name).value = (flag_value,) self.browser.submit()
def run(self, state): if not self._options.close_bug: return # Check to make sure there are no r? or r+ patches on the bug before closing. # Assume that r- patches are just previous patches someone forgot to obsolete. patches = self._tool.bugs.fetch_patches_from_bug( state["patch"]["bug_id"]) for patch in patches: review_flag = patch.get("review") if review_flag == "?" or review_flag == "+": log("Not closing bug %s as attachment %s has review=%s. Assuming there are more patches to land from this bug." % (patch["bug_id"], patch["id"], review_flag)) return self._tool.bugs.close_bug_as_fixed( state["patch"]["bug_id"], "All reviewed patches have been landed. Closing bug.")
def run(self, state): bug_id = state["patch"]["bug_id"] reviewer = self._options.reviewer if not reviewer: if not bug_id: log("No bug id provided and --reviewer= not provided. Not updating ChangeLogs with reviewer.") return reviewer = self._guess_reviewer_from_bug(bug_id) if not reviewer: log("Failed to guess reviewer from bug %s and --reviewer= not provided. Not updating ChangeLogs with reviewer." % bug_id) return os.chdir(self._tool.scm().checkout_root) for changelog_path in self._tool.scm().modified_changelogs(): ChangeLog(changelog_path).set_reviewer(reviewer)
def clear_attachment_review_flag(self, attachment_id, additional_comment_text=None): self.authenticate() comment_text = "Clearing review flag on attachment: %s" % attachment_id if additional_comment_text: comment_text += "\n\n" + additional_comment_text log(comment_text) if self.dryrun: return self.browser.open(self.attachment_url_for_id(attachment_id, 'edit')) self.browser.select_form(nr=1) self.browser.set_value(comment_text, name='comment', nr=0) self.browser.find_control(type='select', nr=0).value = ("X",) self.browser.submit()
def _validate_setter_email(self, patch, result_key, lookup_function, rejection_function, reject_invalid_patches): setter_email = patch.get(result_key + '_email') if not setter_email: return None committer = lookup_function(setter_email) if committer: patch[result_key] = committer.full_name return patch[result_key] if reject_invalid_patches: committer_list = "WebKitTools/Scripts/modules/committers.py" failure_message = "%s does not have %s permissions according to %s." % (setter_email, result_key, self._view_source_link(committer_list)) rejection_function(patch['id'], failure_message) else: log("Warning, attachment %s on bug %s has invalid %s (%s)", (patch['id'], patch['bug_id'], result_key, setter_email)) return None
def commit_message_for_this_commit(self): changelog_paths = self.modified_changelogs() if not len(changelog_paths): raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n" "All changes require a ChangeLog. See:\n" "http://webkit.org/coding/contributing.html") changelog_messages = [] for changelog_path in changelog_paths: log("Parsing ChangeLog: %s" % changelog_path) changelog_entry = ChangeLog(changelog_path).latest_entry() if not changelog_entry: raise ScriptError(message="Failed to parse ChangeLog: " + os.path.abspath(changelog_path)) changelog_messages.append(changelog_entry) # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does. return CommitMessage("".join(changelog_messages).splitlines())
def clear_attachment_flags(self, attachment_id, additional_comment_text=None): self.authenticate() comment_text = "Clearing flags on attachment: %s" % attachment_id if additional_comment_text: comment_text += "\n\n%s" % additional_comment_text log(comment_text) if self.dryrun: return self.browser.open(self.attachment_url_for_id(attachment_id, "edit")) self.browser.select_form(nr=1) self.browser.set_value(comment_text, name="comment", nr=0) self._find_select_element_for_flag("review").value = ("X",) self._find_select_element_for_flag("commit-queue").value = ("X",) self.browser.submit()
def run_shell(cmd, timeout=60, verbose=False): # run a shell command and return the output, verbose enables live command output via yield retcode = None signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(timeout) try: p = Popen([cmd],shell=True, stdout=PIPE, stderr=STDOUT, executable='/bin/bash') log("[$] Started.") continue_running = True except Exception as e: yield("Failed: %s" % e) continue_running = False signal.alarm(0) while continue_running: signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(1) try: line = p.stdout.readline() if verbose: yield(line) else: yield(line.strip()) except: pass signal.alarm(0) signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(1) try: log('[#] Checking for input.') data = irc.recv(4096) except Exception as e: data = "" retcode = p.poll() #returns None while subprocess is running signal.alarm(0) if (data.find('!cancel') != -1): log('[+] Recieved:') log('[>] ', data.strip()) retcode = "Cancelled live output reading. You have to kill the process manually." yield("[X]: %s" % retcode) continue_running = False break elif retcode is not None: signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(1) try: line = p.stdout.read() except: retcode = "Too much output, read timed out. Process is still running in background." signal.alarm(0) if verbose and len(line) > 0: yield(line) if retcode != 0: yield("[X]: %s" % retcode) elif retcode == 0 and verbose: yield("[√]") continue_running = False break