garden-o-matic should support gardening a single port and specifying how to deal...
authordpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Oct 2012 19:34:11 +0000 (19:34 +0000)
committerdpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Oct 2012 19:34:11 +0000 (19:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=100563

Reviewed by Ojan Vafai.

This patch starts the process of making garden-o-matic more useful for
bringing up a single new port in two ways. The goal is to fully
obsolete webkit-patch rebaseline-server.

First, it adds support for the --platform arguments to garden-o-matic
(so that the UI will default to the right cluster of bots), and if the platform arg
specifies a single bot, filters the results down to just that bot.

Second, it adds support for --move-overwritten-baselines and changes
the implementation of the move_overwritten_baselines setting in builders.py
so that it is only used if this flag is provided.

Future patches will make it possible to use local copies of the build
results (rather than going to the bots) and other optimizations to make
it faster to review lots of changes on a single bot.

* BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/garden-o-matic.html:
* BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/config.js:
(.):
* Scripts/webkitpy/layout_tests/port/builders.py:
* Scripts/webkitpy/tool/commands/gardenomatic.py:
(GardenOMatic):
(GardenOMatic.execute):
* Scripts/webkitpy/tool/commands/rebaseline.py:
(AbstractRebaseliningCommand):
(AbstractRebaseliningCommand.__init__):
(RebaselineTest):
(OptimizeBaselines):
(AnalyzeBaselines):
(AbstractParallelRebaselineCommand):
(AbstractParallelRebaselineCommand._rebaseline_commands):
(AbstractParallelRebaselineCommand._rebaseline):
(Rebaseline.__init__):
* Scripts/webkitpy/tool/servers/gardeningserver.py:
(GardeningHTTPServer.url):
(GardeningHTTPRequestHandler.rebaselineall):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@133060 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/garden-o-matic.html
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/run-unittests.html
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/builders.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/config.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/garden-o-matic.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/model.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/summary-mock.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/ui/failures.js
Tools/ChangeLog
Tools/Scripts/webkitpy/layout_tests/port/builders.py
Tools/Scripts/webkitpy/tool/commands/gardenomatic.py
Tools/Scripts/webkitpy/tool/commands/rebaseline.py
Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
Tools/Scripts/webkitpy/tool/servers/gardeningserver.py

index 904e5ed..2c28fbe 100644 (file)
@@ -50,8 +50,8 @@ James, a web developer from Birmingham, UK.
 <body>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
 <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js"></script>
-<script src="scripts/config.js"></script>
 <script src="scripts/base.js"></script>
+<script src="scripts/config.js"></script>
 <script src="scripts/net.js"></script>
 <script src="scripts/Trac.js"></script>
 <script src="scripts/Bugzilla.js"></script>
index ce2e6cd..2ce6e71 100644 (file)
@@ -39,8 +39,8 @@ THE POSSIBILITY OF SUCH DAMAGE.
 
 <link rel="stylesheet" href="styles/results.css">
 
-<script src="scripts/config.js"></script>
 <script src="scripts/base.js"></script>
+<script src="scripts/config.js"></script>
 <script src="scripts/base_unittests.js"></script>
 <script src="scripts/net.js"></script>
 <script src="scripts/net_unittests.js"></script>
index b65895a..7f5b36c 100644 (file)
@@ -97,7 +97,7 @@ function fetchMostRecentBuildInfoByBuilder(platform, callback)
         var builderNames = Object.keys(builderStatus);
         var requestTracker = new base.RequestTracker(builderNames.length, callback, [buildInfoByBuilder]);
         builderNames.forEach(function(builderName) {
-            if (!config.kPlatforms[config.currentPlatform].builderApplies(builderName)) {
+            if (!config.builderApplies(builderName)) {
                 requestTracker.requestComplete();
                 return;
             }
index 92fa03a..1f80744 100644 (file)
@@ -52,7 +52,7 @@ config.kPlatforms = {
         resultsDirectoryForBuildNumber: function(buildNumber, revision) {
             return encodeURIComponent('r' + revision + ' (' + buildNumber + ')');
         },
-        builderApplies: function(builderName) {
+        _builderApplies: function(builderName) {
             return builderName.indexOf('Apple') != -1;
         },
     },
@@ -84,7 +84,7 @@ config.kPlatforms = {
         resultsDirectoryForBuildNumber: function(buildNumber, revision) {
             return buildNumber;
         },
-        builderApplies: function(builderName) {
+        _builderApplies: function(builderName) {
             // FIXME: Should garden-o-matic show these? I can imagine showing the deps bots being useful at least so
             // that the gardener only need to look at garden-o-matic and never at the waterfall. Not really sure who
             // watches the GPU bots.
@@ -115,7 +115,7 @@ config.kPlatforms = {
         resultsDirectoryForBuildNumber: function(buildNumber, revision) {
             return encodeURIComponent('r' + revision + ' (' + buildNumber + ')');
         },
-        builderApplies: function(builderName) {
+        _builderApplies: function(builderName) {
             return builderName.indexOf('GTK') != -1;
         },
     },
@@ -136,7 +136,7 @@ config.kPlatforms = {
         resultsDirectoryForBuildNumber: function(buildNumber, revision) {
             return encodeURIComponent('r' + revision + ' (' + buildNumber + ')');
         },
-        builderApplies: function(builderName) {
+        _builderApplies: function(builderName) {
             return builderName.indexOf('Qt') != -1;
         },
     },
@@ -159,10 +159,29 @@ config.kRelativeTimeUpdateFrequency = 1000 * 60;
 
 config.kExperimentalFeatures = window.location.search.search('enableExperiments=1') != -1;
 
-config.currentPlatform = 'chromium';
+config.currentPlatform = base.getURLParameter('platform') || 'chromium';
 
-config.setPlatform = function(platform)
-{
+// FIXME: We should add a way to restrict the results to a subset of the builders
+// (or maybe just a single builder) in the UI as well as via an URL parameter.
+config.currentBuilder = base.getURLParameter('builder');
+
+config.currentBuilders = function() {
+    var current_builders = {};
+    if (config.currentBuilder) {
+        current_builders[config.currentBuilder] = config.kPlatforms[config.currentPlatform].builders[config.currentBuilder];
+        return current_builders;
+    } else {
+        return config.kPlatforms[config.currentPlatform].builders;
+    }
+};
+
+config.builderApplies = function(builderName) {
+    if (config.currentBuilder)
+        return builderName == config.currentBuilder;
+    return config.kPlatforms[config.currentPlatform]._builderApplies(builderName);
+};
+
+config.setPlatform = function(platform) {
     if (!this.kPlatforms[platform]) {
         window.console.log(platform + ' is not a recognized platform');
         return;
index dab2b80..ebd4d5d 100644 (file)
@@ -77,7 +77,7 @@ function update()
             updatePartyTime();
             g_unexpectedFailuresController.purge();
 
-            Object.keys(config.kPlatforms[config.currentPlatform].builders).forEach(function(builderName) {
+            Object.keys(config.currentBuilders()).forEach(function(builderName) {
                 if (!model.state.resultsByBuilder[builderName])
                     g_info.add(new ui.notifications.Info('Could not find test results for ' + builderName + ' in the last ' + config.kBuildNumberLimit + ' runs.'));            
             });
index 476e94e..3c3f852 100644 (file)
@@ -158,7 +158,7 @@ model.latestRevisionWithNoBuildersInFlight = function()
 
 model.updateResultsByBuilder = function(callback)
 {
-    var platformBuilders = config.kPlatforms[config.currentPlatform].builders;
+    var platformBuilders = config.currentBuilders();
     results.fetchResultsByBuilder(Object.keys(platformBuilders), function(resultsByBuilder) {
         model.state.resultsByBuilder = resultsByBuilder;
         callback();
index 5e732cf..eb3c2a2 100644 (file)
@@ -96,7 +96,7 @@ var testNames = new Cycler([
     'tables/mozilla/bugs/bug52505.html'
 ]);
 
-var builders = new Cycler(Object.keys(config.kPlatforms[config.currentPlatform].builders), 3);
+var builders = new Cycler(Object.keys(config.currentBuilders()), 3);
 
 var expectations = new Cycler([
     'TEXT',
index 77ecda3..b4948b2 100644 (file)
@@ -33,7 +33,7 @@ var kBuildingResult = 'BUILDING';
 ui.failures.Builder = base.extends('a', {
     init: function(builderName, failures)
     {
-        var platformBuilders = config.kPlatforms[config.currentPlatform].builders;
+        var platformBuilders = config.currentBuilders();
         var configuration = platformBuilders[builderName];
         if (configuration) {
             if (configuration.version)
index ead52df..8e47c1d 100644 (file)
@@ -1,5 +1,49 @@
 2012-10-31  Dirk Pranke  <dpranke@chromium.org>
 
+        garden-o-matic should support gardening a single port and specifying how to deal with overwritten baselines
+        https://bugs.webkit.org/show_bug.cgi?id=100563
+
+        Reviewed by Ojan Vafai.
+
+        This patch starts the process of making garden-o-matic more useful for
+        bringing up a single new port in two ways. The goal is to fully
+        obsolete webkit-patch rebaseline-server.
+        
+        First, it adds support for the --platform arguments to garden-o-matic
+        (so that the UI will default to the right cluster of bots), and if the platform arg
+        specifies a single bot, filters the results down to just that bot.
+
+        Second, it adds support for --move-overwritten-baselines and changes
+        the implementation of the move_overwritten_baselines setting in builders.py
+        so that it is only used if this flag is provided.
+
+        Future patches will make it possible to use local copies of the build
+        results (rather than going to the bots) and other optimizations to make
+        it faster to review lots of changes on a single bot.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/garden-o-matic.html:
+        * BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/config.js:
+        (.):
+        * Scripts/webkitpy/layout_tests/port/builders.py:
+        * Scripts/webkitpy/tool/commands/gardenomatic.py:
+        (GardenOMatic):
+        (GardenOMatic.execute):
+        * Scripts/webkitpy/tool/commands/rebaseline.py:
+        (AbstractRebaseliningCommand):
+        (AbstractRebaseliningCommand.__init__):
+        (RebaselineTest):
+        (OptimizeBaselines):
+        (AnalyzeBaselines):
+        (AbstractParallelRebaselineCommand):
+        (AbstractParallelRebaselineCommand._rebaseline_commands):
+        (AbstractParallelRebaselineCommand._rebaseline):
+        (Rebaseline.__init__):
+        * Scripts/webkitpy/tool/servers/gardeningserver.py:
+        (GardeningHTTPServer.url):
+        (GardeningHTTPRequestHandler.rebaselineall):
+
+2012-10-31  Dirk Pranke  <dpranke@chromium.org>
+
         test-webkitpy: fix running modules and classes on the command line
         https://bugs.webkit.org/show_bug.cgi?id=100787
 
index c2ab8d2..155ac89 100644 (file)
@@ -58,7 +58,8 @@ _exact_matches = {
     "WebKit Mac10.6 (dbg)": {"port_name": "chromium-mac-snowleopard", "specifiers": set(["snowleopard", "debug"])},
     "WebKit Mac10.7": {"port_name": "chromium-mac-lion", "specifiers": set(["lion", "release"])},
     "WebKit Mac10.7 (dbg)": {"port_name": "chromium-mac-lion", "specifiers": set(["lion", "debug"])},
-    "WebKit Mac10.8": {"port_name": "chromium-mac-mountainlion", "specifiers": set(["mountainlion", "release"])},
+    "WebKit Mac10.8": {"port_name": "chromium-mac-mountainlion", "specifiers": set(["mountainlion", "release"]),
+                       "move_overwritten_baselines_to": ["chromium-mac-lion"]},
 
     # These builders are on build.webkit.org.
     "Apple MountainLion Release WK1 (Tests)": {"port_name": "mac-mountainlion", "specifiers": set(["mountainlion"]), "rebaseline_override_dir": "mac"},
index 66b9fae..24d30a7 100644 (file)
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.layout_tests.port import builders
+from webkitpy.tool.commands.rebaseline import AbstractRebaseliningCommand
 from webkitpy.tool.servers.gardeningserver import GardeningHTTPServer
 
 
-class GardenOMatic(AbstractDeclarativeCommand):
+class GardenOMatic(AbstractRebaseliningCommand):
     name = "garden-o-matic"
-    help_text = "Experimental command for gardening the WebKit tree."
+    help_text = "Command for gardening the WebKit tree."
+
+    def __init__(self):
+        return super(AbstractRebaseliningCommand, self).__init__(options=(self.platform_options + [
+            self.move_overwritten_baselines_option,
+            self.no_optimize_option,
+            ]))
 
     def execute(self, options, args, tool):
         print "This command runs a local HTTP server that changes your working copy"
         print "based on the actions you take in the web-based UI."
 
+        args = {}
+        if options.platform:
+            # FIXME: This assumes that the port implementation (chromium-, gtk-, etc.) is the first part of options.platform.
+            args['platform'] = options.platform.split('-')[0]
+            builder = builders.builder_name_for_port_name(options.platform)
+            if builder:
+                args['builder'] = builder
+
         httpd = GardeningHTTPServer(httpd_port=8127, config={'tool': tool, 'options': options})
-        self._tool.user.open_url(httpd.url())
+        self._tool.user.open_url(httpd.url(args))
 
         print "Local HTTP server started."
         httpd.serve_forever()
index b129a48..a1d4bae 100644 (file)
@@ -60,10 +60,15 @@ def _baseline_name(fs, test_name, suffix):
 
 
 class AbstractRebaseliningCommand(AbstractDeclarativeCommand):
+    move_overwritten_baselines_option = optparse.make_option("--move-overwritten-baselines", action="store_true", default=False,
+        help="Move overwritten baselines elsewhere in the baseline path. This is for bringing up new ports.")
+
     no_optimize_option = optparse.make_option('--no-optimize', dest='optimize', action='store_false', default=True,
         help=('Do not optimize/de-dup the expectations after rebaselining (default is to de-dup automatically). '
               'You can use "webkit-patch optimize-baselines" to optimize separately.'))
 
+    platform_options = factory.platform_options()
+
     suffixes_option = optparse.make_option("--suffixes", default=','.join(BASELINE_SUFFIX_LIST), action="store",
         help="Comma-separated-list of file types to rebaseline")
 
@@ -269,7 +274,7 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand):
                 builders_to_fallback_paths[builder] = fallback_path
         return builders_to_fallback_paths.keys()
 
-    def _rebaseline_commands(self, test_list, verbose=False):
+    def _rebaseline_commands(self, test_list, move_overwritten_baselines=False, verbose=False):
 
         path_to_webkit_patch = self._tool.path()
         cwd = self._tool.scm().checkout_root
@@ -278,9 +283,10 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand):
             for builder in self._builders_to_fetch_from(test_list[test]):
                 suffixes = ','.join(test_list[test][builder])
                 cmd_line = [path_to_webkit_patch, 'rebaseline-test-internal', '--suffixes', suffixes, '--builder', builder, '--test', test]
-                move_overwritten_baselines_to = builders.move_overwritten_baselines_to(builder)
-                for platform in move_overwritten_baselines_to:
-                    cmd_line.extend(['--move-overwritten-baselines-to', platform])
+                if move_overwritten_baselines:
+                    move_overwritten_baselines_to = builders.move_overwritten_baselines_to(builder)
+                    for platform in move_overwritten_baselines_to:
+                        cmd_line.extend(['--move-overwritten-baselines-to', platform])
                 if verbose:
                     cmd_line.append('--verbose')
                 commands.append(tuple([cmd_line, cwd]))
@@ -310,6 +316,7 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand):
             all_suffixes = set()
             for builder in self._builders_to_fetch_from(test_list[test]):
                 all_suffixes.update(test_list[test][builder])
+            # FIXME: We should propagate the platform options as well.
             self._run_webkit_patch(['optimize-baselines', '--suffixes', ','.join(all_suffixes), test], verbose)
 
     def _rebaseline(self, options, test_list):
@@ -318,7 +325,7 @@ class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand):
             for builder, suffixes in sorted(builders.items()):
                 _log.debug("  %s: %s" % (builder, ",".join(suffixes)))
 
-        commands = self._rebaseline_commands(test_list, options.verbose)
+        commands = self._rebaseline_commands(test_list, options.move_overwritten_baselines, options.verbose)
         command_results = self._tool.executive.run_in_parallel(commands)
 
         log_output = '\n'.join(result[2] for result in command_results).replace('\n\n', '\n')
@@ -338,8 +345,11 @@ class RebaselineJson(AbstractParallelRebaselineCommand):
     name = "rebaseline-json"
     help_text = "Rebaseline based off JSON passed to stdin. Intended to only be called from other scripts."
 
-    def __init__(self):
-        return super(RebaselineJson, self).__init__(options=[self.no_optimize_option])
+    def __init__(self,):
+        return super(RebaselineJson, self).__init__(options=[
+            self.move_overwritten_baselines_option,
+            self.no_optimize_option,
+            ])
 
     def execute(self, options, args, tool):
         self._rebaseline(options, json.loads(sys.stdin.read()))
@@ -350,7 +360,11 @@ class RebaselineExpectations(AbstractParallelRebaselineCommand):
     help_text = "Rebaselines the tests indicated in TestExpectations."
 
     def __init__(self):
-        return super(RebaselineExpectations, self).__init__(options=[self.no_optimize_option])
+        # FIXME: We should also support platform_options here so that we only look at some TestExpectations files instead of all of them.
+        return super(RebaselineExpectations, self).__init__(options=[
+            self.move_overwritten_baselines_option,
+            self.no_optimize_option,
+            ])
 
     def _update_expectations_files(self, port_name):
         port = self._tool.port_factory.get(port_name)
@@ -403,6 +417,7 @@ class Rebaseline(AbstractParallelRebaselineCommand):
 
     def __init__(self):
         super(Rebaseline, self).__init__(options=[
+            self.move_overwritten_baselines_option,
             self.no_optimize_option,
             # FIXME: should we support the platform options in addition to (or instead of) --builders?
             self.suffixes_option,
index 94c2f20..d0a1f36 100644 (file)
@@ -214,8 +214,9 @@ class TestRebaselineJson(_BaseTestCase):
         self.tool.executive = MockExecutive2()
         self.old_exact_matches = builders._exact_matches
         builders._exact_matches = {
-            "MOCK builder": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
-            "MOCK builder (Debug)": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier", "debug"])},
+            "MOCK builder": {"port_name": "test-mac-snowleopard", "specifiers": set(["mock-specifier"]),
+                             "move_overwritten_baselines_to": ["test-mac-leopard"]},
+            "MOCK builder (Debug)": {"port_name": "test-mac-snowleopard", "specifiers": set(["mock-specifier", "debug"])},
         }
 
     def tearDown(self):
@@ -223,7 +224,7 @@ class TestRebaselineJson(_BaseTestCase):
         super(TestRebaselineJson, self).tearDown()
 
     def test_rebaseline_all(self):
-        options = MockOptions(optimize=True, verbose=True)
+        options = MockOptions(optimize=True, verbose=True, move_overwritten_baselines=False)
         self.command._rebaseline(options,  {"user-scripts/another-test.html": {"MOCK builder": ["txt", "png"]}})
 
         # Note that we have one run_in_parallel() call followed by a run_command()
@@ -232,7 +233,7 @@ class TestRebaselineJson(_BaseTestCase):
              ['echo', '--verbose', 'optimize-baselines', '--suffixes', 'txt,png', 'user-scripts/another-test.html']])
 
     def test_rebaseline_debug(self):
-        options = MockOptions(optimize=True, verbose=True)
+        options = MockOptions(optimize=True, verbose=True, move_overwritten_baselines=False)
         self.command._rebaseline(options,  {"user-scripts/another-test.html": {"MOCK builder (Debug)": ["txt", "png"]}})
 
         # Note that we have one run_in_parallel() call followed by a run_command()
@@ -240,6 +241,23 @@ class TestRebaselineJson(_BaseTestCase):
             [[['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder (Debug)', '--test', 'user-scripts/another-test.html', '--verbose']],
              ['echo', '--verbose', 'optimize-baselines', '--suffixes', 'txt,png', 'user-scripts/another-test.html']])
 
+    def test_move_overwritten(self):
+        options = MockOptions(optimize=True, verbose=True, move_overwritten_baselines=True)
+        self.command._rebaseline(options,  {"user-scripts/another-test.html": {"MOCK builder": ["txt", "png"]}})
+
+        # Note that we have one run_in_parallel() call followed by a run_command()
+        self.assertEquals(self.tool.executive.calls,
+            [[['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'user-scripts/another-test.html', '--move-overwritten-baselines-to', 'test-mac-leopard', '--verbose']],
+             ['echo', '--verbose', 'optimize-baselines', '--suffixes', 'txt,png', 'user-scripts/another-test.html']])
+
+    def test_no_optimize(self):
+        options = MockOptions(optimize=False, verbose=True, move_overwritten_baselines=False)
+        self.command._rebaseline(options,  {"user-scripts/another-test.html": {"MOCK builder (Debug)": ["txt", "png"]}})
+
+        # Note that we have only one run_in_parallel() call
+        self.assertEquals(self.tool.executive.calls,
+            [[['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder (Debug)', '--test', 'user-scripts/another-test.html', '--verbose']]])
+
 
 class TestRebaseline(_BaseTestCase):
     # This command shares most of its logic with RebaselineJson, so these tests just test what is different.
@@ -292,7 +310,7 @@ class TestRebaselineExpectations(_BaseTestCase):
         self.tool.executive = MockExecutive2()
 
         self.command._tests_to_rebaseline = lambda port: {'userscripts/another-test.html': set(['txt']), 'userscripts/images.svg': set(['png'])}
-        self.command.execute(MockOptions(optimize=False, verbose=False), [], self.tool)
+        self.command.execute(MockOptions(optimize=False, verbose=False, move_overwritten_baselines=False), [], self.tool)
 
         # FIXME: change this to use the test- ports.
         calls = filter(lambda x: x != ['qmake', '-v'], self.tool.executive.calls)
index de699cf..ec07893 100644 (file)
@@ -27,6 +27,7 @@ import logging
 import json
 import os
 import sys
+import urllib
 
 from webkitpy.common.memoized import memoized
 from webkitpy.tool.servers.reflectionhandler import ReflectionHandler
@@ -58,8 +59,10 @@ class GardeningHTTPServer(BaseHTTPServer.HTTPServer):
         self.options = config['options']
         BaseHTTPServer.HTTPServer.__init__(self, (server_name, httpd_port), GardeningHTTPRequestHandler)
 
-    def url(self):
-        return 'file://' + os.path.join(GardeningHTTPRequestHandler.STATIC_FILE_DIRECTORY, 'garden-o-matic.html')
+    def url(self, args=None):
+        # We can't use urllib.encode() here because that encodes spaces as plus signs and the buildbots don't decode those properly.
+        arg_string = ('?' + '&'.join("%s=%s" % (key, urllib.quote(value)) for (key, value) in args.items())) if args else ''
+        return 'file://' + os.path.join(GardeningHTTPRequestHandler.STATIC_FILE_DIRECTORY, 'garden-o-matic.html' + arg_string)
 
 
 class GardeningHTTPRequestHandler(ReflectionHandler):
@@ -106,6 +109,10 @@ class GardeningHTTPRequestHandler(ReflectionHandler):
 
     def rebaselineall(self):
         command = ['rebaseline-json']
+        if self.server.options.move_overwritten_baselines:
+            command.append('--move-overwritten-baselines')
+        if not self.server.options.optimize:
+            command.append('--no-optimize')
         if self.server.options.verbose:
             command.append('--verbose')
         json_input = self.read_entity_body()