mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
219 lines
7.4 KiB
Python
219 lines
7.4 KiB
Python
|
from datetime import datetime
|
||
|
import os
|
||
|
from os import path
|
||
|
import re
|
||
|
import shutil
|
||
|
import sys
|
||
|
from urllib2 import urlopen
|
||
|
|
||
|
from release.paths import makeCandidatesDir
|
||
|
|
||
|
import logging
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
# If version has two parts with no trailing specifiers like "rc", we
|
||
|
# consider it a "final" release for which we only create a _RELEASE tag.
|
||
|
FINAL_RELEASE_REGEX = "^\d+\.\d+$"
|
||
|
|
||
|
|
||
|
class ConfigError(Exception):
|
||
|
pass
|
||
|
|
||
|
|
||
|
def getBuildID(platform, product, version, buildNumber, nightlyDir='nightly',
|
||
|
server='stage.mozilla.org'):
|
||
|
infoTxt = makeCandidatesDir(product, version, buildNumber, nightlyDir,
|
||
|
protocol='http', server=server) + \
|
||
|
'%s_info.txt' % platform
|
||
|
try:
|
||
|
buildInfo = urlopen(infoTxt).read()
|
||
|
except:
|
||
|
log.error("Failed to retrieve %s" % infoTxt)
|
||
|
raise
|
||
|
|
||
|
for line in buildInfo.splitlines():
|
||
|
key, value = line.rstrip().split('=', 1)
|
||
|
if key == 'buildID':
|
||
|
return value
|
||
|
|
||
|
|
||
|
def findOldBuildIDs(product, version, buildNumber, platforms,
|
||
|
nightlyDir='nightly', server='stage.mozilla.org'):
|
||
|
ids = {}
|
||
|
if buildNumber <= 1:
|
||
|
return ids
|
||
|
for n in range(1, buildNumber):
|
||
|
for platform in platforms:
|
||
|
if platform not in ids:
|
||
|
ids[platform] = []
|
||
|
try:
|
||
|
id = getBuildID(platform, product, version, n, nightlyDir,
|
||
|
server)
|
||
|
ids[platform].append(id)
|
||
|
except Exception, e:
|
||
|
log.error("Hit exception: %s" % e)
|
||
|
return ids
|
||
|
|
||
|
|
||
|
def getReleaseConfigName(product, branch, version=None, staging=False):
|
||
|
# XXX: Horrible hack for bug 842741. Because Thunderbird release
|
||
|
# and esr both build out of esr17 repositories we'll bump the wrong
|
||
|
# config for release without this.
|
||
|
if product == 'thunderbird' and 'esr17' in branch and version and 'esr' not in version:
|
||
|
cfg = 'release-thunderbird-comm-release.py'
|
||
|
else:
|
||
|
cfg = 'release-%s-%s.py' % (product, branch)
|
||
|
if staging:
|
||
|
cfg = 'staging_%s' % cfg
|
||
|
return cfg
|
||
|
|
||
|
|
||
|
def readReleaseConfig(configfile, required=[]):
|
||
|
return readConfig(configfile, keys=['releaseConfig'], required=required)
|
||
|
|
||
|
|
||
|
def readBranchConfig(dir, localconfig, branch, required=[]):
|
||
|
shutil.copy(localconfig, path.join(dir, "localconfig.py"))
|
||
|
oldcwd = os.getcwd()
|
||
|
os.chdir(dir)
|
||
|
sys.path.append(".")
|
||
|
try:
|
||
|
return readConfig("config.py", keys=['BRANCHES', branch],
|
||
|
required=required)
|
||
|
finally:
|
||
|
os.chdir(oldcwd)
|
||
|
sys.path.remove(".")
|
||
|
|
||
|
|
||
|
def readConfig(configfile, keys=[], required=[]):
|
||
|
c = {}
|
||
|
execfile(configfile, c)
|
||
|
for k in keys:
|
||
|
c = c[k]
|
||
|
items = c.keys()
|
||
|
err = False
|
||
|
for key in required:
|
||
|
if key not in items:
|
||
|
err = True
|
||
|
log.error("Required item `%s' missing from %s" % (key, c))
|
||
|
if err:
|
||
|
raise ConfigError("Missing at least one item in config, see above")
|
||
|
return c
|
||
|
|
||
|
|
||
|
def isFinalRelease(version):
|
||
|
return bool(re.match(FINAL_RELEASE_REGEX, version))
|
||
|
|
||
|
|
||
|
def getBaseTag(product, version):
|
||
|
product = product.upper()
|
||
|
version = version.replace('.', '_')
|
||
|
return '%s_%s' % (product, version)
|
||
|
|
||
|
|
||
|
def getTags(baseTag, buildNumber, buildTag=True):
|
||
|
t = ['%s_RELEASE' % baseTag]
|
||
|
if buildTag:
|
||
|
t.append('%s_BUILD%d' % (baseTag, int(buildNumber)))
|
||
|
return t
|
||
|
|
||
|
|
||
|
def getRuntimeTag(tag):
|
||
|
return "%s_RUNTIME" % tag
|
||
|
|
||
|
|
||
|
def getReleaseTag(tag):
|
||
|
return "%s_RELEASE" % tag
|
||
|
|
||
|
|
||
|
def generateRelbranchName(version, prefix='GECKO'):
|
||
|
return '%s%s_%s_RELBRANCH' % (
|
||
|
prefix, version.replace('.', ''),
|
||
|
datetime.now().strftime('%Y%m%d%H'))
|
||
|
|
||
|
|
||
|
def getReleaseName(product, version, buildNumber):
|
||
|
return '%s-%s-build%s' % (product.title(), version, str(buildNumber))
|
||
|
|
||
|
|
||
|
def getRepoMatchingBranch(branch, sourceRepositories):
|
||
|
for sr in sourceRepositories.values():
|
||
|
if branch in sr['path']:
|
||
|
return sr
|
||
|
return None
|
||
|
|
||
|
|
||
|
def fileInfo(filepath, product):
|
||
|
"""Extract information about a release file. Returns a dictionary with the
|
||
|
following keys set:
|
||
|
'product', 'version', 'locale', 'platform', 'contents', 'format',
|
||
|
'pathstyle'
|
||
|
|
||
|
'contents' is one of 'complete', 'installer'
|
||
|
'format' is one of 'mar' or 'exe'
|
||
|
'pathstyle' is either 'short' or 'long', and refers to if files are all in
|
||
|
one directory, with the locale as part of the filename ('short' paths,
|
||
|
firefox 3.0 style filenames), or if the locale names are part of the
|
||
|
directory structure, but not the file name itself ('long' paths,
|
||
|
firefox 3.5+ style filenames)
|
||
|
"""
|
||
|
try:
|
||
|
# Mozilla 1.9.0 style (aka 'short') paths
|
||
|
# e.g. firefox-3.0.12.en-US.win32.complete.mar
|
||
|
filename = os.path.basename(filepath)
|
||
|
m = re.match("^(%s)-([0-9.]+)\.([-a-zA-Z]+)\.(win32)\.(complete|installer)\.(mar|exe)$" % product, filename)
|
||
|
if not m:
|
||
|
raise ValueError("Could not parse: %s" % filename)
|
||
|
return {'product': m.group(1),
|
||
|
'version': m.group(2),
|
||
|
'locale': m.group(3),
|
||
|
'platform': m.group(4),
|
||
|
'contents': m.group(5),
|
||
|
'format': m.group(6),
|
||
|
'pathstyle': 'short',
|
||
|
'leading_path': '',
|
||
|
}
|
||
|
except:
|
||
|
# Mozilla 1.9.1 and on style (aka 'long') paths
|
||
|
# e.g. update/win32/en-US/firefox-3.5.1.complete.mar
|
||
|
# win32/en-US/Firefox Setup 3.5.1.exe
|
||
|
ret = {'pathstyle': 'long'}
|
||
|
if filepath.endswith('.mar'):
|
||
|
ret['format'] = 'mar'
|
||
|
m = re.search("update/(win32|linux-i686|linux-x86_64|mac|mac64)/([-a-zA-Z]+)/(%s)-(\d+\.\d+(?:\.\d+)?(?:\w+(?:\d+)?)?)\.(complete)\.mar" % product, filepath)
|
||
|
if not m:
|
||
|
raise ValueError("Could not parse: %s" % filepath)
|
||
|
ret['platform'] = m.group(1)
|
||
|
ret['locale'] = m.group(2)
|
||
|
ret['product'] = m.group(3)
|
||
|
ret['version'] = m.group(4)
|
||
|
ret['contents'] = m.group(5)
|
||
|
ret['leading_path'] = ''
|
||
|
elif filepath.endswith('.exe'):
|
||
|
ret['format'] = 'exe'
|
||
|
ret['contents'] = 'installer'
|
||
|
# EUballot builds use a different enough style of path than others
|
||
|
# that we can't catch them in the same regexp
|
||
|
if filepath.find('win32-EUballot') != -1:
|
||
|
ret['platform'] = 'win32'
|
||
|
m = re.search("(win32-EUballot/)([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+\d+)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
|
||
|
if not m:
|
||
|
raise ValueError("Could not parse: %s" % filepath)
|
||
|
ret['leading_path'] = m.group(1)
|
||
|
ret['locale'] = m.group(2)
|
||
|
ret['product'] = m.group(3).lower()
|
||
|
ret['version'] = m.group(4)
|
||
|
else:
|
||
|
m = re.search("(partner-repacks/[-a-zA-Z0-9_]+/|)(win32|mac|linux-i686)/([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+(?:\d+)?)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
|
||
|
if not m:
|
||
|
raise ValueError("Could not parse: %s" % filepath)
|
||
|
ret['leading_path'] = m.group(1)
|
||
|
ret['platform'] = m.group(2)
|
||
|
ret['locale'] = m.group(3)
|
||
|
ret['product'] = m.group(4).lower()
|
||
|
ret['version'] = m.group(5)
|
||
|
else:
|
||
|
raise ValueError("Unknown filetype for %s" % filepath)
|
||
|
|
||
|
return ret
|