rune/cli/
check.rs

1use std::io::Write;
2use std::path::Path;
3use std::path::PathBuf;
4
5use anyhow::{Context, Result};
6
7use crate::cli::{visitor, AssetKind, CommandBase, Config, Entry, ExitCode, Io, SharedFlags};
8use crate::compile::FileSourceLoader;
9use crate::{Diagnostics, Options, Source, Sources};
10
11mod cli {
12    use std::path::PathBuf;
13    use std::vec::Vec;
14
15    use clap::Parser;
16
17    #[derive(Parser, Debug)]
18    #[command(rename_all = "kebab-case")]
19    pub(crate) struct Flags {
20        /// Exit with a non-zero exit-code even for warnings
21        #[arg(long)]
22        pub(super) warnings_are_errors: bool,
23        /// Explicit paths to check.
24        pub(super) check_path: Vec<PathBuf>,
25    }
26}
27
28pub(super) use cli::Flags;
29
30impl CommandBase for Flags {
31    #[inline]
32    fn is_debug(&self) -> bool {
33        true
34    }
35
36    #[inline]
37    fn is_workspace(&self, _: AssetKind) -> bool {
38        true
39    }
40
41    #[inline]
42    fn describe(&self) -> &str {
43        "Checking"
44    }
45
46    #[inline]
47    fn paths(&self) -> &[PathBuf] {
48        &self.check_path
49    }
50}
51
52pub(super) fn run(
53    io: &mut Io<'_>,
54    entry: &mut Entry<'_>,
55    c: &Config,
56    flags: &Flags,
57    shared: &SharedFlags,
58    options: &Options,
59    path: &Path,
60) -> Result<ExitCode> {
61    writeln!(io.stdout, "Checking: {}", path.display())?;
62
63    let context = shared.context(entry, c, None)?;
64
65    let source =
66        Source::from_path(path).with_context(|| format!("reading file: {}", path.display()))?;
67
68    let mut sources = Sources::new();
69
70    sources.insert(source)?;
71
72    let mut diagnostics = if shared.warnings || flags.warnings_are_errors {
73        Diagnostics::new()
74    } else {
75        Diagnostics::without_warnings()
76    };
77
78    let mut test_finder = visitor::FunctionVisitor::new(visitor::Attribute::None);
79    let mut source_loader = FileSourceLoader::new();
80
81    let _ = crate::prepare(&mut sources)
82        .with_context(&context)
83        .with_diagnostics(&mut diagnostics)
84        .with_options(options)
85        .with_visitor(&mut test_finder)?
86        .with_source_loader(&mut source_loader)
87        .build();
88
89    diagnostics.emit(&mut io.stdout.lock(), &sources)?;
90
91    if diagnostics.has_error() || flags.warnings_are_errors && diagnostics.has_warning() {
92        Ok(ExitCode::Failure)
93    } else {
94        Ok(ExitCode::Success)
95    }
96}