[Git][debian-gis-team/openstreetmap-carto][master] 4 commits: New upstream version 5.6.2

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Thu Dec 1 13:25:33 GMT 2022



Bas Couwenberg pushed to branch master at Debian GIS Project / openstreetmap-carto


Commits:
556cef2c by Bas Couwenberg at 2022-12-01T14:22:27+01:00
New upstream version 5.6.2
- - - - -
7000ff47 by Bas Couwenberg at 2022-12-01T14:23:49+01:00
New upstream release.

- - - - -
c7a3b777 by Bas Couwenberg at 2022-12-01T14:23:53+01:00
Update lintian overrides.

- - - - -
7c2852bf by Bas Couwenberg at 2022-12-01T14:23:53+01:00
Set distribution to unstable.

- - - - -


23 changed files:

- .github/issue_template.md
- .github/workflows/ci.yml
- .gitignore
- − .travis.yml
- CHANGELOG.md
- CODE_OF_CONDUCT.md
- DOCKER.md
- INSTALL.md
- RELEASES.md
- debian/changelog
- + debian/openstreetmap-carto-common.lintian-overrides
- debian/po/sv.po
- docker-compose.yml
- project.mml
- scripts/docker-startup.sh
- scripts/get-external-data.py
- + scripts/get-fonts.sh
- style/amenity-points.mss
- style/fonts.mss
- style/landcover.mss
- style/roads.mss
- style/water.mss
- + symbols/amenity/parcel_locker.svg


Changes:

=====================================
.github/issue_template.md
=====================================
@@ -2,4 +2,4 @@
 
 ### Actual behavior
 
-### Links and screenshots illustrating the problem
+### Screenshots with links illustrating the problem


=====================================
.github/workflows/ci.yml
=====================================
@@ -13,8 +13,6 @@ jobs:
     - name: Set up Python
       run: |
         python -m pip install pyyaml colormath
-    - name: Set up apt
-      run: sudo apt-get update -qq
     - name: Set up xmllint
       run: sudo apt-get install -qq --no-install-recommends libxml2-utils
     - name: Set up shell
@@ -31,3 +29,19 @@ jobs:
       run: diff -qu <(scripts/generate_road_colours.py) style/road-colors-generated.mss
     - name: Check for unsupported class usage
       run: '! grep "class:" project.mml > /dev/null'
+  import:
+    needs: [syntax]
+    runs-on: ubuntu-22.04
+    steps:
+    - uses: actions/checkout at v3
+    - name: Install osm2pgsql and database
+      run: sudo apt-get install -qq --no-install-recommends osm2pgsql postgresql-14-postgis-3
+    - name: Wait for database
+      run : sudo pg_ctlcluster 14 main start; until pg_isready; do sleep 0.5; done
+    - name: Setup database
+      run: sudo -i -u postgres createuser -s $USER && createdb -E utf8 gis && psql -Xq -d gis -c "CREATE EXTENSION postgis; CREATE EXTENSION hstore;"
+    - name: Import empty file
+      run: |
+        osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -d gis -r xml <(echo '<osm version="0.6"/>')
+    - name: Create indexes
+      run: psql -1Xq -v ON_ERROR_STOP=1 -d gis -f indexes.sql


=====================================
.gitignore
=====================================
@@ -1,6 +1,7 @@
 .thumb.png
 layers/
 data/
+fonts/
 tmp/
 *.xml
 *.osm.pbf


=====================================
.travis.yml deleted
=====================================
@@ -1,45 +0,0 @@
-language: node_js
-dist: bionic
-sudo: false
-node_js:
-  - "14"
-services:
-  - postgresql
-addons:
-  postgresql: "9.5"
-  apt:
-    packages:
-    - lua5.1
-    - libxml2-utils
-    - python3-pip
-    - python3-setuptools
-    - python-yaml
-    - postgresql-9.5-postgis-2.4
-    - osm2pgsql
-env:
-  - CARTO=1.2.0 MAPNIK='3.0.0 3.0.12 3.0.22'
-install:
-  - npm install carto@$CARTO
-  - pip3 install --user colormath
-  - createdb -w -E utf8 -U postgres gis && psql -Xq -d gis -U postgres -w -c "CREATE EXTENSION postgis; CREATE EXTENSION hstore;"
-script:
-  # We're using pipes in the checks, so fail if any part fails
-  - set -o pipefail
-  # Check all tye YAML files are valid YAML
-  - find . -not \( -path ./node_modules -prune \) \( -type f -name '*.yaml' -o -name '*.yml' -o -name '*.mml' \)
-     -exec python -c "from yaml import safe_load; safe_load(file('{}'))" \;
-  # Validate the MML against multiple Mapnik versions, and report its lines for debugging purposes
-  - for m in $MAPNIK; do ./node_modules/carto/bin/carto -a $m project.mml | xmllint - | wc -l; done
-  # Validate that the SVGs are valid XML
-  - find symbols/ -name '*.svg' | xargs xmllint --noout
-  # Check the Lua transforms
-  - lua scripts/lua/test.lua
-  # Check the indexes and road colours files are up to date
-  - diff -qu <(scripts/indexes.py) indexes.sql
-  - diff -qu <(scripts/generate_road_colours.py) style/road-colors-generated.mss
-  # Create the PostgreSQL tables
-  - osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -U postgres -d gis -r xml <(echo '<osm version="0.6"/>')
-  # Apply the custom indexes
-  - psql -1Xq -v ON_ERROR_STOP=1 -d gis -f indexes.sql
-  # Test for classes in project.mml (not supported in vector tiles)
-  - '! grep "class:" project.mml > /dev/null'


