From 6044f30bd998ecac796d4ebf6b3c7b7a07c97b2f Mon Sep 17 00:00:00 2001 From: acikek Date: Tue, 23 Nov 2021 11:11:44 -0800 Subject: [PATCH] initial commands --- .gitignore | 2 + Cargo.lock | 766 +++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 21 ++ src/cli.yml | 43 +++ src/config.rs | 1 + src/config/styles.rs | 35 ++ src/io.rs | 2 + src/io/fs.rs | 57 +++ src/io/log.rs | 13 + src/main.rs | 23 ++ src/structs.rs | 1 + src/structs/project.rs | 166 +++++++++ src/subcmd.rs | 3 + src/subcmd/new.rs | 56 +++ src/subcmd/project.rs | 22 ++ src/subcmd/script.rs | 50 +++ 16 files changed, 1261 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/cli.yml create mode 100644 src/config.rs create mode 100644 src/config/styles.rs create mode 100644 src/io.rs create mode 100644 src/io/fs.rs create mode 100644 src/io/log.rs create mode 100644 src/main.rs create mode 100644 src/structs.rs create mode 100644 src/structs/project.rs create mode 100644 src/subcmd.rs create mode 100644 src/subcmd/new.rs create mode 100644 src/subcmd/project.rs create mode 100644 src/subcmd/script.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c4bf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/test \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..59d0e28 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,766 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term 0.11.0", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", + "yaml-rust 0.3.5", +] + +[[package]] +name = "clipboard-win" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + +[[package]] +name = "dzp" +version = "0.1.0" +dependencies = [ + "ansi_term 0.12.1", + "clap", + "dirs", + "git2", + "lazer", + "license", + "reduce", + "rustyline", + "semver", + "serde", + "serde_yaml", + "url", + "walkdir", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "error-code" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "fd-lock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8806dd91a06a7a403a8e596f9bfbfb34e469efbc363fc9c9713e79e26472e36" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "git2" +version = "0.13.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "845e007a28f1fcac035715988a234e8ec5458fd825b20a20c7dec74237ef341f" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "lazer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3383f4c9bd586ccf2e2b12ed242952d818af999ad0168402f718a4cc8ae2df9f" +dependencies = [ + "chrono", +] + +[[package]] +name = "libc" +version = "0.2.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" + +[[package]] +name = "libgit2-sys" +version = "0.12.25+1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68169ef08d6519b2fe133ecc637408d933c0174b23b80bb2f79828966fbaab" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "license" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915cfc01b6d1df117c5118ffeb5daaed908dd6d54ef2ee6ac40143c191d20" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "openssl-probe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" + +[[package]] +name = "openssl-sys" +version = "0.9.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pkg-config" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" + +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "reduce" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d2dc47b68ac15ea328cd7ebe01d7d512ed29787f7d534ad2a3c341328b35d7" + +[[package]] +name = "rustyline" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790487c3881a63489ae77126f57048b42d62d3b2bafbf37453ea19eedb6340d6" +dependencies = [ + "bitflags", + "cfg-if", + "clipboard-win", + "dirs-next", + "fd-lock", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "scopeguard", + "smallvec", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" +dependencies = [ + "dtoa", + "indexmap", + "serde", + "yaml-rust 0.4.5", +] + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "str-buf" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "syn" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1ce1ae7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "dzp" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ansi_term = "0.12.1" +clap = { version = "2.33.0", features = ["yaml"] } +dirs = "4.0.0" +git2 = "0.13.24" +lazer = "0.3.1" +license = "<=1.1.10" +reduce = "0.1.4" +rustyline = "9.0.0" +semver = { version = "1.0", features = ["serde"] } +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.8.20" +url = { version = "2.2.2", features = ["serde"] } +walkdir = "2" \ No newline at end of file diff --git a/src/cli.yml b/src/cli.yml new file mode 100644 index 0000000..a45f5f3 --- /dev/null +++ b/src/cli.yml @@ -0,0 +1,43 @@ +name: dzp +version: "0.1.0" +author: Skye P. +about: DeniZip, the Denizen Project Manager +subcommands: +- new: + about: Creates a new Denizen project + version: "0.1.0" + author: Skye P. + args: + - default: + help: Initializes the project data and skips input + short: d + long: default + - style: + help: Sets the project style + short: s + long: style + takes_value: true + value_name: STYLE + - NAME: + help: Sets the project name + required: true + index: 1 +- project: + about: Displays the current project info + version: "0.1.0" + author: Skye P. + args: + - path: + help: The relative path to the project + short: p + long: path + takes_value: true + value_name: PATH +- script: + about: Retrieves Denizen script data + version: "0.1.0" + author: Skye P. + args: + - NAME: + help: Sets the script name + index: 1 \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..b107b10 --- /dev/null +++ b/src/config.rs @@ -0,0 +1 @@ +pub mod styles; \ No newline at end of file diff --git a/src/config/styles.rs b/src/config/styles.rs new file mode 100644 index 0000000..0bc4eee --- /dev/null +++ b/src/config/styles.rs @@ -0,0 +1,35 @@ +use std::fs::{read_to_string, write}; +use std::path::Path; + +use dirs::config_dir; + +use crate::io::fs::create_dir; + +pub fn get_dir() -> String { + String::from(config_dir().unwrap().to_str().unwrap()) +} + +pub fn init_styles(force: bool) { + let dir = format!("{}/dzp_styles", get_dir()); + + if force || !Path::new(&dir).exists() { + create_dir(dir.as_str(), false); + let _ = write(format!("{}/default.txt", dir), "src/data\nsrc/util\nsrc/main"); + let _ = write(format!("{}/main.txt", dir), "src/main"); + } +} + +pub fn read_style(style: &str) -> Result, String> { + let dir = format!("{}/dzp_styles/{}.txt", get_dir(), style); + + match read_to_string(dir) { + Ok(txt) => { + Ok(txt + .split_terminator('\n') + .map(|s| String::from(s)) + .collect::>() + ) + }, + Err(e) => Err(e.to_string()) + } +} \ No newline at end of file diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..5a1c99d --- /dev/null +++ b/src/io.rs @@ -0,0 +1,2 @@ +pub mod fs; +pub mod log; \ No newline at end of file diff --git a/src/io/fs.rs b/src/io/fs.rs new file mode 100644 index 0000000..e696793 --- /dev/null +++ b/src/io/fs.rs @@ -0,0 +1,57 @@ +use std::collections::BTreeMap; +use std::fs::{create_dir_all, write, read_to_string}; + +use serde_yaml::{from_str, Value}; +use walkdir::WalkDir; + +use super::log::err; + +pub fn create_dir(path: &str, debug: bool) { + if debug { println!("Creating {}...", path); } + + match create_dir_all(path) { + Ok(_) => (), + Err(e) => err("Failed to create directory.", Some(e.to_string())) + } +} + +pub fn create(path: &str, content: String) { + println!("Creating {}...", path); + + match write(path, content) { + Ok(_) => (), + Err(e) => err("Failed to create file.", Some(e.to_string())) + } +} + +pub type ScriptContents = BTreeMap; +pub type ScriptFile = BTreeMap; + +pub fn find_scripts() -> BTreeMap { + // Get files in current directory + let files = WalkDir::new(".").into_iter().filter_map(|e| e.ok()); + // File extension needs to be .dsc + let script_files = files.filter(|f| f.path().extension().unwrap_or_default() == "dsc"); + // Return both the path string and the file contents + let file_pairs = script_files.map(|f| { + let path = String::from(f.clone().path().to_string_lossy()); + (path, read_to_string(f.path())) + }) + .filter(|r| r.1.is_ok()); + // Parse file contents + let parsed_files = file_pairs.map(|(p, c)| (p, from_str::(&c.unwrap()))) + // Validate parse + .filter(|r| r.1.is_ok()) + .map(|(p, c)| (p, c.unwrap())) + .collect::>(); + + let mut result = BTreeMap::::new(); + + for (path, scripts) in parsed_files { + for (script, contents) in scripts { + result.insert(script, (path.clone(), contents)); + } + } + + result +} \ No newline at end of file diff --git a/src/io/log.rs b/src/io/log.rs new file mode 100644 index 0000000..38f7ade --- /dev/null +++ b/src/io/log.rs @@ -0,0 +1,13 @@ +use ansi_term::Color::{Red, Black}; + +pub fn err(text: &str, reason: Option) { + let msg = Red.paint(text); + + match reason { + Some(r) => { + let rsn = Black.bold().paint(r); + println!("{} {}", msg, rsn); + } + None => println!("{}", msg) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3c44a53 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,23 @@ +use clap::{App, load_yaml}; + +mod config; +mod io; +mod structs; +mod subcmd; + +fn main() { + #[cfg(target_os = "windows")] + ansi_term::enable_ansi_support(); + + let yaml = load_yaml!("cli.yml"); + let mut app = App::from_yaml(yaml); + + config::styles::init_styles(true); + + let _ = match app.clone().get_matches().subcommand() { + ("new", Some(sub)) => subcmd::new::new(&sub), + ("project", Some(sub)) => subcmd::project::project(&sub), + ("script", Some(sub)) => subcmd::script::script(&sub), + _ => { let _ = app.print_help(); } + }; +} diff --git a/src/structs.rs b/src/structs.rs new file mode 100644 index 0000000..432f815 --- /dev/null +++ b/src/structs.rs @@ -0,0 +1 @@ +pub mod project; \ No newline at end of file diff --git a/src/structs/project.rs b/src/structs/project.rs new file mode 100644 index 0000000..09e4cf3 --- /dev/null +++ b/src/structs/project.rs @@ -0,0 +1,166 @@ +use lazer::lazer; +use license::from_id; +use rustyline::Editor; +use semver::Version; +use serde::{Serialize, Deserialize}; +use serde_yaml::to_string; +use url::Url; + +use crate::io::log::err; + +#[derive(Debug, Serialize, Deserialize)] +pub struct ProjectData { + pub name: String, + pub description: String, + pub authors: Vec, + pub version: Version, + pub license: String, + pub homepage: Option, + pub repository: Option, + pub dependencies: Option> +} + +type Error = rustyline::error::ReadlineError; + +impl ProjectData { + fn input(text: &str, rl: &mut Editor<()>) -> Result { + let line = rl.readline(&format!("{}: ", text))?; + rl.add_history_entry(&line); + Ok(line.trim().to_string()) + } + + fn input_authors(rl: &mut Editor<()>) -> Result, Error> { + let input = Self::input("Authors", rl)?; + + Ok(input + .split_terminator(',') + .map(|s| String::from(s.trim())) + .filter(|s| !s.is_empty()) + .collect()) + } + + fn input_version(rl: &mut Editor<()>) -> Result { + loop { + let input = Self::input("Version", rl)?; + if input.is_empty() { return Ok(Version::new(0, 1, 0)) } + + let v = Version::parse(&input); + + match v { + Ok(version) => return Ok(version), + Err(_) => err("Invalid version.", None) + } + } + } + + fn input_url(text: &str, rl: &mut Editor<()>) -> Result, Error> { + loop { + let input = Self::input(text, rl)?; + if input.is_empty() { return Ok(None) } + + let u = Url::parse(&input); + + match u { + Ok(url) => return Ok(Some(url)), + Err(_) => err("Invalid URL.", None) + } + } + } + + fn input_license(rl: &mut Editor<()>) -> Result { + loop { + let input = Self::input("License", rl)?; + if input.is_empty() { return Ok(String::from("MIT")) } + + let l = from_id(&input); + + match l { + Some(_) => return Ok(String::from(input)), + None => err("Invalid license.", None) + } + } + } + + pub fn from_input(name: String) -> Result { + let mut rl = Editor::<()>::new(); + + let description: String = Self::input("Description", &mut rl)?; + let authors = Self::input_authors(&mut rl)?; + let version = Self::input_version(&mut rl)?; + let license = Self::input_license(&mut rl)?; + let homepage = Self::input_url("Homepage", &mut rl)?; + let repository = Self::input_url("Repository", &mut rl)?; + + println!(); + + Ok(Self { + name, + description, + authors, + version, + license, + homepage, + repository, + dependencies: Some(Vec::new()) + }) + } + + pub fn from_name(name: String) -> Self { + Self { + name, + description: String::new(), + authors: Vec::::new(), + version: Version::new(0, 1, 0), + license: String::from("MIT"), + homepage: None, + repository: None, + dependencies: Some(Vec::new()) + } + } + + pub fn readme_header(&self) -> String { + format!("# {}\n\n{}", self.name, if self.description.is_empty() { + String::from("Sample description") + } else { + self.description.clone() + }) + } + + pub fn license_text(&self) -> String { + from_id(&self.license).unwrap_or(&license::MIT).text().to_string() + } + + pub fn yaml(&self) -> String { + to_string(&self).ok().unwrap() + } + + pub fn print_url(key: &str, url: Option) { + match url { + Some(u) => println!("{}: {}", key, u), + None => () + } + } + + pub fn print(&self) { + lazer() + .print(&self.name) + .print_ln(&format!(" v{}", self.version)) + .print_ln(&self.description) + .print_ln("") + .iff(self.authors.len() > 1) + .print_ln(&format!("Authors: {}", self.authors.join(", "))) + .el() + .print_ln(&format!("Author: {}", self.authors.first().unwrap())) + .end() + .print_ln(&format!("License: {}", self.license)); + + Self::print_url("Homepage", self.homepage.clone()); + Self::print_url("Repository", self.repository.clone()); + + lazer() + .iff(self.dependencies.is_some()) + .print_ln("\nDependencies:") + .print_ln(&self.dependencies.clone().unwrap_or(Vec::new()).iter().map(|s| format!("- {}", s)).collect::>().join("\n")) + .end(); + } +} \ No newline at end of file diff --git a/src/subcmd.rs b/src/subcmd.rs new file mode 100644 index 0000000..e1d8231 --- /dev/null +++ b/src/subcmd.rs @@ -0,0 +1,3 @@ +pub mod new; +pub mod project; +pub mod script; \ No newline at end of file diff --git a/src/subcmd/new.rs b/src/subcmd/new.rs new file mode 100644 index 0000000..4c53593 --- /dev/null +++ b/src/subcmd/new.rs @@ -0,0 +1,56 @@ +use std::env::current_dir; + +use clap::ArgMatches; +use git2::Repository; + +use crate::config::styles::read_style; +use crate::io::{log::err, fs::{create_dir, create}}; +use crate::structs::project::ProjectData; + +const MAIN: &str = r#" + type: world + events: + after server start: + - debug log "Hello, world!""#; + +pub fn new(matches: &ArgMatches) { + // Name of the project + let name: String = matches.value_of("NAME").unwrap().to_string(); + // Style argument + let style = matches.value_of("style").unwrap_or("default"); + // Forced to discontinue if unable to read style + match read_style(style) { + Ok(dirs) => { + // The project data object + // Take input if default argument not supplied + let project = if matches.is_present("default") { + Ok(ProjectData::from_name(name)) + } else { + ProjectData::from_input(name) + }; + + if let Ok(project) = project { + // Create style directories + for dir in &dirs { + create_dir(dir.as_str(), true); + } + // Main dsc file + create( + format!("{}/{}.dsc", dirs.last().unwrap(), &project.name).as_str(), + format!("{}:{}", &project.name, MAIN)); + // README & LICENSE + create("README.md", project.readme_header()); + create("LICENSE", project.license_text()); + // Create dzp directory + create_dir(".dzp", true); + create(".dzp/project", project.yaml()); + // Initialize git repository if possible + match Repository::init(current_dir().unwrap()) { + Ok(_) => create(".gitignore", String::from("/.dzp")), + Err(e) => err("Failed to initialize git repository.", Some(e.to_string())) + } + } + } + Err(e) => err("Invalid style.", Some(e.to_string())) + } +} \ No newline at end of file diff --git a/src/subcmd/project.rs b/src/subcmd/project.rs new file mode 100644 index 0000000..f5ebc1e --- /dev/null +++ b/src/subcmd/project.rs @@ -0,0 +1,22 @@ +use clap::ArgMatches; +use serde_yaml::from_str; + +use crate::io::log::err; +use crate::structs::project::ProjectData; + +pub fn project(matches: &ArgMatches) { + let path = matches.value_of("path").unwrap_or("./"); + + match std::fs::read_to_string(path.to_owned() + ".dzp/project") { + Ok(file) => { + match from_str::(&file) { + Ok(data) => { + println!(); + data.print(); + }, + Err(e) => err("Failed to parse project file.", Some(e.to_string())) + } + } + Err(e) => err("Failed to read project file.", Some(e.to_string())) + } +} \ No newline at end of file diff --git a/src/subcmd/script.rs b/src/subcmd/script.rs new file mode 100644 index 0000000..0f576b3 --- /dev/null +++ b/src/subcmd/script.rs @@ -0,0 +1,50 @@ +use clap::ArgMatches; +use lazer::lazer; +use serde_yaml::from_value; + +use crate::io::log::err; +use crate::io::fs::{find_scripts, ScriptContents}; + +pub fn print_script(name: &str, path: &String, data: &ScriptContents) { + if !data.contains_key("type") { + err("Script does not contain a 'type' key.", None); + } else { + match from_value::(data.get("type").unwrap().clone()) { + Ok(script_type) => { + lazer() + .print_ln(&format!("Name: {}", name)) + .print_ln(&format!("Type: {}", script_type)) + .print_ln(&format!("Path: {}", path)) + .print_ln(&format!("Keys: {}", data.keys().map(|s| s.clone()).collect::>().join(", "))); + } + Err(e) => err("Failed to parse 'type' key.", Some(e.to_string())) + } + } + + +} + +pub fn script(matches: &ArgMatches) { + let scripts = find_scripts(); + + match matches.value_of("NAME") { + Some(name) => { + match scripts.get(name) { + Some((path, data)) => { + println!(); + print_script(name, &path, &data); + } + None => err("Failed to find script.", None) + } + }, + None => { + let keys = scripts.keys() + .clone() + .map(|s| String::from(s)) + .collect::>() + .join(", "); + + println!("{}", keys); + } + } +} \ No newline at end of file