feat: add rust-script
This commit is contained in:
5
external/rust-script/.gitignore
vendored
Normal file
5
external/rust-script/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
target
|
||||
/local
|
||||
/.cargo
|
||||
/.idea
|
||||
/tests/scripts/*.actual*
|
||||
1
external/rust-script/CNAME
vendored
Normal file
1
external/rust-script/CNAME
vendored
Normal file
@@ -0,0 +1 @@
|
||||
rust-script.org
|
||||
616
external/rust-script/Cargo.lock
generated
vendored
Normal file
616
external/rust-script/Cargo.lock
generated
vendored
Normal file
@@ -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",
|
||||
]
|
||||
47
external/rust-script/Cargo.toml
vendored
Normal file
47
external/rust-script/Cargo.toml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
[package]
|
||||
name = "rust-script"
|
||||
version = "0.22.0"
|
||||
edition = "2018"
|
||||
authors = ["Fredrik Fornwall <fredrik@fornwall.net>"]
|
||||
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
|
||||
201
external/rust-script/LICENSE-APACHE
vendored
Normal file
201
external/rust-script/LICENSE-APACHE
vendored
Normal file
@@ -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.
|
||||
23
external/rust-script/LICENSE-MIT
vendored
Normal file
23
external/rust-script/LICENSE-MIT
vendored
Normal file
@@ -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.
|
||||
44
external/rust-script/README.md
vendored
Normal file
44
external/rust-script/README.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
[](https://github.com/fornwall/rust-script/actions?query=workflow%3ACI)
|
||||
[](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).
|
||||
1
external/rust-script/_config.yml
vendored
Normal file
1
external/rust-script/_config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
||||
1
external/rust-script/docs/CNAME
vendored
Normal file
1
external/rust-script/docs/CNAME
vendored
Normal file
@@ -0,0 +1 @@
|
||||
rust-script.org
|
||||
211
external/rust-script/docs/README.md
vendored
Normal file
211
external/rust-script/docs/README.md
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
<style>
|
||||
ul li:not(:last-child) { margin-bottom: 0.4em; }
|
||||
</style>
|
||||
|
||||
- [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 <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::<Box<Read>>()"
|
||||
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.
|
||||
1
external/rust-script/docs/_config.yml
vendored
Normal file
1
external/rust-script/docs/_config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
||||
BIN
external/rust-script/docs/favicon.ico
vendored
Normal file
BIN
external/rust-script/docs/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
3
external/rust-script/examples/hello-without-main.ers
vendored
Executable file
3
external/rust-script/examples/hello-without-main.ers
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env rust-script
|
||||
|
||||
println!("hello, rust");
|
||||
5
external/rust-script/examples/hello.ers
vendored
Executable file
5
external/rust-script/examples/hello.ers
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env rust-script
|
||||
|
||||
fn main() {
|
||||
println!("hello, rust");
|
||||
}
|
||||
12
external/rust-script/examples/time-main.ers
vendored
Normal file
12
external/rust-script/examples/time-main.ers
vendored
Normal file
@@ -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());
|
||||
}
|
||||
13
external/rust-script/examples/time-without-main.ers
vendored
Normal file
13
external/rust-script/examples/time-without-main.ers
vendored
Normal file
@@ -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());
|
||||
186
external/rust-script/src/consts.rs
vendored
Normal file
186
external/rust-script/src/consts.rs
vendored
Normal file
@@ -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<dyn std::error::Error>> {
|
||||
fn _rust_script_is_empty_tuple<T: ?Sized + Any>(_s: &T) -> bool {
|
||||
TypeId::of::<()>() == TypeId::of::<T>()
|
||||
}
|
||||
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<F, T>(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<F, T>(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;
|
||||
61
external/rust-script/src/error.rs
vendored
Normal file
61
external/rust-script/src/error.rs
vendored
Normal file
@@ -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<T> = Result<T, MainError>;
|
||||
|
||||
/// An error in the program.
|
||||
#[derive(Debug)]
|
||||
pub enum MainError {
|
||||
Io(io::Error),
|
||||
Tag(Cow<'static, str>, Box<MainError>),
|
||||
Other(Box<dyn Error>),
|
||||
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<T> From<Box<T>> for MainError
|
||||
where
|
||||
T: 'static + Error,
|
||||
{
|
||||
fn from(src: Box<T>) -> Self {
|
||||
MainError::Other(src)
|
||||
}
|
||||
}
|
||||
101
external/rust-script/src/file_assoc.rs
vendored
Normal file
101
external/rust-script/src/file_assoc.rs
vendored
Normal file
@@ -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<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce();
|
||||
}
|
||||
|
||||
impl IgnoreMissing for io::Result<()> {
|
||||
fn ignore_missing_and<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
match self {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::NotFound {
|
||||
f();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1230
external/rust-script/src/main.rs
vendored
Normal file
1230
external/rust-script/src/main.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1214
external/rust-script/src/manifest.rs
vendored
Normal file
1214
external/rust-script/src/manifest.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
94
external/rust-script/src/platform.rs
vendored
Normal file
94
external/rust-script/src/platform.rs
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/*!
|
||||
This module is for platform-specific stuff.
|
||||
*/
|
||||
|
||||
pub use self::inner::force_cargo_color;
|
||||
|
||||
use crate::consts;
|
||||
use crate::error::MainError;
|
||||
use std::fs;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
// Last-modified time of a file, in milliseconds since the UNIX epoch.
|
||||
pub fn file_last_modified(file: &fs::File) -> u128 {
|
||||
file.metadata()
|
||||
.and_then(|md| {
|
||||
md.modified()
|
||||
.map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_millis())
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
// Current system time, in milliseconds since the UNIX epoch.
|
||||
pub fn current_time() -> u128 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis()
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub fn cache_dir() -> Result<PathBuf, MainError> {
|
||||
dirs_next::cache_dir()
|
||||
.map(|dir| dir.join(consts::PROGRAM_NAME))
|
||||
.ok_or_else(|| ("Cannot get cache directory").into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn cache_dir() -> Result<PathBuf, MainError> {
|
||||
use lazy_static::lazy_static;
|
||||
lazy_static! {
|
||||
static ref TEMP_DIR: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
}
|
||||
Ok(TEMP_DIR.path().to_path_buf())
|
||||
}
|
||||
|
||||
pub fn generated_projects_cache_path() -> Result<PathBuf, MainError> {
|
||||
cache_dir().map(|dir| dir.join("projects"))
|
||||
}
|
||||
|
||||
pub fn binary_cache_path() -> Result<PathBuf, MainError> {
|
||||
cache_dir().map(|dir| dir.join("binaries"))
|
||||
}
|
||||
|
||||
pub fn templates_dir() -> Result<PathBuf, MainError> {
|
||||
if cfg!(debug_assertions) {
|
||||
if let Ok(path) = std::env::var("RUST_SCRIPT_DEBUG_TEMPLATE_PATH") {
|
||||
return Ok(path.into());
|
||||
}
|
||||
}
|
||||
|
||||
dirs_next::data_local_dir()
|
||||
.map(|dir| dir.join(consts::PROGRAM_NAME).join("templates"))
|
||||
.ok_or_else(|| ("Cannot get cache directory").into())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod inner {
|
||||
pub use super::*;
|
||||
|
||||
/**
|
||||
Returns `true` if `rust-script` should force Cargo to use coloured output.
|
||||
|
||||
This depends on whether `rust-script`'s STDERR is connected to a TTY or not.
|
||||
*/
|
||||
pub fn force_cargo_color() -> bool {
|
||||
atty::is(atty::Stream::Stderr)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod inner {
|
||||
pub use super::*;
|
||||
|
||||
/**
|
||||
Returns `true` if `rust-script` should force Cargo to use coloured output.
|
||||
|
||||
Always returns `false` on Windows because colour is communicated over a side-channel.
|
||||
*/
|
||||
pub fn force_cargo_color() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
138
external/rust-script/src/templates.rs
vendored
Normal file
138
external/rust-script/src/templates.rs
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
/*!
|
||||
This module contains code related to template support.
|
||||
*/
|
||||
use crate::consts;
|
||||
use crate::error::{MainError, MainResult};
|
||||
use crate::platform;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
lazy_static! {
|
||||
static ref RE_SUB: Regex = Regex::new(r#"#\{([A-Za-z_][A-Za-z0-9_]*)}"#).unwrap();
|
||||
}
|
||||
|
||||
pub fn expand(src: &str, subs: &HashMap<&str, &str>) -> MainResult<String> {
|
||||
// The estimate of final size is the sum of the size of all the input.
|
||||
let sub_size = subs.iter().map(|(_, v)| v.len()).sum::<usize>();
|
||||
let est_size = src.len() + sub_size;
|
||||
|
||||
let mut anchor = 0;
|
||||
let mut result = String::with_capacity(est_size);
|
||||
|
||||
for m in RE_SUB.captures_iter(src) {
|
||||
// Concatenate the static bit just before the match.
|
||||
let (m_start, m_end) = {
|
||||
let m_0 = m.get(0).unwrap();
|
||||
(m_0.start(), m_0.end())
|
||||
};
|
||||
let prior_slice = anchor..m_start;
|
||||
anchor = m_end;
|
||||
result.push_str(&src[prior_slice]);
|
||||
|
||||
// Concat the substitution.
|
||||
let sub_name = m.get(1).unwrap().as_str();
|
||||
match subs.get(sub_name) {
|
||||
Some(s) => result.push_str(s),
|
||||
None => {
|
||||
return Err(MainError::OtherOwned(format!(
|
||||
"substitution `{}` in template is unknown",
|
||||
sub_name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push_str(&src[anchor..]);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to locate and load the contents of the specified template.
|
||||
*/
|
||||
pub fn get_template(name: &str) -> MainResult<Cow<'static, str>> {
|
||||
use std::io::Read;
|
||||
|
||||
let base = platform::templates_dir()?;
|
||||
|
||||
let file = fs::File::open(base.join(format!("{}.rs", name)))
|
||||
.map_err(MainError::from)
|
||||
.map_err(|e| {
|
||||
MainError::Tag(
|
||||
format!(
|
||||
"template file `{}.rs` does not exist in {}",
|
||||
name,
|
||||
base.display()
|
||||
)
|
||||
.into(),
|
||||
Box::new(e),
|
||||
)
|
||||
});
|
||||
|
||||
// If the template is one of the built-in ones, do fallback if it wasn't found on disk.
|
||||
if file.is_err() {
|
||||
if let Some(text) = builtin_template(name) {
|
||||
return Ok(text.into());
|
||||
}
|
||||
}
|
||||
|
||||
let mut file = file?;
|
||||
|
||||
let mut text = String::new();
|
||||
file.read_to_string(&mut text)?;
|
||||
Ok(text.into())
|
||||
}
|
||||
|
||||
fn builtin_template(name: &str) -> Option<&'static str> {
|
||||
Some(match name {
|
||||
"expr" => consts::EXPR_TEMPLATE,
|
||||
"file" => consts::FILE_TEMPLATE,
|
||||
"loop" => consts::LOOP_TEMPLATE,
|
||||
"loop-count" => consts::LOOP_COUNT_TEMPLATE,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn list() -> MainResult<()> {
|
||||
use std::ffi::OsStr;
|
||||
|
||||
let t_path = platform::templates_dir()?;
|
||||
|
||||
if !t_path.exists() {
|
||||
fs::create_dir_all(&t_path)?;
|
||||
}
|
||||
|
||||
println!("Listing templates in {}", t_path.display());
|
||||
|
||||
if !t_path.exists() {
|
||||
return Err(format!(
|
||||
"cannot list template directory `{}`: it does not exist",
|
||||
t_path.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if !t_path.is_dir() {
|
||||
return Err(format!(
|
||||
"cannot list template directory `{}`: it is not a directory",
|
||||
t_path.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
for entry in fs::read_dir(&t_path)? {
|
||||
let entry = entry?;
|
||||
if !entry.file_type()?.is_file() {
|
||||
continue;
|
||||
}
|
||||
let f_path = entry.path();
|
||||
if f_path.extension() != Some(OsStr::new("rs")) {
|
||||
continue;
|
||||
}
|
||||
if let Some(stem) = f_path.file_stem() {
|
||||
println!("{}", stem.to_string_lossy());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
54
external/rust-script/src/util.rs
vendored
Normal file
54
external/rust-script/src/util.rs
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*!
|
||||
This module just contains other random implementation stuff.
|
||||
*/
|
||||
use log::error;
|
||||
use std::error::Error;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/**
|
||||
Used to defer a closure until the value is dropped.
|
||||
|
||||
The closure *must* return a `Result<(), _>`, as a reminder to *not* panic; doing so will abort your whole program if it happens during another panic. If the closure returns an `Err`, then it is logged as an `error`.
|
||||
|
||||
A `Defer` can also be "disarmed", preventing the closure from running at all.
|
||||
*/
|
||||
#[must_use]
|
||||
pub struct Defer<'a, F, E>(Option<F>, PhantomData<&'a F>)
|
||||
where
|
||||
F: 'a + FnOnce() -> Result<(), E>,
|
||||
E: Error;
|
||||
|
||||
impl<'a, F, E> Defer<'a, F, E>
|
||||
where
|
||||
F: 'a + FnOnce() -> Result<(), E>,
|
||||
E: Error,
|
||||
{
|
||||
/**
|
||||
Create a new `Defer` with the given closure.
|
||||
*/
|
||||
pub fn new(f: F) -> Defer<'a, F, E> {
|
||||
Defer(Some(f), PhantomData)
|
||||
}
|
||||
|
||||
/**
|
||||
Consume this `Defer` *without* invoking the closure.
|
||||
*/
|
||||
pub fn disarm(mut self) {
|
||||
self.0 = None;
|
||||
drop(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F, E> ::std::ops::Drop for Defer<'a, F, E>
|
||||
where
|
||||
F: 'a + FnOnce() -> Result<(), E>,
|
||||
E: Error,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
if let Some(f) = self.0.take() {
|
||||
if let Err(err) = f() {
|
||||
error!("deferred function failed: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
external/rust-script/tests/data/cargo-target-dir-env.rs
vendored
Normal file
13
external/rust-script/tests/data/cargo-target-dir-env.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
use std::env;
|
||||
|
||||
pub fn main() {
|
||||
// Test that CARGO_TARGET_DIR is not set by rust-script to avoid
|
||||
// interfering with cargo calls done by the script.
|
||||
// See https://github.com/fornwall/rust-script/issues/27
|
||||
let env_variable = env::var("CARGO_TARGET_DIR");
|
||||
println!("--output--");
|
||||
println!(
|
||||
"{:?}",
|
||||
matches!(env_variable, Err(env::VarError::NotPresent))
|
||||
);
|
||||
}
|
||||
1
external/rust-script/tests/data/file-to-be-included.txt
vendored
Normal file
1
external/rust-script/tests/data/file-to-be-included.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
hello, including script
|
||||
10
external/rust-script/tests/data/outer-line-doc.rs
vendored
Normal file
10
external/rust-script/tests/data/outer-line-doc.rs
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/// ```cargo
|
||||
/// [dependencies]
|
||||
/// boolinator = "=0.1.0"
|
||||
/// ```
|
||||
use boolinator::Boolinator;
|
||||
|
||||
pub fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
10
external/rust-script/tests/data/pub-fn-main.rs
vendored
Normal file
10
external/rust-script/tests/data/pub-fn-main.rs
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! boolinator = "=0.1.0"
|
||||
//! ```
|
||||
use boolinator::Boolinator;
|
||||
|
||||
pub fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
3
external/rust-script/tests/data/question-mark.rs
vendored
Normal file
3
external/rust-script/tests/data/question-mark.rs
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
use std::fs::File;
|
||||
|
||||
File::open("__rust-script-this-file-does-not-exist.txt")?;
|
||||
4
external/rust-script/tests/data/same-flags.rs
vendored
Normal file
4
external/rust-script/tests/data/same-flags.rs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
println!("--output--");
|
||||
if let Some(arg) = std::env::args().skip(1).next() {
|
||||
println!("Argument: {}", arg);
|
||||
}
|
||||
6
external/rust-script/tests/data/script-args.rs
vendored
Normal file
6
external/rust-script/tests/data/script-args.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
for (i, arg) in std::env::args().enumerate() {
|
||||
println!("{:>4}: {:?}", format!("[{}]", i), arg);
|
||||
}
|
||||
}
|
||||
14
external/rust-script/tests/data/script-async-main.rs
vendored
Normal file
14
external/rust-script/tests/data/script-async-main.rs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
//! This is merged into a default manifest in order to form the full package manifest:
|
||||
//!
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! boolinator = "=0.1.0"
|
||||
//! tokio = { version = "1", features = ["full"] }
|
||||
//! ```
|
||||
use boolinator::Boolinator;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
12
external/rust-script/tests/data/script-cs-env.rs
vendored
Normal file
12
external/rust-script/tests/data/script-cs-env.rs
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
let path = env::var("RUST_SCRIPT_PATH").expect("CSSP wasn't set");
|
||||
assert!(path.ends_with("script-cs-env.rs"));
|
||||
assert_eq!(env::var("RUST_SCRIPT_SAFE_NAME"), Ok("script-cs-env".into()));
|
||||
assert_eq!(env::var("RUST_SCRIPT_PKG_NAME"), Ok("script-cs-env".into()));
|
||||
let base_path = env::var("RUST_SCRIPT_BASE_PATH").expect("CSBP wasn't set");
|
||||
assert!(base_path.ends_with("data"));
|
||||
println!("Ok");
|
||||
}
|
||||
6
external/rust-script/tests/data/script-explicit.rs
vendored
Normal file
6
external/rust-script/tests/data/script-explicit.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
extern crate boolinator;
|
||||
use boolinator::Boolinator;
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
16
external/rust-script/tests/data/script-features.rs
vendored
Normal file
16
external/rust-script/tests/data/script-features.rs
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/*!
|
||||
```cargo
|
||||
[features]
|
||||
dont-panic = []
|
||||
```
|
||||
*/
|
||||
#[cfg(feature="dont-panic")]
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("Keep calm and borrow check.");
|
||||
}
|
||||
|
||||
#[cfg(not(feature="dont-panic"))]
|
||||
fn main() {
|
||||
panic!("Do I really exist from an external, non-subjective point of view?");
|
||||
}
|
||||
11
external/rust-script/tests/data/script-full-block.rs
vendored
Normal file
11
external/rust-script/tests/data/script-full-block.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//! This is merged into a default manifest in order to form the full package manifest:
|
||||
//!
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! boolinator = "=0.1.0"
|
||||
//! ```
|
||||
use boolinator::Boolinator;
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
11
external/rust-script/tests/data/script-full-line-without-main.rs
vendored
Normal file
11
external/rust-script/tests/data/script-full-line-without-main.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env rust-script
|
||||
/// This is merged into a default manifest in order to form the full package manifest:
|
||||
///
|
||||
/// ```cargo
|
||||
/// [dependencies]
|
||||
/// boolinator = "=0.1.0"
|
||||
/// ```
|
||||
use boolinator::Boolinator;
|
||||
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
13
external/rust-script/tests/data/script-full-line.rs
vendored
Normal file
13
external/rust-script/tests/data/script-full-line.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/*!
|
||||
This is merged into a default manifest in order to form the full package manifest:
|
||||
|
||||
```cargo
|
||||
[dependencies]
|
||||
boolinator = "=0.1.0"
|
||||
```
|
||||
*/
|
||||
use boolinator::Boolinator;
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
4
external/rust-script/tests/data/script-has.weird§chars!.rs
vendored
Normal file
4
external/rust-script/tests/data/script-has.weird§chars!.rs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("Ok");
|
||||
}
|
||||
12
external/rust-script/tests/data/script-including-relative.rs
vendored
Normal file
12
external/rust-script/tests/data/script-including-relative.rs
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
use std::env;
|
||||
|
||||
mod script_module {
|
||||
include!(concat!(env!("RUST_SCRIPT_BASE_PATH"), "/script-module.rs"));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
let s = include_str!(concat!(env!("RUST_SCRIPT_BASE_PATH"), "/file-to-be-included.txt"));
|
||||
assert_eq!(script_module::A_VALUE, 1);
|
||||
println!("{}", s);
|
||||
}
|
||||
12
external/rust-script/tests/data/script-invalid-doc-comment.rs
vendored
Normal file
12
external/rust-script/tests/data/script-invalid-doc-comment.rs
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("Hello, World!");
|
||||
}
|
||||
|
||||
/**
|
||||
```cargo
|
||||
[dependencies]
|
||||
i-cant-decide-whether-you-should = ["live", "die"]
|
||||
```
|
||||
*/
|
||||
fn dummy() {}
|
||||
1
external/rust-script/tests/data/script-module.rs
vendored
Normal file
1
external/rust-script/tests/data/script-module.rs
vendored
Normal file
@@ -0,0 +1 @@
|
||||
pub const A_VALUE: i32 = 1;
|
||||
4
external/rust-script/tests/data/script-no-deps.rs
vendored
Normal file
4
external/rust-script/tests/data/script-no-deps.rs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("Hello, World!");
|
||||
}
|
||||
9
external/rust-script/tests/data/script-short-without-main.rs
vendored
Normal file
9
external/rust-script/tests/data/script-short-without-main.rs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// cargo-deps: boolinator="=0.1.0"
|
||||
// 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.
|
||||
use boolinator::Boolinator;
|
||||
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
10
external/rust-script/tests/data/script-short.rs
vendored
Normal file
10
external/rust-script/tests/data/script-short.rs
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// cargo-deps: boolinator="=0.1.0"
|
||||
// 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.
|
||||
use boolinator::Boolinator;
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("{:?}", true.as_some(1));
|
||||
}
|
||||
10
external/rust-script/tests/data/script-slow-output.rs
vendored
Normal file
10
external/rust-script/tests/data/script-slow-output.rs
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
```cargo
|
||||
[dependencies]
|
||||
slow-build = { version = "0.1.0", path = "slow-build" }
|
||||
```
|
||||
*/
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("Ok");
|
||||
}
|
||||
2
external/rust-script/tests/data/script-test.rs
vendored
Normal file
2
external/rust-script/tests/data/script-test.rs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#[test]
|
||||
fn test() {}
|
||||
6
external/rust-script/tests/data/script-unstable-feature.rs
vendored
Normal file
6
external/rust-script/tests/data/script-unstable-feature.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#![feature(lang_items)]
|
||||
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("`#![feature]` *may* be used!");
|
||||
}
|
||||
1
external/rust-script/tests/data/slow-build/.gitignore
vendored
Normal file
1
external/rust-script/tests/data/slow-build/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/Cargo.lock
|
||||
10
external/rust-script/tests/data/slow-build/Cargo.toml
vendored
Normal file
10
external/rust-script/tests/data/slow-build/Cargo.toml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "slow-build"
|
||||
version = "0.1.0"
|
||||
authors = ["Daniel Keep <daniel.keep@gmail.com>"]
|
||||
|
||||
build = "slow-build-build.rs"
|
||||
|
||||
[lib]
|
||||
name = "slow_build"
|
||||
path = "slow-build-lib.rs"
|
||||
5
external/rust-script/tests/data/slow-build/slow-build-build.rs
vendored
Normal file
5
external/rust-script/tests/data/slow-build/slow-build-build.rs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
println!("Sleeping for 2 seconds...");
|
||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||
println!("Done.");
|
||||
}
|
||||
0
external/rust-script/tests/data/slow-build/slow-build-lib.rs
vendored
Normal file
0
external/rust-script/tests/data/slow-build/slow-build-lib.rs
vendored
Normal file
9
external/rust-script/tests/data/templates/boolinate.rs
vendored
Normal file
9
external/rust-script/tests/data/templates/boolinate.rs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// cargo-deps: boolinator="0.1.0"
|
||||
#{prelude}
|
||||
|
||||
extern crate boolinator;
|
||||
use boolinator::Boolinator;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Boolinator::as_option({#{script}}));
|
||||
}
|
||||
9
external/rust-script/tests/data/templates/override/expr.rs
vendored
Normal file
9
external/rust-script/tests/data/templates/override/expr.rs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// cargo-deps: boolinator="0.1.0"
|
||||
#{prelude}
|
||||
|
||||
extern crate boolinator;
|
||||
use boolinator::Boolinator;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Boolinator::as_option({#{script}}));
|
||||
}
|
||||
11
external/rust-script/tests/data/templates/shout.rs
vendored
Normal file
11
external/rust-script/tests/data/templates/shout.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#{prelude}
|
||||
|
||||
fn main() {
|
||||
match {#{script}} {
|
||||
script_result => {
|
||||
let text = script_result.to_string();
|
||||
let text = text.to_uppercase();
|
||||
println!("{}", text);
|
||||
}
|
||||
}
|
||||
}
|
||||
6
external/rust-script/tests/data/time.rs
vendored
Normal file
6
external/rust-script/tests/data/time.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// cargo-deps: chrono
|
||||
extern crate chrono;
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("Hello");
|
||||
}
|
||||
4
external/rust-script/tests/data/whitespace-before-main.rs
vendored
Normal file
4
external/rust-script/tests/data/whitespace-before-main.rs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!("--output--");
|
||||
println!("hello, world");
|
||||
}
|
||||
19
external/rust-script/tests/integration.rs
vendored
Normal file
19
external/rust-script/tests/integration.rs
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
# Why is this here?
|
||||
|
||||
Because *both* Cargo and Rust both know better than I do and won't let me tell them to stop running the tests in parallel. This is a problem because they do not, in fact, know better than me: Cargo doesn't do *any* locking, which causes random failures as two tests try to update the registry simultaneously (quite *why* Cargo needs to update the registry so fucking often I have no damn idea).
|
||||
|
||||
*All* integration tests have to be glommed into a single runner so that we can use locks to prevent Cargo from falling over and breaking both its legs as soon as a gentle breeze comes along. I *would* do this "properly" using file locks, except that's apparently impossible in Rust without writing the whole stack yourself directly on native OS calls, and I just can't be arsed to go to *that* much effort just to get some bloody tests to work.
|
||||
*/
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate scan_rules;
|
||||
#[macro_use]
|
||||
mod util;
|
||||
|
||||
mod tests {
|
||||
mod expr;
|
||||
mod others;
|
||||
mod script;
|
||||
}
|
||||
4
external/rust-script/tests/scripts/basic-eval.expected
vendored
Normal file
4
external/rust-script/tests/scripts/basic-eval.expected
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
hello
|
||||
2
|
||||
3
|
||||
4
|
||||
7
external/rust-script/tests/scripts/basic-eval.script
vendored
Executable file
7
external/rust-script/tests/scripts/basic-eval.script
vendored
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e -u
|
||||
|
||||
rust-script -e 'println!("hello");'
|
||||
rust-script -e '1+1'
|
||||
rust-script -e '1+2'
|
||||
rust-script -e '1+3'
|
||||
6
external/rust-script/tests/scripts/loop-to-prefix.expected
vendored
Normal file
6
external/rust-script/tests/scripts/loop-to-prefix.expected
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
First:
|
||||
1: line1
|
||||
2: line2
|
||||
Second:
|
||||
1: line1
|
||||
2: line2
|
||||
10
external/rust-script/tests/scripts/loop-to-prefix.script
vendored
Executable file
10
external/rust-script/tests/scripts/loop-to-prefix.script
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
set -e -u
|
||||
|
||||
echo "First:"
|
||||
echo "line1\nline2" | rust-script --loop \
|
||||
"let mut n=0; move |l| {n+=1; println!(\"{:>6}: {}\",n,l.trim_right())}"
|
||||
|
||||
echo "Second:"
|
||||
echo "line1\nline2" | rust-script --count --loop \
|
||||
"|l,n| println!(\"{:>6}: {}\", n, l.trim_right())"
|
||||
40
external/rust-script/tests/scripts/test-runner.sh
vendored
Executable file
40
external/rust-script/tests/scripts/test-runner.sh
vendored
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
set -e -u
|
||||
|
||||
ANY_ERROR=0
|
||||
|
||||
# Make sure newly built binary is first in PATH:
|
||||
cargo build &> /dev/null || {
|
||||
echo "ERROR: Compilation failed"
|
||||
exit 1
|
||||
}
|
||||
export PATH=$PWD/target/debug/:$PATH
|
||||
cd tests/scripts
|
||||
|
||||
for TEST_SCRIPT in *.script; do
|
||||
EXPECTED_STDOUT=${TEST_SCRIPT/.script/.expected}
|
||||
ACTUAL_STDOUT=${TEST_SCRIPT/.script/.actual-stdout}
|
||||
ACTUAL_STDERR=${TEST_SCRIPT/.script/.actual-stderr}
|
||||
echo -n "Running $TEST_SCRIPT ... "
|
||||
|
||||
./$TEST_SCRIPT > $ACTUAL_STDOUT 2> $ACTUAL_STDERR || {
|
||||
ANY_ERROR=1
|
||||
echo "Failed to run!"
|
||||
}
|
||||
|
||||
if cmp -s "$EXPECTED_STDOUT" "$ACTUAL_STDOUT"; then
|
||||
echo "Ok"
|
||||
else
|
||||
ANY_ERROR=1
|
||||
echo "Failed!"
|
||||
echo "######################## Expected:"
|
||||
cat $EXPECTED_STDOUT
|
||||
echo "######################## Actual:"
|
||||
cat $ACTUAL_STDOUT
|
||||
echo "######################## Error output:"
|
||||
cat $ACTUAL_STDERR
|
||||
echo "########################"
|
||||
fi
|
||||
done
|
||||
|
||||
exit $ANY_ERROR
|
||||
112
external/rust-script/tests/tests/expr.rs
vendored
Normal file
112
external/rust-script/tests/tests/expr.rs
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
#[test]
|
||||
fn test_expr_0() {
|
||||
let out = rust_script!("-e", with_output_marker!("0")).unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("0") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_comma() {
|
||||
let out = rust_script!("-e", with_output_marker!("[1, 2, 3]")).unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("[1, 2, 3]") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_dnc() {
|
||||
let out = rust_script!("-e", "swing begin").unwrap();
|
||||
assert!(!out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_temporary() {
|
||||
let out = rust_script!("-e", "[1].iter().max()").unwrap();
|
||||
assert!(out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_dep() {
|
||||
let out = rust_script!(
|
||||
"-d",
|
||||
"boolinator=0.1.0",
|
||||
"-e",
|
||||
with_output_marker!(
|
||||
prelude "use boolinator::Boolinator;";
|
||||
"true.as_some(1)"
|
||||
)
|
||||
)
|
||||
.unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_panic() {
|
||||
let out = rust_script!("-e", with_output_marker!("panic!()")).unwrap();
|
||||
assert!(!out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_qmark() {
|
||||
let code = with_output_marker!("\"42\".parse::<i32>()?.wrapping_add(1)");
|
||||
let out = rust_script!("-e", code).unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("43") => ()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_template() {
|
||||
let template_dir = "tests/data/templates";
|
||||
let out = rust_script!(
|
||||
#[env(RUST_SCRIPT_DEBUG_TEMPLATE_PATH=template_dir)]
|
||||
"-t",
|
||||
"shout",
|
||||
"-e",
|
||||
with_output_marker!(r#""no way? no way!""#)
|
||||
)
|
||||
.unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("NO WAY? NO WAY!") => ()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_template_with_deps() {
|
||||
let template_dir = "tests/data/templates";
|
||||
let out = rust_script!(
|
||||
#[env(RUST_SCRIPT_DEBUG_TEMPLATE_PATH=template_dir)]
|
||||
"-t",
|
||||
"boolinate",
|
||||
"-e",
|
||||
with_output_marker!(r#"true"#)
|
||||
)
|
||||
.unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(())") => ()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_template_override_expr() {
|
||||
let template_dir = "tests/data/templates/override";
|
||||
let out = rust_script!(
|
||||
#[env(RUST_SCRIPT_DEBUG_TEMPLATE_PATH=template_dir)]
|
||||
"-e",
|
||||
with_output_marker!(r#"true"#)
|
||||
)
|
||||
.unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(())") => ()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
15
external/rust-script/tests/tests/others.rs
vendored
Normal file
15
external/rust-script/tests/tests/others.rs
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#[test]
|
||||
fn test_version() {
|
||||
let out = rust_script!("--version").unwrap();
|
||||
assert!(out.success());
|
||||
scan!(&out.stdout;
|
||||
("rust-script", &::std::env::var("CARGO_PKG_VERSION").unwrap(), .._) => ()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clear_cache() {
|
||||
let out = rust_script!("--clear-cache").unwrap();
|
||||
assert!(out.success());
|
||||
}
|
||||
235
external/rust-script/tests/tests/script.rs
vendored
Normal file
235
external/rust-script/tests/tests/script.rs
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
#[test]
|
||||
fn test_script_explicit() {
|
||||
let out = rust_script!("-d", "boolinator", "tests/data/script-explicit.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_features() {
|
||||
let out = rust_script!("--features", "dont-panic", "tests/data/script-features.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Keep calm and borrow check.") => ()
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let out = rust_script!("tests/data/script-features.rs").unwrap();
|
||||
assert!(!out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_full_block() {
|
||||
let out = rust_script!("tests/data/script-full-block.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_full_line() {
|
||||
let out = rust_script!("tests/data/script-full-line.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_full_line_without_main() {
|
||||
let out = rust_script!("tests/data/script-full-line-without-main.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_invalid_doc_comment() {
|
||||
let out = rust_script!("tests/data/script-invalid-doc-comment.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Hello, World!") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_no_deps() {
|
||||
let out = rust_script!("tests/data/script-no-deps.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Hello, World!") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_short() {
|
||||
let out = rust_script!("tests/data/script-short.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_short_without_main() {
|
||||
let out = rust_script!("tests/data/script-short-without-main.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_test() {
|
||||
let out = rust_script!("--test", "tests/data/script-test.rs").unwrap();
|
||||
assert!(out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_hyphens() {
|
||||
use scan_rules::scanner::QuotedString;
|
||||
let out = rust_script!("--", "tests/data/script-args.rs", "-NotAnArg").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("[0]:", let _: QuotedString, "[1]:", let arg: QuotedString) => {
|
||||
assert_eq!(arg, "-NotAnArg");
|
||||
}
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_hyphens_without_separator() {
|
||||
use scan_rules::scanner::QuotedString;
|
||||
let out = rust_script!("tests/data/script-args.rs", "-NotAnArg").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("[0]:", let _: QuotedString, "[1]:", let arg: QuotedString) => {
|
||||
assert_eq!(arg, "-NotAnArg");
|
||||
}
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_has_weird_chars() {
|
||||
let out = rust_script!("tests/data/script-has.weird§chars!.rs").unwrap();
|
||||
assert!(out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_cs_env() {
|
||||
let out = rust_script!("tests/data/script-cs-env.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Ok") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_including_relative() {
|
||||
let out = rust_script!("tests/data/script-including-relative.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("hello, including script") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn script_with_same_name_as_dependency() {
|
||||
let out = rust_script!("tests/data/time.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Hello") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn script_without_main_question_mark() {
|
||||
let out = rust_script!("tests/data/question-mark").unwrap();
|
||||
assert!(out
|
||||
.stderr
|
||||
.starts_with("Error: Os { code: 2, kind: NotFound, message:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_async_main() {
|
||||
let out = rust_script!("tests/data/script-async-main.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pub_fn_main() {
|
||||
let out = rust_script!("tests/data/pub-fn-main.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cargo_target_dir_env() {
|
||||
let out = rust_script!("tests/data/cargo-target-dir-env.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("true") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_outer_line_doc() {
|
||||
let out = rust_script!("tests/data/outer-line-doc.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Some(1)") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_whitespace_before_main() {
|
||||
let out = rust_script!("tests/data/whitespace-before-main.rs").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("hello, world") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stable_toolchain() {
|
||||
let out = rust_script!(
|
||||
"--toolchain-version",
|
||||
"stable",
|
||||
"tests/data/script-unstable-feature.rs"
|
||||
)
|
||||
.unwrap();
|
||||
assert!(out.stderr.contains("`#![feature]` may not be used"));
|
||||
assert!(!out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nightly_toolchain() {
|
||||
let out = rust_script!(
|
||||
"--toolchain-version",
|
||||
"nightly",
|
||||
"tests/data/script-unstable-feature.rs"
|
||||
)
|
||||
.unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("`#![feature]` *may* be used!") => ()
|
||||
)
|
||||
.unwrap();
|
||||
assert!(out.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_same_flags() {
|
||||
let out = rust_script!("tests/data/same-flags.rs", "--help").unwrap();
|
||||
scan!(out.stdout_output();
|
||||
("Argument: --help") => ()
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
121
external/rust-script/tests/util/mod.rs
vendored
Normal file
121
external/rust-script/tests/util/mod.rs
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
macro_rules! rust_script {
|
||||
(
|
||||
#[env($($env_k:ident=$env_v:expr),* $(,)*)]
|
||||
$($args:expr),* $(,)*
|
||||
) => {
|
||||
{
|
||||
extern crate tempfile;
|
||||
use std::process::Command;
|
||||
|
||||
let cargo_lock = crate::util::CARGO_MUTEX.lock().expect("Could not acquire Cargo mutex");
|
||||
|
||||
let cmd_str;
|
||||
let out = {
|
||||
let target_dir = ::std::env::var("CARGO_TARGET_DIR")
|
||||
.unwrap_or_else(|_| String::from("target"));
|
||||
let mut cmd = Command::new(format!("{}/debug/rust-script", target_dir));
|
||||
$(
|
||||
cmd.arg($args);
|
||||
)*
|
||||
|
||||
cmd.env_remove("CARGO_TARGET_DIR");
|
||||
$(cmd.env(stringify!($env_k), $env_v);)*
|
||||
|
||||
cmd_str = format!("{:?}", cmd);
|
||||
|
||||
cmd.output()
|
||||
.map(crate::util::Output::from)
|
||||
};
|
||||
|
||||
if let Ok(out) = out.as_ref() {
|
||||
println!("rust-script cmd: {}", cmd_str);
|
||||
println!("rust-script stdout:");
|
||||
println!("-----");
|
||||
println!("{}", out.stdout);
|
||||
println!("-----");
|
||||
println!("rust-script stderr:");
|
||||
println!("-----");
|
||||
println!("{}", out.stderr);
|
||||
println!("-----");
|
||||
}
|
||||
|
||||
drop(cargo_lock);
|
||||
|
||||
out
|
||||
}
|
||||
};
|
||||
|
||||
($($args:expr),* $(,)*) => {
|
||||
rust_script!(#[env()] $($args),*)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! with_output_marker {
|
||||
(prelude $p:expr; $e:expr) => {
|
||||
format!(concat!($p, "{}", $e), crate::util::OUTPUT_MARKER_CODE)
|
||||
};
|
||||
|
||||
($e:expr) => {
|
||||
format!(concat!("{}", $e), crate::util::OUTPUT_MARKER_CODE)
|
||||
};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
#[doc(hidden)]
|
||||
pub static ref CARGO_MUTEX: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
pub const OUTPUT_MARKER: &str = "--output--";
|
||||
pub const OUTPUT_MARKER_CODE: &str = "println!(\"--output--\");";
|
||||
|
||||
pub struct Output {
|
||||
pub status: ::std::process::ExitStatus,
|
||||
pub stdout: String,
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub fn stdout_output(&self) -> &str {
|
||||
assert!(self.success());
|
||||
for marker in self.stdout.matches(OUTPUT_MARKER) {
|
||||
let i = subslice_offset(&self.stdout, marker).expect("couldn't find marker in output");
|
||||
let before_cp = self.stdout[..i].chars().rev().next().unwrap_or('\n');
|
||||
if !(before_cp == '\r' || before_cp == '\n') {
|
||||
continue;
|
||||
}
|
||||
let after = &self.stdout[i + OUTPUT_MARKER.len()..];
|
||||
let after_cp = after.chars().next().expect("couldn't find cp after marker");
|
||||
if !(after_cp == '\r' || after_cp == '\n') {
|
||||
continue;
|
||||
}
|
||||
return after;
|
||||
}
|
||||
panic!("could not find `{}` in script output", OUTPUT_MARKER);
|
||||
}
|
||||
|
||||
pub fn success(&self) -> bool {
|
||||
self.status.success()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::std::process::Output> for Output {
|
||||
fn from(v: ::std::process::Output) -> Self {
|
||||
Self {
|
||||
status: v.status,
|
||||
stdout: String::from_utf8(v.stdout).unwrap(),
|
||||
stderr: String::from_utf8(v.stderr).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn subslice_offset(outer: &str, inner: &str) -> Option<usize> {
|
||||
let outer_beg = outer.as_ptr() as usize;
|
||||
let inner = inner.as_ptr() as usize;
|
||||
if inner < outer_beg || inner > outer_beg.wrapping_add(outer.len()) {
|
||||
None
|
||||
} else {
|
||||
Some(inner.wrapping_sub(outer_beg))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user