flowey_lib_hvlite/_jobs/
check_clippy.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Ensure the OpenVMM repo is `clippy` clean.
5
6use crate::init_openvmm_magicpath_openhcl_sysroot::OpenvmmSysrootArch;
7use crate::run_cargo_build::common::CommonArch;
8use crate::run_cargo_build::common::CommonPlatform;
9use crate::run_cargo_build::common::CommonProfile;
10use crate::run_cargo_build::common::CommonTriple;
11use flowey::node::prelude::*;
12use flowey_lib_common::run_cargo_build::CargoBuildProfile;
13use flowey_lib_common::run_cargo_build::CargoFeatureSet;
14use flowey_lib_common::run_cargo_clippy::CargoPackage;
15
16flowey_request! {
17    pub struct Request {
18        pub target: target_lexicon::Triple,
19        pub profile: CommonProfile,
20        pub done: WriteVar<SideEffect>,
21        pub also_check_misc_nostd_crates: bool,
22    }
23}
24
25new_simple_flow_node!(struct Node);
26
27impl SimpleFlowNode for Node {
28    type Request = Request;
29
30    fn imports(ctx: &mut ImportCtx<'_>) {
31        ctx.import::<crate::build_xtask::Node>();
32        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
33        ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
34        ctx.import::<crate::install_openvmm_rust_build_essential::Node>();
35        ctx.import::<crate::init_cross_build::Node>();
36        ctx.import::<flowey_lib_common::install_rust::Node>();
37        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
38        ctx.import::<flowey_lib_common::run_cargo_clippy::Node>();
39    }
40
41    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
42        let Request {
43            target,
44            profile,
45            done,
46            also_check_misc_nostd_crates,
47        } = request;
48
49        let flowey_platform = ctx.platform();
50        let flowey_arch = ctx.arch();
51
52        let (boot_target, uefi_target, sysroot_arch) = match target.architecture {
53            target_lexicon::Architecture::X86_64 => (
54                "x86_64-unknown-none",
55                "x86_64-unknown-uefi",
56                OpenvmmSysrootArch::X64,
57            ),
58            target_lexicon::Architecture::Aarch64(_) => (
59                "aarch64-unknown-linux-musl",
60                "aarch64-unknown-uefi",
61                OpenvmmSysrootArch::Aarch64,
62            ),
63            arch => anyhow::bail!("unsupported arch {arch}"),
64        };
65
66        let mut pre_build_deps = Vec::new();
67
68        // FIXME: this will go away once we have a dedicated cargo .config.toml
69        // for the openhcl _bin_. until we have that, we are building _every_
70        // musl target using the openhcl toolchain...
71
72        if matches!(target.environment, target_lexicon::Environment::Musl) {
73            pre_build_deps.push(
74                ctx.reqv(|v| crate::init_openvmm_magicpath_openhcl_sysroot::Request {
75                    arch: sysroot_arch,
76                    path: v,
77                })
78                .into_side_effect(),
79            );
80        }
81
82        ctx.req(flowey_lib_common::install_rust::Request::InstallTargetTriple(target.clone()));
83        if also_check_misc_nostd_crates {
84            ctx.req(
85                flowey_lib_common::install_rust::Request::InstallTargetTriple(
86                    target_lexicon::triple!(uefi_target),
87                ),
88            );
89            ctx.req(
90                flowey_lib_common::install_rust::Request::InstallTargetTriple(
91                    target_lexicon::triple!(boot_target),
92                ),
93            );
94        }
95
96        // TODO: install build tools for other platforms
97        if matches!(
98            ctx.platform(),
99            FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu)
100        ) {
101            pre_build_deps.push(ctx.reqv(|v| {
102                flowey_lib_common::install_dist_pkg::Request::Install {
103                    package_names: vec!["libssl-dev".into(), "build-essential".into()],
104                    done: v,
105                }
106            }));
107        }
108
109        pre_build_deps.push(ctx.reqv(crate::install_openvmm_rust_build_essential::Request));
110
111        // Cross compiling for MacOS isn't supported, but clippy still works
112        // with no additional dependencies
113        if !matches!(
114            target.operating_system,
115            target_lexicon::OperatingSystem::Darwin(_)
116        ) {
117            pre_build_deps.push(
118                ctx.reqv(|v| crate::init_cross_build::Request {
119                    target: target.clone(),
120                    injected_env: v,
121                })
122                .into_side_effect(),
123            );
124        }
125
126        let xtask_target = CommonTriple::Common {
127            arch: match flowey_arch {
128                FlowArch::X86_64 => CommonArch::X86_64,
129                FlowArch::Aarch64 => CommonArch::Aarch64,
130                arch => anyhow::bail!("unsupported arch {arch}"),
131            },
132            platform: match flowey_platform {
133                FlowPlatform::Windows => CommonPlatform::WindowsMsvc,
134                FlowPlatform::Linux(_) => CommonPlatform::LinuxGnu,
135                FlowPlatform::MacOs => CommonPlatform::MacOs,
136                platform => anyhow::bail!("unsupported platform {platform}"),
137            },
138        };
139
140        let xtask = ctx.reqv(|v| crate::build_xtask::Request {
141            target: xtask_target,
142            xtask: v,
143        });
144
145        let profile = match profile {
146            CommonProfile::Release => CargoBuildProfile::Release,
147            CommonProfile::Debug => CargoBuildProfile::Debug,
148        };
149
150        let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
151
152        let exclude = ctx.emit_rust_stepv("determine clippy exclusions", |ctx| {
153            let xtask = xtask.claim(ctx);
154            let repo_path = openvmm_repo_path.clone().claim(ctx);
155            move |rt| {
156                let xtask = rt.read(xtask);
157                let repo_path = rt.read(repo_path);
158
159                let mut exclude = vec!["guest_test_uefi".into()];
160
161                // packages depending on libfuzzer-sys are currently x86 only
162                if !(matches!(target.architecture, target_lexicon::Architecture::X86_64)
163                    && matches!(flowey_arch, FlowArch::X86_64))
164                {
165                    let xtask_bin = match xtask {
166                        crate::build_xtask::XtaskOutput::LinuxBin { bin, dbg: _ } => bin,
167                        crate::build_xtask::XtaskOutput::WindowsBin { exe, pdb: _ } => exe,
168                    };
169
170                    rt.sh.change_dir(repo_path);
171                    let output =
172                        flowey::shell_cmd!(rt, "{xtask_bin} fuzz list --crates").output()?;
173                    let output = String::from_utf8(output.stdout)?;
174
175                    let fuzz_crates = output.trim().split('\n').map(|s| s.to_owned());
176                    exclude.extend(fuzz_crates);
177
178                    exclude.push("chipset_device_fuzz".into());
179                    exclude.push("xtask_fuzz".into());
180                }
181
182                // packages requiring openssl-sys won't cross compile for macos
183                if matches!(
184                    target.operating_system,
185                    target_lexicon::OperatingSystem::Darwin(_)
186                ) {
187                    exclude.extend(
188                        ["openssl_kdf", "vmgs_lib", "disk_crypt", "crypto"].map(|x| x.into()),
189                    );
190                }
191
192                Ok(Some(exclude))
193            }
194        });
195
196        // HACK: the following behavior has been cargo-culted from our old
197        // CI, and at some point, we should actually improve the testing
198        // story on windows, so that we can run with FeatureSet::All in CI.
199        //
200        // On windows & mac, we can't build with all features, as many crates
201        // require openSSL for crypto, which isn't supported in CI yet.
202        let features = if matches!(
203            target.operating_system,
204            target_lexicon::OperatingSystem::Windows | target_lexicon::OperatingSystem::Darwin(_)
205        ) {
206            CargoFeatureSet::None
207        } else {
208            CargoFeatureSet::All
209        };
210
211        let mut reqs = vec![ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
212            in_folder: openvmm_repo_path.clone(),
213            package: CargoPackage::Workspace,
214            profile: profile.clone(),
215            features: features.clone(),
216            target,
217            extra_env: None,
218            exclude,
219            keep_going: true,
220            all_targets: true,
221            pre_build_deps: pre_build_deps.clone(),
222            done: v,
223        })];
224
225        if also_check_misc_nostd_crates {
226            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
227                in_folder: openvmm_repo_path.clone(),
228                package: CargoPackage::Crate("openhcl_boot".into()),
229                profile: profile.clone(),
230                features: features.clone(),
231                target: target_lexicon::triple!(boot_target),
232                extra_env: Some(vec![("MINIMAL_RT_BUILD".into(), "1".into())]),
233                exclude: ReadVar::from_static(None),
234                keep_going: true,
235                all_targets: false,
236                pre_build_deps: pre_build_deps.clone(),
237                done: v,
238            }));
239
240            // don't pass --all-targets, since that pulls in a std dependency
241            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
242                in_folder: openvmm_repo_path.clone(),
243                package: CargoPackage::Crate("guest_test_uefi".into()),
244                profile: profile.clone(),
245                features,
246                target: target_lexicon::triple!(uefi_target),
247                extra_env: None,
248                exclude: ReadVar::from_static(None),
249                keep_going: true,
250                all_targets: false,
251                pre_build_deps: pre_build_deps.clone(),
252                done: v,
253            }));
254        }
255
256        ctx.emit_side_effect_step(reqs, [done]);
257
258        Ok(())
259    }
260}