Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nik4: init at 1.8 #366194

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ in {
nix-channel = pkgs.callPackage ../modules/config/nix-channel/test.nix { };
nebula = handleTest ./nebula.nix {};
netbird = handleTest ./netbird.nix {};
nik4 = runTest ./nik4.nix;
nimdow = handleTest ./nimdow.nix {};
neo4j = handleTest ./neo4j.nix {};
netdata = handleTest ./netdata.nix {};
Expand Down
69 changes: 69 additions & 0 deletions nixos/tests/nik4.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# This test downloads some example OpenStreetMap data, imports it into a database and then renders a portion of it. The resulting PNG image will be in the output.
Luflosi marked this conversation as resolved.
Show resolved Hide resolved
# Importing the data takes some time, at least a couple minutes.

{ lib, pkgs, ... }:
let
# Fetch a tiny example region
andorra = pkgs.fetchurl {
# The OpenStreetMap data from the first of January seems to be kept for at least 10 years
url = "https://download.geofabrik.de/europe/andorra-240101.osm.pbf";
hash = "sha256-9RylVK1C28e9qnc8Lu1VGcxS3lNlmjPTWcWvJJlmAf4=";
};
in
{
name = "nik4";
meta.maintainers = lib.teams.geospatial.members ++ (with lib.maintainers; [ Luflosi ]);

nodes.machine = {
virtualisation = {
cores = 2;
diskSize = 8 * 1024;
memorySize = 2 * 1024;
};

services.postgresql = {
enable = true;
extensions = ps: with ps; [ postgis ];
ensureUsers = lib.singleton {
name = "osmuser";
ensureClauses.createdb = true;
};
};

users.users.osmuser = {
isSystemUser = true;
group = "osmuser";
};
users.groups.osmuser = { };

environment.systemPackages = with pkgs; [
osm2pgsql
nik4
];
};

testScript = ''
machine.wait_for_unit("multi-user.target")

with subtest("Create database"):
machine.succeed("sudo -u postgres createdb --encoding=UTF8 --owner=osmuser gis")
machine.succeed("sudo -u postgres psql gis --command='CREATE EXTENSION postgis;'")
machine.succeed("sudo -u postgres psql gis --command='CREATE EXTENSION hstore;'")

with subtest("Insert data into database"):
machine.succeed("mkdir /osm >&2")
machine.succeed("chown osmuser /osm >&2")

machine.succeed("sudo -u osmuser '${pkgs.openstreetmap-carto.get_external_data}/bin/get-external-data.py' --config '${pkgs.openstreetmap-carto.get_external_data}/external-data.yml' --data '/osm/get-external-data/'")
machine.succeed("sudo -u osmuser osm2pgsql --output=flex --style='${pkgs.openstreetmap-carto}/openstreetmap-carto-flex.lua' --database=gis --create '${andorra}'")
machine.succeed("sudo -u osmuser psql -d gis -f '${pkgs.openstreetmap-carto}/indexes.sql'")
machine.succeed("sudo -u osmuser psql -d gis -f '${pkgs.openstreetmap-carto}/functions.sql'")

with subtest("Execute nik4.py"):
machine.succeed("sudo -u osmuser nik4.py --url 'https://www.openstreetmap.org/#map=17/42.506650/1.525828' --ppi 300 -a 4 '${pkgs.openstreetmap-carto}/mapnik.xml' /tmp/map.png >&2")
machine.copy_from_vm("/tmp/map.png")
import os
image_size = os.stat(machine.out_dir / "map.png").st_size
assert image_size >= 2 * 1024 * 1024, f"The rendered map image was too small ({image_size} bytes). This indicates, that the map was not rendered correctly."
'';
}
43 changes: 43 additions & 0 deletions pkgs/by-name/ni/nik4/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
lib,
fetchFromGitHub,

nixosTests,
python3Packages,
}:

