PostgREST 的 Nix 开发与构建环境:从可复现构建到一站式测试工具链

PostgREST 的 Nix 开发与构建环境:从可复现构建到一站式测试工具链 PostgREST 的 Nix 开发与构建环境从可复现构建到一站式测试工具链【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest本文以 nix/README.md 为骨架系统讲解如何用 Nix 在本地快速、可复现地构建、开发、测试 PostgRESTREST API for any Postgres database。读完本文你将掌握nix-build产出动态/静态二进制、nix-shell进入带全套postgrest-工具的开发环境以及测试、覆盖率、lint、文档、依赖升级等完整工作流并结合仓库内的 default.nix、shell.nix、flake.nix 与 nix/tools 下的实现理解其底层原理。为什么 PostgREST 团队选择 NixPostgREST 是一个依赖众多GHC、Cabal、多个 PostgreSQL 版本、pytest、vegeta 等的 Haskell 项目。借助 Nix可以在任何机器上快速且可靠地重建完整的开发、测试与构建环境GHC 版本、系统库、测试数据库、工具链全部由 Nix 表达式固定杜绝在我机器上能跑的环境漂移问题。仓库的 Nix 资产分为几层各自职责清晰文件作用default.nix仓库级表达式聚合所有 derivation导出postgrestPackage、postgrestStatic、postgrestProfiled等构建产物shell.nix定义nix-shell开发环境在构建环境基础上追加开发工具与 bash 补全flake.nixNix Flake 入口声明nixpkgs输入与 packages / apps / devShells 输出nix/static.nix基于pkgsStatic构建完全静态的postgrestStatic可执行文件nix/overlays对 Nix 包集的覆盖overlay用于固定/覆盖依赖版本nix/tools定义各类postgrest-*工具脚本的 Nix 模块nix/UPGRADE.mdNix 依赖升级的检查清单开始使用 Nix环境准备首先需要安装 Nix请从 Nix 官方下载页面按照官方推荐流程为你的操作系统安装支持 Linux 与 macOS仓库 flake.nix 中声明的构建系统包括aarch64-darwin、aarch64-linux、x86_64-darwin、x86_64-linux。安装完成后即可在 PostgREST 仓库根目录执行下述所有命令。构建 PostgREST常规构建nix-build --attr postgrestPackage在仓库本地检出目录中运行$ nix-build --attr postgrestPackage执行后会在当前目录生成一个result符号链接内含 PostgREST 二进制路径为result/bin/postgrest。--attr简写-A告诉 Nix 从 default.nix 中解析并构建postgrestPackage这个属性。Nix 会自动获取正确的 GHC 版本以及全部构建依赖无需手动安装。从 default.nix 可以看到postgrestPackage的定义postgrestPackage pkgs.lib.pipe postgrest [ lib.dontCheck lib.enableSeparateBinOutput (haskellPackages.generateOptparseApplicativeCompletions [ postgrest ]) ];几个关键点值得注意postgrest基础 derivation 由haskellPackages.callCabal2nix name src { }生成并对 Haskell 包关闭了 library profiling 与动态库default.nix保证所有 Haskell 依赖始终静态链接lib.dontCheckNix 构建时不运行测试套件因为测试需要真实数据库测试有专门的postgrest-test-*工具见下文lib.enableSeparateBinOutput将二进制拆分为独立 output使 flake.nix 的默认分发闭包体积显著更小源码过滤src通过sourceFilesBySuffices只包含.cabal、.hs、.hsc、.lhs与LICENSE文件default.nix尽可能减少进入 Nix store 的文件从而避免无谓的 derivation 重建。静态构建nix-build --attr postgrestStatic如需静态链接的二进制运行$ nix-build --attr postgrestStatic $ ldd result/bin/postgrest $ not a dynamic executableldd输出not a dynamic executable说明这是一个完全静态的可执行文件可以脱离目标机器的系统库直接分发部署。其实现位于 nix/static.nix基于pkgsStatic.haskell.packages.native-bignum编译并通过justStaticExecutables提取静态可执行文件同时通过allowedReferences限制 Nix store 引用避免膨胀闭包并挂接testVersion冒烟测试验证可运行性。该属性仅在 Linux 上可用——default.nix 用pkgs.lib.optionalAttrs pkgs.stdenv.isLinux包裹了postgrestStatic与基于它的 Docker 镜像构建macOS 上不存在此属性。性能剖析构建除常规与静态构建外default.nix 还导出postgrestProfiled同时开启可执行文件与库的 profiling 并跳过 Haddock 文档配合下文postgrest-profiled-run工具用于性能优化。二进制缓存用 cachix 避免漫长重建强烈建议使用 PostgREST 的 cachix 二进制缓存否则静态构建需要在本地基于 Musl 重新编译全部依赖耗时极长。# 安装 cachix $ nix-env -iA cachix -f https://cachix.org/api/v1/install # 配置使用 PostgREST 二进制缓存 $ cachix use postgrest在 Nix Flake 时代flake.nix 也内置了同样的缓存配置nixConfig { extra-substituters https://postgrest.cachix.org; extra-trusted-public-keys postgrest.cachix.org-1:icgW4R15fz1LqvhPjt4EnX/r19AaqxiVV1olwlZtI; };如果你有向该缓存推送的权限可用postgrest-push-cachix将本地构建产物推送到缓存以加速 CI需要先cachix authtoken token登录该工具在 nix/tools/devTools.nix 中通过nix-store -qR --include-outputs收集全部依赖后统一推送。开发环境进入 nix-shell运行下面命令即可进入 PostgREST 的开发 shellGHC 与 Cabal 会自动加入 PATH$ nix-shell在 shell 内部可以像平常一样执行 Cabal 命令也可以使用带--nix选项的 stack让 stack 复用 Nix 构建所固定的同一版本 Nixpkgs 中的非 Haskell 依赖。从 shell.nix 的源码可以看到该环境由三部分叠加而成继承postgrest.env即postgrestderivation 的env来自 default.nix追加cabal-install、postgresql、hsie.binhsie 是用于分析 Haskell import/export 的工具见 nix/hsie追加全部工具箱toolboxcabalTools、devTools、docs、gitTools、loadtest、nixpkgsTools、release、style、tests、withTools并通过shellHook加载 bash 补全脚本shell.nix。shellHook还做了两件实用的事设置HISTFILE.history让 shell 历史保留在仓库内导出NO_PROXY*以绕过代理防止测试套件中的 HTTP 客户端失败。nix-shell还支持按需启用大依赖模块# 启用 docker 相关工具生成 Docker 镜像 $ nix-shell --arg docker truedocker模块默认关闭因其依赖体积大其实现见 default.nix基于postgrestStatic构建镜像与 nix/tools/docker。使用postgrest-工具脚本nix-shell中所有 PostgREST 实用工具都以postgrest-前缀命名因此可以借助 tab 补全输入postgrest-后按tab查看全部可用工具[nix-shell]$ postgrest-tab postgrest-build postgrest-cabal-update postgrest-check postgrest-clean postgrest-commitlint ...大部分命令都提供--help输出请务必查阅。一次性命令nix-shell --run不需要进入交互式 shell 时可以用nix-shell --run command启动 shell、执行单个命令后退出$ nix-shell --run postgrest-style # 注意传给内部命令的参数需要整体加引号 $ nix-shell --run postgrest-foo --bar注意 tab 补全在nix-shell --run下不生效——Nix 需要先求值我们的 Nix 表达式才能知道有哪些工具可用。若你频繁使用nix-shell可以考虑使用 cached-nix-shell 工具它在 Nix 表达式未变化时跳过求值显著缩短 shell 启动时间。路径解析规则始终相对仓库根进入nix-shell后工具脚本在仓库内的任何目录都可运行但路径一律相对仓库根解析[nix-shell]$ cd src # 尽管当前目录是 ./src配置路径仍须从仓库根开始 [nix-shell]$ postgrest-run test/io/configs/simple.conf该行为源于工具脚本统一设置workingDir /见 nix/tools/cabalTools.nix所有脚本均在仓库根工作目录下执行。测试一键跑起完整测试矩阵nix-shell内置的工具脚本让测试变得非常简单包括自动搭建依赖与临时测试数据库# 针对最新版本 PostgreSQL 运行测试 $ nix-shell --run postgrest-test-spec # 针对所有受支持版本的 PostgreSQL 运行测试 $ nix-shell --run postgrest-with-all postgrest-test-spec # 针对特定版本 PostgreSQL 运行测试在 nix-shell 中用 tab 补全可查看所有可用版本 $ nix-shell --run postgrest-with-pg-17 postgrest-test-spec支持的 PostgreSQL 版本矩阵定义在 default.nix包括 pg-19、pg-18、pg-17、pg-16、pg-15、pg-14每个都附带postgis与pg_safeupdate扩展另有启用 orioledb 存储引擎的oriole-18变体。临时数据库是怎么搭起来的postgrest-with-pg-*系列工具由 nix/tools/withTools.nix 生成。withTmpDb的核心逻辑是在临时目录初始化 PostgreSQL 数据目录initdb指定时区、UTF-8 编码、--nosync加速通过 unix domain socket 监听而非 TCP 端口listen_addresses 避免端口冲突自动创建最小权限的连接角色默认Postgrest_Test_Authenticator故意用混合大小写以隐式验证 schema cache 查询中的正确引用支持-f sql加载 fixture默认环境变量PGRST_DB_SCHEMAStest、PGTZutc、PGOPTIONS-c search_pathpublic,test支持--replica模式用pg_basebackup起一个流复制副本并导出PGREPLICAHOST/PGREPLICASLOT/PGRST_DB_URInix/tools/withTools.nix。工具还会在启动时打印连接与日志指引例如psql postgres:///$PGDATABASE?host$PGHOST -U postgres与tail -f $tmpdir/db.log。IO 测试黑盒测试将 PostgREST 作为黑盒、以输入输出方式测试的 io-test 由postgrest-test-io运行底层测试运行器是 pytest可以透传 pytest 常用选项# 按名称过滤测试例如包含 config 的全部测试 [nix-shell]$ postgrest-test-io -k config # 用 xdist 并行运行指定进程数 [nix-shell]$ postgrest-test-io -n auto [nix-shell]$ postgrest-test-io -n 8从 nix/tools/tests.nix 可以看到该命令先cabal v2-build exe:postgrest再在临时数据库中加载 test/io/fixtures/load.sql然后运行 pytest默认跳过test_big_schema.py与test_replica.py它们有专属命令postgrest-test-big-schema与postgrest-test-replica。pytest 环境由python3.withPackages组装包含pyjwt、pytest、pytest-xdist、pyyaml、requests、requests-unixsocket、syrupy等依赖nix/tools/tests.nix。内存测试内存测试用于验证大请求体下内存不超阈值# 构建内存测试所需依赖 $ nix-shell --arg memory true # 运行内存测试 [nix-shell]$ postgrest-test-memory其脚本位于 test/memory/memory-tests.shpostgrest-test-memory使用 profiling 构建--enable-profiling --disable-sharedbuilddir 为dist-prof后运行nix/tools/tests.nix。负载测试负载测试确保性能不因改动而回退底层使用 vegeta# 对最新提交 (HEAD) 运行负载测试 [nix-shell]$ postgrest-loadtest # 与另一分支对比 [nix-shell]$ postgrest-loadtest-against main # 生成用于 CI 的 markdown 报告 [nix-shell]$ postgrest-loadtest-report负载测试实现见 nix/tools/loadtest.nix报告合并逻辑见 nix/tools/merge_monitor_result.py。Doctest部分模块还提供了 doctest 测试[nix-shell]$ postgrest-test-doctests幂等性检查postgrest-test-spec-idempotence会在同一个数据库上连续运行两次 spec 测试验证测试可重复执行nix/tools/tests.nix。代码覆盖率postgrest-coverage命令会运行全部测试并生成./coverage目录可在浏览器中查看# 运行所有测试并生成覆盖率目录 [nix-shell]$ postgrest-coverage ... postgrest-coverage: To see the results, visit file://$(pwd)/coverage/check/hpc_index.html其内部流程nix/tools/tests.nix值得展开先构建exe:postgrest、lib:postgrest、test:spec、test:observability用 weeder配置见 test/weeder.toml检测死代码然后分别收集 io、big_schema、replica、spec、observability 五组测试的.tix文件用hpc sum --union合并再叠加 test/coverage.overlay 并校验 overlay 区域确实未被测试覆盖最终产出 HTML 报告、hpc report文本与 codecov JSON。还提供postgrest-coverage-draft-overlay从当前报告草拟新的 overlay 文件。Lint 与代码风格nix-shell内置代码检查与格式化脚本# Lint $ nix-shell --run postgrest-lint # 自动格式化代码 $ nix-shell --run postgrest-style另有postgrest-style-check若检查产生任何未提交变更则以非零退出码退出主要用于 CI。样式工具的 Nix 定义见 nix/tools/style.nix其中hsienix/hsie用于分析 import/export。文档工具处理 PostgREST 文档时可用以下命令# 构建文档 [nix-shell]$ postgrest-docs-build # 构建文档并启动 livereload 服务器http://localhost:5500 [nix-shell]$ postgrest-docs-serve # 运行 aspell 检查拼写 [nix-shell]$ postgrest-docs-spellcheck # 检测 postgrest.dict 中的过时词条 [nix-shell]$ postgrest-docs-dictcheck # 构建并运行全部校验脚本 [nix-shell]$ postgrest-docs-check文档工具定义于 nix/tools/docs.nix拼写词典为 docs/postgrest.dict文档源码位于 docs。通用开发工具postgrest-build、postgrest-run、postgrest-repl等是围绕cabal的简单封装行为符合直觉postgrest-build以-f dev --test-show-detaildirect选项执行cabal v2-builddev flag 定义见 postgrest.cabalpostgrest-run构建并运行 PostgREST支持通过环境变量覆盖关键配置默认值来自 nix/tools/cabalTools.nixPGRST_DB_ANON_ROLEpostgrest_test_anonymous、PGRST_DB_POOL1、PGRST_DB_POOL_ACQUISITION_TIMEOUT1、PGRST_JWT_SECRETreallyreallyreallyreallyverysafe、PGRST_ADMIN_SERVER_PORT3001postgrest-profiled-run运行 profiling 构建生成postgrest.prof供性能优化分析postgrest-clean清理 cabal 产物含.hpc、coverage、*.hiepostgrest-cabal-update从 Hackage 更新 cabal 包列表postgrest-check运行 CI 中执行的大部分检查spec、observability、doctests、io、big-schema、replica 测试 lint style-check但不含 IO 之外需要单独运行的 Memory 检查nix/tools/devTools.nix。postgrest-with-pg-*接受一个命令参数并为其提供临时数据库运行postgrest-with-all则对所有受支持的 PostgreSQL 版本依次运行。不加postgrest-with-*时测试默认针对最新版 PostgreSQL。postgrest-watch接受一个命令参数在任何源文件变化时重新执行它。例如# 每次变更都针对所有 PostgreSQL 版本重跑完整 spec 测试套件 [nix-shell]$ postgrest-watch postgrest-with-all postgrest-test-spec其实现基于fdentrnix/tools/devTools.nix。其他开发小工具还包括postgrest-gen-jwt生成 HS256 JWT支持--exp负数模拟过期令牌、postgrest-gen-secret生成 32 位随机 JWT 密钥、postgrest-parallel-curl对同一 host 发起 N 路并行 curl、postgrest-gen-ctags为 Haskell/Python 生成 ctags、postgrest-hsie-graph-modules/postgrest-hsie-graph-symbols生成模块/符号依赖图 PNG等全部定义在 nix/tools/devTools.nix。REPL交互式探索 PostgREST 模块postgrest-repl基于cabal v2-replnix/tools/cabalTools.nix可手动检查 PostgREST 模块$ postgrest-repl ghci import PostgREST.tab PostgREST.Admin PostgREST.Config.Database PostgREST.Plan.MutatePlan PostgREST.Response.OpenAPI PostgREST.ApiRequest PostgREST.Config.JSPath PostgREST.Plan.ReadPlan PostgREST.SchemaCache ... ghci import PostgREST.MediaType ghci decodeMediaType application/json MTApplicationJSONPostgREST.MediaType模块位于 src/library/PostgREST/MediaType.hs上述例子展示了如何直接调用内部函数验证媒体类型解析逻辑。使用本地修改的 Haskell 包调试或增强某个 Haskell 库例如hasql-poolPostgREST 的连接池实现也位于本仓库 src/hasql时可以临时把库替换为本地版本第一步将库拷贝到仓库根目录并去掉.git$ git clone --depth1 --branch0.10.1 hasql-pool 仓库地址 hasql-pool $ rm -rf ./hasql-pool/.git第二步在 nix/overlays/haskell-packages.nix 中固定该本地包overrides # ... rec { # 若 cabal 文件不在库的根目录可能需要不同的子路径 hasql-pool lib.dontCheck (prev.callCabal2nixWithOptions hasql-pool ../../hasql-pool --subpath. {} ); };第三步同步更新 cabal.project 与 stack.yaml-- cabal.project packages: ./hasql-pool/hasql-pool.cabal# stack.yaml extra-deps: - ./hasql-pool/hasql-pool.cabal第四步运行nix-shell构建本地包。修改库代码后无需反复进出 Nix shell重新执行postgrest-run即可。haskell-packages.nix注释中还给出了其他常用覆盖技巧nix/overlays/haskell-packages.nix用prev.callHackageDirect固定 Hackage 上的特定版本、用fetchFromGitHubcallCabal2nixWithOptions固定未发布的 GitHub 提交、用lib.dontCheck跳过失败的单测等。注意这只是开发用途本地库不得留在生产代码中。Tour理解 Nix 表达式的组织结构以下内容并非使用 Nix 开发 PostgREST 的必要知识但有助于深入理解其工作原理。default.nix仓库级表达式default.nix 是仓库表达式把所有用 Nix 定义的部件聚合在一起返回一个属性集合类似其他语言中的 dict每个属性都是 Nix 可以构建的 derivation例如postgrestPackage、postgrestProfiled、hsie、各类工具集合等。其内部通过pkgs.callPackage导入nix目录下定义的各模块并自动传入pkgs中可用的参数意味着pkgs在一定程度上以自身来定义。default.nix还负责加载固定版本的nixpkgs仓库——该包集在任何地点、任何时间求值结果都一致。固定版本取自 flake.lock可通过postgrest-nixpkgs-upgrade更新非 Flake 场景下nixpkgsVersion参数从flake.lock读取作为兼容层见 default.nix。shell.nix开发环境shell.nix 定义了可构建、可开发 PostgREST 的环境。它继承postgrest属性的构建环境再叠加进入nix-shell后会加入 PATH 的实用工具。如前所述它支持--arg docker true按需启用 Docker 工具并通过shellHook统一加载 bash 补全。nix/overlays包集覆盖nix/overlays目录定义了针对 Nix 包集的 overlays用于在default.nix中调整pkgs新增包或覆盖已有包。当前启用的四个 overlay 见 default.nixbuild-toolbox、checked-shell-script生成带参数校验与补全的脚本见 nix/overlays/checked-shell-script、gitignore、haskell-packages参数化传入compiler。Flake 输出flake.nix 将上述资产封装为标准 Flakepackages.default指向postgrestPackage.bin、packages.profiled指向postgrestProfiled.bin、Linux 下还有packages.staticapps.default指向postgrestStatic缺失时回退到postgrestPackage.bindevShells.default即shell.nix。这意味着也可以直接用nix build、nix develop等 Flake 命令消费这些输出。升级 Nix 依赖完整的升级检查清单见 nix/UPGRADE.md核心流程是# 更新固定的 Nixpkgs 版本 nix-shell --run postgrest-nixpkgs-upgrade # 验证一切可构建 nix-build更细的步骤包括检查各 nix/overlays 是否仍然必要借助二进制缓存运行nix-build构建全部产物并修复可能的 patch 问题若有权限用nix-shell --run postgrest-push-cachix把本地新产物推送到二进制缓存以加速 CInix/UPGRADE.md。小结Postgrest 的 Nix 体系把构建—开发—测试—覆盖率—代码风格—文档—依赖升级整合为一套自洽、可复现的工作流nix-build -A postgrestPackage与postgrestStatic产出二进制nix-shell提供带完整补全的postgrest-工具集postgrest-with-pg-*自动搭建任意受支持版本的临时 PostgreSQL 数据库postgrest-coverage一键产出可视化覆盖率报告。无论是贡献者本地开发还是 CI 上的全矩阵测试这套 Nix 环境都能保证在不同机器上得到一致的结果。【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考