=====================================
CHANGELOG.md
=====================================
@@ -1,4 +1,25 @@
-## [Unreleased](https://github.com/gravitystorm/openstreetmap-carto/compare/v5.5.1...master)
+## [Unreleased](https://github.com/gravitystorm/openstreetmap-carto/compare/v5.6.2...master)
+
+## [v5.6.2](https://github.com/gravitystorm/openstreetmap-carto/compare/v5.6.1...v5.6.2) - 2022-11-10
+### Changes
+- Fixed CartoCSS for using locally installed fonts
+
+## [v5.6.1](https://github.com/gravitystorm/openstreetmap-carto/compare/v5.6.0...v5.6.1) - 2022-08-12
+### Changes
+- Rendering of water areas on zooms 0 to 4 fixed (#4640)
+
+## [v5.6.0](https://github.com/gravitystorm/openstreetmap-carto/compare/v5.5.1...v5.6.0) - 2022-08-03
+### Major Changes
+- The style now uses locally installed fonts, using `scripts/get-fonts.sh` to download the fonts.
+
+### Changes
+- Code and performance improvements (#4591, #4601)
+- Recommend disabling PostgreSQL JIT for rendering (#4592)
+- Change tree and tree row colours to the same colour as areas with trees (#4448)
+- Don't label public transport shelters with elevation (#4313)
+- Update code of conduct to explicitly prohibit doxxing (#4554)
+- Add parcel lockers (#4512)
+- Render name labels of bays and straights from z14 only, and lakes from z5 (#3750)
 
 ## [v5.5.1](https://github.com/gravitystorm/openstreetmap-carto/compare/v5.5.0...v5.5.1) - 2022-07-13
 ### Changes


=====================================
CODE_OF_CONDUCT.md
=====================================
@@ -49,6 +49,7 @@ These actions are explicitly forbidden in OpenStreetMap Carto spaces:
 - Insulting, demeaning, hateful, or threatening remarks.
 - Discrimination based on age, disability, gender, nationality, ethnicity, religion, sexuality, or similar personal characteristic.
 - Bullying or systematic harassment.
+- Revealing private information about other participants without explicit permission ("doxxing").
 - Unwelcome sexual advances.
 - Incitement to any of these.
 
@@ -62,7 +63,7 @@ When using the OpenStreetMap Carto spaces you should act in the spirit of the va
 
 The OpenStreetMap Carto maintainers are responsible for handling conduct-related issues. Their goal is to de-escalate conflicts and try to resolve issues to the satisfaction of all parties.
 
-If you encounter a conduct-related issue, you should report it to the maintainers by sending them [all an email](mailto:openstreetmap-carto at gravitystorm.co.uk,osm at paulnorman.ca,chris_hormann at gmx.de,daniel at xn--ko-wla.pl,sommerluk at gmail.com,joseph.eisenberg at gmail.com).
+If you encounter a conduct-related issue, you should report it to the maintainers by sending them [all an email](mailto:openstreetmap-carto at gravitystorm.co.uk,osm at paulnorman.ca,chris_hormann at gmx.de,daniel at xn--ko-wla.pl,sommerluk at gmail.com,joseph.eisenberg at gmail.com). In the event that you wish to make a complaint against a maintainer, you may instead contact the other maintainers.
 
 **Note that the goal of the Code of Conduct and the maintainers is to resolve conflicts in the most harmonious way possible.** We hope that in most cases issues may be resolved through polite discussion and mutual agreement. Bans and other forceful measures are to be employed only as a last resort.
 


=====================================
DOCKER.md
=====================================
@@ -21,7 +21,7 @@ Read on below to get the details.
 * `git clone https://github.com/gravitystorm/openstreetmap-carto.git` to clone openstreetmap-carto repository into a directory on your host system
 * download OpenStreetMap data in osm.pbf format to a file `data.osm.pbf` and place it within the openstreetmap-carto directory (for example some small area from [Geofabrik](https://download.geofabrik.de/))
 * If necessary, `sudo service postgresql stop` to make sure you don't have currently running a native PostgreSQL server which would conflict with Docker's PostgreSQL server.
-* `docker-compose up import` to import the data (only necessary the first time or when you change the data file)
+* `docker-compose up import` to import the data (only necessary the first time or when you change the data file). Additionally you can set import options through [environment variables](#Importing-data). More on that [later](#Hands-on-approach)
 * `docker-compose up kosmtik` to run the style preview application
 * browse to [http://localhost:6789](http://localhost:6789) to view the output of Kosmtik
 * Ctrl+C to stop the style preview application
@@ -39,11 +39,24 @@ OpenStreetMap Carto needs a database populated with rendering data to work. You
 It's probably easiest to grab an PBF of OSM data from [Geofabrik](https://download.geofabrik.de/).
 Once you have that file put it into the openstreetmap-carto directory and run `docker-compose up import` in the openstreetmap-carto directory.
 This starts the PostgreSQL container (downloads it if it not exists) and starts a container that runs [osm2pgsql](https://github.com/openstreetmap/osm2pgsql) to import the data. The container is built the first time you run that command if it not exists.
-At startup of the container the script `scripts/docker-startup.sh` is invoked which prepares the database and itself starts osm2pgsql for importing the data.
+At startup of the container the script `scripts/docker-startup.sh` is invoked which prepares the database and itself starts osm2pgsql for importing the data. Then the `scripts/get-external-data.py` is called to download and import needed shapefiles.
 
-osm2pgsql has a few [command line options](https://manpages.debian.org/testing/osm2pgsql/osm2pgsql.1.en.html) and the import by default uses a RAM cache of 512 MB, 1 worker and expects the import file to be named `data.osm.pbf`. If you want to customize any of these parameters you have to set the environment variables `OSM2PGSQL_CACHE` (e.g. `export OSM2PGSQL_CACHE=1024` on Linux to set the cache to 1 GB) for the RAM cache (the value depends on the amount of RAM you have available, the more you can use here the faster the import may be), `OSM2PGSQL_NUMPROC` for the number of workers (this depends on the number of processors you have and whether your harddisk is fast enough e.g. is a SSD), or `OSM2PGSQL_DATAFILE` if your file has a different name.
+### Supplying command line options as environment variables
 
-You can also [tune the PostgreSQL](https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server) during the import phases, with `PG_WORK_MEM` (default to 16MB) and `PG_MAINTENANCE_WORK_MEM` (default to 256MB), which will eventually write `work_mem` and `maintenance_work_mem` to the `postgresql.auto.conf` once, making them applied each time the database started. Note that unlike osm2pgsql variables, once thay are set, you can only change them by running `ALTER SYSTEM` on your own, changing `postgresql.auto.conf` or remove the database volume by `docker-compose down -v && docker-compose rm -v` and import again.
+**osm2pgsql** has a few [command line options](https://manpages.debian.org/testing/osm2pgsql/osm2pgsql.1.en.html) and the import by default uses a RAM cache of 512 MB, 1 worker and expects the import file to be named `data.osm.pbf`. If you want to customize any of these parameters you have to set the environment variables `OSM2PGSQL_CACHE` (e.g. `export OSM2PGSQL_CACHE=1024` on Linux to set the cache to 1 GB) for the RAM cache (the value depends on the amount of RAM you have available, the more you can use here the faster the import may be), `OSM2PGSQL_NUMPROC` for the number of workers (this depends on the number of processors you have and whether your harddisk is fast enough e.g. is a SSD), or `OSM2PGSQL_DATAFILE` if your file has a different name.
+
+You can also [tune the **PostgreSQL**](https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server) during the import phases, with `PG_WORK_MEM` (default to 16MB) and `PG_MAINTENANCE_WORK_MEM` (default to 256MB), which will eventually write `work_mem` and `maintenance_work_mem` to the `postgresql.auto.conf` once, making them applied each time the database started. Note that unlike osm2pgsql variables, once thay are set, you can only change them by running `ALTER SYSTEM` on your own, changing `postgresql.auto.conf` or remove the database volume by `docker-compose down -v && docker-compose rm -v` and import again.
+
+**get-external-data.py script** has option `-C (--cache)` to save data after download (useful when you are tinkering with docker and ending up deleting volumes).
+It also has option `--no-update` to stop program from downloading newer versions of shapefiles if you don't deem updating them necessary. Best used in conjunction with `-C`.
+If everything goes out of the window, option `--force` will forcefully download data and import it. Option `--force-import` will try to force just import part.
+Use `EXTERNAL_DATA_SCRIPT_FLAGS` env variable to pass those options. For example:
+```
+EXTERNAL_DATA_SCRIPT_FLAGS="--cache --no-update"
+```
+will keep data you downloaded and not update them (saving you on bandwidth) until you change this options.
+
+### Hands on approach
 
 If you want to customize and remember the values, supply it during your first import:
 
@@ -51,10 +64,13 @@ If you want to customize and remember the values, supply it during your first im
 PG_WORK_MEM=128MB PG_MAINTENANCE_WORK_MEM=2GB \
 OSM2PGSQL_CACHE=2048 OSM2PGSQL_NUMPROC=4 \
 OSM2PGSQL_DATAFILE=taiwan.osm.pbf \
+EXTERNAL_DATA_SCRIPT_FLAGS="--cache --no-update" \
 docker-compose up import
 ```
 
-Variables will be remembered in `.env` if you don't have that file, and values in the file will be applied unless you manually assign them.
+Note that on Linux you need to export those environment variables before calling docker-compose. If you are using sudo to call docker (because your user is not in the docker group (which we don't recommend)), you need to also use sudo -E option
+
+Variables will be remembered in `.env` if you don't have that file, and values in the file will be applied unless you manually assign them. Keep in mind this means if you change your `.env` file, but keep your environment variables untouched (you haven't unset them or you haven't rebooted your host), they will be used instead of anything that you changed in `.env`.
 
 Depending on your machine and the size of the extract the import can take a while. When it is finished you should have the data necessary to render it with OpenStreetMap Carto.
 


=====================================
INSTALL.md
=====================================
@@ -26,6 +26,14 @@ osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script o
 
 You can find a more detailed guide to setting up a database and loading data with osm2pgsql at [switch2osm.org](https://switch2osm.org/serving-tiles/manually-building-a-tile-server-16-04-2-lts/).
 
+### Disable JIT
+
+We do not recommend [PostgreSQL JIT](https://www.postgresql.org/docs/current/jit-reason.html), which is on by default in PostgreSQL 12 and higher. JIT is benifitial for slow queries where executing the SQL takes substantial time and that time is not spent in function calls. This is not the case for rendering, where most time is spent either fetching from disk, in PostGIS functions, or the query is fast. In theory, the query planner will only use JIT on slower queries, but it is known to get the type of queries map rendering requries wrong.
+
+Disabling JIT is **essential** for use with Kosmtik and other style development tools.
+
+JIT can be disabled with `psql -d gis -c 'ALTER SYSTEM SET jit=off;' -c 'SELECT pg_reload_conf();'` or any other means of adjusting the PostgreSQL config.
+
 ### Custom indexes
 Custom indexes are required for rendering performance and are essential on full planet databases.
 
@@ -47,49 +55,16 @@ The script downloads shapefiles, loads them into the database and sets up the ta
 ## Fonts
 The stylesheet uses Noto, an openly licensed font family from Google with support for multiple scripts. The stylesheet uses Noto's "Sans" style where available. If not available, this stylesheet uses another appropriate style of the Noto family. The "UI" version is used where available, with its vertical metrics which fit better with Latin text.
 
-DejaVu Sans is used as an optional fallback font for systems without Noto Sans. If all the Noto fonts are installed, it should never be used. Noto Naskh Arabic UI is used an an optional fallback font for systems without Noto Sans Arabic.
-
 Hanazono is used a fallback for seldom used CJK characters that are not covered by Noto.
 
-Unifont is used as a last resort fallback, with it's excellent coverage, common presence on machines, and ugly look. For compatibility reasons, we support two Linux-distributions-specific versions of Unifont, therefore it's expected that you *always* get a warning about a missing Unifont version.
-
-If you do not install all the fonts, the rendering itself will not break, but missing glyphs will be ugly.
-
 For more details, see the documentation at [fonts.mss](style/fonts.mss).
 
-### Installation on Ubuntu/Debian
-
-On Ubuntu 16.04 or Debian Testing you can download and install most of the required fonts
+To download the fonts, run the following script
 
 ```
-sudo apt-get install fonts-noto-cjk fonts-noto-hinted fonts-noto-unhinted fonts-hanazono ttf-unifont
+scripts/get-fonts.sh
 ```
 
-Noto Emoji Regular (*not* Noto Color Emoji) can be downloaded [from the Noto Emoji repository](https://github.com/googlefonts/noto-emoji).
-
-It might be useful to have a more recent version of the fonts for [rare non-latin scripts](#non-latin-scripts). The current upstream font release has also some more scripts and style variants than in the Ubuntu package. It can be installed [from source](https://github.com/googlefonts/noto-fonts/blob/master/FAQ.md#where-are-the-fonts).
-
-DejaVu is packaged as `fonts-dejavu-core`.
-
-### Installation on other operating systems
-
-The fonts can be downloaded here:
-
-* [Noto homepage](https://www.google.com/get/noto/) and [Noto github repositories](https://github.com/googlefonts?utf8=%E2%9C%93&q=noto)
-* [DejaVu homepage](https://dejavu-fonts.org/)
-* [Hanazono homepage](http://fonts.jp/hanazono/)
-* [Unifont homepage](http://unifoundry.com/)
-
-After the download, you have to install the font files in the usual way of your operating system.
-
-### Non-latin scripts
-
-For proper rendering of non-latin scripts, particularly those with complicated diacritics and tone marks the requirements are
-
-* FreeType 2.6.2 or later for CJK characters
-
-* A recent enough version of Noto with coverage for the scripts needed.
-
 ## Dependencies
 
 For development, a style design studio is needed.
@@ -120,9 +95,3 @@ For deployment, CartoCSS and Mapnik are required.
 * [Mapnik](https://github.com/mapnik/mapnik/wiki/Mapnik-Installation) >= 3.0
 
 With CartoCSS you compile these sources into a Mapnik compatible XML file. When running CartoCSS, specify the Mapnik API version you are using (at least 3.0.0: `carto -a "3.0.0"`).
-
-If you're calling Mapnik in your own program, remember to load the XML file in non strict mode. This way, fonts declared with alternative names will only generate warnings, not errors. For instance, using the Python bindings, this becomes:
-
-```python
-mapnik.load_map(mapnik.Map(width, height), xml_filename, False)  # False for non-strict mode
-```


=====================================
RELEASES.md
=====================================
@@ -28,9 +28,9 @@ Decide among the maintainers if a new release is due.
 Dear all,
 
 Today, $NEW_VERSION of the OpenStreetMap Carto stylesheet (the default
-stylesheet on the OSM website) has been released. Once changes are deployed
-on the openstreetmap.org it will take couple of days before all tiles
-show the new rendering.
+stylesheet on the OSM website) has been released. Once changes are
+deployed on the openstreetmap.org it will take couple of days before
+all tiles show the new rendering.
 
 If the tile server admins have rolled out the new version, change it to:
 


=====================================
debian/changelog
=====================================
@@ -1,3 +1,12 @@
+openstreetmap-carto (5.6.2-1) unstable; urgency=medium
+
+  * Team upload.
+  * New upstream release.
+  * Bump Standards-Version to 4.6.1, no changes.
+  * Update lintian overrides.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Thu, 01 Dec 2022 14:11:32 +0100
+
 openstreetmap-carto (5.5.1-1) unstable; urgency=medium
 
   [ Bas Couwenberg ]


=====================================
debian/openstreetmap-carto-common.lintian-overrides
=====================================
@@ -0,0 +1,3 @@
+# Not documentation
+package-contains-documentation-outside-usr-share-doc [usr/share/openstreetmap-carto-common/symbols/*]
+


=====================================
debian/po/sv.po
=====================================
@@ -10,13 +10,13 @@ msgstr ""
 "POT-Creation-Date: 2015-10-11 13:38+0200\n"
 "PO-Revision-Date: 2019-03-25 21:05+0100\n"
 "Last-Translator: Jonatan Nyberg <jonatan.nyberg.karl at gmail.com>\n"
+"Language-Team: \n"
 "Language: sv\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: Poedit 2.2.1\n"
-"Language-Team: \n"
 
 #. Type: boolean
 #. Description
@@ -27,14 +27,24 @@ msgstr "Hämta OpenStreetMap-datafiler från Internet?"
 #. Type: boolean
 #. Description
 #: ../openstreetmap-carto-common.templates:2001
-msgid "The openstreetmap-carto stylesheet uses several data files that must be downloaded from the Internet."
-msgstr "OpenStreetMap-carto-formatmall använder flera datafiler som måste hämtas från Internet."
+msgid ""
+"The openstreetmap-carto stylesheet uses several data files that must be "
+"downloaded from the Internet."
+msgstr ""
+"OpenStreetMap-carto-formatmall använder flera datafiler som måste hämtas "
+"från Internet."
 
 #. Type: boolean
 #. Description
 #: ../openstreetmap-carto-common.templates:2001
-msgid "If you choose not to do this now, it can be done manually later by running the \"get-external-data.py\" script in the /usr/share/openstreetmap-carto-common directory."
-msgstr "Om du väljer att inte göra det nu kan det göras manuellt senare genom att köra \"get-external-data.py\"-skriptet i mappen /usr/share/openstreetmap-carto-common."
+msgid ""
+"If you choose not to do this now, it can be done manually later by running "
+"the \"get-external-data.py\" script in the /usr/share/openstreetmap-carto-"
+"common directory."
+msgstr ""
+"Om du väljer att inte göra det nu kan det göras manuellt senare genom att "
+"köra \"get-external-data.py\"-skriptet i mappen /usr/share/openstreetmap-"
+"carto-common."
 
 #. Type: string
 #. Description
@@ -45,8 +55,12 @@ msgstr "PostgreSQL-databasnamn:"
 #. Type: string
 #. Description
 #: ../openstreetmap-carto.templates:2001
-msgid "The openstreetmap-carto stylesheet uses a PostgreSQL database to store OpenStreetMap data."
-msgstr "OpenStreetMap-carto formatmall använder en PostgreSQL-databas för att lagra OpenStreetMap-data."
+msgid ""
+"The openstreetmap-carto stylesheet uses a PostgreSQL database to store "
+"OpenStreetMap data."
+msgstr ""
+"OpenStreetMap-carto formatmall använder en PostgreSQL-databas för att lagra "
+"OpenStreetMap-data."
 
 #. Type: string
 #. Description


=====================================
docker-compose.yml
=====================================
@@ -41,3 +41,4 @@ services:
       - OSM2PGSQL_CACHE
       - OSM2PGSQL_NUMPROC
       - OSM2PGSQL_DATAFILE
+      - EXTERNAL_DATA_SCRIPT_FLAGS


=====================================
project.mml
=====================================
@@ -103,7 +103,7 @@ Layer:
                                                     'recreation_ground', 'village_green', 'retail', 'industrial', 'railway', 'commercial',
                                                     'brownfield', 'landfill', 'salt_pond', 'construction', 'plant_nursery', 'religious') THEN landuse END)) AS landuse,
               ('shop_' || (CASE WHEN shop IN ('mall') AND (tags->'location' NOT IN ('underground') OR (tags->'location') IS NULL) THEN shop END)) AS shop,
-              ('leisure_' || (CASE WHEN leisure IN ('swimming_pool', 'playground', 'park', 'recreation_ground', 'garden',
+              ('leisure_' || (CASE WHEN leisure IN ('swimming_pool', 'playground', 'park', 'garden',
                                                     'golf_course', 'miniature_golf', 'sports_centre', 'stadium', 'pitch', 'ice_rink',
                                                     'track', 'dog_park', 'fitness_station', 'water_park') THEN leisure END)) AS leisure,
               ('man_made_' || (CASE WHEN man_made IN ('works', 'wastewater_plant', 'water_works') THEN man_made END)) AS man_made,
@@ -635,8 +635,9 @@ Layer:
           WHERE p.highway IN (
             'turning_circle',
             'turning_loop',
-            'mini_roundabout'
-          )
+            'mini_roundabout')
+            AND l.way && !bbox!
+            AND p.way && !bbox! -- Both conditions are necessary for good index usage, even with the DWithin above
           ORDER BY p.way, v.prio
         ) AS turning_circle_sql
     properties:
@@ -1456,23 +1457,28 @@ Layer:
           FROM
           (SELECT -- This subselect allows filtering on the feature column
               way,
-              CONCAT(
-                name,
-                E'\n' || CONCAT( -- by doing this with a || if both the ele and height branches are null, this entire expression is null and only name is used
-                  CASE
-                    WHEN (tags ? 'ele') AND tags->'ele' ~ '^-?\d{1,4}(\.\d+)?$'
-                      AND ("natural" IN ('peak', 'volcano', 'saddle')
-                        OR tourism = 'alpine_hut' OR (tourism = 'information' AND tags->'information' = 'guidepost')
-                        OR amenity = 'shelter'
-                        OR tags->'mountain_pass' = 'yes')
-                    THEN CONCAT(REPLACE(ROUND((tags->'ele')::NUMERIC)::TEXT, '-', U&'\2212'), U&'\00A0', 'm') END,
-                  CASE
-                    WHEN (tags ? 'height') AND tags->'height' ~ '^\d{1,3}(\.\d+)?$'
-                      AND waterway = 'waterfall'
-                    THEN CONCAT(ROUND((tags->'height')::NUMERIC)::TEXT, U&'\00A0', 'm') END
+              CASE
+                WHEN amenity = 'parcel_locker'
+                THEN CONCAT_WS(E'\n', COALESCE(tags->'brand', tags->'operator', name), ref)
+                ELSE
+                CONCAT(
+                  name,
+                  E'\n' || CONCAT( -- by doing this with a || if both the ele and height branches are null, this entire expression is null and only name is used
+                    CASE
+                      WHEN (tags ? 'ele') AND tags->'ele' ~ '^-?\d{1,4}(\.\d+)?$'
+                        AND ("natural" IN ('peak', 'volcano', 'saddle')
+                          OR tourism = 'alpine_hut' OR (tourism = 'information' AND tags->'information' = 'guidepost')
+                          OR (amenity = 'shelter' AND tags->'shelter_type' NOT IN ('public_transport', 'picnic_shelter'))
+                          OR tags->'mountain_pass' = 'yes')
+                      THEN CONCAT(REPLACE(ROUND((tags->'ele')::NUMERIC)::TEXT, '-', U&'\2212'), U&'\00A0', 'm') END,
+                    CASE
+                      WHEN (tags ? 'height') AND tags->'height' ~ '^\d{1,3}(\.\d+)?$'
+                        AND waterway = 'waterfall'
+                      THEN CONCAT(ROUND((tags->'height')::NUMERIC)::TEXT, U&'\00A0', 'm') END
+                    )
                   )
-                ) AS name,
-                tags->'parking' as "parking",
+                END AS name,
+              tags->'parking' as "parking",
               COALESCE(
                 'aeroway_' || CASE WHEN aeroway IN ('gate', 'apron', 'helipad', 'aerodrome') THEN aeroway END,
                 'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'apartment', 'artwork', 'camp_site', 'caravan_site', 'chalet', 'gallery', 'guest_house',
@@ -1490,13 +1496,14 @@ Layer:
                                                     'university', 'vehicle_inspection', 'veterinary') THEN amenity END,
                 'amenity_' || CASE WHEN amenity IN ('waste_disposal') AND way_area IS NOT NULL THEN amenity END, -- Waste disposal points are rendered in the low priority layer
                 'amenity_' || CASE WHEN amenity IN ('vending_machine') AND tags->'vending' IN ('excrement_bags', 'parking_tickets', 'public_transport_tickets') THEN amenity END,
+                'amenity_' || CASE WHEN amenity IN ('parcel_locker') THEN amenity END,
                 'diplomatic_'|| CASE WHEN tags->'office' IN ('diplomatic') AND tags->'diplomatic' IN ('embassy', 'consulate') THEN tags->'diplomatic' ELSE NULL END,
                 'advertising_' || CASE WHEN tags->'advertising' in ('column') THEN tags->'advertising' END,
                 'emergency_' || CASE WHEN tags->'emergency' IN ('phone') AND way_area IS NULL THEN tags->'emergency' END,
                 'shop' || CASE WHEN shop IN ('yes', 'no', 'vacant', 'closed', 'disused', 'empty') OR shop IS NULL THEN NULL ELSE '' END,
                 'leisure_' || CASE WHEN leisure IN ('amusement_arcade', 'beach_resort', 'bird_hide', 'bowling_alley', 'dog_park', 'firepit', 'fishing',
                                                     'fitness_centre', 'fitness_station', 'garden', 'golf_course', 'ice_rink', 'marina', 'miniature_golf',
-                                                    'outdoor_seating', 'park', 'picnic_table', 'pitch', 'playground', 'recreation_ground',
+                                                    'outdoor_seating', 'park', 'picnic_table', 'pitch', 'playground',
                                                     'sauna', 'slipway', 'sports_centre', 'stadium', 'swimming_area', 'swimming_pool', 'track', 'water_park') THEN leisure END,
                 'power_' || CASE WHEN power IN ('plant', 'generator', 'substation') THEN power END,
                 'man_made_' || CASE WHEN (man_made IN ('chimney', 'communications_tower', 'crane', 'lighthouse', 'mast', 'obelisk', 'silo', 'storage_tank',
@@ -1970,8 +1977,7 @@ Layer:
             COALESCE(
               'landuse_' || CASE WHEN landuse IN ('forest', 'military', 'farmland') THEN landuse END,
               'military_' || CASE WHEN military IN ('danger_area') THEN military END,
-              'natural_' || CASE WHEN "natural" IN ('wood', 'glacier', 'sand', 'scree', 'shingle', 'bare_rock',
-                                                    'water', 'bay', 'strait') THEN "natural" END,
+              'natural_' || CASE WHEN "natural" IN ('wood', 'glacier', 'sand', 'scree', 'shingle', 'bare_rock', 'water') THEN "natural" END,
               'place_' || CASE WHEN place IN ('island') THEN place END,
               'boundary_' || CASE WHEN boundary IN ('aboriginal_lands', 'national_park')
                                        OR (boundary = 'protected_area' AND tags->'protect_class' IN ('1','1a','1b','2','3','4','5','6'))
@@ -1985,7 +1991,7 @@ Layer:
             AND name IS NOT NULL
             AND (landuse IN ('forest', 'military', 'farmland')
               OR military IN ('danger_area')
-              OR "natural" IN ('wood', 'glacier', 'sand', 'scree', 'shingle', 'bare_rock', 'water', 'bay', 'strait')
+              OR "natural" IN ('wood', 'glacier', 'sand', 'scree', 'shingle', 'bare_rock', 'water')
               OR "place" IN ('island')
               OR boundary IN ('aboriginal_lands', 'national_park')
               OR (boundary = 'protected_area' AND tags->'protect_class' IN ('1','1a','1b','2','3','4','5','6'))
@@ -1996,7 +2002,7 @@ Layer:
           ORDER BY way_area DESC
         ) AS text_poly_low_zoom
     properties:
-      minzoom: 0
+      minzoom: 4
       maxzoom: 9
   - id: text-line
     geometry: linestring


=====================================
scripts/docker-startup.sh
=====================================
@@ -31,6 +31,7 @@ PG_MAINTENANCE_WORK_MEM=${PG_MAINTENANCE_WORK_MEM:-256MB}
 OSM2PGSQL_CACHE=${OSM2PGSQL_CACHE:-512}
 OSM2PGSQL_NUMPROC=${OSM2PGSQL_NUMPROC:-1}
 OSM2PGSQL_DATAFILE=${OSM2PGSQL_DATAFILE:-data.osm.pbf}
+EXTERNAL_DATA_SCRIPT_FLAGS=${EXTERNAL_DATA_SCRIPT_FLAGS:-}
 EOF
     chmod a+rw .env
     export OSM2PGSQL_CACHE=${OSM2PGSQL_CACHE:-512}
@@ -51,8 +52,11 @@ EOF
   --tag-transform-script openstreetmap-carto.lua \
   $OSM2PGSQL_DATAFILE
 
-  # Downloading needed shapefiles
-  scripts/get-external-data.py
+  # Downloading and importing needed shapefiles
+  scripts/get-external-data.py $EXTERNAL_DATA_SCRIPT_FLAGS
+
+  # Download fonts
+  scripts/get-fonts.sh
   ;;
 
 kosmtik)


=====================================
scripts/get-external-data.py
=====================================
@@ -14,6 +14,7 @@ Some implicit assumptions are
 '''
 
 import yaml
+from urllib.parse import urlparse
 import os
 import re
 import argparse
@@ -148,7 +149,7 @@ class Downloader:
     def _download(self, url, headers=None):
         if url.startswith('file://'):
             filename = url[7:]
-            if headers and 'If-Modified-Since' in headers and os.path.exists(filename):
+            if headers and 'If-Modified-Since' in headers:
                 if str(os.path.getmtime(filename)) == headers['If-Modified-Since']:
                     return DownloadResult(status_code = requests.codes.not_modified)
             with open(filename, 'rb') as fp:
@@ -159,54 +160,65 @@ class Downloader:
         return DownloadResult(status_code = response.status_code, content = response.content,
                               last_modified = response.headers.get('Last-Modified', None))
 
-    @staticmethod
-    def _return_or_raise(response):
-        if response.status_code != requests.codes.ok:
-            raise RuntimeError('Unsupported HTTP response code {}, expected {} OK'.format(
-                response.status_code, requests.codes.ok))
-        return response
-
-    def download(self, url):
-        response = self._download(url)
-        return self._return_or_raise(response)
-
-    def download_if_newer(self, url, last_modified):
-        headers = {}
-        if last_modified:
-            headers['If-Modified-Since'] = last_modified
-        response = self._download(url, headers)
-        if response.status_code == requests.codes.not_modified:
-            return None
-        return self._return_or_raise(response)
-
-    def download_cache(self, url, last_modified):
-        filename = os.path.basename(url)
+    def download(self, url, name, opts, data_dir, table_last_modified):
+        filename = os.path.join(data_dir, os.path.basename(urlparse(url).path))
         filename_lastmod = filename + '.lastmod'
-
-        # Check if cached version exists
         if os.path.exists(filename) and os.path.exists(filename_lastmod):
             with open(filename_lastmod, 'r') as fp:
-                lastmod = fp.read()
-            # Revalidate cache entry
-            result = self.download_if_newer(url, lastmod)
-
-            # Check if cache is up to date and DB last modified differs
-            if result is None and lastmod != last_modified:
-                with open(filename, 'rb') as fp:
-                    # Return cached document
-                    return DownloadResult(status_code = 200, content = fp.read(),
-                                          last_modified = lastmod)
+                lastmod_cache = fp.read()
+            with open(filename, 'rb') as fp:
+                cached_data = DownloadResult(status_code = 200, content = fp.read(),
+                                             last_modified = lastmod_cache)
         else:
-            # Download a file normally, no cached version
-            result = self.download(url)
+            cached_data = None
+            lastmod_cache = None
+
+        result = None
+        # Variable used to tell if we downloaded something
+        download_happened = False
+
+        if opts.no_update and (cached_data or table_last_modified):
+            # It is ok if this returns None, because for this to be None, 
+            # we need to have something in table and therefore need not import (since we are opts.no-update)
+            result = cached_data
+        else:
+            if opts.force:
+                headers = {}
+            else:
+                # If none of those 2 exist, value will be None and it will have the same effect as not having If-Modified-Since set
+                headers = {'If-Modified-Since': table_last_modified or lastmod_cache}
+
+            response = self._download(url, headers)
+            # Check status codes
+            if response.status_code == requests.codes.ok:
+                logging.info("  Download complete ({} bytes)".format(len(response.content)))
+                download_happened = True
+                if opts.cache:
+                    # Write to cache
+                    with open(filename, 'wb') as fp:
+                        fp.write(response.content)
+                    with open(filename_lastmod, 'w') as fp:
+                        fp.write(response.last_modified)
+                result = response
+            elif response.status_code == requests.codes.not_modified:
+                # Now we need to figure out if our not modified data came from table or cache
+                if os.path.exists(filename) and os.path.exists(filename_lastmod):
+                    logging.info("  Cached file {} did not require updating".format(url))
+                    result = cached_data
+                else:
+                    result = None
+            else:
+                logging.critical("  Unexpected response code ({}".format(response.status_code))
+                logging.critical("  Content {} was not downloaded".format(name))
+                return None
+
 
-        # We had a cache miss or nothing in cache
-        if result is not None and result.last_modified is not None:
-            # Cache downloaded file
-            with open(filename, 'wb') as fp:
-                fp.write(result.content)
-            with open(filename_lastmod, 'w') as fp:
-                fp.write(result.last_modified)
+        if opts.delete_cache or (not opts.cache and download_happened):
+            try:
+                os.remove(filename)
+                os.remove(filename_lastmod)
+            except FileNotFoundError:
+                pass
 
         return result
 
@@ -224,9 +236,16 @@ def main():
         description="Load external data into a database")
 
     parser.add_argument("-f", "--force", action="store_true",
-                        help="Download new data, even if not required")
+                        help="Download and import new data, even if not required.")
     parser.add_argument("-C", "--cache", action="store_true",
-                        help="Cache downloaded data and use cache if possible")
+                        help="Cache downloaded data. Useful if you'll have your database volume deleted in the future")
+    parser.add_argument("--no-update", action="store_true",
+                        help="Don't download newer data than what is locally available (either in cache or table). Overridden by --force")
+
+    parser.add_argument("--delete-cache", action="store_true",
+                        help="Execute as usual, but delete cached data")
+    parser.add_argument("--force-import", action="store_true",
+                        help="Import data into table even if may not be needed")
 
     parser.add_argument("-c", "--config", action="store", default="external-data.yml",
                         help="Name of configuration file (default external-data.yml)")
@@ -260,6 +279,10 @@ def main():
     else:
         logging.basicConfig(level=logging.INFO)
 
+    if opts.force and opts.no_update:
+        opts.no_update = False
+        logging.warning("Force (-f) flag overrides --no-update flag")
+
     logging.info("Starting load of external data into database")
 
     with open(opts.config) as config_file:
@@ -298,85 +321,81 @@ def main():
                     raise RuntimeError(
                         "Only ASCII alphanumeric table are names supported")
 
-                workingdir = os.path.join(data_dir, name)
-                # Clean up anything left over from an aborted run
-                shutil.rmtree(workingdir, ignore_errors=True)
-
-                os.makedirs(workingdir, exist_ok=True)
-
                 this_table = Table(name, conn,
                                    config["settings"]["temp_schema"],
                                    config["settings"]["schema"],
                                    config["settings"]["metadata_table"])
                 this_table.clean_temp()
 
-                if opts.force:
-                    download = d.download(source["url"])
-                elif opts.cache:
-                    download = d.download_cache(source["url"], this_table.last_modified())
-                else:
-                    download = d.download_if_newer(source["url"], this_table.last_modified())
+                # This will fetch data needed for import
+                download = d.download(source["url"], name, opts, data_dir, this_table.last_modified())
 
-                if download is None:
+                # Check if there is need to import
+                if download == None or (not opts.force and not opts.force_import and this_table.last_modified() == download.last_modified):
                     logging.info("  Table {} did not require updating".format(name))
-                else:
-                    logging.info("  Download complete ({} bytes)".format(len(download.content)))
-
-                    if "archive" in source and source["archive"]["format"] == "zip":
-                        logging.info("  Decompressing file")
-                        zip = zipfile.ZipFile(io.BytesIO(download.content))
-                        for member in source["archive"]["files"]:
-                            zip.extract(member, workingdir)
-
-                    ogrpg = "PG:dbname={}".format(database)
-
-                    if port is not None:
-                        ogrpg = ogrpg + " port={}".format(port)
-                    if user is not None:
-                        ogrpg = ogrpg + " user={}".format(user)
-                    if host is not None:
-                        ogrpg = ogrpg + " host={}".format(host)
-                    if password is not None:
-                        ogrpg = ogrpg + " password={}".format(password)
-
-                    ogrcommand = ["ogr2ogr",
-                                  '-f', 'PostgreSQL',
-                                  '-lco', 'GEOMETRY_NAME=way',
-                                  '-lco', 'SPATIAL_INDEX=FALSE',
-                                  '-lco', 'EXTRACT_SCHEMA_FROM_LAYER_NAME=YES',
-                                  '-nln', "{}.{}".format(config["settings"]["temp_schema"], name)]
-
-                    if "ogropts" in source:
-                        ogrcommand += source["ogropts"]
-
-                    ogrcommand += [ogrpg,
-                                   os.path.join(workingdir, source["file"])]
-
-                    logging.info("  Importing into database")
-                    logging.debug("running {}".format(
-                        subprocess.list2cmdline(ogrcommand)))
-
-                    # ogr2ogr can raise errors here, so they need to be caught
-                    try:
-                        subprocess.check_output(
-                            ogrcommand, stderr=subprocess.PIPE, universal_newlines=True)
-                    except subprocess.CalledProcessError as e:
-                        # Add more detail on stdout for the logs
-                        logging.critical(
-                            "ogr2ogr returned {} with layer {}".format(e.returncode, name))
-                        logging.critical("Command line was {}".format(
-                            subprocess.list2cmdline(e.cmd)))
-                        logging.critical("Output was\n{}".format(e.output))
-                        logging.critical("Error was\n{}".format(e.stderr))
-                        raise RuntimeError(
-                            "ogr2ogr error when loading table {}".format(name))
-
-                    logging.info("  Import complete")
-
-                    this_table.index()
-                    if renderuser is not None:
-                        this_table.grant_access(renderuser)
-                    this_table.replace(download.last_modified)
+                    continue
+
+
+                workingdir = os.path.join(data_dir, name)
+                shutil.rmtree(workingdir, ignore_errors=True)
+                os.makedirs(workingdir, exist_ok=True)
+                if "archive" in source and source["archive"]["format"] == "zip":
+                    logging.info("  Decompressing file")
+                    zip = zipfile.ZipFile(io.BytesIO(download.content))
+                    for member in source["archive"]["files"]:
+                        zip.extract(member, workingdir)
+
+                ogrpg = "PG:dbname={}".format(database)
+
+                if port is not None:
+                    ogrpg = ogrpg + " port={}".format(port)
+                if user is not None:
+                    ogrpg = ogrpg + " user={}".format(user)
+                if host is not None:
+                    ogrpg = ogrpg + " host={}".format(host)
+                if password is not None:
+                    ogrpg = ogrpg + " password={}".format(password)
+
+                ogrcommand = ["ogr2ogr",
+                                '-f', 'PostgreSQL',
+                                '-lco', 'GEOMETRY_NAME=way',
+                                '-lco', 'SPATIAL_INDEX=FALSE',
+                                '-lco', 'EXTRACT_SCHEMA_FROM_LAYER_NAME=YES',
+                                '-nln', "{}.{}".format(config["settings"]["temp_schema"], name)]
+
+                if "ogropts" in source:
+                    ogrcommand += source["ogropts"]
+
+                ogrcommand += [ogrpg,
+                                os.path.join(workingdir, source["file"])]
+
+                logging.info("  Importing into database")
+                logging.debug("running {}".format(
+                    subprocess.list2cmdline(ogrcommand)))
+
+                # ogr2ogr can raise errors here, so they need to be caught
+                try:
+                    subprocess.check_output(
+                        ogrcommand, stderr=subprocess.PIPE, universal_newlines=True)
+                except subprocess.CalledProcessError as e:
+                    # Add more detail on stdout for the logs
+                    logging.critical(
+                        "ogr2ogr returned {} with layer {}".format(e.returncode, name))
+                    logging.critical("Command line was {}".format(
+                        subprocess.list2cmdline(e.cmd)))
+                    logging.critical("Output was\n{}".format(e.output))
+                    logging.critical("Error was\n{}".format(e.stderr))
+                    raise RuntimeError(
+                        "ogr2ogr error when loading table {}".format(name))
+
+                logging.info("  Import complete")
+
+                this_table.index()
+                if renderuser is not None:
+                    this_table.grant_access(renderuser)
+                this_table.replace(download.last_modified)
+
+                shutil.rmtree(workingdir, ignore_errors=True)
 
             if conn:
                 conn.close()


=====================================
scripts/get-fonts.sh
=====================================
@@ -0,0 +1,133 @@
+#!/bin/sh
+set -e
+
+FONTDIR="./fonts"
+
+mkdir -p "${FONTDIR}"
+
+# download filename url
+download() {
+  ## Download if newer, and if curl fails, clean up and exit
+  curl --fail --compressed -A "get-fonts.sh/osm-carto" -o "$1" -z "$1" -L "$2" || { echo "Failed to download $1 $2"; rm -f "$1"; exit 1; }
+}
+
+# TTF Hinted Noto Fonts
+
+# Fonts available in regular, bold, and italic
+REGULAR_BOLD_ITALIC="NotoSans"
+
+# Fonts available in regular and bold
+REGULAR_BOLD="NotoSansAdlam
+NotoSansAdlamUnjoined
+NotoSansArabicUI
+NotoSansArmenian
+NotoSansBalinese
+NotoSansBamum
+NotoSansBengaliUI
+NotoSansCanadianAboriginal
+NotoSansCham
+NotoSansCherokee
+NotoSansDevanagariUI
+NotoSansEthiopic
+NotoSansGeorgian
+NotoSansGujaratiUI
+NotoSansGurmukhiUI
+NotoSansHebrew
+NotoSansJavanese
+NotoSansKannadaUI
+NotoSansKayahLi
+NotoSansKhmerUI
+NotoSansLaoUI
+NotoSansLisu
+NotoSansMalayalamUI
+NotoSansMyanmarUI
+NotoSansOlChiki
+NotoSansOriyaUI
+NotoSansSinhalaUI
+NotoSansSundanese
+NotoSansSymbols
+NotoSansTaiTham
+NotoSansTamilUI
+NotoSansTeluguUI
+NotoSansThaana
+NotoSansThaiUI
+NotoSerifTibetan"
+
+# Fonts with regular and black, but no bold
+REGULAR_BLACK="NotoSansSyriac"
+
+# Fonts only available in regular
+REGULAR="NotoSansBatak
+NotoSansBuginese
+NotoSansBuhid
+NotoSansChakma
+NotoSansCoptic
+NotoSansHanunoo
+NotoSansLepcha
+NotoSansLimbu
+NotoSansMandaic
+NotoSansMongolian
+NotoSansNewTaiLue
+NotoSansNKo
+NotoSansOsage
+NotoSansOsmanya
+NotoSansSamaritan
+NotoSansSaurashtra
+NotoSansShavian
+NotoSansSymbols2
+NotoSansTagalog
+NotoSansTagbanwa
+NotoSansTaiLe
+NotoSansTaiViet
+NotoSansTifinagh
+NotoSansVai
+NotoSansYi"
+
+# Download the fonts in the lists above
+
+for font in $REGULAR_BOLD_ITALIC; do
+  regular="$font-Regular.ttf"
+  bold="$font-Bold.ttf"
+  italic="$font-Italic.ttf"
+  download "${FONTDIR}/${regular}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${regular}"
+  download "${FONTDIR}/${bold}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${bold}"
+  download "${FONTDIR}/${italic}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${italic}"
+done
+
+for font in $REGULAR_BOLD; do
+  regular="$font-Regular.ttf"
+  bold="$font-Bold.ttf"
+  download "${FONTDIR}/${regular}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${regular}"
+  download "${FONTDIR}/${bold}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${bold}"
+done
+
+for font in $REGULAR_BLACK; do
+  regular="$font-Regular.ttf"
+  black="$font-Black.ttf"
+  download "${FONTDIR}/${regular}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${regular}"
+  download "${FONTDIR}/${black}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${black}"
+done
+
+for font in $REGULAR; do
+  regular="$font-Regular.ttf"
+  download "${FONTDIR}/${regular}" "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/${font}/${regular}"
+done
+
+# Other noto fonts which don't follow the URL pattern above
+download "${FONTDIR}/NotoSansCJKjp-Regular.otf" "https://github.com/googlefonts/noto-cjk/raw/main/Sans/OTF/Japanese/NotoSansCJKjp-Regular.otf"
+download "${FONTDIR}/NotoSansCJKjp-Bold.otf" "https://github.com/googlefonts/noto-cjk/raw/main/Sans/OTF/Japanese/NotoSansCJKjp-Bold.otf"
+
+# Fonts in zipfiles need a temporary directory
+TMPDIR=$(mktemp -d -t get-fonts.XXXXXXXXX)
+trap "rm -rf ${TMPDIR} ${FONTDIR}/static" EXIT
+
+# Noto Emoji B&W isn't available as a separate download, so we need to download the package and unzip it
+curl --fail -A "get-fonts.sh/osm-carto" -o "${TMPDIR}/Noto_Emoji.zip" -L 'https://fonts.google.com/download?family=Noto%20Emoji'
+
+unzip -oqq "${TMPDIR}/Noto_Emoji.zip" static/NotoEmoji-Regular.ttf static/NotoEmoji-Bold.ttf -d "${FONTDIR}"
+mv "${FONTDIR}/static/NotoEmoji-Regular.ttf" "${FONTDIR}"
+mv "${FONTDIR}/static/NotoEmoji-Bold.ttf" "${FONTDIR}"
+
+curl --fail -A "get-fonts.sh/osm-carto" -o "${TMPDIR}/hanazono.zip" -L 'https://osdn.net/frs/redir.php?f=hanazono-font%2F68253%2Fhanazono-20170904.zip'
+
+unzip -oqq "${TMPDIR}/hanazono.zip" HanaMinA.ttf HanaMinB.ttf -d "${FONTDIR}"


=====================================
style/amenity-points.mss
=====================================
@@ -192,6 +192,18 @@
     marker-clip: false;
   }
 
+  [feature = 'amenity_parcel_locker'][zoom >= 17] {
+    marker-fill: @amenity-brown;
+    [zoom >= 17][zoom < 18] {
+      marker-width: 4;
+      marker-line-width: 0;
+    }
+    [zoom >= 18] {
+      marker-file: url('symbols/amenity/parcel_locker.svg');
+      marker-clip: false;
+    }
+  }
+
   [feature = 'highway_traffic_signals'][zoom >= 17] {
     marker-file: url('symbols/highway/traffic_light.svg');
     marker-fill: #545454;
@@ -2150,7 +2162,6 @@
   [feature = 'natural_wetland'],
   [feature = 'natural_mud'],
   [feature = 'leisure_park'],
-  [feature = 'leisure_recreation_ground'],
   [feature = 'landuse_recreation_ground'],
   [feature = 'landuse_village_green'],
   [feature = 'leisure_garden'],
@@ -2202,8 +2213,8 @@
   [feature = 'leisure_pitch'] {
     [zoom >= 10][way_pixels > 3000][is_building = 'no'],
     [zoom >= 17][is_building = 'no'],
-    [zoom >= 10][way_pixels > 3000][shop = 'mall'],
-    [zoom >= 17][shop = 'mall'] {
+    [zoom >= 10][way_pixels > 3000][feature = 'shop'][shop = 'mall'],
+    [zoom >= 17][feature = 'shop'][shop = 'mall'] {
       text-name: "[name]";
       text-size: @landcover-font-size;
       text-wrap-width: @landcover-wrap-width-size;
@@ -2228,7 +2239,6 @@
         text-fill: @wetland-text;
       }
       [feature = 'leisure_park'],
-      [feature = 'leisure_recreation_ground'],
       [feature = 'landuse_recreation_ground'],
       [feature = 'landuse_village_green'],
       [feature = 'leisure_garden'] {
@@ -2522,8 +2532,7 @@
     text-halo-fill: @standard-halo-fill;
   }
 
-  [feature = 'amenity_hospital'][zoom >= 16],
-  [feature = 'healthcare_hospital'][zoom >= 16] {
+  [feature = 'amenity_hospital'][zoom >= 16] {
     text-name: "[name]";
     text-fill: @health-color;
     text-size: @standard-font-size;
@@ -2540,27 +2549,7 @@
   [feature = 'amenity_pharmacy'],
   [feature = 'amenity_doctors'],
   [feature = 'amenity_dentist'],
-  [feature = 'amenity_veterinary'],
-  [feature = 'healthcare_alternative'],
-  [feature = 'healthcare_audiologist'],
-  [feature = 'healthcare_birthing_center'],
-  [feature = 'healthcare_blood_bank'],
-  [feature = 'healthcare_blood_donation'],
-  [feature = 'healthcare_centre'],
-  [feature = 'healthcare_clinic'],
-  [feature = 'healthcare_dentist'],
-  [feature = 'healthcare_dialysis'],
-  [feature = 'healthcare_doctor'],
-  [feature = 'healthcare_laboratory'],
-  [feature = 'healthcare_midwife'],
-  [feature = 'healthcare_occupational_therapist'],
-  [feature = 'healthcare_optometrist'],
-  [feature = 'healthcare_physiotherapist'],
-  [feature = 'healthcare_podiatrist'],
-  [feature = 'healthcare_psychotherapist'],
-  [feature = 'healthcare_rehabilitation'],
-  [feature = 'healthcare_speech_therapist'],
-  [feature = 'healthcare_yes'] {
+  [feature = 'amenity_veterinary'] {
     [zoom >= 17] {
       text-name: "[name]";
       text-size: @standard-font-size;
@@ -2976,6 +2965,18 @@
       [feature = 'amenity_motorcycle_parking'] { text-dy: 12; }
     }
   }
+
+  [feature = 'amenity_parcel_locker'][zoom >= 18] {
+    text-name: "[name]";
+    text-dy: 10;
+    text-size: @standard-font-size;
+    text-wrap-width: @standard-wrap-width;
+    text-line-spacing: @standard-line-spacing-size;
+    text-fill: @amenity-brown;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
+    text-halo-fill: @standard-halo-fill;
+  }
 }
 
 #text-low-priority {
@@ -3076,9 +3077,9 @@
 
 #trees [zoom >= 16] {
   ::canopy {
-    opacity: 0.3;
+    opacity: 0.6;
     [natural = 'tree_row'] {
-      line-color: green;
+      line-color: darken(@forest,10%);
       line-cap: round;
       line-width: 2.5;
       [zoom >= 17] {
@@ -3095,11 +3096,17 @@
       }
     }
     [natural = 'tree'] {
+      marker-fill: darken(@forest,10%);
+      marker-allow-overlap: true;
+      marker-line-width: 0;
+      marker-ignore-placement: true;
+      marker-width: 2.5;
+      marker-height: 2.5;
+      [zoom >= 17] {
+        marker-width: 5;
+        marker-height: 5;
+      }
       [zoom >= 18] {
-        marker-fill: green;
-        marker-allow-overlap: true;
-        marker-line-width: 0;
-        marker-ignore-placement: true;
         marker-width: 10;
         marker-height: 10;
       }
@@ -3115,7 +3122,8 @@
   }
   [natural = 'tree']::trunk {
     [zoom >= 18] {
-      trunk/marker-fill: #b27f36;
+      trunk/opacity: 0.4;
+      trunk/marker-fill: #6b8d5e; // Same opacity and color as forest svg patterns
       trunk/marker-allow-overlap: true;
       trunk/marker-line-width: 0;
       trunk/marker-width: 2;


=====================================
style/fonts.mss
=====================================
@@ -2,81 +2,57 @@
 About fonts:
 
 Noto is a font family that wants to cover most of Unicode with a harmonic
-design across various scripts. We use Noto for most text, with some support
-for backward-compatibility and some fallback fonts.
+design across various scripts. We use Noto for most text and some fallback fonts.
 
 By order:
 
 1. Noto Sans is available for most scripts and it is used as a first choice.
 Where available the UI version of the fonts – which provides tighter vertical
-metrics – is used (except for the base font, where the UI version is deprecated
-since Noto Phase III, and Sinhala where both versions are used for backwards
-compatibility with Ubuntu 16.04). We intent to have all scripts of Noto in
+metrics – is used. We intent to have all scripts of Noto in
 our list except dead (historic) scripts of whom we assume that they are not
 used in “name” tags in OSM. Most of the list is in alphabetical order,
 but there are some exceptions.
 
   - Noto Sans is before all other fonts
-  - The CJK fonts are manually ordered. The used CJK font covers all CJK
-    languages, but defaults to the japanese glyph style if various glyph
-    styles are available. We have to default to one of JP, KR, SC, TC because
-    this carto style has no knowledge about what language the “names” tag
-    contains. As in Korea Han characters are not so widely used, it seems
-    better to default to either Chinese or Japanese. As Chinese exists in the
-    two variants SC/TC, it won’t be a uniform rendering anyway. So we default
-    to Japanese. However, this choice stays somewhat arbitrary and subjective.
-    See also https://github.com/gravitystorm/openstreetmap-carto/issues/2208
-  - For the Syriac script, there exist Noto Sans Syriac Eastern,
-    Noto Sans Syriac Western Regular and Noto Sans Syriac Estrangela Regular.
-    As for CJK fonts, we have no knowledge about what language the “names” tag
-    contains. We choose Syriac Eastern because it seems to be the most
-    widespreaded script variant (Syriac Western is less common, and Syriac
-    Estrangela mostly of historic interest.)
-
-2. Noto provides various variants of Arabic: Noto Kufi Arabic, Noto Naskh
-Arabic, Noto Nastaliq Urdu and Noto Sans Arabic. Kufi and Urdu styles are not
-widespread in use. Noto Sans Arabic (a Naskh-style low-contrast “Sans” font) and
-Noto Naskh Arabic are the fonts with the greatest coverage and provide an UI
-variant. This style uses Noto Sans Arabic UI because it’s consistent with the
-other Sans fonts and legible. The Arabic fonts are placed behind Sans fonts
-because they might re-define some commonly used signs like parenthesis or
-quotation marks, and the arabic design should not overwrite the standard design.
-The list still includes Noto Naskh Arabic UI for compatibility on systems
-without Noto Sans Arabic UI.
-
-3. Noto Serif is used for scripts that are not supported by Noto Sans. Currently
+
+  - Noto Sans Arabic and Noto Sanc CJK JP are placed behind sans fonts because
+    commonly used signs like parenthesis or quotation marks, and their design
+    should not overwrite the standard design.
+
+The used CJK font covers all CJK languages, but defaults to the Japanese
+glyph style if various glyph styles are available. We have to default to one
+of JP, KR, SC, TC because this style has no knowledge about what language the
+“names” tag contains. As in Korea Han characters are not so widely used, it is
+better to default to either Chinese or Japanese. As Chinese exists in the two
+variants SC/TC, it won’t be a uniform rendering anyway. So we default to
+Japanese. However, this choice stays somewhat arbitrary and subjective.
+
+Noto provides multiple designs for the Arabic script. This style uses
+Noto Sans Arabic UI because it’s consistent with the other Sans
+fonts and legible.
+
+2. Noto Serif is used for scripts that are not supported by Noto Sans. Currently
 this is only Tibetan: The old Noto Sans Tibetan has been renamed to Noto Serif
-Tibetan in 2015, since then only Noto Serif Tibetan gets updated. We still
-include the old one for compatibility on systems without Noto Serif Tibetan.
-See also https://github.com/googlefonts/noto-fonts/issues/1540
+Tibetan in 2015, since then only Noto Serif Tibetan gets updated.
 
-4. Noto provides two variants of Emoji: Noto Color Emoji and Noto Emoji. The
+3. Noto provides two variants of Emoji: Noto Color Emoji and Noto Emoji. The
 colour variant is a SVG flavoured OpenType font that contains coloured emojis.
 This is not useful in cartography, so we use the “normal” monochromatic
 Noto Emoji.
 
-5. The list still includes DejaVu for compatibility on systems without Noto.
-
-6. Fallback fonts. Hanazono covers almost all CJK characters, even in Unicode
-Plane 2. Unifont is a fallback of last resort with full coverage in Plane 0
-(Unifont Medium), some coverage in Plane 1 (Unifont Upper Medium) and no
-coverage in Plane 2. Unifont has different font names on different Linux
-distributions (and sometimes even in different versions of the same Linux
-distribution), see #429 and #2924 for details. We have therefore both,
-“Unifont Medium” and “unifont Medium” in our list, so on almost all
-distributions we catch the font if installed – and you will always get an error
-message for the other missing font name. We prefer having an error message than
-requiring our users to customize the font list depending on their Linux
-distribution. Unifont Medium Sample would cover the BMP PUA with
-replacement characters, but cannot be used because Mapnik does not
-support SBIT TTF.
+4. Fallback fonts. Hanazono covers almost all CJK characters, even in Unicode
+Plane 2.
 */
 
+/* Use vendored fonts. This allows for more recent versions and better coverage */
+Map {
+  font-directory: url('fonts');
+}
+
 /*
 A regular style.
 */
 @book-fonts:    "Noto Sans Regular",
-                "Noto Sans CJK JP Regular",
                 "Noto Sans Adlam Regular",
                 "Noto Sans Adlam Unjoined Regular",
                 "Noto Sans Armenian Regular",
@@ -119,11 +95,11 @@ A regular style.
                 "Noto Sans Samaritan Regular",
                 "Noto Sans Saurashtra Regular",
                 "Noto Sans Shavian Regular",
-                "Noto Sans Sinhala UI Regular", "Noto Sans Sinhala Regular",
+                "Noto Sans Sinhala UI Regular",
                 "Noto Sans Sundanese Regular",
                 "Noto Sans Symbols Regular",
                 "Noto Sans Symbols2 Regular",
-                "Noto Sans Syriac Eastern Regular",
+                "Noto Sans Syriac Regular",
                 "Noto Sans Tagalog Regular",
                 "Noto Sans Tagbanwa Regular",
                 "Noto Sans Tai Le Regular",
@@ -136,26 +112,27 @@ A regular style.
                 "Noto Sans Tifinagh Regular",
                 "Noto Sans Vai Regular",
                 "Noto Sans Yi Regular",
-
-                "Noto Sans Arabic UI Regular", "Noto Naskh Arabic UI Regular",
+                "Noto Sans CJK JP Regular",
+                "Noto Sans Arabic UI Regular",
                 
-                "Noto Serif Tibetan Regular", "Noto Sans Tibetan Regular",
+                "Noto Serif Tibetan Regular",
 
                 "Noto Emoji Regular",
 
-                "DejaVu Sans Book",
-
-                "HanaMinA Regular", "HanaMinB Regular",
-                "Unifont Medium", "unifont Medium", "Unifont Upper Medium";
+                "HanaMinA Regular", "HanaMinB Regular";
 
 /*
 A bold style is available for almost all scripts. Bold text is heavier than
 regular text and can be used for emphasis. Fallback is a regular style.
 */
 @bold-fonts:    "Noto Sans Bold",
-                "Noto Sans CJK JP Bold",
+                "Noto Sans Adlam Bold",
+                "Noto Sans Adlam Unjoined Bold",
                 "Noto Sans Armenian Bold",
+                "Noto Sans Balinese Bold",
+                "Noto Sans Bamum Bold",
                 "Noto Sans Bengali UI Bold",
+                "Noto Sans Canadian Aboriginal Bold",
                 "Noto Sans Cham Bold",
                 "Noto Sans Cherokee Bold",
                 "Noto Sans Devanagari UI Bold",
@@ -164,29 +141,37 @@ regular text and can be used for emphasis. Fallback is a regular style.
                 "Noto Sans Gujarati UI Bold",
                 "Noto Sans Gurmukhi UI Bold",
                 "Noto Sans Hebrew Bold",
+                "Noto Sans Javanese Bold",
                 "Noto Sans Kannada UI Bold",
+                "Noto Sans Kayah Li Bold",
                 "Noto Sans Khmer UI Bold",
                 "Noto Sans Lao UI Bold",
+                "Noto Sans Lisu Bold",
                 "Noto Sans Malayalam UI Bold",
                 "Noto Sans Myanmar UI Bold",
+                "Noto Sans Ol Chiki Bold",
                 "Noto Sans Oriya UI Bold",
-                "Noto Sans Sinhala UI Bold", "Noto Sans Sinhala Bold",
+                "Noto Sans Sinhala UI Bold",
+                "Noto Sans Sundanese Bold",
                 "Noto Sans Symbols Bold",
+                "Noto Sans Syriac Black",
+                "Noto Sans Tai Tham Bold",
                 "Noto Sans Tamil UI Bold",
                 "Noto Sans Telugu UI Bold",
                 "Noto Sans Thaana Bold",
                 "Noto Sans Thai UI Bold",
+                "Noto Sans CJK JP Bold",
+                "Noto Sans Arabic UI Bold",
 
-                "Noto Sans Arabic UI Bold", "Noto Naskh Arabic UI Bold",
-
-                "Noto Serif Tibetan Bold", "Noto Sans Tibetan Bold",
+                "Noto Serif Tibetan Bold",
 
-                "DejaVu Sans Bold",
+                "Noto Emoji Bold",
 
                 @book-fonts;
 
 /*
-Italics are only available for the base font, not the other scripts.
+Italics are only available for the (Latin-Greek-Cyrillic) base font, not the other scripts.
+(Apart from that, only Noto Tamil has an Italic style, but just for Serif, not for Sans.)
 For a considerable number of labels this style will make no difference to the regular style.
 */
 @oblique-fonts: "Noto Sans Italic", @book-fonts;


=====================================
style/landcover.mss
=====================================
@@ -88,7 +88,6 @@
     [way_pixels >= 64] { polygon-gamma: 0.3;  }
   }
 
-  [feature = 'leisure_recreation_ground'][zoom >= 10],
   [feature = 'landuse_recreation_ground'][zoom >= 10],
   [feature = 'leisure_playground'][zoom >= 13],
   [feature = 'leisure_fitness_station'][zoom >= 13] {


=====================================
style/roads.mss
=====================================
@@ -1302,7 +1302,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
             }
             [zoom >= 18] {
               line-width: 8;
-              b/line-width: 7
+              b/line-width: 7;
             }
           }
           [service = 'INT-minor'] {


=====================================
style/water.mss
=====================================
@@ -287,12 +287,12 @@
 #text-poly-low-zoom[zoom < 10],
 #text-point[zoom >= 10] {
   [feature = 'natural_water'],
-  [feature = 'natural_bay'],
-  [feature = 'natural_strait'],
   [feature = 'landuse_reservoir'],
   [feature = 'landuse_basin'],
-  [feature = 'waterway_dock'] {
-    [zoom >= 0][way_pixels > 3000][way_pixels <= 768000],
+  [feature = 'waterway_dock'],
+  [feature = 'natural_strait'],
+  [feature = 'natural_bay'] {
+    [zoom >= 5][way_pixels > 3000][way_pixels <= 768000],
     [zoom >= 14][way_pixels <= 768000][feature = 'natural_bay'],
     [zoom >= 14][way_pixels <= 768000][feature = 'natural_strait'],
     [zoom >= 17][way_pixels <= 768000] {
@@ -300,18 +300,19 @@
       text-size: 10;
       text-wrap-width: 25; // 2.5 em
       text-line-spacing: -1.5; // -0.15 em
-      [way_pixels > 12000],
-      [zoom >= 15][feature = 'natural_strait'] {
+      [way_pixels > 12000][feature != 'natural_strait'][feature != 'natural_bay'],
+      [zoom >= 15][feature = 'natural_strait'],
+      [zoom >= 15][feature = 'natural_bay'] {
         text-size: 12;
         text-wrap-width: 37; // 3.1 em
         text-line-spacing: -1.6; // -0.13 em
       }
-      [way_pixels > 48000] {
+      [way_pixels > 48000][feature != 'natural_strait'][feature != 'natural_bay'] {
         text-size: 15;
         text-wrap-width: 59; // 3.9 em
         text-line-spacing: -1.5; // -0.10 em
       }
-      [way_pixels > 192000] {
+      [way_pixels > 192000][feature != 'natural_strait'][feature != 'natural_bay'] {
         text-size: 19;
         text-wrap-width: 95; // 5.0 em
         text-line-spacing: -0.95; // -0.05 em


=====================================
symbols/amenity/parcel_locker.svg
=====================================
@@ -0,0 +1,8 @@
+<svg version="1.1" width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg">
+ <path d="m2 5.0723v5.9258l6 2.9336v-5.9316z"/>
+ <path d="m14 4-4.9995 3.3456-4.897e-4 5.922 5-3.2676z"/>
+ <path d="m7.5 0-5.5 4 6.0058 2.8751 5.9942-3.8732v-0.00391z"/>
+ <path d="m0 14h3v-1h-2v-12h2v-1h-3z"/>
+ <path d="m2 4 6.9987 3.3474"/>
+ <path d="m8.4973 6.4726 1e-4 7.5274"/>
+</svg>



View it on GitLab: https://salsa.debian.org/debian-gis-team/openstreetmap-carto/-/compare/cc41bcaa3e1963d50bb33b5e069ba944af082511...7c2852bfe665175668ed97d1d3104962ebc19c97

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/openstreetmap-carto/-/compare/cc41bcaa3e1963d50bb33b5e069ba944af082511...7c2852bfe665175668ed97d1d3104962ebc19c97
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20221201/144d002e/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list