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