diff --git a/CHANGELOG.md b/CHANGELOG.md index fdafd8e98b..ffe0509b63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.17.0 (unreleased) + +### Breaking +- `get_file_hash` is removed, use `get_hash` instead. Arguments do not change + +### Other + +- Add `get_taxonomy_term` function +- Add slugify.paths_keep_dates option +- Add command to generate shell completions +- Fix link generation to colocated assets other than images +- Add `get_hash` Tera function + + ## 0.16.1 (2022-08-14) - Fix many Windows bugs diff --git a/Cargo.lock b/Cargo.lock index 8d83fc78bc..40044ea9d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "ahash" version = "0.8.0" @@ -28,18 +22,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] [[package]] name = "ammonia" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5ed2509ee88cc023cccee37a6fab35826830fe8b748b3869790e7720c2c4a74" +checksum = "4b477377562f3086b7778d241786e9406b883ccfaa03557c0fe0924b9349f13a" dependencies = [ "html5ever", "maplit", @@ -50,9 +44,9 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] @@ -65,9 +59,9 @@ checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" [[package]] name = "anyhow" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508b352bb5c066aac251f6daf6b36eccd03e8a88e8081cd44959ea277a3af9a8" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "arrayvec" @@ -164,9 +158,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array 0.14.6", ] @@ -200,9 +194,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "byte-tools" @@ -224,9 +218,9 @@ checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" [[package]] name = "bytemuck" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" +checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" [[package]] name = "byteorder" @@ -289,6 +283,7 @@ dependencies = [ "iana-time-zone", "num-integer", "num-traits", + "pure-rust-locales", "winapi 0.3.9", ] @@ -316,9 +311,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.17" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", @@ -333,18 +328,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "3.2.4" +version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4179da71abd56c26b54dd0c248cc081c1f43b0a1a7e8448e28e57a29baa993d" +checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "3.2.17" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -449,9 +444,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -564,23 +559,14 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.2" +version = "3.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" +checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173" dependencies = [ "nix", "winapi 0.3.9", ] -[[package]] -name = "deflate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" -dependencies = [ - "adler32", -] - [[package]] name = "derive_more" version = "0.99.17" @@ -611,11 +597,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.3", "crypto-common", ] @@ -627,9 +613,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "either" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "elasticlunr-rs" @@ -728,9 +714,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" dependencies = [ "atty", "humantime", @@ -748,16 +734,15 @@ dependencies = [ [[package]] name = "exr" -version = "1.4.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cc0e06fb5f67e5d6beadf3a382fec9baca1aa751c6d5368fdeee7e5932c215" +checksum = "c9a7880199e74c6d3fe45579df2f436c5913a71405494cb89d59234d86b47dc5" dependencies = [ "bit_field", - "deflate", "flume", "half", - "inflate", "lebe", + "miniz_oxide", "smallvec", "threadpool", ] @@ -835,11 +820,10 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] @@ -896,42 +880,42 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-io" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-sink" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-util" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-core", "futures-io", @@ -1046,9 +1030,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" dependencies = [ "bytes 1.2.1", "fnv", @@ -1134,9 +1118,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1208,24 +1192,24 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.44" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf7d67cf4a22adc5be66e75ebdf769b3f2ea032041437a7061f97a63dad4b" +checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0" dependencies = [ "android_system_properties", "core-foundation-sys", "js-sys", + "once_cell", "wasm-bindgen", "winapi 0.3.9", ] [[package]] name = "idna" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] @@ -1290,15 +1274,6 @@ dependencies = [ "hashbrown 0.12.3", ] -[[package]] -name = "inflate" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" -dependencies = [ - "adler32", -] - [[package]] name = "inotify" version = "0.7.1" @@ -1321,14 +1296,13 @@ dependencies = [ [[package]] name = "insta" -version = "1.18.2" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a9aec10c9a062ef0454fd49ebaefa59239f836d1b30891d9cc2289978dd970" +checksum = "58a931b01c76064c5be919faa2ef0dc570e9a889dcd1e5fef08a8ca6eb4d6c0b" dependencies = [ "console 0.15.1", "linked-hash-map", "once_cell", - "serde", "similar", "yaml-rust", ] @@ -1404,9 +1378,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -1444,9 +1418,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lebe" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "lexical-core" @@ -1472,9 +1446,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.131" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libs" @@ -1715,9 +1689,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" dependencies = [ "autocfg", "scopeguard", @@ -1783,12 +1757,6 @@ dependencies = [ "tendril", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" version = "2.5.0" @@ -1855,9 +1823,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] @@ -1987,10 +1955,11 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nix" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" dependencies = [ + "autocfg", "bitflags", "cfg-if 1.0.0", "libc", @@ -2161,9 +2130,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "onig" @@ -2195,9 +2164,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "open" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23a407004a1033f53e93f9b45580d14de23928faad187384f891507c9b0c045" +checksum = "b4a3100141f1733ea40b53381b0ae3117330735ef22309a190ac57b9576ea716" dependencies = [ "pathdiff", "windows-sys", @@ -2300,15 +2269,15 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" +checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048" dependencies = [ "thiserror", "ucd-trie", @@ -2316,9 +2285,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13570633aff33c6d22ce47dd566b10a3b9122c2fe9d8e7501895905be532b91" +checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1" dependencies = [ "pest", "pest_generator", @@ -2326,9 +2295,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c567e5702efdc79fb18859ea74c3eb36e14c43da7b8c1f098a4ed6514ec7a0" +checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c" dependencies = [ "pest", "pest_meta", @@ -2339,13 +2308,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb32be5ee3bbdafa8c7a18b0a8a8d962b66cfa2ceee4037f49267a50ee821fe" +checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6" dependencies = [ "once_cell", "pest", - "sha-1 0.10.0", + "sha1", ] [[package]] @@ -2427,18 +2396,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", @@ -2479,13 +2448,13 @@ dependencies = [ [[package]] name = "png" -version = "0.17.5" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" +checksum = "8f0e7f4c94ec26ff209cee506314212639d6c91b80afb82984819fafce9df01c" dependencies = [ "bitflags", "crc32fast", - "deflate", + "flate2", "miniz_oxide", ] @@ -2545,6 +2514,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "pure-rust-locales" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45c49fc4f91f35bae654f85ebb3a44d60ac64f11b3166ffa609def390c732d8" + [[package]] name = "quick-error" version = "1.2.3" @@ -2608,7 +2583,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2628,7 +2603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2642,9 +2617,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.7", ] @@ -2788,9 +2763,9 @@ dependencies = [ [[package]] name = "roxmltree" -version = "0.13.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf7d7b1ea646d380d0e8153158063a6da7efe30ddbf3184042848e3f8a6f671" +checksum = "112908c3ac4711a1554b3948432ecaf5f061a951aa326977b63f7f72a86a4c0e" dependencies = [ "xmlparser", ] @@ -2922,9 +2897,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -2945,24 +2920,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "serde" -version = "1.0.143" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.143" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -2971,9 +2946,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "indexmap", "itoa 1.0.3", @@ -2995,9 +2970,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.9" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50845f68d5c693aac7d72a25415ddd21cb8182c04eafe447b73af55a05f9e1b" +checksum = "8613d593412a0deb7bbd8de9d908efff5a0cb9ccd8f62c641e7b2ed2f57291d1" dependencies = [ "indexmap", "itoa 1.0.3", @@ -3019,25 +2994,25 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -3097,9 +3072,9 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi 0.3.9", @@ -3160,9 +3135,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "svg_metadata" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39f36262efe61096a17aa42140b0e44b9189806c3fa71ab3cff123429938eb0" +checksum = "eacedf9d5c2552d510718db410b2c0e0f367456acacf317000d6d31067e50ccd" dependencies = [ "doc-comment", "lazy_static", @@ -3172,9 +3147,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -3263,9 +3238,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4685e72cb35f0eb74319c8fe2d3b61e93da5609841cde2cb87fcc3bea56d20" +checksum = "3df578c295f9ec044ff1c829daf31bb7581d5b3c2a7a3d87419afe1f2531438c" dependencies = [ "chrono", "chrono-tz", @@ -3326,24 +3301,24 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "thiserror" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" dependencies = [ "proc-macro2", "quote", @@ -3381,9 +3356,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db76ff9fa4b1458b3c7f077f3ff9887394058460d21e634355b273aaf11eea45" +checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b" dependencies = [ "itoa 1.0.3", "libc", @@ -3420,9 +3395,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95" dependencies = [ "autocfg", "bytes 1.2.1", @@ -3459,9 +3434,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes 1.2.1", "futures-core", @@ -3520,9 +3495,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uncased" @@ -3618,30 +3593,30 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unsafe-libyaml" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931179334a56395bcf64ba5e0ff56781381c1a5832178280c7d7f91d1679aeb0" +checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68" [[package]] name = "untrusted" @@ -3651,13 +3626,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] @@ -3724,9 +3698,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3734,9 +3708,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", @@ -3749,9 +3723,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3761,9 +3735,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3771,9 +3745,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -3784,15 +3758,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3950,7 +3924,7 @@ dependencies = [ "mio 0.6.23", "mio-extras", "rand 0.7.3", - "sha-1 0.8.2", + "sha-1", "slab", "url", ] @@ -4009,7 +3983,7 @@ dependencies = [ [[package]] name = "zola" -version = "0.16.1" +version = "0.17.0" dependencies = [ "clap", "clap_complete", diff --git a/Cargo.toml b/Cargo.toml index d17eab87f1..f7945099cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zola" -version = "0.16.1" +version = "0.17.0" authors = ["Vincent Prouillet "] edition = "2018" license = "MIT" @@ -13,8 +13,6 @@ keywords = ["static", "site", "generator", "blog"] include = ["src/**/*", "LICENSE", "README.md"] [build-dependencies] -clap = "3" -clap_complete = "3" winres = "0.1" time = "0.3" @@ -23,6 +21,7 @@ name = "zola" [dependencies] clap = { version = "3", features = ["derive"] } +clap_complete = "3" # Below is for the serve cmd hyper = { version = "0.14.1", default-features = false, features = ["runtime", "server", "http2", "http1"] } tokio = { version = "1.0.1", default-features = false, features = ["rt", "fs", "time"] } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f6432ad0fb..0d8add88dc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,7 +40,7 @@ stages: displayName: Cargo build (Native TLS) - script: cargo build --all displayName: Cargo build (Rust TLS) - - script: cargo test --all + - script: RUST_BACKTRACE=1 cargo test --all displayName: Cargo test diff --git a/build.rs b/build.rs index 40f11040bb..71b1c452fd 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,3 @@ -// use clap::Shell; - -include!("src/cli.rs"); - fn generate_pe_header() { use time::OffsetDateTime; @@ -18,12 +14,6 @@ fn generate_pe_header() { } fn main() { - // disabled below as it fails in CI - // let mut app = build_cli(); - // app.gen_completions("zola", Shell::Bash, "completions/"); - // app.gen_completions("zola", Shell::Fish, "completions/"); - // app.gen_completions("zola", Shell::Zsh, "completions/"); - // app.gen_completions("zola", Shell::PowerShell, "completions/"); if std::env::var("CARGO_CFG_TARGET_OS").unwrap() != "windows" && std::env::var("PROFILE").unwrap() != "release" { diff --git a/completions/_zola b/completions/_zola deleted file mode 100644 index 3ca5a4d28f..0000000000 --- a/completions/_zola +++ /dev/null @@ -1,144 +0,0 @@ -#compdef zola - -autoload -U is-at-least - -_zola() { - typeset -A opt_args - typeset -a _arguments_options - local ret=1 - - if is-at-least 5.2; then - _arguments_options=(-s -S -C) - else - _arguments_options=(-s -C) - fi - - local context curcontext="$curcontext" state line - _arguments "${_arguments_options[@]}" \ -'-c+[Path to a config file other than config.toml]' \ -'--config=[Path to a config file other than config.toml]' \ -'-h[Prints help information]' \ -'--help[Prints help information]' \ -'-V[Prints version information]' \ -'--version[Prints version information]' \ -":: :_zola_commands" \ -"*::: :->zola" \ -&& ret=0 - case $state in - (zola) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:zola-command-$line[1]:" - case $line[1] in - (init) -_arguments "${_arguments_options[@]}" \ -'-h[Prints help information]' \ -'--help[Prints help information]' \ -'-V[Prints version information]' \ -'--version[Prints version information]' \ -'::name -- Name of the project. Will create a new directory with that name in the current directory:_files' \ -&& ret=0 -;; -(build) -_arguments "${_arguments_options[@]}" \ -'-u+[Force the base URL to be that value (default to the one in config.toml)]' \ -'--base-url=[Force the base URL to be that value (default to the one in config.toml)]' \ -'-o+[Outputs the generated site in the given path]' \ -'--output-dir=[Outputs the generated site in the given path]' \ -'--drafts[Include drafts when loading the site]' \ -'-h[Prints help information]' \ -'--help[Prints help information]' \ -'-V[Prints version information]' \ -'--version[Prints version information]' \ -&& ret=0 -;; -(serve) -_arguments "${_arguments_options[@]}" \ -'-i+[Interface to bind on]' \ -'--interface=[Interface to bind on]' \ -'-p+[Which port to use]' \ -'--port=[Which port to use]' \ -'-o+[Outputs the generated site in the given path]' \ -'--output-dir=[Outputs the generated site in the given path]' \ -'-u+[Changes the base_url]' \ -'--base-url=[Changes the base_url]' \ -'--watch-only[Do not start a server, just re-build project on changes]' \ -'--drafts[Include drafts when loading the site]' \ -'-O[Open site in the default browser]' \ -'--open[Open site in the default browser]' \ -'-h[Prints help information]' \ -'--help[Prints help information]' \ -'-V[Prints version information]' \ -'--version[Prints version information]' \ -&& ret=0 -;; -(check) -_arguments "${_arguments_options[@]}" \ -'--drafts[Include drafts when loading the site]' \ -'-h[Prints help information]' \ -'--help[Prints help information]' \ -'-V[Prints version information]' \ -'--version[Prints version information]' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -'-h[Prints help information]' \ -'--help[Prints help information]' \ -'-V[Prints version information]' \ -'--version[Prints version information]' \ -&& ret=0 -;; - esac - ;; -esac -} - -(( $+functions[_zola_commands] )) || -_zola_commands() { - local commands; commands=( - "init:Create a new Zola project" \ -"build:Deletes the output directory if there is one and builds the site" \ -"serve:Serve the site. Rebuild and reload on change automatically" \ -"check:Try building the project without rendering it. Checks links" \ -"help:Prints this message or the help of the given subcommand(s)" \ - ) - _describe -t commands 'zola commands' commands "$@" -} -(( $+functions[_zola__build_commands] )) || -_zola__build_commands() { - local commands; commands=( - - ) - _describe -t commands 'zola build commands' commands "$@" -} -(( $+functions[_zola__check_commands] )) || -_zola__check_commands() { - local commands; commands=( - - ) - _describe -t commands 'zola check commands' commands "$@" -} -(( $+functions[_zola__help_commands] )) || -_zola__help_commands() { - local commands; commands=( - - ) - _describe -t commands 'zola help commands' commands "$@" -} -(( $+functions[_zola__init_commands] )) || -_zola__init_commands() { - local commands; commands=( - - ) - _describe -t commands 'zola init commands' commands "$@" -} -(( $+functions[_zola__serve_commands] )) || -_zola__serve_commands() { - local commands; commands=( - - ) - _describe -t commands 'zola serve commands' commands "$@" -} - -_zola "$@" \ No newline at end of file diff --git a/completions/_zola.ps1 b/completions/_zola.ps1 deleted file mode 100644 index 977ee07122..0000000000 --- a/completions/_zola.ps1 +++ /dev/null @@ -1,93 +0,0 @@ - -using namespace System.Management.Automation -using namespace System.Management.Automation.Language - -Register-ArgumentCompleter -Native -CommandName 'zola' -ScriptBlock { - param($wordToComplete, $commandAst, $cursorPosition) - - $commandElements = $commandAst.CommandElements - $command = @( - 'zola' - for ($i = 1; $i -lt $commandElements.Count; $i++) { - $element = $commandElements[$i] - if ($element -isnot [StringConstantExpressionAst] -or - $element.StringConstantType -ne [StringConstantType]::BareWord -or - $element.Value.StartsWith('-')) { - break - } - $element.Value - }) -join ';' - - $completions = @(switch ($command) { - 'zola' { - [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Path to a config file other than config.toml in the root of project') - [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'Path to a config file other than config.toml in the root of project') - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Create a new Zola project') - [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Deletes the output directory if there is one and builds the site') - [CompletionResult]::new('serve', 'serve', [CompletionResultType]::ParameterValue, 'Serve the site. Rebuild and reload on change automatically') - [CompletionResult]::new('check', 'check', [CompletionResultType]::ParameterValue, 'Try building the project without rendering it. Checks links') - [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Prints this message or the help of the given subcommand(s)') - break - } - 'zola;init' { - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') - break - } - 'zola;build' { - [CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'Force the base URL to be that value (default to the one in config.toml)') - [CompletionResult]::new('--base-url', 'base-url', [CompletionResultType]::ParameterName, 'Force the base URL to be that value (default to the one in config.toml)') - [CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'Outputs the generated site in the given path') - [CompletionResult]::new('--output-dir', 'output-dir', [CompletionResultType]::ParameterName, 'Outputs the generated site in the given path') - [CompletionResult]::new('--drafts', 'drafts', [CompletionResultType]::ParameterName, 'Include drafts when loading the site') - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') - break - } - 'zola;serve' { - [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'Interface to bind on') - [CompletionResult]::new('--interface', 'interface', [CompletionResultType]::ParameterName, 'Interface to bind on') - [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Which port to use') - [CompletionResult]::new('--port', 'port', [CompletionResultType]::ParameterName, 'Which port to use') - [CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'Outputs the generated site in the given path') - [CompletionResult]::new('--output-dir', 'output-dir', [CompletionResultType]::ParameterName, 'Outputs the generated site in the given path') - [CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'Changes the base_url') - [CompletionResult]::new('--base-url', 'base-url', [CompletionResultType]::ParameterName, 'Changes the base_url') - [CompletionResult]::new('--watch-only', 'watch-only', [CompletionResultType]::ParameterName, 'Do not start a server, just re-build project on changes') - [CompletionResult]::new('--drafts', 'drafts', [CompletionResultType]::ParameterName, 'Include drafts when loading the site') - [CompletionResult]::new('-O', 'O', [CompletionResultType]::ParameterName, 'Open site in the default browser') - [CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'Open site in the default browser') - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') - break - } - 'zola;check' { - [CompletionResult]::new('--drafts', 'drafts', [CompletionResultType]::ParameterName, 'Include drafts when loading the site') - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') - break - } - 'zola;help' { - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') - break - } - }) - - $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | - Sort-Object -Property ListItemText -} diff --git a/completions/zola.bash b/completions/zola.bash deleted file mode 100644 index dcaa073423..0000000000 --- a/completions/zola.bash +++ /dev/null @@ -1,187 +0,0 @@ -_zola() { - local i cur prev opts cmds - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - cmd="" - opts="" - - for i in ${COMP_WORDS[@]} - do - case "${i}" in - zola) - cmd="zola" - ;; - - build) - cmd+="__build" - ;; - check) - cmd+="__check" - ;; - help) - cmd+="__help" - ;; - init) - cmd+="__init" - ;; - serve) - cmd+="__serve" - ;; - *) - ;; - esac - done - - case "${cmd}" in - zola) - opts=" -h -V -c --help --version --config init build serve check help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - - --config) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -c) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - - zola__build) - opts=" -h -V -u -o --drafts --help --version --base-url --output-dir " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - - --base-url) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -u) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --output-dir) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -o) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - zola__check) - opts=" -h -V --drafts --help --version " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - zola__help) - opts=" -h -V --help --version " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - zola__init) - opts=" -h -V --help --version " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - zola__serve) - opts=" -O -h -V -i -p -o -u --watch-only --drafts --open --help --version --interface --port --output-dir --base-url " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - - --interface) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -i) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --port) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -p) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --output-dir) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -o) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --base-url) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -u) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - esac -} - -complete -F _zola -o bashdefault -o default zola diff --git a/completions/zola.fish b/completions/zola.fish deleted file mode 100644 index a0d1bad893..0000000000 --- a/completions/zola.fish +++ /dev/null @@ -1,29 +0,0 @@ -complete -c zola -n "__fish_use_subcommand" -s c -l config -d 'Path to a config file other than config.toml in the root of project' -complete -c zola -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' -complete -c zola -n "__fish_use_subcommand" -s V -l version -d 'Prints version information' -complete -c zola -n "__fish_use_subcommand" -f -a "init" -d 'Create a new Zola project' -complete -c zola -n "__fish_use_subcommand" -f -a "build" -d 'Deletes the output directory if there is one and builds the site' -complete -c zola -n "__fish_use_subcommand" -f -a "serve" -d 'Serve the site. Rebuild and reload on change automatically' -complete -c zola -n "__fish_use_subcommand" -f -a "check" -d 'Try building the project without rendering it. Checks links' -complete -c zola -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)' -complete -c zola -n "__fish_seen_subcommand_from init" -s h -l help -d 'Prints help information' -complete -c zola -n "__fish_seen_subcommand_from init" -s V -l version -d 'Prints version information' -complete -c zola -n "__fish_seen_subcommand_from build" -s u -l base-url -d 'Force the base URL to be that value (default to the one in config.toml)' -complete -c zola -n "__fish_seen_subcommand_from build" -s o -l output-dir -d 'Outputs the generated site in the given path' -complete -c zola -n "__fish_seen_subcommand_from build" -l drafts -d 'Include drafts when loading the site' -complete -c zola -n "__fish_seen_subcommand_from build" -s h -l help -d 'Prints help information' -complete -c zola -n "__fish_seen_subcommand_from build" -s V -l version -d 'Prints version information' -complete -c zola -n "__fish_seen_subcommand_from serve" -s i -l interface -d 'Interface to bind on' -complete -c zola -n "__fish_seen_subcommand_from serve" -s p -l port -d 'Which port to use' -complete -c zola -n "__fish_seen_subcommand_from serve" -s o -l output-dir -d 'Outputs the generated site in the given path' -complete -c zola -n "__fish_seen_subcommand_from serve" -s u -l base-url -d 'Changes the base_url' -complete -c zola -n "__fish_seen_subcommand_from serve" -l watch-only -d 'Do not start a server, just re-build project on changes' -complete -c zola -n "__fish_seen_subcommand_from serve" -l drafts -d 'Include drafts when loading the site' -complete -c zola -n "__fish_seen_subcommand_from serve" -s O -l open -d 'Open site in the default browser' -complete -c zola -n "__fish_seen_subcommand_from serve" -s h -l help -d 'Prints help information' -complete -c zola -n "__fish_seen_subcommand_from serve" -s V -l version -d 'Prints version information' -complete -c zola -n "__fish_seen_subcommand_from check" -l drafts -d 'Include drafts when loading the site' -complete -c zola -n "__fish_seen_subcommand_from check" -s h -l help -d 'Prints help information' -complete -c zola -n "__fish_seen_subcommand_from check" -s V -l version -d 'Prints version information' -complete -c zola -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information' -complete -c zola -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information' diff --git a/components/config/src/config/mod.rs b/components/config/src/config/mod.rs index 3221166773..b41ccc27fb 100644 --- a/components/config/src/config/mod.rs +++ b/components/config/src/config/mod.rs @@ -658,10 +658,30 @@ anchors = "off" let config = Config::parse(config_str).unwrap(); assert_eq!(config.slugify.paths, SlugifyStrategy::On); + assert_eq!(config.slugify.paths_keep_dates, false); assert_eq!(config.slugify.taxonomies, SlugifyStrategy::Safe); assert_eq!(config.slugify.anchors, SlugifyStrategy::Off); } + #[test] + fn slugify_paths_keep_dates() { + let config_str = r#" +title = "My site" +base_url = "example.com" + +[slugify] +paths_keep_dates = true +taxonomies = "off" +anchors = "safe" + "#; + + let config = Config::parse(config_str).unwrap(); + assert_eq!(config.slugify.paths, SlugifyStrategy::On); + assert_eq!(config.slugify.paths_keep_dates, true); + assert_eq!(config.slugify.taxonomies, SlugifyStrategy::Off); + assert_eq!(config.slugify.anchors, SlugifyStrategy::Safe); + } + #[test] fn cannot_overwrite_theme_mapping_with_invalid_type() { let config_str = r#" diff --git a/components/config/src/config/slugify.rs b/components/config/src/config/slugify.rs index c22065b34d..1a67376c2a 100644 --- a/components/config/src/config/slugify.rs +++ b/components/config/src/config/slugify.rs @@ -6,6 +6,7 @@ use utils::slugs::SlugifyStrategy; #[serde(default)] pub struct Slugify { pub paths: SlugifyStrategy, + pub paths_keep_dates: bool, pub taxonomies: SlugifyStrategy, pub anchors: SlugifyStrategy, } diff --git a/components/content/src/page.rs b/components/content/src/page.rs index 57d9812f85..7501a4c622 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -126,7 +126,9 @@ impl Page { }; if let Some(ref caps) = RFC3339_DATE.captures(&file_path_for_slug) { - slug_from_dated_filename = Some(caps.name("slug").unwrap().as_str().to_string()); + if !config.slugify.paths_keep_dates { + slug_from_dated_filename = Some(caps.name("slug").unwrap().as_str().to_string()); + } if page.meta.date.is_none() { page.meta.date = Some(caps.name("datetime").unwrap().as_str().to_string()); page.meta.date_to_datetime(); diff --git a/components/content/src/sorting.rs b/components/content/src/sorting.rs index 313df3674c..eb4b91fb1e 100644 --- a/components/content/src/sorting.rs +++ b/components/content/src/sorting.rs @@ -16,6 +16,7 @@ pub fn sort_pages(pages: &[&Page], sort_by: SortBy) -> (Vec, Vec page.meta.title.is_some(), SortBy::Weight => page.meta.weight.is_some(), + SortBy::Slug => true, SortBy::None => unreachable!(), }); @@ -32,6 +33,7 @@ pub fn sort_pages(pages: &[&Page], sort_by: SortBy) -> (Vec, Vec a.meta.weight.unwrap().cmp(&b.meta.weight.unwrap()), + SortBy::Slug => natural_lexical_cmp(&a.slug, &b.slug), SortBy::None => unreachable!(), }; @@ -73,6 +75,16 @@ mod tests { Page::new(format!("content/hello-{}.md", weight), front_matter, &PathBuf::new()) } + fn create_page_with_slug(slug: &str) -> Page { + let front_matter = PageFrontMatter { slug: Some(slug.to_owned()), ..Default::default() }; + let mut page = + Page::new(format!("content/hello-{}.md", slug), front_matter, &PathBuf::new()); + // Normally, the slug field is populated when a page is parsed, but + // since we're creating one manually, we have to set it explicitly + page.slug = slug.to_owned(); + page + } + #[test] fn can_sort_by_dates() { let page1 = create_page_with_date("2018-01-01", None); @@ -185,6 +197,28 @@ mod tests { ); } + #[test] + fn can_sort_by_slug() { + let page1 = create_page_with_slug("2"); + let page2 = create_page_with_slug("3"); + let page3 = create_page_with_slug("1"); + let (pages, ignored_pages) = sort_pages(&[&page1, &page2, &page3], SortBy::Slug); + assert_eq!(pages[0], page3.file.path); + assert_eq!(pages[1], page1.file.path); + assert_eq!(pages[2], page2.file.path); + assert_eq!(ignored_pages.len(), 0); + + // 10 should come after 2 + let page1 = create_page_with_slug("1"); + let page2 = create_page_with_slug("10"); + let page3 = create_page_with_slug("2"); + let (pages, ignored_pages) = sort_pages(&[&page1, &page2, &page3], SortBy::Slug); + assert_eq!(pages[0], page1.file.path); + assert_eq!(pages[1], page3.file.path); + assert_eq!(pages[2], page2.file.path); + assert_eq!(ignored_pages.len(), 0); + } + #[test] fn can_find_ignored_pages() { let page1 = create_page_with_date("2018-01-01", None); diff --git a/components/content/src/taxonomies.rs b/components/content/src/taxonomies.rs index 52c86e0c01..23494705c1 100644 --- a/components/content/src/taxonomies.rs +++ b/components/content/src/taxonomies.rs @@ -23,14 +23,17 @@ pub struct SerializedTaxonomyTerm<'a> { path: &'a str, permalink: &'a str, pages: Vec>, + page_count: usize, } impl<'a> SerializedTaxonomyTerm<'a> { - pub fn from_item(item: &'a TaxonomyTerm, library: &'a Library) -> Self { + pub fn from_item(item: &'a TaxonomyTerm, library: &'a Library, include_pages: bool) -> Self { let mut pages = vec![]; - for p in &item.pages { - pages.push(SerializingPage::new(&library.pages[p], Some(library), false)); + if include_pages { + for p in &item.pages { + pages.push(SerializingPage::new(&library.pages[p], Some(library), false)); + } } SerializedTaxonomyTerm { @@ -39,6 +42,7 @@ impl<'a> SerializedTaxonomyTerm<'a> { path: &item.path, permalink: &item.permalink, pages, + page_count: item.pages.len(), } } } @@ -79,7 +83,14 @@ impl TaxonomyTerm { } pub fn serialize<'a>(&'a self, library: &'a Library) -> SerializedTaxonomyTerm<'a> { - SerializedTaxonomyTerm::from_item(self, library) + SerializedTaxonomyTerm::from_item(self, library, true) + } + + pub fn serialize_without_pages<'a>( + &'a self, + library: &'a Library, + ) -> SerializedTaxonomyTerm<'a> { + SerializedTaxonomyTerm::from_item(self, library, false) } pub fn merge(&mut self, other: Self) { @@ -104,7 +115,7 @@ pub struct SerializedTaxonomy<'a> { impl<'a> SerializedTaxonomy<'a> { pub fn from_taxonomy(taxonomy: &'a Taxonomy, library: &'a Library) -> Self { let items: Vec = - taxonomy.items.iter().map(|i| SerializedTaxonomyTerm::from_item(i, library)).collect(); + taxonomy.items.iter().map(|i| SerializedTaxonomyTerm::from_item(i, library, true)).collect(); SerializedTaxonomy { kind: &taxonomy.kind, lang: &taxonomy.lang, @@ -176,7 +187,7 @@ impl Taxonomy { let mut context = Context::new(); context.insert("config", &config.serialize(&self.lang)); context.insert("lang", &self.lang); - context.insert("term", &SerializedTaxonomyTerm::from_item(item, library)); + context.insert("term", &SerializedTaxonomyTerm::from_item(item, library, true)); context.insert("taxonomy", &self.kind); context.insert("current_url", &self.permalink); context.insert("current_path", &self.path); @@ -199,7 +210,7 @@ impl Taxonomy { let mut context = Context::new(); context.insert("config", &config.serialize(&self.lang)); let terms: Vec = - self.items.iter().map(|i| SerializedTaxonomyTerm::from_item(i, library)).collect(); + self.items.iter().map(|i| SerializedTaxonomyTerm::from_item(i, library, true)).collect(); context.insert("terms", &terms); context.insert("lang", &self.lang); context.insert("taxonomy", &self.kind); diff --git a/components/content/src/types.rs b/components/content/src/types.rs index e058dec9a3..4d78303e82 100644 --- a/components/content/src/types.rs +++ b/components/content/src/types.rs @@ -15,6 +15,8 @@ pub enum SortBy { TitleBytes, /// Lower weight comes first Weight, + /// Sort by slug + Slug, /// No sorting None, } diff --git a/components/imageproc/src/lib.rs b/components/imageproc/src/lib.rs index db56d4888e..52c2af85ea 100644 --- a/components/imageproc/src/lib.rs +++ b/components/imageproc/src/lib.rs @@ -4,7 +4,7 @@ use std::ffi::OsStr; use std::fs::{self, File}; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; -use std::{collections::hash_map::DefaultHasher, io::Write}; +use std::{collections::hash_map::DefaultHasher, io::{Write, BufWriter}}; use image::error::ImageResult; use image::io::Reader as ImgReader; @@ -322,14 +322,15 @@ impl ImageOp { let img = fix_orientation(&img, &self.input_path).unwrap_or(img); - let mut f = File::create(target_path)?; + let f = File::create(target_path)?; + let mut buffered_f = BufWriter::new(f); match self.format { Format::Png => { - img.write_to(&mut f, ImageOutputFormat::Png)?; + img.write_to(&mut buffered_f, ImageOutputFormat::Png)?; } Format::Jpeg(q) => { - img.write_to(&mut f, ImageOutputFormat::Jpeg(q))?; + img.write_to(&mut buffered_f, ImageOutputFormat::Jpeg(q))?; } Format::WebP(q) => { let encoder = webp::Encoder::from_image(&img) @@ -338,7 +339,7 @@ impl ImageOp { Some(q) => encoder.encode(q as f32), None => encoder.encode_lossless(), }; - f.write_all(memory.as_bytes())?; + buffered_f.write_all(memory.as_bytes())?; } } diff --git a/components/libs/Cargo.toml b/components/libs/Cargo.toml index b2ef1d4272..6dbb39ae36 100644 --- a/components/libs/Cargo.toml +++ b/components/libs/Cargo.toml @@ -34,7 +34,7 @@ sha2 = "0.10" slug = "0.1" svg_metadata = "0.4" syntect = "5" -tera = { version = "1", features = ["preserve_order"] } +tera = { version = "1.17", features = ["preserve_order", "date-locale"] } termcolor = "1.0.4" time = "0.3" toml = "0.5" diff --git a/components/markdown/src/markdown.rs b/components/markdown/src/markdown.rs index 63007e12b5..912eae3841 100644 --- a/components/markdown/src/markdown.rs +++ b/components/markdown/src/markdown.rs @@ -56,7 +56,10 @@ fn insert_many(input: &mut Vec, elem_to_insert: Vec<(usize, T)>) { /// Colocated asset links refers to the files in the same directory. fn is_colocated_asset_link(link: &str) -> bool { - !link.starts_with('/') && !link.starts_with('#') && !STARTS_WITH_SCHEMA_RE.is_match(link) + !link.starts_with('/') + && !link.starts_with("..") + && !link.starts_with('#') + && !STARTS_WITH_SCHEMA_RE.is_match(link) } #[derive(Debug)] @@ -171,6 +174,8 @@ fn fix_link( } } } + } else if is_colocated_asset_link(link) { + format!("{}{}", context.current_page_permalink, link) } else if is_external_link(link) { external_links.push(link.to_owned()); link.to_owned() @@ -606,4 +611,22 @@ mod tests { assert!(!is_external_link("http.jpg")) } + + #[test] + // Tests for link that points to files in the same directory + fn test_is_colocated_asset_link_true() { + let links: [&str; 3] = ["./same-dir.md", "file.md", "qwe.js"]; + for link in links { + assert!(is_colocated_asset_link(link)); + } + } + + #[test] + // Tests for files where the link points to a different directory + fn test_is_colocated_asset_link_false() { + let links: [&str; 2] = ["/other-dir/file.md", "../sub-dir/file.md"]; + for link in links { + assert!(!is_colocated_asset_link(link)); + } + } } diff --git a/components/site/src/minify.rs b/components/site/src/minify.rs index 46a48f4808..ceed8ff483 100644 --- a/components/site/src/minify.rs +++ b/components/site/src/minify.rs @@ -6,6 +6,8 @@ use libs::minify_html::{minify, Cfg}; pub fn html(html: String) -> Result { let mut cfg = Cfg::spec_compliant(); cfg.keep_html_and_head_opening_tags = true; + cfg.minify_css = true; + cfg.minify_js = true; let minified = minify(html.as_bytes(), &cfg); match std::str::from_utf8(&minified) { @@ -83,4 +85,61 @@ mod tests { let res = html(input.to_owned()).unwrap(); assert_eq!(res, expected); } + + // https://github.com/getzola/zola/issues/1765 + #[test] + fn can_minify_css() { + let input = r#" + + + + + + + + + +

