Rust library to generate static websites
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(cli): Init command (#7)

* feat(cli): Init command

* feat: implement directory creation

* feat: make template creation work

authored by

Erika and committed by
GitHub
eb52f811 4feee60a

+892 -22
+1
.gitignore
··· 3 3 node_modules 4 4 5 5 .DS_Store 6 + project.tar
+388 -12
Cargo.lock
··· 498 498 ] 499 499 500 500 [[package]] 501 + name = "crc32fast" 502 + version = "1.4.2" 503 + source = "registry+https://github.com/rust-lang/crates.io-index" 504 + checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 505 + dependencies = [ 506 + "cfg-if", 507 + ] 508 + 509 + [[package]] 501 510 name = "crossbeam-channel" 502 511 version = "0.5.14" 503 512 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 532 541 checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 533 542 534 543 [[package]] 544 + name = "crossterm" 545 + version = "0.25.0" 546 + source = "registry+https://github.com/rust-lang/crates.io-index" 547 + checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" 548 + dependencies = [ 549 + "bitflags 1.3.2", 550 + "crossterm_winapi", 551 + "libc", 552 + "mio 0.8.11", 553 + "parking_lot", 554 + "signal-hook", 555 + "signal-hook-mio", 556 + "winapi", 557 + ] 558 + 559 + [[package]] 560 + name = "crossterm_winapi" 561 + version = "0.9.1" 562 + source = "registry+https://github.com/rust-lang/crates.io-index" 563 + checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 564 + dependencies = [ 565 + "winapi", 566 + ] 567 + 568 + [[package]] 535 569 name = "crypto-common" 536 570 version = "0.1.6" 537 571 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 657 691 checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" 658 692 659 693 [[package]] 694 + name = "dyn-clone" 695 + version = "1.0.18" 696 + source = "registry+https://github.com/rust-lang/crates.io-index" 697 + checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35" 698 + 699 + [[package]] 660 700 name = "dyn-eq" 661 701 version = "0.1.3" 662 702 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 762 802 version = "0.5.7" 763 803 source = "registry+https://github.com/rust-lang/crates.io-index" 764 804 checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 805 + 806 + [[package]] 807 + name = "flate2" 808 + version = "1.0.35" 809 + source = "registry+https://github.com/rust-lang/crates.io-index" 810 + checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" 811 + dependencies = [ 812 + "crc32fast", 813 + "miniz_oxide", 814 + ] 765 815 766 816 [[package]] 767 817 name = "fnv" ··· 883 933 ] 884 934 885 935 [[package]] 936 + name = "fuzzy-matcher" 937 + version = "0.3.7" 938 + source = "registry+https://github.com/rust-lang/crates.io-index" 939 + checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" 940 + dependencies = [ 941 + "thread_local", 942 + ] 943 + 944 + [[package]] 886 945 name = "fxhash" 887 946 version = "0.2.1" 888 947 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 961 1020 "gix-utils", 962 1021 "itoa", 963 1022 "thiserror 1.0.69", 964 - "winnow", 1023 + "winnow 0.6.26", 965 1024 ] 966 1025 967 1026 [[package]] ··· 982 1041 "smallvec", 983 1042 "thiserror 1.0.69", 984 1043 "unicode-bom", 985 - "winnow", 1044 + "winnow 0.6.26", 986 1045 ] 987 1046 988 1047 [[package]] ··· 1085 1144 "itoa", 1086 1145 "smallvec", 1087 1146 "thiserror 1.0.69", 1088 - "winnow", 1147 + "winnow 0.6.26", 1089 1148 ] 1090 1149 1091 1150 [[package]] ··· 1119 1178 "gix-validate", 1120 1179 "memmap2", 1121 1180 "thiserror 1.0.69", 1122 - "winnow", 1181 + "winnow 0.6.26", 1123 1182 ] 1124 1183 1125 1184 [[package]] ··· 1433 1492 ] 1434 1493 1435 1494 [[package]] 1495 + name = "inquire" 1496 + version = "0.7.5" 1497 + source = "registry+https://github.com/rust-lang/crates.io-index" 1498 + checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" 1499 + dependencies = [ 1500 + "bitflags 2.8.0", 1501 + "crossterm", 1502 + "dyn-clone", 1503 + "fuzzy-matcher", 1504 + "fxhash", 1505 + "newline-converter", 1506 + "once_cell", 1507 + "unicode-segmentation", 1508 + "unicode-width 0.1.14", 1509 + ] 1510 + 1511 + [[package]] 1436 1512 name = "is_terminal_polyfill" 1437 1513 version = "1.70.1" 1438 1514 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1648 1724 "log", 1649 1725 "lol_html", 1650 1726 "maud", 1651 - "maudit-macros", 1727 + "maudit-macros 0.2.0", 1728 + "maudit_rolldown", 1729 + "pulldown-cmark", 1730 + "rustc-hash", 1731 + "serde", 1732 + "serde_yml", 1733 + "thiserror 2.0.11", 1734 + "tokio", 1735 + ] 1736 + 1737 + [[package]] 1738 + name = "maudit" 1739 + version = "0.2.0" 1740 + source = "registry+https://github.com/rust-lang/crates.io-index" 1741 + checksum = "3a43d06acbe0b824e6c4d0f66a326db3b632650fd8b5478eea258fd559774935" 1742 + dependencies = [ 1743 + "chrono", 1744 + "colored", 1745 + "dyn-eq", 1746 + "env_logger", 1747 + "glob", 1748 + "log", 1749 + "lol_html", 1750 + "maud", 1751 + "maudit-macros 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1652 1752 "maudit_rolldown", 1653 1753 "pulldown-cmark", 1654 1754 "rustc-hash", ··· 1663 1763 version = "0.1.0" 1664 1764 dependencies = [ 1665 1765 "maud", 1666 - "maudit", 1766 + "maudit 0.2.0", 1667 1767 ] 1668 1768 1669 1769 [[package]] ··· 1678 1778 "futures", 1679 1779 "futures-util", 1680 1780 "http-body-util", 1781 + "inquire", 1681 1782 "log", 1783 + "rand 0.9.0", 1682 1784 "serde", 1785 + "spinach", 1786 + "tar", 1683 1787 "tokio", 1684 1788 "tokio-tungstenite", 1789 + "toml_edit", 1685 1790 "tower-http", 1686 1791 "tracing", 1687 1792 "tracing-subscriber", 1793 + "ureq", 1688 1794 "watchexec", 1689 1795 "watchexec-events", 1690 1796 ] ··· 1694 1800 version = "0.1.0" 1695 1801 dependencies = [ 1696 1802 "maud", 1697 - "maudit", 1803 + "maudit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1698 1804 ] 1699 1805 1700 1806 [[package]] ··· 1702 1808 version = "0.1.0" 1703 1809 dependencies = [ 1704 1810 "maud", 1705 - "maudit", 1811 + "maudit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1706 1812 "serde", 1707 1813 ] 1708 1814 ··· 1711 1817 version = "0.1.0" 1712 1818 dependencies = [ 1713 1819 "maud", 1714 - "maudit", 1820 + "maudit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1715 1821 ] 1716 1822 1717 1823 [[package]] ··· 1723 1829 ] 1724 1830 1725 1831 [[package]] 1832 + name = "maudit-macros" 1833 + version = "0.2.0" 1834 + source = "registry+https://github.com/rust-lang/crates.io-index" 1835 + checksum = "0e4e05a151d3aa99a22dce5679fd04b25a21cf0440938b431a199d36f3e705bc" 1836 + dependencies = [ 1837 + "quote", 1838 + "syn 2.0.98", 1839 + ] 1840 + 1841 + [[package]] 1726 1842 name = "maudit-website" 1727 1843 version = "0.1.0" 1728 1844 dependencies = [ 1729 1845 "maud", 1730 - "maudit", 1846 + "maudit 0.2.0", 1731 1847 "serde", 1732 1848 ] 1733 1849 ··· 2090 2206 "log", 2091 2207 "wasi 0.11.0+wasi-snapshot-preview1", 2092 2208 "windows-sys 0.52.0", 2209 + ] 2210 + 2211 + [[package]] 2212 + name = "newline-converter" 2213 + version = "0.3.0" 2214 + source = "registry+https://github.com/rust-lang/crates.io-index" 2215 + checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" 2216 + dependencies = [ 2217 + "unicode-segmentation", 2093 2218 ] 2094 2219 2095 2220 [[package]] ··· 2910 3035 source = "registry+https://github.com/rust-lang/crates.io-index" 2911 3036 checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 2912 3037 dependencies = [ 2913 - "zerocopy", 3038 + "zerocopy 0.7.35", 2914 3039 ] 2915 3040 2916 3041 [[package]] ··· 3052 3177 ] 3053 3178 3054 3179 [[package]] 3180 + name = "rand" 3181 + version = "0.9.0" 3182 + source = "registry+https://github.com/rust-lang/crates.io-index" 3183 + checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" 3184 + dependencies = [ 3185 + "rand_chacha 0.9.0", 3186 + "rand_core 0.9.0", 3187 + "zerocopy 0.8.16", 3188 + ] 3189 + 3190 + [[package]] 3055 3191 name = "rand_chacha" 3056 3192 version = "0.2.2" 3057 3193 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3072 3208 ] 3073 3209 3074 3210 [[package]] 3211 + name = "rand_chacha" 3212 + version = "0.9.0" 3213 + source = "registry+https://github.com/rust-lang/crates.io-index" 3214 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 3215 + dependencies = [ 3216 + "ppv-lite86", 3217 + "rand_core 0.9.0", 3218 + ] 3219 + 3220 + [[package]] 3075 3221 name = "rand_core" 3076 3222 version = "0.5.1" 3077 3223 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3090 3236 ] 3091 3237 3092 3238 [[package]] 3239 + name = "rand_core" 3240 + version = "0.9.0" 3241 + source = "registry+https://github.com/rust-lang/crates.io-index" 3242 + checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" 3243 + dependencies = [ 3244 + "getrandom 0.3.1", 3245 + "zerocopy 0.8.16", 3246 + ] 3247 + 3248 + [[package]] 3093 3249 name = "rand_hc" 3094 3250 version = "0.2.0" 3095 3251 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3191 3347 ] 3192 3348 3193 3349 [[package]] 3350 + name = "ring" 3351 + version = "0.17.8" 3352 + source = "registry+https://github.com/rust-lang/crates.io-index" 3353 + checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 3354 + dependencies = [ 3355 + "cc", 3356 + "cfg-if", 3357 + "getrandom 0.2.15", 3358 + "libc", 3359 + "spin", 3360 + "untrusted", 3361 + "windows-sys 0.52.0", 3362 + ] 3363 + 3364 + [[package]] 3194 3365 name = "ropey" 3195 3366 version = "1.6.1" 3196 3367 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3235 3406 ] 3236 3407 3237 3408 [[package]] 3409 + name = "rustls" 3410 + version = "0.23.22" 3411 + source = "registry+https://github.com/rust-lang/crates.io-index" 3412 + checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" 3413 + dependencies = [ 3414 + "log", 3415 + "once_cell", 3416 + "ring", 3417 + "rustls-pki-types", 3418 + "rustls-webpki", 3419 + "subtle", 3420 + "zeroize", 3421 + ] 3422 + 3423 + [[package]] 3424 + name = "rustls-pemfile" 3425 + version = "2.2.0" 3426 + source = "registry+https://github.com/rust-lang/crates.io-index" 3427 + checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 3428 + dependencies = [ 3429 + "rustls-pki-types", 3430 + ] 3431 + 3432 + [[package]] 3433 + name = "rustls-pki-types" 3434 + version = "1.11.0" 3435 + source = "registry+https://github.com/rust-lang/crates.io-index" 3436 + checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" 3437 + 3438 + [[package]] 3439 + name = "rustls-webpki" 3440 + version = "0.102.8" 3441 + source = "registry+https://github.com/rust-lang/crates.io-index" 3442 + checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 3443 + dependencies = [ 3444 + "ring", 3445 + "rustls-pki-types", 3446 + "untrusted", 3447 + ] 3448 + 3449 + [[package]] 3238 3450 name = "rustversion" 3239 3451 version = "1.0.19" 3240 3452 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3435 3647 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 3436 3648 3437 3649 [[package]] 3650 + name = "signal-hook" 3651 + version = "0.3.17" 3652 + source = "registry+https://github.com/rust-lang/crates.io-index" 3653 + checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 3654 + dependencies = [ 3655 + "libc", 3656 + "signal-hook-registry", 3657 + ] 3658 + 3659 + [[package]] 3660 + name = "signal-hook-mio" 3661 + version = "0.2.4" 3662 + source = "registry+https://github.com/rust-lang/crates.io-index" 3663 + checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 3664 + dependencies = [ 3665 + "libc", 3666 + "mio 0.8.11", 3667 + "signal-hook", 3668 + ] 3669 + 3670 + [[package]] 3438 3671 name = "signal-hook-registry" 3439 3672 version = "1.4.2" 3440 3673 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3493 3726 ] 3494 3727 3495 3728 [[package]] 3729 + name = "spin" 3730 + version = "0.9.8" 3731 + source = "registry+https://github.com/rust-lang/crates.io-index" 3732 + checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 3733 + 3734 + [[package]] 3735 + name = "spinach" 3736 + version = "3.0.0" 3737 + source = "registry+https://github.com/rust-lang/crates.io-index" 3738 + checksum = "2bb127edbed8b91951c7a35237d0c4ba5f01338bb11ecc2a75e5a93365b24302" 3739 + 3740 + [[package]] 3496 3741 name = "stable_deref_trait" 3497 3742 version = "1.2.0" 3498 3743 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3529 3774 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 3530 3775 3531 3776 [[package]] 3777 + name = "subtle" 3778 + version = "2.6.1" 3779 + source = "registry+https://github.com/rust-lang/crates.io-index" 3780 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 3781 + 3782 + [[package]] 3532 3783 name = "sugar_path" 3533 3784 version = "1.2.0" 3534 3785 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3563 3814 checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 3564 3815 3565 3816 [[package]] 3817 + name = "tar" 3818 + version = "0.4.43" 3819 + source = "registry+https://github.com/rust-lang/crates.io-index" 3820 + checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" 3821 + dependencies = [ 3822 + "filetime", 3823 + "libc", 3824 + "xattr", 3825 + ] 3826 + 3827 + [[package]] 3566 3828 name = "tempfile" 3567 3829 version = "3.16.0" 3568 3830 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3736 3998 ] 3737 3999 3738 4000 [[package]] 4001 + name = "toml_datetime" 4002 + version = "0.6.8" 4003 + source = "registry+https://github.com/rust-lang/crates.io-index" 4004 + checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 4005 + 4006 + [[package]] 4007 + name = "toml_edit" 4008 + version = "0.22.23" 4009 + source = "registry+https://github.com/rust-lang/crates.io-index" 4010 + checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" 4011 + dependencies = [ 4012 + "indexmap", 4013 + "toml_datetime", 4014 + "winnow 0.7.1", 4015 + ] 4016 + 4017 + [[package]] 3739 4018 name = "tower" 3740 4019 version = "0.5.2" 3741 4020 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3935 4214 ] 3936 4215 3937 4216 [[package]] 4217 + name = "unicode-segmentation" 4218 + version = "1.12.0" 4219 + source = "registry+https://github.com/rust-lang/crates.io-index" 4220 + checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 4221 + 4222 + [[package]] 3938 4223 name = "unicode-width" 3939 4224 version = "0.1.14" 3940 4225 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3947 4232 checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 3948 4233 3949 4234 [[package]] 4235 + name = "untrusted" 4236 + version = "0.9.0" 4237 + source = "registry+https://github.com/rust-lang/crates.io-index" 4238 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 4239 + 4240 + [[package]] 4241 + name = "ureq" 4242 + version = "3.0.5" 4243 + source = "registry+https://github.com/rust-lang/crates.io-index" 4244 + checksum = "b2916852be768844b6e9cbe107358b5bc40a696bd6dc8e036c9f80c731242c9c" 4245 + dependencies = [ 4246 + "base64", 4247 + "flate2", 4248 + "log", 4249 + "percent-encoding", 4250 + "rustls", 4251 + "rustls-pemfile", 4252 + "rustls-pki-types", 4253 + "ureq-proto", 4254 + "utf-8", 4255 + "webpki-roots", 4256 + ] 4257 + 4258 + [[package]] 4259 + name = "ureq-proto" 4260 + version = "0.3.0" 4261 + source = "registry+https://github.com/rust-lang/crates.io-index" 4262 + checksum = "2c51fe73e1d8c4e06bb2698286f7e7453c6fc90528d6d2e7fc36bb4e87fe09b1" 4263 + dependencies = [ 4264 + "base64", 4265 + "http", 4266 + "httparse", 4267 + "log", 4268 + ] 4269 + 4270 + [[package]] 3950 4271 name = "urlencoding" 3951 4272 version = "2.1.3" 3952 4273 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4150 4471 ] 4151 4472 4152 4473 [[package]] 4474 + name = "webpki-roots" 4475 + version = "0.26.8" 4476 + source = "registry+https://github.com/rust-lang/crates.io-index" 4477 + checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" 4478 + dependencies = [ 4479 + "rustls-pki-types", 4480 + ] 4481 + 4482 + [[package]] 4153 4483 name = "winapi" 4154 4484 version = "0.3.9" 4155 4485 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4474 4804 ] 4475 4805 4476 4806 [[package]] 4807 + name = "winnow" 4808 + version = "0.7.1" 4809 + source = "registry+https://github.com/rust-lang/crates.io-index" 4810 + checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" 4811 + dependencies = [ 4812 + "memchr", 4813 + ] 4814 + 4815 + [[package]] 4477 4816 name = "wit-bindgen-rt" 4478 4817 version = "0.33.0" 4479 4818 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4483 4822 ] 4484 4823 4485 4824 [[package]] 4825 + name = "xattr" 4826 + version = "1.4.0" 4827 + source = "registry+https://github.com/rust-lang/crates.io-index" 4828 + checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" 4829 + dependencies = [ 4830 + "libc", 4831 + "linux-raw-sys", 4832 + "rustix", 4833 + ] 4834 + 4835 + [[package]] 4486 4836 name = "xxhash-rust" 4487 4837 version = "0.8.15" 4488 4838 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4501 4851 checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 4502 4852 dependencies = [ 4503 4853 "byteorder", 4504 - "zerocopy-derive", 4854 + "zerocopy-derive 0.7.35", 4855 + ] 4856 + 4857 + [[package]] 4858 + name = "zerocopy" 4859 + version = "0.8.16" 4860 + source = "registry+https://github.com/rust-lang/crates.io-index" 4861 + checksum = "7b8c07a70861ce02bad1607b5753ecb2501f67847b9f9ada7c160fff0ec6300c" 4862 + dependencies = [ 4863 + "zerocopy-derive 0.8.16", 4505 4864 ] 4506 4865 4507 4866 [[package]] ··· 4514 4873 "quote", 4515 4874 "syn 2.0.98", 4516 4875 ] 4876 + 4877 + [[package]] 4878 + name = "zerocopy-derive" 4879 + version = "0.8.16" 4880 + source = "registry+https://github.com/rust-lang/crates.io-index" 4881 + checksum = "5226bc9a9a9836e7428936cde76bb6b22feea1a8bfdbc0d241136e4d13417e25" 4882 + dependencies = [ 4883 + "proc-macro2", 4884 + "quote", 4885 + "syn 2.0.98", 4886 + ] 4887 + 4888 + [[package]] 4889 + name = "zeroize" 4890 + version = "1.8.1" 4891 + source = "registry+https://github.com/rust-lang/crates.io-index" 4892 + checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+6
crates/cli/Cargo.toml
··· 30 30 tracing-subscriber = { version = "0.3", features = ["env-filter", "chrono"] } 31 31 watchexec = "5.0.0" 32 32 watchexec-events = "4.0.0" 33 + inquire = "0.7.5" 34 + rand = "0.9.0" 35 + spinach = "3" 36 + ureq = "3.0.5" 37 + tar = "0.4.43" 38 + toml_edit = "0.22.23"
+1 -1
crates/cli/src/dev.rs
··· 17 17 18 18 use crate::logging::format_elapsed_time; 19 19 20 - pub async fn coordinate_dev_env(cwd: &str) -> io::Result<()> { 20 + pub async fn start_dev_env(cwd: &str) -> io::Result<()> { 21 21 info!(name: "dev", "Preparing dev environment…"); 22 22 let (sender_websocket, _) = broadcast::channel::<WebSocketMessage>(100); 23 23
+343
crates/cli/src/init.rs
··· 1 + use std::{ 2 + path::{Path, PathBuf}, 3 + process::Stdio, 4 + }; 5 + 6 + use colored::Colorize; 7 + use inquire::{validator::Validation, Confirm, Select, Text}; 8 + use rand::seq::IndexedRandom; 9 + use spinach::{Color, Spinner}; 10 + use toml_edit::DocumentMut; 11 + use tracing::{debug, info}; 12 + 13 + mod names; 14 + mod render_config; 15 + use names::generate_directory_name; 16 + use render_config::get_render_config; 17 + 18 + use crate::logging::format_elapsed_time; 19 + 20 + const REPO_TAR_URL: &str = "https://api.github.com/repos/web-lsp/maudit/tarball/main"; 21 + 22 + const INTROS: [&str; 6] = [ 23 + "Let the coronation begin.", 24 + "The coronation shall begin.", 25 + "A new era begins.", 26 + "A new chapter unfolds.", 27 + "A reign begins anew.", 28 + "History is made today.", 29 + ]; 30 + 31 + pub fn start_new_project(dry_run: &bool) { 32 + if *dry_run { 33 + debug!("Dry run enabled"); 34 + } 35 + 36 + inquire::set_global_render_config(get_render_config()); 37 + 38 + // Run cargo info maudit in a tmp directory to avoid catching a local version 39 + let cargo_search = std::process::Command::new("cargo") 40 + .arg("search") 41 + .arg("maudit") 42 + .args(["--limit", "1"]) 43 + .output() 44 + .expect("Failed to run cargo info maudit"); 45 + 46 + let maudit_version = if cargo_search.status.success() { 47 + let output = String::from_utf8_lossy(&cargo_search.stdout).to_string(); 48 + format!( 49 + "(v{})", 50 + output 51 + .lines() 52 + .next() 53 + .and_then(|line| { 54 + let start = line.find('"')?; 55 + let end = line[start + 1..].find('"')?; 56 + Some(line[start + 1..start + 1 + end].to_string()) 57 + }) 58 + .unwrap_or_else(|| "unknown".to_string()) 59 + ) 60 + } else { 61 + "".to_string() 62 + }; 63 + 64 + println!(); 65 + match maudit_version.is_empty() { 66 + true => { 67 + info!(name: "SKIP_FORMAT", "👑 {} {}!", "Welcome to".bold(), "Maudit".red().to_string().bold(), ) 68 + } 69 + false => { 70 + info!(name: "SKIP_FORMAT", "👑 {} {}! {}", "Welcome to".bold(), "Maudit".red().to_string().bold(), maudit_version.dimmed()) 71 + } 72 + } 73 + 74 + let rng = &mut rand::rng(); 75 + let intro = INTROS.choose(rng).unwrap(); 76 + info!(name: "SKIP_FORMAT", " {}", intro.dimmed()); 77 + println!(); 78 + 79 + let directory_name = format!("./{}", generate_directory_name(rng)); 80 + let project_path = Text::new("Where should we create the project?") 81 + .with_formatter(&|i| { 82 + if i.is_empty() { 83 + return directory_name.clone(); 84 + } 85 + 86 + i.to_owned() 87 + }) 88 + .with_validators(&[ 89 + Box::new(|s: &str| { 90 + if std::path::Path::new(&s).exists() { 91 + Ok(Validation::Invalid( 92 + "A directory with this name already exists".into(), 93 + )) 94 + } else { 95 + Ok(Validation::Valid) 96 + } 97 + }), 98 + Box::new(|s: &str| { 99 + if has_invalid_filepath_chars(s) { 100 + Ok(Validation::Invalid( 101 + "The directory name contains invalid characters".into(), 102 + )) 103 + } else { 104 + Ok(Validation::Valid) 105 + } 106 + }), 107 + ]) 108 + .with_placeholder(&directory_name) 109 + .prompt(); 110 + 111 + let project_path = match project_path { 112 + Ok(path) => { 113 + let path = if path.is_empty() { 114 + directory_name 115 + } else { 116 + path 117 + }; 118 + 119 + PathBuf::from(path) 120 + } 121 + Err(_) => { 122 + println!(); 123 + return; 124 + } 125 + }; 126 + 127 + let templates: Vec<&str> = vec!["Blog", "Basics", "Empty"]; 128 + let template = Select::new("Which template would you like to use?", templates).prompt(); 129 + 130 + let template = match template { 131 + Ok(template) => template.to_ascii_lowercase(), 132 + Err(_) => { 133 + println!(); 134 + return; 135 + } 136 + }; 137 + 138 + let git = Confirm::new("Do you want to initialize a git repository?") 139 + .with_default(true) 140 + .prompt(); 141 + 142 + let git = match git { 143 + Ok(git) => git, 144 + Err(_) => { 145 + println!(); 146 + return; 147 + } 148 + }; 149 + 150 + // Do the steps 151 + println!(); 152 + 153 + // Create the project directory 154 + let directory_spinner = Spinner::new(" Creating directory") 155 + .symbols(vec!["◐", "◓", "◑", "◒"]) 156 + .start(); 157 + 158 + let start_time = std::time::Instant::now(); 159 + if !dry_run { 160 + std::fs::create_dir_all(&project_path).expect("Failed to create project directory"); 161 + } 162 + let elasped_time = format_elapsed_time(Ok(start_time.elapsed()), &Default::default()).unwrap(); 163 + 164 + directory_spinner 165 + .text(&format!(" Created directory {}", elasped_time)) 166 + .symbol("●") 167 + .color(Color::Green) 168 + .stop(); 169 + 170 + let template_spinner = Spinner::new(" Downloading template") 171 + .symbols(vec!["◐", "◓", "◑", "◒"]) 172 + .start(); 173 + 174 + let start_time = std::time::Instant::now(); 175 + if !dry_run { 176 + download_and_unpack_template(&template, &project_path) 177 + .expect("Failed to download template"); 178 + } 179 + let elasped_time = format_elapsed_time(Ok(start_time.elapsed()), &Default::default()).unwrap(); 180 + 181 + template_spinner 182 + .text(&format!(" Downloaded template {}", elasped_time)) 183 + .symbol("●") 184 + .color(Color::Green) 185 + .stop(); 186 + 187 + if git { 188 + let git_spinner = Spinner::new(" Initializing git repository") 189 + .symbols(vec!["◐", "◓", "◑", "◒"]) 190 + .start(); 191 + 192 + let start_time = std::time::Instant::now(); 193 + 194 + let init_result = if !dry_run { 195 + init_git_repo(&project_path, dry_run) 196 + } else { 197 + Ok(()) 198 + }; 199 + 200 + let elasped_time = 201 + format_elapsed_time(Ok(start_time.elapsed()), &Default::default()).unwrap(); 202 + 203 + match init_result { 204 + Ok(_) => git_spinner 205 + .text(&format!(" Initialized git repository {}", elasped_time)) 206 + .symbol("●") 207 + .color(Color::Green) 208 + .stop(), 209 + Err(e) => { 210 + git_spinner 211 + .text(" Failed to initialize git repository") 212 + .failure(); 213 + eprintln!("{}", e); 214 + } 215 + } 216 + } 217 + 218 + println!(); 219 + 220 + info!(name: "SKIP_FORMAT", "👑 {} {}! Next steps:", "Project created".bold(), "successfully".green().to_string().bold()); 221 + println!(); 222 + 223 + info!(name: "SKIP_FORMAT", "1. Run {} to enter your project's directory.", format!("cd {}", project_path.display()).bold().bright_blue().underline()); 224 + info!(name: "SKIP_FORMAT", "2. Run {} to start the development server, {} to stop it.", "maudit dev".bold().bright_blue().underline(), "CTRL+C".bright_blue()); 225 + println!(); 226 + 227 + info!(name: "SKIP_FORMAT", " Visit {} for more information on using Maudit.", "https://maudit.org/docs".bold().bright_magenta().underline()); 228 + info!(name: "SKIP_FORMAT", " Need a hand? Find us at {}.", "https://maudit.org/chat".bold().bright_magenta().underline()); 229 + } 230 + 231 + fn download_and_unpack_template(template: &str, project_path: &Path) -> Result<(), String> { 232 + let tarball = ureq::get(REPO_TAR_URL) 233 + .call() 234 + .map_err(|e| format!("Failed to download template: {}", e))?; 235 + 236 + if !tarball.status().is_success() { 237 + return Err("Failed to download template".to_string()); 238 + } 239 + 240 + let (_, body) = tarball.into_parts(); 241 + let archive = body.into_reader(); 242 + 243 + // Uncomment to test with a local tarball 244 + //let archive = std::fs::File::open("project.tar").unwrap(); 245 + 246 + let mut archive = tar::Archive::new(archive); 247 + 248 + for file in archive.entries().unwrap() { 249 + let mut file = file.unwrap(); 250 + let path = file.path().unwrap(); 251 + 252 + if path.starts_with(format!("examples/{}", template)) { 253 + let path = path.strip_prefix(format!("examples/{}", template)).unwrap(); 254 + let path = project_path.join(path); 255 + 256 + file.unpack(path).unwrap(); 257 + } 258 + } 259 + 260 + // Edit the Cargo.toml file 261 + let cargo_toml_path = project_path.join("Cargo.toml"); 262 + 263 + let cargo_toml_content = std::fs::read_to_string(&cargo_toml_path).unwrap(); 264 + let mut cargo_toml = cargo_toml_content 265 + .parse::<DocumentMut>() 266 + .expect("invalid doc"); 267 + 268 + let project_name = project_path 269 + .components() 270 + .last() 271 + .unwrap() 272 + .as_os_str() 273 + .to_str() 274 + .unwrap(); 275 + 276 + cargo_toml["package"]["name"] = toml_edit::value(project_name); 277 + 278 + std::fs::write(&cargo_toml_path, cargo_toml.to_string()).unwrap(); 279 + 280 + Ok(()) 281 + } 282 + 283 + fn init_git_repo(project_path: &PathBuf, dry_run: &bool) -> Result<(), String> { 284 + if !dry_run { 285 + let git_init = std::process::Command::new("git") 286 + .arg("init") 287 + .arg(project_path) 288 + .stdout(Stdio::null()) 289 + .stderr(Stdio::null()) 290 + .status() 291 + .map_err(|e| format!("Failed to run git init: {}", e))? 292 + .success(); 293 + 294 + if !git_init { 295 + return Err("Failed to initialize git repository".to_string()); 296 + } 297 + 298 + let git_add = std::process::Command::new("git") 299 + .arg("add") 300 + .arg("-A") 301 + .current_dir(project_path) 302 + .stdout(Stdio::null()) 303 + .stderr(Stdio::null()) 304 + .status() 305 + .map_err(|e| format!("Failed to run git add: {}", e))? 306 + .success(); 307 + 308 + if !git_add { 309 + return Err("Failed to add initial changes".to_string()); 310 + } 311 + 312 + let git_commit = std::process::Command::new("git") 313 + .arg("commit") 314 + .arg("-m") 315 + .arg("Initial commit") 316 + .current_dir(project_path) 317 + .stdout(Stdio::null()) 318 + .stderr(Stdio::null()) 319 + .status() 320 + .map_err(|e| format!("Failed to run git commit: {}", e))? 321 + .success(); 322 + 323 + if !git_commit { 324 + return Err("Failed to commit initial changes".to_string()); 325 + } 326 + } 327 + 328 + Ok(()) 329 + } 330 + 331 + fn has_invalid_filepath_chars(s: &str) -> bool { 332 + s.chars().any(|c| { 333 + c == '/' 334 + || c == '\\' 335 + || c == ':' 336 + || c == '*' 337 + || c == '?' 338 + || c == '"' 339 + || c == '<' 340 + || c == '>' 341 + || c == '|' 342 + }) 343 + }
+123
crates/cli/src/init/names.rs
··· 1 + use rand::{rngs::ThreadRng, seq::IndexedRandom}; 2 + 3 + const ADJECTIVE: [&str; 35] = [ 4 + "valiant", 5 + "gallant", 6 + "stalwart", 7 + "noble", 8 + "chivalrous", 9 + "fearless", 10 + "bold", 11 + "mighty", 12 + "regal", 13 + "venerable", 14 + "doughty", 15 + "heroic", 16 + "virtuous", 17 + "majestic", 18 + "ancient", 19 + "fabled", 20 + "valorous", 21 + "steadfast", 22 + "resolute", 23 + "forthright", 24 + "grumpy", 25 + "cantankerous", 26 + "cranky", 27 + "sullen", 28 + "pompous", 29 + "roguish", 30 + "wily", 31 + "somber", 32 + "haughty", 33 + "cunning", 34 + "dashing", 35 + "grim", 36 + "stern", 37 + "ardent", 38 + "jovial", 39 + ]; 40 + const TITLE: [&str; 35] = [ 41 + "duke", 42 + "duchess", 43 + "marquess", 44 + "marchioness", 45 + "earl", 46 + "count", 47 + "countess", 48 + "baron", 49 + "baroness", 50 + "viscount", 51 + "viscountess", 52 + "lord", 53 + "lady", 54 + "knight", 55 + "baronet", 56 + "prince", 57 + "princess", 58 + "king", 59 + "queen", 60 + "landgrave", 61 + "palatine", 62 + "constable", 63 + "seneschal", 64 + "provost", 65 + "castellan", 66 + "ogre", 67 + "basilisk", 68 + "griffin", 69 + "chimera", 70 + "werewolf", 71 + "vampire", 72 + "dragon", 73 + "gorgon", 74 + "troll", 75 + "wyvern", 76 + ]; 77 + const NAME: [&str; 37] = [ 78 + "amelia", 79 + "eleanor", 80 + "gwendolyn", 81 + "isolde", 82 + "matilda", 83 + "rosamund", 84 + "celestine", 85 + "genevieve", 86 + "cordelia", 87 + "ophelia", 88 + "edmund", 89 + "geoffrey", 90 + "oswald", 91 + "algernon", 92 + "reginald", 93 + "cedric", 94 + "theodore", 95 + "roderick", 96 + "finnian", 97 + "goulven", 98 + "lavinia", 99 + "rosalind", 100 + "bartholomew", 101 + "philip", 102 + "cornelius", 103 + "erika", 104 + "rosaline", 105 + "annabel", 106 + "mirabelle", 107 + "winifred", 108 + "vivienne", 109 + "leopold", 110 + "fitzroy", 111 + "walter", 112 + "roland", 113 + "giles", 114 + "aurelien", 115 + ]; 116 + 117 + pub fn generate_directory_name(rng: &mut ThreadRng) -> String { 118 + let title = TITLE.choose(rng).unwrap(); 119 + let name = NAME.choose(rng).unwrap(); 120 + let adjective = ADJECTIVE.choose(rng).unwrap(); 121 + 122 + format!("{}-{}-{}", adjective, title, name) 123 + }
+12
crates/cli/src/init/render_config.rs
··· 1 + use inquire::ui::{Attributes, Color, RenderConfig, StyleSheet, Styled}; 2 + 3 + pub fn get_render_config() -> RenderConfig<'static> { 4 + RenderConfig { 5 + prompt: StyleSheet::new().with_attr(Attributes::BOLD), 6 + prompt_prefix: Styled::new("○ ").with_fg(Color::LightCyan), 7 + text_input: StyleSheet::new().with_fg(Color::LightCyan), 8 + answer: StyleSheet::new().with_fg(Color::LightGreen), 9 + answered_prompt_prefix: Styled::new("● ").with_fg(Color::LightGreen), 10 + ..Default::default() 11 + } 12 + }
crates/cli/src/init/template.rs

This is a binary file and will not be displayed.

+11 -2
crates/cli/src/main.rs
··· 1 1 mod build; 2 2 mod dev; 3 + mod init; 3 4 mod preview; 4 5 5 6 mod logging; 6 7 7 8 use clap::{Parser, Subcommand}; 8 - use dev::coordinate_dev_env; 9 + use dev::start_dev_env; 9 10 use logging::init_logging; 10 11 use preview::start_preview_web_server; 11 12 use std::path::{Path, PathBuf}; ··· 20 21 21 22 #[derive(Subcommand)] 22 23 enum Commands { 24 + /// Initialize a new Maudit project 25 + Init { 26 + #[clap(long, short)] 27 + dry_run: bool, 28 + }, 23 29 /// Build the project 24 30 Build, 25 31 /// Run the project in development mode ··· 36 42 // You can check for the existence of subcommands, and if found use their 37 43 // matches just as you would the top level cmd 38 44 match &cli.command { 45 + Commands::Init { dry_run } => { 46 + init::start_new_project(dry_run); 47 + } 39 48 Commands::Build {} => { 40 49 build::start_build(); 41 50 } ··· 53 62 let _ = start_preview_web_server(PathBuf::from("dist")).await; 54 63 } 55 64 Commands::Dev {} => { 56 - let _ = coordinate_dev_env(".").await; 65 + let _ = start_dev_env(".").await; 57 66 } 58 67 } 59 68 }
+2 -2
examples/basics/Cargo.toml
··· 5 5 publish = false 6 6 7 7 [dependencies] 8 - maudit = { workspace = true } 9 - maud = { workspace = true } 8 + maudit = "0.2.0" 9 + maud = "0.26.0"
+3 -3
examples/blog/Cargo.toml
··· 5 5 publish = false 6 6 7 7 [dependencies] 8 - maudit = { workspace = true } 9 - maud = { workspace = true } 10 - serde = { workspace = true } 8 + maudit = "0.2.0" 9 + maud = "0.26.0" 10 + serde = { version = "1.0.216" }
+2 -2
examples/kitchen-sink/Cargo.toml
··· 5 5 publish = false 6 6 7 7 [dependencies] 8 - maudit = { workspace = true } 9 - maud = { workspace = true } 8 + maudit = "0.2.0" 9 + maud = "0.26.0"