blob: ae4e32a3212fca2ce767d2b2cbff20082300045c [file] [log] [blame]
#!/usr/bin/env python
import logging
import os
from os import path
from traceback import format_exc, print_exc
import site
import sys
from distutils.version import LooseVersion
site.addsitedir(path.join(path.dirname(__file__), "../../lib/python"))
site.addsitedir(path.join(path.dirname(__file__), "../../lib/python/vendor"))
from balrog.submitter.cli import ReleaseSubmitterV3
from build.checksums import parseChecksumsFile
from build.l10n import repackLocale, l10nRepackPrep
from build.paths import get_repo_dirname
import build.misc
from build.upload import postUploadCmdPrefix
from release.download import downloadReleaseBuilds, downloadUpdateIgnore404
from release.info import readReleaseConfig, readConfig, fileInfo
from release.l10n import getReleaseLocalesForChunk
from util.hg import mercurial, update, make_hg_url
from util.retry import retry
from release.info import getBuildID
logging.basicConfig(
stream=sys.stdout, level=logging.INFO, format="%(message)s")
log = logging.getLogger(__name__)
HG = "hg.mozilla.org"
DEFAULT_BUILDBOT_CONFIGS_REPO = make_hg_url(HG, "build/buildbot-configs")
class RepackError(Exception):
pass
def createRepacks(sourceRepo, revision, l10nRepoDir, l10nBaseRepo,
mozconfigPath, srcMozconfigPath, objdir, makeDirs, appName,
locales, product, version, buildNumber,
stageServer, stageUsername, stageSshKey,
compareLocalesRepo, merge, platform, brand, appVersion,
generatePartials=False, partialUpdates=None,
usePymake=False, tooltoolManifest=None,
tooltool_script=None, tooltool_urls=None,
balrog_submitter=None, balrog_hash="sha512",
mozillaDir=None, mozillaSrcDir=None):
buildid = retry(getBuildID, args=(platform, product, version,
buildNumber, 'candidates', stageServer))
log.info('Got buildid: %s' % buildid)
sourceRepoName = path.split(sourceRepo)[-1]
absObjdir = path.abspath(path.join(sourceRepoName, objdir))
localeSrcDir = path.join(absObjdir, appName, "locales")
# Even on Windows we need to use "/" as a separator for this because
# compare-locales doesn"t work any other way
l10nIni = "/".join([sourceRepoName, appName, "locales", "l10n.ini"])
env = {
"MOZ_OBJDIR": objdir,
"MOZ_MAKE_COMPLETE_MAR": "1",
"UPLOAD_HOST": stageServer,
"UPLOAD_USER": stageUsername,
"UPLOAD_SSH_KEY": stageSshKey,
"UPLOAD_TO_TEMP": "1",
"MOZ_PKG_PRETTYNAMES": "1",
"MOZILLA_REV": os.getenv('MOZILLA_REV', ''),
"COMM_REV": os.getenv('COMM_REV', ''),
"LD_LIBRARY_PATH": os.getenv("LD_LIBRARY_PATH", ""),
"MBSDIFF_HOOK": os.getenv("MBSDIFF_HOOK", ""),
}
if appVersion is None or version != appVersion:
env["MOZ_PKG_VERSION"] = version
signed = False
if os.environ.get('MOZ_SIGN_CMD'):
env['MOZ_SIGN_CMD'] = os.environ['MOZ_SIGN_CMD']
signed = True
env['POST_UPLOAD_CMD'] = postUploadCmdPrefix(
to_candidates=True,
product=product,
version=version,
buildNumber=buildNumber,
signed=signed,
)
if usePymake:
env['USE_PYMAKE'] = "1"
env['MOZILLA_OFFICIAL'] = "1"
env["MOZ_SIGN_CMD"] = "python " + \
path.join(os.getcwd(), "scripts", "release", "signing", "signtool.py").replace('\\', '\\\\\\\\') + \
" --cachedir " + \
path.join(os.getcwd(), "signing_cache").replace('\\', '\\\\\\\\') + \
" -t " + \
path.join(os.getcwd(), "token").replace('\\', '\\\\\\\\') + \
" -n " + \
path.join(os.getcwd(), "nonce").replace('\\', '\\\\\\\\') + \
" -c " + \
path.join(os.getcwd(), "scripts", "release", "signing", "host.cert").replace('\\', '\\\\\\\\')
signingServers = os.environ["MOZ_SIGN_CMD"].split("-H", 1)[1].split("-H")
for s in signingServers:
env["MOZ_SIGN_CMD"] += " -H %s" % s.strip()
build.misc.cleanupObjdir(sourceRepoName, objdir, appName)
mercurial(sourceRepo, sourceRepoName)
update(sourceRepoName, revision=revision)
l10nRepackPrep(
sourceRepoName, objdir, mozconfigPath, srcMozconfigPath, l10nRepoDir,
makeDirs, env, tooltoolManifest, tooltool_script, tooltool_urls)
input_env = retry(downloadReleaseBuilds,
args=(stageServer, product, brand, version, buildNumber,
platform),
kwargs={'signed': signed,
'usePymake': usePymake})
env.update(input_env)
failed = []
for l in locales:
try:
if generatePartials:
for oldVersion in partialUpdates:
oldBuildNumber = partialUpdates[oldVersion]['buildNumber']
partialUpdates[oldVersion]['mar'] = retry(
downloadUpdateIgnore404,
args=(stageServer, product, oldVersion, oldBuildNumber,
platform, l)
)
checksums_file = repackLocale(locale=l, l10nRepoDir=l10nRepoDir,
l10nBaseRepo=l10nBaseRepo, revision=revision,
localeSrcDir=localeSrcDir, l10nIni=l10nIni,
compareLocalesRepo=compareLocalesRepo, env=env,
absObjdir=absObjdir, merge=merge,
productName=product, platform=platform,
version=version, partialUpdates=partialUpdates,
buildNumber=buildNumber, stageServer=stageServer,
mozillaDir=mozillaDir, mozillaSrcDir=mozillaSrcDir)
if balrog_submitter:
# TODO: partials, after bug 797033 is fixed
checksums = parseChecksumsFile(open(checksums_file).read())
completeInfo = []
partialInfo = []
for f, info in checksums.iteritems():
if f.endswith('.complete.mar'):
completeInfo.append({
"size": info["size"],
"hash": info["hashes"][balrog_hash],
})
if f.endswith('.partial.mar'):
pathInfo = fileInfo(f, product.lower())
previousVersion = pathInfo["previousVersion"]
partialInfo.append({
"previousVersion": previousVersion,
"previousBuildNumber": partialUpdates[previousVersion]['buildNumber'],
"size": info["size"],
"hash": info["hashes"][balrog_hash],
})
if not completeInfo:
raise Exception("Couldn't find complete mar info")
retry(balrog_submitter.run,
kwargs={
'platform': platform,
'productName': product.capitalize(),
'appVersion': appVersion,
'version': version,
'build_number': buildNumber,
'locale': l,
'hashFunction': balrog_hash,
'extVersion': appVersion,
'buildID': buildid,
'completeInfo': completeInfo,
'partialInfo': partialInfo,
}
)
except Exception, e:
print_exc()
failed.append((l, format_exc()))
if len(failed) > 0:
log.error("The following tracebacks were detected during repacks:")
for l, e in failed:
log.error("%s:" % l)
log.error("%s\n" % e)
raise Exception(
"Failed locales: %s" % " ".join([x for x, _ in failed]))
REQUIRED_BRANCH_CONFIG = ("stage_server", "stage_username", "stage_ssh_key",
"compare_locales_repo_path", "hghost")
REQUIRED_RELEASE_CONFIG = ("sourceRepositories", "l10nRepoPath", "appName",
"productName", "version", "buildNumber", "appVersion")
def validate(options, args):
if not options.configfile:
log.info("Must pass --configfile")
sys.exit(1)
releaseConfigFile = "/".join(["buildbot-configs", options.releaseConfig])
if options.chunks or options.thisChunk:
assert options.chunks and options.thisChunk, \
"chunks and this-chunk are required when one is passed"
assert not options.locales, \
"locale option cannot be used when chunking"
else:
if len(options.locales) < 1:
raise Exception('Need at least one locale to repack')
if options.balrog_api_root:
if not options.credentials_file or not options.balrog_username:
raise Exception("--credentials-file and --balrog-username must be set when --balrog-api-root is set.")
releaseConfig = readReleaseConfig(releaseConfigFile,
required=REQUIRED_RELEASE_CONFIG)
branchConfig = {
'stage_ssh_key': options.stage_ssh_key,
'hghost': options.hghost,
'stage_server': options.stage_server,
'stage_username': options.stage_username,
'compare_locales_repo_path': options.compare_locales_repo_path,
}
return branchConfig, releaseConfig
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser("")
makeDirs = ["config"]
parser.set_defaults(
buildbotConfigs=os.environ.get("BUILDBOT_CONFIGS",
DEFAULT_BUILDBOT_CONFIGS_REPO),
locales=[],
chunks=None,
thisChunk=None,
objdir="obj-l10n",
source_repo_key="mozilla"
)
parser.add_option("-c", "--configfile", dest="configfile")
parser.add_option("-r", "--release-config", dest="releaseConfig")
parser.add_option("-b", "--buildbot-configs", dest="buildbotConfigs")
parser.add_option("-t", "--release-tag", dest="releaseTag")
parser.add_option("-p", "--platform", dest="platform")
parser.add_option("-o", "--objdir", dest="objdir")
parser.add_option("-l", "--locale", dest="locales", action="append")
parser.add_option("--source-repo-key", dest="source_repo_key")
parser.add_option("--chunks", dest="chunks", type="int")
parser.add_option("--this-chunk", dest="thisChunk", type="int")
parser.add_option("--generate-partials", dest="generatePartials",
action='store_true', default=False)
parser.add_option("--stage-ssh-key", dest="stage_ssh_key")
parser.add_option("--hghost", dest="hghost")
parser.add_option("--stage-server", dest="stage_server")
parser.add_option("--stage-username", dest="stage_username")
parser.add_option(
"--compare-locales-repo-path", dest="compare_locales_repo_path")
parser.add_option("--properties-dir", dest="properties_dir")
parser.add_option("--tooltool-manifest", dest="tooltool_manifest")
parser.add_option("--tooltool-script", dest="tooltool_script",
default=[], action="append")
parser.add_option("--tooltool-url", dest="tooltool_urls", action="append")
parser.add_option("--use-pymake", dest="use_pymake",
action="store_true", default=False)
# todo: maybe read these from branch/release config? is that even possible for credentials file?
parser.add_option("--balrog-api-root", dest="balrog_api_root")
parser.add_option("--credentials-file", dest="credentials_file")
parser.add_option("--balrog-username", dest="balrog_username")
options, args = parser.parse_args()
mercurial(options.buildbotConfigs, "buildbot-configs")
update("buildbot-configs", revision=options.releaseTag)
sys.path.append(os.getcwd())
branchConfig, releaseConfig = validate(options, args)
sourceRepoInfo = releaseConfig["sourceRepositories"][
options.source_repo_key]
try:
brandName = releaseConfig["brandName"]
except KeyError:
brandName = releaseConfig["productName"].title()
platform = options.platform
if platform == "linux":
platform = "linux32"
mozconfig = path.join(get_repo_dirname(sourceRepoInfo["path"]),
releaseConfig["appName"], "config", "mozconfigs",
platform, "l10n-mozconfig")
if options.chunks:
locales = retry(getReleaseLocalesForChunk,
args=(
releaseConfig[
"productName"], releaseConfig["appName"],
releaseConfig[
"version"], int(releaseConfig["buildNumber"]),
sourceRepoInfo["path"], options.platform,
options.chunks, options.thisChunk)
)
else:
locales = options.locales
if options.properties_dir:
# Output a list of the locales into the properties directory. This will
# allow consumers of the Buildbot JSON to know which locales were built
# in a particular repack chunk.
localeProps = path.normpath(path.join(options.properties_dir, 'locales'))
f = open(localeProps, 'w+')
f.write('locales:%s' % ','.join(locales))
f.close()
l10nRepoDir = 'l10n'
stageSshKey = path.join("~", ".ssh", branchConfig["stage_ssh_key"])
mozillaDir = None
mozillaSrcDir = None
# If mozilla_dir is defined, extend the paths in makeDirs with the prefix
# of the mozilla_dir
if 'mozilla_dir' in releaseConfig:
for i in range(0, len(makeDirs)):
makeDirs[i] = path.join(releaseConfig['mozilla_dir'], makeDirs[i])
mozillaDir = releaseConfig['mozilla_dir']
mozillaSrcDir = releaseConfig['mozilla_dir']
elif 'mozilla_srcdir' in releaseConfig:
mozillaSrcDir = releaseConfig['mozilla_srcdir']
if not options.tooltool_script:
options.tooltool_script = ['/tools/tooltool.py']
if options.balrog_api_root:
credentials = readConfig(options.credentials_file,
required=['balrog_credentials']
)
auth = (options.balrog_username, credentials['balrog_credentials'][options.balrog_username])
balrog_submitter = ReleaseSubmitterV3(options.balrog_api_root, auth)
else:
balrog_submitter = None
partialUpdates = releaseConfig.get('partialUpdates', {}).copy()
# FIXME: the follwong hack can be removed when win64 has the same list of
# partial update as other platforms. Check mozilla-esr38 to be sure.
if platform in releaseConfig.get('HACK_first_released_version', {}):
partialUpdates_copy = {}
for k, v in partialUpdates.iteritems():
if LooseVersion(k) >= LooseVersion(releaseConfig['HACK_first_released_version'][platform]):
partialUpdates_copy[k] = v
partialUpdates = partialUpdates_copy
# FIXME: end of hack
createRepacks(
sourceRepo=make_hg_url(branchConfig["hghost"], sourceRepoInfo["path"]),
revision=options.releaseTag,
l10nRepoDir=l10nRepoDir,
l10nBaseRepo=make_hg_url(branchConfig["hghost"],
releaseConfig["l10nRepoPath"]),
mozconfigPath=mozconfig,
srcMozconfigPath=releaseConfig.get('l10n_mozconfigs', {}).get(options.platform),
objdir=options.objdir,
makeDirs=makeDirs,
appName=releaseConfig["appName"],
locales=locales,
product=releaseConfig["productName"],
version=releaseConfig["version"],
appVersion=releaseConfig["appVersion"],
buildNumber=int(releaseConfig["buildNumber"]),
stageServer=branchConfig["stage_server"],
stageUsername=branchConfig["stage_username"],
stageSshKey=stageSshKey,
compareLocalesRepo=make_hg_url(branchConfig["hghost"],
branchConfig[
"compare_locales_repo_path"]),
merge=releaseConfig["mergeLocales"],
platform=options.platform,
brand=brandName,
generatePartials=options.generatePartials,
partialUpdates=partialUpdates,
usePymake=options.use_pymake,
tooltoolManifest=options.tooltool_manifest,
tooltool_script=options.tooltool_script,
tooltool_urls=options.tooltool_urls,
balrog_submitter=balrog_submitter,
mozillaDir=mozillaDir,
mozillaSrcDir=mozillaSrcDir
)