1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use anyhow::Context;
5use clap::Parser;
6use std::error::Error;
7use std::path::PathBuf;
8
9mod cppdocs;
10mod license_headers_check;
11mod nodepackage;
12mod reuse_compliance_check;
13mod slintdocs;
14
15#[derive(Debug, clap::Parser)]
16#[command(author, version, about, long_about = None)]
17pub enum TaskCommand {
18 #[command(name = "check_license_headers")]
19 CheckLicenseHeaders(license_headers_check::LicenseHeaderCheck),
20 #[command(name = "cppdocs")]
21 CppDocs(CppDocsCommand),
22 #[command(name = "node_package")]
23 NodePackage(nodepackage::NodePackageOptions),
24 #[command(name = "check_reuse_compliance")]
25 ReuseComplianceCheck(reuse_compliance_check::ReuseComplianceCheck),
26 #[command(name = "slintdocs")]
27 SlintDocs(SlintDocsCommand),
28}
29
30#[derive(Debug, clap::Parser)]
31#[command(name = "xtask")]
32pub struct ApplicationArguments {
33 #[command(subcommand)]
34 pub command: TaskCommand,
35}
36
37#[derive(Debug, clap::Parser)]
38pub struct CppDocsCommand {
39 #[arg(long, action)]
40 show_warnings: bool,
41 #[arg(long, action)]
42 experimental: bool,
43}
44
45#[derive(Debug, clap::Parser)]
46pub struct SlintDocsCommand {}
47
48/// The root dir of the git repository
49fn root_dir() -> PathBuf {
50 let mut root: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
51 root.pop(); // $root/xtask -> $root
52 root
53}
54
55struct CommandOutput {
56 stdout: Vec<u8>,
57 stderr: Vec<u8>,
58}
59
60fn run_command<I, K, V>(program: &str, args: &[&str], env: I) -> anyhow::Result<CommandOutput>
61where
62 I: IntoIterator<Item = (K, V)>,
63 K: AsRef<std::ffi::OsStr>,
64 V: AsRef<std::ffi::OsStr>,
65{
66 let cmdline: impl Fn() -> String = || format!("{} {}", program, args.join(" "));
67 let output: Output = stdResult::process::Command::new(program)
68 .args(args)
69 .current_dir(root_dir())
70 .envs(vars:env)
71 .output()
72 .with_context(|| format!("Error launching {}", cmdline()))?;
73 let code: i32 = outputOption
74 .status
75 .code()
76 .with_context(|| format!("Command received callback: {}", cmdline()))?;
77 if code != 0 {
78 Err(anyhow::anyhow!(
79 "Command {} exited with non-zero status: {}\nstdout: {}\nstderr: {}",
80 cmdline(),
81 code,
82 String::from_utf8_lossy(&output.stdout),
83 String::from_utf8_lossy(&output.stderr)
84 ))
85 } else {
86 Ok(CommandOutput { stderr: output.stderr, stdout: output.stdout })
87 }
88}
89
90fn main() -> Result<(), Box<dyn Error>> {
91 match ApplicationArguments::parse().command {
92 TaskCommand::CheckLicenseHeaders(cmd: LicenseHeaderCheck) => cmd.check_license_headers()?,
93 TaskCommand::CppDocs(cmd: CppDocsCommand) => cppdocs::generate(cmd.show_warnings, cmd.experimental)?,
94 TaskCommand::SlintDocs(_) => slintdocs::generate()?,
95 TaskCommand::NodePackage(cmd: NodePackageOptions) => nodepackage::generate(cmd.sha1)?,
96 TaskCommand::ReuseComplianceCheck(cmd: ReuseComplianceCheck) => cmd.check_reuse_compliance()?,
97 };
98
99 Ok(())
100}
101