1mod build;
2mod config;
3mod dependency;
4pub mod languages;
5mod package;
6mod program;
7pub mod utils;
8
9use std::{
10 collections::HashMap,
11 env::{current_dir, set_current_dir},
12 path::{Path, PathBuf},
13};
14
15pub use build::{Build, BuildConfig};
16pub use config::{ModeTable, ModeTableConfig, Table, TableConfig};
17pub use dependency::{Dependency, DependencyConfig, DependencySource};
18pub use languages::{Language, LanguageConfig};
19pub use package::{Package, PackageConfig};
20pub use program::Program;
21
22use crate::{config::program::ProgramConfig, utils::TryAll};
23
24pub trait Shelling<T, P: AsRef<Path>> {
26 fn shelling(self, base: P) -> T;
29}
30
31pub trait Expand<T, P: AsRef<Path>> {
33 fn expand(self, base: P) -> T;
34}
35
36impl<P: AsRef<Path>> Expand<anyhow::Result<Vec<PathBuf>>, P> for Vec<String> {
37 fn expand(self, base: P) -> anyhow::Result<Vec<PathBuf>> {
38 let cpath = current_dir()?;
39 set_current_dir(&base)?;
40
41 let mut result = vec![];
43 for pattern in self.iter() {
44 for entry in glob::glob(pattern)? {
45 let path = entry?;
46 let path = if path.is_relative() {
47 base.as_ref().join(path)
48 } else {
49 path
50 };
51 result.push(path);
52 }
53 }
54
55 set_current_dir(cpath)?;
56 Ok(result)
57 }
58}
59
60#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
61pub struct RawConfig {
62 pub package: PackageConfig,
63 pub build: Option<BuildConfig>,
64 pub dependencies: Option<HashMap<String, DependencyConfig>>,
65 #[serde(rename = "dev-dependencies")]
66 pub dev_dependencies: Option<HashMap<String, DependencyConfig>>,
67 pub executables: Option<Vec<ProgramConfig>>,
68 pub tests: Option<Vec<ProgramConfig>>,
69 pub examples: Option<Vec<ProgramConfig>>,
70 pub features: Option<HashMap<String, Vec<String>>>,
71 pub target: Option<HashMap<String, ModeTableConfig>>,
72 pub feature: Option<HashMap<String, ModeTableConfig>>,
73 pub generator: Option<HashMap<String, ModeTableConfig>>,
74}
75
76impl<P: AsRef<Path>> Shelling<anyhow::Result<Config>, P> for RawConfig {
77 fn shelling(self, base: P) -> anyhow::Result<Config> {
78 Ok(Config {
79 package: self.package.shelling(&base),
80 build: self.build.unwrap_or_default().shelling(&base)?,
81 dependencies: self
82 .dependencies
83 .unwrap_or_default()
84 .into_iter()
85 .try_all(|(k, v)| -> anyhow::Result<_> { Ok((k, v.shelling(&base)?)) })?
86 .collect(),
87 dev_dependencies: self
88 .dev_dependencies
89 .unwrap_or_default()
90 .into_iter()
91 .try_all(|(k, v)| -> anyhow::Result<_> { Ok((k, v.shelling(&base)?)) })?
92 .collect(),
93 executables: self
94 .executables
95 .unwrap_or_default()
96 .into_iter()
97 .map(|v| v.shelling(&base))
98 .collect(),
99 tests: self
100 .tests
101 .unwrap_or_default()
102 .into_iter()
103 .map(|v| v.shelling(&base))
104 .collect(),
105 examples: self
106 .examples
107 .unwrap_or_default()
108 .into_iter()
109 .map(|v| v.shelling(&base))
110 .collect(),
111 features: self.features.unwrap_or_default(),
112 target: self
113 .target
114 .unwrap_or_default()
115 .into_iter()
116 .try_all(|(k, v)| -> anyhow::Result<_> { Ok((k, v.shelling(&base)?)) })?
117 .collect(),
118 feature: self
119 .feature
120 .unwrap_or_default()
121 .into_iter()
122 .try_all(|(k, v)| -> anyhow::Result<_> { Ok((k, v.shelling(&base)?)) })?
123 .collect(),
124 generator: self
125 .generator
126 .unwrap_or_default()
127 .into_iter()
128 .try_all(|(k, v)| -> anyhow::Result<_> { Ok((k, v.shelling(&base)?)) })?
129 .collect(),
130 })
131 }
132}
133
134#[derive(Debug, Clone)]
136pub struct Config {
137 pub package: Package,
138 pub build: Build,
139 pub dependencies: HashMap<String, Dependency>,
140 pub dev_dependencies: HashMap<String, Dependency>,
141 pub executables: Vec<Program>,
142 pub tests: Vec<Program>,
143 pub examples: Vec<Program>,
144 pub features: HashMap<String, Vec<String>>,
145 pub target: HashMap<String, ModeTable>,
146 pub feature: HashMap<String, ModeTable>,
147 pub generator: HashMap<String, ModeTable>,
148}
149
150impl Config {
151 pub fn read<P: AsRef<Path>>(project: P) -> anyhow::Result<Config> {
153 let content = fs_err::read_to_string(project.as_ref().join("Cup.toml"))?;
154 let raw_config: RawConfig = toml::from_str(&content)?;
155 Ok(raw_config.shelling(project)?)
156 }
157}