Changeset 51889 in webkit
- Timestamp:
- Dec 9, 2009 12:20:57 AM (14 years ago)
- Location:
- trunk/WebKitTools
- Files:
-
- 1 deleted
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKitTools/ChangeLog
r51888 r51889 1 2009-12-09 Adam Barth <abarth@webkit.org> 2 3 Reviewed by Eric Seidel. 4 5 [bzt] Implement abstract Steps 6 https://bugs.webkit.org/show_bug.cgi?id=32212 7 8 This is a fairly disruptive change that refactors how we build 9 commands. Instead of using a landing sequence, we can now assemble a 10 sequence of steps directly. We still use the landing sequence in the 11 interim, but this will be removed soon. 12 13 * Scripts/bugzilla-tool: 14 * Scripts/modules/buildsteps.py: 15 * Scripts/modules/commands/download.py: 16 * Scripts/modules/commands/early_warning_system.py: 17 * Scripts/modules/commands/queues.py: 18 * Scripts/modules/commands/queues_unittest.py: 19 * Scripts/modules/landingsequence.py: 20 * Scripts/modules/mock_bugzillatool.py: 21 * Scripts/modules/processutils.py: Removed. 22 * Scripts/modules/scm.py: 23 * Scripts/modules/scm_unittest.py: 24 * Scripts/modules/webkitport.py: 25 1 26 2009-12-08 Eric Seidel <eric@webkit.org> 2 27 -
trunk/WebKitTools/Scripts/bugzilla-tool
r51747 r51889 41 41 from modules.commands.queues import * 42 42 from modules.commands.upload import * 43 from modules.executive import Executive 43 44 from modules.logging import log 44 45 from modules.multicommandtool import MultiCommandTool … … 52 53 self.bugs = Bugzilla() 53 54 self.buildbot = BuildBot() 55 self.executive = Executive() 54 56 self._scm = None 55 57 self._status = None -
trunk/WebKitTools/Scripts/modules/buildsteps.py
r51729 r51889 31 31 from optparse import make_option 32 32 33 from modules.comments import bug_comment_from_commit_text 33 34 from modules.logging import log, error 34 from modules.processutils import run_and_throw_if_fail35 35 from modules.webkitport import WebKitPort 36 36 37 38 class CommandOptions(object): 39 force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)") 40 clean = make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches") 41 check_builders = make_option("--ignore-builders", action="store_false", dest="check_builders", default=True, help="Don't check to see if the build.webkit.org builders are green before landing.") 42 quiet = make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output.") 43 non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.") 44 parent_command = make_option("--parent-command", action="store", dest="parent_command", default=None, help="(Internal) The command that spawned this instance.") 45 update = make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory.") 46 build = make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test.") 47 test = make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests.") 48 close_bug = make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing.") 49 port = make_option("--port", action="store", dest="port", default=None, help="Specify a port (e.g., mac, qt, gtk, ...).") 50 51 52 class AbstractStep(object): 53 def __init__(self, tool, options): 54 self._tool = tool 55 self._options = options 56 self._port = None 57 58 def _run_script(self, script_name, quiet=False, port=WebKitPort): 59 log("Running %s" % script_name) 60 self._tool.executive.run_and_throw_if_fail(port.script_path(script_name), quiet) 61 62 # FIXME: The port should live on the tool. 63 def port(self): 64 if self._port: 65 return self._port 66 self._port = WebKitPort.port(self._options.port) 67 return self._port 68 69 @classmethod 70 def options(cls): 71 return [] 72 73 def run(self, tool): 74 raise NotImplementedError, "subclasses must implement" 75 76 77 class AbstractPatchStep(AbstractStep): 78 def __init__(self, tool, options, patch): 79 AbstractStep.__init__(self, tool, options) 80 self._patch = patch 81 82 83 class PrepareChangelogStep(AbstractStep): 84 def run(self): 85 self._run_script("prepare-ChangeLog") 86 87 88 class CleanWorkingDirectoryStep(AbstractStep): 89 def __init__(self, tool, options, allow_local_commits=False): 90 AbstractStep.__init__(self, tool, options) 91 self._allow_local_commits = allow_local_commits 92 93 @classmethod 94 def options(cls): 95 return [ 96 CommandOptions.force_clean, 97 CommandOptions.clean, 98 ] 99 100 def run(self): 101 os.chdir(self._tool._scm.checkout_root) 102 if not self._allow_local_commits: 103 self._tool.scm().ensure_no_local_commits(self._options.force_clean) 104 if self._options.clean: 105 self._tool.scm().ensure_clean_working_directory(force_clean=self._options.force_clean) 106 107 108 class UpdateStep(AbstractStep): 109 @classmethod 110 def options(cls): 111 return [ 112 CommandOptions.update, 113 CommandOptions.port, 114 ] 115 116 def run(self): 117 if not self._options.update: 118 return 119 log("Updating working directory") 120 self._tool.executive.run_and_throw_if_fail(self.port().update_webkit_command()) 121 122 123 class ApplyPatchStep(AbstractPatchStep): 124 @classmethod 125 def options(cls): 126 return [ 127 CommandOptions.non_interactive, 128 ] 129 130 def run(self): 131 log("Processing patch %s from bug %s." % (self._patch["id"], self._patch["bug_id"])) 132 self._tool.scm().apply_patch(self._patch, force=self._options.non_interactive) 133 134 135 class EnsureBuildersAreGreenStep(AbstractStep): 136 @classmethod 137 def options(cls): 138 return [ 139 CommandOptions.check_builders, 140 ] 141 142 def run(self): 143 if not self._options.check_builders: 144 return 145 if not self._tool.buildbot.core_builders_are_green(): 146 error("Builders at %s are red, please do not commit. Pass --ignore-builders to bypass this check." % (self._tool.buildbot.buildbot_host)) 147 148 149 class BuildStep(AbstractStep): 150 @classmethod 151 def options(cls): 152 return [ 153 CommandOptions.build, 154 CommandOptions.quiet, 155 ] 156 157 def run(self): 158 if not self._options.build: 159 return 160 log("Building WebKit") 161 self._tool.executive.run_and_throw_if_fail(self.port().build_webkit_command(), self._options.quiet) 162 163 164 class CheckStyleStep(AbstractStep): 165 def run(self): 166 self._run_script("check-webkit-style") 167 168 169 class RunTestsStep(AbstractStep): 170 @classmethod 171 def options(cls): 172 return [ 173 CommandOptions.build, 174 CommandOptions.test, 175 CommandOptions.non_interactive, 176 CommandOptions.quiet, 177 CommandOptions.port, 178 ] 179 180 def run(self): 181 if not self._options.build: 182 return 183 if not self._options.test: 184 return 185 args = self.port().run_webkit_tests_command() 186 if self._options.non_interactive: 187 args.append("--no-launch-safari") 188 args.append("--exit-after-n-failures=1") 189 if self._options.quiet: 190 args.append("--quiet") 191 self._tool.executive.run_and_throw_if_fail(args) 192 193 194 class CommitStep(AbstractStep): 195 def run(self): 196 commit_message = self._tool.scm().commit_message_for_this_commit() 197 return self._tool.scm().commit_with_message(commit_message.message()) 198 199 200 class ClosePatchStep(AbstractPatchStep): 201 def run(self, commit_log): 202 comment_text = bug_comment_from_commit_text(self._tool.scm(), commit_log) 203 self._tool.bugs.clear_attachment_flags(self._patch["id"], comment_text) 204 205 206 class CloseBugStep(AbstractPatchStep): 207 @classmethod 208 def options(cls): 209 return [ 210 CommandOptions.close_bug, 211 ] 212 213 def run(self): 214 if not self._options.close_bug: 215 return 216 # Check to make sure there are no r? or r+ patches on the bug before closing. 217 # Assume that r- patches are just previous patches someone forgot to obsolete. 218 patches = self._tool.bugs.fetch_patches_from_bug(self._patch["bug_id"]) 219 for patch in patches: 220 review_flag = patch.get("review") 221 if review_flag == "?" or review_flag == "+": 222 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)) 223 return 224 self._tool.bugs.close_bug_as_fixed(self._patch["bug_id"], "All reviewed patches have been landed. Closing bug.") 225 226 227 # FIXME: This class is a dinosaur and should be extinct soon. 37 228 class BuildSteps: 38 229 # FIXME: The options should really live on each "Step" object. … … 40 231 def cleaning_options(): 41 232 return [ 42 make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)"),43 make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches"),233 CommandOptions.force_clean, 234 CommandOptions.clean, 44 235 ] 45 236 … … 48 239 def build_options(): 49 240 return [ 50 make_option("--ignore-builders", action="store_false", dest="check_builders", default=True, help="Don't check to see if the build.webkit.org builders are green before landing."), 51 make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output."), 52 make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible."), 53 make_option("--parent-command", action="store", dest="parent_command", default=None, help="(Internal) The command that spawned this instance."), 54 ] + WebKitPort.port_options() 241 CommandOptions.check_builders, 242 CommandOptions.quiet, 243 CommandOptions.non_interactive, 244 CommandOptions.parent_command, 245 CommandOptions.port, 246 ] 55 247 56 248 @staticmethod 57 249 def land_options(): 58 250 return [ 59 make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory."), 60 make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test."), 61 make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests."), 62 make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing."), 63 ] 64 65 def _run_script(cls, script_name, quiet=False, port=WebKitPort): 66 log("Running %s" % script_name) 67 run_and_throw_if_fail(port.script_path(script_name), quiet) 68 69 def prepare_changelog(self): 70 self.run_script("prepare-ChangeLog") 71 72 def clean_working_directory(self, scm, options, allow_local_commits=False): 73 os.chdir(scm.checkout_root) 74 if not allow_local_commits: 75 scm.ensure_no_local_commits(options.force_clean) 76 if options.clean: 77 scm.ensure_clean_working_directory(force_clean=options.force_clean) 78 79 def update(self, port=WebKitPort): 80 log("Updating working directory") 81 run_and_throw_if_fail(port.update_webkit_command()) 82 83 def run_tests(self, launch_safari, fail_fast=False, quiet=False, port=WebKitPort): 84 args = port.run_webkit_tests_command() 85 if not launch_safari: 86 args.append("--no-launch-safari") 87 if quiet: 88 args.append("--quiet") 89 if fail_fast: 90 args.append("--exit-after-n-failures=1") 91 run_and_throw_if_fail(args) 92 93 def ensure_builders_are_green(self, buildbot, options): 94 if not options.check_builders or buildbot.core_builders_are_green(): 95 return 96 error("Builders at %s are red, please do not commit. Pass --ignore-builders to bypass this check." % (buildbot.buildbot_host)) 97 98 def build_webkit(self, quiet=False, port=WebKitPort): 99 log("Building WebKit") 100 run_and_throw_if_fail(port.build_webkit_command(), quiet) 101 102 def check_style(self): 103 self._run_script("check-webkit-style") 104 251 CommandOptions.update, 252 CommandOptions.build, 253 CommandOptions.test, 254 CommandOptions.close_bug, 255 ] 256 -
trunk/WebKitTools/Scripts/modules/commands/download.py
r51888 r51889 34 34 35 35 from modules.bugzilla import parse_bug_id 36 from modules.buildsteps import BuildSteps 36 from modules.buildsteps import BuildSteps, EnsureBuildersAreGreenStep, CleanWorkingDirectoryStep, UpdateStep, CheckStyleStep, PrepareChangelogStep, CleanWorkingDirectoryStep 37 37 from modules.changelogs import ChangeLog 38 38 from modules.comments import bug_comment_from_commit_text 39 39 from modules.grammar import pluralize 40 from modules.landingsequence import LandingSequence , ConditionalLandingSequence40 from modules.landingsequence import LandingSequence 41 41 from modules.logging import error, log 42 42 from modules.multicommandtool import Command … … 44 44 45 45 46 class BuildSequence(ConditionalLandingSequence): 47 def __init__(self, options, tool): 48 ConditionalLandingSequence.__init__(self, None, options, tool) 49 46 class BuildSequence(LandingSequence): 50 47 def run(self): 51 48 self.clean() … … 64 61 65 62 def execute(self, options, args, tool): 66 sequence = BuildSequence( options, tool)63 sequence = BuildSequence(None, options, tool) 67 64 sequence.run_and_handle_errors() 68 65 … … 108 105 @staticmethod 109 106 def setup_for_patch_apply(tool, options): 110 tool.steps.clean_working_directory(tool.scm(), options, allow_local_commits=True) 111 if options.update: 112 tool.steps.update() 107 clean_step = CleanWorkingDirectoryStep(tool, options, allow_local_commits=True) 108 clean_step.run() 109 update_step = UpdateStep(tool, options) 110 update_step.run() 113 111 114 112 @staticmethod … … 125 123 126 124 127 class LandDiffSequence(ConditionalLandingSequence): 128 def __init__(self, patch, options, tool): 129 ConditionalLandingSequence.__init__(self, patch, options, tool) 130 125 class LandDiffSequence(LandingSequence): 131 126 def run(self): 132 127 self.check_builders() … … 190 185 bug_id = (args and args[0]) or parse_bug_id(tool.scm().create_patch()) 191 186 192 tool.steps.ensure_builders_are_green(tool.buildbot, options)187 EnsureBuildersAreGreenStep(tool, options).run() 193 188 194 189 os.chdir(tool.scm().checkout_root) … … 235 230 236 231 class CheckStyleSequence(LandingSequence): 237 def __init__(self, patch, options, tool):238 LandingSequence.__init__(self, patch, options, tool)239 240 232 def run(self): 241 233 self.clean() … … 246 238 def build(self): 247 239 # Instead of building, we check style. 248 self._tool.steps.check_style() 240 step = CheckStyleStep(self._tool, self._options) 241 step.run() 249 242 250 243 … … 268 261 269 262 270 class BuildAttachmentSequence(ConditionalLandingSequence): 271 def __init__(self, patch, options, tool): 272 LandingSequence.__init__(self, patch, options, tool) 273 263 class BuildAttachmentSequence(LandingSequence): 274 264 def run(self): 275 265 self.clean() … … 308 298 def _prepare_to_process(self, options, args, tool): 309 299 # Check the tree status first so we can fail early. 310 tool.steps.ensure_builders_are_green(tool.buildbot, options)300 EnsureBuildersAreGreenStep(tool, options).run() 311 301 312 302 def _process_patch(self, patch, options, args, tool): 313 sequence = ConditionalLandingSequence(patch, options, tool)303 sequence = LandingSequence(patch, options, tool) 314 304 sequence.run_and_handle_errors() 315 305 … … 359 349 # Second, make new ChangeLog entries for this rollout. 360 350 # This could move to prepare-ChangeLog by adding a --revert= option. 361 tool.steps.prepare_changelog()351 PrepareChangelogStep(tool, None).run() 362 352 for changelog_path in changelog_paths: 363 353 ChangeLog(changelog_path).update_for_revert(revision) … … 385 375 log("Failed to parse bug number from diff. No bugs will be updated/reopened after the rollout.") 386 376 387 tool.steps.clean_working_directory(tool.scm(), options)388 tool.steps.update()377 CleanWorkingDirectoryStep(tool, options).run() 378 UpdateStep(tool, options).run() 389 379 tool.scm().apply_reverse_diff(revision) 390 380 self._create_changelogs_for_revert(tool, revision) -
trunk/WebKitTools/Scripts/modules/commands/early_warning_system.py
r51888 r51889 29 29 30 30 from modules.commands.queues import AbstractReviewQueue 31 from modules. processutilsimport ScriptError31 from modules.executive import ScriptError 32 32 from modules.webkitport import WebKitPort 33 33 -
trunk/WebKitTools/Scripts/modules/commands/queues.py
r51888 r51889 34 34 from optparse import make_option 35 35 36 from modules.executive import ScriptError 36 37 from modules.grammar import pluralize 37 from modules.landingsequence import LandingSequence, ConditionalLandingSequence,LandingSequenceErrorHandler38 from modules.landingsequence import LandingSequence, LandingSequenceErrorHandler 38 39 from modules.logging import error, log 39 40 from modules.multicommandtool import Command 40 41 from modules.patchcollection import PatchCollection, PersistentPatchCollection, PersistentPatchCollectionDelegate 41 from modules.processutils import run_and_throw_if_fail, ScriptError42 42 from modules.statusbot import StatusBot 43 43 from modules.workqueue import WorkQueue, WorkQueueDelegate … … 93 93 def run_bugzilla_tool(self, args): 94 94 bugzilla_tool_args = [self.tool.path()] + map(str, args) 95 run_and_throw_if_fail(bugzilla_tool_args)95 self.tool.executive.run_and_throw_if_fail(bugzilla_tool_args) 96 96 97 97 def log_progress(self, patch_ids): -
trunk/WebKitTools/Scripts/modules/commands/queues_unittest.py
r51622 r51889 63 63 64 64 def test_run_bugzilla_tool(self): 65 self._assert_run_bugzilla_tool_output([1], " 1\n")66 self._assert_run_bugzilla_tool_output(["one", 2], " one 2\n")65 self._assert_run_bugzilla_tool_output([1], "") 66 self._assert_run_bugzilla_tool_output(["one", 2], "") -
trunk/WebKitTools/Scripts/modules/landingsequence.py
r51888 r51889 35 35 from modules.webkitport import WebKitPort 36 36 from modules.workqueue import WorkQueue 37 from modules.buildsteps import CleanWorkingDirectoryStep, UpdateStep, ApplyPatchStep, EnsureBuildersAreGreenStep, BuildStep, RunTestsStep, CommitStep, ClosePatchStep, CloseBugStep 38 37 39 38 40 class LandingSequenceErrorHandler(): … … 76 78 77 79 def clean(self): 78 self._tool.steps.clean_working_directory(self._tool.scm(), self._options) 80 step = CleanWorkingDirectoryStep(self._tool, self._options) 81 step.run() 79 82 80 83 def update(self): 81 self._tool.steps.update(port=self._port) 84 step = UpdateStep(self._tool, self._options) 85 step.run() 82 86 83 87 def apply_patch(self): 84 log("Processing patch %s from bug %s." % (self._patch["id"], self._patch["bug_id"]))85 s elf._tool.scm().apply_patch(self._patch, force=self._options.non_interactive)88 step = ApplyPatchStep(self._tool, self._options, self._patch) 89 step.run() 86 90 87 91 def check_builders(self): 88 self._tool.steps.ensure_builders_are_green(self._tool.buildbot, self._options) 92 step = EnsureBuildersAreGreenStep(self._tool, self._options) 93 step.run() 89 94 90 95 def build(self): 91 self._tool.steps.build_webkit(quiet=self._options.quiet, port=self._port) 96 step = BuildStep(self._tool, self._options) 97 step.run() 92 98 93 99 def test(self): 94 # When running non-interactively we don't want to launch Safari and we want to exit after the first failure.95 s elf._tool.steps.run_tests(launch_safari=not self._options.non_interactive, fail_fast=self._options.non_interactive, quiet=self._options.quiet, port=self._port)100 step = RunTestsStep(self._tool, self._options) 101 step.run() 96 102 97 103 def commit(self): 98 commit_message = self._tool.scm().commit_message_for_this_commit()99 return s elf._tool.scm().commit_with_message(commit_message.message())104 step = CommitStep(self._tool, self._options) 105 return step.run() 100 106 101 107 def close_patch(self, commit_log): 102 comment_text = bug_comment_from_commit_text(self._tool.scm(), commit_log)103 s elf._tool.bugs.clear_attachment_flags(self._patch["id"], comment_text)108 step = ClosePatchStep(self._tool, self._options, self._patch) 109 step.run(commit_log) 104 110 105 111 def close_bug(self): 106 # Check to make sure there are no r? or r+ patches on the bug before closing. 107 # Assume that r- patches are just previous patches someone forgot to obsolete. 108 patches = self._tool.bugs.fetch_patches_from_bug(self._patch["bug_id"]) 109 for patch in patches: 110 review_flag = patch.get("review") 111 if review_flag == "?" or review_flag == "+": 112 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)) 113 return 114 self._tool.bugs.close_bug_as_fixed(self._patch["bug_id"], "All reviewed patches have been landed. Closing bug.") 115 116 117 class ConditionalLandingSequence(LandingSequence): 118 def __init__(self, patch, options, tool): 119 LandingSequence.__init__(self, patch, options, tool) 120 121 def update(self): 122 if self._options.update: 123 LandingSequence.update(self) 124 125 def check_builders(self): 126 if self._options.build: 127 LandingSequence.check_builders(self) 128 129 def build(self): 130 if self._options.build: 131 LandingSequence.build(self) 132 133 def test(self): 134 if self._options.build and self._options.test: 135 LandingSequence.test(self) 136 137 def close_bug(self): 138 if self._options.close_bug: 139 LandingSequence.close_bug(self) 140 112 step = CloseBugStep(self._tool, self._options, self._patch) 113 step.run() -
trunk/WebKitTools/Scripts/modules/mock_bugzillatool.py
r51622 r51889 126 126 self.bugs = MockBugzilla() 127 127 self.buildbot = MockBuildBot() 128 self. steps= Mock()128 self.executive = Mock() 129 129 self._scm = MockSCM() 130 130 -
trunk/WebKitTools/Scripts/modules/scm.py
r51888 r51889 36 36 # Import WebKit-specific modules. 37 37 from modules.changelogs import ChangeLog 38 from modules.executive import run_command, ScriptError, default_error_handler, ignore_error 38 39 from modules.logging import error, log 39 from modules.processutils import run_command, ScriptError, default_error_handler, ignore_error40 40 41 41 def detect_scm_system(path): -
trunk/WebKitTools/Scripts/modules/scm_unittest.py
r51888 r51889 39 39 40 40 from datetime import date 41 from modules.executive import run_command, ignore_error, ScriptError 41 42 from modules.scm import detect_scm_system, SCM, CheckoutNeedsUpdate, commit_error_handler 42 from modules.processutils import run_command, ignore_error, ScriptError43 43 44 44 # Eventually we will want to write tests which work for both scms. (like update_webkit, changed_files, etc.) 45 45 # Perhaps through some SCMTest base-class which both SVNTest and GitTest inherit from. 46 46 47 # FIXME: This should be unified into one of the processutils.py commands!47 # FIXME: This should be unified into one of the executive.py commands! 48 48 def run_silent(args, cwd=None): 49 49 process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) -
trunk/WebKitTools/Scripts/modules/webkitport.py
r51747 r51889 38 38 def script_path(cls, script_name): 39 39 return os.path.join("WebKitTools", "Scripts", script_name) 40 41 @staticmethod42 def port_options():43 return [44 make_option("--port", action="store", dest="port", default=None, help="Specify a port (e.g., mac, qt, gtk, ...)."),45 ]46 40 47 41 @staticmethod
Note: See TracChangeset
for help on using the changeset viewer.