diff --git a/.gitignore b/.gitignore index 6f97ca1..ba02c7c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build *.pyc +configure.py diff --git a/README.md b/README.md index fd6b1d9..90496c6 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ See `man osm2pgsql` or the [online documentation][5] for more details. Included with this style is a configuration script to help you adjust parameters such as the database connection information and a few other things. -Open up `configure.py` in a text editor and make any necessary adjustments; +Copy `configure.py.sample` to `configure.py` and make any necessary adjustments; the comments within this file explain what the various parameters are. - Make sure the "importer" option matches the program you used to import your diff --git a/configure.py b/configure.py.sample similarity index 60% rename from configure.py rename to configure.py.sample index d800c69..f68db4f 100755 --- a/configure.py +++ b/configure.py.sample @@ -1,11 +1,9 @@ #!/usr/bin/env python -## OSM BRIGHT CARTO TEMPLATE CONFIGURATION OPTIONS ############################# +from collections import defaultdict +config = defaultdict(defaultdict) -config = { - "importer": "imposm", # either 'imposm' or 'osm2pgsql' - "postgis": {} -} +config["importer"] = "osm2pgsql" # either 'imposm' or 'osm2pgsql' # PostGIS connection setup # Leave empty for Mapnik defaults. The only required parameter is dbname. @@ -29,5 +27,15 @@ # infrequently. The latest versions can be downloaded from osm.org: # - http://tile.openstreetmap.org/processed_p.tar.bz2 # - http://tile.openstreetmap.org/shoreline_300.tar.bz2 -processed_p = "http://tilemill-data.s3.amazonaws.com/osm/coastline-good.zip" -shoreline_300 = "http://tilemill-data.s3.amazonaws.com/osm/shoreline_300.zip" +config["processed_p"] = "http://tilemill-data.s3.amazonaws.com/osm/coastline-good.zip" +config["shoreline_300"] = "http://tilemill-data.s3.amazonaws.com/osm/shoreline_300.zip" + +# The name given to the style. This is the name it will have in the TileMill +# project list, and a sanitized version will be used as the directory name +# in which the project is stored +config["name"] = "OSM Bright" + +# The path to your MapBox projects directory. In Windows, this defaults to +# %UserProfile%\MapBox\project ; in Mac it's ~/Documents/MapBox/project +# and in Ubuntu it's /usr/share/mapbox/project/ +config["path"] = "/Users//Documents/MapBox/project/" diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..3c127d5 --- /dev/null +++ b/lib/__init__.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +import re +import sys + +from os import unlink +from json import loads, dumps +from glob import glob +from shutil import rmtree +from os.path import join, isdir + +#unlike shutils.copytree, will copy files without disturbing anything that was added +from distutils.dir_util import copy_tree + +from configure import config +from lib.utils import copy_tree + +def clean(): + if isdir("build"): + rmtree("build") + + for f in glob("build/*.html"): unlink(f) + +def build(): + #copy the osm-bright tree to a build dir + copy_tree("osm-bright", "build") + + #remove the mml templates + for f in glob("build/*.mml"): + unlink(f) + + #load the project template + templatefile = open(join('osm-bright', 'osm-bright.%s.mml' % config["importer"])) + template = loads(templatefile.read()) + + #fill in the project template + for layer in template["Layer"]: + if layer["id"] == "shoreline_300": + layer["Datasource"]["file"] = config["shoreline_300"] + elif layer["id"] in ("processed_p", "processed_p_outline"): + layer["Datasource"]["file"] = config["processed_p"] + else: + # Assume all other layers are PostGIS layers + for opt, val in config["postgis"].iteritems(): + if (val == ""): + if (opt in layer["Datasource"]): + del layer["Datasource"][opt] + else: + layer["Datasource"][opt] = val + + template["name"] = config["name"] + + #dump the filled-in project template to the build dir + with open(join('build', 'project.mml'), 'w') as output: + output.write(dumps(template, sort_keys=True, indent=2)) + +def install(): + assert isdir(config["path"]), "Config.path does not point to your mapbox projects directory; please fix and re-run" + sanitized_name = re.sub("[^\w]", "", config["name"]) + output_dir = join(config["path"], sanitized_name) + print "installing to %s" % output_dir + copy_tree("build", output_dir) + +def pull(): + #copy the project from mapbox to osm-bright + sanitized_name = re.sub("[^\w]", "", config["name"]) + output_dir = join(config["path"], sanitized_name) + copy_tree(output_dir, "osm-bright") + + #load the project file + project = loads(open(join("osm-bright", "project.mml"))) + + #Make sure we reset postgis data in the project file back to its default values + defaultconfig = defaultdict(defaultdict) + defaultconfig["postgis"]["host"] = "" + defaultconfig["postgis"]["port"] = "" + defaultconfig["postgis"]["dbname"] = "osm" + defaultconfig["postgis"]["user"] = "" + defaultconfig["postgis"]["password"] = "" + defaultconfig["postgis"]["extent"] = "-20037508.34 -20037508.34 20037508.34 20037508.34" + defaultconfig["name"] = "NYC Bright Osm2pgsql" + defaultconfig["processed_p"] = "http://tilemill-data.s3.amazonaws.com/osm/coastline-good.zip" + defaultconfig["shoreline_300"] = "http://tilemill-data.s3.amazonaws.com/osm/shoreline_300.zip" + + for layer in project["Layer"]: + if layer["id"] == "shoreline_300": + layer["Datasource"]["file"] = defaultconfig["shoreline_300"] + elif layer["id"] in ("processed_p", "processed_p_outline"): + layer["Datasource"]["file"] = defaultconfig["processed_p"] + else: + # Assume all other layers are PostGIS layers + for opt, val in defaultconfig["postgis"].iteritems(): + if not val and opt in layer["Datasource"]: + del layer["Datasource"][opt] + else: + layer["Datasource"][opt] = val + + project_template = open(join("build", "osm-bright.%s.mml") % config["importer"], 'w') + project_template.write(dumps(project, sort_keys=True, indent=2)) + +if __name__ == "__main__": + if sys.argv[-1] == "clean": + clean() + elif sys.argv[-1] == "build": + build() + elif sys.argv[-1] == "install": + install() + elif sys.argv[-1] == "pull": + pull() + else: + clean() + build() + install() diff --git a/lib/utils.py b/lib/utils.py new file mode 100644 index 0000000..a75ac20 --- /dev/null +++ b/lib/utils.py @@ -0,0 +1,49 @@ +import os +from distutils.file_util import copy_file +from distutils.dir_util import mkpath + +def copy_tree(src, dst, ignores): + """Copy an entire directory tree 'src' to a new location 'dst'. + + Both 'src' and 'dst' must be directory names. If 'src' is not a + directory, raise DistutilsFileError. If 'dst' does not exist, it is + created with 'mkpath()'. The end result of the copy is that every + file in 'src' is copied to 'dst', and directories under 'src' are + recursively copied to 'dst'. Return the list of files that were + copied or might have been copied, using their output name. + + Ignore any file whose name is in the "ignores" iterable. + + This is a forked version of distutils.dir_util.copy_tree, which + did not have a way to ignore the files I wanted to ignore. + """ + if not os.path.isdir(src): + raise DistutilsFileError, "cannot copy tree '%s': not a directory" % src + + try: + names = os.listdir(src) + except os.error, (errno, errstr): + raise DistutilsFileError, "error listing files in '%s': %s" % (src, errstr) + + mkpath(dst) + + outputs = [] + + for n in names: + if n in ignores: continue + + src_name = os.path.join(src, n) + dst_name = os.path.join(dst, n) + +#def copy_tree(src, dst, preserve_mode=1, preserve_times=1, +# preserve_symlinks=0, update=0, verbose=1, dry_run=0): + + if os.path.islink(src_name): + continue + elif os.path.isdir(src_name): + outputs.extend(copy_tree(src_name, dst_name, ignores)) + else: + copy_file(src_name, dst_name, verbose=1) + outputs.append(dst_name) + + return outputs diff --git a/make.py b/make.py index 936ab16..b8bb0ba 100755 --- a/make.py +++ b/make.py @@ -1,12 +1,20 @@ #!/usr/bin/env python -import json +import re +import sys + from os import unlink +from json import loads, dumps from glob import glob -from shutil import copytree, rmtree +from shutil import rmtree from os.path import join, isdir +from collections import defaultdict + +#unlike shutils.copytree, will copy files without disturbing anything that was added +from distutils.dir_util import copy_tree -from configure import config, processed_p, shoreline_300 +from configure import config +from lib.utils import copy_tree def clean(): if isdir("build"): @@ -16,7 +24,7 @@ def clean(): def build(): #copy the osm-bright tree to a build dir - copytree("osm-bright", "build") + copy_tree("osm-bright", "build") #remove the mml templates for f in glob("build/*.mml"): @@ -24,14 +32,14 @@ def build(): #load the project template templatefile = open(join('osm-bright', 'osm-bright.%s.mml' % config["importer"])) - template = json.loads(templatefile.read()) + template = loads(templatefile.read()) #fill in the project template for layer in template["Layer"]: if layer["id"] == "shoreline_300": - layer["Datasource"]["file"] = shoreline_300 + layer["Datasource"]["file"] = config["shoreline_300"] elif layer["id"] in ("processed_p", "processed_p_outline"): - layer["Datasource"]["file"] = processed_p + layer["Datasource"]["file"] = config["processed_p"] else: # Assume all other layers are PostGIS layers for opt, val in config["postgis"].iteritems(): @@ -41,10 +49,69 @@ def build(): else: layer["Datasource"][opt] = val + template["name"] = config["name"] + #dump the filled-in project template to the build dir with open(join('build', 'project.mml'), 'w') as output: - output.write(json.dumps(template, sort_keys=True, indent=2)) + output.write(dumps(template, sort_keys=True, indent=2)) + +def install(): + assert isdir(config["path"]), "Config.path does not point to your mapbox projects directory; please fix and re-run" + sanitized_name = re.sub("[^\w]", "", config["name"]) + output_dir = join(config["path"], sanitized_name) + print "installing to %s" % output_dir + copy_tree("build", output_dir) + +def pull(): + #copy the project from mapbox to osm-bright + sanitized_name = re.sub("[^\w]", "", config["name"]) + output_dir = join(config["path"], sanitized_name) + copy_tree(output_dir, "osm-bright", ("layers", ".thumb.png")) + + #load the project file + project = loads(open(join("osm-bright", "project.mml")).read()) + + #Make sure we reset postgis data in the project file back to its default values + defaultconfig = defaultdict(defaultdict) + defaultconfig["postgis"]["host"] = "" + defaultconfig["postgis"]["port"] = "" + defaultconfig["postgis"]["dbname"] = "osm" + defaultconfig["postgis"]["user"] = "" + defaultconfig["postgis"]["password"] = "" + defaultconfig["postgis"]["extent"] = "-20037508.34 -20037508.34 20037508.34 20037508.34" + defaultconfig["name"] = "NYC Bright Osm2pgsql" + defaultconfig["processed_p"] = "http://tilemill-data.s3.amazonaws.com/osm/coastline-good.zip" + defaultconfig["shoreline_300"] = "http://tilemill-data.s3.amazonaws.com/osm/shoreline_300.zip" + + for layer in project["Layer"]: + if layer["id"] == "shoreline_300": + layer["Datasource"]["file"] = defaultconfig["shoreline_300"] + elif layer["id"] in ("processed_p", "processed_p_outline"): + layer["Datasource"]["file"] = defaultconfig["processed_p"] + else: + # Assume all other layers are PostGIS layers + for opt, val in defaultconfig["postgis"].iteritems(): + if not val and opt in layer["Datasource"]: + del layer["Datasource"][opt] + else: + layer["Datasource"][opt] = val + + project_template = open(join("build", "osm-bright.%s.mml") % config["importer"], 'w') + project_template.write(dumps(project, sort_keys=True, indent=2)) + + #now delete project.mml + unlink(join("osm-bright", "project.mml")) if __name__ == "__main__": - clean() - build() + if sys.argv[-1] == "clean": + clean() + elif sys.argv[-1] == "build": + build() + elif sys.argv[-1] == "install": + install() + elif sys.argv[-1] == "pull": + pull() + else: + clean() + build() + install() diff --git a/precommit.py b/precommit.py deleted file mode 100755 index f032a49..0000000 --- a/precommit.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -## Run this script before preparing a Git commit in order to pull your changes -## from your working .mml to one in the root directory with default settings. - -################################################################################ - -config = { "postgis": {} } - -config["postgis"]["host"] = "" -config["postgis"]["port"] = "" -config["postgis"]["dbname"] = "osm" -config["postgis"]["user"] = "" -config["postgis"]["password"] = "" - -config["postgis"]["extent"] = "-20037508.34 -20037508.34 20037508.34 20037508.34" - -processed_p = "http://tilemill-data.s3.amazonaws.com/osm/coastline-good.zip" -shoreline_300 = "http://tilemill-data.s3.amazonaws.com/osm/shoreline_300.zip" - -import json -from sys import path -from os.path import join - -output = join('osm-bright', 'osm-bright.imposm.mml') -template = join('build', 'project.mml') - -with open(template, 'r') as f: - newf = json.loads(f.read()) - -with open(output, 'w') as f: - for layer in newf["Layer"]: - if layer["id"] == "shoreline_300": - layer["Datasource"]["file"] = shoreline_300 - elif (layer["id"] == "processed_p") or (layer["id"] == "processed_p_outline"): - layer["Datasource"]["file"] = processed_p - else: - # Assume all other layers are PostGIS layers - for opt, val in config["postgis"].iteritems(): - if (val == ""): - if (opt in layer["Datasource"]): - del layer["Datasource"][opt] - else: - layer["Datasource"][opt] = val - f.write(json.dumps(newf, sort_keys=True, indent=2))