@@ -48,6 +48,30 @@ impl ProjectMetadata {
4848 }
4949 }
5050
51+ pub fn from_config_file (
52+ path : SystemPathBuf ,
53+ root : SystemPathBuf ,
54+ system : & dyn System ,
55+ ) -> Result < Self , ProjectMetadataError > {
56+ tracing:: debug!( "Using overridden configuration file at '{path}'" ) ;
57+
58+ let config_file = ConfigurationFile :: from_path ( path. clone ( ) , system) . map_err ( |error| {
59+ ProjectMetadataError :: ConfigurationFileError {
60+ source : Box :: new ( error) ,
61+ path : path. clone ( ) ,
62+ }
63+ } ) ?;
64+
65+ let options = config_file. into_options ( ) ;
66+
67+ Ok ( Self {
68+ name : Name :: new ( root. file_name ( ) . unwrap_or ( "root" ) ) ,
69+ root,
70+ options,
71+ extra_configuration_paths : vec ! [ path] ,
72+ } )
73+ }
74+
5175 /// Loads a project from a `pyproject.toml` file.
5276 pub ( crate ) fn from_pyproject (
5377 pyproject : PyProject ,
@@ -106,11 +130,11 @@ impl ProjectMetadata {
106130 pub fn discover (
107131 path : & SystemPath ,
108132 system : & dyn System ,
109- ) -> Result < ProjectMetadata , ProjectDiscoveryError > {
133+ ) -> Result < ProjectMetadata , ProjectMetadataError > {
110134 tracing:: debug!( "Searching for a project in '{path}'" ) ;
111135
112136 if !system. is_directory ( path) {
113- return Err ( ProjectDiscoveryError :: NotADirectory ( path. to_path_buf ( ) ) ) ;
137+ return Err ( ProjectMetadataError :: NotADirectory ( path. to_path_buf ( ) ) ) ;
114138 }
115139
116140 let mut closest_project: Option < ProjectMetadata > = None ;
@@ -125,7 +149,7 @@ impl ProjectMetadata {
125149 ) {
126150 Ok ( pyproject) => Some ( pyproject) ,
127151 Err ( error) => {
128- return Err ( ProjectDiscoveryError :: InvalidPyProject {
152+ return Err ( ProjectMetadataError :: InvalidPyProject {
129153 path : pyproject_path,
130154 source : Box :: new ( error) ,
131155 } ) ;
@@ -144,7 +168,7 @@ impl ProjectMetadata {
144168 ) {
145169 Ok ( options) => options,
146170 Err ( error) => {
147- return Err ( ProjectDiscoveryError :: InvalidTyToml {
171+ return Err ( ProjectMetadataError :: InvalidTyToml {
148172 path : ty_toml_path,
149173 source : Box :: new ( error) ,
150174 } ) ;
@@ -171,7 +195,7 @@ impl ProjectMetadata {
171195 . and_then ( |pyproject| pyproject. project . as_ref ( ) ) ,
172196 )
173197 . map_err ( |err| {
174- ProjectDiscoveryError :: InvalidRequiresPythonConstraint {
198+ ProjectMetadataError :: InvalidRequiresPythonConstraint {
175199 source : err,
176200 path : pyproject_path,
177201 }
@@ -185,7 +209,7 @@ impl ProjectMetadata {
185209 let metadata =
186210 ProjectMetadata :: from_pyproject ( pyproject, project_root. to_path_buf ( ) )
187211 . map_err (
188- |err| ProjectDiscoveryError :: InvalidRequiresPythonConstraint {
212+ |err| ProjectMetadataError :: InvalidRequiresPythonConstraint {
189213 source : err,
190214 path : pyproject_path,
191215 } ,
@@ -282,7 +306,7 @@ impl ProjectMetadata {
282306}
283307
284308#[ derive( Debug , Error ) ]
285- pub enum ProjectDiscoveryError {
309+ pub enum ProjectMetadataError {
286310 #[ error( "project path '{0}' is not a directory" ) ]
287311 NotADirectory ( SystemPathBuf ) ,
288312
@@ -303,6 +327,12 @@ pub enum ProjectDiscoveryError {
303327 source : ResolveRequiresPythonError ,
304328 path : SystemPathBuf ,
305329 } ,
330+
331+ #[ error( "Error loading configuration file at {path}: {source}" ) ]
332+ ConfigurationFileError {
333+ source : Box < ConfigurationFileError > ,
334+ path : SystemPathBuf ,
335+ } ,
306336}
307337
308338#[ cfg( test) ]
@@ -314,7 +344,7 @@ mod tests {
314344 use ruff_db:: system:: { SystemPathBuf , TestSystem } ;
315345 use ruff_python_ast:: PythonVersion ;
316346
317- use crate :: { ProjectDiscoveryError , ProjectMetadata } ;
347+ use crate :: { ProjectMetadata , ProjectMetadataError } ;
318348
319349 #[ test]
320350 fn project_without_pyproject ( ) -> anyhow:: Result < ( ) > {
@@ -1030,7 +1060,7 @@ expected `.`, `]`
10301060 }
10311061
10321062 #[ track_caller]
1033- fn assert_error_eq ( error : & ProjectDiscoveryError , message : & str ) {
1063+ fn assert_error_eq ( error : & ProjectMetadataError , message : & str ) {
10341064 assert_eq ! ( error. to_string( ) . replace( '\\' , "/" ) , message) ;
10351065 }
10361066
0 commit comments