From 1ecac4625733d7cb36a3dc0fbbb4a12561575ac3 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 10 Jul 2023 16:52:09 +0200 Subject: [PATCH 1/5] Cargo: Remove `cargo_fetch` dependency and big refactorings --- Cargo.lock | 1121 +---------------------- Cargo.toml | 2 +- cargo-marker/Cargo.toml | 6 +- cargo-marker/src/backend.rs | 100 ++ cargo-marker/src/backend/driver.rs | 170 ++++ cargo-marker/src/backend/lints.rs | 38 + cargo-marker/src/backend/lints/build.rs | 70 ++ cargo-marker/src/backend/lints/fetch.rs | 163 ++++ cargo-marker/src/backend/toolchain.rs | 181 ++++ cargo-marker/src/cli.rs | 24 +- cargo-marker/src/config.rs | 224 +++-- cargo-marker/src/driver.rs | 370 -------- cargo-marker/src/lints.rs | 200 ---- cargo-marker/src/main.rs | 195 +--- cargo-marker/src/utils.rs | 14 + 15 files changed, 957 insertions(+), 1921 deletions(-) create mode 100644 cargo-marker/src/backend.rs create mode 100644 cargo-marker/src/backend/driver.rs create mode 100644 cargo-marker/src/backend/lints.rs create mode 100644 cargo-marker/src/backend/lints/build.rs create mode 100644 cargo-marker/src/backend/lints/fetch.rs create mode 100644 cargo-marker/src/backend/toolchain.rs delete mode 100644 cargo-marker/src/driver.rs delete mode 100644 cargo-marker/src/lints.rs create mode 100644 cargo-marker/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index d5dc413b..de155c7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - [[package]] name = "aho-corasick" version = "1.0.2" @@ -71,7 +62,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -81,7 +72,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -90,12 +81,6 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "autocfg" version = "1.1.0" @@ -117,12 +102,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "bitflags" version = "1.3.2" @@ -135,24 +114,6 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" -[[package]] -name = "bitmaps" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -dependencies = [ - "typenum", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "bstr" version = "1.6.0" @@ -170,18 +131,6 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "bytesize" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38fcc2979eff34a4b84e1cf9a1e3da42a7d44b3b690a40cdcb23e3d556cfb2e5" - [[package]] name = "camino" version = "1.1.4" @@ -191,70 +140,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo" -version = "0.68.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5e8070173cd407a849cb3d231542f6781fe09cf52ae1c58fbb4d3ae01cf24d" -dependencies = [ - "anyhow", - "base64", - "bytesize", - "cargo-platform", - "cargo-util", - "clap", - "crates-io", - "curl", - "curl-sys", - "env_logger", - "filetime", - "flate2", - "fwdansi", - "git2", - "git2-curl", - "glob", - "hex", - "hmac", - "home", - "http-auth", - "humantime", - "ignore", - "im-rc", - "indexmap 1.9.3", - "is-terminal", - "itertools", - "jobserver", - "lazy_static", - "lazycell", - "libc", - "libgit2-sys", - "log", - "memchr", - "opener", - "os_info", - "pathdiff", - "percent-encoding", - "rustc-workspace-hack", - "rustfix", - "semver", - "serde", - "serde-value", - "serde_ignored", - "serde_json", - "sha1", - "shell-escape", - "strip-ansi-escapes", - "tar", - "tempfile", - "termcolor", - "toml_edit 0.15.0", - "unicode-width", - "unicode-xid", - "url", - "walkdir", - "winapi", -] - [[package]] name = "cargo-platform" version = "0.1.2" @@ -264,44 +149,11 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e2320a2b1242f9181a3347ae0884bb497e1853d299da99780fa1e96f9abe23" -dependencies = [ - "anyhow", - "core-foundation", - "filetime", - "hex", - "jobserver", - "libc", - "log", - "miow", - "same-file", - "sha2", - "shell-escape", - "tempfile", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "cargo_fetch" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce9709e3d591a17d00a9a39428ae772a3dfbef88b2ca5f17c4088a83339e51e6" -dependencies = [ - "cargo", - "semver", - "url", -] - [[package]] name = "cargo_marker" version = "0.1.0" dependencies = [ - "cargo_fetch", + "cargo_metadata", "clap", "once_cell", "serde", @@ -327,9 +179,6 @@ name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] [[package]] name = "cfg-if" @@ -405,65 +254,7 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cpufeatures" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -dependencies = [ - "libc", -] - -[[package]] -name = "crates-io" -version = "0.35.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2dfb6077da60207264ab2eb0e3734f02e0a0c50c347b32c728e42c6fbbf7e2e" -dependencies = [ - "anyhow", - "curl", - "percent-encoding", - "serde", - "serde_json", - "url", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", + "windows-sys", ] [[package]] @@ -485,83 +276,12 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.63+curl-8.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.0" @@ -576,7 +296,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -608,122 +328,12 @@ dependencies = [ "instant", ] -[[package]] -name = "filetime" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.2.16", - "windows-sys 0.48.0", -] - -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "libz-sys", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fwdansi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c1f5787fe85505d1f7777268db5103d80a7a374d2316a7ce262e57baf8f208" -dependencies = [ - "memchr", - "termcolor", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "gimli" version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -[[package]] -name = "git2" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" -dependencies = [ - "bitflags 1.3.2", - "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", -] - -[[package]] -name = "git2-curl" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7577f4e6341ba7c90d883511130a45b956c274ba5f4d205d9f9da990f654cd33" -dependencies = [ - "curl", - "git2", - "log", - "url", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" -dependencies = [ - "aho-corasick 0.7.20", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.0" @@ -736,102 +346,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "http-auth" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5430cacd7a1f9a02fbeb350dfc81a0e5ed42d81f3398cb0ba184017f85bdcfbc" -dependencies = [ - "memchr", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" -dependencies = [ - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "im-rc" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" -dependencies = [ - "bitmaps", - "rand_core", - "rand_xoshiro", - "sized-chunks", - "typenum", - "version_check", -] - [[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.0.0" @@ -839,7 +359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown", ] [[package]] @@ -859,7 +379,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -870,16 +390,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix 0.38.3", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", + "windows-sys", ] [[package]] @@ -888,56 +399,18 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" -[[package]] -name = "jobserver" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" -dependencies = [ - "libc", -] - -[[package]] -name = "kstring" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" -dependencies = [ - "static_assertions", -] - [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" -[[package]] -name = "libgit2-sys" -version = "0.14.2+1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" -dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - [[package]] name = "libloading" version = "0.8.0" @@ -945,43 +418,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" dependencies = [ "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "libnghttp2-sys" -version = "0.1.7+1.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "windows-sys", ] [[package]] @@ -1055,100 +492,34 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "miow" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" -dependencies = [ - "windows-sys 0.42.0", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "opener" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" -dependencies = [ - "bstr", - "winapi", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" +name = "memchr" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] -name = "openssl-sys" -version = "0.9.90" +name = "miniz_oxide" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "adler", ] [[package]] -name = "ordered-float" -version = "2.10.0" +name = "object" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ - "num-traits", + "memchr", ] [[package]] -name = "os_info" -version = "3.7.0" +name = "once_cell" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" -dependencies = [ - "log", - "serde", - "winapi", -] +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "owo-colors" @@ -1156,30 +527,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - [[package]] name = "pin-project-lite" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - [[package]] name = "proc-macro2" version = "1.0.63" @@ -1198,30 +551,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -1237,7 +566,7 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", "regex-automata", "regex-syntax", @@ -1249,7 +578,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", "regex-syntax", ] @@ -1266,12 +595,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-workspace-hack" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" - [[package]] name = "rustc_tools_util" version = "0.3.0" @@ -1310,7 +633,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1323,7 +646,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.3", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1332,24 +655,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] - [[package]] name = "semver" version = "1.0.17" @@ -1368,16 +673,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.167" @@ -1389,15 +684,6 @@ dependencies = [ "syn 2.0.23", ] -[[package]] -name = "serde_ignored" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6de9d103529a9ba50008099785839df1e6f40b4576ed4c000cbfdb051182b827" -dependencies = [ - "serde", -] - [[package]] name = "serde_json" version = "1.0.100" @@ -1418,28 +704,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sharded-slab" version = "0.1.4" @@ -1449,59 +713,12 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-escape" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" - -[[package]] -name = "sized-chunks" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strip-ansi-escapes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" -dependencies = [ - "vte", -] - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - [[package]] name = "syn" version = "1.0.109" @@ -1524,16 +741,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", -] - [[package]] name = "tempfile" version = "3.6.0" @@ -1543,18 +750,9 @@ dependencies = [ "autocfg", "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix 0.37.23", - "windows-sys 0.48.0", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", + "windows-sys", ] [[package]] @@ -1587,21 +785,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.7.6" @@ -1610,17 +793,8 @@ checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", - "toml_datetime 0.6.3", - "toml_edit 0.19.12", -] - -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" -dependencies = [ - "serde", + "toml_datetime", + "toml_edit", ] [[package]] @@ -1632,30 +806,16 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646" -dependencies = [ - "combine", - "indexmap 1.9.3", - "itertools", - "kstring", - "serde", - "toml_datetime 0.5.1", -] - [[package]] name = "toml_edit" version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" dependencies = [ - "indexmap 2.0.0", + "indexmap", "serde", "serde_spanned", - "toml_datetime 0.6.3", + "toml_datetime", "winnow", ] @@ -1701,12 +861,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - [[package]] name = "ui_test" version = "0.11.7" @@ -1729,50 +883,12 @@ dependencies = [ "tempfile", ] -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - [[package]] name = "unicode-ident" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "url" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "utf8parse" version = "0.2.1" @@ -1785,18 +901,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "visibility" version = "0.0.1" @@ -1808,114 +912,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "vte" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" -dependencies = [ - "arrayvec", - "utf8parse", - "vte_generate_state_changes", -] - -[[package]] -name = "vte_generate_state_changes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -1924,93 +927,51 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 2a689c72..00f41da0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ members = [ resolver = "2" [workspace.metadata.marker.lints] -marker_uitest = { path = "marker_uitest" } +marker_lints = { path = "./marker_lints" } diff --git a/cargo-marker/Cargo.toml b/cargo-marker/Cargo.toml index 7765b585..3ccd34a5 100644 --- a/cargo-marker/Cargo.toml +++ b/cargo-marker/Cargo.toml @@ -16,11 +16,11 @@ name = "cargo-marker" path = "src/main.rs" [dependencies] -clap = { version = "4.0.26", features = ["string"] } +clap = { version = "4.0", features = ["string"] } serde = { version = "1.0", features = ["derive"] } -toml = { version = "0.7.3" } +toml = { version = "0.7" } once_cell = "1.17.0" -cargo_fetch = "0.1.2" +cargo_metadata = "0.15.4" [features] default = [] diff --git a/cargo-marker/src/backend.rs b/cargo-marker/src/backend.rs new file mode 100644 index 00000000..cb54b8ad --- /dev/null +++ b/cargo-marker/src/backend.rs @@ -0,0 +1,100 @@ +//! The backend is the brains of rust-marker, it's responsible for installing or +//! finding the correct driver, building lints and start linting. The backend should +//! be decoupled from the frontend. Most of the time the frontend will be the +//! `cargo-marker` CLI. However, `cargo-marker` might also be used as a library for UI +//! tests later down the line. + +use std::{ + collections::HashMap, + ffi::{OsStr, OsString}, + path::PathBuf, +}; + +use crate::{config::LintDependencyEntry, ExitStatus}; + +use self::toolchain::Toolchain; + +pub mod driver; +pub mod lints; +pub mod toolchain; + +/// Markers configuration for any action that requires lint crates to be available. +/// +/// It's assumed that all paths in this struct are absolute paths. +#[derive(Debug)] +pub struct Config { + /// The base directory used by Marker to fetch and compile lints. + /// This will default to something like `./target/marker`. + /// + /// This should generally be used as a base path for everything. Notable + /// exceptions can be the installation of a driver or the compilation of + /// a lint for uitests. + pub marker_dir: PathBuf, + /// The list of lints. + pub lints: HashMap, + /// Additional flags, which should be passed to rustc during the compilation + /// of crates. + pub build_rustc_flags: String, + /// Indicates if this is a release or debug build. + pub debug_build: bool, + /// Indicates if this is a development build. + pub dev_build: bool, + pub toolchain: Toolchain, +} + +impl Config { + pub fn try_base_from(toolchain: Toolchain) -> Result { + Ok(Self { + marker_dir: toolchain.find_target_dir()?.join("marker"), + lints: HashMap::default(), + build_rustc_flags: String::new(), + debug_build: false, + dev_build: cfg!(feature = "dev-build"), + toolchain, + }) + } + + fn markers_target_dir(&self) -> PathBuf { + self.marker_dir.join("target") + } + + fn lint_crate_dir(&self) -> PathBuf { + self.marker_dir.join("lints") + } +} + +pub fn run_check(config: &Config, additional_cargo_args: &[String]) -> Result<(), ExitStatus> { + // If this is a dev build, we want to rebuild the driver before checking + if config.dev_build { + driver::install_driver(false, true, &config.build_rustc_flags)?; + } + + println!(); + println!("Compiling Lints:"); + let lints = lints::build_lints(config)?; + let lint_paths: Vec<_> = lints + .iter() + .map(|krate| OsString::from(krate.file.as_os_str())) + .collect(); + + println!(); + println!("Start linting:"); + + let mut cmd = config.toolchain.cargo_command(); + cmd.arg("check"); + cmd.args(additional_cargo_args); + + cmd.env("RUSTC_WORKSPACE_WRAPPER", config.toolchain.driver_path.as_os_str()); + cmd.env("MARKER_LINT_CRATES", lint_paths.join(OsStr::new(";"))); + let exit_status = cmd + .spawn() + .expect("could not run cargo") + .wait() + .expect("failed to wait for cargo?"); + + if exit_status.success() { + Ok(()) + } else { + Err(ExitStatus::MarkerCheckFailed) + } +} diff --git a/cargo-marker/src/backend/driver.rs b/cargo-marker/src/backend/driver.rs new file mode 100644 index 00000000..52b00d8e --- /dev/null +++ b/cargo-marker/src/backend/driver.rs @@ -0,0 +1,170 @@ +use std::{process::Command, str::from_utf8}; + +use once_cell::sync::Lazy; + +use crate::ExitStatus; + +use super::toolchain::{get_toolchain_folder, rustup_which, Toolchain}; + +#[cfg(unix)] +pub const MARKER_DRIVER_BIN_NAME: &str = "marker_rustc_driver"; +#[cfg(windows)] +pub const MARKER_DRIVER_BIN_NAME: &str = "marker_rustc_driver.exe"; + +/// This is the driver version and toolchain, that is used by the setup command +/// to install the driver. +pub static DEFAULT_DRIVER_INFO: Lazy = Lazy::new(|| DriverVersionInfo { + toolchain: "nightly-2023-06-01".to_string(), + version: "0.1.0".to_string(), + api_version: "0.1.0".to_string(), +}); + +/// The version info of one specific driver +pub struct DriverVersionInfo { + pub toolchain: String, + pub version: String, + pub api_version: String, +} + +impl DriverVersionInfo { + fn try_from_toolchain(toolchain: &Toolchain) -> Result { + if let Ok(output) = Command::new(toolchain.driver_path.as_os_str()) + .arg("--toolchain") + .output() + { + if !output.status.success() { + return Err(ExitStatus::DriverFailed); + } + + if let Ok(info) = from_utf8(&output.stdout) { + let mut toolchain = Err(ExitStatus::InvalidValue); + let mut driver_version = Err(ExitStatus::InvalidValue); + let mut api_version = Err(ExitStatus::InvalidValue); + for line in info.lines() { + if let Some(value) = line.strip_prefix("toolchain: ") { + toolchain = Ok(value.trim().to_string()); + } else if let Some(value) = line.strip_prefix("driver: ") { + driver_version = Ok(value.trim().to_string()); + } else if let Some(value) = line.strip_prefix("marker-api: ") { + api_version = Ok(value.trim().to_string()); + } + } + + return Ok(DriverVersionInfo { + toolchain: toolchain?, + version: driver_version?, + api_version: api_version?, + }); + } + } + + Err(ExitStatus::DriverFailed) + } +} + +pub fn print_driver_version(dev_build: bool) { + if let Ok(ts) = Toolchain::try_find_toolchain(dev_build, false) { + if let Ok(info) = DriverVersionInfo::try_from_toolchain(&ts) { + println!( + "rustc driver version: {} (toolchain: {}, api: {})", + info.version, info.toolchain, info.api_version + ); + } + } +} + +/// This tries to install the rustc driver specified in [`DEFAULT_DRIVER_INFO`]. +pub fn install_driver( + auto_install_toolchain: bool, + dev_build: bool, + additional_rustc_flags: &str, +) -> Result<(), ExitStatus> { + // The toolchain, driver version and api version should ideally be configurable. + // However, that will require more prototyping and has a low priority rn. + // See #60 + + // Prerequisites + let toolchain = &DEFAULT_DRIVER_INFO.toolchain; + if rustup_which(toolchain, "cargo", false).is_err() { + if auto_install_toolchain { + install_toolchain(toolchain)?; + } else { + eprintln!("Error: The required toolchain `{toolchain}` can't be found"); + eprintln!(); + eprintln!("You can install the toolchain by running: `rustup toolchain install {toolchain}`"); + eprintln!("Or by adding the `--auto-install-toolchain` flag"); + return Err(ExitStatus::InvalidToolchain); + } + } + + build_driver( + toolchain, + &DEFAULT_DRIVER_INFO.version, + dev_build, + additional_rustc_flags, + ) +} + +fn install_toolchain(toolchain: &str) -> Result<(), ExitStatus> { + let mut cmd = Command::new("rustup"); + + cmd.args(["toolchain", "install", toolchain]); + + let status = cmd + .spawn() + .expect("unable to start rustup to install the toolchain") + .wait() + .expect("unable to wait on rustup to install the toolchain"); + if status.success() { + Ok(()) + } else { + // The user can see rustup's output, as the command output was passed on + // to the user via the `.spawn()` call. + Err(ExitStatus::InvalidToolchain) + } +} + +/// This tries to compile the driver. +fn build_driver( + toolchain: &str, + version: &str, + dev_build: bool, + additional_rustc_flags: &str, +) -> Result<(), ExitStatus> { + if dev_build { + println!("Compiling rustc driver"); + } else { + println!("Compiling rustc driver v{version} with {toolchain}"); + } + + let mut rustc_flags = additional_rustc_flags.to_string(); + + // Build driver + let mut cmd = Command::new("cargo"); + if dev_build { + cmd.args(["build", "--bin", "marker_rustc_driver"]); + } else { + cmd.env("RUSTUP_TOOLCHAIN", toolchain); + cmd.args(["install", "marker_rustc_driver", "--version", version]); + rustc_flags += " --cap-lints=allow"; + + let install_root = get_toolchain_folder(toolchain)?; + cmd.arg("--root"); + cmd.arg(install_root.as_os_str()); + cmd.arg("--no-track"); + } + cmd.env("RUSTFLAGS", rustc_flags); + + let status = cmd + .spawn() + .expect("unable to start cargo install for the driver") + .wait() + .expect("unable to wait on cargo install for the driver"); + if status.success() { + Ok(()) + } else { + // The user can see cargo's output, as the command output was passed on + // to the user via the `.spawn()` call. + Err(ExitStatus::DriverInstallationFailed) + } +} diff --git a/cargo-marker/src/backend/lints.rs b/cargo-marker/src/backend/lints.rs new file mode 100644 index 00000000..c880d398 --- /dev/null +++ b/cargo-marker/src/backend/lints.rs @@ -0,0 +1,38 @@ +use std::path::PathBuf; + +use crate::ExitStatus; + +use super::Config; + +mod build; +mod fetch; + +/// This struct contains all information of a lint crate required to compile +/// the crate. See the [fetch] module for how external crates are fetched and +/// this info is retrieved. +#[derive(Debug)] +#[allow(unused)] +pub struct LintCrateSource { + /// The name of the package, for now we can assume that this is the name + /// that will be used to construct the dynamic library. + name: String, + /// The absolute path to the manifest of this lint crate + manifest: PathBuf, +} + +/// The information of a compiled lint crate. +#[derive(Debug)] +pub struct LintCrate { + /// The absolute path of the compiled crate, as a dynamic library. + pub file: PathBuf, +} + +/// This function fetches and builds all lints specified in the given [`Config`] +pub fn build_lints(config: &Config) -> Result, ExitStatus> { + // FIXME(xFrednet): Potentially handle local crates compiled for UI tests + // differently. Like running the build command in the project root. This + // would allow cargo to cache the compilation better. Right now normal + // Cargo and cargo-marker might invalidate each others caches. + let sources = fetch::fetch_crates(config)?; + build::build_lints(&sources, config) +} diff --git a/cargo-marker/src/backend/lints/build.rs b/cargo-marker/src/backend/lints/build.rs new file mode 100644 index 00000000..a9d03052 --- /dev/null +++ b/cargo-marker/src/backend/lints/build.rs @@ -0,0 +1,70 @@ +use std::ffi::OsStr; + +use crate::{backend::Config, ExitStatus}; + +use super::{LintCrate, LintCrateSource}; + +#[cfg(target_os = "linux")] +const DYNAMIC_LIB_FILE_ENDING: &str = "so"; +#[cfg(target_os = "macos")] +const DYNAMIC_LIB_FILE_ENDING: &str = "dylib"; +#[cfg(target_os = "windows")] +const DYNAMIC_LIB_FILE_ENDING: &str = "dll"; + +pub fn build_lints(sources: &[LintCrateSource], config: &Config) -> Result, ExitStatus> { + // By default Cargo doesn't provide the path of the compiled lint crate. + // As a work around, we use the `--out-dir` option to make cargo copy all + // created binaries into one folder. We then scan that folder and collect + // all dynamic libraries, assuming that they're lint crates. + + // Build lint crates + for lint_src in sources { + build_lint(lint_src, config)?; + } + + // Find lint lint crates + let lints_dir = config.lint_crate_dir(); + match std::fs::read_dir(&lints_dir) { + Ok(dir) => { + let ending = OsStr::new(DYNAMIC_LIB_FILE_ENDING); + let mut lints = vec![]; + for file in dir { + let file = file.unwrap().path(); + if file.extension() == Some(ending) { + lints.push(LintCrate { file }); + } + } + Ok(lints) + }, + Err(err) => { + // This shouldn't really be a point of failure. In this case, I'm + // more interested in the HOW? + panic!( + "unable to read lints dir after lint compilation: {} ({err:#?})", + lints_dir.display() + ); + }, + } +} + +fn build_lint(lint_src: &LintCrateSource, config: &Config) -> Result<(), ExitStatus> { + let mut cmd = config.toolchain.cargo_build_command(config, &lint_src.manifest); + + // Set output dir. This currently requires unstable options + cmd.arg("-Z"); + cmd.arg("unstable-options"); + cmd.arg("--out-dir"); + cmd.arg(config.lint_crate_dir().as_os_str()); + + let exit_status = cmd + .spawn() + .expect("could not run cargo") + .wait() + .expect("failed to wait for cargo?"); + + if !exit_status.success() { + return Err(ExitStatus::LintCrateBuildFail); + } + + Ok(()) +} diff --git a/cargo-marker/src/backend/lints/fetch.rs b/cargo-marker/src/backend/lints/fetch.rs new file mode 100644 index 00000000..b01b8156 --- /dev/null +++ b/cargo-marker/src/backend/lints/fetch.rs @@ -0,0 +1,163 @@ +//! This module is responsible for fetching the lint crates and returning the +//! absolute path of the lints, for further processing. +//! +//! Cargo sadly doesn't provide an official public interface, to fetch crates +//! from git and registries. This will hopefully come at one point (rust-lang/cargo#1861) +//! but until then, we have to do some manual fetching. +//! +//! This module uses a small hack. Marker creates a new Cargo project, with the +//! specified lint crates as dependencies. Then `cargo fetch` is called, which +//! will download the crates into Cargo's cache. The absolute path to the lints +//! can then be retrieved from `cargo metadata`. + +use std::{ + collections::HashMap, + fs::OpenOptions, + io::Write, + path::{Path, PathBuf}, +}; + +use cargo_metadata::{Metadata, MetadataCommand}; + +use crate::{backend::Config, config::LintDependencyEntry, ExitStatus}; + +use super::LintCrateSource; + +/// This function fetches and locates all lint crates specified in the given +/// configuration. +pub fn fetch_crates(config: &Config) -> Result, ExitStatus> { + // FIXME(xFrednet): Only create the dummy crate, if there is a non + // local dependency. + + let manifest = setup_dummy_crate(config)?; + + call_cargo_fetch(&manifest, config)?; + + let metadata = call_cargo_metadata(&manifest, config)?; + + Ok(extract_lint_crate_sources(&metadata, config)) +} + +/// This function sets up the dummy crate with all the lints listed as dependencies. +/// It returns the path of the manifest, if everything was successful. +fn setup_dummy_crate(config: &Config) -> Result { + /// A small hack, to have the lints namespaced under the `[dependencies]` section + #[derive(serde::Serialize)] + struct DepNamespace<'a> { + dependencies: &'a HashMap, + } + + // Manifest + let lints_as_deps = if let Ok(lints_as_deps) = toml::to_string(&DepNamespace { + dependencies: &config.lints, + }) { + lints_as_deps + } else { + unreachable!("a valid toml structure is enforced my rustc's type system"); + }; + let manifest_content = DUMMY_MANIFEST_TEMPLATE.to_string() + &lints_as_deps; + let manifest_path = config.marker_dir.join("Cargo.toml"); + write_to_file(&manifest_path, &manifest_content)?; + + // `./src/main.rs` file + write_to_file(&config.marker_dir.join("src").join("main.rs"), DUMMY_MAIN_CONTENT)?; + + Ok(manifest_path) +} + +fn write_to_file(path: &PathBuf, content: &str) -> Result<(), ExitStatus> { + if let Some(parent) = path.parent() { + // The result is ignored in this case. If the creation failed an error + // will be emitted when the file creation fails. It's easier to handle + // that case only once. + let _ = std::fs::create_dir_all(parent); + } + let mut file = match OpenOptions::new().create(true).write(true).open(path) { + Ok(file) => file, + Err(_) => { + // FIXME(xFrednet): Handle this case better by returning a custom status + // with more information, to help us and users with debugging. + return Err(ExitStatus::LintCrateFetchFailed); + }, + }; + + if file.write_all(content.as_bytes()).is_err() { + // FIXME(xFrednet): Also handle this error better + return Err(ExitStatus::LintCrateFetchFailed); + } + Ok(()) +} + +const DUMMY_MANIFEST_TEMPLATE: &str = r#" +# This is a dummy crate used by Marker, to get Cargo to fetch the lint crates +# as normal dependencies. The location of the fetched crates is then read using +# `cargo metadata`. + +[package] +name = "markers-dummy-crate-for-fetching" +version = "0.1.0" +edition = "2021" +publish = false + +# This prevents Cargo from searching the parent directories for a workspace. +[workspace] + +"#; + +const DUMMY_MAIN_CONTENT: &str = r#" + fn main() { + println!("Hey curious mind and welcome to Marker's internals."); + println!("This is just a dummy crate to fetch some dependencies."); + println!(); + println!("Achievement Unlocked: [Marker's hidden crate]"); + } +"#; + +fn call_cargo_fetch(manifest: &Path, config: &Config) -> Result<(), ExitStatus> { + let mut cmd = config.toolchain.cargo_command(); + cmd.arg("fetch"); + cmd.arg("--manifest-path"); + cmd.arg(manifest.as_os_str()); + + // Only fetch for the specified target. Cargo will just fetch everything, + // if the `--target` flag is not specified. + if let Ok(target) = std::env::var("TARGET") { + cmd.arg("--target"); + cmd.arg(target); + } + + let status = cmd + .spawn() + .expect("unable to start `cargo fetch` to fetch lint crates") + .wait() + .expect("unable to wait for `cargo fetch` to fetch lint crates"); + if status.success() { + Ok(()) + } else { + // The user can see cargo's output, as the command output was passed on + // to the user via the `.spawn()` call. + Err(ExitStatus::DriverInstallationFailed) + } +} + +fn call_cargo_metadata(manifest: &PathBuf, config: &Config) -> Result { + let res = MetadataCommand::new() + .cargo_path(&config.toolchain.cargo_path) + .manifest_path(manifest) + .exec(); + + // FIXME(xFrednet): Handle errors properly. + res.map_err(|_| ExitStatus::LintCrateFetchFailed) +} + +fn extract_lint_crate_sources(metadata: &Metadata, marker_config: &Config) -> Vec { + metadata + .packages + .iter() + .filter(|pkg| marker_config.lints.contains_key(&pkg.name)) + .map(|pkg| LintCrateSource { + name: pkg.name.clone(), + manifest: pkg.manifest_path.clone().into(), + }) + .collect() +} diff --git a/cargo-marker/src/backend/toolchain.rs b/cargo-marker/src/backend/toolchain.rs new file mode 100644 index 00000000..fe0693dc --- /dev/null +++ b/cargo-marker/src/backend/toolchain.rs @@ -0,0 +1,181 @@ +use std::{ + path::{Path, PathBuf}, + process::Command, +}; + +use cargo_metadata::MetadataCommand; + +use crate::{utils::to_os_str, ExitStatus}; + +use super::{ + driver::{DEFAULT_DRIVER_INFO, MARKER_DRIVER_BIN_NAME}, + Config, +}; + +#[derive(Debug)] +pub struct Toolchain { + pub(crate) driver_path: PathBuf, + /// The Cargo binary that should be used for all Cargo commands. Prefer this + /// over the `CARGO` environment value as this is the Cargo binary used for + /// the specified toolchain. + pub(crate) cargo_path: PathBuf, + /// The rustc toolchain this driver belongs to. This can be `None` during + /// custom builds where the driver was found but not the connected toolchain. + pub(crate) toolchain: Option, +} + +impl Toolchain { + /// This returns a command, calling the Cargo instance of the selected toolchain. + /// It may add additional flags for verbose output. + /// + /// See also [`Self::cargo_build_command`] if the commands is intended to build + /// a crate. + pub fn cargo_command(&self) -> Command { + let mut cmd = Command::new(&self.cargo_path); + + // In theory, it's not necessary to set the toolchain, as the comment + // takes the absolute path to the cargo of the toolchain. It's still + // better to set it, to keep everything consistent. + self.toolchain + .as_ref() + .map(|toolchain| cmd.env("RUSTUP_TOOLCHAIN", toolchain)); + + cmd + } + + pub fn cargo_build_command(&self, config: &Config, manifest: &Path) -> Command { + let mut cmd = self.cargo_command(); + cmd.arg("build"); + + // Manifest + cmd.arg("--manifest-path"); + cmd.arg(manifest.as_os_str()); + + // Target dir + cmd.arg("--target-dir"); + cmd.arg(config.markers_target_dir().as_os_str()); + + // Potential "--release" flag + if !config.debug_build { + cmd.arg("--release"); + } + + // Environment + cmd.env("RUSTFLAGS", &config.build_rustc_flags); + + cmd + } + + pub fn find_target_dir(&self) -> Result { + // FIXME(xFrednet): Handle errors properly. + let metadata = MetadataCommand::new() + .cargo_path(&self.cargo_path) + .exec() + .map_err(|_| ExitStatus::LintCrateFetchFailed)?; + + Ok(metadata.target_directory.into()) + } + + pub fn try_find_toolchain(dev_build: bool, verbose: bool) -> Result { + if dev_build { + Self::search_next_to_cargo_marker(verbose) + } else { + // First check if there is a rustc driver for the current toolchain. This + // allows the used to override the used toolchain with `+` or + // `rust-toolchain` + if let Ok(toolchain) = std::env::var("RUSTUP_TOOLCHAIN") { + if let Ok(info) = Self::search_toolchain(&toolchain, verbose) { + return Ok(info); + } + } + + // Next we check, if we can find a driver for the linked marker toolchain. + if let Ok(info) = Self::search_toolchain(&DEFAULT_DRIVER_INFO.toolchain, verbose) { + return Ok(info); + } + + // Check if this is a *weird* custom installation, where the driver is + // placed next to the `cargo-marker` binary for one reason or another. + if let Ok(path) = Self::search_next_to_cargo_marker(verbose) { + return Ok(path); + } + + Err(ExitStatus::MissingDriver) + } + } + + fn search_toolchain(toolchain: &str, verbose: bool) -> Result { + if let Ok(driver_path) = rustup_which(toolchain, "marker_rustc_driver", verbose) { + if let Ok(cargo_path) = rustup_which(toolchain, "cargo", verbose) { + return Ok(Toolchain { + driver_path, + cargo_path, + toolchain: Some(toolchain.to_string()), + }); + } + } + + Err(ExitStatus::MissingDriver) + } + + fn search_next_to_cargo_marker(verbose: bool) -> Result { + if let Ok(path) = std::env::current_exe() { + let driver_path = path.with_file_name(MARKER_DRIVER_BIN_NAME); + if verbose { + println!("Searching for driver at '{}'", driver_path.to_string_lossy()); + } + + if driver_path.exists() && driver_path.is_file() { + if verbose { + println!("Found driver at '{}'", driver_path.to_string_lossy()); + } + return Ok(Toolchain { + driver_path, + cargo_path: PathBuf::from( + std::env::var_os("CARGO").expect("expected environment value `CARGO` to be set"), + ), + toolchain: None, + }); + } + } + + Err(ExitStatus::MissingDriver) + } +} + +pub(crate) fn get_toolchain_folder(toolchain: &str) -> Result { + if let Ok(toolchain_cargo) = rustup_which(toolchain, "cargo", false) { + // ../toolchain/bin/cargo -> ../toolchain + if let Some(path) = toolchain_cargo.ancestors().nth(2) { + return Ok(path.to_path_buf()); + } + } + Err(ExitStatus::BadConfiguration) +} + +pub(crate) fn rustup_which(toolchain: &str, tool: &str, verbose: bool) -> Result { + if verbose { + println!("Searching for `{tool}` with rustup for toolchain `{toolchain}`"); + } + + if let Ok(output) = Command::new("rustup") + .env("RUSTUP_TOOLCHAIN", toolchain) + .args(["which", tool]) + .output() + { + // rustup will error, if it can't find the binary file. Therefore, + // we know that it exists if this succeeds + if output.status.success() { + if let Some(path_str) = to_os_str(output.stdout) { + let path = PathBuf::from(path_str); + if verbose { + println!("Found `{tool}` for `{toolchain}` at {}", path.to_string_lossy()); + } + + return Ok(path); + } + } + return Err(ExitStatus::MissingDriver); + } + Err(ExitStatus::ToolExecutionFailed) +} diff --git a/cargo-marker/src/cli.rs b/cargo-marker/src/cli.rs index f2c1114b..ff4e7c2a 100644 --- a/cargo-marker/src/cli.rs +++ b/cargo-marker/src/cli.rs @@ -1,13 +1,18 @@ +use std::collections::HashMap; + use clap::{builder::ValueParser, Arg, ArgAction, ArgMatches, Command}; -use crate::VERSION; +use crate::{ + config::{Config, LintDependency}, + VERSION, +}; const AFTER_HELP_MSG: &str = r#"CARGO ARGS All arguments after double dashes(`--`) will be passed to cargo. Run `cargo check --help` to see these options. EXAMPLES: - * `cargo marker -l ./marker_uitest` + * `cargo marker -l 'marker_uitest = { path = "./marker_lints" }'` "#; #[allow(clippy::struct_excessive_bools)] @@ -30,6 +35,21 @@ impl Flags { } } +pub fn collect_lint_deps(args: &ArgMatches) -> Option> { + if let Some(lints) = args.get_many::<&str>("lints") { + let mut virtual_manifest = "[workspace.metadata.marker.lints]\n".to_string(); + for dep in lints.copied() { + virtual_manifest.push_str(dep); + virtual_manifest.push('\n'); + } + + let Config { lints } = Config::try_from_str(&virtual_manifest).ok()?; + Some(lints) + } else { + None + } +} + pub fn get_clap_config() -> Command { Command::new(VERSION) .arg( diff --git a/cargo-marker/src/config.rs b/cargo-marker/src/config.rs index 6ffba367..0481f3c7 100644 --- a/cargo-marker/src/config.rs +++ b/cargo-marker/src/config.rs @@ -1,28 +1,30 @@ +//! This module is responsible for translating the `[workspace.metadata.marker]` +//! section in `Cargo.toml` files. +//! +//! The TOML format specifies that every TOML file must be a valid UTF-8. +//! ([source](https://toml.io/en/v1.0.0)) This allows Marker to just use +//! strings here, without worrying about OS specific string magic. + use std::{ collections::HashMap, fs::File, io::{self, Read}, - path::PathBuf, }; -use cargo_fetch::{GitReference, PackageSource}; -use serde::Deserialize; - -use toml::{from_str, Value}; +use serde::{Deserialize, Serialize}; -use crate::{ - lints::{LintCrateSpec, PackageName}, - ExitStatus, -}; +use crate::ExitStatus; const CARGO_TOML: &str = "Cargo.toml"; +/// Markers metadata section `workspace.metadata.marker` in `Cargo.toml` #[derive(Deserialize, Debug)] pub struct Config { - lints: HashMap, + /// A list of lints. + pub lints: HashMap, } -#[derive(Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug)] #[serde(untagged)] pub enum LintDependency { /// Version string like: `lint = "0.0.1"` @@ -32,51 +34,76 @@ pub enum LintDependency { Full(LintDependencyEntry), } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "lowercase")] -pub enum GitRef { - Rev(String), - Tag(String), - Branch(String), -} +impl LintDependency { + /// This function normalizes the struct, by making all paths absolute paths + fn normalize(&mut self) { + match self { + LintDependency::Full(full) => full.source.normalize(), + LintDependency::Simple(_) => {}, + } + } -impl From for GitReference { - fn from(value: GitRef) -> Self { - match value { - GitRef::Rev(rev) => GitReference::Revision(rev), - GitRef::Tag(tag) => GitReference::Tag(tag), - GitRef::Branch(branch) => GitReference::Branch(branch), + pub fn to_dep_entry(&self) -> LintDependencyEntry { + match self { + LintDependency::Simple(version) => LintDependencyEntry { + source: Source::Registry { + version: version.clone(), + registry: None, + }, + package: None, + default_features: None, + features: None, + }, + LintDependency::Full(entry) => entry.clone(), } } } -#[derive(Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LintDependencyEntry { + #[serde(flatten)] + source: Source, + package: Option, + // FIXME: Features are not supported yet, see https://github.com/rust-marker/marker/issues/81 + #[serde(rename = "default-features")] + default_features: Option, + features: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum Source { - // FIXME: Registries are not supported yet, see https://github.com/rust-marker/marker/issues/87 - Registry { - version: String, - registry: Option, - }, + /// A registry dependency, like `lint_crate = "1.0"` + Registry { version: String, registry: Option }, + /// A git dependency, like: `lint_crate = { git = "./lint_crate"}` Git { git: String, #[serde(flatten)] git_ref: Option, }, - Path { - path: String, - }, + /// A path dependency, like: `lint_crate = { path = "./lint_crate"}` + Path { path: String }, } -#[derive(Deserialize, Debug)] -pub struct LintDependencyEntry { - #[serde(flatten)] - source: Source, - package: Option, - // FIXME: Features are not supported yet, see https://github.com/rust-marker/marker/issues/81 - #[serde(rename = "default-features")] - default_features: Option, - features: Option>, +impl Source { + /// This function normalizes the struct, by making all paths absolute paths + fn normalize(&mut self) { + if let Source::Path { ref mut path } = self { + if let Ok(absolute_path) = std::fs::canonicalize(&path) { + if let Some(absolute_path) = absolute_path.to_str() { + *path = absolute_path.to_string(); + } + } + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "lowercase")] +pub enum GitRef { + Rev(String), + Tag(String), + Branch(String), } #[derive(Debug)] @@ -90,7 +117,7 @@ pub enum ConfigFetchError { /// `workspace.metadata.marker` has invalid structure InvalidStructure, /// `workspace.metadata.marker` doesn't exist - NotFound, + SectionNotFound, } impl ConfigFetchError { @@ -99,7 +126,7 @@ impl ConfigFetchError { ConfigFetchError::FileNotFound => eprintln!("`Cargo.toml` wasn't found"), ConfigFetchError::IoError(err) => eprintln!("IO error reading config: {err:?}"), ConfigFetchError::ParseError(err) => eprintln!("Can't parse config: {err:?}"), - ConfigFetchError::NotFound => eprintln!("Marker config wasn't found"), + ConfigFetchError::SectionNotFound => eprintln!("Marker config wasn't found"), ConfigFetchError::InvalidStructure => { eprintln!("`workspace.metadata.marker` has invalid structure"); return ExitStatus::WrongStructure; @@ -110,96 +137,57 @@ impl ConfigFetchError { } impl Config { - fn get_raw_manifest() -> Result { - let Ok(mut config_file) = File::open(CARGO_TOML) else { - return Err(ConfigFetchError::FileNotFound); - }; + pub fn try_from_manifest() -> Result { + let config_str = Self::load_raw_manifest()?; - let mut config_str = String::new(); - if let Err(e) = config_file.read_to_string(&mut config_str) { - return Err(ConfigFetchError::IoError(e)); - } - Ok(config_str) + Self::try_from_str(&config_str) } - pub fn get_marker_config() -> Result { - let config_str = Self::get_raw_manifest()?; - - let cargo_config = match from_str::(&config_str) { + pub fn try_from_str(config_str: &str) -> Result { + let cargo_config: toml::Value = match toml::from_str(config_str) { Ok(v) => v, Err(e) => return Err(ConfigFetchError::ParseError(e)), }; - let Some(config_value) = cargo_config.get("workspace").and_then(|v| v.get("metadata")).and_then(|v| v.get("marker")) else { - return Err(ConfigFetchError::NotFound); + let config_value = if let Some(value) = cargo_config + .get("workspace") + .and_then(|v| v.get("metadata")) + .and_then(|v| v.get("marker")) + { + value + } else { + return Err(ConfigFetchError::SectionNotFound); }; - let Some(marker_config) = config_value.clone().try_into::().ok() else { + let mut config: Config = if let Ok(config) = config_value.clone().try_into() { + config + } else { return Err(ConfigFetchError::InvalidStructure); }; - Ok(marker_config) - } + config.normalize(); - pub fn collect_crates(self) -> Result, ExitStatus> { - self.lints.into_iter().map(dep_to_spec).collect() + Ok(config) } -} -macro_rules! unsupported_fields { - ($name:expr, $dep:expr => [$($i:ident),+]) => { - $( - if let Some(ref $i) = $dep.$i { - eprintln!(concat!("warning: {} ({:?}): marker doesn't yet support `", stringify!($i), "` field"), $name, $i); - } - )+ - } -} + fn load_raw_manifest() -> Result { + // FIXME(xFrednet): Use `cargo locate-project` to find the `Cargo.toml` file + let Ok(mut config_file) = File::open(CARGO_TOML) else { + return Err(ConfigFetchError::FileNotFound); + }; -fn dep_to_spec((name, dep): (String, LintDependency)) -> Result { - let dep = match dep { - LintDependency::Simple(ver) => { - eprintln!("{name} ({ver}): marker does not yet support registries"); - return Err(ExitStatus::InvalidValue); - }, - LintDependency::Full(dep) => dep, - }; - - unsupported_fields!( - name, dep => [ - default_features, - features - ] - ); - - let pkg_name = if let Some(package) = dep.package { - PackageName::Renamed { - orig: package, - new: name.clone(), + // FIXME(xFrednet): Maybe load `Cargo.toml` with `toml` that allows to display + // warnings with a span + let mut config_str = String::new(); + if let Err(e) = config_file.read_to_string(&mut config_str) { + return Err(ConfigFetchError::IoError(e)); } - } else { - PackageName::Named(name.clone()) - }; - - match dep.source { - Source::Registry { version, .. } => { - eprintln!("{name} ({version}): marker does not yet support registries"); - Err(ExitStatus::BadConfiguration) - }, - Source::Git { git, git_ref } => { - let src = PackageSource::git(&git, git_ref.map(Into::into)).map_err(|e| { - eprintln!("{name}: {git} is not a valid git repository url ({e})"); - ExitStatus::InvalidValue - })?; - Ok(LintCrateSpec::new(pkg_name, None, src)) - }, - Source::Path { path } => { - let path: PathBuf = path.into(); - let src = PackageSource::path(path.clone()).map_err(|e| { - eprintln!("{name}: {} is not a valid lint crate path ({e})", path.display()); - ExitStatus::LintCrateNotFound - })?; - Ok(LintCrateSpec::new(pkg_name, None, src)) - }, + Ok(config_str) + } + + /// This function normalizes the config, to be generally applicable. Currently, + /// it normalizes all relative paths to be absolute paths instead. + fn normalize(&mut self) { + self.lints.iter_mut().for_each(|(_name, lint)| lint.normalize()); } } diff --git a/cargo-marker/src/driver.rs b/cargo-marker/src/driver.rs deleted file mode 100644 index f81424ad..00000000 --- a/cargo-marker/src/driver.rs +++ /dev/null @@ -1,370 +0,0 @@ -//! This module hosts functions required to run rustc as a driver. -//! -//! The rustc driver depends on rustc's unstable interface. This means -//! that each driver version is bound to a specific version of rustc. The same -//! goes for Clippy. However, Clippy has the advantage, that it's distributes via -//! rustup, which handles the version matching for it. We're not so lucky, at -//! least not yet. Therefore, we're responsible that the driver is compiled and -//! run with the correct toolchain. -//! -//! If no driver is installed, the user will be requested to run the setup command. -//! That command will first ensure that the required toolchain is installed and then -//! run `cargo install` for the driver with a specific toolchain. The version and -//! toolchain are hardcoded in this crate. - -use std::{ffi::OsString, path::PathBuf, process::Command, str::from_utf8}; - -use once_cell::sync::Lazy; - -use crate::{cli::Flags, ExitStatus}; - -#[cfg(unix)] -const MARKER_DRIVER_BIN_NAME: &str = "marker_rustc_driver"; -#[cfg(windows)] -const MARKER_DRIVER_BIN_NAME: &str = "marker_rustc_driver.exe"; - -/// This is the driver version and toolchain, that is used by the setup command -/// to install the driver. -static DEFAULT_DRIVER_INFO: Lazy = Lazy::new(|| VersionInfo { - toolchain: "nightly-2023-06-01".to_string(), - version: "0.1.0".to_string(), - api_version: "0.1.0".to_string(), -}); - -pub struct VersionInfo { - toolchain: String, - version: String, - api_version: String, -} - -pub fn print_driver_version(flags: &Flags) { - if let Ok(info) = RunInfo::find_driver_location(flags) { - if let Ok(driver) = info.fetch_version_info() { - println!( - "rustc driver version: {} (toolchain: {}, api: {})", - driver.version, driver.toolchain, driver.api_version - ); - } - } -} - -/// This tries to install the rustc driver specified in [`DEFAULT_DRIVER_INFO`]. -pub fn install_driver(flags: &Flags, auto_install_toolchain: bool) -> Result<(), ExitStatus> { - // The toolchain, driver version and api version should ideally be configurable. - // However, that will require more prototyping and has a low priority rn. - // See #60 - - // Prerequisites - let toolchain = &DEFAULT_DRIVER_INFO.toolchain; - if rustup_which(toolchain, "cargo", false).is_err() { - if auto_install_toolchain { - install_toolchain(toolchain, flags)?; - } else { - eprintln!("Error: The required toolchain `{toolchain}` can't be found"); - eprintln!(); - eprintln!("You can install the toolchain by running: `rustup toolchain install {toolchain}`"); - eprintln!("Or by adding the `--auto-install-toolchain` flag"); - return Err(ExitStatus::InvalidToolchain); - } - } - - build_driver(toolchain, &DEFAULT_DRIVER_INFO.version, flags)?; - - RunInfo::find_driver_location(flags).map(|_| ()) -} - -fn install_toolchain(toolchain: &str, flags: &Flags) -> Result<(), ExitStatus> { - let mut cmd = Command::new("rustup"); - - if flags.verbose { - cmd.arg("--verbose"); - } - - cmd.args(["toolchain", "install", toolchain]); - - let status = cmd - .spawn() - .expect("unable to start rustup to install the toolchain") - .wait() - .expect("unable to wait on rustup to install the toolchain"); - if status.success() { - Ok(()) - } else { - // The user can see rustup's output, as the command output was passed on - // to the user via the `.spawn()` call. - Err(ExitStatus::InvalidToolchain) - } -} - -/// This tries to compile the driver. If successful the driver binary will -/// be places next to the executable of `cargo-linter`. -fn build_driver(toolchain: &str, version: &str, flags: &Flags) -> Result<(), ExitStatus> { - if flags.dev_build { - println!("Compiling rustc driver"); - } else { - println!("Compiling rustc driver v{version} with {toolchain}"); - } - - // Build driver - let mut cmd = Command::new("cargo"); - - if !flags.dev_build { - cmd.env("RUSTUP_TOOLCHAIN", toolchain); - } - - if flags.verbose { - cmd.arg("--verbose"); - } - - let mut rustc_flags = if flags.forward_rust_flags { - std::env::var("RUSTFLAGS").unwrap_or_default() - } else { - String::new() - }; - - if flags.dev_build { - cmd.args(["build", "--bin", "marker_rustc_driver"]); - } else { - // FIXME: This is awkward, it looks like I reserved `marker_rustc_driver` - // as the crate name... I'll have to rename the other package -.- - // - // See: #143 - cmd.args(["install", "marker_rustc_driver", "--version", version]); - rustc_flags += " --cap-lints=allow"; - - let install_root = get_toolchain_folder(toolchain)?; - cmd.arg("--root"); - cmd.arg(install_root.as_os_str()); - cmd.arg("--no-track"); - } - cmd.env("RUSTFLAGS", rustc_flags); - - let status = cmd - .spawn() - .expect("unable to start cargo install for the driver") - .wait() - .expect("unable to wait on cargo install for the driver"); - if status.success() { - Ok(()) - } else { - // The user can see cargo's output, as the command output was passed on - // to the user via the `.spawn()` call. - Err(ExitStatus::DriverInstallationFailed) - } -} - -fn get_toolchain_folder(toolchain: &str) -> Result { - if let Ok(toolchain_cargo) = rustup_which(toolchain, "cargo", false) { - // ../toolchain/bin/cargo -> ../toolchain - if let Some(path) = toolchain_cargo.ancestors().nth(2) { - return Ok(path.to_path_buf()); - } - } - Err(ExitStatus::BadConfiguration) -} - -/// This validate function validates that a driver is available and -/// it fetches the data of the driver -pub fn validate_and_get_info(flags: &Flags, print_advice: bool) -> Result<(RunInfo, VersionInfo), ExitStatus> { - let search = RunInfo::find_driver_location(flags); - - if let Err(ExitStatus::MissingDriver) = search { - if print_advice { - eprintln!("Error: The driver could not be found."); - eprintln!(); - eprintln!("Try installing it via `cargo marker setup`"); - } - return Err(ExitStatus::MissingDriver); - } - - let run_info = search?; - let version_info = run_info.fetch_version_info()?; - Ok((run_info, version_info)) -} - -pub fn run_driver( - info: &RunInfo, - env: Vec<(OsString, OsString)>, - cargo_args: impl Iterator, - flags: &Flags, -) -> Result<(), ExitStatus> { - println!(); - println!("Start linting:"); - - let mut cmd = info.cargo_cmd(); - cmd.envs(env).arg("check").args(cargo_args); - if flags.verbose { - cmd.arg("--verbose"); - } - - let exit_status = cmd - .spawn() - .expect("could not run cargo") - .wait() - .expect("failed to wait for cargo?"); - - if exit_status.success() { - Ok(()) - } else { - Err(ExitStatus::MarkerCheckFailed) - } -} - -#[derive(Debug)] -pub struct RunInfo { - pub(crate) driver_path: PathBuf, - pub(crate) cargo_path: PathBuf, - pub(crate) toolchain: Option, -} - -impl RunInfo { - pub fn find_driver_location(flags: &Flags) -> Result { - if flags.dev_build { - Self::search_next_to_cargo_marker(flags) - } else { - // First check if there is a rustc driver for the current toolchain. This - // allows the used to override the used toolchain with `+` or - // `rust-toolchain` - if let Ok(toolchain) = std::env::var("RUSTUP_TOOLCHAIN") { - if let Ok(info) = Self::search_toolchain(&toolchain, flags) { - return Ok(info); - } - } - - // Next we check, if we can find a driver for the linked marker toolchain. - if let Ok(info) = Self::search_toolchain(&DEFAULT_DRIVER_INFO.toolchain, flags) { - return Ok(info); - } - - // Check if this is a *weird* custom installation, where the driver is - // placed next to the `cargo-marker` binary for one reason or another. - if let Ok(path) = Self::search_next_to_cargo_marker(flags) { - return Ok(path); - } - - Err(ExitStatus::MissingDriver) - } - } - - fn search_toolchain(toolchain: &str, flags: &Flags) -> Result { - if let Ok(driver_path) = rustup_which(toolchain, "marker_rustc_driver", flags.verbose) { - if let Ok(cargo_path) = rustup_which(toolchain, "cargo", flags.verbose) { - return Ok(RunInfo { - driver_path, - cargo_path, - toolchain: Some(toolchain.to_string()), - }); - } - } - - Err(ExitStatus::MissingDriver) - } - - fn search_next_to_cargo_marker(flags: &Flags) -> Result { - if let Ok(path) = std::env::current_exe() { - let driver_path = path.with_file_name(MARKER_DRIVER_BIN_NAME); - if flags.verbose { - println!("Searching for driver at '{}'", driver_path.to_string_lossy()); - } - - if driver_path.exists() && driver_path.is_file() { - if flags.verbose { - println!("Found driver at '{}'", driver_path.to_string_lossy()); - } - return Ok(RunInfo { - driver_path, - cargo_path: PathBuf::from( - std::env::var_os("CARGO").expect("expected environment value `CARGO` to be set"), - ), - toolchain: None, - }); - } - } - - Err(ExitStatus::MissingDriver) - } - - fn cargo_cmd(&self) -> Command { - let mut cmd = Command::new(&self.cargo_path); - - // In theory, it's not necessary to set the toolchain, as the comment - // above takes the absolute path to the cargo of the toolchain. It's - // still better to set it, to keep everything consistent. - self.toolchain - .as_ref() - .map(|toolchain| cmd.env("RUSTUP_TOOLCHAIN", toolchain)); - - cmd - } - - fn fetch_version_info(&self) -> Result { - if let Ok(output) = Command::new(self.driver_path.as_os_str()).arg("--toolchain").output() { - if !output.status.success() { - return Err(ExitStatus::DriverFailed); - } - - if let Ok(info) = from_utf8(&output.stdout) { - let mut toolchain = Err(ExitStatus::InvalidValue); - let mut driver_version = Err(ExitStatus::InvalidValue); - let mut api_version = Err(ExitStatus::InvalidValue); - for line in info.lines() { - if let Some(value) = line.strip_prefix("toolchain: ") { - toolchain = Ok(value.trim().to_string()); - } else if let Some(value) = line.strip_prefix("driver: ") { - driver_version = Ok(value.trim().to_string()); - } else if let Some(value) = line.strip_prefix("marker-api: ") { - api_version = Ok(value.trim().to_string()); - } - } - - return Ok(VersionInfo { - toolchain: toolchain?, - version: driver_version?, - api_version: api_version?, - }); - } - } - - Err(ExitStatus::DriverFailed) - } -} - -fn rustup_which(toolchain: &str, tool: &str, verbose: bool) -> Result { - if verbose { - println!("Searching for `{tool}` with rustup for toolchain `{toolchain}`"); - } - - if let Ok(output) = Command::new("rustup") - .env("RUSTUP_TOOLCHAIN", toolchain) - .args(["which", tool]) - .output() - { - // rustup will error, if it can't find the binary file. Therefore, - // we know that it exists if this succeeds - if output.status.success() { - if let Some(path_str) = to_os_str(output.stdout) { - let path = PathBuf::from(path_str); - if verbose { - println!("Found `{tool}` for `{toolchain}` at {}", path.to_string_lossy()); - } - - return Ok(path); - } - } - return Err(ExitStatus::MissingDriver); - } - Err(ExitStatus::ToolExecutionFailed) -} - -#[allow(clippy::unnecessary_wraps)] -fn to_os_str(bytes: Vec) -> Option { - #[cfg(unix)] - { - use std::os::unix::prelude::OsStringExt; - Some(OsString::from_vec(bytes)) - } - - // Windows paths are guaranteed to be valid UTF - #[cfg(windows)] - Some(OsString::from(String::from_utf8(bytes).ok()?)) -} diff --git a/cargo-marker/src/lints.rs b/cargo-marker/src/lints.rs deleted file mode 100644 index 8dbea87b..00000000 --- a/cargo-marker/src/lints.rs +++ /dev/null @@ -1,200 +0,0 @@ -use std::{ - ffi::OsString, - path::{Path, PathBuf}, - process::Command, -}; - -use crate::{cli::Flags, ExitStatus}; - -use cargo_fetch::{PackageFetcher, PackageSource}; - -/// Holds the "cargo name", and optionally the real name, of the package which contains the lint -/// crate. -/// -/// This struct is parsed from `Cargo.toml`, see variant documentation for more info. -pub enum PackageName { - /// Renamed - stores both "cargo name" and the real package name - /// ```toml - /// lint_b = { path = "...", package = "lint_c" } - /// ``` - /// Results in: - /// ```rust,no_run - /// PackageName::Renamed { orig: "lint_c", new: "lint_b" } - /// ``` - Renamed { orig: String, new: String }, - /// Not renamed - "cargo name" is the package name. - /// ```toml - /// lint_a = { path = "..." } - /// ``` - /// Results in: - /// ```rust,no_run - /// PackageName::Named("lint_a") - /// ``` - Named(String), -} - -/// Represents a downloaded package -struct DownloadedPackage { - /// Path to the package - path: PathBuf, - /// Optional package name, to specify during building. - /// - /// This is [`None`] if we don't rename the package. - package_name: Option, -} - -impl DownloadedPackage { - fn new(path: PathBuf, package_name: Option) -> Self { - Self { path, package_name } - } -} - -pub struct LintCrateSpec { - /// Name of the package which contains the lint crate. - /// - /// if the lint crate was supplied only from path, this is taken from - /// [`Path::file_name`], for example in case of - /// command-line arguments: - /// - /// `--lints ./marker_uitest` - /// - /// `marker_uitest` is the `package_name`. - package_name: PackageName, - /// Version requirement of the package, [`None`] is a wildcard requirement, aka "*". - version_req: Option, - /// Source to fetch the lint crate from. - source: PackageSource, -} - -impl LintCrateSpec { - pub fn new(package_name: PackageName, version_req: Option, source: PackageSource) -> Self { - Self { - package_name, - version_req, - source, - } - } - - fn fetch_many(specs: Vec) -> Result, String> { - let mut fetcher = PackageFetcher::new()?; - - // Packages which we don't need to identify, they just need to be downloaded and built. - // Basically: set of pkgs goes in - set of pathbufs goes out - let mut auto_fetch = vec![]; - - // Packages which we care to identify, because they need some special building flags - // like `--package=...` - let mut manual_fetch = vec![]; - - for spec in specs { - match spec.package_name { - PackageName::Named(s) => { - auto_fetch.push(fetcher.resolve_first(s, spec.version_req.as_deref(), &spec.source, None)?); - }, - PackageName::Renamed { orig, new } => manual_fetch.push(( - fetcher.resolve_first(orig, spec.version_req.as_deref(), &spec.source, None)?, - new, - )), - } - } - - let mut v: Vec<_> = fetcher - .fetch_many(&auto_fetch)? - .into_iter() - .map(|path| DownloadedPackage::new(path, None)) - .collect(); - - for package in manual_fetch { - let pkg = fetcher.fetch(package.0)?; - v.push(DownloadedPackage::new(pkg, Some(package.1))); - } - - Ok(v) - } - - /// Fetches and debug builds crates. The paths of built libraries - /// will be returned, if the operations were successful. - pub fn build_many(specs: Vec, target_dir: &Path, flags: &Flags) -> Result, ExitStatus> { - let pkg_paths = match Self::fetch_many(specs) { - Ok(p) => p, - Err(e) => { - eprintln!("Failed fetching lint crates: {e}"); - return Err(ExitStatus::LintCrateFetchFailed); - }, - }; - - pkg_paths - .into_iter() - .map(|p| build_local_lint_crate(&p.path, p.package_name, target_dir, flags)) - .collect() - } -} - -fn build_local_lint_crate( - krate: &Path, - pkg_name: Option, - target_dir: &Path, - flags: &Flags, -) -> Result { - if !krate.exists() { - eprintln!("The given lint can't be found, searched at: `{}`", krate.display()); - return Err(ExitStatus::LintCrateNotFound); - } - - let mut rustc_flags = if flags.forward_rust_flags { - std::env::var("RUSTFLAGS").unwrap_or_default() - } else { - String::new() - }; - rustc_flags += " --cap-lints=allow"; - - // Compile the lint crate - let mut cmd = Command::new("cargo"); - cmd.arg("build"); - if flags.verbose { - cmd.arg("--verbose"); - } - if let Some(name) = pkg_name { - cmd.arg("--package"); - cmd.arg(name); - } - let exit_status = cmd - .current_dir(std::fs::canonicalize(krate).unwrap()) - .args(["--lib", "--target-dir"]) - .arg(target_dir.as_os_str()) - .env("RUSTFLAGS", rustc_flags) - .spawn() - .expect("could not run cargo") - .wait() - .expect("failed to wait for cargo?"); - - if !exit_status.success() { - return Err(ExitStatus::LintCrateBuildFail); - } - - // Find the final binary and return the string - #[cfg(any(target_os = "linux", target_os = "macos"))] - let lib_file_prefix = "lib"; - #[cfg(target_os = "windows")] - let lib_file_prefix = ""; - - // FIXME: currently this expect, that the lib name is the same as the crate dir. - // See marker#60 - let mut file_name = OsString::from(lib_file_prefix); - file_name.push(krate.file_name().unwrap_or_default()); - // Here `debug` is attached as the crate is build with the `cargo build` command - let mut krate_path = target_dir.join("debug").join(file_name); - - #[cfg(target_os = "linux")] - krate_path.set_extension("so"); - #[cfg(target_os = "macos")] - krate_path.set_extension("dylib"); - #[cfg(target_os = "windows")] - krate_path.set_extension("dll"); - - if !krate_path.exists() && !krate_path.is_file() { - Err(ExitStatus::LintCrateLibNotFound) - } else { - Ok(krate_path) - } -} diff --git a/cargo-marker/src/main.rs b/cargo-marker/src/main.rs index 27883424..7d27f2cc 100644 --- a/cargo-marker/src/main.rs +++ b/cargo-marker/src/main.rs @@ -2,38 +2,25 @@ #![warn(clippy::pedantic)] #![warn(clippy::index_refutable_slice)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::manual_let_else)] // Rustfmt doesn't like `let ... else {` rn +mod backend; mod cli; mod config; -mod driver; -mod lints; - -use std::{ - ffi::{OsStr, OsString}, - fs::create_dir_all, - io, - path::Path, - process::exit, -}; - -use cargo_fetch::PackageSource; +mod utils; + +use std::collections::HashMap; + use cli::{get_clap_config, Flags}; use config::Config; -use driver::run_driver; -use lints::{LintCrateSpec, PackageName}; -use once_cell::sync::Lazy; - -use crate::driver::print_driver_version; const CARGO_ARGS_SEPARATOR: &str = "--"; const VERSION: &str = concat!("cargo-marker ", env!("CARGO_PKG_VERSION")); -const LINT_KRATES_BASE_DIR: &str = "./target/marker"; const NO_LINTS_ERROR: &str = concat!( "Please provide at least one valid lint crate, ", "with the `--lints` argument, ", "or `[workspace.metadata.marker.lints]` in `Cargo.toml`" ); -static MARKER_LINT_DIR: Lazy = Lazy::new(|| prepare_lint_build_dir("marker", "marker")); #[derive(Debug)] pub enum ExitStatus { @@ -69,54 +56,6 @@ pub enum ExitStatus { MarkerCheckFailed = 1000, } -/// This creates the absolute path for a given build directory. -fn prepare_lint_build_dir(dir_name: &str, info_name: &str) -> String { - if !Path::new("Cargo.toml").exists() { - // FIXME: This is a temporary check to ensure that we don't randomly create files. - // This should not be part of the release and maybe be replaced by something more - // elegant or removed completely. - eprintln!("Cargo manifest doesn't exist (`Cargo.toml`), most likely running in the wrong directory"); - exit(-1); - } - - let path = Path::new(LINT_KRATES_BASE_DIR).join(dir_name); - if !path.exists() { - create_dir_all(&path).unwrap_or_else(|_| panic!("Error while creating lint crate {info_name} directory")); - } - - std::fs::canonicalize(path) - .expect("This should find the directory, as we just created it") - .display() - .to_string() -} - -fn choose_lint_crates(args: &clap::ArgMatches, config: Option) -> Result, ExitStatus> { - match args.get_many::("lints") { - Some(v) => v - .map(|s| { - let p = Path::new(s); - let src = PackageSource::path(p).map_err(|e| { - eprintln!("{}: {e}", p.display()); - ExitStatus::LintCrateNotFound - })?; - Ok(LintCrateSpec::new( - PackageName::Named(p.file_name().unwrap_or_default().to_string_lossy().to_string()), - None, - src, - )) - }) - .collect::>(), - None => { - if let Some(config) = config { - config.collect_crates() - } else { - eprintln!("{NO_LINTS_ERROR}"); - Err(ExitStatus::NoLints) - } - }, - } -} - fn main() -> Result<(), ExitStatus> { let matches = get_clap_config().get_matches_from( std::env::args() @@ -132,110 +71,72 @@ fn main() -> Result<(), ExitStatus> { return Ok(()); } - let config = match Config::get_marker_config() { + // TODO: Remove old implementation thingies + // TODO: Probably next PR, but make uitest use the `cargo-marker` as a lib + + let config = match Config::try_from_manifest() { Ok(v) => Some(v), Err(e) => match e { - config::ConfigFetchError::NotFound => None, + config::ConfigFetchError::SectionNotFound => None, _ => return Err(e.emit_and_convert()), }, }; match matches.subcommand() { - Some(("setup", args)) => driver::install_driver(&flags, args.get_flag("auto-install-toolchain")), - Some(("check", args)) => run_check(choose_lint_crates(args, config)?, &flags), - None => run_check(choose_lint_crates(&matches, config)?, &flags), + Some(("setup", args)) => { + let rustc_flags = if flags.forward_rust_flags { + std::env::var("RUSTFLAGS").unwrap_or_default() + } else { + String::new() + }; + backend::driver::install_driver(args.get_flag("auto-install-toolchain"), flags.dev_build, &rustc_flags) + }, + Some(("check", args)) => run_check(args, config, &flags), + None => run_check(&matches, config, &flags), _ => unreachable!(), } } -fn run_check(crate_entries: Vec, flags: &Flags) -> Result<(), ExitStatus> { - // If this is a dev build, we want to recompile the driver before checking - if flags.dev_build { - driver::install_driver(flags, false)?; +fn run_check(args: &clap::ArgMatches, config: Option, flags: &Flags) -> Result<(), ExitStatus> { + // determine lints + let mut lints = HashMap::new(); + let deps = if let Some(deps) = cli::collect_lint_deps(args) { + deps + } else if let Some(config) = config { + config.lints + } else { + HashMap::new() + }; + for (name, dep) in deps { + lints.insert(name, dep.to_dep_entry()); } - // FIXME: Respect version info during lint crate compilation - let (run_info, _version_info) = driver::validate_and_get_info(flags, true)?; - - if crate_entries.is_empty() { + // Validation + if lints.is_empty() { eprintln!("{NO_LINTS_ERROR}"); return Err(ExitStatus::NoLints); } - println!(); - println!("Compiling Lints:"); - let target_dir = Path::new(&*MARKER_LINT_DIR); + // Configure backend + let toolchain = backend::toolchain::Toolchain::try_find_toolchain(flags.dev_build, flags.verbose)?; + let backend_conf = backend::Config { + dev_build: flags.dev_build, + lints, + ..backend::Config::try_base_from(toolchain)? + }; - let lint_crates: Vec = LintCrateSpec::build_many(crate_entries, target_dir, flags)? - .into_iter() - .map(OsString::from) + // Run backend + let additional_cargo_args: Vec<_> = std::env::args() + .skip_while(|c| c != CARGO_ARGS_SEPARATOR) + .skip(1) .collect(); - - #[rustfmt::skip] - let mut env = vec![ - (OsString::from("RUSTC_WORKSPACE_WRAPPER"), run_info.driver_path.as_os_str().to_os_string()), - (OsString::from("MARKER_LINT_CRATES"), lint_crates.join(OsStr::new(";"))), - ]; - if let Some(toolchain) = &run_info.toolchain { - env.push((OsString::from("RUSTUP_TOOLCHAIN"), toolchain.into())); - } - - if flags.test_build { - print_env(env).unwrap(); - Ok(()) - } else { - let cargo_args = std::env::args().skip_while(|c| c != CARGO_ARGS_SEPARATOR).skip(1); - run_driver(&run_info, env, cargo_args, flags) - } + backend::run_check(&backend_conf, &additional_cargo_args) } fn print_version(flags: &Flags) { println!("cargo-marker version: {}", env!("CARGO_PKG_VERSION")); if flags.verbose { - print_driver_version(flags); - } -} - -#[allow(clippy::unnecessary_wraps)] -fn print_env(env: Vec<(OsString, OsString)>) -> io::Result<()> { - // Operating systems are fun... So, this function prints out the environment - // values to the standard output. For Unix systems, this requires `OsStr` - // objects, as file names are just bytes and don't need to be valid UTF-8. - // Windows, on the other hand, restricts file names, but uses UTF-16. The - // restriction only makes it slightly better, since windows `OsString` version - // doesn't have a `bytes()` method. Rust additionally has a restriction on the - // stdout of windows, that it has to be valid UTF-8, which means more conversion. - // - // This would be so much easier if everyone followed the "UTF-8 Everywhere Manifesto" - - #[cfg(any(target_os = "linux", target_os = "macos"))] - { - use std::io::Write; - use std::os::unix::prelude::OsStrExt; - - // stdout is used directly, to print the `OsString`s without requiring - // them to be valid UTF-8 - let mut lock = io::stdout().lock(); - for (name, value) in env { - write!(lock, "env:")?; - lock.write_all(name.as_bytes())?; - write!(lock, "=")?; - lock.write_all(value.as_bytes())?; - writeln!(lock)?; - } + backend::driver::print_driver_version(flags.dev_build); } - - #[cfg(target_os = "windows")] - { - for (name, value) in env { - if let (Some(name), Some(value)) = (name.to_str(), value.to_str()) { - println!("env:{name}={value}"); - } else { - unreachable!("Windows requires it's file path to be valid UTF-16 AFAIK"); - } - } - } - - Ok(()) } diff --git a/cargo-marker/src/utils.rs b/cargo-marker/src/utils.rs new file mode 100644 index 00000000..5d0ce872 --- /dev/null +++ b/cargo-marker/src/utils.rs @@ -0,0 +1,14 @@ +use std::ffi::OsString; + +#[allow(clippy::unnecessary_wraps)] +pub fn to_os_str(bytes: Vec) -> Option { + #[cfg(unix)] + { + use std::os::unix::prelude::OsStringExt; + Some(OsString::from_vec(bytes)) + } + + // Windows paths are guaranteed to be valid UTF + #[cfg(windows)] + Some(OsString::from(String::from_utf8(bytes).ok()?)) +} From 57037cc3deb44307d98a7b9f16b3c1bae2a28a63 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 11 Jul 2023 12:19:43 +0200 Subject: [PATCH 2/5] Test, Cargo: Use `cargo-marker` as a lib crate in uitests --- Cargo.lock | 2 + cargo-marker/Cargo.toml | 5 +++ cargo-marker/src/backend.rs | 18 +++++--- cargo-marker/src/backend/driver.rs | 1 + cargo-marker/src/backend/toolchain.rs | 44 ++++++++++++------- cargo-marker/src/config.rs | 8 ++-- cargo-marker/src/exit.rs | 36 +++++++++++++++ cargo-marker/src/lib.rs | 63 +++++++++++++++++++++++++++ cargo-marker/src/main.rs | 41 ++--------------- marker_lints/Cargo.toml | 2 +- marker_lints/tests/uitest.rs | 52 +++------------------- marker_uitest/Cargo.toml | 1 + marker_uitest/tests/uitest.rs | 59 +++---------------------- 13 files changed, 167 insertions(+), 165 deletions(-) create mode 100644 cargo-marker/src/exit.rs create mode 100644 cargo-marker/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index de155c7c..b2165a71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,6 +460,7 @@ dependencies = [ name = "marker_lints" version = "0.1.0" dependencies = [ + "cargo_marker", "marker_api", "tempfile", "ui_test", @@ -479,6 +480,7 @@ dependencies = [ name = "marker_uitest" version = "0.1.0" dependencies = [ + "cargo_marker", "marker_api", "tempfile", "ui_test", diff --git a/cargo-marker/Cargo.toml b/cargo-marker/Cargo.toml index 3ccd34a5..f8e6ae04 100644 --- a/cargo-marker/Cargo.toml +++ b/cargo-marker/Cargo.toml @@ -14,6 +14,11 @@ description = "Marker's CLI interface to automatically compile and run lint crat [[bin]] name = "cargo-marker" path = "src/main.rs" +doc = false + +[lib] +name = "cargo_marker" +path = "src/lib.rs" [dependencies] clap = { version = "4.0", features = ["string"] } diff --git a/cargo-marker/src/backend.rs b/cargo-marker/src/backend.rs index cb54b8ad..f6434be5 100644 --- a/cargo-marker/src/backend.rs +++ b/cargo-marker/src/backend.rs @@ -12,7 +12,7 @@ use std::{ use crate::{config::LintDependencyEntry, ExitStatus}; -use self::toolchain::Toolchain; +use self::{lints::LintCrate, toolchain::Toolchain}; pub mod driver; pub mod lints; @@ -66,16 +66,12 @@ impl Config { pub fn run_check(config: &Config, additional_cargo_args: &[String]) -> Result<(), ExitStatus> { // If this is a dev build, we want to rebuild the driver before checking if config.dev_build { - driver::install_driver(false, true, &config.build_rustc_flags)?; + driver::install_driver(false, config.dev_build, &config.build_rustc_flags)?; } println!(); println!("Compiling Lints:"); let lints = lints::build_lints(config)?; - let lint_paths: Vec<_> = lints - .iter() - .map(|krate| OsString::from(krate.file.as_os_str())) - .collect(); println!(); println!("Start linting:"); @@ -85,7 +81,7 @@ pub fn run_check(config: &Config, additional_cargo_args: &[String]) -> Result<() cmd.args(additional_cargo_args); cmd.env("RUSTC_WORKSPACE_WRAPPER", config.toolchain.driver_path.as_os_str()); - cmd.env("MARKER_LINT_CRATES", lint_paths.join(OsStr::new(";"))); + cmd.env("MARKER_LINT_CRATES", to_marker_lint_crates_env(&lints)); let exit_status = cmd .spawn() .expect("could not run cargo") @@ -98,3 +94,11 @@ pub fn run_check(config: &Config, additional_cargo_args: &[String]) -> Result<() Err(ExitStatus::MarkerCheckFailed) } } + +pub fn to_marker_lint_crates_env(lints: &[LintCrate]) -> OsString { + let lint_paths: Vec<_> = lints + .iter() + .map(|krate| OsString::from(krate.file.as_os_str())) + .collect(); + lint_paths.join(OsStr::new(";")) +} diff --git a/cargo-marker/src/backend/driver.rs b/cargo-marker/src/backend/driver.rs index 52b00d8e..d6f3eac8 100644 --- a/cargo-marker/src/backend/driver.rs +++ b/cargo-marker/src/backend/driver.rs @@ -142,6 +142,7 @@ fn build_driver( // Build driver let mut cmd = Command::new("cargo"); if dev_build { + cmd.current_dir(std::fs::canonicalize("..").unwrap()); cmd.args(["build", "--bin", "marker_rustc_driver"]); } else { cmd.env("RUSTUP_TOOLCHAIN", toolchain); diff --git a/cargo-marker/src/backend/toolchain.rs b/cargo-marker/src/backend/toolchain.rs index fe0693dc..9b3f644b 100644 --- a/cargo-marker/src/backend/toolchain.rs +++ b/cargo-marker/src/backend/toolchain.rs @@ -78,7 +78,7 @@ impl Toolchain { pub fn try_find_toolchain(dev_build: bool, verbose: bool) -> Result { if dev_build { - Self::search_next_to_cargo_marker(verbose) + Self::search_target_dir(verbose) } else { // First check if there is a rustc driver for the current toolchain. This // allows the used to override the used toolchain with `+` or @@ -120,23 +120,35 @@ impl Toolchain { fn search_next_to_cargo_marker(verbose: bool) -> Result { if let Ok(path) = std::env::current_exe() { - let driver_path = path.with_file_name(MARKER_DRIVER_BIN_NAME); - if verbose { - println!("Searching for driver at '{}'", driver_path.to_string_lossy()); - } + return Self::search_directory(&path, verbose); + } - if driver_path.exists() && driver_path.is_file() { - if verbose { - println!("Found driver at '{}'", driver_path.to_string_lossy()); - } - return Ok(Toolchain { - driver_path, - cargo_path: PathBuf::from( - std::env::var_os("CARGO").expect("expected environment value `CARGO` to be set"), - ), - toolchain: None, - }); + Err(ExitStatus::MissingDriver) + } + + fn search_target_dir(verbose: bool) -> Result { + let metadata = MetadataCommand::new().exec().map_err(|_| ExitStatus::BadConfiguration)?; + let path = metadata.target_directory.as_std_path(); + Self::search_directory(&path.join("debug").join("dummy_file_name"), verbose) + } + + fn search_directory(path: &Path, verbose: bool) -> Result { + let driver_path = path.with_file_name(MARKER_DRIVER_BIN_NAME); + if verbose { + println!("Searching for driver at '{}'", driver_path.to_string_lossy()); + } + + if driver_path.exists() && driver_path.is_file() { + if verbose { + println!("Found driver at '{}'", driver_path.to_string_lossy()); } + return Ok(Toolchain { + driver_path, + cargo_path: PathBuf::from( + std::env::var_os("CARGO").expect("expected environment value `CARGO` to be set"), + ), + toolchain: None, + }); } Err(ExitStatus::MissingDriver) diff --git a/cargo-marker/src/config.rs b/cargo-marker/src/config.rs index 0481f3c7..030702cb 100644 --- a/cargo-marker/src/config.rs +++ b/cargo-marker/src/config.rs @@ -62,12 +62,12 @@ impl LintDependency { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct LintDependencyEntry { #[serde(flatten)] - source: Source, - package: Option, + pub(crate) source: Source, + pub(crate) package: Option, // FIXME: Features are not supported yet, see https://github.com/rust-marker/marker/issues/81 #[serde(rename = "default-features")] - default_features: Option, - features: Option>, + pub(crate) default_features: Option, + pub(crate) features: Option>, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/cargo-marker/src/exit.rs b/cargo-marker/src/exit.rs new file mode 100644 index 00000000..8661f250 --- /dev/null +++ b/cargo-marker/src/exit.rs @@ -0,0 +1,36 @@ +//! The error handling in this crate is really not great. This is a quick hack +//! anyone interested in fixing this would be highly appreciated!!! <3 + +#[derive(Debug)] +pub enum ExitStatus { + /// The toolchain validation failed. This could happen, if rustup is not + /// installed or the required toolchain is not installed. + InvalidToolchain = 100, + /// The execution of a tool, like rustup or cargo, failed. + ToolExecutionFailed = 101, + /// Unable to find the driver binary + MissingDriver = 200, + /// Nothing we can really do, but good to know. The user will have to analyze + /// the forwarded cargo output. + DriverInstallationFailed = 300, + /// A general collection status, for failures originating from the driver + DriverFailed = 400, + /// The lint crate build failed for some reason + LintCrateBuildFail = 500, + /// Lint crate could not be found + LintCrateNotFound = 501, + /// The lint crate has been build, but the resulting binary could not be found. + LintCrateLibNotFound = 502, + /// Failed to fetch the lint crate + LintCrateFetchFailed = 550, + /// General "bad config" error + BadConfiguration = 600, + /// No lint crates were specified -> nothing to do + NoLints = 601, + /// Can't deserialise `workspace.metadata.marker.lints` properly + WrongStructure = 602, + /// An invalid configuration value was specified + InvalidValue = 603, + /// Check failed + MarkerCheckFailed = 1000, +} diff --git a/cargo-marker/src/lib.rs b/cargo-marker/src/lib.rs new file mode 100644 index 00000000..f2826194 --- /dev/null +++ b/cargo-marker/src/lib.rs @@ -0,0 +1,63 @@ +#![warn(clippy::pedantic)] +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::manual_let_else)] // Rustfmt doesn't like `let ... else {` rn + +#[allow(dead_code)] // Only check for dead code when the binary gets compiled +mod backend; +#[allow(dead_code)] // Only check for dead code when the binary gets compiled +mod config; +mod exit; +#[allow(dead_code)] // Only check for dead code when the binary gets compiled +mod utils; + +use std::{ + collections::HashMap, + ffi::OsString, + path::{Path, PathBuf}, +}; + +pub use exit::ExitStatus; + +use crate::{backend::Config, config::LintDependencyEntry}; + +#[derive(Debug)] +pub struct TestSetup { + pub rustc_path: PathBuf, + /// The environment values that should be set. The first element is the + /// value name, the second is the value the it should be set to. + pub env_vars: HashMap, +} + +pub fn test_setup(krate_name: String, krate_dir: &Path) -> Result { + let dev_build = cfg!(feature = "dev-build"); + + if dev_build { + backend::driver::install_driver(false, dev_build, "")?; + } + + let toolchain = backend::toolchain::Toolchain::try_find_toolchain(dev_build, true)?; + let mut config = Config::try_base_from(toolchain)?; + config.lints.insert( + krate_name, + LintDependencyEntry { + source: config::Source::Path { + path: krate_dir.to_str().unwrap().to_string(), + }, + package: None, + default_features: None, + features: None, + }, + ); + + println!(); + println!("Compiling Lints:"); + let lints = backend::lints::build_lints(&config)?; + let env_vars = HashMap::from([( + "MARKER_LINT_CRATES".to_string(), + backend::to_marker_lint_crates_env(&lints), + )]); + Ok(TestSetup { + rustc_path: config.toolchain.driver_path.clone(), + env_vars, + }) +} diff --git a/cargo-marker/src/main.rs b/cargo-marker/src/main.rs index 7d27f2cc..ee237721 100644 --- a/cargo-marker/src/main.rs +++ b/cargo-marker/src/main.rs @@ -1,12 +1,12 @@ #![doc = include_str!("../README.md")] #![warn(clippy::pedantic)] -#![warn(clippy::index_refutable_slice)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::manual_let_else)] // Rustfmt doesn't like `let ... else {` rn mod backend; mod cli; mod config; +mod exit; mod utils; use std::collections::HashMap; @@ -14,6 +14,8 @@ use std::collections::HashMap; use cli::{get_clap_config, Flags}; use config::Config; +pub use exit::ExitStatus; + const CARGO_ARGS_SEPARATOR: &str = "--"; const VERSION: &str = concat!("cargo-marker ", env!("CARGO_PKG_VERSION")); const NO_LINTS_ERROR: &str = concat!( @@ -22,40 +24,6 @@ const NO_LINTS_ERROR: &str = concat!( "or `[workspace.metadata.marker.lints]` in `Cargo.toml`" ); -#[derive(Debug)] -pub enum ExitStatus { - /// The toolchain validation failed. This could happen, if rustup is not - /// installed or the required toolchain is not installed. - InvalidToolchain = 100, - /// The execution of a tool, like rustup or cargo, failed. - ToolExecutionFailed = 101, - /// Unable to find the driver binary - MissingDriver = 200, - /// Nothing we can really do, but good to know. The user will have to analyze - /// the forwarded cargo output. - DriverInstallationFailed = 300, - /// A general collection status, for failures originating from the driver - DriverFailed = 400, - /// The lint crate build failed for some reason - LintCrateBuildFail = 500, - /// Lint crate could not be found - LintCrateNotFound = 501, - /// The lint crate has been build, but the resulting binary could not be found. - LintCrateLibNotFound = 502, - /// Failed to fetch the lint crate - LintCrateFetchFailed = 550, - /// General "bad config" error - BadConfiguration = 600, - /// No lint crates were specified -> nothing to do - NoLints = 601, - /// Can't deserialise `workspace.metadata.marker.lints` properly - WrongStructure = 602, - /// An invalid configuration value was specified - InvalidValue = 603, - /// Check failed - MarkerCheckFailed = 1000, -} - fn main() -> Result<(), ExitStatus> { let matches = get_clap_config().get_matches_from( std::env::args() @@ -71,9 +39,6 @@ fn main() -> Result<(), ExitStatus> { return Ok(()); } - // TODO: Remove old implementation thingies - // TODO: Probably next PR, but make uitest use the `cargo-marker` as a lib - let config = match Config::try_from_manifest() { Ok(v) => Some(v), Err(e) => match e { diff --git a/marker_lints/Cargo.toml b/marker_lints/Cargo.toml index 90404df1..24e16b01 100644 --- a/marker_lints/Cargo.toml +++ b/marker_lints/Cargo.toml @@ -18,4 +18,4 @@ marker_api = { path = "../marker_api" } marker_api = { path = "../marker_api" } ui_test = "0.11.5" tempfile = "3.5.0" - +cargo_marker = { path = "../cargo-marker", features = ["dev-build"] } diff --git a/marker_lints/tests/uitest.rs b/marker_lints/tests/uitest.rs index ed973792..8f7cd119 100644 --- a/marker_lints/tests/uitest.rs +++ b/marker_lints/tests/uitest.rs @@ -1,11 +1,15 @@ -use std::{collections::HashMap, env, fs, num::NonZeroUsize, path::PathBuf, process::Command}; +use std::{env, num::NonZeroUsize, path::PathBuf}; use ui_test::*; #[test] fn ui_test() -> ui_test::color_eyre::Result<()> { let path = "../target"; - let setup = run_test_setup(); + let setup = cargo_marker::test_setup( + env!("CARGO_PKG_NAME").to_string(), + &PathBuf::from(env!("CARGO_MANIFEST_DIR")), + ) + .unwrap(); for (key, val) in setup.env_vars { env::set_var(key, val); } @@ -44,47 +48,3 @@ fn ui_test() -> ui_test::color_eyre::Result<()> { status_emitter::Text, ) } - -struct TestSetup { - rustc_path: String, - /// The environment values that should be set. The first element is the - /// value name, the second is the value the it should be set to. - env_vars: HashMap, -} - -/// This function is currently quite slow and hacky. marker#155 should clean this -/// up and give us a speed up as well. -fn run_test_setup() -> TestSetup { - const CARGO_MARKER_INVOCATION: &[&str] = &["run", "--bin", "cargo-marker", "--features", "dev-build", "--"]; - - // ../rust-marker/marker_uitest - let current_dir = env::current_dir().unwrap(); - let lint_crate_src = fs::canonicalize(¤t_dir).unwrap(); - let mut cmd = Command::new("cargo"); - let output = cmd - .current_dir(current_dir.parent().unwrap()) - .args(CARGO_MARKER_INVOCATION) - .arg("-l") - .arg(lint_crate_src) - .arg("--test-setup") - .output() - .expect("Unable to run the test setup using `cargo-marker`"); - let stdout = String::from_utf8(output.stdout).unwrap(); - - if !output.status.success() { - let stderr = String::from_utf8(output.stderr).unwrap(); - panic!("Test setup failed:\n\n===STDOUT===\n{stdout}\n\n===STDERR===\n{stderr}\n"); - } - - let mut env_vars: HashMap<_, _> = stdout - .lines() - .filter_map(|line| line.strip_prefix("env:")) - .filter_map(|line| line.split_once('=')) - .map(|(var, val)| (var.to_string(), val.to_string())) - .collect(); - - TestSetup { - rustc_path: env_vars.remove("RUSTC_WORKSPACE_WRAPPER").unwrap(), - env_vars, - } -} diff --git a/marker_uitest/Cargo.toml b/marker_uitest/Cargo.toml index 69b2b0b4..8792c2b9 100644 --- a/marker_uitest/Cargo.toml +++ b/marker_uitest/Cargo.toml @@ -16,3 +16,4 @@ marker_api = { path = "../marker_api" } [dev-dependencies] ui_test = "0.11.5" tempfile = "3.5.0" +cargo_marker = { path = "../cargo-marker", features = ["dev-build"] } diff --git a/marker_uitest/tests/uitest.rs b/marker_uitest/tests/uitest.rs index 5fbf1208..c6b0c76a 100644 --- a/marker_uitest/tests/uitest.rs +++ b/marker_uitest/tests/uitest.rs @@ -1,9 +1,7 @@ use std::{ - collections::HashMap, - env, fs, + env, num::NonZeroUsize, path::{Path, PathBuf}, - process::Command, }; use ui_test::*; @@ -11,7 +9,11 @@ use ui_test::*; fn ui_test() -> ui_test::color_eyre::Result<()> { let path = "../target"; - let setup = run_test_setup(); + let setup = cargo_marker::test_setup( + env!("CARGO_PKG_NAME").to_string(), + &PathBuf::from(env!("CARGO_MANIFEST_DIR")), + ) + .unwrap(); for (key, val) in setup.env_vars { env::set_var(key, val); } @@ -70,52 +72,3 @@ fn test_name_filter() -> Box bool + Sync> { Box::new(|_| true) } } - -struct TestSetup { - rustc_path: String, - /// The environment values that should be set. The first element is the - /// value name, the second is the value the it should be set to. - env_vars: HashMap, -} - -/// This function calls `cargo-marker` for the basic test setup. For normal linting -/// crates this will need to be adjusted to run the installed `cargo-marker` version -/// -/// This function is currently slow and hacky. marker#155 should clean this up and -/// give us a speed up. -/// -/// In the future it would be nice to have a nice wrapper library as well. -fn run_test_setup() -> TestSetup { - const CARGO_MARKER_INVOCATION: &[&str] = &["run", "--bin", "cargo-marker", "--features", "dev-build", "--"]; - - // ../rust-marker/marker_uitest - let current_dir = env::current_dir().unwrap(); - let lint_crate_src = fs::canonicalize(¤t_dir).unwrap(); - let mut cmd = Command::new("cargo"); - let output = cmd - .current_dir(current_dir.parent().unwrap()) - .args(CARGO_MARKER_INVOCATION) - .arg("-l") - .arg(lint_crate_src) - .arg("--test-setup") - .output() - .expect("Unable to run the test setup using `cargo-marker`"); - let stdout = String::from_utf8(output.stdout).unwrap(); - - if !output.status.success() { - let stderr = String::from_utf8(output.stderr).unwrap(); - panic!("Test setup failed:\n\n===STDOUT===\n{stdout}\n\n===STDERR===\n{stderr}\n"); - } - - let mut env_vars: HashMap<_, _> = stdout - .lines() - .filter_map(|line| line.strip_prefix("env:")) - .filter_map(|line| line.split_once('=')) - .map(|(var, val)| (var.to_string(), val.to_string())) - .collect(); - - TestSetup { - rustc_path: env_vars.remove("RUSTC_WORKSPACE_WRAPPER").unwrap(), - env_vars, - } -} From 49e104d6f440483a62aee96d5e5cee1bf2ba355c Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 11 Jul 2023 14:18:12 +0200 Subject: [PATCH 3/5] Cargo: Auto delte lints dir, truncate virtual manifest and other fixes --- Cargo.toml | 1 + cargo-marker/src/backend/driver.rs | 1 - cargo-marker/src/backend/lints/build.rs | 42 +++++++++++++++++++++++-- cargo-marker/src/backend/lints/fetch.rs | 2 +- cargo-marker/src/backend/toolchain.rs | 6 ++-- cargo-marker/src/lib.rs | 10 +++++- 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00f41da0..d7a226be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ resolver = "2" [workspace.metadata.marker.lints] marker_lints = { path = "./marker_lints" } +marker_uitest = { path = "./marker_uitest" } diff --git a/cargo-marker/src/backend/driver.rs b/cargo-marker/src/backend/driver.rs index d6f3eac8..52b00d8e 100644 --- a/cargo-marker/src/backend/driver.rs +++ b/cargo-marker/src/backend/driver.rs @@ -142,7 +142,6 @@ fn build_driver( // Build driver let mut cmd = Command::new("cargo"); if dev_build { - cmd.current_dir(std::fs::canonicalize("..").unwrap()); cmd.args(["build", "--bin", "marker_rustc_driver"]); } else { cmd.env("RUSTUP_TOOLCHAIN", toolchain); diff --git a/cargo-marker/src/backend/lints/build.rs b/cargo-marker/src/backend/lints/build.rs index a9d03052..0bca1047 100644 --- a/cargo-marker/src/backend/lints/build.rs +++ b/cargo-marker/src/backend/lints/build.rs @@ -1,4 +1,4 @@ -use std::ffi::OsStr; +use std::{ffi::OsStr, path::Path}; use crate::{backend::Config, ExitStatus}; @@ -17,13 +17,16 @@ pub fn build_lints(sources: &[LintCrateSource], config: &Config) -> Result { let ending = OsStr::new(DYNAMIC_LIB_FILE_ENDING); @@ -47,6 +50,41 @@ pub fn build_lints(sources: &[LintCrateSource], config: &Config) -> Result Result<(), ExitStatus> { + if lints_dir.exists() { + // Delete all files + match std::fs::read_dir(lints_dir) { + Ok(dir) => { + let ending = OsStr::new(DYNAMIC_LIB_FILE_ENDING); + for file in dir { + let file = file.unwrap().path(); + if file.extension() == Some(ending) { + std::fs::remove_file(file).map_err(|_| ExitStatus::LintCrateBuildFail)?; + } else { + eprintln!( + "Marker's lint directory contains an unexpected file: {}", + file.display() + ); + return Err(ExitStatus::LintCrateBuildFail); + } + } + + // The dir should now be empty + std::fs::remove_dir(lints_dir).map_err(|_| ExitStatus::LintCrateBuildFail) + }, + Err(_) => Err(ExitStatus::LintCrateBuildFail), + } + } else { + Ok(()) + } +} + fn build_lint(lint_src: &LintCrateSource, config: &Config) -> Result<(), ExitStatus> { let mut cmd = config.toolchain.cargo_build_command(config, &lint_src.manifest); diff --git a/cargo-marker/src/backend/lints/fetch.rs b/cargo-marker/src/backend/lints/fetch.rs index b01b8156..c0c20107 100644 --- a/cargo-marker/src/backend/lints/fetch.rs +++ b/cargo-marker/src/backend/lints/fetch.rs @@ -72,7 +72,7 @@ fn write_to_file(path: &PathBuf, content: &str) -> Result<(), ExitStatus> { // that case only once. let _ = std::fs::create_dir_all(parent); } - let mut file = match OpenOptions::new().create(true).write(true).open(path) { + let mut file = match OpenOptions::new().create(true).truncate(true).write(true).open(path) { Ok(file) => file, Err(_) => { // FIXME(xFrednet): Handle this case better by returning a custom status diff --git a/cargo-marker/src/backend/toolchain.rs b/cargo-marker/src/backend/toolchain.rs index 9b3f644b..5c0b5fa0 100644 --- a/cargo-marker/src/backend/toolchain.rs +++ b/cargo-marker/src/backend/toolchain.rs @@ -127,12 +127,14 @@ impl Toolchain { } fn search_target_dir(verbose: bool) -> Result { - let metadata = MetadataCommand::new().exec().map_err(|_| ExitStatus::BadConfiguration)?; + let metadata = MetadataCommand::new() + .exec() + .map_err(|_| ExitStatus::BadConfiguration)?; let path = metadata.target_directory.as_std_path(); Self::search_directory(&path.join("debug").join("dummy_file_name"), verbose) } - fn search_directory(path: &Path, verbose: bool) -> Result { + fn search_directory(path: &Path, verbose: bool) -> Result { let driver_path = path.with_file_name(MARKER_DRIVER_BIN_NAME); if verbose { println!("Searching for driver at '{}'", driver_path.to_string_lossy()); diff --git a/cargo-marker/src/lib.rs b/cargo-marker/src/lib.rs index f2826194..079e446b 100644 --- a/cargo-marker/src/lib.rs +++ b/cargo-marker/src/lib.rs @@ -28,14 +28,22 @@ pub struct TestSetup { pub env_vars: HashMap, } +#[allow(clippy::missing_panics_doc, clippy::missing_errors_doc)] pub fn test_setup(krate_name: String, krate_dir: &Path) -> Result { let dev_build = cfg!(feature = "dev-build"); + let toolchain; if dev_build { + let lint_dir = std::env::current_dir().unwrap(); + std::env::set_current_dir(lint_dir.parent().unwrap()).unwrap(); backend::driver::install_driver(false, dev_build, "")?; + + toolchain = backend::toolchain::Toolchain::try_find_toolchain(dev_build, true)?; + std::env::set_current_dir(lint_dir).unwrap(); + } else { + toolchain = backend::toolchain::Toolchain::try_find_toolchain(dev_build, true)?; } - let toolchain = backend::toolchain::Toolchain::try_find_toolchain(dev_build, true)?; let mut config = Config::try_base_from(toolchain)?; config.lints.insert( krate_name, From a7c4b11d3bc6b9f1e5f28efadbe845c5417f2d5d Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 11 Jul 2023 14:33:36 +0200 Subject: [PATCH 4/5] Cargo: Update readme to reflect changes --- cargo-marker/README.md | 12 ++++++------ util/update-toolchain.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cargo-marker/README.md b/cargo-marker/README.md index 1644d71b..9e5ac21c 100644 --- a/cargo-marker/README.md +++ b/cargo-marker/README.md @@ -48,14 +48,14 @@ Marker requires lint crates to be specified. The best way, is to add them to the ```sh [workspace.metadata.marker.lints] -# Add a local crate as a path -local_lint_crate = { path = "path/to/lint_crate" } -# Add an external crate via git -git_lint_crate = { git = "https://github.com/rust-marker/marker" } +# A local crate as a path +marker_lints = { path = "./marker_lints" } +# An external crate via git +marker_lints = { git = "https://github.com/rust-marker/marker" } +# An external crate from a registry +marker_lints = "0.1.0" ``` -Lints from registries, like crates.io, are sadly not yet supported. See [rust-marker/marker#87](https://github.com/rust-marker/marker/issues/87). - ### Running Marker Running Marker is as simple as running its sibling *[Clippy]*. Navigate to your Rust project directory and run the following command: diff --git a/util/update-toolchain.sh b/util/update-toolchain.sh index 95154da4..05e3216f 100755 --- a/util/update-toolchain.sh +++ b/util/update-toolchain.sh @@ -2,7 +2,7 @@ if [[ $1 == nightly-????-??-?? ]] then - sed -i "s/nightly-2023-06-01/$1/g" ./marker_rustc_driver/src/main.rs ./rust-toolchain ./.github/workflows/* ./util/update-toolchain.sh ./cargo-marker/src/driver.rs ./cargo-marker/README.md + sed -i "s/nightly-2023-06-01/$1/g" ./marker_rustc_driver/src/main.rs ./rust-toolchain ./.github/workflows/* ./util/update-toolchain.sh .cargo-marker/src/backend/driver.rs ./cargo-marker/README.md else echo "Please enter a valid toolchain like \`nightly-2022-01-01\`" fi; From 73a2f8b265e236e80323d23efe76626f643099cd Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 11 Jul 2023 23:47:28 +0200 Subject: [PATCH 5/5] Cargo: Fix CI after refactorings --- cargo-marker/src/backend/lints/build.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cargo-marker/src/backend/lints/build.rs b/cargo-marker/src/backend/lints/build.rs index 0bca1047..92e645cf 100644 --- a/cargo-marker/src/backend/lints/build.rs +++ b/cargo-marker/src/backend/lints/build.rs @@ -11,6 +11,18 @@ const DYNAMIC_LIB_FILE_ENDING: &str = "dylib"; #[cfg(target_os = "windows")] const DYNAMIC_LIB_FILE_ENDING: &str = "dll"; +/// A list of file endings which are expected to be inside the lint crate dir. +/// It's assumed that these can be safely removed. +const ARTIFACT_ENDINGS: &[&str] = &[ + DYNAMIC_LIB_FILE_ENDING, + #[cfg(target_os = "windows")] + "exp", + #[cfg(target_os = "windows")] + "lib", + #[cfg(target_os = "windows")] + "pdb", +]; + pub fn build_lints(sources: &[LintCrateSource], config: &Config) -> Result, ExitStatus> { // By default Cargo doesn't provide the path of the compiled lint crate. // As a work around, we use the `--out-dir` option to make cargo copy all @@ -61,10 +73,10 @@ fn clear_lints_dir(lints_dir: &Path) -> Result<(), ExitStatus> { // Delete all files match std::fs::read_dir(lints_dir) { Ok(dir) => { - let ending = OsStr::new(DYNAMIC_LIB_FILE_ENDING); + let endings: Vec<_> = ARTIFACT_ENDINGS.iter().map(OsStr::new).collect(); for file in dir { let file = file.unwrap().path(); - if file.extension() == Some(ending) { + if file.extension().map_or(false, |ending| endings.contains(&ending)) { std::fs::remove_file(file).map_err(|_| ExitStatus::LintCrateBuildFail)?; } else { eprintln!(