diff options
Diffstat (limited to 'build/release/info.py')
-rw-r--r-- | build/release/info.py | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/build/release/info.py b/build/release/info.py new file mode 100644 index 000000000..9f42edd5a --- /dev/null +++ b/build/release/info.py @@ -0,0 +1,218 @@ +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 |