python3Packages.buildPythonPackage rec {
pname = "nik4";
version = "1.8";
pyproject = true;

src = fetchFromGitHub {
owner = "Zverik";
repo = "Nik4";
tag = "v${version}";
hash = "sha256-ICNy+H1N8YY/5P4gCX/laAn+G2JNQOKhvh4fsgcM0kM=";
};

build-system = with python3Packages; [ setuptools ];

dependencies = with python3Packages; [
pycairo
python-mapnik
];

strictDeps = true;

passthru.tests = {
inherit (nixosTests) nik4;
};

meta = {
changelog = "https://github.com/Zverik/Nik4/releases/tag/v${version}";
description = "Mapnik to image export";
homepage = "https://github.com/Zverik/Nik4";
license = lib.licenses.wtfpl;
mainProgram = "nik4.py";
maintainers = lib.teams.geospatial.members ++ (with lib.maintainers; [ Luflosi ]);
platforms = lib.platforms.linux;
};
}
201 changes: 201 additions & 0 deletions pkgs/by-name/op/openstreetmap-carto/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
{
lib,
stdenvNoCC,
fetchFromGitHub,
fetchurl,

carto,
gdal,
hanazono,
nixosTests,
noto-fonts,
python3,
runCommand,
symlinkJoin,
Comment on lines +2 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lib,
stdenvNoCC,
fetchFromGitHub,
fetchurl,
carto,
gdal,
hanazono,
nixosTests,
noto-fonts,
python3,
runCommand,
symlinkJoin,
lib,
stdenvNoCC,
fetchFromGitHub,
fetchurl,
nixosTests,
runCommand,
symlinkJoin,
carto,
gdal,
hanazono,
noto-fonts,
python3,

}:

let
generate_env = python3.withPackages (
p: with p; [
colormath
lxml
pyyaml
]
);
get-external-data_env = python3.withPackages (
p: with p; [
psycopg2
pyyaml
requests
]
);

mkArchive =
{
url,
archive_time,
hash,
}:
{
inherit url;
archive = fetchurl {
url = "https://web.archive.org/web/${archive_time}/${url}";
inherit hash;
};
};
simplified_water_polygons = mkArchive {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about moving all data downloading code to nixos/tests/nik4.nix test and generate external-data.yml file required for test script there ? It looks to me as a more appropriate place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal was to make this script as reproducible as possible, no matter if it's called in the NixOS test or on a users system. I'm in favor of keeping it this way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this data ? Isn't it useful mostly for testing ? If that's true, I still lean more towards moving this code to the test.
Another issue of having this code in package is how to update this data over the time (and how often). We might end up with reproducible but very outdated data.

What do you think @autra ?

url = "https://osmdata.openstreetmap.de/download/simplified-water-polygons-split-3857.zip";
archive_time = "20241201150706";
hash = "sha256-vVVbHBCbeaTaYAZRvIEQ5N1Dy5E+RaOSgZS3Uf59QkU=";
};
water_polygons = mkArchive {
url = "https://osmdata.openstreetmap.de/download/water-polygons-split-3857.zip";
archive_time = "20241201150707";
hash = "sha256-YV3KCcVGZoSrZVjASUCPEcTCn0C39l0pG4gBl5AJm5M=";
};
icesheet_polygons = mkArchive {
url = "https://osmdata.openstreetmap.de/download/antarctica-icesheet-polygons-3857.zip";
archive_time = "20241201150705";
hash = "sha256-QvaegTQuiju8B8IyT6qq3QDjBWk2D02bu6g07G8VPMA=";
};
icesheet_outlines = mkArchive {
url = "https://osmdata.openstreetmap.de/download/antarctica-icesheet-outlines-3857.zip";
archive_time = "20241201150707";
hash = "sha256-d09olTATtgLO4VOAAnbO6XOrSm89DOLbSzP4id7njtU=";
};
ne_110m_admin_0_boundary_lines_land = mkArchive {
url = "https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_admin_0_boundary_lines_land.zip";
archive_time = "20241201150708";
hash = "sha256-uylUmBVwSYpLQ0T46D+lTKpYWOFegACUESQH0r0vlA0=";
};
in
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "openstreetmap-carto";
version = "5.9.0-unstable-2024-11-27";

src = fetchFromGitHub {
owner = "gravitystorm";
repo = "openstreetmap-carto";
rev = "5791e79934164f8d5ff73460ad993f3d9f64222c";
hash = "sha256-0kPgX09oJprnTDnXdLhse8VWz/crjN5d40yKS0WhsHc=";
};

postPatch = ''
substituteInPlace external-data.yml \
--replace-fail '${simplified_water_polygons.url}' 'file://${simplified_water_polygons.archive}' \
--replace-fail '${water_polygons.url}' 'file://${water_polygons.archive}' \
--replace-fail '${icesheet_polygons.url}' 'file://${icesheet_polygons.archive}' \
--replace-fail '${icesheet_outlines.url}' 'file://${icesheet_outlines.archive}' \
--replace-fail '${ne_110m_admin_0_boundary_lines_land.url}' 'file://${ne_110m_admin_0_boundary_lines_land.archive}'

if grep http external-data.yml; then
echo 'Not all URLs were patched!'
exit 1
fi

substituteInPlace style/fonts.mss --replace-fail \
"url('fonts')" \
"url('${finalAttrs.passthru.fonts}')"

