1{
2 lib,
3 stdenv,
4 rustPlatform,
5 fetchFromGitHub,
6 fetchNpmDeps,
7 fetchurl,
8 binaryen,
9 gzip,
10 nodejs,
11 npmHooks,
12 python3,
13 rustc,
14 versionCheckHook,
15 wasm-bindgen-cli_0_2_92,
16 wasm-pack,
17}:
18
19# TODO: package python bindings
20
21let
22
23 # the lindera-unidic v0.32.2 crate uses [1] an outdated unidic-mecab fork [2] and builds it in pure rust
24 # [1] https://github.com/lindera/lindera/blob/v0.32.2/lindera-unidic/build.rs#L5-L11
25 # [2] https://github.com/lindera/unidic-mecab
26 # To find these urls:
27 # rg -A5 download_urls $(nix-build . -A pagefind.cargoDeps --no-out-link)/lindera-*/build.rs
28 lindera-srcs = {
29 unidic-mecab = fetchurl {
30 passthru.vendorDir = "lindera-unidic-*";
31 url = "https://Lindera.dev/unidic-mecab-2.1.2.tar.gz";
32 hash = "sha256-JKx1/k5E2XO1XmWEfDX6Suwtt6QaB7ScoSUUbbn8EYk=";
33 };
34 mecab-ko-dic = fetchurl {
35 passthru.vendorDir = "lindera-ko-dic-*";
36 url = "https://Lindera.dev/mecab-ko-dic-2.1.1-20180720.tar.gz";
37 hash = "sha256-cCztIcYWfp2a68Z0q17lSvWNREOXXylA030FZ8AgWRo=";
38 };
39 ipadic = fetchurl {
40 passthru.vendorDir = "lindera-ipadic-0.*";
41 url = "https://Lindera.dev/mecab-ipadic-2.7.0-20070801.tar.gz";
42 hash = "sha256-CZ5G6A1V58DWkGeDr/cTdI4a6Q9Gxe+W7BU7vwm/VVA=";
43 };
44 cc-cedict = fetchurl {
45 passthru.vendorDir = "lindera-cc-cedict-*";
46 url = "https://lindera.dev/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz";
47 hash = "sha256-7Tz54+yKgGR/DseD3Ana1DuMytLplPXqtv8TpB0JFsg=";
48 };
49 ipadic-neologd = fetchurl {
50 passthru.vendorDir = "lindera-ipadic-neologd-*";
51 url = "https://lindera.dev/mecab-ipadic-neologd-0.0.7-20200820.tar.gz";
52 hash = "sha256-1VwCwgSTKFixeQUFVCdqMzZKne/+FTgM56xT7etqjqI=";
53 };
54 };
55
56in
57
58rustPlatform.buildRustPackage (finalAttrs: {
59 pname = "pagefind";
60 version = "1.4.0";
61
62 src = fetchFromGitHub {
63 owner = "Pagefind";
64 repo = "pagefind";
65 tag = "v${finalAttrs.version}";
66 hash = "sha256-+jArZueDqpJQKg3fKdJjeQQL+egyR6Zi6wqPMZoFgyk=";
67 };
68
69 cargoPatches = [ ./cargo-lock.patch ];
70 cargoHash = "sha256-zbo8NkB9umpNDvkhKXpOdt8hJn+d+nrTXMaUghmIPrg=";
71
72 env.cargoDeps_web = rustPlatform.fetchCargoVendor {
73 name = "cargo-deps-web-${finalAttrs.version}";
74 inherit (finalAttrs) src;
75 sourceRoot = "${finalAttrs.src.name}/pagefind_web";
76 hash = "sha256-DaipINtwePA03YdbSzh6EjH4Q13P3CB9lwcmTOR54dM=";
77 };
78 env.npmDeps_web_js = fetchNpmDeps {
79 name = "pagefind-npm-deps-web-js-${finalAttrs.version}";
80 inherit (finalAttrs) src;
81 sourceRoot = "${finalAttrs.src.name}/pagefind_web_js";
82 hash = "sha256-whpmjNKdiMxNfg7fRIWUPdyRWqsEphhqvQfiM65GYDs=";
83 };
84 env.npmDeps_ui_default = fetchNpmDeps {
85 name = "pagefind-npm-deps-ui-default-${finalAttrs.version}";
86 inherit (finalAttrs) src;
87 sourceRoot = "${finalAttrs.src.name}/pagefind_ui/default";
88 hash = "sha256-voCs49JneWYE1W9U7aB6G13ypH6JqathVDeF58V57U8=";
89 };
90 env.npmDeps_ui_modular = fetchNpmDeps {
91 name = "pagefind-npm-deps-ui-modular-${finalAttrs.version}";
92 inherit (finalAttrs) src;
93 sourceRoot = "${finalAttrs.src.name}/pagefind_ui/modular";
94 hash = "sha256-4d85V2X1doq3G8okgYSXOMuQDoAXCgtAtegFEPr+Wno=";
95 };
96 env.npmDeps_playground = fetchNpmDeps {
97 name = "pagefind-npm-deps-playground-${finalAttrs.version}";
98 inherit (finalAttrs) src;
99 sourceRoot = "${finalAttrs.src.name}/pagefind_playground";
100 hash = "sha256-npo8MV6AAuQ/mGC9iu3bR7pjGoI7NgxuIeh+H3oz7Y8=";
101 };
102
103 env.GIT_VERSION = finalAttrs.version;
104
105 postPatch = ''
106 # Set the correct version, e.g. for `pagefind --version`
107 node .backstage/version.cjs
108
109 # Tricky way to run the cargo setup a second time
110 (
111 cd pagefind_web
112 cargoDeps=$cargoDeps_web cargoSetupPostUnpackHook
113 cargoDeps=$cargoDeps_web cargoSetupPostPatchHook
114 )
115
116 # Tricky way to run npmConfigHook multiple times
117 (
118 local postPatchHooks=() # written to by npmConfigHook
119 source ${npmHooks.npmConfigHook}/nix-support/setup-hook
120 npmRoot=pagefind_web_js npmDeps=$npmDeps_web_js npmConfigHook
121 npmRoot=pagefind_ui/default npmDeps=$npmDeps_ui_default npmConfigHook
122 npmRoot=pagefind_ui/modular npmDeps=$npmDeps_ui_modular npmConfigHook
123 npmRoot=pagefind_playground npmDeps=$npmDeps_playground npmConfigHook
124 )
125
126 # patch build-time dependency downloads
127 (
128 # add support for file:// urls
129 patch -d $cargoDepsCopy/lindera-dictionary-*/ -p1 < ${./lindera-dictionary-support-file-paths.patch}
130
131 # patch urls
132 ${lib.pipe finalAttrs.passthru.lindera-srcs [
133 (lib.mapAttrsToList (
134 key: src: ''
135 # compgen is only in bashInteractive
136 declare -a expanded_glob=($cargoDepsCopy/${src.vendorDir}/build.rs)
137 if [[ "''${#expanded_glob[@]}" -eq 0 ]]; then
138 echo >&2 "ERROR: '$cargoDepsCopy/${src.vendorDir}/build.rs' not found! (pagefind.passthru.lindera-srcs.${key})"
139 false
140 elif [[ "''${#expanded_glob[@]}" -gt 1 ]]; then
141 echo >&2 "ERROR: '$cargoDepsCopy/${src.vendorDir}/build.rs' matches more than one file! (pagefind.passthru.lindera-srcs.${key})"
142 printf >&2 "match: %s\n" "''${expanded_glob[@]}"
143 false
144 fi
145 echo "patching $cargoDepsCopy/${src.vendorDir}/build.rs..."
146 substituteInPlace $cargoDepsCopy/${src.vendorDir}/build.rs --replace-fail "${src.url}" "file://${src}"
147 unset expanded_glob
148 ''
149 ))
150 lib.concatLines
151 ]}
152 )
153
154 # nightly-only feature
155 substituteInPlace pagefind_web/local_build.sh \
156 --replace-fail ' -Z build-std=panic_abort,std' "" \
157 --replace-fail ' -Z build-std-features=panic_immediate_abort' ""
158 '';
159
160 __darwinAllowLocalNetworking = true;
161
162 nativeBuildInputs = [
163 binaryen
164 gzip
165 nodejs
166 rustc
167 rustc.llvmPackages.lld
168 wasm-bindgen-cli_0_2_92
169 wasm-pack
170 ]
171 ++ lib.optionals stdenv.buildPlatform.isDarwin [
172 python3
173 ];
174
175 # build wasm and js assets
176 # based on "test-and-build" in https://github.com/CloudCannon/pagefind/blob/main/.github/workflows/release.yml
177 preBuild = ''
178 export HOME=$(mktemp -d)
179
180 echo Entering ./pagefind_web_js
181 (
182 cd pagefind_web_js
183 npm run build-coupled
184 )
185
186 echo Entering ./pagefind_web
187 (
188 cd pagefind_web
189 bash ./local_build.sh
190 )
191
192 echo Entering ./pagefind_ui/default
193 (
194 cd pagefind_ui/default
195 npm run build
196 )
197
198 echo Entering ./pagefind_ui/modular
199 (
200 cd pagefind_ui/modular
201 npm run build
202 )
203
204 echo Entering ./pagefind_playground
205 (
206 cd pagefind_playground
207 npm run build
208 )
209 '';
210
211 # always build extended
212 buildFeatures = [ "extended" ];
213
214 doInstallCheck = true;
215
216 nativeInstallCheckInputs = [
217 versionCheckHook
218 ];
219
220 passthru = {
221 inherit lindera-srcs;
222 tests.non-extended = finalAttrs.finalPackage.overrideAttrs {
223 buildFeatures = [ ];
224 };
225 };
226
227 meta = {
228 description = "Generate low-bandwidth search index for your static website";
229 homepage = "https://pagefind.app/";
230 changelog = "https://github.com/Pagefind/pagefind/releases/tag/v${finalAttrs.version}";
231 license = lib.licenses.mit;
232 maintainers = with lib.maintainers; [ pbsds ];
233 platforms = lib.platforms.unix;
234 mainProgram = "pagefind";
235 };
236})