From 535ea3212dba1d39d413adae645c536e159ac907 Mon Sep 17 00:00:00 2001 From: Ivan Mincik Date: Tue, 22 Apr 2025 13:59:54 +0200 Subject: [PATCH] Add Nix package for PyQGIS API Documentation builder --- README.md | 2 +- flake.lock | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 148 +++++++++++++++++++++++++++++++++ package.nix | 89 ++++++++++++++++++++ 4 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 package.nix diff --git a/README.md b/README.md index 4ef574cbbe74..13dee9305bd8 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You can either: * export the PYTHONPATH yourself * export your QGIS build directory with ``export QGIS_BUILD_DIR=~/dev/QGIS/build`` -* or provide QGIS build directory as argument to the script: ``./build-docs.sh -qgis-build-dir ~/dev/QGIS/build`` +* or provide QGIS build directory as argument to the script: ``./scripts/build-docs.sh -qgis-build-dir ~/dev/QGIS/build`` ### Testing & development diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000000..ae5cbd03ff5c --- /dev/null +++ b/flake.lock @@ -0,0 +1,234 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1743550720, + "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "c621e8422220273271f52058f618c94e405bb0f5", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_2" + }, + "locked": { + "lastModified": 1743550720, + "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "c621e8422220273271f52058f618c94e405bb0f5", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_3" + }, + "locked": { + "lastModified": 1743550720, + "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "c621e8422220273271f52058f618c94e405bb0f5", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1745234285, + "narHash": "sha256-GfpyMzxwkfgRVN0cTGQSkTC0OHhEkv3Jf6Tcjm//qZ0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c11863f1e964833214b767f4a369c6e6a7aba141", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1743296961, + "narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs-lib_2": { + "locked": { + "lastModified": 1743296961, + "narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs-lib_3": { + "locked": { + "lastModified": 1743296961, + "narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1744868846, + "narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1744868846, + "narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1744868846, + "narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "qgisLatest": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1746268773, + "narHash": "sha256-WO1SHo96bKcPkZ0s9GogL0JqEukhwTZrSsw+bwl79m4=", + "owner": "imincik", + "repo": "QGIS", + "rev": "0e95bafe8cdc920080c53b7d15ab867eb78f631d", + "type": "github" + }, + "original": { + "owner": "imincik", + "ref": "nix-package-release-3_42", + "repo": "QGIS", + "type": "github" + } + }, + "qgisLtr": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1746604554, + "narHash": "sha256-uglIhnYAN7dB02sBr+DV2KlYtARURUVNuP0uIsiEAs8=", + "owner": "imincik", + "repo": "QGIS", + "rev": "e82dcace180741f5e23baea8c46b08d625fba14f", + "type": "github" + }, + "original": { + "owner": "imincik", + "ref": "nix-package-release-3_40", + "repo": "QGIS", + "type": "github" + } + }, + "qgisMaster": { + "inputs": { + "flake-parts": "flake-parts_3", + "nixpkgs": "nixpkgs_4" + }, + "locked": { + "lastModified": 1746545503, + "narHash": "sha256-3bBzsn+6swpEKk5obmENeQj4XmMkxXFdze9oQ0xfdIs=", + "owner": "imincik", + "repo": "QGIS", + "rev": "43f75f91b5d16a8bd83cee030e015839cc2b76c2", + "type": "github" + }, + "original": { + "owner": "imincik", + "ref": "nix-package-master", + "repo": "QGIS", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "qgisLatest": "qgisLatest", + "qgisLtr": "qgisLtr", + "qgisMaster": "qgisMaster" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000000..3e3ea58279bb --- /dev/null +++ b/flake.nix @@ -0,0 +1,148 @@ +{ + description = "PyQGIS API Documentation"; + + nixConfig = { + # extra-substituters = [ "https://example.cachix.org" ]; + # extra-trusted-public-keys = [ "example.cachix.org-1:xxxx=" ]; + + # IFD is required for QGIS repo. + allow-import-from-derivation = true; + }; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + # TODO: https://github.com/qgis/QGIS-Sysadmin-Documentation/issues/129 + qgisMaster = { + url = "github:imincik/QGIS/nix-package-master"; + }; + + # TODO: https://github.com/qgis/QGIS-Sysadmin-Documentation/issues/129 + qgisLatest = { + url = "github:imincik/QGIS/nix-package-release-3_42"; + }; + + # TODO: https://github.com/qgis/QGIS-Sysadmin-Documentation/issues/129 + qgisLtr = { + url = "github:imincik/QGIS/nix-package-release-3_40"; + }; + }; + + outputs = inputs@{ self, nixpkgs, qgisMaster, qgisLatest, qgisLtr }: + + let + # Flake system + supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + nixpkgsFor = forAllSystems (system: import nixpkgs { + inherit system; + config.allowUnfree = true; + }); + + in + { + # + ### PACKAGES + # + + packages = forAllSystems (system: + let + pkgs = nixpkgsFor.${system}; + + in + { + docs-master = pkgs.callPackage ./package.nix { + qgis = inputs.qgisMaster.packages.${system}.qgis; + qgisRepo = qgisMaster; + qgisIsMasterVersion = true; + }; + + docs-latest = pkgs.callPackage ./package.nix { + qgis = inputs.qgisLatest.packages.${system}.qgis; + qgisRepo = qgisLatest; + }; + + docs-ltr = pkgs.callPackage ./package.nix { + qgis = inputs.qgisLtr.packages.${system}.qgis; + qgisRepo = qgisLtr; + }; + }); + + + # + ### APPS + # + + apps = forAllSystems (system: + let + pkgs = nixpkgsFor.${system}; + inherit (nixpkgs) lib; + + wwwLauncherMaster = pkgs.writeShellApplication { + name = "website"; + runtimeInputs = [ pkgs.python3 ]; + text = '' + exec ${lib.getExe pkgs.python3} \ + -m http.server 8000 \ + -d ${self.packages.${system}.docs-master}/ + ''; + }; + + wwwLauncherLatest = pkgs.writeShellApplication { + name = "website"; + runtimeInputs = [ pkgs.python3 ]; + text = '' + exec ${lib.getExe pkgs.python3} \ + -m http.server 8000 \ + -d ${self.packages.${system}.docs-latest}/ + ''; + }; + + wwwLauncherLtr = pkgs.writeShellApplication { + name = "website"; + runtimeInputs = [ pkgs.python3 ]; + text = '' + exec ${lib.getExe pkgs.python3} \ + -m http.server 8000 \ + -d ${self.packages.${system}.docs-ltr}/ + ''; + }; + + in + rec { + website-master = { + type = "app"; + program = "${wwwLauncherMaster}/bin/website"; + }; + + website-latest = { + type = "app"; + program = "${wwwLauncherLatest}/bin/website"; + }; + + website-ltr = { + type = "app"; + program = "${wwwLauncherLtr}/bin/website"; + }; + + default = website-master; + }); + + + # + ### SHELLS + # + + devShells = forAllSystems (system: + let + pkgs = nixpkgsFor.${system}; + + in + { + # Development environment + default = pkgs.mkShell { + buildInputs = [ ]; + }; + }); + }; +} diff --git a/package.nix b/package.nix new file mode 100644 index 000000000000..695c7ae6aa9f --- /dev/null +++ b/package.nix @@ -0,0 +1,89 @@ +{ lib +, stdenv + +, qgis +, qgisRepo +, qgisIsMasterVersion ? false + +, graphviz +, python3 +, python3Packages +}: + +let + qgisPackage = qgis.override { withServer = true; }; + qgisMinorVersion = + let + versionSplit = builtins.splitVersion qgis.version; + version = + if qgisIsMasterVersion then + "master" + else + builtins.elemAt versionSplit 0 + "." + builtins.elemAt versionSplit 1; + in + version; + +in + +stdenv.mkDerivation { + pname = "qgis-pyqgis-documentation"; + version = qgisMinorVersion; + + src = lib.cleanSourceWith { + src = ./.; + filter = ( + path: type: (builtins.all (x: x != baseNameOf path) [ + ".git" + ".github" + "flake.nix" + "flake.lock" + "package.nix" + "result" + ]) + ); + }; + + dontWrapQtApps = true; + + buildInputs = with python3Packages; [ + graphviz + python3 + sphinx + sphinx-rtd-theme + ] ++ qgisPackage.passthru.unwrapped.pythonBuildInputs; + + # Taken from + # https://github.com/qgis/pyqgis-api-docs-builder/blob/main/scripts/build-docs.sh + buildPhase = '' + # Build RST + mkdir -p temp + for module in "3d" "analysis" "core" "gui" "server"; do + CLASS_MAP_FILE="temp/$module/class_map.yaml" + mkdir -p temp/$module + cp ${qgisRepo}/python/$module/class_map.yaml $CLASS_MAP_FILE + done + + export PYTHONPATH=$PYTHONPATH:${qgisPackage}/share/qgis/python + + python3 ./scripts/make_api_rst.py --version ${qgisMinorVersion} + + mkdir api/${qgisMinorVersion}/_static + cp -r _static/css api/${qgisMinorVersion}/_static/css + cp -r _static/js api/${qgisMinorVersion}/_static/js + cp _static/*.rst api/${qgisMinorVersion}/ + + # Build HTML + sed -r "s/__QGIS_VERSION__/${qgisMinorVersion}/g;" conf.in.py > api/${qgisMinorVersion}/conf.py + sphinx-build -M html api/${qgisMinorVersion} build/${qgisMinorVersion} -T -j auto + + # Move files around + rm -rf build/${qgisMinorVersion}/doctrees + mv build/${qgisMinorVersion}/html/* build/${qgisMinorVersion} + rm -rf build/${qgisMinorVersion}/html + ''; + + installPhase = '' + mkdir -p $out + cp -r build/* $out/ + ''; +}