Skip to main content

nom_kconfig/entry/source/
osource.rs

1/// For cases where it's okay for a pattern to match no files (or for a plain filename to not exist), a separate osource (optional source) statement is available.
2/// osource is a no-op if no file matches.
3/// <https://docs.zephyrproject.org/latest/build/kconfig/extensions.html>
4use nom::{branch::alt, bytes::complete::tag, sequence::delimited, IResult, Parser};
5
6use crate::{
7    entry::{
8        source::{expand_source_files, parse_filepath, parse_source_kconfig, JoinPathMode},
9        Source,
10    },
11    kconfig::Kconfig,
12    util::{ws, wsi},
13    KconfigInput,
14};
15
16pub type OSource = Source;
17
18pub fn parse_osource(input: KconfigInput) -> IResult<KconfigInput, OSource> {
19    let (input, _) = ws(tag("osource")).parse(input)?;
20    let (mut input, file) = wsi(alt((
21        delimited(tag("\""), parse_filepath, tag("\"")),
22        parse_filepath,
23    )))
24    .parse(input)?;
25    let expanded_files = expand_source_files(input.clone(), file, JoinPathMode::Root)?;
26    let mut sources = vec![];
27
28    for expanded_file in expanded_files {
29        let source_kconfig_file = input.extra.new_source_file(expanded_file);
30
31        if !source_kconfig_file.full_path().exists() {
32            sources.push(Kconfig {
33                file: file.to_string(),
34                ..Default::default()
35            });
36            continue;
37        }
38        let (variables, source) = parse_source_kconfig(input.clone(), source_kconfig_file)?;
39        input.extra.add_local_vars(variables);
40        sources.push(source);
41    }
42
43    Ok((input, OSource { kconfigs: sources }))
44}
45
46#[cfg(test)]
47use crate::attribute::r#type::ConfigType;
48#[cfg(test)]
49use crate::attribute::r#type::Type;
50#[cfg(test)]
51use crate::entry::config::Config;
52#[cfg(test)]
53use crate::Attribute;
54#[cfg(test)]
55use crate::Entry;
56#[cfg(test)]
57use std::path::PathBuf;
58
59#[test]
60fn test_parse_osource() {
61    assert_parsing_osource_eq(
62        r#"osource "Kconfig.simple""#,
63        Ok((
64            "",
65            OSource {
66                kconfigs: vec![Kconfig {
67                    file: "Kconfig.simple".to_string(),
68                    entries: vec![Entry::Config(Config {
69                        symbol: "KVM".to_string(),
70                        attributes: vec![Attribute::Type(ConfigType {
71                            r#type: Type::Tristate(None),
72                            r#if: None,
73                        })],
74                    })],
75                }],
76            },
77        )),
78    )
79}
80
81#[test]
82fn test_parse_osource_does_not_exist() {
83    assert_parsing_osource_eq(
84        r#"osource "this-file-does-not-exist""#,
85        Ok((
86            "",
87            OSource {
88                kconfigs: vec![Kconfig {
89                    file: "this-file-does-not-exist".to_string(),
90                    ..Default::default()
91                }],
92            },
93        )),
94    )
95}
96
97#[cfg(test)]
98fn assert_parsing_osource_eq(
99    input: &str,
100    expected: Result<(&str, OSource), nom::Err<nom::error::Error<KconfigInput>>>,
101) {
102    use crate::KconfigFile;
103
104    let res = parse_osource(KconfigInput::new_extra(
105        input,
106        KconfigFile {
107            root_dir: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"),
108            ..Default::default()
109        },
110    ))
111    .map(|r| (r.0.fragment().to_owned(), r.1));
112    assert_eq!(res, expected)
113}