Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 535 lines (465 sloc) 18.8 KB
#!/usr/bin/env python
"choose build options for and push to Mozilla's try server"
import sys
import re
import inspect
# A node in the decision tree
class N: # Node
def __init__ (self, prompt, help, action):
self.prompt = prompt = help
self.action = action
# this deletes a character, then moves to the next option.
class D: # delete_command
def __init__(self, next): = next
class NoPrompt:
def __init__ (self, action):
self.action = action
finish = object()
error = object()
# Build each node with it's data
a = N ("Run everything", "Run all platforms, tests and talos, and don't ask any more questions", ' -b do -p all -u all -t all')
b_od = N ("Both optimized and debug", "All builds and tests will run both on optimized and debug builds", ' -b do')
b_o = N ("Just optimized", "Only use optimized builds, do not use debug builds", ' -b o')
b_d = N ("Just debug", "Only use debug builds, do not use optimized builds", ' -b d')
p_all = N ("All platforms", "Build on all platforms", ' -p all')
p_any = NoPrompt (" -p ")
p_linux = N ("Linux", "Build on i386 (32-bit) linux", 'linux,')
p_linux64 = N ("linux64", "Build on x86-64 (64-bit) linux", 'linux64,')
p_macosx64 = N ("macosx64", "Build on Mac OSX 10.6 (x86-64, 64-bit, part of a universal binary)", 'macosx64,')
p_win32 = N ("win32", "Build on Windows (32-bit)", 'win32,')
p_win64 = N ("win64", "Build on Windows (64-bit)", 'win64,')
p_android = N ("android", "Build on Android", 'android,')
p_android_armv6 = N ("android-armv6", "Build on Android Armv6", 'android-armv6,')
p_android_noion = N ("android-noion", "Build on Android without IonMonkey", 'android-noion,')
p_emulator = N ("emulator", "Build on the B2G emulator ICS", 'emulator,')
p_emulator_jb = N ("emulator-jb", "Build on the B2G emulator JB", 'emulator-jb,')
p_emulator_kk = N ("emulator-kk", "Build on the B2G emulator KK", 'emulator-kk,')
p_none = NoPrompt (" -p none")
u_all = N ("All Unit tests", "Run all unit tests on all chosen platforms", ' -u all')
u_any = N ("Any unit tests", "Would you like to be asked about running each set of unit tests", ' -u ')
u_reftest = N ("reftest", "Run reftests", 'reftest,')
u_reftest_ipc = N ("reftest-ipc", "Run IPC reftests", 'reftest-ipc,')
u_reftest_naccel = N ("reftest-no-accel", "Run non-accelerated reftests (linux/win7 only)", 'reftest-no-accel,')
u_crashtest = N ("crashtest", "Run crashtest tests", 'crashtest,')
u_crashtest_ipc = N ("crashtest-ipc", "Run IPC crashtests", 'crashtest-ipc,')
u_xpcshell = N ("xpcshell", "Run xpcshell tests", 'xpcshell,')
u_jsreftest = N ("jsreftest", "Run jsreftests", 'jsreftest,')
u_jetpack = N ("jetpack", "Run jetpack tests", 'jetpack,')
u_marionette = N ("marionette", "Run marionette tests", 'marionette,')
u_mozmill = N ("mozmill", "Run mozmill tests (thunderbird-only)", 'mozmill,')
u_mochitests = N ("Run all mochitests", "Run all of the mochitests", 'mochitests,')
u_mochitests_any = N ("Run any mochitests", "Run any of the mochitests", '')
u_mochitest1 = N ("mochitest-1", "Run mochitest-1", 'mochitest-1,')
u_mochitest2 = N ("mochitest-2", "Run mochitest-2", 'mochitest-2,')
u_mochitest3 = N ("mochitest-3", "Run mochitest-3", 'mochitest-3,')
u_mochitest4 = N ("mochitest-4", "Run mochitest-4", 'mochitest-4,')
u_mochitest5 = N ("mochitest-5", "Run mochitest-5", 'mochitest-5,')
u_mochitestbc = N ("mochitest-bc", "Run mochitest-browser-chrome", 'mochitest-bc,')
u_mochitesto = N ("mochitest-o", "Run mochitest-o", 'mochitest-o,')
## Android only suite names
u_mochitest6 = N ("mochitest-6", "Run mochitest-6 (android-only)", 'mochitest-6,')
u_mochitest7 = N ("mochitest-7", "Run mochitest-7 (android-only)", 'mochitest-7,')
u_mochitest8 = N ("mochitest-8", "Run mochitest-8 (android-only)", 'mochitest-8,')
u_reftest1 = N ("reftest-1", "Run reftest-1 (android-only)", 'reftest-1,')
u_reftest2 = N ("reftest-2", "Run reftest-2 (android-only)", 'reftest-2,')
u_reftest3 = N ("reftest-3", "Run reftest-3 (android-only)", 'reftest-3,')
u_reftest4 = N ("reftest-4", "Run reftest-4 (android-only)", 'reftest-4,')
u_crashtest1 = N ("crashtest-1", "Run crashtest-1 (android-only)", 'crashtest-1,')
u_crashtest2 = N ("crashtest-2", "Run crashtest-2 (android-only)", 'crashtest-2,')
u_crashtest3 = N ("crashtest-3", "Run crashtest-3 (android-only)", 'crashtest-3,')
u_jsreftest1 = N ("jsreftest-1", "Run jsreftests-1 (android-only)", 'jsreftest-1,')
u_jsreftest2 = N ("jsreftest-2", "Run jsreftests-2 (android-only)", 'jsreftest-2,')
u_jsreftest3 = N ("jsreftest-3", "Run jsreftests-3 (android-only)", 'jsreftest-3,')
u_robocop1 = N ("robocop-1", "Run robocop-1 tests (android-only)", 'robocop-1,')
u_robocop2 = N ("robocop-2", "Run robocop-2 tests (android-only)", 'robocop-2,')
u_robocop3 = N ("robocop-3", "Run robocop-3 tests (android-only)", 'robocop-3,')
u_robocop4 = N ("robocop-4", "Run robocop-4 tests (android-only)", 'robocop-4,')
## B2G only suite names
u_reftest5 = N ("reftest-5", "Run reftest-5 (B2G-only)", 'reftest-5,')
u_reftest6 = N ("reftest-6", "Run reftest-6 (B2G-only)", 'reftest-6,')
u_marionette_webapi = N ("marionette-webapi", "Run marionette-webapi (B2G-only)", 'marionette-webapi,')
u_none = NoPrompt (" -u none")
t_all = N ("All talos tests", "Run all talos tests on all chosen platforms", ' -t all')
t_any = N ("Any talos tests", "Would you like to be asked about running each set of talos tests", ' -t ')
t_tpn = N ("tpn", "Run tpn suite", 'tpn,')
t_nochromer = N ("nochromer", "Run nochromer suite", 'nochromer,')
t_other = N ("other", "Run other suite", 'other,')
t_dirtypaint = N ("dirtypaint", "Run dirtypaint suite", 'dirtypaint,')
t_svgr = N ("svgr", "Run svgr suite", 'svgr,')
t_dromaeojs = N ("dromaeojs", "Run dromaeojs suite", 'dromaeojs,')
t_xperf = N ("xperf", "Run xperf suite", 'xperf,')
t_none = NoPrompt (" -t none")
remote_talos = ','.join(['remote-ts', 'remote-tdhtml', 'remote-tsvg', 'remote-tpan',
'remote-trobopan', 'remote-trobocheck', 'remote-troboprovider',
'remote-trobocheck2', 'remote-trobocheck3', 'remote-tp4m_nochrome',])
t_all_android = N ("All android talos tests", "Run all android talos tests", remote_talos)
t_any_android = N ("Any android talos tests", "Run any android talos tests", '')
t_ts_r = N ("remote-ts", "Run Android ts suite", 'remote-ts,')
t_tdhtml_r = N ("remote-tdhtml", "Run Android tdhtml suite", 'remote-tdhtml,')
t_tsvg_r = N ("remote-tsvg", "Run Android tsvg suite", 'remote-tsvg,')
t_tpan_r = N ("remote-tpan", "Run Android tpan suite", 'remote-tpan,')
t_trobopan_r = N ("remote-trobopan", "Run Android trobopan suite", 'remote-trobopan,')
t_trobocheck_r = N ("remote-trobocheck", "Run Android trobocheck suite", 'remote-trobocheck,')
t_trobocheck2_r = N ("remote-trobocheck2", "Run Android trobocheck2 suite", 'remote-trobocheck2,')
t_trobocheck3_r = N ("remote-trobocheck3", "Run Android trobocheck3 suite", 'remote-trobocheck3,')
t_troboprovider_r = N ("remote-troboprovider", "Run Android troboprovider suite", 'remote-troboprovider,')
t_nochrome_r = N ("remote-tp4m_nochrome", "Run tp4m nochrome suite", 'remote-tp4m_nochrome,')
t_none_r = NoPrompt ("")
# Build decision tree. Each object has a y and n property, which are chosen if
# Y or N is chosen. That property is the next question.
a.y = finish
a.n = b_od
b_od.y = p_all
b_od.n = b_o
b_o.y = p_all
b_o.n = b_d
b_d.y = p_all
b_d.n = error
p_all.y = u_all
p_all.n = p_any = p_linux
p_linux.y = p_linux64
p_linux.n = p_linux64
p_linux64.y = p_macosx64
p_linux64.n = p_macosx64
p_macosx64.y = p_win32
p_macosx64.n = p_win32
p_win32.y = p_win64
p_win32.n = p_win64
p_win64.y = p_android
p_win64.n = p_android
p_android.y = p_android_armv6
p_android.n = p_android_armv6
p_android_armv6.y = p_android_noion
p_android_armv6.n = p_android_noion
p_android_noion.y = p_emulator
p_android_noion.n = p_emulator
p_emulator.y = p_emulator_jb
p_emulator.n = p_emulator_jb
p_emulator_jb.y = p_emulator_kk
p_emulator_jb.n = p_emulator_kk
p_emulator_kk.y = D(u_all)
p_emulator_kk.n = D(u_all)
u_all.y = t_all
u_all.n = u_any
u_any.y = u_reftest
u_any.n = u_none = t_all
u_reftest.y = u_reftest1
u_reftest.n = u_reftest1
u_reftest1.y = u_reftest2
u_reftest1.n = u_reftest2
u_reftest2.y = u_reftest3
u_reftest2.n = u_reftest3
u_reftest3.y = u_reftest4
u_reftest3.n = u_reftest4
u_reftest4.y = u_reftest5
u_reftest4.n = u_reftest5
u_reftest5.y = u_reftest6
u_reftest5.n = u_reftest6
u_reftest6.y = u_reftest_ipc
u_reftest6.n = u_reftest_ipc
u_reftest_ipc.y = u_reftest_naccel
u_reftest_ipc.n = u_reftest_naccel
u_reftest_naccel.y = u_crashtest
u_reftest_naccel.n = u_crashtest
u_crashtest.y = u_crashtest1
u_crashtest.n = u_crashtest1
u_crashtest1.y = u_crashtest2
u_crashtest1.n = u_crashtest2
u_crashtest2.y = u_crashtest3
u_crashtest2.n = u_crashtest3
u_crashtest3.y = u_crashtest_ipc
u_crashtest3.n = u_crashtest_ipc
u_crashtest_ipc.y = u_xpcshell
u_crashtest_ipc.n = u_xpcshell
u_xpcshell.y = u_jsreftest
u_xpcshell.n = u_jsreftest
u_jsreftest.y = u_jsreftest1
u_jsreftest.n = u_jsreftest1
u_jsreftest1.y = u_jsreftest2
u_jsreftest1.n = u_jsreftest2
u_jsreftest2.y = u_jsreftest3
u_jsreftest2.n = u_jsreftest3
u_jsreftest3.y = u_jetpack
u_jsreftest3.n = u_jetpack
u_jetpack.y = u_marionette
u_jetpack.n = u_marionette
u_marionette.y = u_marionette_webapi
u_marionette.n = u_marionette_webapi
u_marionette_webapi.y = u_mozmill
u_marionette_webapi.n = u_mozmill
u_mozmill.y = u_robocop1
u_mozmill.n = u_robocop1
u_robocop1.y = u_robocop2
u_robocop1.n = u_robocop2
u_robocop2.y = u_robocop3
u_robocop2.n = u_robocop3
u_robocop3.y = u_robocop4
u_robocop3.n = u_robocop4
u_robocop4.y = u_mochitests
u_robocop4.n = u_mochitests
u_mochitests.y = D(t_all)
u_mochitests.n = u_mochitests_any
u_mochitests_any.y = u_mochitest1
u_mochitests_any.n = D(t_all)
u_mochitest1.y = u_mochitest2
u_mochitest1.n = u_mochitest2
u_mochitest2.y = u_mochitest3
u_mochitest2.n = u_mochitest3
u_mochitest3.y = u_mochitest4
u_mochitest3.n = u_mochitest4
u_mochitest4.y = u_mochitest5
u_mochitest4.n = u_mochitest5
u_mochitest5.y = u_mochitest6
u_mochitest5.n = u_mochitest6
u_mochitest6.y = u_mochitest7
u_mochitest6.n = u_mochitest7
u_mochitest7.y = u_mochitest8
u_mochitest7.n = u_mochitest8
u_mochitest8.y = u_mochitestbc
u_mochitest8.n = u_mochitestbc
u_mochitestbc.y = u_mochitesto
u_mochitestbc.n = u_mochitesto
u_mochitesto.y = D(t_all)
u_mochitesto.n = D(t_all)
t_all.y = finish
t_all.n = t_any
t_any.y = t_tpn
t_any.n = t_none = finish
t_tpn.y = t_nochromer
t_tpn.n = t_nochromer
t_nochromer.y = t_other
t_nochromer.n = t_other
t_other.y = t_dirtypaint
t_other.n = t_dirtypaint
t_dirtypaint.y = t_svgr
t_dirtypaint.n = t_svgr
t_svgr.y = t_dromaeojs
t_svgr.n = t_dromaeojs
t_dromaeojs.y = t_xperf
t_dromaeojs.n = t_xperf
t_xperf.y = t_all_android
t_xperf.n = t_all_android
t_all_android.y = finish
t_all_android.n = t_any_android
t_any_android.y = t_ts_r
t_any_android.n = t_none_r = finish
t_ts_r.y = t_tdhtml_r
t_ts_r.n = t_tdhtml_r
t_tdhtml_r.y = t_tsvg_r
t_tdhtml_r.n = t_tsvg_r
t_tsvg_r.y = t_tpan_r
t_tsvg_r.n = t_tpan_r
t_tpan_r.y = t_trobopan_r
t_tpan_r.n = t_trobopan_r
t_trobopan_r.y = t_trobocheck_r
t_trobopan_r.n = t_trobocheck_r
t_trobocheck_r.y = t_trobocheck2_r
t_trobocheck_r.n = t_trobocheck2_r
t_trobocheck2_r.y = t_trobocheck3_r
t_trobocheck2_r.n = t_trobocheck3_r
t_trobocheck3_r.y = t_troboprovider_r
t_trobocheck3_r.n = t_troboprovider_r
t_troboprovider_r.y = t_nochrome_r
t_troboprovider_r.n = t_nochrome_r
t_nochrome_r.y = D(finish)
t_nochrome_r.n = D(finish)
# The actual algorithm is simple
def run_algorithm(state):
node = a
string = 'try:'
while node != finish:
if node == error:
state.say("Invalid selection")
elif isinstance(node, D):
string = string[:-1] # remove last character
node =
elif isinstance(node, NoPrompt):
string += node.action
node =
elif isinstance(node, N):
state.say(node.prompt + '?')
input = state.prompt()
if input in 'Yy':
string += node.action
node = node.y
elif input in 'Nn':
node = node.n
elif input == '?':
state.say("Invalid option, please try again")
# Hard to test these above, so use string search for weird flag combination
platforms = 'linux,linux64,macosx64,win32,win64,android,android-armv6,android-noion,emulator,panda,unagi'.split(',')
unittests = 'reftest,reftest-ipc,reftest-no-accel,crashtest,crashtest-ipc,xpcshell,jsreftest,jetpack,marionette,mozmill,mochitests,reftest-1,reftest-2,reftest-3,reftest-4,jsreftest-1,jsreftest-2,jsreftest-3,crashtest-2,crashtest-3,mochitest-6,mochitest-7,mochitest-8,mochitest-bc,robocop-1,robocop-2,robocop-3,robocop-4,reftest-1,reftest-2,reftest-3,reftest-4,reftest-5,reftest-6,marionette-webapi'.split(',')
taloss = 'nochrome,dromaeo,a11y,svg,chrome,tp,dirty,scroll,cold,v8'.split(',')
if string.find ('-p') + string.find('-a') == -2:
state.say("no platform selected")
state.say ("Invalid selection: " + string)
if string.find ('-b') + string.find('-a') == -2:
state.say ("no build selected")
state.say ("Invalid selection: " + string)
if string.find ('-p') != -1 and \
string.find ('-p all') == -1 and \
(sum([string.find(x) for x in platforms]) == -1*len(platforms)):
state.say ("no platforms selected, despite asking for some")
state.say ("Invalid selection: " + string)
if string.find ('-u') != -1 and \
string.find ('-u all') == -1 and \
string.find ('-u none') == -1 and \
(sum([string.find(x) for x in unittests]) == -1*len(unittests)):
state.say ("no unit tests selected, despite asking for some")
state.say ("Invalid selection: " + string)
if string.find ('-t') != -1 and \
string.find ('-t all') == -1 and \
string.find ('-t none') == -1 and \
(sum([string.find(x) for x in taloss]) == -1*len(taloss)):
state.say ("no talos tests selected, despite asking for some")
state.say ("Invalid selection: " + string)
return string
# Wrapper function for ui.promptchoice because newer versions take two
# parameters with a unified message and choices string and older versions take
# three parameters with separate strings.
def promptchoice(ui, prompt, choices):
num_args = len(inspect.getargspec(ui.promptchoice)[0])
if num_args == 4:
return ui.promptchoice(prompt, choices, default=0)
elif num_args == 3:
prompt_list = [prompt]
unifed_prompt = ' $$ '.join(prompt_list)
return ui.promptchoice(unifed_prompt, default=0)
if __name__ == '__main__':
class Test_interface:
# print isn't a function
def say(self, string):
print string
def prompt(self):
return raw_input('[Ynh?]\n')
def exit(self, code):
print run_algorithm(Test_interface())
from mercurial import ui
from mercurial import extensions
from mercurial.i18n import _
from mercurial import commands
from mercurial import util
class HG_interface:
def __init__ (self, ui, repo):
self.ui = ui
self.repo = repo
def say(self, string):
self.ui.write(string + '\n')
def prompt(self):
index = promptchoice(self.ui, '[Ynh?]', ['&Yes', '&no', '&h', '&?'])
return 'Ynh?'[index]
def exit(self, code):
def suggest_results_bug(ui, repo):
ui.write('Leave a comment in a bug on completion?\n')
if promptchoice(ui, '[Yn]', ['&Yes', '&no']):
return None
# Derive a suggested bug number in which to leave results (regex stolen from
bug_re = re.compile(r'''# bug followed by any sequence of numbers, or
# a standalone sequence of numbers
bug |
b= |
# a sequence of 5+ numbers preceded by whitespace
(?=\b\#?\d{5,}) |
# numbers at the very beginning
)''', re.I | re.X)
rev =[-1].name
match =, repo[rev].description())
s = 'Bug number'
suggested = None
if match:
suggested =
s += ' (%s)' % suggested
ui.write('%s:\n' % s)
bugnum = None
while not bugnum:
numstr = ui.prompt('', str(suggested))
return int(numstr)
ui.write('Invalid bug number\n')
def run_mercurial_command(ui, repo, *args, **opts):
"""Build a TryChooser string by asking a few questions.
For all questions, choosing Y means adding something to the TryChooser string. Choosing ? shows context-sensitive help."""
mq = extensions.find('mq')
except KeyError:
ui.warn(_("Warning: mq extension hasn't been found, this is going to print the syntax only.\n"))
string = run_algorithm(HG_interface(ui, repo))
ui.write(string + '\n')
if repo[None].dirty():
raise util.Abort(_("local changes found, refresh first"))
if opts.get('message'):
msg = opts.get('message')
if msg.find('try:') == -1:
msg = 'try: ' + msg
msg = run_algorithm(HG_interface(ui, repo))
bugnum = suggest_results_bug(ui, repo)
if bugnum:
msg += ' --post-to-bugzilla Bug %s' % bugnum
ui.write(_("The following try message is going to be used:\n%s\n") % msg)
ui.write(_("Creates the trychooser mq entry...\n")), repo, 'trychooser', message=msg)
if opts.get('dry_run'):
ui.write(_("Pretending to push to try server...\n"))
ui.write(_("Push to try server...\n"))
commands.push(ui, repo, "ssh://", force=True,
ui.write("ERROR: failed to push to try server!\n");
# In Mercurial 2.1 phases support was added, and until Mozilla updates to
# this version and configures the try repository to be non-publishing, we
# need to reset the pushed patches to be editable again.
commands.phase(ui, repo, 'mq()', draft=True, public=False, secret=False, force=True, rev="")
except AttributeError:
pass # we're running a old Mercurial version, don't bother.
mq.pop(ui, repo)
mq.delete(ui, repo, 'trychooser')
# Mercurial interface
cmdtable = {
('n', 'dry-run', False, _('do not perform actions, just print output')),
('m', 'message', '', _('use text as try message'))
_('hg trychooser [-m TEXT]')
# TODO: add an MQ option to qrefresh