Example blog post

+ + FOO BAR + + +"#; + let expected = r#"

Example blog post

FOO BAR"#; + let res = html(input.to_owned()).unwrap(); + assert_eq!(res, expected); + } + + // https://github.com/getzola/zola/issues/1765 + #[test] + fn can_minify_js() { + let input = r#" + + + + + + + + + +

Example blog post

+ + FOO BAR + + +"#; + let expected = r#"

Example blog post

FOO BAR"#; + let res = html(input.to_owned()).unwrap(); + assert_eq!(res, expected); + } } + diff --git a/components/site/src/tpls.rs b/components/site/src/tpls.rs index 98d8066534..d1e2eacd5a 100644 --- a/components/site/src/tpls.rs +++ b/components/site/src/tpls.rs @@ -53,14 +53,13 @@ pub fn register_early_global_fns(site: &mut Site) -> TeraResult<()> { ), ); site.tera.register_function( - "get_file_hash", - global_fns::GetFileHash::new( + "get_hash", + global_fns::GetHash::new( site.base_path.clone(), site.config.theme.clone(), site.output_path.clone(), ), ); - site.tera.register_filter( "markdown", filters::MarkdownFilter::new( @@ -91,4 +90,12 @@ pub fn register_tera_global_fns(site: &mut Site) { site.library.clone(), ), ); + site.tera.register_function( + "get_taxonomy_term", + global_fns::GetTaxonomyTerm::new( + &site.config.default_language, + site.taxonomies.clone(), + site.library.clone(), + ), + ); } diff --git a/components/templates/src/global_fns/content.rs b/components/templates/src/global_fns/content.rs index a4555b42a9..84c155fd71 100644 --- a/components/templates/src/global_fns/content.rs +++ b/components/templates/src/global_fns/content.rs @@ -1,4 +1,4 @@ -use content::{Library, Taxonomy}; +use content::{Library, Taxonomy, TaxonomyTerm}; use libs::tera::{from_value, to_value, Function as TeraFn, Result, Value}; use std::collections::HashMap; use std::path::PathBuf; @@ -182,6 +182,93 @@ impl TeraFn for GetTaxonomy { } } +#[derive(Debug)] +pub struct GetTaxonomyTerm { + library: Arc>, + taxonomies: HashMap, + default_lang: String, +} +impl GetTaxonomyTerm { + pub fn new( + default_lang: &str, + all_taxonomies: Vec, + library: Arc>, + ) -> Self { + let mut taxonomies = HashMap::new(); + for taxo in all_taxonomies { + taxonomies.insert(format!("{}-{}", taxo.kind.name, taxo.lang), taxo); + } + Self { taxonomies, library, default_lang: default_lang.to_string() } + } +} +impl TeraFn for GetTaxonomyTerm { + fn call(&self, args: &HashMap) -> Result { + let kind = required_arg!( + String, + args.get("kind"), + "`get_taxonomy_term` requires a `kind` argument with a string value" + ); + let term = required_arg!( + String, + args.get("term"), + "`get_taxonomy_term` requires a `term` argument with a string value" + ); + let include_pages = optional_arg!( + bool, + args.get("include_pages"), + "`get_taxonomy_term`: `include_pages` must be a boolean (true or false)" + ) + .unwrap_or(true); + let required = optional_arg!( + bool, + args.get("required"), + "`get_taxonomy_term`: `required` must be a boolean (true or false)" + ) + .unwrap_or(true); + + let lang = optional_arg!( + String, + args.get("lang"), + "`get_taxonomy_term_by_name`: `lang` must be a string" + ) + .unwrap_or_else(|| self.default_lang.clone()); + + let tax: &Taxonomy = match (self.taxonomies.get(&format!("{}-{}", kind, lang)), required) { + (Some(t), _) => t, + (None, false) => { + return Ok(Value::Null); + } + (None, true) => { + return Err(format!( + "`get_taxonomy_term_by_name` received an unknown taxonomy as kind: {}", + kind + ) + .into()); + } + }; + + let term: &TaxonomyTerm = match (tax.items.iter().find(|i| i.name == term), required) { + (Some(t), _) => t, + (None, false) => { + return Ok(Value::Null); + } + (None, true) => { + return Err(format!( + "`get_taxonomy_term_by_name` received an unknown taxonomy as kind: {}", + kind + ) + .into()); + } + }; + + if include_pages { + Ok(to_value(term.serialize(&self.library.read().unwrap())).unwrap()) + } else { + Ok(to_value(term.serialize_without_pages(&self.library.read().unwrap())).unwrap()) + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -325,4 +412,68 @@ mod tests { args.insert("name".to_string(), to_value("random").unwrap()); assert!(static_fn.call(&args).is_err()); } + + #[test] + fn can_get_taxonomy_term() { + let mut config = Config::default_for_test(); + config.slugify.taxonomies = SlugifyStrategy::On; + let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; + let taxo_config_fr = + TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; + config.slugify_taxonomies(); + let library = Arc::new(RwLock::new(Library::new(&config))); + let tag = TaxonomyTerm::new("Programming", &config.default_language, "tags", &[], &config); + let tag_fr = TaxonomyTerm::new("Programmation", "fr", "tags", &[], &config); + let tags = Taxonomy { + kind: taxo_config, + lang: config.default_language.clone(), + slug: "tags".to_string(), + path: "/tags/".to_string(), + permalink: "https://vincent.is/tags/".to_string(), + items: vec![tag], + }; + let tags_fr = Taxonomy { + kind: taxo_config_fr, + lang: "fr".to_owned(), + slug: "tags".to_string(), + path: "/fr/tags/".to_string(), + permalink: "https://vincent.is/fr/tags/".to_string(), + items: vec![tag_fr], + }; + + let taxonomies = vec![tags.clone(), tags_fr.clone()]; + let static_fn = GetTaxonomyTerm::new(&config.default_language, taxonomies, library); + // can find it correctly + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("term".to_string(), to_value("Programming").unwrap()); + let res = static_fn.call(&args).unwrap(); + let res_obj = res.as_object().unwrap(); + assert_eq!(res_obj["name"], Value::String("Programming".to_string())); + assert_eq!(res_obj["slug"], Value::String("programming".to_string())); + assert_eq!( + res_obj["permalink"], + Value::String("http://a-website.com/tags/programming/".to_string()) + ); + assert_eq!(res_obj["pages"], Value::Array(vec![])); + // Works with other languages as well + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("term".to_string(), to_value("Programmation").unwrap()); + args.insert("lang".to_string(), to_value("fr").unwrap()); + let res = static_fn.call(&args).unwrap(); + let res_obj = res.as_object().unwrap(); + assert_eq!(res_obj["name"], Value::String("Programmation".to_string())); + + // and errors if it can't find either taxonomy or term + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("something-else").unwrap()); + args.insert("term".to_string(), to_value("Programming").unwrap()); + assert!(static_fn.call(&args).is_err()); + + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("kind".to_string(), to_value("something-else").unwrap()); + assert!(static_fn.call(&args).is_err()); + } } diff --git a/components/templates/src/global_fns/files.rs b/components/templates/src/global_fns/files.rs index 57c72f398a..13361c5dff 100644 --- a/components/templates/src/global_fns/files.rs +++ b/components/templates/src/global_fns/files.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::path::PathBuf; -use std::{fs, io, result}; +use std::fs; +use std::io::Read; use crate::global_fns::helpers::search_for_file; use config::Config; @@ -10,20 +11,20 @@ use libs::tera::{from_value, to_value, Function as TeraFn, Result, Value}; use libs::url; use utils::site::resolve_internal_link; -fn compute_file_hash( - mut file: fs::File, +fn compute_hash( + literal: String, as_base64: bool, -) -> result::Result +) -> String where digest::Output: core::fmt::LowerHex, D: std::io::Write, { let mut hasher = D::new(); - io::copy(&mut file, &mut hasher)?; + hasher.update(literal); if as_base64 { - Ok(encode_b64(hasher.finalize())) + encode_b64(hasher.finalize()) } else { - Ok(format!("{:x}", hasher.finalize())) + format!("{:x}", hasher.finalize()) } } @@ -128,7 +129,13 @@ impl TeraFn for GetUrl { ) .map_err(|e| format!("`get_url`: {}", e))? .and_then(|(p, _)| fs::File::open(&p).ok()) - .and_then(|f| compute_file_hash::(f, false).ok()) + .and_then(|mut f| { + let mut contents = String::new(); + + f.read_to_string(&mut contents).ok()?; + + Some(compute_hash::(contents, false)) + }) { Some(hash) => { permalink = format!("{}?h={}", permalink, hash); @@ -166,71 +173,99 @@ impl TeraFn for GetUrl { } #[derive(Debug)] -pub struct GetFileHash { +pub struct GetHash { base_path: PathBuf, theme: Option, output_path: PathBuf, } -impl GetFileHash { +impl GetHash { pub fn new(base_path: PathBuf, theme: Option, output_path: PathBuf) -> Self { Self { base_path, theme, output_path } } } -impl TeraFn for GetFileHash { +impl TeraFn for GetHash { fn call(&self, args: &HashMap) -> Result { - let path = required_arg!( + let path = optional_arg!( String, args.get("path"), - "`get_file_hash` requires a `path` argument with a string value" + "`get_hash` requires either a `path` or a `literal` argument with a string value" + ); + + let literal = optional_arg!( + String, + args.get("literal"), + "`get_hash` requires either a `path` or a `literal` argument with a string value" ); + + let contents = match (path, literal) { + (Some(_), Some(_)) => { + return Err("`get_hash`: must have only one of `path` or `literal` argument".into()); + }, + (None, None) => { + return Err("`get_hash`: must have at least one of `path` or `literal` argument".into()); + }, + (Some(path_v), None) => { + let file_path = + match search_for_file(&self.base_path, &path_v, &self.theme, &self.output_path) + .map_err(|e| format!("`get_hash`: {}", e))? + { + Some((f, _)) => f, + None => { + return Err(format!("`get_hash`: Cannot find file: {}", path_v).into()); + } + }; + + let mut f = match std::fs::File::open(file_path) { + Ok(f) => f, + Err(e) => { + return Err(format!("File {} could not be open: {}", path_v, e).into()); + } + }; + + let mut contents = String::new(); + + match f.read_to_string(&mut contents) { + Ok(f) => f, + Err(e) => { + return Err(format!("File {} could not be read: {}", path_v, e).into()); + } + }; + + contents + } + (None, Some(literal_v)) => { literal_v } + }; + + let sha_type = optional_arg!( u16, args.get("sha_type"), - "`get_file_hash`: `sha_type` must be 256, 384 or 512" + "`get_hash`: `sha_type` must be 256, 384 or 512" ) .unwrap_or(384); + let base64 = optional_arg!( bool, args.get("base64"), - "`get_file_hash`: `base64` must be true or false" + "`get_hash`: `base64` must be true or false" ) .unwrap_or(true); - let file_path = - match search_for_file(&self.base_path, &path, &self.theme, &self.output_path) - .map_err(|e| format!("`get_file_hash`: {}", e))? - { - Some((f, _)) => f, - None => { - return Err(format!("`get_file_hash`: Cannot find file: {}", path).into()); - } - }; - - let f = match std::fs::File::open(file_path) { - Ok(f) => f, - Err(e) => { - return Err(format!("File {} could not be open: {}", path, e).into()); - } - }; - let hash = match sha_type { - 256 => compute_file_hash::(f, base64), - 384 => compute_file_hash::(f, base64), - 512 => compute_file_hash::(f, base64), - _ => return Err("`get_file_hash`: Invalid sha value".into()), + 256 => compute_hash::(contents, base64), + 384 => compute_hash::(contents, base64), + 512 => compute_hash::(contents, base64), + _ => return Err("`get_hash`: Invalid sha value".into()), }; - match hash { - Ok(digest) => Ok(to_value(digest).unwrap()), - Err(_) => Err("`get_file_hash`: could no compute hash".into()), - } + Ok(to_value(hash).unwrap()) } } #[cfg(test)] mod tests { - use super::{GetFileHash, GetUrl}; + use super::{GetHash, GetUrl}; use std::collections::HashMap; use std::fs::create_dir; @@ -456,7 +491,7 @@ title = "A title" #[test] fn can_get_file_hash_sha256_no_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(256).unwrap()); @@ -470,7 +505,7 @@ title = "A title" #[test] fn can_get_file_hash_sha256_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(256).unwrap()); @@ -481,7 +516,7 @@ title = "A title" #[test] fn can_get_file_hash_sha384_no_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("base64".to_string(), to_value(false).unwrap()); @@ -494,7 +529,7 @@ title = "A title" #[test] fn can_get_file_hash_sha384() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); assert_eq!( @@ -506,7 +541,7 @@ title = "A title" #[test] fn can_get_file_hash_sha512_no_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(512).unwrap()); @@ -520,7 +555,7 @@ title = "A title" #[test] fn can_get_file_hash_sha512() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(512).unwrap()); @@ -530,6 +565,85 @@ title = "A title" ); } + #[test] + fn can_get_hash_sha256_no_base64() { + let dir = create_temp_dir(); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("literal".to_string(), to_value("Hello World").unwrap()); + args.insert("sha_type".to_string(), to_value(256).unwrap()); + args.insert("base64".to_string(), to_value(false).unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e" + ); + } + + #[test] + fn can_get_hash_sha256_base64() { + let dir = create_temp_dir(); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("literal".to_string(), to_value("Hello World").unwrap()); + args.insert("sha_type".to_string(), to_value(256).unwrap()); + args.insert("base64".to_string(), to_value(true).unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + "pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4="); + } + + #[test] + fn can_get_hash_sha384_no_base64() { + let dir = create_temp_dir(); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("literal".to_string(), to_value("Hello World").unwrap()); + args.insert("base64".to_string(), to_value(false).unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + "99514329186b2f6ae4a1329e7ee6c610a729636335174ac6b740f9028396fcc803d0e93863a7c3d90f86beee782f4f3f" + ); + } + + #[test] + fn can_get_hash_sha384() { + let dir = create_temp_dir(); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("literal".to_string(), to_value("Hello World").unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + "mVFDKRhrL2rkoTKefubGEKcpY2M1F0rGt0D5AoOW/MgD0Ok4Y6fD2Q+Gvu54L08/" + ); + } + + #[test] + fn can_get_hash_sha512_no_base64() { + let dir = create_temp_dir(); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("literal".to_string(), to_value("Hello World").unwrap()); + args.insert("sha_type".to_string(), to_value(512).unwrap()); + args.insert("base64".to_string(), to_value(false).unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + "2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b" + ); + } + + #[test] + fn can_get_hash_sha512() { + let dir = create_temp_dir(); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("literal".to_string(), to_value("Hello World").unwrap()); + args.insert("sha_type".to_string(), to_value(512).unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + "LHT9F+2v2A6ER7DUZ0HuJDt+t03SFJoKsbkkb7MDgvJ+hT2FhXGeDmfL2g2qj1FnEGRhXWRa4nrLFb+xRH9Fmw==" + ); + } + #[test] fn can_resolve_asset_path_to_valid_url() { let config = Config::parse(CONFIG_DATA).unwrap(); @@ -540,7 +654,7 @@ title = "A title" args.insert( "path".to_string(), to_value(dir.path().join("app.css").strip_prefix(std::env::temp_dir()).unwrap()) - .unwrap(), + .unwrap(), ); assert_eq!( static_fn.call(&args).unwrap(), @@ -554,7 +668,7 @@ title = "A title" #[test] fn error_when_file_not_found_for_hash() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); + let static_fn = GetHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("doesnt-exist").unwrap()); let err = format!("{}", static_fn.call(&args).unwrap_err()); diff --git a/components/templates/src/global_fns/mod.rs b/components/templates/src/global_fns/mod.rs index e817ba935a..154dc266b6 100644 --- a/components/templates/src/global_fns/mod.rs +++ b/components/templates/src/global_fns/mod.rs @@ -8,8 +8,8 @@ mod i18n; mod images; mod load_data; -pub use self::content::{GetPage, GetSection, GetTaxonomy, GetTaxonomyUrl}; -pub use self::files::{GetFileHash, GetUrl}; +pub use self::content::{GetPage, GetSection, GetTaxonomy, GetTaxonomyTerm, GetTaxonomyUrl}; +pub use self::files::{GetHash, GetUrl}; pub use self::i18n::Trans; pub use self::images::{GetImageMetadata, ResizeImage}; pub use self::load_data::LoadData; diff --git a/docs/content/documentation/content/page.md b/docs/content/documentation/content/page.md index 0f018e04cd..18d0a8cb96 100644 --- a/docs/content/documentation/content/page.md +++ b/docs/content/documentation/content/page.md @@ -16,11 +16,13 @@ create a **page** at `[base_url]/about`). If the file is given any name _other_ than `index.md` or `_index.md`, then it will create a page with that name (without the `.md`). For example, naming a file in the root of your content directory `about.md` would create a page at `[base_url]/about`. + Another exception to this rule is that a filename starting with a datetime (YYYY-mm-dd or [an RFC3339 datetime](https://www.ietf.org/rfc/rfc3339.txt)) followed by an underscore (`_`) or a dash (`-`) will use that date as the page date, unless already set in the front matter. The page name will be anything after `_`/`-`, so the file `2018-10-10-hello-world.md` will be available at `[base_url]/hello-world`. Note that the full RFC3339 datetime contains colons, which is not a valid character in a filename on Windows. +This behavior can be disabled by setting `slugify.paths_keep_date` to `true` (the default is `false`). Note that a `_` separating the date would be slugified into a `-` with the default value for `slugify.paths` of `"on"`. As you can see, creating an `about.md` file is equivalent to creating an `about/index.md` file. The only difference between the two methods is that creating diff --git a/docs/content/documentation/content/section.md b/docs/content/documentation/content/section.md index 527451473d..0508819dc0 100644 --- a/docs/content/documentation/content/section.md +++ b/docs/content/documentation/content/section.md @@ -188,11 +188,14 @@ of the Swedish alphabet, åäö, for example would be considered by the natural sort as aao. In that case the standard byte-order sort may be more suitable. ### `weight` -This will be sort all pages by their `weight` field, from lightest weight -(at the top of the list) to heaviest (at the bottom of the list). Each +This will sort all pages by their `weight` field, from the lightest weight +(at the top of the list) to the heaviest (at the bottom of the list). Each page gets `page.lower` and `page.higher` variables that contain the pages with lighter and heavier weights, respectively. +### `slug` +This will sort pages or sections by their slug in natural lexical order. + ### Reversed sorting When iterating through pages, you may wish to use the Tera `reverse` filter, which reverses the order of the pages. For example, after using the `reverse` filter, diff --git a/docs/content/documentation/content/shortcodes.md b/docs/content/documentation/content/shortcodes.md index 953b319ce5..4ca48b4062 100644 --- a/docs/content/documentation/content/shortcodes.md +++ b/docs/content/documentation/content/shortcodes.md @@ -59,7 +59,7 @@ This will create a shortcode `books` with the argument `path` pointing to a `.to titles and descriptions. They will flow with the rest of the document in which `books` is called. Shortcodes are rendered before the page's Markdown is parsed so they don't have access to the page's table of contents. -Because of that, you also cannot use the [`get_page`](@/documentation/templates/overview.md#get-page)/[`get_section`](@/documentation/templates/overview.md#get-section)/[`get_taxonomy`](@/documentation/templates/overview.md#get-taxonomy) global functions. It might work while +Because of that, you also cannot use the [`get_page`](@/documentation/templates/overview.md#get-page)/[`get_section`](@/documentation/templates/overview.md#get-section)/[`get_taxonomy`](@/documentation/templates/overview.md#get-taxonomy)/[`get_taxonomy_term`](@/documentation/templates/overview.md#get-term) global functions. It might work while running `zola serve` because it has been loaded but it will fail during `zola build`. ## Using shortcodes diff --git a/docs/content/documentation/getting-started/cli-usage.md b/docs/content/documentation/getting-started/cli-usage.md index 842f5b61c4..10275037f3 100644 --- a/docs/content/documentation/getting-started/cli-usage.md +++ b/docs/content/documentation/getting-started/cli-usage.md @@ -46,7 +46,7 @@ $ zola build --base-url $DEPLOY_URL This is useful for example when you want to deploy previews of a site to a dynamic URL, such as Netlify deploy previews. -You can override the default output directory `public` by passing another value to the `output-dir` flag (if this directory already exists, the user will be prompted whether to replace the folder). +You can override the default output directory `public` by passing another value to the `output-dir` flag. If this directory already exists, the user will be prompted whether to replace the folder; you can override this prompt by passing the --force flag. ```bash $ zola build --output-dir $DOCUMENT_ROOT diff --git a/docs/content/documentation/getting-started/configuration.md b/docs/content/documentation/getting-started/configuration.md index f8f2d473fc..92675197ca 100644 --- a/docs/content/documentation/getting-started/configuration.md +++ b/docs/content/documentation/getting-started/configuration.md @@ -142,6 +142,10 @@ external_level = "error" paths = "on" taxonomies = "on" anchors = "on" +# Whether to remove date prefixes for page path slugs. +# For example, content/posts/2016-10-08_a-post-with-dates.md => posts/a-post-with-dates +# When true, content/posts/2016-10-08_a-post-with-dates.md => posts/2016-10-08-a-post-with-dates +paths_keep_dates = false [search] # Whether to include the title of the page/section in the index diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index b48e8ffb53..e0eb8d64fc 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -180,6 +180,23 @@ items: Array; See the [Taxonomies documentation](@/documentation/templates/taxonomies.md) for a full documentation of those types. +### `get_taxonomy_term` +Gets a single term from a taxonomy of a specific kind. + +```jinja2 +{% set categories = get_taxonomy_term(kind="categories", term="term_name") %} +``` + +The type of the output is a single `TaxonomyTerm` item. + +`lang` (optional) default to `config.default_language` in config.toml + +`include_pages` (optional) default to true. If false, the `pages` item in the `TaxonomyTerm` will be empty, regardless of what pages may actually exist for this term. `page_count` will correctly reflect the number of pages for this term in both cases. + +`required` (optional) if a taxonomy or term is not found`. + +See the [Taxonomies documentation](@/documentation/templates/taxonomies.md) for a full documentation of those types. + ### `get_url` Gets the permalink for the given path. If the path starts with `@/`, it will be treated as an internal link like the ones used in Markdown, @@ -217,17 +234,21 @@ In the case of non-internal links, you can also add a cachebust of the format `? by passing `cachebust=true` to the `get_url` function. In this case, the path will need to resolve to an actual file. See [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic) for details. -### `get_file_hash` +### `get_hash` -Returns the hash digest (SHA-256, SHA-384 or SHA-512) of a file. +Returns the hash digest (SHA-256, SHA-384 or SHA-512) of a file or a string literal. It can take the following arguments: - `path`: mandatory, see [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic) for details +- **or** `literal`: mandatory, the string value to be hashed - `sha_type`: optional, one of `256`, `384` or `512`, defaults to `384` - `base64`: optional, `true` or `false`, defaults to `true`. Whether to encode the hash as base64 +Either `path` or `literal` must be given. + ```jinja2 -{{/* get_file_hash(path="static/js/app.js", sha_type=256) */}} +{{/* get_hash(literal="Hello World", sha_type=256) */}} +{{/* get_hash(path="static/js/app.js", sha_type=256) */}} ``` The function can also output a base64-encoded hash value when its `base64` @@ -236,10 +257,10 @@ integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Int ```jinja2 + integrity="sha384-{{ get_hash(path="static/js/app.js", sha_type=384, base64=true) | safe }}"> ``` -Do note that subresource integrity is typically used when using external scripts, which `get_file_hash` does not support. +Do note that subresource integrity is typically used when using external scripts, which `get_hash` does not support. ### `get_image_metadata` diff --git a/docs/content/documentation/templates/taxonomies.md b/docs/content/documentation/templates/taxonomies.md index 064623b71b..72bbd0ee73 100644 --- a/docs/content/documentation/templates/taxonomies.md +++ b/docs/content/documentation/templates/taxonomies.md @@ -20,6 +20,7 @@ slug: String; path: String; permalink: String; pages: Array; +page_count: Number; ``` and `TaxonomyConfig` has the following fields: diff --git a/snapcraft.yaml b/snapcraft.yaml index ef540fb69e..3e67d64c60 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,5 +1,5 @@ name: zola -version: 0.16.1 +version: 0.17.0 summary: A fast static site generator in a single binary with everything built-in. description: | A fast static site generator in a single binary with everything built-in. @@ -21,7 +21,7 @@ parts: zola: source-type: git source: https://github.com/getzola/zola.git - source-tag: v0.16.1 + source-tag: v0.17.0 plugin: rust rust-channel: stable build-packages: diff --git a/src/cli.rs b/src/cli.rs index 82b1f9084e..8d6629cd74 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; +use clap_complete::Shell; #[derive(Parser)] #[clap(version, author, about)] @@ -40,6 +41,10 @@ pub enum Command { #[clap(short = 'o', long)] output_dir: Option, + /// Force building the site even if output directory is non-empty + #[clap(short = 'f', long)] + force: bool, + /// Include drafts when loading the site #[clap(long)] drafts: bool, @@ -75,6 +80,10 @@ pub enum Command { /// Only rebuild the minimum on change - useful when working on a specific page/section #[clap(short = 'f', long)] fast: bool, + + /// Default append port to the base url. + #[clap(long, default_value_t = false)] + no_port_append: bool, }, /// Try to build the project without rendering it. Checks links @@ -83,4 +92,11 @@ pub enum Command { #[clap(long)] drafts: bool, }, + + /// Generate shell completion + Completion { + /// Shell to generate completion for + #[clap(arg_enum)] + shell: Shell, + }, } diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 6bfe603d88..d088743687 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -4,38 +4,22 @@ use errors::{Error, Result}; use site::Site; use crate::messages; -use crate::prompt::ask_bool_timeout; - -const BUILD_PROMPT_TIMEOUT_MILLIS: u64 = 10_000; pub fn build( root_dir: &Path, config_file: &Path, base_url: Option<&str>, output_dir: Option<&Path>, + force: bool, include_drafts: bool, ) -> Result<()> { let mut site = Site::new(root_dir, config_file)?; if let Some(output_dir) = output_dir { - // Check whether output directory exists or not - // This way we don't replace already existing files. - if output_dir.exists() { - console::warn(&format!("The directory '{}' already exists. Building to this directory will delete files contained within this directory.", output_dir.display())); - - // Prompt the user to ask whether they want to continue. - let clear_dir = tokio::runtime::Runtime::new() - .expect("Tokio runtime failed to instantiate") - .block_on(ask_bool_timeout( - "Are you sure you want to continue?", - false, - std::time::Duration::from_millis(BUILD_PROMPT_TIMEOUT_MILLIS), - ))?; - - if !clear_dir { - return Err(Error::msg( - "Cancelled build process because output directory already exists.", - )); - } + if !force && output_dir.exists() { + return Err(Error::msg(format!( + "Directory '{}' already exists. Use --force to overwrite.", + output_dir.display(), + ))); } site.set_output_path(output_dir); diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 0242a9a075..785f9f15a3 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -241,6 +241,7 @@ fn create_new_site( base_url: &str, config_file: &Path, include_drafts: bool, + no_port_append: bool, ws_port: Option, ) -> Result<(Site, String)> { SITE_CONTENT.write().unwrap().clear(); @@ -251,7 +252,11 @@ fn create_new_site( let base_url = if base_url == "/" { String::from("/") } else { - let base_address = format!("{}:{}", base_url, interface_port); + let base_address = if no_port_append { + base_url.to_string() + } else { + format!("{}:{}", base_url, interface_port) + }; if site.config.base_url.ends_with('/') { format!("http://{}/", base_address) @@ -291,6 +296,7 @@ pub fn serve( open: bool, include_drafts: bool, fast_rebuild: bool, + no_port_append: bool, utc_offset: UtcOffset, ) -> Result<()> { let start = Instant::now(); @@ -302,6 +308,7 @@ pub fn serve( base_url, config_file, include_drafts, + no_port_append, None, )?; messages::report_elapsed_time(start); @@ -502,6 +509,7 @@ pub fn serve( base_url, config_file, include_drafts, + no_port_append, ws_port, ) { Ok((s, _)) => { diff --git a/src/main.rs b/src/main.rs index 22fa101cec..05542e6149 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use std::time::Instant; use cli::{Cli, Command}; use utils::net::{get_available_port, port_is_available}; -use clap::Parser; +use clap::{CommandFactory, Parser}; use time::UtcOffset; mod cli; @@ -39,7 +39,7 @@ fn main() { std::process::exit(1); } } - Command::Build { base_url, output_dir, drafts } => { + Command::Build { base_url, output_dir, force, drafts } => { console::info("Building site..."); let start = Instant::now(); let (root_dir, config_file) = get_config_file_path(&cli_dir, &cli.config); @@ -48,6 +48,7 @@ fn main() { &config_file, base_url.as_deref(), output_dir.as_deref(), + force, drafts, ) { Ok(()) => messages::report_elapsed_time(start), @@ -57,7 +58,16 @@ fn main() { } } } - Command::Serve { interface, mut port, output_dir, base_url, drafts, open, fast } => { + Command::Serve { + interface, + mut port, + output_dir, + base_url, + drafts, + open, + fast, + no_port_append, + } => { if port != 1111 && !port_is_available(port) { console::error("The requested port is not available"); std::process::exit(1); @@ -82,6 +92,7 @@ fn main() { open, drafts, fast, + no_port_append, UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC), ) { messages::unravel_errors("Failed to serve the site", &e); @@ -100,5 +111,9 @@ fn main() { } } } + Command::Completion { shell } => { + let cmd = &mut Cli::command(); + clap_complete::generate(shell, cmd, cmd.get_name().to_string(), &mut std::io::stdout()); + } } } diff --git a/src/prompt.rs b/src/prompt.rs index 2820f48f79..9083efcd3f 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,5 +1,4 @@ use std::io::{self, BufRead, Write}; -use std::time::Duration; use libs::url::Url; @@ -33,24 +32,6 @@ pub fn ask_bool(question: &str, default: bool) -> Result { } } -/// Ask a yes/no question to the user with a timeout -pub async fn ask_bool_timeout(question: &str, default: bool, timeout: Duration) -> Result { - let (tx, rx) = tokio::sync::oneshot::channel(); - - let q = question.to_string(); - std::thread::spawn(move || { - tx.send(ask_bool(&q, default)).unwrap(); - }); - - match tokio::time::timeout(timeout, rx).await { - Err(_) => { - console::warn("\nWaited too long for response."); - Ok(default) - } - Ok(val) => val.expect("Tokio failed to properly execute"), - } -} - /// Ask a question to the user where they can write a URL pub fn ask_url(question: &str, default: &str) -> Result { print!("{} ({}): ", question, default); diff --git a/test_site/templates/index.html b/test_site/templates/index.html index 35a24be4b7..0c19bb0867 100644 --- a/test_site/templates/index.html +++ b/test_site/templates/index.html @@ -14,5 +14,5 @@

{{ page.title }}

{% block script %} + integrity="sha384-{{ get_hash(path="scripts/hello.js", base64=true) | safe }}"> {% endblock script %} diff --git a/zola.metainfo.xml b/zola.metainfo.xml index 85d2fa3ee2..2d6cad3ea2 100644 --- a/zola.metainfo.xml +++ b/zola.metainfo.xml @@ -52,6 +52,9 @@ + + https://github.com/getzola/zola/releases/tag/v0.16.1 + https://github.com/getzola/zola/releases/tag/v0.16.0