From 99a6ee6ea280daa03447ef8fd1f51a94e0c1648a Mon Sep 17 00:00:00 2001 From: david Date: Wed, 15 May 2024 11:29:15 +0200 Subject: [PATCH 1/2] Removing IDE files and adding them to .gitignore --- .gitignore | 2 ++ warp.iml | 25 ------------------------- 2 files changed, 2 insertions(+), 25 deletions(-) delete mode 100644 warp.iml diff --git a/.gitignore b/.gitignore index 74e1037..6e44d69 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ Cargo.lock # Intellij .idea/ +/*.iml +/.project diff --git a/warp.iml b/warp.iml deleted file mode 100644 index 4d0de19..0000000 --- a/warp.iml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file -- 2.45.2 From d9aeb582a22f6eb62642e3b2693a50c299fc78f7 Mon Sep 17 00:00:00 2001 From: Reisz Date: Sat, 11 Dec 2021 13:20:14 +0100 Subject: [PATCH 2/2] Upgrade to Rust 2021 - Fix lints - Formatting pass - Add Cargo.lock Use anyhow to improve error handling Fix errors during directory removal in Windows Update dependencies Switch linux build to musl Switch to musl Set version to 0.4.0 Allow using uid instead of mtime Remove name duplication with runner map Fixing typo --- .gitignore | 4 - Cargo.lock | 741 +++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- Makefile | 8 +- warp-args/Cargo.toml | 10 + warp-args/src/lib.rs | 22 ++ warp-packer/Cargo.toml | 14 +- warp-packer/src/cli.rs | 47 +++ warp-packer/src/main.rs | 202 ++++------ warp-runner/Cargo.toml | 16 +- warp-runner/src/executor.rs | 167 ++++---- warp-runner/src/extractor.rs | 219 ++++++----- warp-runner/src/main.rs | 161 +++++--- 13 files changed, 1226 insertions(+), 387 deletions(-) create mode 100644 Cargo.lock create mode 100644 warp-args/Cargo.toml create mode 100644 warp-args/src/lib.rs create mode 100644 warp-packer/src/cli.rs 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)?); } -- 2.45.2