1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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.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
|