substituteInPlace scripts/get-external-data.py \
--replace-fail \
'ogrcommand = ["ogr2ogr",' \
'ogrcommand = ["${lib.getExe' gdal "ogr2ogr"}",' \
--replace-fail \
'#!/usr/bin/env python3' \
'#!${lib.getExe get-external-data_env}'

substituteInPlace scripts/generate_road_colours.py scripts/generate_shields.py scripts/generate_unpaved_patterns.py scripts/indexes.py \
--replace-fail \
'#!/usr/bin/env python3' \
'#!${lib.getExe generate_env}'
'';

outputs = [
"out"
"get_external_data"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to rename this output.

Suggested change
"get_external_data"
"external_data"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script is called get-external-data.py, so I named the output get_external_data. The output does not directly contain the external data but only a script that knows how to "get" it. Do you still think that I should rename it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still in favor calling it external_data.

];

buildPhase = ''
runHook preBuild

# Generate some files ourselves instead of relying on the pre-generated ones
mv symbols/unpaved/unpaved.svg unpaved.svg
mv style/road-colors-generated.mss road-colors-generated.orig.mss
rm -r indexes.sql symbols/shields symbols/unpaved
mkdir -p symbols/shields symbols/unpaved
mv unpaved.svg symbols/unpaved/unpaved.svg

scripts/indexes.py > indexes.sql
scripts/generate_road_colours.py > style/road-colors-generated.mss
scripts/generate_shields.py
scripts/generate_unpaved_patterns.py

# We don't copy this file to the output, so we can only check it here
if ! diff 'road-colors-generated.orig.mss' 'style/road-colors-generated.mss'; then
echo 'The file style/road-colors-generated.mss we generated differs from the pre-generated one!'
exit 1
fi

mkdir -p "$out/"
'${lib.getExe carto}' project.mml > "$out/mapnik.xml"

runHook postBuild
'';

installPhase = ''
runHook preInstall

mkdir -p "$get_external_data/"
cp -r patterns/ symbols/ *.sql *.lua "$out/"
cp external-data.yml "$get_external_data/"
install -D scripts/get-external-data.py --target-directory="$get_external_data/bin/"
# There should be no need for the get-fonts.sh script as we patch `style/fonts.mss` to depend directly on the fonts.

runHook postInstall
'';

strictDeps = true;

passthru = {
fonts = symlinkJoin {
name = "osm-fonts";
paths = [
# Some fonts are probably missing, please add
"${noto-fonts}/share/fonts/noto"
"${hanazono}/share/fonts/truetype"
];
};

tests = {
inherit (nixosTests) nik4;
inherit (finalAttrs.finalPackage.passthru) fonts;

# Check that we generated the exact same files as the pre-generated ones
compare-generated-files = runCommand "compare-generated-files" { } ''
if ! diff '${finalAttrs.src}/indexes.sql' '${finalAttrs.finalPackage}/indexes.sql'; then
echo 'The file indexes.sql we generated differs from the pre-generated one!'
exit 1
fi
if ! diff -r '${finalAttrs.src}/symbols/shields/' '${finalAttrs.finalPackage}/symbols/shields/'; then
echo 'The directory symbols/shields/ we generated differs from the pre-generated one!'
exit 1
fi
if ! diff -r --exclude=unpaved.md '${finalAttrs.src}/symbols/unpaved/' '${finalAttrs.finalPackage}/symbols/unpaved/'; then
echo 'The directory symbols/unpaved/ we generated differs from the pre-generated one!'
exit 1
fi

touch "$out"
'';
};
};

meta = {
description = "General-purpose OpenStreetMap mapnik style, in CartoCSS";
homepage = "https://github.com/gravitystorm/openstreetmap-carto";
license = lib.licenses.cc0;
maintainers = lib.teams.geospatial.members ++ (with lib.maintainers; [ Luflosi ]);
platforms = lib.platforms.linux;
};
})
2 changes: 1 addition & 1 deletion pkgs/development/python-modules/python-mapnik/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ buildPythonPackage rec {
"test_geometry_type"
"test_passing_pycairo_context_pdf"
"test_pdf_printing"
"test_raster_warping"
"test_render_with_scale_factor"
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
Expand All @@ -134,6 +135,5 @@ buildPythonPackage rec {
maintainers = [ ];
homepage = "https://mapnik.org";
license = licenses.lgpl21Plus;
broken = true; # At 2024-11-13, test_raster_warping fails.
imincik marked this conversation as resolved.
Show resolved Hide resolved
};
}