From 70286c0a9a388a99cbaa873d6cca39f474691e4a Mon Sep 17 00:00:00 2001 From: Rasmus Rosengren Date: Wed, 8 Mar 2023 03:04:24 +0100 Subject: [PATCH] remove async --- Cargo.lock | 444 ++++++++++++++++------------------ Cargo.toml | 11 +- src/apply.rs | 73 ++++++ src/build.rs | 31 ++- src/{config.rs => context.rs} | 2 +- src/diff.rs | 30 ++- src/install.rs | 48 ---- src/main.rs | 80 +++--- src/opts.rs | 52 ++-- src/utils.rs | 65 +++-- 10 files changed, 428 insertions(+), 408 deletions(-) create mode 100644 src/apply.rs rename src/{config.rs => context.rs} (89%) delete mode 100644 src/install.rs diff --git a/Cargo.lock b/Cargo.lock index 4b845ff..87e978a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,21 +3,19 @@ version = 3 [[package]] -name = "anyhow" -version = "1.0.45" +name = "aho-corasick" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] [[package]] -name = "async-recursion" -version = "0.3.2" +name = "anyhow" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" [[package]] name = "atty" @@ -25,17 +23,11 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "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.3.2" @@ -43,10 +35,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "bytes" -version = "1.1.0" +name = "cc" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -56,35 +48,33 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.0.14" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ - "atty", "bitflags", "clap_derive", - "indexmap", - "lazy_static", - "os_str_bytes", + "clap_lex", + "is-terminal", + "once_cell", "strsim", "termcolor", - "textwrap", ] [[package]] name = "clap_complete" -version = "3.0.6" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678db4c39c013cc68b54d372bce2efc58e30a0337c497c9032fd196802df3bc3" +checksum = "501ff0a401473ea1d4c3b125ff95506b62c5bc5768d818634195fbb7c4ad5ff4" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "3.0.14" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" dependencies = [ "heck", "proc-macro-error", @@ -93,18 +83,26 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_lex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "dfm" version = "0.1.0" dependencies = [ "anyhow", - "async-recursion", "clap", "clap_complete", "directories", - "futures", + "log", + "pretty_env_logger", "terminal_size", - "tokio", "xdg", ] @@ -129,97 +127,37 @@ dependencies = [ ] [[package]] -name = "futures" -version = "0.3.16" +name = "env_logger" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" - -[[package]] -name = "futures-executor" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] -name = "futures-io" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" - -[[package]] -name = "futures-macro" -version = "0.3.16" +name = "errno" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ - "autocfg", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "errno-dragonfly", + "libc", + "winapi", ] [[package]] -name = "futures-sink" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" - -[[package]] -name = "futures-task" -version = "0.3.16" +name = "errno-dragonfly" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" - -[[package]] -name = "futures-util" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "autocfg", - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", + "cc", + "libc", ] [[package]] @@ -233,12 +171,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - [[package]] name = "heck" version = "0.4.0" @@ -255,109 +187,90 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" +name = "hermit-abi" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] -name = "libc" -version = "0.2.100" +name = "humantime" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] [[package]] -name = "log" -version = "0.4.14" +name = "io-lifetimes" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" dependencies = [ - "cfg-if", + "libc", + "windows-sys", ] [[package]] -name = "memchr" -version = "2.4.1" +name = "is-terminal" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] [[package]] -name = "mio" -version = "0.7.14" +name = "libc" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] -name = "miow" -version = "0.3.7" +name = "linux-raw-sys" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] -name = "ntapi" -version = "0.3.6" +name = "log" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "winapi", + "cfg-if", ] [[package]] -name = "num_cpus" -version = "1.13.0" +name = "memchr" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "once_cell" -version = "1.8.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "os_str_bytes" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pretty_env_logger" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] [[package]] name = "proc-macro-error" @@ -383,27 +296,21 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ - "unicode-xid", + "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.9" @@ -433,19 +340,35 @@ dependencies = [ ] [[package]] -name = "signal-hook-registry" -version = "1.4.0" +name = "regex" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ - "libc", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "slab" -version = "0.4.4" +name = "regex-syntax" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "rustix" +version = "0.36.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] [[package]] name = "strsim" @@ -475,48 +398,19 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.1.17" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" dependencies = [ - "libc", - "winapi", + "rustix", + "windows-sys", ] [[package]] -name = "textwrap" -version = "0.14.2" +name = "unicode-ident" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" - -[[package]] -name = "tokio" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92036be488bb6594459f2e03b60e42df6f937fe6ca5c5ffdcb539c6b84dc40f5" -dependencies = [ - "autocfg", - "bytes", - "libc", - "mio", - "num_cpus", - "once_cell", - "pin-project-lite", - "signal-hook-registry", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-xid" @@ -567,6 +461,72 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + [[package]] name = "xdg" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index d28d87d..a0bd6dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,10 @@ edition = "2021" [dependencies] anyhow = "1.0" -async-recursion = "0.3" -clap = { version = "3.0", features = ["derive"] } -clap_complete = "3.0" +clap = { version = "4.1.8", features = ["derive"] } +clap_complete = "4.1.4" directories = "4.0" -futures = "0.3" -terminal_size = "0.1" -tokio = { version = "1.10", features = ["fs", "macros", "process", "rt-multi-thread"] } +log = "0.4.17" +pretty_env_logger = "0.4.0" +terminal_size = "0.2.5" xdg = "2.2" diff --git a/src/apply.rs b/src/apply.rs new file mode 100644 index 0000000..5b78f54 --- /dev/null +++ b/src/apply.rs @@ -0,0 +1,73 @@ +use crate::{ + context::Context, + utils::{get_tree_files, remove_dir_if_empty}, +}; + +pub fn apply(context: &Context, filter: &Option, link: bool) -> anyhow::Result<()> { + std::fs::create_dir_all(&context.install_dir)?; + let mut built_files = get_tree_files(context, &context.build_dir)?; + let mut installed_files = get_tree_files(context, &context.install_dir)?; + if let Some(filter) = filter { + log::debug!("Using filter: {}", filter); + built_files = built_files + .into_iter() + .filter(|path| path.starts_with(filter)) + .collect(); + installed_files = installed_files + .into_iter() + .filter(|path| path.starts_with(filter)) + .collect(); + } + log::debug!("Built files: {:#?}", built_files); + log::debug!("Installed files: {:#?}", installed_files); + + for file_path in built_files.iter() { + if let Some(folder_path) = file_path.parent() { + let dir = context.install_dir.join(folder_path); + std::fs::create_dir_all(dir)?; + } + + let from = context.build_dir.join(file_path); + let to = context.install_dir.join(file_path); + std::fs::copy(from, to)?; + + if link { + // Make sure symlink doesn't exist before attempting to symlink + let link_target = context.link_dir.join(&file_path); + let link_target_exists = link_target.exists(); + if link_target_exists && !link_target.is_symlink() { + log::warn!( + "Could not link {:?}, link target already exists and is not a symlink", + file_path + ); + } else { + if link_target_exists { + match std::fs::remove_file(&link_target) { + Ok(_) => {} + Err(e) => anyhow::bail!(e), + }; + } + + if let Some(folder_path) = file_path.parent() { + let dir = context.link_dir.join(folder_path); + std::fs::create_dir_all(dir)?; + } + + std::os::unix::fs::symlink(context.install_dir.join(&file_path), link_target)?; + } + } + } + + for file_path in installed_files { + if !built_files.contains(&file_path) { + let installed_file = context.install_dir.join(&file_path); + let linked_file = context.link_dir.join(&file_path); + std::fs::remove_file(linked_file.clone())?; + remove_dir_if_empty(linked_file.parent().unwrap())?; + std::fs::remove_file(installed_file.clone())?; + remove_dir_if_empty(installed_file.parent().unwrap())?; + } + } + + Ok(()) +} diff --git a/src/build.rs b/src/build.rs index 61a9ea8..974f270 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,29 +1,34 @@ use crate::{ - config::Config, + context::Context, utils::{get_tree_files, remove_dir_if_empty}, }; -pub async fn build(config: &Config) -> anyhow::Result<()> { - tokio::fs::create_dir_all(&config.build_dir).await?; - let source_files = get_tree_files(config, &config.source_dir).await?; - let build_files = get_tree_files(config, &config.build_dir).await?; +pub fn build(context: &Context) -> anyhow::Result<()> { + std::fs::create_dir_all(&context.build_dir)?; + let source_files = get_tree_files(context, &context.source_dir)?; + let build_files = get_tree_files(context, &context.build_dir)?; + log::debug!("Source files: {:#?}", source_files); + log::debug!("Existing files: {:#?}", build_files); for file_path in source_files.iter() { + // Make sure that the folder into which the file is to be created exists if let Some(folder_path) = file_path.parent() { - let dir = config.build_dir.join(folder_path); - tokio::fs::create_dir_all(dir).await?; + let dir = context.build_dir.join(folder_path); + std::fs::create_dir_all(dir)?; } - let from = config.source_dir.join(file_path); - let to = config.build_dir.join(file_path); - tokio::fs::copy(from, to).await?; + let from = context.source_dir.join(file_path); + let to = context.build_dir.join(file_path); + log::debug!("Copied {:?} to {:?}", from, to); + std::fs::copy(from, to)?; } for file_path in build_files { if !source_files.contains(&file_path) { - let file = config.build_dir.join(file_path); - tokio::fs::remove_file(file.clone()).await?; - remove_dir_if_empty(file.parent().unwrap()).await?; + let file = context.build_dir.join(file_path); + log::debug!("Removed {:?}", file); + std::fs::remove_file(file.clone())?; + remove_dir_if_empty(file.parent().unwrap())?; } } diff --git a/src/config.rs b/src/context.rs similarity index 89% rename from src/config.rs rename to src/context.rs index cb76863..58c8878 100644 --- a/src/config.rs +++ b/src/context.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; #[derive(Debug)] -pub struct Config { +pub struct Context { pub source_dir: PathBuf, pub build_dir: PathBuf, pub install_dir: PathBuf, diff --git a/src/diff.rs b/src/diff.rs index 413d9f5..8429101 100644 --- a/src/diff.rs +++ b/src/diff.rs @@ -2,12 +2,14 @@ use std::{io::Write, path::PathBuf}; use terminal_size::{terminal_size, Width}; -use crate::{config::Config, utils::get_tree_files}; +use crate::{context::Context, utils::get_tree_files}; -pub async fn diff(config: &Config) -> anyhow::Result<()> { - tokio::fs::create_dir_all(&config.install_dir).await?; - let built_files = get_tree_files(config, &config.build_dir).await?; - let installed_files = get_tree_files(config, &config.install_dir).await?; +pub fn diff(context: &Context) -> anyhow::Result<()> { + std::fs::create_dir_all(&context.install_dir)?; + let built_files = get_tree_files(context, &context.build_dir)?; + let installed_files = get_tree_files(context, &context.install_dir)?; + log::debug!("Built files: {:#?}", built_files); + log::debug!("Installed files: {:#?}", installed_files); let mut all_files = built_files.clone(); all_files.extend(installed_files.clone()); @@ -21,32 +23,34 @@ pub async fn diff(config: &Config) -> anyhow::Result<()> { let (workdir, first_path, second_path) = if is_added { ( - config.build_dir.clone(), + context.build_dir.clone(), file.clone(), PathBuf::from("/dev/null"), ) } else if is_removed { ( - config.install_dir.clone(), + context.install_dir.clone(), PathBuf::from("/dev/null"), file.clone(), ) } else { ( - config.build_dir.clone(), + context.build_dir.clone(), file.clone(), - config.install_dir.join(file), + context.install_dir.join(file), ) }; - let output = tokio::process::Command::new("delta") + let output = std::process::Command::new("difft") .current_dir(workdir) .arg(second_path) .arg(first_path) - .arg("-w") + .arg("--skip-unchanged") + .arg("--color") + .arg("always") + .arg("--width") .arg(terminal_width.to_string()) - .output() - .await?; + .output()?; std::io::stdout().write_all(&output.stdout)?; } diff --git a/src/install.rs b/src/install.rs deleted file mode 100644 index a222fdc..0000000 --- a/src/install.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{ - config::Config, - utils::{get_tree_files, remove_dir_if_empty}, -}; - -pub async fn install(config: &Config) -> anyhow::Result<()> { - tokio::fs::create_dir_all(&config.install_dir).await?; - let built_files = get_tree_files(config, &config.build_dir).await?; - let installed_files = get_tree_files(config, &config.install_dir).await?; - - for file_path in built_files.iter() { - if let Some(folder_path) = file_path.parent() { - let dir = config.install_dir.join(folder_path); - tokio::fs::create_dir_all(dir).await?; - } - - let from = config.build_dir.join(file_path); - let to = config.install_dir.join(file_path); - tokio::fs::copy(from, to).await?; - - if let Some(folder_path) = file_path.parent() { - let dir = config.link_dir.join(folder_path); - tokio::fs::create_dir_all(dir).await?; - } - - // Make sure symlink doesn't exist before attempting to symlink - let link_target = config.link_dir.join(&file_path); - match tokio::fs::remove_file(&link_target).await { - Ok(_) => {} - Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} - Err(e) => anyhow::bail!(e), - }; - tokio::fs::symlink(config.install_dir.join(&file_path), link_target).await?; - } - - for file_path in installed_files { - if !built_files.contains(&file_path) { - let installed_file = config.install_dir.join(&file_path); - let linked_file = config.link_dir.join(&file_path); - tokio::fs::remove_file(linked_file.clone()).await?; - remove_dir_if_empty(linked_file.parent().unwrap()).await?; - tokio::fs::remove_file(installed_file.clone()).await?; - remove_dir_if_empty(installed_file.parent().unwrap()).await?; - } - } - - Ok(()) -} diff --git a/src/main.rs b/src/main.rs index bd8cd2c..ba233f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,64 +1,72 @@ +mod apply; mod build; -mod config; +mod context; mod diff; -mod install; mod opts; mod utils; use std::path::PathBuf; -use clap::{IntoApp, Parser}; +use clap::{CommandFactory, Parser}; use clap_complete::generate; use directories::{ProjectDirs, UserDirs}; -use utils::command_exists; -use crate::{build::build, config::Config, diff::diff, install::install, opts::Opts}; +use crate::{ + apply::apply, build::build, context::Context, diff::diff, opts::Opts, utils::command_exists, +}; -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let opts = Opts::parse(); +fn main() -> anyhow::Result<()> { + pretty_env_logger::init(); - if let Some(generator) = opts.generate { - generate( - generator, - &mut Opts::into_app(), - "dfm", - &mut std::io::stdout(), - ); - return Ok(()); + let opts = Opts::parse(); + log::debug!("Command line options: {:#?}", opts); + match opts.command { + opts::Commands::Apply { + repo_path, + filter, + link, + } => { + if !command_exists("difft") { + println!("'difft' is not installed"); + } else { + let context = build_context(repo_path); + log::debug!("Context: {:#?}", context); + build(&context).expect("Failed to build"); + apply(&context, &filter, link).expect("Failed to apply"); + } + } + opts::Commands::Diff { repo_path } => { + let context = build_context(repo_path); + log::debug!("Context: {:#?}", context); + build(&context).expect("Failed to build"); + diff(&context).expect("Failed to diff"); + } + opts::Commands::GenerateCompletions { shell } => { + generate(shell, &mut Opts::command(), "dfm", &mut std::io::stdout()); + } } + Ok(()) +} + +fn build_context(repo_path: PathBuf) -> Context { let user_dirs = UserDirs::new().expect("Could not find user directories"); let project_dirs = ProjectDirs::from("se", "rsrp", "dfm").expect("Could not find project directories"); - let repo_path = if opts.repo_path.is_relative() { - let mut repo_path = PathBuf::from(user_dirs.home_dir()); - repo_path.push(opts.repo_path); - repo_path + let repo_path = if repo_path.is_relative() { + let mut absolute_repo_path = PathBuf::from(user_dirs.home_dir()); + absolute_repo_path.push(repo_path); + absolute_repo_path } else { - opts.repo_path + repo_path }; - let config = Config { + Context { source_dir: repo_path, build_dir: project_dirs.cache_dir().to_path_buf().join("tree"), install_dir: project_dirs.config_dir().to_path_buf().join("tree"), link_dir: user_dirs.home_dir().to_path_buf(), ignored_dirs: vec![".git".to_string()], - }; - - build(&config).await?; - if opts.install { - install(&config).await?; - } else { - if !command_exists("delta").await { - println!("'delta' is not installed"); - return Ok(()); - } - - diff(&config).await?; } - - Ok(()) } diff --git a/src/opts.rs b/src/opts.rs index a6a27c0..142259d 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -1,29 +1,51 @@ use std::path::PathBuf; -use clap::Parser; +use clap::{Parser, Subcommand}; use clap_complete::Shell; -use crate::utils::APP_VERSION; - #[derive(Debug, Parser)] #[clap( name = "dfm", - version = APP_VERSION, + version = env!("CARGO_PKG_VERSION"), author = "Rasmus Rosengren ", about = "Utility to manage dotfiles" )] pub struct Opts { - #[clap(short, long)] - pub install: bool, + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Debug, Subcommand)] +pub enum Commands { + #[clap(about = "Apply changes")] + Apply { + #[clap( + short, + long, + default_value = ".df", + help = "Path to source repo, absolute path or path relative to $HOME" + )] + repo_path: PathBuf, - #[clap( - short, - long, - default_value = ".df", - help = "Absolute path or relative path to $HOME" - )] - pub repo_path: PathBuf, + #[clap(help = "Filter which files should be installed, checks for substring")] + filter: Option, - #[clap(long, value_name = "SHELL", help = "Generate shell completions")] - pub generate: Option, + #[clap(short, long, default_value = "true", help = "Symlink the built files")] + link: bool, + }, + #[clap(about = "Display diff between repo and installed files")] + Diff { + #[clap( + short, + long, + default_value = ".df", + help = "Path to source repo, absolute path or path relative to $HOME" + )] + repo_path: PathBuf, + }, + #[clap(about = "Generate shell completions")] + GenerateCompletions { + #[clap(long, value_name = "SHELL", help = "Generate shell completions")] + shell: Shell, + }, } diff --git a/src/utils.rs b/src/utils.rs index 5412f9a..606bdc3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,68 +3,65 @@ use std::{ path::{Path, PathBuf}, }; -use futures::future::try_join_all; -use tokio::fs::read_dir; +use crate::context::Context; -use crate::config::Config; - -pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); - -pub async fn get_tree_files(config: &Config, tree_root: &Path) -> anyhow::Result> { - get_tree_files_recursively(config, tree_root, PathBuf::new()).await +pub fn get_tree_files(context: &Context, tree_root: &Path) -> anyhow::Result> { + get_tree_files_recursively(context, tree_root, PathBuf::new()) } -#[async_recursion::async_recursion] -async fn get_tree_files_recursively( - config: &Config, +fn get_tree_files_recursively( + context: &Context, tree_root: &Path, relative_path: PathBuf, ) -> anyhow::Result> { let current_path = tree_root.join(&relative_path); - - let mut dir_walker = read_dir(¤t_path).await?; - let mut dir_tasks = vec![]; - + let mut dir_walker = std::fs::read_dir(¤t_path)?; let mut files = HashSet::new(); - while let Some(entry) = dir_walker.next_entry().await? { - let metadata = entry.metadata().await?; + while let Some(Ok(entry)) = dir_walker.next() { + let metadata = entry.metadata()?; let os_name = entry.file_name(); let name = os_name.to_string_lossy().to_string(); - if config.ignored_dirs.contains(&name) { + if context.ignored_dirs.contains(&name) { continue; } if metadata.is_dir() { - dir_tasks.push(get_tree_files_recursively( - config, + files.extend(get_tree_files_recursively( + context, tree_root, relative_path.join(name), - )); + )?); } else if metadata.is_file() { files.insert(relative_path.join(name)); } } - let file_sets = try_join_all(dir_tasks).await?; - for file_set in file_sets { - files.extend(file_set); - } - Ok(files) } -pub async fn remove_dir_if_empty(path: &Path) -> anyhow::Result<()> { - let mut dir_walker = tokio::fs::read_dir(path).await?; +pub fn remove_dir_if_empty(path: &Path) -> anyhow::Result<()> { + let mut path = path.to_path_buf(); - if dir_walker.next_entry().await?.is_none() { - tokio::fs::remove_dir(path).await?; + loop { + let mut dir_walker = std::fs::read_dir(&path)?; + if dir_walker.next().is_none() { + std::fs::remove_dir(&path)?; + match path.parent() { + Some(parent) => path = parent.to_path_buf(), + None => break, + } + } else { + break; + } } Ok(()) } -pub async fn command_exists(command: &str) -> bool { - tokio::process::Command::new("which") - .arg(&command).status().await.is_ok() -} \ No newline at end of file +pub fn command_exists(command: &str) -> bool { + std::process::Command::new("which") + .arg(&command) + .status() + .is_ok() +}