Skip to content

Commit 701e33e

Browse files
committed
Move config to the top level args, start to allow override at source level
1 parent 3210179 commit 701e33e

File tree

19 files changed

+196
-180
lines changed

19 files changed

+196
-180
lines changed

martin/benches/bench.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use async_trait::async_trait;
22
use criterion::async_executor::FuturesExecutor;
33
use criterion::{Criterion, criterion_group, criterion_main};
4+
use martin::file_config::ValidationLevel;
45
use martin::srv::DynTileSource;
56
use martin::{CatalogSourceEntry, MartinResult, Source, TileData, TileSources, UrlQuery};
67
use martin_tile_utils::{Encoding, Format, TileCoord, TileInfo};
@@ -42,6 +43,10 @@ impl Source for NullSource {
4243
false
4344
}
4445

46+
async fn validate(&self, _validation_level: ValidationLevel) -> MartinResult<()> {
47+
MartinResult::Ok(())
48+
}
49+
4550
async fn get_tile(
4651
&self,
4752
_xyz: TileCoord,
@@ -63,7 +68,7 @@ async fn process_tile(sources: &TileSources) {
6368
}
6469

6570
fn bench_null_source(c: &mut Criterion) {
66-
let sources = TileSources::new(vec![vec![Box::new(NullSource::new())]]);
71+
let sources = TileSources::new(vec![Box::new(NullSource::new())]);
6772
c.bench_function("get_table_source_tile", |b| {
6873
b.to_async(FuturesExecutor).iter(|| process_tile(&sources));
6974
});

martin/src/args/mbtiles.rs

-36
This file was deleted.

martin/src/args/mod.rs

-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ mod pg;
99
#[cfg(feature = "postgres")]
1010
pub use pg::{BoundsCalcType, DEFAULT_BOUNDS_TIMEOUT, PgArgs};
1111

12-
#[cfg(feature = "mbtiles")]
13-
mod mbtiles;
14-
#[cfg(feature = "mbtiles")]
15-
pub use mbtiles::MbtArgs;
16-
1712
mod root;
1813
pub use root::{Args, ExtraArgs, MetaArgs};
1914

martin/src/args/root.rs

-14
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ pub struct Args {
3535
#[cfg(feature = "postgres")]
3636
#[command(flatten)]
3737
pub pg: Option<crate::args::pg::PgArgs>,
38-
#[cfg(feature = "mbtiles")]
39-
#[command(flatten)]
40-
pub mbtiles: Option<crate::args::mbtiles::MbtArgs>,
4138
}
4239

4340
// None of these params will be transferred to the config
@@ -118,17 +115,6 @@ impl Args {
118115
config.pmtiles = parse_file_args(&mut cli_strings, &["pmtiles"], true);
119116
}
120117

121-
#[cfg(feature = "mbtiles")]
122-
{
123-
if !cli_strings.is_empty() {
124-
config.mbtiles = parse_file_args(&mut cli_strings, &["mbtiles"], false);
125-
}
126-
let mbt_args = self.mbtiles.unwrap_or_default();
127-
if let FileConfigEnum::Config(c) = &mut config.mbtiles {
128-
mbt_args.override_config(&mut c.custom);
129-
}
130-
}
131-
132118
#[cfg(feature = "cog")]
133119
if !cli_strings.is_empty() {
134120
config.cog = parse_file_args(&mut cli_strings, &["tif", "tiff"], false);

martin/src/args/srv.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use clap::ValueEnum;
22
use serde::{Deserialize, Serialize};
33

4-
use crate::srv::{KEEP_ALIVE_DEFAULT, LISTEN_ADDRESSES_DEFAULT, SrvConfig};
4+
use crate::{
5+
file_config::{OnInvalid, ValidationLevel},
6+
srv::{KEEP_ALIVE_DEFAULT, LISTEN_ADDRESSES_DEFAULT, SrvConfig},
7+
};
58

69
#[allow(clippy::doc_markdown)]
710
#[derive(clap::Args, Debug, PartialEq, Default)]
@@ -34,6 +37,12 @@ pub struct SrvArgs {
3437
#[arg(short = 'u', long = "webui")]
3538
#[cfg(feature = "webui")]
3639
pub web_ui: Option<WebUiMode>,
40+
/// Level of validation to apply to sources
41+
#[arg(long)]
42+
pub validate: Option<ValidationLevel>,
43+
/// How to handle invalid source
44+
#[arg(long)]
45+
pub on_invalid: Option<OnInvalid>,
3746
}
3847

3948
#[cfg(feature = "webui")]
@@ -81,6 +90,12 @@ impl SrvArgs {
8190
if self.preferred_encoding.is_some() {
8291
srv_config.preferred_encoding = self.preferred_encoding;
8392
}
93+
if let Some(v) = self.validate {
94+
srv_config.validate = v
95+
}
96+
if let Some(v) = self.on_invalid {
97+
srv_config.on_invalid = v;
98+
}
8499
#[cfg(feature = "webui")]
85100
if self.web_ui.is_some() {
86101
srv_config.web_ui = self.web_ui;

martin/src/bin/martin-cp.rs

-5
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ pub struct CopierArgs {
4949
#[cfg(feature = "postgres")]
5050
#[command(flatten)]
5151
pub pg: Option<martin::args::PgArgs>,
52-
#[cfg(feature = "mbtiles")]
53-
#[command(flatten)]
54-
pub mbtiles: Option<martin::args::MbtArgs>,
5552
}
5653

5754
#[serde_with::serde_as]
@@ -144,8 +141,6 @@ async fn start(copy_args: CopierArgs) -> MartinCpResult<()> {
144141
srv: SrvArgs::default(),
145142
#[cfg(feature = "postgres")]
146143
pg: copy_args.pg,
147-
#[cfg(feature = "mbtiles")]
148-
mbtiles: copy_args.mbtiles,
149144
};
150145

151146
args.merge_into_config(&mut config, &env)?;

martin/src/cog/source.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tiff::tags::Tag::{self, GdalNodata};
1313
use tilejson::{TileJSON, tilejson};
1414

1515
use super::CogError;
16-
use crate::file_config::{FileError, FileResult};
16+
use crate::file_config::{FileError, FileResult, ValidationLevel};
1717
use crate::{MartinResult, Source, TileData, UrlQuery};
1818

1919
#[derive(Clone, Debug)]
@@ -151,6 +151,10 @@ impl Source for CogSource {
151151
Box::new(self.clone())
152152
}
153153

154+
async fn validate(&self, _validation_level: ValidationLevel) -> MartinResult<()> {
155+
MartinResult::Ok(())
156+
}
157+
154158
async fn get_tile(
155159
&self,
156160
xyz: TileCoord,

martin/src/config.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ use std::path::{Path, PathBuf};
66
use std::pin::Pin;
77

88
use futures::future::try_join_all;
9-
use log::info;
9+
use log::{info, warn};
1010
use serde::{Deserialize, Serialize};
1111
use subst::VariableMap;
1212

13+
use crate::file_config::OnInvalid;
1314
use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources};
1415
#[cfg(any(feature = "fonts", feature = "postgres"))]
1516
use crate::OptOneMany;
@@ -209,7 +210,34 @@ impl Config {
209210
sources.push(Box::pin(val));
210211
}
211212

212-
Ok(TileSources::new(try_join_all(sources).await?))
213+
let resolved_sources = try_join_all(sources).await?
214+
.into_iter()
215+
.flatten()
216+
.collect::<TileInfoSources>();
217+
218+
let mut sources_to_prune: Vec<usize> = vec![];
219+
for (idx, source) in resolved_sources.iter().enumerate() {
220+
let validation_result = source.validate(self.srv.validate).await;
221+
if let Err(e) = validation_result {
222+
match self.srv.on_invalid {
223+
OnInvalid::Abort => {
224+
return MartinResult::Err(e)
225+
},
226+
OnInvalid::Warn => {
227+
warn!(
228+
"Source {} failed validation, this may cause performance issues: {}",
229+
source.get_id(),
230+
e.to_string()
231+
);
232+
},
233+
OnInvalid::Ignore => {
234+
sources_to_prune.push(idx)
235+
},
236+
}
237+
}
238+
}
239+
240+
Ok(TileSources::new(resolved_sources))
213241
}
214242

215243
pub fn save_to_file(&self, file_name: PathBuf) -> MartinResult<()> {

martin/src/file_config.rs

+36-14
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use std::fmt::Debug;
33
use std::mem;
44
use std::path::{Path, PathBuf};
55

6+
use clap::ValueEnum;
67
use futures::TryFutureExt;
78
use log::{info, warn};
8-
use martin_tile_utils::TileInfo;
99
use serde::{Deserialize, Serialize};
1010
use url::Url;
1111

@@ -62,6 +62,31 @@ pub enum FileError {
6262
CogError(#[from] crate::cog::CogError),
6363
}
6464

65+
#[derive(PartialEq, Eq, Debug, Clone, Copy, Default, Serialize, Deserialize, ValueEnum)]
66+
#[serde(rename_all = "lowercase")]
67+
pub enum ValidationLevel {
68+
/// Quickly check the source
69+
#[default]
70+
Fast,
71+
72+
/// Do a slow check of everything
73+
Thorough,
74+
}
75+
76+
#[derive(PartialEq, Eq, Debug, Clone, Copy, Default, Serialize, Deserialize, ValueEnum)]
77+
#[serde(rename_all = "lowercase")]
78+
pub enum OnInvalid {
79+
/// Print warning message, and abort if the error is critical
80+
#[default]
81+
Warn,
82+
83+
/// Skip this source
84+
Ignore,
85+
86+
/// Do not start Martin on any warnings
87+
Abort,
88+
}
89+
6590
pub trait ConfigExtras: Clone + Debug + Default + PartialEq + Send {
6691
fn init_parsing(&mut self, _cache: OptMainCache) -> FileResult<()> {
6792
Ok(())
@@ -130,6 +155,8 @@ impl<T: ConfigExtras> FileConfigEnum<T> {
130155
} else {
131156
Some(configs)
132157
},
158+
validate: None,
159+
on_invalid: None,
133160
custom,
134161
})
135162
}
@@ -187,6 +214,10 @@ pub struct FileConfig<T> {
187214
pub paths: OptOneMany<PathBuf>,
188215
/// A map of source IDs to file paths or config objects
189216
pub sources: Option<BTreeMap<String, FileConfigSrc>>,
217+
#[serde(default)]
218+
pub validate: Option<ValidationLevel>,
219+
#[serde(default)]
220+
pub on_invalid: Option<OnInvalid>,
190221
/// Any customizations related to the specifics of the configuration section
191222
#[serde(flatten)]
192223
pub custom: T,
@@ -275,10 +306,7 @@ async fn resolve_int<T: SourceConfigExtras>(
275306
let dup = if dup { "duplicate " } else { "" };
276307
let id = idr.resolve(&id, url.to_string());
277308
configs.insert(id.clone(), source);
278-
maybe_add_source(
279-
&mut results,
280-
cfg.custom.new_sources_url(id.clone(), url.clone()).await,
281-
)?;
309+
results.push(cfg.custom.new_sources_url(id.clone(), url.clone()).await?);
282310
info!("Configured {dup}source {id} from {}", sanitize_url(&url));
283311
} else {
284312
let can = source.abs_path()?;
@@ -292,10 +320,7 @@ async fn resolve_int<T: SourceConfigExtras>(
292320
let id = idr.resolve(&id, can.to_string_lossy().to_string());
293321
info!("Configured {dup}source {id} from {}", can.display());
294322
configs.insert(id.clone(), source.clone());
295-
maybe_add_source(
296-
&mut results,
297-
cfg.custom.new_sources(id, source.into_path()).await,
298-
)?;
323+
results.push(cfg.custom.new_sources(id, source.into_path()).await?);
299324
}
300325
}
301326
}
@@ -319,10 +344,7 @@ async fn resolve_int<T: SourceConfigExtras>(
319344

320345
let id = idr.resolve(id, url.to_string());
321346
configs.insert(id.clone(), FileConfigSrc::Path(path));
322-
maybe_add_source(
323-
&mut results,
324-
cfg.custom.new_sources_url(id.clone(), url.clone()).await,
325-
)?;
347+
results.push(cfg.custom.new_sources_url(id.clone(), url.clone()).await?);
326348
info!("Configured source {id} from URL {}", sanitize_url(&url));
327349
} else {
328350
let is_dir = path.is_dir();
@@ -351,7 +373,7 @@ async fn resolve_int<T: SourceConfigExtras>(
351373
info!("Configured source {id} from {}", can.display());
352374
files.insert(can);
353375
configs.insert(id.clone(), FileConfigSrc::Path(path.clone()));
354-
maybe_add_source(&mut results, cfg.custom.new_sources(id, path).await)?;
376+
results.push(cfg.custom.new_sources(id, path).await?);
355377
}
356378
}
357379
}

0 commit comments

Comments
 (0)