diff --git a/external/rust-script/.gitignore b/external/rust-script/.gitignore new file mode 100644 index 0000000..cba3739 --- /dev/null +++ b/external/rust-script/.gitignore @@ -0,0 +1,5 @@ +target +/local +/.cargo +/.idea +/tests/scripts/*.actual* diff --git a/external/rust-script/CNAME b/external/rust-script/CNAME new file mode 100644 index 0000000..d01c780 --- /dev/null +++ b/external/rust-script/CNAME @@ -0,0 +1 @@ +rust-script.org \ No newline at end of file diff --git a/external/rust-script/Cargo.lock b/external/rust-script/Cargo.lock new file mode 100644 index 0000000..54c8fa8 --- /dev/null +++ b/external/rust-script/Cargo.lock @@ -0,0 +1,616 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "3.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +dependencies = [ + "atty", + "bitflags", + "clap_lex", + "indexmap", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a9b56eb56058f43dc66e58f40a214b2ccbc9f3df51861b63d51dec7b65bc3f" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "lazy_static" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" + +[[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.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "os_str_bytes" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" +dependencies = [ + "bitflags", + "getopts", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[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 = "rust-script" +version = "0.22.0" +dependencies = [ + "atty", + "clap", + "dirs-next", + "env_logger", + "lazy_static 1.4.0", + "log", + "pulldown-cmark", + "regex", + "rustversion", + "scan-rules", + "serde", + "serde_json", + "sha-1", + "tempfile", + "toml", + "winreg", +] + +[[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "scan-rules" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc8b462b0f8ce7deae199b4b5cecbbe01006f808408d815c09a9f7b11ee044ac" +dependencies = [ + "itertools", + "lazy_static 0.1.16", + "rustc_version", + "strcursor", +] + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "strcursor" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53cb721e1f6d0dbba1296e2d7770edbec9a4888fdd8f6a22fea97a0a69b465a" +dependencies = [ + "rustc_version", + "unicode-segmentation", +] + +[[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.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "unicode-segmentation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b905d0fc2a1f0befd86b0e72e31d1787944efef9d38b9358a9e92a69757f7e3b" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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 = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/external/rust-script/Cargo.toml b/external/rust-script/Cargo.toml new file mode 100644 index 0000000..6568065 --- /dev/null +++ b/external/rust-script/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "rust-script" +version = "0.22.0" +edition = "2018" +authors = ["Fredrik Fornwall "] +description = "Command-line tool to run Rust \"scripts\" which can make use of crates." +homepage = "https://rust-script.org" +documentation = "https://rust-script.org" +repository = "https://github.com/fornwall/rust-script" +readme = "README.md" +license = "MIT/Apache-2.0" +keywords = ["cargo", "script"] +categories = ["command-line-utilities", "development-tools"] + +exclude = [ + "_config.yml", + "CNAME", + ".github", + "target" +] + +[dependencies] +clap = "3.1.2" +dirs-next = "2" +env_logger = "0.9" +lazy_static = "1" +log = "0.4" +pulldown-cmark = "0.9" +regex = "1" +rustversion = "1.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sha-1 = "0.10" +tempfile = "3" +toml = "0.5" + +[target.'cfg(windows)'.dependencies] +winreg = "0.10" + +[target.'cfg(unix)'.dependencies] +atty = "0.2" + +[dev-dependencies] +scan-rules = "0.2" + +[profile.release] +lto = true diff --git a/external/rust-script/LICENSE-APACHE b/external/rust-script/LICENSE-APACHE new file mode 100644 index 0000000..c98d27d --- /dev/null +++ b/external/rust-script/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/external/rust-script/LICENSE-MIT b/external/rust-script/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/external/rust-script/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/external/rust-script/README.md b/external/rust-script/README.md new file mode 100644 index 0000000..c7466f2 --- /dev/null +++ b/external/rust-script/README.md @@ -0,0 +1,44 @@ + +[![CI](https://github.com/fornwall/rust-script/workflows/CI/badge.svg)](https://github.com/fornwall/rust-script/actions?query=workflow%3ACI) +[![Crates.io](https://img.shields.io/crates/v/rust-script.svg)](https://crates.io/crates/rust-script) + +# rust-script +Run Rust script files without any setup or explicit compilation step, with seamless use of crates specified as dependencies inside the scripts. + +```sh +$ cargo install rust-script +[...] + +$ cat script.rs +#!/usr/bin/env rust-script +//! Dependencies can be specified in the script file itself as follows: +//! +//! ```cargo +//! [dependencies] +//! rand = "0.8.0" +//! ``` + +use rand::prelude::*; + +fn main() { + let x: u64 = random(); + println!("A random number: {}", x); +} + +$ ./script.rs +A random number: 9240261453149857564 +``` + +Rust version 1.54 or newer required. + +See the [documentation at rust-script.org](https://rust-script.org). + +## Related projects +- [cargo-script](https://github.com/DanielKeep/cargo-script) - the unmaintained project that `rust-script` was forked from. +- [cargo-eval](https://github.com/reitermarkus/cargo-eval/) - maintained fork of `cargo-script`. +- [cargo-play](https://github.com/fanzeyi/cargo-play) - local Rust playground. +- [runner](https://github.com/stevedonovan/runner/) - tool for running Rust snippets. +- [scriptisto](https://github.com/igor-petruk/scriptisto) - language-agnostic "shebang interpreter" that enables you to write scripts in compiled languages. + +## License +`rust-script` is primarily distributed under the terms of both the [MIT license](LICENSE-MIT) and the [Apache License (Version 2.0)](LICENSE-APACHE). diff --git a/external/rust-script/_config.yml b/external/rust-script/_config.yml new file mode 100644 index 0000000..fc24e7a --- /dev/null +++ b/external/rust-script/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-hacker \ No newline at end of file diff --git a/external/rust-script/docs/CNAME b/external/rust-script/docs/CNAME new file mode 100644 index 0000000..d01c780 --- /dev/null +++ b/external/rust-script/docs/CNAME @@ -0,0 +1 @@ +rust-script.org \ No newline at end of file diff --git a/external/rust-script/docs/README.md b/external/rust-script/docs/README.md new file mode 100644 index 0000000..7f560f9 --- /dev/null +++ b/external/rust-script/docs/README.md @@ -0,0 +1,211 @@ + + +- [Overview](#overview) +- [Installation](#installation) + - [Distro Packages](#distro-packages) + - [Arch Linux](#arch-linux) +- [Scripts](#scripts) +- [Executable Scripts](#executable-scripts) +- [Expressions](#expressions) +- [Filters](#filters) +- [Environment Variables](#environment-variables) +- [Templates](#templates) +- [Troubleshooting](#troubleshooting) + +## Overview + +With `rust-script` Rust files and expressions can be executed just like a shell or Python script. Features include: + +- Caching compiled artifacts for speed. +- Reading Cargo manifests embedded in Rust scripts. +- Supporting executable Rust scripts via Unix shebangs and Windows file associations. +- Using expressions as stream filters (*i.e.* for use in command pipelines). +- Running unit tests and benchmarks from scripts. +- Custom templates for command-line expressions and filters. + +You can get an overview of the available options using the `--help` flag. + +## Installation + +Install or update `rust-script` using Cargo: + +```sh +cargo install rust-script +``` + +Rust 1.54 or later is required. + +### Distro Packages + +#### Arch Linux + +`rust-script` can be installed from the [community repository](https://archlinux.org/packages/community/x86_64/rust-script/): + +```sh +pacman -S rust-script +``` + +## Scripts + +The primary use for `rust-script` is for running Rust source files as scripts. For example: + +```sh +$ echo 'println!("Hello, World!");' > hello.rs +$ rust-script hello.rs +Hello, World! +``` + +Under the hood, a Cargo project will be generated and built (with the Cargo output hidden unless compilation fails or the `-o`/`--cargo-output` option is used). The first invocation of the script will be slower as the script is compiled - subsequent invocations of unmodified scripts will be fast as the built executable is cached. + +As seen from the above example, using a `fn main() {}` function is not required. If not present, the script file will be wrapped in a `fn main() { ... }` block. + +`rust-script` will look for embedded dependency and manifest information in the script as shown by the below two equivalent `now.rs` variants: + +```rust +#!/usr/bin/env rust-script +//! This is a regular crate doc comment, but it also contains a partial +//! Cargo manifest. Note the use of a *fenced* code block, and the +//! `cargo` "language". +//! +//! ```cargo +//! [dependencies] +//! time = "0.1.25" +//! ``` +fn main() { + println!("{}", time::now().rfc822z()); +} +``` + +```rust +// cargo-deps: time="0.1.25" +// You can also leave off the version number, in which case, it's assumed +// to be "*". Also, the `cargo-deps` comment *must* be a single-line +// comment, and it *must* be the first thing in the file, after the +// shebang. +// Multiple dependencies should be separated by commas: +// cargo-deps: time="0.1.25", libc="0.2.5" +fn main() { + println!("{}", time::now().rfc822z()); +} +``` + +The output from running one of the above scripts may look something like: + +```sh +$ rust-script now +Wed, 28 Oct 2020 00:38:45 +0100 +``` + +Useful command-line arguments: + +- `--bench`: Compile and run benchmarks. Requires a nightly toolchain. +- `--debug`: Build a debug executable, not an optimised one. +- `--features `: Cargo features to pass when building and running. +- `--force`: Force the script to be rebuilt. Useful if you want to force a recompile with a different toolchain. +- `--gen-pkg-only`: Generate the Cargo package, but don't compile or run it. Effectively "unpacks" the script into a Cargo package. +- `--test`: Compile and run tests. + +## Executable Scripts + +On Unix systems, you can use `#!/usr/bin/env rust-script` as a shebang line in a Rust script. This will allow you to execute a script files (which don't need to have the `.rs` file extension) directly. + +If you are using Windows, you can associate the `.ers` extension (executable Rust - a renamed `.rs` file) with `rust-script`. This allows you to execute Rust scripts simply by naming them like any other executable or script. + +This can be done using the `rust-script --install-file-association` command. Uninstall the file association with `rust-script --uninstall-file-association`. + +If you want to make a script usable across platforms, use *both* a shebang line *and* give the file a `.ers` file extension. + +## Expressions + +Using the `-e`/`--expr` option a Rust expression can be evaluated directly, with dependencies (if any) added using `-d`/`--dep`: + +```sh +$ rust-script -e '1+2' +3 +$ rust-script --dep time --expr "time::OffsetDateTime::now_utc().format(time::Format::Rfc3339).to_string()"` +"2020-10-28T11:42:10+00:00" +$ # Use a specific version of the time crate (instead of default latest): +$ rust-script --dep time=0.1.38 -e "time::now().rfc822z().to_string()" +"2020-10-28T11:42:10+00:00" +``` + +The code given is embedded into a block expression, evaluated, and printed out using the `Debug` formatter (*i.e.* `{:?}`). + +## Filters + +You can use `rust-script` to write a quick filter, by specifying a closure to be called for each line read from stdin, like so: + +```sh +$ cat now.ers | rust-script --loop \ + "let mut n=0; move |l| {n+=1; println!(\"{:>6}: {}\",n,l.trim_right())}" + 1: // cargo-deps: time="0.1.25" + 3: fn main() { + 4: println!("{}", time::now().rfc822z()); + 5: } +``` + +You can achieve a similar effect to the above by using the `--count` flag, which causes the line number to be passed as a second argument to your closure: + +```sh +$ cat now.ers | rust-script --count --loop \ + "|l,n| println!(\"{:>6}: {}\", n, l.trim_right())" + 1: // cargo-deps: time="0.1.25" + 2: fn main() { + 3: println!("{}", time::now().rfc822z()); + 4: } +``` + +Note that, like with expressions, you can specify a custom template for stream filters. + +## Environment Variables + +The following environment variables are provided to scripts by `rust-script`: + +- `RUST_SCRIPT_BASE_PATH`: the base path used by `rust-script` to resolve relative dependency paths. Note that this is *not* necessarily the same as either the working directory, or the directory in which the script is being compiled. + +- `RUST_SCRIPT_PKG_NAME`: the generated package name of the script. + +- `RUST_SCRIPT_SAFE_NAME`: the file name of the script (sans file extension) being run. For scripts, this is derived from the script's filename. May also be `"expr"` or `"loop"` for those invocations. + +- `RUST_SCRIPT_PATH`: absolute path to the script being run, assuming one exists. Set to the empty string for expressions. + +## Templates + +You can use templates to avoid having to re-specify common code and dependencies. You can find out the directory where templates are stored and view a list of your templates by running `rust-script --list-templates`. + +Templates are Rust source files with two placeholders: `#{prelude}` for the auto-generated prelude (which should be placed at the top of the template), and `#{script}` for the contents of the script itself. + +For example, a minimal expression template that adds a dependency and imports some additional symbols might be: + +```rust +// cargo-deps: itertools="0.6.2" +#![allow(unused_imports)] +#{prelude} +use std::io::prelude::*; +use std::mem; +use itertools::Itertools; + +fn main() { + let result = { + #{script} + }; + println!("{:?}", result); +} +``` + +If stored in the templates folder as `grabbag.rs`, you can use it by passing the name `grabbag` via the `--template` option, like so: + +```sh +$ rust-script -t grabbag -e "mem::size_of::>()" +16 +``` + +In addition, there are three built-in templates: `expr`, `loop`, and `loop-count`. These are used for the `--expr`, `--loop`, and `--loop --count` invocation forms. They can be overridden by placing templates with the same name in the template folder. + +## Troubleshooting + +Please report all issues on [the GitHub issue tracker](https://github.com/fornwall/rust-script/issues). + +If relevant, run with the `RUST_LOG=rust_script=trace` environment variable set to see verbose log output and attach that output to an issue. diff --git a/external/rust-script/docs/_config.yml b/external/rust-script/docs/_config.yml new file mode 100644 index 0000000..fc24e7a --- /dev/null +++ b/external/rust-script/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-hacker \ No newline at end of file diff --git a/external/rust-script/docs/favicon.ico b/external/rust-script/docs/favicon.ico new file mode 100644 index 0000000..3cab15b Binary files /dev/null and b/external/rust-script/docs/favicon.ico differ diff --git a/external/rust-script/examples/hello-without-main.ers b/external/rust-script/examples/hello-without-main.ers new file mode 100755 index 0000000..0082981 --- /dev/null +++ b/external/rust-script/examples/hello-without-main.ers @@ -0,0 +1,3 @@ +#!/usr/bin/env rust-script + +println!("hello, rust"); diff --git a/external/rust-script/examples/hello.ers b/external/rust-script/examples/hello.ers new file mode 100755 index 0000000..a1c7747 --- /dev/null +++ b/external/rust-script/examples/hello.ers @@ -0,0 +1,5 @@ +#!/usr/bin/env rust-script + +fn main() { + println!("hello, rust"); +} diff --git a/external/rust-script/examples/time-main.ers b/external/rust-script/examples/time-main.ers new file mode 100644 index 0000000..7c013b6 --- /dev/null +++ b/external/rust-script/examples/time-main.ers @@ -0,0 +1,12 @@ +#!/usr/bin/env rust-script +//! This is a regular crate doc comment, but it also contains a partial +//! Cargo manifest. Note the use of a *fenced* code block, and the +//! `cargo` "language". +//! +//! ```cargo +//! [dependencies] +//! time = "0.1.25" +//! ``` +fn main() { + println!("{}", time::now().rfc822z()); +} diff --git a/external/rust-script/examples/time-without-main.ers b/external/rust-script/examples/time-without-main.ers new file mode 100644 index 0000000..c3a8b03 --- /dev/null +++ b/external/rust-script/examples/time-without-main.ers @@ -0,0 +1,13 @@ +#!/usr/bin/env rust-script +/// This is a regular crate doc comment, but it also contains a partial +/// Cargo manifest. Note the use of a *fenced* code block, and the +/// `cargo` "language". +/// +/// ```cargo +/// [dependencies] +/// time = "0.1.25" +/// ``` + +use time::now; + +println!("{}", now().rfc822z()); diff --git a/external/rust-script/src/consts.rs b/external/rust-script/src/consts.rs new file mode 100644 index 0000000..b63b20e --- /dev/null +++ b/external/rust-script/src/consts.rs @@ -0,0 +1,186 @@ +/*! +This module just contains any big string literals I don't want cluttering up the rest of the code. +*/ + +pub const PROGRAM_NAME: &str = "rust-script"; + +/* +What follows are the templates used to wrap script input. +*/ + +/// Substitution for the script body. +pub const SCRIPT_BODY_SUB: &str = "script"; + +/// Substitution for the script prelude. +pub const SCRIPT_PRELUDE_SUB: &str = "prelude"; + +/// The template used for script file inputs. +pub const FILE_TEMPLATE: &str = r#"#{script}"#; + +/// The template used for `--expr` input. +pub const EXPR_TEMPLATE: &str = r#" +#{prelude} +use std::any::{Any, TypeId}; + +fn main() { + let exit_code = match try_main() { + Ok(()) => None, + Err(e) => { + use std::io::{self, Write}; + let _ = writeln!(io::stderr(), "Error: {}", e); + Some(1) + }, + }; + if let Some(exit_code) = exit_code { + std::process::exit(exit_code); + } +} + +fn try_main() -> Result<(), Box> { + fn _rust_script_is_empty_tuple(_s: &T) -> bool { + TypeId::of::<()>() == TypeId::of::() + } + match {#{script}} { + __rust_script_expr if !_rust_script_is_empty_tuple(&__rust_script_expr) => println!("{:?}", __rust_script_expr), + _ => {} + } + Ok(()) +} +"#; + +/* +Regarding the loop templates: what I *want* is for the result of the closure to be printed to standard output *only* if it's not `()`. + +* TODO: Merge the `LOOP_*` templates so there isn't duplicated code. It's icky. +*/ + +/// The template used for `--loop` input, assuming no `--count` flag is also given. +pub const LOOP_TEMPLATE: &str = r#" +#![allow(unused_imports)] +#![allow(unused_braces)] +#{prelude} +use std::any::Any; +use std::io::prelude::*; + +fn main() { + let mut closure = enforce_closure( +{#{script}} + ); + let mut line_buffer = String::new(); + let stdin = std::io::stdin(); + loop { + line_buffer.clear(); + let read_res = stdin.read_line(&mut line_buffer).unwrap_or(0); + if read_res == 0 { break } + let output = closure(&line_buffer); + + let display = { + let output_any: &dyn Any = &output; + !output_any.is::<()>() + }; + + if display { + println!("{:?}", output); + } + } +} + +fn enforce_closure(closure: F) -> F +where F: FnMut(&str) -> T, T: 'static { + closure +} +"#; + +/// The template used for `--count --loop` input. +pub const LOOP_COUNT_TEMPLATE: &str = r#" +#![allow(unused_imports)] +#![allow(unused_braces)] +use std::any::Any; +use std::io::prelude::*; + +fn main() { + let mut closure = enforce_closure( +{#{script}} + ); + let mut line_buffer = String::new(); + let stdin = std::io::stdin(); + let mut count = 0; + loop { + line_buffer.clear(); + let read_res = stdin.read_line(&mut line_buffer).unwrap_or(0); + if read_res == 0 { break } + count += 1; + let output = closure(&line_buffer, count); + + let display = { + let output_any: &dyn Any = &output; + !output_any.is::<()>() + }; + + if display { + println!("{:?}", output); + } + } +} + +fn enforce_closure(closure: F) -> F +where F: FnMut(&str, usize) -> T, T: 'static { + closure +} +"#; + +/// Substitution for the identifier-safe package name of the script. +pub const MANI_NAME_SUB: &str = "name"; + +/// Substitution for the identifier-safe bin name of the script. +pub const MANI_BIN_NAME_SUB: &str = "bin_name"; + +/// Substitution for the filesystem-safe name of the script. +pub const MANI_FILE_SUB: &str = "file"; + +/** +The default manifest used for packages. +*/ +#[rustversion::before(1.59)] +pub const DEFAULT_MANIFEST: &str = r##" +[package] +name = "#{name}" +version = "0.1.0" +authors = ["Anonymous"] +edition = "2018" + +[[bin]] +name = "#{bin_name}" +path = "#{file}.rs" +"##; +#[rustversion::since(1.59)] +pub const DEFAULT_MANIFEST: &str = r##" +[package] +name = "#{name}" +version = "0.1.0" +authors = ["Anonymous"] +edition = "2018" + +[[bin]] +name = "#{bin_name}" +path = "#{file}.rs" + +[profile.release] +strip = true +"##; + +/** +When generating a package's unique ID, how many hex nibbles of the digest should be used *at most*? + +The largest meaningful value is `40`. +*/ +pub const ID_DIGEST_LEN_MAX: usize = 24; + +/** +How old can stuff in the cache be before we automatically clear it out? + +Measured in milliseconds. +*/ +// It's been *one week* since you looked at me, +// cocked your head to the side and said "I'm angry." +pub const MAX_CACHE_AGE_MS: u128 = 7 * 24 * 60 * 60 * 1000; diff --git a/external/rust-script/src/error.rs b/external/rust-script/src/error.rs new file mode 100644 index 0000000..dbd1a20 --- /dev/null +++ b/external/rust-script/src/error.rs @@ -0,0 +1,61 @@ +/*! +Definition of the program's main error type. +*/ + +use std::borrow::Cow; +use std::error::Error; +use std::fmt; +use std::io; +use std::result::Result; + +/// Shorthand for the program's common result type. +pub type MainResult = Result; + +/// An error in the program. +#[derive(Debug)] +pub enum MainError { + Io(io::Error), + Tag(Cow<'static, str>, Box), + Other(Box), + OtherOwned(String), + OtherBorrowed(&'static str), +} + +impl fmt::Display for MainError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use self::MainError::*; + use std::fmt::Display; + match *self { + Io(ref err) => Display::fmt(err, fmt), + Tag(ref msg, ref err) => write!(fmt, "{}: {}", msg, err), + Other(ref err) => Display::fmt(err, fmt), + OtherOwned(ref err) => Display::fmt(err, fmt), + OtherBorrowed(err) => Display::fmt(err, fmt), + } + } +} + +impl Error for MainError {} + +macro_rules! from_impl { + ($src_ty:ty => $dst_ty:ty, $src:ident -> $e:expr) => { + impl From<$src_ty> for $dst_ty { + fn from($src: $src_ty) -> $dst_ty { + $e + } + } + }; +} + +from_impl! { io::Error => MainError, v -> MainError::Io(v) } +from_impl! { String => MainError, v -> MainError::OtherOwned(v) } +from_impl! { &'static str => MainError, v -> MainError::OtherBorrowed(v) } + +impl From> for MainError +where + T: 'static + Error, +{ + fn from(src: Box) -> Self { + MainError::Other(src) + } +} diff --git a/external/rust-script/src/file_assoc.rs b/external/rust-script/src/file_assoc.rs new file mode 100644 index 0000000..75f6a40 --- /dev/null +++ b/external/rust-script/src/file_assoc.rs @@ -0,0 +1,101 @@ +/*! +This module deals with setting up file associations on Windows +*/ +use crate::error::MainResult; +use std::env; +use std::io; +use winreg::{enums as wre, RegKey}; + +pub fn install_file_association() -> MainResult<()> { + let rust_script_path = env::current_exe()?.canonicalize()?; + if !rust_script_path.exists() { + return Err(format!("{:?} not found", rust_script_path).into()); + } + + // We have to remove the `\\?\` prefix because, if we don't, the shell freaks out. + let rust_script_path = rust_script_path.to_string_lossy(); + let rust_script_path = if let Some(stripped) = rust_script_path.strip_prefix(r#"\\?\"#) { + stripped + } else { + &rust_script_path[..] + }; + + let res = (|| -> io::Result<()> { + let hlcr = RegKey::predef(wre::HKEY_CLASSES_ROOT); + let (dot_ers, _) = hlcr.create_subkey(".ers")?; + dot_ers.set_value("", &"RustScript.Ers")?; + + let (cs_ers, _) = hlcr.create_subkey("RustScript.Ers")?; + cs_ers.set_value("", &"Rust Script")?; + + let (sh_o_c, _) = cs_ers.create_subkey(r#"shell\open\command"#)?; + sh_o_c.set_value("", &format!(r#""{}" "%1" %*"#, rust_script_path))?; + Ok(()) + })(); + + match res { + Ok(()) => (), + Err(e) => { + if e.kind() == io::ErrorKind::PermissionDenied { + println!( + "Access denied. Make sure you run this command from an administrator prompt." + ); + } + return Err(e.into()); + } + } + + println!("Created rust-script registry entry."); + println!("- Handler set to: {}", rust_script_path); + + Ok(()) +} + +pub fn uninstall_file_association() -> MainResult<()> { + let mut ignored_missing = false; + { + let mut notify = || ignored_missing = true; + + let hlcr = RegKey::predef(wre::HKEY_CLASSES_ROOT); + hlcr.delete_subkey(r#"RustScript.Ers\shell\open\command"#) + .ignore_missing_and(&mut notify)?; + hlcr.delete_subkey(r#"RustScript.Ers\shell\open"#) + .ignore_missing_and(&mut notify)?; + hlcr.delete_subkey(r#"RustScript.Ers\shell"#) + .ignore_missing_and(&mut notify)?; + hlcr.delete_subkey(r#"RustScript.Ers"#) + .ignore_missing_and(&mut notify)?; + } + + if ignored_missing { + println!("Ignored some missing registry entries."); + } + println!("Deleted rust-script registry entry."); + + Ok(()) +} + +trait IgnoreMissing { + fn ignore_missing_and(self, f: F) -> Self + where + F: FnOnce(); +} + +impl IgnoreMissing for io::Result<()> { + fn ignore_missing_and(self, f: F) -> Self + where + F: FnOnce(), + { + match self { + Ok(()) => Ok(()), + Err(e) => { + if e.kind() == io::ErrorKind::NotFound { + f(); + Ok(()) + } else { + Err(e) + } + } + } + } +} diff --git a/external/rust-script/src/main.rs b/external/rust-script/src/main.rs new file mode 100644 index 0000000..97de59a --- /dev/null +++ b/external/rust-script/src/main.rs @@ -0,0 +1,1230 @@ +#![forbid(unsafe_code)] + +/** +If this is set to `false`, then code that automatically deletes stuff *won't*. +*/ +const ALLOW_AUTO_REMOVE: bool = true; + +mod consts; +mod error; +mod manifest; +mod platform; +mod templates; +mod util; + +#[cfg(windows)] +mod file_assoc; + +#[cfg(not(windows))] +mod file_assoc {} + +#[cfg(unix)] +use std::os::unix::process::CommandExt; + +use log::{debug, error, info}; +use serde::{Deserialize, Serialize}; +use std::ffi::OsString; +use std::fs; +use std::io::{BufWriter, Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use crate::error::{MainError, MainResult}; +use crate::util::Defer; +use sha1::{Digest, Sha1}; + +#[derive(Debug)] +struct Args { + script: Option, + script_args: Vec, + features: Option, + + expr: bool, + loop_: bool, + count: bool, + + bin_name: Option, + pkg_path: Option, + gen_pkg_only: bool, + cargo_output: bool, + clear_cache: bool, + debug: bool, + dep: Vec, + extern_: Vec, + force: bool, + unstable_features: Vec, + build_kind: BuildKind, + template: Option, + list_templates: bool, + // This is a String instead of an + // enum since one can have custom + // toolchains (ex. a rustc developer + // will probably have `stage1`). + toolchain_version: Option, + + #[cfg(windows)] + install_file_association: bool, + #[cfg(windows)] + uninstall_file_association: bool, +} + +#[derive(Copy, Clone, Debug)] +enum BuildKind { + Normal, + Test, + Bench, +} + +impl BuildKind { + fn exec_command(&self) -> &'static str { + match *self { + Self::Normal => "run", + Self::Test => "test", + Self::Bench => "bench", + } + } + + fn from_flags(test: bool, bench: bool) -> Self { + match (test, bench) { + (false, false) => Self::Normal, + (true, false) => Self::Test, + (false, true) => Self::Bench, + _ => panic!("got both test and bench"), + } + } +} + +fn parse_args() -> Args { + use clap::{Arg, ArgGroup, Command}; + use std::iter::FromIterator; + let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"); + let about = r#"Compiles and runs a Rust script."#; + + let app = Command::new(consts::PROGRAM_NAME) + .version(version) + .about(about) + .trailing_var_arg(true) + .arg(Arg::new("script") + .index(1) + .help("Script file or expression to execute.") + .required_unless_present_any(if cfg!(windows) { + vec!["clear-cache", "list-templates", "install-file-association", "uninstall-file-association"] + } else { + vec!["clear-cache", "list-templates"] + }) + .conflicts_with_all(if cfg!(windows) { + &["list-templates", "install-file-association", "uninstall-file-association"] + } else { + &["list-templates"] + }) + .multiple_values(true) + ) + .arg(Arg::new("expr") + .help("Execute