123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- 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.utcnow().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
|