build/compare-mozconfig/compare-mozconfigs.py

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:f80488477fcd
1 #!/usr/bin/python
2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6 # originally from http://hg.mozilla.org/build/tools/file/4ab9c1a4e05b/scripts/release/compare-mozconfigs.py
7
8 from __future__ import unicode_literals
9
10 import logging
11 import os
12 import site
13 import sys
14 import urllib2
15 import difflib
16
17 FAILURE_CODE = 1
18 SUCCESS_CODE = 0
19
20 log = logging.getLogger(__name__)
21
22 class ConfigError(Exception):
23 pass
24
25 def make_hg_url(hgHost, repoPath, protocol='https', revision=None,
26 filename=None):
27 """construct a valid hg url from a base hg url (hg.mozilla.org),
28 repoPath, revision and possible filename"""
29 base = '%s://%s' % (protocol, hgHost)
30 repo = '/'.join(p.strip('/') for p in [base, repoPath])
31 if not filename:
32 if not revision:
33 return repo
34 else:
35 return '/'.join([p.strip('/') for p in [repo, 'rev', revision]])
36 else:
37 assert revision
38 return '/'.join([p.strip('/') for p in [repo, 'raw-file', revision,
39 filename]])
40
41 def readConfig(configfile, keys=[], required=[]):
42 c = {}
43 execfile(configfile, c)
44 for k in keys:
45 c = c[k]
46 items = c.keys()
47 err = False
48 for key in required:
49 if key not in items:
50 err = True
51 log.error("Required item `%s' missing from %s" % (key, c))
52 if err:
53 raise ConfigError("Missing at least one item in config, see above")
54 return c
55
56 def verify_mozconfigs(mozconfig_pair, nightly_mozconfig_pair, platform,
57 mozconfigWhitelist={}):
58 """Compares mozconfig to nightly_mozconfig and compare to an optional
59 whitelist of known differences. mozconfig_pair and nightly_mozconfig_pair
60 are pairs containing the mozconfig's identifier and the list of lines in
61 the mozconfig."""
62
63 # unpack the pairs to get the names, the names are just for
64 # identifying the mozconfigs when logging the error messages
65 mozconfig_name, mozconfig_lines = mozconfig_pair
66 nightly_mozconfig_name, nightly_mozconfig_lines = nightly_mozconfig_pair
67
68 missing_args = mozconfig_lines == [] or nightly_mozconfig_lines == []
69 if missing_args:
70 log.info("Missing mozconfigs to compare for %s" % platform)
71 return False
72
73 success = True
74
75 diff_instance = difflib.Differ()
76 diff_result = diff_instance.compare(mozconfig_lines, nightly_mozconfig_lines)
77 diff_list = list(diff_result)
78
79 for line in diff_list:
80 clean_line = line[1:].strip()
81 if (line[0] == '-' or line[0] == '+') and len(clean_line) > 1:
82 # skip comment lines
83 if clean_line.startswith('#'):
84 continue
85 # compare to whitelist
86 message = ""
87 if line[0] == '-':
88 if platform in mozconfigWhitelist.get('release', {}):
89 if clean_line in \
90 mozconfigWhitelist['release'][platform]:
91 continue
92 elif line[0] == '+':
93 if platform in mozconfigWhitelist.get('nightly', {}):
94 if clean_line in \
95 mozconfigWhitelist['nightly'][platform]:
96 continue
97 else:
98 log.warning("%s not in %s %s!" % (
99 clean_line, platform,
100 mozconfigWhitelist['nightly'][platform]))
101 else:
102 log.error("Skipping line %s!" % line)
103 continue
104 message = "found in %s but not in %s: %s"
105 if line[0] == '-':
106 log.error(message % (mozconfig_name,
107 nightly_mozconfig_name, clean_line))
108 else:
109 log.error(message % (nightly_mozconfig_name,
110 mozconfig_name, clean_line))
111 success = False
112 return success
113
114 def get_mozconfig(path, options):
115 """Consumes a path and returns a list of lines from
116 the mozconfig file. If download is required, the path
117 specified should be relative to the root of the hg
118 repository e.g browser/config/mozconfigs/linux32/nightly"""
119 if options.no_download:
120 return open(path, 'r').readlines()
121 else:
122 url = make_hg_url(options.hghost, options.branch, 'http',
123 options.revision, path)
124 return urllib2.urlopen(url).readlines()
125
126 if __name__ == '__main__':
127 from optparse import OptionParser
128 parser = OptionParser()
129
130 parser.add_option('--branch', dest='branch')
131 parser.add_option('--revision', dest='revision')
132 parser.add_option('--hghost', dest='hghost', default='hg.mozilla.org')
133 parser.add_option('--whitelist', dest='whitelist')
134 parser.add_option('--no-download', action='store_true', dest='no_download',
135 default=False)
136 options, args = parser.parse_args()
137
138 logging.basicConfig(level=logging.INFO)
139
140 missing_args = options.branch is None or options.revision is None
141 if not options.no_download and missing_args:
142 logging.error('Not enough arguments to download mozconfigs')
143 sys.exit(FAILURE_CODE)
144
145 mozconfig_whitelist = readConfig(options.whitelist, ['whitelist'])
146
147 for arg in args:
148 platform, mozconfig_path, nightly_mozconfig_path = arg.split(',')
149
150 mozconfig_lines = get_mozconfig(mozconfig_path, options)
151 nightly_mozconfig_lines = get_mozconfig(nightly_mozconfig_path, options)
152
153 mozconfig_pair = (mozconfig_path, mozconfig_lines)
154 nightly_mozconfig_pair = (nightly_mozconfig_path,
155 nightly_mozconfig_lines)
156
157 passed = verify_mozconfigs(mozconfig_pair, nightly_mozconfig_pair,
158 platform, mozconfig_whitelist)
159
160 if passed:
161 logging.info('Mozconfig check passed!')
162 else:
163 logging.error('Mozconfig check failed!')
164 sys.exit(FAILURE_CODE)
165 sys.exit(SUCCESS_CODE)

mercurial