diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05a2129..d1d9df3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,6 +102,52 @@ jobs: throw 'error on rg.exe' } + - if: matrix.os == 'windows-latest' + name: "Integration test: [windows] [sync-self]" + env: + SYNC_DIR: "sync-self" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mkdir $env:SYNC_DIR + + $tool = -join($env:SYNC_DIR, '\tool.exe') + + copy "target\debug\tool.exe" $tool + + $output = &$tool --config="tests\$env:SYNC_DIR.toml" sync + + ls -l $env:SYNC_DIR + + if ($output -notmatch '1 tool') { + throw 'error on tool.exe' + } + + $err_output = &$tool --config="tests\$env:SYNC_DIR.toml" sync + + if ($output -notmatch '0 tools') { + throw 'error on tool.exe' + } + + - if: matrix.os != 'windows-latest' + name: "Integration test: [unix] [sync-self]" + env: + SYNC_DIR: "sync-self" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mkdir $SYNC_DIR + + cp "target/debug/tool" "$SYNC_DIR/tool" + + "$SYNC_DIR/tool" --config="tests/$SYNC_DIR.toml" sync > /dev/null 2> out + cat out + if ! grep -q '1 tool!' out; then echo "error on: tool"; false; fi + + ls -l $SYNC_DIR + + "$SYNC_DIR/tool" --config="tests/$SYNC_DIR.toml" sync > /dev/null 2> out + cat out + if ! grep -q 'tools!' out; then echo "error on: tool"; false; fi + - if: matrix.os != 'windows-latest' name: "Integration test: [unix] [sync-full]" env: diff --git a/Cargo.lock b/Cargo.lock index 90778f0..7f25aa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ 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", ] @@ -165,6 +165,36 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "filetime" version = "0.2.17" @@ -173,8 +203,8 @@ checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys", + "redox_syscall 0.2.16", + "windows-sys 0.36.1", ] [[package]] @@ -229,6 +259,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "idna" version = "0.2.3" @@ -251,6 +287,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itoa" version = "1.0.3" @@ -274,9 +330,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.134" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" @@ -414,6 +476,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -421,7 +492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -449,6 +520,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.20.6" @@ -477,6 +562,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "self-replace" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6028b2dc5d3d76987b552192e082f690dd854697d7fc46162fe31172a2e98a" +dependencies = [ + "fastrand", + "tempfile", + "windows-sys 0.48.0", +] + [[package]] name = "serde" version = "1.0.143" @@ -561,6 +657,19 @@ dependencies = [ "remove_dir_all", ] +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -634,6 +743,7 @@ dependencies = [ "dirs", "flate2", "indicatif", + "self-replace", "serde", "shellexpand", "tar", @@ -839,43 +949,175 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "xattr" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index ecc3be1..19b66df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ dirs = "4.0.0" flate2 = "1.0" indicatif = "0.17.1" shellexpand = "2.1.2" +self-replace = "1.3.3" tar = "0.4.38" tempdir = "0.3.7" toml = "0.5.9" diff --git a/src/config/schema.rs b/src/config/schema.rs index 0825c07..6c412cd 100644 --- a/src/config/schema.rs +++ b/src/config/schema.rs @@ -1,5 +1,6 @@ use shellexpand; use std::collections::BTreeMap; +use std::env; use std::path::PathBuf; use crate::err; @@ -70,11 +71,18 @@ impl Config { pub fn ensure_store_directory(&self) -> PathBuf { let expanded_store_directory = shellexpand::full(&self.store_directory); - let store_directory = match expanded_store_directory { + let mut store_directory = match expanded_store_directory { Err(e) => err::abort_with(e), Ok(cow_path) => PathBuf::from(cow_path.into_owned()), }; + if store_directory.is_relative() { + store_directory = env::current_dir() + .expect("unable to current executable directory") + .join(store_directory) + .to_path_buf(); + } + let has_store_directory = store_directory.as_path().is_dir(); if !has_store_directory { diff --git a/src/sync/install.rs b/src/sync/install.rs index cf15f45..3fa8ab6 100644 --- a/src/sync/install.rs +++ b/src/sync/install.rs @@ -1,4 +1,6 @@ use indicatif::ProgressBar; +use self_replace; +use std::env; use std::error::Error; use std::fs; use std::path::{Path, PathBuf}; @@ -17,6 +19,7 @@ use super::progress::SyncProgress; pub struct Installer<'a> { store_directory: &'a Path, + self_exe: PathBuf, tmp_dir: TempDir, sync_progress: SyncProgress, } @@ -32,6 +35,7 @@ impl<'a> Installer<'a> { } Ok(tmp_dir) => Installer { store_directory, + self_exe: env::current_exe().expect("unable to get current executable path"), tmp_dir, sync_progress, }, @@ -87,7 +91,13 @@ impl<'a> Installer<'a> { Err(unpack_err.to_string().into()) } Ok(tool_path) => { - copy_file(tool_path, self.store_directory, &tool_asset.exe_name)?; + copy_file( + tool_path, + self.store_directory, + &tool_asset.exe_name, + &self.self_exe, + )?; + Ok(()) } }, @@ -95,17 +105,29 @@ impl<'a> Installer<'a> { } } -fn copy_file(tool_path: PathBuf, store_directory: &Path, exe_name: &str) -> std::io::Result<()> { +fn copy_file( + tool_path: PathBuf, + store_directory: &Path, + exe_name: &str, + self_path: &Path, +) -> std::io::Result<()> { let exe_name = mk_exe_name(exe_name); let mut install_path = PathBuf::new(); install_path.push(store_directory); install_path.push(exe_name); - // Copy file from the downloaded unpacked archive to 'store_directory' - fs::copy(tool_path, &install_path)?; + if self_path == &install_path { + // May have issues with a symbolic links. The assumption is that + // the store directory is in the PATH and the executable itself + // where this issue should not apply but may be an edge case. + self_replace::self_replace(tool_path)?; + } else { + // Copy file from the downloaded unpacked archive to 'store_directory' + fs::copy(tool_path, &install_path)?; - set_executable_permissions(&install_path); + set_executable_permissions(&install_path); + } Ok(()) } diff --git a/tests/sync-self.toml b/tests/sync-self.toml new file mode 100644 index 0000000..edea670 --- /dev/null +++ b/tests/sync-self.toml @@ -0,0 +1,4 @@ +store_directory = "sync-self" + +[tool-sync] +tag = "v0.2.0"