Skip to content

Commit fef750c

Browse files
committed
feat: support search path for loading additional config files
Signed-off-by: tison <wander4096@gmail.com>
1 parent fc27a4a commit fef750c

File tree

3 files changed

+100
-38
lines changed

3 files changed

+100
-38
lines changed

fmt/src/document/factory.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use anyhow::Context;
1615
use std::collections::HashMap;
1716
use std::collections::HashSet;
1817
use std::fs;
@@ -21,6 +20,8 @@ use std::path::Path;
2120
use std::path::PathBuf;
2221
use std::time::SystemTime;
2322

23+
use anyhow::Context;
24+
2425
use crate::config::Mapping;
2526
use crate::document::Attributes;
2627
use crate::document::Document;

fmt/src/license/mod.rs

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,11 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use anyhow::Context;
16-
17-
use crate::config::Config;
18-
1915
#[derive(Debug, Clone)]
2016
pub struct HeaderSource {
2117
pub content: String,
2218
}
2319

24-
impl HeaderSource {
25-
pub fn from_config(config: &Config) -> anyhow::Result<Self> {
26-
// 1. inline_header takes priority.
27-
if let Some(content) = config.inline_header.as_ref().cloned() {
28-
return Ok(HeaderSource { content });
29-
}
30-
31-
// 2. Then, header_path tries to load from base_dir.
32-
let header_path = config
33-
.header_path
34-
.as_ref()
35-
.context("no header source found (both inline_header and header_path are None)")?;
36-
let path = {
37-
let mut path = config.base_dir.clone();
38-
path.push(header_path);
39-
path
40-
};
41-
if let Ok(content) = std::fs::read_to_string(path) {
42-
return Ok(HeaderSource { content });
43-
}
44-
45-
// 3. Finally, fallback to try bundled headers.
46-
bundled_headers(header_path).with_context(|| {
47-
format!("no header source found (header_path is invalid: {header_path})")
48-
})
49-
}
50-
}
51-
5220
macro_rules! match_bundled_headers {
5321
($name:expr, $($file:expr),*) => {
5422
match $name {
@@ -60,7 +28,7 @@ macro_rules! match_bundled_headers {
6028
}
6129
}
6230

63-
fn bundled_headers(name: &str) -> Option<HeaderSource> {
31+
pub(crate) fn bundled_headers(name: &str) -> Option<HeaderSource> {
6432
match_bundled_headers!(
6533
name,
6634
"Apache-2.0.txt",

fmt/src/processor.rs

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ use crate::git;
2828
use crate::header::matcher::HeaderMatcher;
2929
use crate::header::model::default_headers;
3030
use crate::header::model::deserialize_header_definitions;
31+
use crate::header::model::HeaderDef;
32+
use crate::license::bundled_headers;
3133
use crate::license::HeaderSource;
3234
use crate::selection::Selection;
3335

@@ -56,6 +58,10 @@ pub fn check_license_header<C: Callback>(
5658
.with_context(|| format!("cannot parse config file: {name}"))?
5759
};
5860

61+
let config_dir = run_config
62+
.parent()
63+
.context("cannot get parent directory of config file")?;
64+
5965
let basedir = config.base_dir.clone();
6066
anyhow::ensure!(
6167
basedir.is_dir(),
@@ -107,10 +113,9 @@ pub fn check_license_header<C: Callback>(
107113
}
108114
}
109115
}
116+
110117
for additional_header in &config.additional_headers {
111-
let additional_defs = fs::read_to_string(additional_header)
112-
.with_context(|| format!("cannot load header definitions: {additional_header}"))
113-
.and_then(deserialize_header_definitions)?;
118+
let additional_defs = load_additional_headers(additional_header, &config, config_dir)?;
114119
for (k, v) in additional_defs {
115120
match defs.entry(k) {
116121
Entry::Occupied(mut ent) => {
@@ -123,11 +128,12 @@ pub fn check_license_header<C: Callback>(
123128
}
124129
}
125130
}
131+
126132
defs
127133
};
128134

129135
let header_matcher = {
130-
let header_source = HeaderSource::from_config(&config)?;
136+
let header_source = load_header_sources(&config, config_dir)?;
131137
HeaderMatcher::new(header_source.content)
132138
};
133139

@@ -164,3 +170,90 @@ pub fn check_license_header<C: Callback>(
164170

165171
Ok(())
166172
}
173+
174+
fn load_additional_headers(
175+
additional_header: impl AsRef<Path>,
176+
config: &Config,
177+
config_dir: &Path,
178+
) -> anyhow::Result<HashMap<String, HeaderDef>> {
179+
let additional_header = additional_header.as_ref();
180+
181+
// 1. Based on config directory.
182+
let path = {
183+
let mut path = config_dir.to_path_buf();
184+
path.push(additional_header);
185+
path
186+
};
187+
if let Ok(content) = fs::read_to_string(&path) {
188+
return deserialize_header_definitions(content)
189+
.with_context(|| format!("cannot load header definitions: {}", path.display()));
190+
}
191+
192+
// 2. Based on the base_dir.
193+
let path = {
194+
let mut path = config.base_dir.clone();
195+
path.push(additional_header);
196+
path
197+
};
198+
if let Ok(content) = fs::read_to_string(&path) {
199+
return deserialize_header_definitions(content)
200+
.with_context(|| format!("cannot load header definitions: {}", path.display()));
201+
}
202+
203+
// 3. Based on current working directory.
204+
if let Ok(content) = fs::read_to_string(additional_header) {
205+
return deserialize_header_definitions(content).with_context(|| {
206+
format!(
207+
"cannot load header definitions: {}",
208+
additional_header.display()
209+
)
210+
});
211+
}
212+
213+
Err(anyhow::anyhow!(
214+
"cannot find header definitions: {}",
215+
additional_header.display()
216+
))
217+
}
218+
219+
fn load_header_sources(config: &Config, config_dir: &Path) -> anyhow::Result<HeaderSource> {
220+
// 1. inline_header takes priority.
221+
if let Some(content) = config.inline_header.as_ref().cloned() {
222+
return Ok(HeaderSource { content });
223+
}
224+
225+
// 2. Then, try to load from header_path.
226+
let header_path = config
227+
.header_path
228+
.as_ref()
229+
.context("no header source found (both inline_header and header_path are None)")?;
230+
231+
// 2.1 Based on config directory.
232+
let path = {
233+
let mut path = config_dir.to_path_buf();
234+
path.push(header_path);
235+
path
236+
};
237+
if let Ok(content) = fs::read_to_string(path) {
238+
return Ok(HeaderSource { content });
239+
}
240+
241+
// 2.2 Based on the base_dir.
242+
let path = {
243+
let mut path = config.base_dir.clone();
244+
path.push(header_path);
245+
path
246+
};
247+
if let Ok(content) = fs::read_to_string(path) {
248+
return Ok(HeaderSource { content });
249+
}
250+
251+
// 2.3 Based on current working directory.
252+
if let Ok(content) = fs::read_to_string(header_path) {
253+
return Ok(HeaderSource { content });
254+
}
255+
256+
// 3. Finally, fallback to try bundled headers.
257+
bundled_headers(header_path)
258+
.with_context(|| format!("no header source found (header_path is invalid: {header_path})"))
259+
}

0 commit comments

Comments
 (0)