Skip to content

Commit 53f8bc2

Browse files
committed
[ty] Add --config-file
217
1 parent 3d55a16 commit 53f8bc2

File tree

5 files changed

+63
-3
lines changed

5 files changed

+63
-3
lines changed

crates/ty/src/args.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ pub(crate) struct CheckCommand {
107107
#[clap(flatten)]
108108
pub(crate) config: ConfigsArg,
109109

110+
/// A path to a `ty.toml` configuration file
111+
///
112+
/// `pyproject.toml` files are not accepted.
113+
/// When provided, this file will be used in place of any discovered configuration (including user-level configuration).
114+
/// ty will skip project discovery and default to the current working directory.
115+
/// Paths are anchored at the current working directory.
116+
#[arg(long)]
117+
pub(crate) config_file: Option<SystemPathBuf>,
118+
110119
/// The format to use for printing diagnostic messages.
111120
#[arg(long)]
112121
pub(crate) output_format: Option<OutputFormat>,

crates/ty/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,16 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
102102
.map(|path| SystemPath::absolute(path, &cwd))
103103
.collect();
104104

105-
let system = OsSystem::new(cwd);
105+
let system = OsSystem::new(cwd.clone());
106106
let watch = args.watch;
107107
let exit_zero = args.exit_zero;
108108

109+
let mut project_metadata = match &args.config_file {
110+
Some(config_file) => ProjectMetadata::from_config_file(config_file.clone(), cwd, &system)?,
111+
None => ProjectMetadata::discover(&project_path, &system)?,
112+
};
113+
109114
let cli_options = args.into_options();
110-
let mut project_metadata = ProjectMetadata::discover(&project_path, &system)?;
111115
project_metadata.apply_cli_options(cli_options.clone());
112116
project_metadata.apply_configuration_files(&system)?;
113117

crates/ty/tests/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,7 @@ fn cli_config_args_toml_string_basic() -> anyhow::Result<()> {
14261426
fn cli_config_args_overrides_knot_toml() -> anyhow::Result<()> {
14271427
let case = TestCase::with_files(vec![
14281428
(
1429-
"knot.toml",
1429+
"ty.toml",
14301430
r#"
14311431
[terminal]
14321432
error-on-warning = true

crates/ty_project/src/metadata.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub struct ProjectMetadata {
2727
/// The raw options
2828
pub(super) options: Options,
2929

30+
/// Config file to override any discovered configuration
31+
pub(super) config_file_override: Option<SystemPathBuf>,
32+
3033
/// Paths of configurations other than the project's configuration that were combined into [`Self::options`].
3134
///
3235
/// This field stores the paths of the configuration files, mainly for
@@ -45,9 +48,28 @@ impl ProjectMetadata {
4548
root,
4649
extra_configuration_paths: Vec::default(),
4750
options: Options::default(),
51+
config_file_override: None,
4852
}
4953
}
5054

55+
pub fn from_config_file(
56+
path: SystemPathBuf,
57+
root: SystemPathBuf,
58+
system: &dyn System,
59+
) -> Result<Self, ConfigurationFileError> {
60+
tracing::debug!("Using overridden configuration file at '{path}'");
61+
62+
let config_file = ConfigurationFile::from_path(path.clone(), system)?;
63+
let options = config_file.into_options();
64+
Ok(Self {
65+
name: Name::new(root.file_name().unwrap_or("root")),
66+
root,
67+
options,
68+
extra_configuration_paths: Vec::new(),
69+
config_file_override: Some(path),
70+
})
71+
}
72+
5173
/// Loads a project from a `pyproject.toml` file.
5274
pub(crate) fn from_pyproject(
5375
pyproject: PyProject,
@@ -92,6 +114,7 @@ impl ProjectMetadata {
92114
root,
93115
options,
94116
extra_configuration_paths: Vec::new(),
117+
config_file_override: None,
95118
})
96119
}
97120

crates/ty_project/src/metadata/configuration_file.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@ pub(crate) struct ConfigurationFile {
1414
}
1515

1616
impl ConfigurationFile {
17+
pub(crate) fn from_path(
18+
path: SystemPathBuf,
19+
system: &dyn System,
20+
) -> Result<Self, ConfigurationFileError> {
21+
let ty_toml_str = system.read_to_string(&path).map_err(|source| {
22+
ConfigurationFileError::FileReadError {
23+
source,
24+
path: path.clone(),
25+
}
26+
})?;
27+
match Options::from_toml_str(&ty_toml_str, ValueSource::File(Arc::new(path.clone()))) {
28+
Ok(options) => Ok(Self { path, options }),
29+
Err(error) => Err(ConfigurationFileError::InvalidTyToml {
30+
source: Box::new(error),
31+
path,
32+
}),
33+
}
34+
}
1735
/// Loads the user-level configuration file if it exists.
1836
///
1937
/// Returns `None` if the file does not exist or if the concept of user-level configurations
@@ -66,4 +84,10 @@ pub enum ConfigurationFileError {
6684
source: Box<TyTomlError>,
6785
path: SystemPathBuf,
6886
},
87+
#[error("Failed to read `{path}`: {source}")]
88+
FileReadError {
89+
#[source]
90+
source: std::io::Error,
91+
path: SystemPathBuf,
92+
},
6993
}

0 commit comments

Comments
 (0)