diff --git a/.gitignore b/.gitignore index 6e44d69..a7f3cda 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,6 @@ # will have compiled files and executables /target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..9617551 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,741 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" + +[[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 = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e67816e006b17427c9b4386915109b494fec2d929c63e3bd3561234cbf1bf1e" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "crc32fast" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[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-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[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 = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "os_str_bytes" +version = "6.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[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 = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "remove_dir_all" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882f368737489ea543bc5c340e6f3d34a28c39980bd9a979e47322b26f60ac40" +dependencies = [ + "libc", + "log", + "num_cpus", + "rayon", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simple_logger" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e190a521c2044948158666916d9e872cbb9984f755e9bb3b5b75a836205affcd" +dependencies = [ + "atty", + "colored", + "log", + "time", + "windows-sys", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tar" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand", + "remove_dir_all 0.5.3", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "uuid" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83" +dependencies = [ + "getrandom", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "warp-args" +version = "0.1.0" +dependencies = [ + "bincode", + "serde", +] + +[[package]] +name = "warp-packer" +version = "0.4.0" +dependencies = [ + "bincode", + "clap", + "flate2", + "lazy_static", + "tar", + "tempdir", + "uuid", + "warp-args", +] + +[[package]] +name = "warp-runner" +version = "0.4.0" +dependencies = [ + "anyhow", + "bincode", + "dirs", + "flate2", + "log", + "memmem", + "remove_dir_all 0.7.0", + "simple_logger", + "tar", + "warp-args", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[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 = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] diff --git a/Cargo.toml b/Cargo.toml index 85fe686..217bdb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["warp-runner", "warp-packer"] +members = ["warp-args", "warp-runner", "warp-packer"] diff --git a/Makefile b/Makefile index 088f0f1..2e2636d 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ all: $(MAKE) build build: - cargo build -p warp-runner --release --target x86_64-unknown-linux-gnu - strip target/x86_64-unknown-linux-gnu/release/warp-runner + cargo build -p warp-runner --release --target x86_64-unknown-linux-musl + strip target/x86_64-unknown-linux-musl/release/warp-runner CC=x86_64-apple-darwin15-clang cargo build -p warp-runner --release --target x86_64-apple-darwin x86_64-apple-darwin15-strip target/x86_64-apple-darwin/release/warp-runner @@ -11,8 +11,8 @@ build: cargo build -p warp-runner --release --target x86_64-pc-windows-gnu strip target/x86_64-pc-windows-gnu/release/warp-runner.exe - cargo build -p warp-packer --release --target x86_64-unknown-linux-gnu - strip target/x86_64-unknown-linux-gnu/release/warp-packer + cargo build -p warp-packer --release --target x86_64-unknown-linux-musl + strip target/x86_64-unknown-linux-musl/release/warp-packer CC=x86_64-apple-darwin15-clang cargo build -p warp-packer --release --target x86_64-apple-darwin x86_64-apple-darwin15-strip target/x86_64-apple-darwin/release/warp-packer diff --git a/warp-args/Cargo.toml b/warp-args/Cargo.toml new file mode 100644 index 0000000..36646bd --- /dev/null +++ b/warp-args/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "warp-args" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bincode = "1.3" +serde = { version = "1.0", features = ["derive"] } diff --git a/warp-args/src/lib.rs b/warp-args/src/lib.rs new file mode 100644 index 0000000..e81a638 --- /dev/null +++ b/warp-args/src/lib.rs @@ -0,0 +1,22 @@ +use std::path::PathBuf; + +use bincode::Options; +use serde::{Deserialize, Serialize}; + +pub const WARP_ARGS_MAGIC: &[u8] = b"DR1PWsJsM6KxNbng9Y38"; + +#[derive(Serialize, Deserialize, Debug)] +pub struct Args { + pub target_file_name: PathBuf, + pub prefix: Option, + pub uid: Option, + pub clean: bool, +} + +pub fn bincode_options() -> impl bincode::Options { + bincode::DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + // Make sure bincode does not trust all size prefixes while scanning the binary + .with_limit(1_000_000) +} diff --git a/warp-packer/Cargo.toml b/warp-packer/Cargo.toml index c592916..b2ed9bb 100644 --- a/warp-packer/Cargo.toml +++ b/warp-packer/Cargo.toml @@ -1,13 +1,15 @@ [package] name = "warp-packer" -version = "0.3.0" +version = "0.4.0" authors = ["Diego Giagio "] +edition = "2021" [dependencies] -clap = "2.32.0" -dirs = "1.0.4" -reqwest = "0.9.2" -tempdir = "0.3.7" +bincode = "1.3" +clap = { version = "4.0", features = ["derive"] } flate2 = "1.0" +lazy_static = "1.1.0" tar = "0.4" -lazy_static = "1.1.0" \ No newline at end of file +tempdir = "0.3.7" +uuid = { version = "1.2", features = ["v4"] } +warp-args = { path = "../warp-args" } diff --git a/warp-packer/src/cli.rs b/warp-packer/src/cli.rs new file mode 100644 index 0000000..2c2226a --- /dev/null +++ b/warp-packer/src/cli.rs @@ -0,0 +1,47 @@ +use std::path::PathBuf; + +use clap::{Args, Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(author, version, about)] +pub struct Cli { + #[command(subcommand)] + pub command: Command, +} + +#[derive(Subcommand, Debug)] +pub enum Command { + Pack(PackArgs), + List, +} + +#[derive(Args, Debug)] +pub struct PackArgs { + /// Sets the architecture. Use list subcommand to get possible options. + #[arg(short, long)] + pub arch: String, + + /// Sets the input directory containing the application and dependencies + #[arg(short, long)] + pub input_dir: PathBuf, + + /// Sets the application executable file name + #[arg(short, long)] + pub exec: PathBuf, + + /// Sets the resulting self-contained application file name + #[arg(short, long)] + pub output: PathBuf, + + /// Generate unique id for each package build + #[arg(short = 'q', long, default_value_t = false)] + pub unique_id: bool, + + /// Prefix to use instead of single-file executable name + #[arg(short, long)] + pub prefix: Option, + + /// When using unique-id, do not look for and clean obsolete versions with the same prefix from cache + #[arg(short = 'n', long = "no-clean", action = clap::ArgAction::SetFalse)] + pub clean: bool, +} diff --git a/warp-packer/src/main.rs b/warp-packer/src/main.rs index 616ae45..f71cc83 100644 --- a/warp-packer/src/main.rs +++ b/warp-packer/src/main.rs @@ -1,42 +1,37 @@ -extern crate clap; -extern crate dirs; -extern crate flate2; -#[macro_use] -extern crate lazy_static; -extern crate reqwest; -extern crate tar; -extern crate tempdir; +mod cli; -use clap::{App, AppSettings, Arg}; -use flate2::Compression; +use bincode::Options; +use clap::Parser; use flate2::write::GzEncoder; -use std::collections::HashMap; +use flate2::Compression; +use lazy_static::lazy_static; use std::error::Error; use std::fs; use std::fs::File; -use std::io; -use std::io::copy; -use std::io::Write; +use std::io::{self, Write}; use std::path::Path; use std::process; -use tempdir::TempDir; +use std::{collections::HashMap, io::BufWriter}; +use uuid::Uuid; +use warp_args::{bincode_options, Args, WARP_ARGS_MAGIC}; -const APP_NAME: &str = env!("CARGO_PKG_NAME"); -const AUTHOR: &str = env!("CARGO_PKG_AUTHORS"); -const VERSION: &str = env!("CARGO_PKG_VERSION"); - -const RUNNER_MAGIC: &[u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; - -const RUNNER_LINUX_X64: &[u8] = include_bytes!("../../target/x86_64-unknown-linux-gnu/release/warp-runner"); -const RUNNER_MACOS_X64: &[u8] = include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner"); -const RUNNER_WINDOWS_X64: &[u8] = include_bytes!("../../target/x86_64-pc-windows-gnu/release/warp-runner.exe"); +use crate::cli::Command; lazy_static! { static ref RUNNER_BY_ARCH: HashMap<&'static str, &'static [u8]> = { let mut m = HashMap::new(); - m.insert("linux-x64", RUNNER_LINUX_X64); - m.insert("macos-x64", RUNNER_MACOS_X64); - m.insert("windows-x64", RUNNER_WINDOWS_X64); + m.insert( + "linux-x64", + include_bytes!("../../target/x86_64-unknown-linux-musl/release/warp-runner").as_slice(), + ); + m.insert( + "macos-x64", + include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner").as_slice(), + ); + m.insert( + "windows-x64", + include_bytes!("../../target/x86_64-pc-windows-gnu/release/warp-runner.exe").as_slice(), + ); m }; } @@ -50,43 +45,16 @@ macro_rules! bail { }) } -fn patch_runner(arch: &str, exec_name: &str) -> io::Result> { - // Read runner executable in memory - let runner_contents = RUNNER_BY_ARCH.get(arch).unwrap(); - let mut buf = runner_contents.to_vec(); - - // Set the correct target executable name into the local magic buffer - let magic_len = RUNNER_MAGIC.len(); - let mut new_magic = vec![0; magic_len]; - new_magic[..exec_name.len()].clone_from_slice(exec_name.as_bytes()); - - // Find the magic buffer offset inside the runner executable - let mut offs_opt = None; - for (i, chunk) in buf.windows(magic_len).enumerate() { - if chunk == RUNNER_MAGIC { - offs_opt = Some(i); - break; - } - } - - if offs_opt.is_none() { - return Err(io::Error::new(io::ErrorKind::Other, "no magic found inside runner")); - } - - // Replace the magic with the new one that points to the target executable - let offs = offs_opt.unwrap(); - buf[offs..offs + magic_len].clone_from_slice(&new_magic); - - Ok(buf) -} - -fn create_tgz(dir: &Path, out: &Path) -> io::Result<()> { - let f = fs::File::create(out)?; +fn append_tgz(f: &mut impl io::Write, dir: &Path) -> io::Result<()> { let gz = GzEncoder::new(f, Compression::best()); let mut tar = tar::Builder::new(gz); tar.follow_symlinks(false); - tar.append_dir_all(".", dir)?; - Ok(()) + tar.append_dir_all(".", dir) +} + +fn append_args(f: &mut impl io::Write, args: &Args) { + f.write_all(WARP_ARGS_MAGIC).unwrap(); + bincode_options().serialize_into(f, args).unwrap(); } #[cfg(target_family = "unix")] @@ -102,76 +70,38 @@ fn create_app_file(out: &Path) -> io::Result { #[cfg(target_family = "windows")] fn create_app_file(out: &Path) -> io::Result { - fs::OpenOptions::new() - .create(true) - .write(true) - .open(out) + fs::OpenOptions::new().create(true).write(true).open(out) } -fn create_app(runner_buf: &Vec, tgz_path: &Path, out: &Path) -> io::Result<()> { - let mut outf = create_app_file(out)?; - let mut tgzf = fs::File::open(tgz_path)?; - outf.write_all(runner_buf)?; - copy(&mut tgzf, &mut outf)?; - Ok(()) -} +fn main() -> Result<(), Box> { + let args = cli::Cli::parse(); -fn main() -> Result<(), Box> { - let args = App::new(APP_NAME) - .settings(&[AppSettings::ArgRequiredElseHelp, AppSettings::ColoredHelp]) - .version(VERSION) - .author(AUTHOR) - .about("Create self-contained single binary application") - .arg(Arg::with_name("arch") - .short("a") - .long("arch") - .value_name("arch") - .help(&format!("Sets the architecture. Supported: {:?}", RUNNER_BY_ARCH.keys())) - .display_order(1) - .takes_value(true) - .required(true)) - .arg(Arg::with_name("input_dir") - .short("i") - .long("input_dir") - .value_name("input_dir") - .help("Sets the input directory containing the application and dependencies") - .display_order(2) - .takes_value(true) - .required(true)) - .arg(Arg::with_name("exec") - .short("e") - .long("exec") - .value_name("exec") - .help("Sets the application executable file name") - .display_order(3) - .takes_value(true) - .required(true)) - .arg(Arg::with_name("output") - .short("o") - .long("output") - .value_name("output") - .help("Sets the resulting self-contained application file name") - .display_order(4) - .takes_value(true) - .required(true)) - .get_matches(); + let args = match args.command { + Command::List => { + for arch in RUNNER_BY_ARCH.keys() { + println!("{arch}"); + } + return Ok(()); + } + Command::Pack(args) => args, + }; - let arch = args.value_of("arch").unwrap(); - if !RUNNER_BY_ARCH.contains_key(&arch) { - bail!("Unknown architecture specified: {}, supported: {:?}", arch, RUNNER_BY_ARCH.keys()); + if !RUNNER_BY_ARCH.contains_key(&args.arch.as_str()) { + bail!( + "Unknown architecture specified: {}, supported: {:?}", + args.arch, + RUNNER_BY_ARCH.keys() + ); } - let input_dir = Path::new(args.value_of("input_dir").unwrap()); - if fs::metadata(input_dir).is_err() { - bail!("Cannot access specified input directory {:?}", input_dir); + if fs::metadata(&args.input_dir).is_err() { + bail!( + "Cannot access specified input directory {:?}", + args.input_dir + ); } - let exec_name = args.value_of("exec").unwrap(); - if exec_name.len() >= RUNNER_MAGIC.len() { - bail!("Executable name is too long, please consider using a shorter name"); - } - - let exec_path = Path::new(input_dir).join(exec_name); + let exec_path = args.input_dir.join(&args.exec); match fs::metadata(&exec_path) { Err(_) => { bail!("Cannot find file {:?}", exec_path); @@ -183,16 +113,24 @@ fn main() -> Result<(), Box> { } } - let runner_buf = patch_runner(&arch, &exec_name)?; + println!( + "Creating self-contained application binary {:?}...", + args.exec + ); + let mut output = BufWriter::new(create_app_file(&args.output).unwrap()); + output.write_all(RUNNER_BY_ARCH.get(&args.arch.as_str()).unwrap())?; + append_args( + &mut output, + &Args { + target_file_name: args.exec, + prefix: args.prefix, + uid: args.unique_id.then(|| format!("{}", Uuid::new_v4())), + clean: args.clean, + }, + ); - println!("Compressing input directory {:?}...", input_dir); - let tmp_dir = TempDir::new(APP_NAME)?; - let tgz_path = tmp_dir.path().join("input.tgz"); - create_tgz(&input_dir, &tgz_path)?; - - let exec_name = Path::new(args.value_of("output").unwrap()); - println!("Creating self-contained application binary {:?}...", exec_name); - create_app(&runner_buf, &tgz_path, &exec_name)?; + println!("Compressing input directory {:?}...", args.input_dir); + append_tgz(&mut output, &args.input_dir).unwrap(); println!("All done"); Ok(()) diff --git a/warp-runner/Cargo.toml b/warp-runner/Cargo.toml index c0afab2..6ffb2f3 100644 --- a/warp-runner/Cargo.toml +++ b/warp-runner/Cargo.toml @@ -1,13 +1,17 @@ [package] name = "warp-runner" -version = "0.3.0" +version = "0.4.0" authors = ["Diego Giagio "] +edition = "2021" [dependencies] -memmem = "0.1.1" +anyhow = "1.0" +bincode = "1.3" +dirs = "4.0" flate2 = "1.0" -tar = "0.4" -dirs = "1.0.4" -winapi = "0.3.6" log = "0.4.5" -simple_logger = "1.0.1" +memmem = "0.1.1" +remove_dir_all = "0.7" +simple_logger = "4.0" +tar = "0.4" +warp-args = { path = "../warp-args" } diff --git a/warp-runner/src/executor.rs b/warp-runner/src/executor.rs index 435f465..55cfe40 100644 --- a/warp-runner/src/executor.rs +++ b/warp-runner/src/executor.rs @@ -1,80 +1,87 @@ -use std::env; -use std::io; -#[cfg(target_family = "unix")] -use std::fs; -#[cfg(target_family = "unix")] -use std::fs::Permissions; -#[cfg(target_family = "unix")] -use std::os::unix::fs::PermissionsExt; -use std::path::Path; -use std::process::Command; -use std::process::Stdio; - -pub fn execute(target: &Path) -> io::Result { - trace!("target={:?}", target); - - let args: Vec = env::args().skip(1).collect(); - trace!("args={:?}", args); - - do_execute(target, &args) -} - -#[cfg(target_family = "unix")] -fn ensure_executable(target: &Path) { - let perms = Permissions::from_mode(0o770); - fs::set_permissions(target, perms).unwrap(); -} - -#[cfg(target_family = "unix")] -fn do_execute(target: &Path, args: &[String]) -> io::Result { - ensure_executable(target); - - Ok(Command::new(target) - .args(args) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .spawn()? - .wait()? - .code().unwrap_or(1)) -} - -#[cfg(target_family = "windows")] -fn is_script(target: &Path) -> bool { - const SCRIPT_EXTENSIONS: &[&str] = &["bat", "cmd"]; - SCRIPT_EXTENSIONS.contains( - &target.extension() - .unwrap_or_default() - .to_string_lossy() - .to_lowercase().as_str()) -} - -#[cfg(target_family = "windows")] -fn do_execute(target: &Path, args: &[String]) -> io::Result { - let target_str = target.as_os_str().to_str().unwrap(); - - if is_script(target) { - let mut cmd_args = Vec::with_capacity(args.len() + 2); - cmd_args.push("/c".to_string()); - cmd_args.push(target_str.to_string()); - cmd_args.extend_from_slice(&args); - - Ok(Command::new("cmd") - .args(cmd_args) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .spawn()? - .wait()? - .code().unwrap_or(1)) - } else { - Ok(Command::new(target) - .args(args) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .spawn()? - .wait()? - .code().unwrap_or(1)) - } -} \ No newline at end of file +use log::trace; +use std::env; +#[cfg(target_family = "unix")] +use std::fs; +#[cfg(target_family = "unix")] +use std::fs::Permissions; +use std::io; +#[cfg(target_family = "unix")] +use std::os::unix::fs::PermissionsExt; +use std::path::Path; +use std::process::Command; +use std::process::Stdio; + +pub fn execute(target: &Path) -> io::Result { + trace!("target={:?}", target); + + let args: Vec = env::args().skip(1).collect(); + trace!("args={:?}", args); + + do_execute(target, &args) +} + +#[cfg(target_family = "unix")] +fn ensure_executable(target: &Path) { + let perms = Permissions::from_mode(0o770); + fs::set_permissions(target, perms).unwrap(); +} + +#[cfg(target_family = "unix")] +fn do_execute(target: &Path, args: &[String]) -> io::Result { + ensure_executable(target); + + Ok(Command::new(target) + .args(args) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn()? + .wait()? + .code() + .unwrap_or(1)) +} + +#[cfg(target_family = "windows")] +fn is_script(target: &Path) -> bool { + const SCRIPT_EXTENSIONS: &[&str] = &["bat", "cmd"]; + SCRIPT_EXTENSIONS.contains( + &target + .extension() + .unwrap_or_default() + .to_string_lossy() + .to_lowercase() + .as_str(), + ) +} + +#[cfg(target_family = "windows")] +fn do_execute(target: &Path, args: &[String]) -> io::Result { + let target_str = target.as_os_str().to_str().unwrap(); + + if is_script(target) { + let mut cmd_args = Vec::with_capacity(args.len() + 2); + cmd_args.push("/c".to_string()); + cmd_args.push(target_str.to_string()); + cmd_args.extend_from_slice(&args); + + Ok(Command::new("cmd") + .args(cmd_args) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn()? + .wait()? + .code() + .unwrap_or(1)) + } else { + Ok(Command::new(target) + .args(args) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn()? + .wait()? + .code() + .unwrap_or(1)) + } +} diff --git a/warp-runner/src/extractor.rs b/warp-runner/src/extractor.rs index 6a71f76..cbaa653 100644 --- a/warp-runner/src/extractor.rs +++ b/warp-runner/src/extractor.rs @@ -1,99 +1,120 @@ -extern crate flate2; -extern crate memmem; -extern crate tar; - -use self::flate2::read::GzDecoder; -use self::memmem::{Searcher, TwoWaySearcher}; -use self::tar::Archive; -use std::fs::File; -use std::io; -use std::io::{BufReader, Read, Seek, SeekFrom}; -use std::path::Path; - -struct FileSearcher<'a> { - buf_reader: BufReader, - searcher: TwoWaySearcher<'a>, - offs: usize, -} - -impl<'a> FileSearcher<'a> { - fn new(path: &'a Path, magic: &'a [u8]) -> io::Result> { - let file = File::open(path)?; - Ok(FileSearcher { - buf_reader: BufReader::new(file), - searcher: TwoWaySearcher::new(magic), - offs: 0, - }) - } -} - -impl<'a> Iterator for FileSearcher<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - let mut buf = [0; 32 * 1024]; - let ret; - - match self.buf_reader.seek(SeekFrom::Start(self.offs as u64)) { - Ok(_) => {} - Err(e) => return Some(Err(e)) - } - - loop { - match self.buf_reader.read(&mut buf[..]) { - Ok(0) => { - ret = None; - break; - } - Ok(n) => { - match self.searcher.search_in(&buf) { - Some(pos) => { - self.offs += pos; - ret = Some(Ok(self.offs)); - self.offs += 1; // one past the match so we can try again if necessary - break; - } - None => self.offs += n - } - } - Err(e) => { - ret = Some(Err(e)); - break; - } - } - } - ret - } -} - -const GZIP_MAGIC: &[u8] = b"\x1f\x8b\x08"; - -pub fn extract_to(src: &Path, dst: &Path) -> io::Result<()> { - let mut found = false; - - let searcher = FileSearcher::new(src, GZIP_MAGIC)?; - for result in searcher { - let offs = result?; - if extract_at_offset(src, offs, dst).is_ok() { - trace!("tarball found at offset {} was extracted successfully", offs); - found = true; - break; - } - } - - if found { - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::Other, "no tarball found inside binary")) - } -} - -fn extract_at_offset(src: &Path, offs: usize, dst: &Path) -> io::Result<()> { - let mut f = File::open(src)?; - f.seek(SeekFrom::Start(offs as u64))?; - - let gz = GzDecoder::new(f); - let mut tar = Archive::new(gz); - tar.unpack(dst)?; - Ok(()) -} +use anyhow::{anyhow, Context, Result}; +use bincode::Options; +use flate2::read::GzDecoder; +use log::trace; +use memmem::{Searcher, TwoWaySearcher}; +use std::fs::File; +use std::io; +use std::io::{BufReader, Read, Seek, SeekFrom}; +use std::path::Path; +use tar::Archive; +use warp_args::{bincode_options, Args, WARP_ARGS_MAGIC}; + +struct FileSearcher<'a> { + buf_reader: BufReader, + searcher: TwoWaySearcher<'a>, + offs: usize, +} + +impl<'a> FileSearcher<'a> { + fn new(path: &'a Path, magic: &'a [u8]) -> io::Result> { + let file = File::open(path)?; + Ok(FileSearcher { + buf_reader: BufReader::new(file), + searcher: TwoWaySearcher::new(magic), + offs: 0, + }) + } +} + +impl<'a> Iterator for FileSearcher<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + let mut buf = [0; 32 * 1024]; + let ret; + + match self.buf_reader.seek(SeekFrom::Start(self.offs as u64)) { + Ok(_) => {} + Err(e) => return Some(Err(e)), + } + + loop { + match self.buf_reader.read(&mut buf[..]) { + Ok(0) => { + ret = None; + break; + } + Ok(n) => { + match self.searcher.search_in(&buf) { + Some(pos) => { + self.offs += pos; + ret = Some(Ok(self.offs)); + self.offs += 1; // one past the match so we can try again if necessary + break; + } + None => self.offs += n, + } + } + Err(e) => { + ret = Some(Err(e)); + break; + } + } + } + ret + } +} + +const GZIP_MAGIC: &[u8] = b"\x1f\x8b\x08"; + +pub fn extract_to(src: &Path, dst: &Path) -> Result<()> { + FileSearcher::new(src, GZIP_MAGIC) + .context("failed searching own binary")? + .map(Result::unwrap) + .find(|offs| extract_at_offset(src, *offs, dst).unwrap()) + .ok_or_else(|| anyhow!("No tarball found inside binary file {}", src.display())) + .map(|offs| { + trace!( + "tarball found at offset {} was extracted successfully", + offs + ); + }) +} + +fn extract_at_offset(src: &Path, offs: usize, dst: &Path) -> Result { + let mut f = File::open(src) + .with_context(|| format!("Failed to open file to extract from: {}", src.display()))?; + f.seek(SeekFrom::Start(offs as u64)) + .with_context(|| format!("Failed to read file to extract from: {}", src.display()))?; + + let gz = GzDecoder::new(f); + let mut tar = Archive::new(gz); + Ok(tar.unpack(dst).is_ok()) +} + +pub fn get_args(src: &Path) -> Result { + FileSearcher::new(src, WARP_ARGS_MAGIC) + .context("failed searching own binary")? + .map(Result::unwrap) + .find_map(|offs| { + Some(( + offs, + extract_args_at_offset(src, offs + WARP_ARGS_MAGIC.len()).unwrap()?, + )) + }) + .ok_or_else(|| anyhow!("No arguments found inside binary file {}", src.display())) + .map(|(offs, args)| { + trace!("args found at offset {} was extracted successfully", offs); + args + }) +} + +fn extract_args_at_offset(src: &Path, offs: usize) -> Result> { + let mut f = File::open(src) + .with_context(|| format!("Failed to open file to extract from: {}", src.display()))?; + f.seek(SeekFrom::Start(offs as u64)) + .with_context(|| format!("Failed to read file to extract from: {}", src.display()))?; + + Ok(bincode_options().deserialize_from(f).ok()) +} diff --git a/warp-runner/src/main.rs b/warp-runner/src/main.rs index f711f4c..1795666 100644 --- a/warp-runner/src/main.rs +++ b/warp-runner/src/main.rs @@ -1,82 +1,133 @@ -extern crate dirs; -#[macro_use] -extern crate log; -extern crate simple_logger; - -use log::Level; +use anyhow::Context; +use anyhow::{anyhow, Result}; +use log::{trace, Level}; +use remove_dir_all::remove_dir_all; use std::env; -use std::error::Error; -use std::ffi::*; +use std::ffi::OsStr; use std::fs; -use std::io; -use std::path::*; +use std::path::{Path, PathBuf}; use std::process; +use warp_args::Args; + +use crate::extractor::get_args; -mod extractor; mod executor; +mod extractor; -static TARGET_FILE_NAME_BUF: &'static [u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; +static STATIC_SUBFOLDER_NAME: &str = "static"; -fn target_file_name() -> &'static str { - let nul_pos = TARGET_FILE_NAME_BUF.iter() - .position(|elem| *elem == b'\0') - .expect("TARGET_FILE_NAME_BUF has no NUL terminator"); - - let slice = &TARGET_FILE_NAME_BUF[..(nul_pos + 1)]; - CStr::from_bytes_with_nul(slice) - .expect("Can't convert TARGET_FILE_NAME_BUF slice to CStr") - .to_str() - .expect("Can't convert TARGET_FILE_NAME_BUF CStr to str") -} - -fn cache_path(target: &str) -> PathBuf { - dirs::data_local_dir() - .expect("No data local dir found") +fn cache_path(target: &str) -> Result { + Ok(dirs::data_local_dir() + .ok_or_else(|| anyhow!("No data local dir found"))? .join("warp") .join("packages") - .join(target) + .join(target)) } -fn extract(exe_path: &Path, cache_path: &Path) -> io::Result<()> { - fs::remove_dir_all(cache_path).ok(); - extractor::extract_to(&exe_path, &cache_path)?; +fn extract(exe_path: &Path, cache_path: &Path) -> Result<()> { + if cache_path.exists() { + remove_dir_all(cache_path) + .with_context(|| format!("Failed to remove directory {}", cache_path.display()))?; + } + extractor::extract_to(exe_path, cache_path).with_context(|| { + format!( + "Failed to extract {} to {}", + exe_path.display(), + cache_path.display() + ) + }) +} + +fn create_cache_folder(self_path: &Path, args: &Args) -> Result { + let prefix = args + .prefix + .as_deref() + .unwrap_or_else(|| Path::new(self_path.file_name().unwrap())); + let cache_path = cache_path(&prefix.to_string_lossy())?; + + trace!("self_path={:?}", self_path); + trace!("prefix={:?}", prefix); + trace!("cache_path={:?}", cache_path); + + if cache_path.exists() && !fs::metadata(&cache_path)?.is_dir() { + return Err(anyhow!("cache at {:?} is not a directory", &cache_path)); + } else { + fs::create_dir_all(&cache_path)?; + } + + Ok(cache_path) +} + +fn clean_cache(cache_folder: &Path, self_path: &Path, args: &Args) -> Result<()> { + if args.uid.is_none() { + let subfolder = cache_folder.join(STATIC_SUBFOLDER_NAME); + if subfolder.exists() + && fs::metadata(&subfolder)?.modified()? < fs::metadata(self_path)?.modified()? + { + trace!("static cache older than source, removing"); + remove_dir_all(subfolder)?; + } + + return Ok(()); + } + + if !args.clean { + return Ok(()); + } + + let uid = OsStr::new(args.uid.as_ref().unwrap()); // Checked above + let static_folder = OsStr::new(STATIC_SUBFOLDER_NAME); + + trace!("cleaning cache"); + for entry in fs::read_dir(cache_folder)? { + let entry = entry?; + + if entry.file_name() == static_folder { + trace!("skipped static subfolder {:?}", static_folder); + continue; + } + + if entry.file_name() == uid { + trace!("skipped own uid {:?}", uid); + continue; + } + + trace!("removing entry {:?}", entry); + if let Err(err) = remove_dir_all(entry.path()) { + eprintln!( + "Error while attempting to remove directory {:?}: {err}", + entry.path() + ); + } + } + Ok(()) } -fn main() -> Result<(), Box> { +fn main() -> Result<()> { if env::var("WARP_TRACE").is_ok() { simple_logger::init_with_level(Level::Trace)?; } let self_path = env::current_exe()?; - let self_file_name = self_path.file_name().unwrap(); - let cache_path = cache_path(&self_file_name.to_string_lossy()); + let args = get_args(&self_path).unwrap(); + trace!("args = {:?}", args); - trace!("self_path={:?}", self_path); - trace!("self_file_name={:?}", self_file_name); - trace!("cache_path={:?}", cache_path); + let cache_path = create_cache_folder(&self_path, &args)?; + clean_cache(&cache_path, &self_path, &args)?; - let target_file_name = target_file_name(); - let target_path = cache_path.join(target_file_name); + let subfolder = args.uid.as_deref().unwrap_or(STATIC_SUBFOLDER_NAME); + let cache_path = cache_path.join(subfolder); - trace!("target_exec={:?}", target_file_name); + let target_path = cache_path.join(&args.target_file_name); + + trace!("target_exec={:?}", args.target_file_name); trace!("target_path={:?}", target_path); - match fs::metadata(&cache_path) { - Ok(cache) => { - if cache.modified()? >= fs::metadata(&self_path)?.modified()? { - trace!("cache is up-to-date"); - } else { - trace!("cache is outdated"); - extract(&self_path, &cache_path)?; - } - } - Err(_) => { - trace!("cache not found"); - extract(&self_path, &cache_path)?; - } + if !cache_path.exists() { + trace!("cache empty, extracting"); + extract(&self_path, &cache_path)?; } - let exit_code = executor::execute(&target_path)?; - process::exit(exit_code); + process::exit(executor::execute(&target_path)?); }