source: subversion/applications/rendering/mapnik/generate_xml.py @ 34655

Last change on this file since 34655 was 29292, checked in by Dirk Stoecker, 7 years ago

update docs, remove warning

  • Property svn:executable set to *
File size: 7.2 KB
Line 
1#!/usr/bin/env python
2
3import os
4import re
5import sys
6import glob
7import optparse
8import platform
9import tempfile
10
11__version__ = '0.1.0'
12
13REASONABLE_DEFAULTS = {
14        'epsg':'900913', # default osm2pgsql import srid
15        'world_boundaries':'world_boundaries', # relative path
16        'symbols':'symbols', # relative path
17        'prefix':'planet_osm', # default osm2pgsql table prefix
18        'extent':'-20037508,-19929239,20037508,19929239', # world in merc
19        'inc':'inc/*.template', # search path for inc templates to parse
20        'estimate_extent':'false',   
21        'extent':'-20037508,-19929239,20037508,19929239',   
22        }
23
24def color_text(color, text):
25    if os.name == 'nt':
26        return text
27    return "\033[9%sm%s\033[0m" % (color,text)
28
29class Params:
30    def __init__(self,params,accept_none):
31        self.params = params
32        self.accept_none = accept_none
33        self.missing = []
34   
35    def blend_with_env(self,opts):
36        d = {}
37       
38        for p in self.params:
39            env_var_name = 'MAPNIK_%s' % p.upper()
40
41            # first pull from passed options...
42            if not opts.get(p) is None:
43                d[p] = opts[p]
44
45            # then try to pull from environment settings
46            elif not os.environ.get(env_var_name) is None:
47                d[p] = os.environ[env_var_name]
48
49            # then assign any reasonable default values...
50            elif p in REASONABLE_DEFAULTS.keys():
51                d[p] = REASONABLE_DEFAULTS[p]
52            # if --accept-none is passed then we assume
53            # its a paramater that mapnik likely does not need
54            # and will ignore if it is an empty string (e.g. db values)
55            elif self.accept_none:
56                d[p] = ''
57            else:
58                self.missing.append(p)
59        return d
60
61def generate_help_text(var,default):
62    if var == 'host':
63        return 'Set postgres database host %s' % default
64    elif var == 'port':
65        return 'Set postgres database host %s' % default
66    return "Set value of '%s' %s" % (var,default)
67   
68def serialize(xml,options):
69    try:
70        import mapnik
71    except:
72        try:
73            import mapnik2 as mapnik
74        except:
75            sys.exit(color_text(1,'Error: saving xml requires Mapnik python bindings to be installed'))
76    m = mapnik.Map(1,1)
77    if options.from_string:
78        mapnik.load_map_from_string(m,xml,True)
79    else:
80        mapnik.load_map(m,xml,True)
81    if options.output:
82        mapnik.save_map(m,options.output)
83    else:
84        if hasattr(mapnik,'mapnik_version') and mapnik.mapnik_version() >= 700:
85            print mapnik.save_map_to_string(m)
86        else:
87            sys.exit(color_text(1,'Minor error: printing XML to stdout requires Mapnik >=0.7.0, please provide a second argument to save the output to a file'))
88
89def validate(params,parser):
90    if not os.path.exists(params['world_boundaries']):
91        parser.error("Directory '%s' used for param '%s' not found" % (params['world_boundaries'],'world_boundaries'))
92    supported_srs = [900913,4326]
93    if not int(params['epsg']) in supported_srs:
94        parser.error('Sorry only supported projections are: %s' % supported_srs)
95    if not params['estimate_extent'] == 'false':
96        params['extent'] = ''
97
98# set up parser...
99parser = optparse.OptionParser(usage="""%prog [template xml] <output xml> <parameters>
100
101Full help:
102 $ %prog -h (or --help for possible options)
103
104Read 'osm.xml' and modify '/inc' files in place, pass dbname and user, accept empty string for other options
105 $ %prog --dbname osm --user postgres --accept-none
106
107Read template, save output xml, and pass variables as options
108 $ %prog osm.xml my_osm.xml --dbname spain --user postgres --host ''""", version='%prog ' + __version__)
109
110
111if __name__ == '__main__':
112
113    # custom parse of includes directory if supplied...
114    if '--inc' in sys.argv:
115        idx = sys.argv.index('--inc')
116        if not len(sys.argv) > (idx+1) or '--' in sys.argv[idx+1]:
117            parser.error("--inc argument requires a path to a directory as an argument")
118        else:
119            search_path = os.path.join(sys.argv[idx+1],'*.template')
120    else:
121        search_path = REASONABLE_DEFAULTS['inc']
122   
123    inc_dir = os.path.dirname(search_path)
124    parser.add_option('--inc', dest='inc', help="Includes dir (default: '%s')" % inc_dir )
125   
126    parser.add_option('--accept-none', dest='accept_none', action='store_true', help="Interpret lacking value as unneeded")
127   
128    if not os.path.exists(inc_dir):
129        parser.error("The 'inc' path you gave is bogus!")
130       
131    # get all the includes
132    includes = glob.glob(search_path)
133   
134    if not includes:
135        parser.error("Can't find include templates, please provide search path using '--inc' , currently using '%s'" % search_path)
136
137    p = re.compile('.*%\((\w+)\)s.*')
138   
139    text = ''
140    for xml in includes:
141        text += file(xml,'rb').read()
142   
143    # find all variables in template includes
144    matches = p.findall(text)
145   
146    if not matches:
147        parser.error(color_text(1,"Can't properly parse out variables in include templates.\nMake sure they are all wrapped like '%(variable)s'"))
148   
149    # look ahead and build up --help text...
150    p = Params(matches,accept_none=False)
151    blended = p.blend_with_env({})
152    c_opts = []
153    for var in matches:
154        if not var in c_opts:
155            msg = "(default: '%(" + var + ")s')"
156            if var in blended:
157                default = msg % blended
158            else:
159                default = ''#msg % {var:'None'}
160            help = generate_help_text(var,default)
161            parser.add_option('--%s' % var, dest=var,help=generate_help_text(var,default))
162            c_opts.append(var)
163
164    # now, actually run the tool...
165    (options, args) = parser.parse_args()
166    p = Params(matches,options.accept_none)
167    blended = p.blend_with_env(options.__dict__)
168   
169    help_text = "\n\nNote: use --accept-none to pass blank values for other parameters "
170    if p.missing:
171        parser.error(color_text(1,"\nPlease provide the following parameters values (or set as env variables):\n%s" % ''.join([" --%s 'value' " % v for v in p.missing]) + help_text))
172   
173    validate(blended,parser)
174   
175    for xml in includes:
176        template = file(xml,'rb')
177        new_name = xml.replace('.template','')
178        new_file = file(new_name,'wb')
179        try:
180            new_file.write(template.read() % blended)
181        except ValueError, e:
182            parser.error(color_text(1,"\n%s (found in %s)" % (e,xml)))
183        template.close()
184        new_file.close()
185       
186    options.output = None
187    options.from_string = False
188    template_xml = None
189    # accepting XML as stream...
190    if not sys.stdin.isatty():
191        template_xml = sys.stdin.read()
192        options.from_string = True
193        if len(args) > 0:
194            options.output = args[0]
195    elif len(args) == 0:
196        template_xml = None
197        options.output = None
198    else:
199        template_xml = args[0]
200        if len(args) > 1:
201            options.output = args[1]
202
203    if template_xml:
204        serialize(template_xml,options)
205    else:
206        print 'Include files written successfully! Pass the osm.xml file as an argument if you want to serialize a new version or test reading the XML'
Note: See TracBrowser for help on using the repository browser.