Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 0cf8366333
Fetching contributors…

Cannot retrieve contributors at this time

executable file 300 lines (260 sloc) 11.0 kb
#!/usr/bin/env python
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
# The Original Code is Mozilla Corporation Code.
# The Initial Developer of the Original Code is
# Heather Arthur
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
# Contributor(s): Heather Arthur <>
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
# ***** END LICENSE BLOCK *****
import os
import datetime
import httplib2
import re
import sys
import platform
import subprocess
from optparse import OptionParser
from ConfigParser import ConfigParser
from BeautifulSoup import BeautifulSoup
from mozprofile import FirefoxProfile
from mozprofile import ThunderbirdProfile
from mozrunner import FirefoxProfile
from mozrunner import ThunderbirdProfile
from mozrunner import Runner
from mozInstall import MozInstaller
from mozInstall import rmdirRecursive
from utils import strsplit, download_url, get_date, get_platform
class Nightly(object):
def __init__(self, repo_name=None):
if platform['name'] == "Windows":
if platform['bits'] == '64':
print "No nightly builds available for 64 bit Windows"
self.buildRegex = ".*"
self.processName = + ".exe"
self.binary = "moznightlyapp/" + + "/" + + ".exe"
elif platform['name'] == "Linux":
self.processName = + "-bin"
self.binary = "moznightlyapp/" + + "/" +
if platform['bits'] == '64':
self.buildRegex = ".*linux-x86_64.tar.bz2"
self.buildRegex = ".*linux-i686.tar.bz2"
elif platform['name'] == "Mac":
self.buildRegex = ".*mac.*\.dmg"
self.processName = + "-bin"
self.binary = "moznightlyapp/" + + "-bin"
self.repo_name = repo_name
self._monthlinks = {}
self.lastdest = None
def __del__(self):
# cleanup
if self.lastdest:
def download(self,, dest=None):
url = self.getBuildUrl(date)
if url:
if not dest:
dest = os.path.basename(url)
print "\nDownloading nightly from " + str(date) + "\n"
if self.lastdest:
download_url(url, dest)
self.dest = self.lastdest = dest
return True
return False
def install(self):
subprocess._cleanup = lambda : None # mikeal's fix for subprocess threading bug
MozInstaller(src=self.dest, dest="moznightlyapp", dest_app="")
return True
def urlLinks(url):
res = [] # do not return a generator but an array, so we can store it for later use
h = httplib2.Http();
resp, content = h.request(url, "GET")
if resp.status != 200:
return res
soup = BeautifulSoup(content)
for link in soup.findAll('a'):
return res
def getBuildUrl(self, date):
url = "" + self.appName + "/nightly/"
year = str(date.year)
month = self.formatDatePart(date.month)
day = self.formatDatePart(
repo_name = self.repo_name or self.getRepoName(date)
url += year + "/" + month + "/"
linkRegex = '^' + year + '-' + month + '-' + day + '-' + '[\d-]+' + repo_name + '/$'
cachekey = year + '-' + month
if cachekey in self._monthlinks:
monthlinks = self._monthlinks[cachekey]
monthlinks = self.urlLinks(url)
self._monthlinks[cachekey] = monthlinks
# first parse monthly list to get correct directory
for dirlink in monthlinks:
dirhref = dirlink.get("href")
if re.match(linkRegex, dirhref):
# now parse the page for the correct build url
for link in self.urlLinks(url + dirhref):
href = link.get("href")
if re.match(self.buildRegex, href):
return url + dirhref + href
return False
def formatDatePart(self, part):
if part < 10:
part = "0" + str(part)
return str(part)
def getAppInfo(self):
parser = ConfigParser()
ini_file = os.path.join(os.path.dirname(self.binary), "application.ini")
changeset = parser.get('App', 'SourceStamp')
repo = parser.get('App', 'SourceRepository')
return (repo, changeset)
return ("", "")
def start(self, profile, addons, cmdargs):
if profile:
profile = self.profileClass(profile=profile, addons=addons)
elif len(addons):
profile = self.profileClass(addons=addons)
profile = self.profileClass()
self.runner = Runner(binary=self.binary, cmdargs=cmdargs, profile=profile)
self.runner.names = [self.processName]
return True
def stop(self):
class ThunderbirdNightly(Nightly):
appName = 'thunderbird'
name = 'thunderbird'
profileClass = ThunderbirdProfile
def getRepoName(self, date):
# sneaking this in here
if get_platform()['name'] == "Windows" and date <, 03, 18):
# no .zip package for Windows, can't use the installer
print "Can't run Windows builds before 2010-03-18"
if date <, 7, 26):
return "trunk"
elif date <, 1, 9):
return "comm-central"
elif date <, 8, 21):
return "comm-central-trunk"
return "comm-central"
class FirefoxNightly(Nightly):
appName = 'firefox'
name = 'firefox'
profileClass = FirefoxProfile
def getRepoName(self, date):
if date <, 6, 17):
return "trunk"
return "mozilla-central"
class FennecNightly(Nightly):
appName = 'mobile'
name = 'fennec'
profileClass = FirefoxProfile
def __init__(self, repo_name=None):
Nightly.__init__(self, repo_name)
self.buildRegex = 'fennec-.*\.apk'
self.processName = 'org.mozilla.fennec'
self.binary = 'org.mozilla.fennec/.App'
def getRepoName(self, date):
return "mozilla-central-android"
def install(self):
subprocess.check_call(["adb", "uninstall", "org.mozilla.fennec"])
subprocess.check_call(["adb", "install", self.dest])
return True
def start(self, profile, addons, cmdargs):
subprocess.check_call(["adb", "shell", "am start -n %s" % self.binary])
return True
def stop(self):
# TODO: kill fennec (don't really care though since uninstalling it kills it)
# PID = $(adb shell ps | grep org.mozilla.fennec | awk '{ print $2 }')
# adb shell run-as org.mozilla.fennec kill $PID
return True
class NightlyRunner(object):
def __init__(self, addons=None, appname="firefox", repo_name=None,
profile=None, cmdargs=[]):
if appname.lower() == 'thunderbird': = ThunderbirdNightly(repo_name=repo_name)
elif appname.lower() == 'fennec': = FennecNightly(repo_name=repo_name)
else: = FirefoxNightly(repo_name=repo_name)
self.addons = addons
self.profile = profile
self.cmdargs = cmdargs
def install(self,
if not
print "could not find nightly from " + str(date)
return False # download failed
print "Starting nightly\n"
def start(self,
if not self.install(date):
return False
if not, self.addons, self.cmdargs):
return False
return True
def stop(self):
def getAppInfo(self):
def cli():
parser = OptionParser()
parser.add_option("-d", "--date", dest="date", help="date of the nightly",
metavar="YYYY-MM-DD", default=str(
parser.add_option("-a", "--addons", dest="addons", help="list of addons to install",
metavar="PATH1,PATH2", default="")
parser.add_option("-p", "--profile", dest="profile", help="path to profile to user", metavar="PATH")
parser.add_option("-n", "--app", dest="app", help="application name (firefox, thunderbird, or fennec)",
metavar="[firefox|thunderbird|fennec]", default="firefox")
parser.add_option("-r", "--repo", dest="repo_name", help="repository name on",
metavar="[tracemonkey|mozilla-1.9.2]", default=None)
(options, args) = parser.parse_args()
runner = NightlyRunner(, addons=strsplit(options.addons, ","),
profile=options.profile, repo_name=options.repo_name)
if __name__ == "__main__":
Jump to Line
Something went wrong with that request. Please try again.