1# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- 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''' 7Script to generate the browsersearch.json file for Fennec. 8 9This script follows these steps: 10 111. Read the region.properties file in all the given source directories (see 12srcdir option). Merge all properties into a single dict accounting for the 13priority of source directories. 14 152. Read the default search plugin from 'browser.search.defaultenginename'. 16 173. Read the list of search plugins from the 'browser.search.order.INDEX' 18properties with values identifying particular search plugins by name. 19 204. Read each region-specific default search plugin from each property named like 21'browser.search.defaultenginename.REGION'. 22 235. Read the list of region-specific search plugins from the 24'browser.search.order.REGION.INDEX' properties with values identifying 25particular search plugins by name. Here, REGION is derived from a REGION for 26which we have seen a region-specific default plugin. 27 286. Generate a JSON representation of the above information, and write the result 29to browsersearch.json in the locale-specific raw resource directory 30e.g. raw/browsersearch.json, raw-pt-rBR/browsersearch.json. 31''' 32 33from __future__ import ( 34 absolute_import, 35 print_function, 36 unicode_literals, 37) 38 39import argparse 40import codecs 41import json 42import sys 43import os 44 45from mozbuild.dotproperties import ( 46 DotProperties, 47) 48from mozbuild.util import ( 49 FileAvoidWrite, 50) 51import mozpack.path as mozpath 52 53 54def merge_properties(filename, srcdirs): 55 """Merges properties from the given file in the given source directories.""" 56 properties = DotProperties() 57 for srcdir in srcdirs: 58 path = mozpath.join(srcdir, filename) 59 try: 60 properties.update(path) 61 except IOError: 62 # Ignore non-existing files 63 continue 64 return properties 65 66 67def main(args): 68 parser = argparse.ArgumentParser() 69 parser.add_argument('--verbose', '-v', default=False, action='store_true', 70 help='be verbose') 71 parser.add_argument('--silent', '-s', default=False, action='store_true', 72 help='be silent') 73 parser.add_argument('--srcdir', metavar='SRCDIR', 74 action='append', required=True, 75 help='directories to read inputs from, in order of priority') 76 parser.add_argument('output', metavar='OUTPUT', 77 help='output') 78 opts = parser.parse_args(args) 79 80 # Use reversed order so that the first srcdir has higher priority to override keys. 81 properties = merge_properties('region.properties', reversed(opts.srcdir)) 82 83 # Default, not region-specific. 84 default = properties.get('browser.search.defaultenginename') 85 engines = properties.get_list('browser.search.order') 86 87 writer = codecs.getwriter('utf-8')(sys.stdout) 88 if opts.verbose: 89 print('Read {len} engines: {engines}'.format(len=len(engines), engines=engines), file=writer) 90 print("Default engine is '{default}'.".format(default=default), file=writer) 91 92 browsersearch = {} 93 browsersearch['default'] = default 94 browsersearch['engines'] = engines 95 96 # This gets defaults, yes; but it also gets the list of regions known. 97 regions = properties.get_dict('browser.search.defaultenginename') 98 99 browsersearch['regions'] = {} 100 for region in regions.keys(): 101 region_default = regions[region] 102 region_engines = properties.get_list('browser.search.order.{region}'.format(region=region)) 103 104 if opts.verbose: 105 print("Region '{region}': Read {len} engines: {region_engines}".format( 106 len=len(region_engines), region=region, region_engines=region_engines), file=writer) 107 print("Region '{region}': Default engine is '{region_default}'.".format( 108 region=region, region_default=region_default), file=writer) 109 110 browsersearch['regions'][region] = { 111 'default': region_default, 112 'engines': region_engines, 113 } 114 115 # FileAvoidWrite creates its parent directories. 116 output = os.path.abspath(opts.output) 117 fh = FileAvoidWrite(output) 118 json.dump(browsersearch, fh) 119 existed, updated = fh.close() 120 121 if not opts.silent: 122 if updated: 123 print('{output} updated'.format(output=output)) 124 else: 125 print('{output} already up-to-date'.format(output=output)) 126 127 return 0 128 129 130if __name__ == '__main__': 131 sys.exit(main(sys.argv[1:])) 132