flowey_lib_common/
run_cargo_clippy.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Clippy
5
6use crate::run_cargo_build::CargoBuildProfile;
7use flowey::node::prelude::*;
8
9#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone)]
10pub enum CargoPackage {
11    Workspace,
12    Crate(String),
13}
14
15flowey_request! {
16    pub struct Request {
17        pub in_folder: ReadVar<PathBuf>,
18        pub package: CargoPackage,
19        pub profile: CargoBuildProfile,
20        pub features: Option<Vec<String>>,
21        pub target: target_lexicon::Triple,
22        pub extra_env: Option<Vec<(String, String)>>,
23        pub exclude: ReadVar<Option<Vec<String>>>,
24        pub keep_going: bool,
25        pub all_targets: bool,
26        /// Wait for specified side-effects to resolve before running cargo-run.
27        ///
28        /// (e.g: to allow for some ambient packages / dependencies to get
29        /// installed).
30        pub pre_build_deps: Vec<ReadVar<SideEffect>>,
31        pub done: WriteVar<SideEffect>,
32    }
33}
34
35new_flow_node!(struct Node);
36
37impl FlowNode for Node {
38    type Request = Request;
39
40    fn imports(ctx: &mut ImportCtx<'_>) {
41        ctx.import::<crate::cfg_cargo_common_flags::Node>();
42        ctx.import::<crate::install_rust::Node>();
43    }
44
45    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
46        let rust_toolchain = ctx.reqv(crate::install_rust::Request::GetRustupToolchain);
47        let flags = ctx.reqv(crate::cfg_cargo_common_flags::Request::GetFlags);
48
49        for Request {
50            in_folder,
51            package,
52            profile,
53            features,
54            target,
55            extra_env,
56            exclude,
57            keep_going,
58            all_targets,
59            pre_build_deps,
60            done,
61        } in requests
62        {
63            ctx.req(crate::install_rust::Request::InstallTargetTriple(
64                target.clone(),
65            ));
66
67            ctx.emit_rust_step("cargo clippy", |ctx| {
68                pre_build_deps.claim(ctx);
69                done.claim(ctx);
70                let rust_toolchain = rust_toolchain.clone().claim(ctx);
71                let flags = flags.clone().claim(ctx);
72                let in_folder = in_folder.claim(ctx);
73                let exclude = exclude.claim(ctx);
74                move |rt| {
75                    let rust_toolchain = rt.read(rust_toolchain);
76                    let flags = rt.read(flags);
77                    let in_folder = rt.read(in_folder);
78                    let exclude = rt.read(exclude);
79
80                    let crate::cfg_cargo_common_flags::Flags { locked, verbose } = flags;
81
82                    let target = target.to_string();
83                    let features = features.map(|x| x.join(","));
84
85                    let cargo_profile = match &profile {
86                        CargoBuildProfile::Debug => "dev",
87                        CargoBuildProfile::Release => "release",
88                        CargoBuildProfile::Custom(s) => s,
89                    };
90
91                    let mut args = Vec::new();
92
93                    args.push("clippy");
94                    if verbose {
95                        args.push("--verbose");
96                    }
97                    if locked {
98                        args.push("--locked");
99                    }
100                    if keep_going {
101                        args.push("--keep-going");
102                    }
103                    if all_targets {
104                        args.push("--all-targets");
105                    }
106                    match &package {
107                        CargoPackage::Workspace => args.push("--workspace"),
108                        CargoPackage::Crate(crate_name) => {
109                            args.push("-p");
110                            args.push(crate_name);
111                        }
112                    }
113                    if let Some(features) = &features {
114                        args.push("--features");
115                        args.push(features);
116                    }
117                    args.push("--target");
118                    args.push(&target);
119                    args.push("--profile");
120                    args.push(cargo_profile);
121                    if let Some(exclude) = &exclude {
122                        for excluded_crate in exclude {
123                            args.push("--exclude");
124                            args.push(excluded_crate);
125                        }
126                    }
127
128                    let sh = xshell::Shell::new()?;
129
130                    sh.change_dir(in_folder);
131
132                    let mut cmd = if let Some(rust_toolchain) = &rust_toolchain {
133                        xshell::cmd!(sh, "rustup run {rust_toolchain} cargo")
134                    } else {
135                        xshell::cmd!(sh, "cargo")
136                    };
137
138                    // if running in CI, no need to waste time with incremental
139                    // build artifacts
140                    if !matches!(rt.backend(), FlowBackend::Local) {
141                        cmd = cmd.env("CARGO_INCREMENTAL", "0");
142                    }
143                    if let Some(env) = extra_env {
144                        for (key, val) in env {
145                            log::info!("env: {key}={val}");
146                            cmd = cmd.env(key, val);
147                        }
148                    }
149
150                    cmd.args(args).run()?;
151
152                    Ok(())
153                }
154            });
155        }
156
157        Ok(())
158    }
159}