build/compare-mozconfig/compare-mozconfigs.py

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial