remove async

master
Rasmus Rosengren 2 years ago
parent 3ae7c26213
commit 70286c0a9a
Signed by: rsrp
SSH Key Fingerprint: SHA256:vdAo4Qg/MlIkxR5BRTABqMRJ1sGSVlUcIciriaE3cNU
  1. 444
      Cargo.lock
  2. 11
      Cargo.toml
  3. 73
      src/apply.rs
  4. 31
      src/build.rs
  5. 2
      src/context.rs
  6. 30
      src/diff.rs
  7. 48
      src/install.rs
  8. 80
      src/main.rs
  9. 52
      src/opts.rs
  10. 63
      src/utils.rs

444
Cargo.lock generated

@ -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"

@ -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"

@ -0,0 +1,73 @@
use crate::{
context::Context,
utils::{get_tree_files, remove_dir_if_empty},
};
pub fn apply(context: &Context, filter: &Option<String>, 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(())
}

@ -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())?;
}
}

@ -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,

@ -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)?;
}

@ -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(())
}

@ -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(())
}

@ -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 <rasmus.rosengren@protonmail.com>",
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<String>,
#[clap(long, value_name = "SHELL", help = "Generate shell completions")]
pub generate: Option<Shell>,
#[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,
},
}

@ -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<HashSet<PathBuf>> {
get_tree_files_recursively(config, tree_root, PathBuf::new()).await
pub fn get_tree_files(context: &Context, tree_root: &Path) -> anyhow::Result<HashSet<PathBuf>> {
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<HashSet<PathBuf>> {
let current_path = tree_root.join(&relative_path);
let mut dir_walker = read_dir(&current_path).await?;
let mut dir_tasks = vec![];
let mut dir_walker = std::fs::read_dir(&current_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()
pub fn command_exists(command: &str) -> bool {
std::process::Command::new("which")
.arg(&command)
.status()
.is_ok()
}
Loading…
Cancel
Save