@@ -8,6 +8,23 @@ use crate::ui::quoted_path;
88/// The name given to the default manifest file.
99pub const DEFAULT_MANIFEST_FILE : & str = "spin.toml" ;
1010
11+ /// Attempts to find a manifest. If a path is provided, that path is resolved
12+ /// using `resolve_manifest_file_path`; otherwise, a directory search is carried out
13+ /// using `search_upwards_for_manifest`. If we had to search, and a manifest is found,
14+ /// a (non-zero) usize is returned indicating how far above the current directory it
15+ /// was found. (A usize of 0 indicates that the manifest was provided or found
16+ /// in the current directory.) This can be used to notify the user that a
17+ /// non-default manifest is being used.
18+ pub fn find_manifest_file_path (
19+ provided_path : Option < impl AsRef < Path > > ,
20+ ) -> Result < ( PathBuf , usize ) > {
21+ match provided_path {
22+ Some ( provided_path) => resolve_manifest_file_path ( provided_path) . map ( |p| ( p, 0 ) ) ,
23+ None => search_upwards_for_manifest ( )
24+ . ok_or_else ( || anyhow ! ( "\" {}\" not found" , DEFAULT_MANIFEST_FILE ) ) ,
25+ }
26+ }
27+
1128/// Resolves a manifest path provided by a user, which may be a file or
1229/// directory, to a path to a manifest file.
1330pub fn resolve_manifest_file_path ( provided_path : impl AsRef < Path > ) -> Result < PathBuf > {
@@ -36,6 +53,43 @@ pub fn resolve_manifest_file_path(provided_path: impl AsRef<Path>) -> Result<Pat
3653 }
3754}
3855
56+ /// Starting from the current directory, searches upward through
57+ /// the directory tree for a manifest (that is, a file with the default
58+ /// manifest name `spin.toml`). If found, the path to the manifest
59+ /// is returned, with a usize indicating how far above the current directory it
60+ /// was found. (A usize of 0 indicates that the manifest was provided or found
61+ /// in the current directory.) This can be used to notify the user that a
62+ /// non-default manifest is being used.
63+ /// If no matching file is found, the function returns None.
64+ ///
65+ /// The search is abandoned if it reaches the root directory, or the
66+ /// root of a Git repository, without finding a 'spin.toml'.
67+ pub fn search_upwards_for_manifest ( ) -> Option < ( PathBuf , usize ) > {
68+ let candidate = PathBuf :: from ( DEFAULT_MANIFEST_FILE ) ;
69+
70+ if candidate. is_file ( ) {
71+ return Some ( ( candidate, 0 ) ) ;
72+ }
73+
74+ for distance in 1 ..20 {
75+ let inferred_dir = PathBuf :: from ( "../" . repeat ( distance) ) ;
76+ if !inferred_dir. is_dir ( ) {
77+ return None ;
78+ }
79+
80+ let candidate = inferred_dir. join ( DEFAULT_MANIFEST_FILE ) ;
81+ if candidate. is_file ( ) {
82+ return Some ( ( candidate, distance) ) ;
83+ }
84+
85+ if is_git_root ( & inferred_dir) {
86+ return None ;
87+ }
88+ }
89+
90+ None
91+ }
92+
3993/// Resolves the parent directory of a path, returning an error if the path
4094/// has no parent. A path with a single component will return ".".
4195pub fn parent_dir ( path : impl AsRef < Path > ) -> Result < PathBuf > {
@@ -49,6 +103,10 @@ pub fn parent_dir(path: impl AsRef<Path>) -> Result<PathBuf> {
49103 Ok ( parent. into ( ) )
50104}
51105
106+ fn is_git_root ( dir : & Path ) -> bool {
107+ dir. join ( ".git" ) . is_dir ( )
108+ }
109+
52110#[ cfg( test) ]
53111mod tests {
54112 use super :: * ;
0 commit comments