Backout a74bd5095902, Bug 959405 - Please update the Buri Moz-central, 1.3, 1.2 with...
[gecko.git] / build / release / info.py
blob9f42edd5a6dd33bd7895870cb5106437cfc88e23
1 from datetime import datetime
2 import os
3 from os import path
4 import re
5 import shutil
6 import sys
7 from urllib2 import urlopen
9 from release.paths import makeCandidatesDir
11 import logging
12 log = logging.getLogger(__name__)
14 # If version has two parts with no trailing specifiers like "rc", we
15 # consider it a "final" release for which we only create a _RELEASE tag.
16 FINAL_RELEASE_REGEX = "^\d+\.\d+$"
19 class ConfigError(Exception):
20 pass
23 def getBuildID(platform, product, version, buildNumber, nightlyDir='nightly',
24 server='stage.mozilla.org'):
25 infoTxt = makeCandidatesDir(product, version, buildNumber, nightlyDir,
26 protocol='http', server=server) + \
27 '%s_info.txt' % platform
28 try:
29 buildInfo = urlopen(infoTxt).read()
30 except:
31 log.error("Failed to retrieve %s" % infoTxt)
32 raise
34 for line in buildInfo.splitlines():
35 key, value = line.rstrip().split('=', 1)
36 if key == 'buildID':
37 return value
40 def findOldBuildIDs(product, version, buildNumber, platforms,
41 nightlyDir='nightly', server='stage.mozilla.org'):
42 ids = {}
43 if buildNumber <= 1:
44 return ids
45 for n in range(1, buildNumber):
46 for platform in platforms:
47 if platform not in ids:
48 ids[platform] = []
49 try:
50 id = getBuildID(platform, product, version, n, nightlyDir,
51 server)
52 ids[platform].append(id)
53 except Exception, e:
54 log.error("Hit exception: %s" % e)
55 return ids
58 def getReleaseConfigName(product, branch, version=None, staging=False):
59 # XXX: Horrible hack for bug 842741. Because Thunderbird release
60 # and esr both build out of esr17 repositories we'll bump the wrong
61 # config for release without this.
62 if product == 'thunderbird' and 'esr17' in branch and version and 'esr' not in version:
63 cfg = 'release-thunderbird-comm-release.py'
64 else:
65 cfg = 'release-%s-%s.py' % (product, branch)
66 if staging:
67 cfg = 'staging_%s' % cfg
68 return cfg
71 def readReleaseConfig(configfile, required=[]):
72 return readConfig(configfile, keys=['releaseConfig'], required=required)
75 def readBranchConfig(dir, localconfig, branch, required=[]):
76 shutil.copy(localconfig, path.join(dir, "localconfig.py"))
77 oldcwd = os.getcwd()
78 os.chdir(dir)
79 sys.path.append(".")
80 try:
81 return readConfig("config.py", keys=['BRANCHES', branch],
82 required=required)
83 finally:
84 os.chdir(oldcwd)
85 sys.path.remove(".")
88 def readConfig(configfile, keys=[], required=[]):
89 c = {}
90 execfile(configfile, c)
91 for k in keys:
92 c = c[k]
93 items = c.keys()
94 err = False
95 for key in required:
96 if key not in items:
97 err = True
98 log.error("Required item `%s' missing from %s" % (key, c))
99 if err:
100 raise ConfigError("Missing at least one item in config, see above")
101 return c
104 def isFinalRelease(version):
105 return bool(re.match(FINAL_RELEASE_REGEX, version))
108 def getBaseTag(product, version):
109 product = product.upper()
110 version = version.replace('.', '_')
111 return '%s_%s' % (product, version)
114 def getTags(baseTag, buildNumber, buildTag=True):
115 t = ['%s_RELEASE' % baseTag]
116 if buildTag:
117 t.append('%s_BUILD%d' % (baseTag, int(buildNumber)))
118 return t
121 def getRuntimeTag(tag):
122 return "%s_RUNTIME" % tag
125 def getReleaseTag(tag):
126 return "%s_RELEASE" % tag
129 def generateRelbranchName(version, prefix='GECKO'):
130 return '%s%s_%s_RELBRANCH' % (
131 prefix, version.replace('.', ''),
132 datetime.now().strftime('%Y%m%d%H'))
135 def getReleaseName(product, version, buildNumber):
136 return '%s-%s-build%s' % (product.title(), version, str(buildNumber))
139 def getRepoMatchingBranch(branch, sourceRepositories):
140 for sr in sourceRepositories.values():
141 if branch in sr['path']:
142 return sr
143 return None
146 def fileInfo(filepath, product):
147 """Extract information about a release file. Returns a dictionary with the
148 following keys set:
149 'product', 'version', 'locale', 'platform', 'contents', 'format',
150 'pathstyle'
152 'contents' is one of 'complete', 'installer'
153 'format' is one of 'mar' or 'exe'
154 'pathstyle' is either 'short' or 'long', and refers to if files are all in
155 one directory, with the locale as part of the filename ('short' paths,
156 firefox 3.0 style filenames), or if the locale names are part of the
157 directory structure, but not the file name itself ('long' paths,
158 firefox 3.5+ style filenames)
160 try:
161 # Mozilla 1.9.0 style (aka 'short') paths
162 # e.g. firefox-3.0.12.en-US.win32.complete.mar
163 filename = os.path.basename(filepath)
164 m = re.match("^(%s)-([0-9.]+)\.([-a-zA-Z]+)\.(win32)\.(complete|installer)\.(mar|exe)$" % product, filename)
165 if not m:
166 raise ValueError("Could not parse: %s" % filename)
167 return {'product': m.group(1),
168 'version': m.group(2),
169 'locale': m.group(3),
170 'platform': m.group(4),
171 'contents': m.group(5),
172 'format': m.group(6),
173 'pathstyle': 'short',
174 'leading_path': '',
176 except:
177 # Mozilla 1.9.1 and on style (aka 'long') paths
178 # e.g. update/win32/en-US/firefox-3.5.1.complete.mar
179 # win32/en-US/Firefox Setup 3.5.1.exe
180 ret = {'pathstyle': 'long'}
181 if filepath.endswith('.mar'):
182 ret['format'] = 'mar'
183 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)
184 if not m:
185 raise ValueError("Could not parse: %s" % filepath)
186 ret['platform'] = m.group(1)
187 ret['locale'] = m.group(2)
188 ret['product'] = m.group(3)
189 ret['version'] = m.group(4)
190 ret['contents'] = m.group(5)
191 ret['leading_path'] = ''
192 elif filepath.endswith('.exe'):
193 ret['format'] = 'exe'
194 ret['contents'] = 'installer'
195 # EUballot builds use a different enough style of path than others
196 # that we can't catch them in the same regexp
197 if filepath.find('win32-EUballot') != -1:
198 ret['platform'] = 'win32'
199 m = re.search("(win32-EUballot/)([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+\d+)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
200 if not m:
201 raise ValueError("Could not parse: %s" % filepath)
202 ret['leading_path'] = m.group(1)
203 ret['locale'] = m.group(2)
204 ret['product'] = m.group(3).lower()
205 ret['version'] = m.group(4)
206 else:
207 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)
208 if not m:
209 raise ValueError("Could not parse: %s" % filepath)
210 ret['leading_path'] = m.group(1)
211 ret['platform'] = m.group(2)
212 ret['locale'] = m.group(3)
213 ret['product'] = m.group(4).lower()
214 ret['version'] = m.group(5)
215 else:
216 raise ValueError("Unknown filetype for %s" % filepath)
218 return ret