1+ using System . Collections . ObjectModel ;
2+
13namespace IntelliTect . Multitool ;
4+
25/// <summary>
36/// Provides consistent environment-independent normalized pathing within a repository.
47/// </summary>
58public static class RepositoryPaths
69{
710 /// <summary>
8- /// Finds the root of the repository by looking for the .git folder.
11+ /// Name of the build variables file that is created by the build process.
12+ /// </summary>
13+ public const string BuildVariableFileName = "IntelliTect.MultiTool.BuildVariables.tmp" ;
14+
15+ /// <summary>
16+ /// Holds the key value pairs of the build variables that this class can use.
17+ /// </summary>
18+ public static ReadOnlyDictionary < string , string ? > BuildVariables { get ; } = new ( File . ReadAllLines ( Path . Combine ( Path . GetTempPath ( ) , BuildVariableFileName ) )
19+ . Select ( line => line . Split ( "::" ) )
20+ . ToDictionary ( split => split [ 0 ] . Trim ( ) ,
21+ split => ! string . IsNullOrEmpty ( split [ 1 ] ) ? split [ 1 ] . Trim ( ) : null ) ) ;
22+
23+ /// <summary>
24+ /// Finds the root of the repository by looking for the directory containing the .git directory.
25+ /// Begins searching up from the current directory, and retries from the project directory if initially not found.
26+ /// Defaults to the solution directory, if available, if the .git directory is not found.
927 /// </summary>
1028 /// <returns>Full path to repo root.</returns>
1129 public static string GetDefaultRepoRoot ( )
1230 {
13- DirectoryInfo ? currentDirectory = new ( Directory . GetCurrentDirectory ( ) ) ;
31+ string gitDirectory ;
32+ DirectoryInfo ? searchStartDirectory ;
1433
15- while ( currentDirectory is not null )
34+ // If not live unit testing, try searching from current directory. But if we are this will fail, so just skip
35+ if ( ! ( BuildVariables . TryGetValue ( "BuildingForLiveUnitTesting" , out string ? isLiveUnitTesting )
36+ && isLiveUnitTesting == "true" ) )
1637 {
17- DirectoryInfo [ ] subDirectories = currentDirectory . GetDirectories ( ".git" ) ;
18- if ( subDirectories . Length > 0 )
38+ searchStartDirectory = new ( Directory . GetCurrentDirectory ( ) ) ;
39+ if ( TrySearchForGitContainingDirectory ( searchStartDirectory , out gitDirectory )
40+ && ! string . IsNullOrWhiteSpace ( gitDirectory ) )
1941 {
20- return currentDirectory . FullName ;
42+ return gitDirectory ;
2143 }
22-
23- currentDirectory = currentDirectory . Parent ;
2444 }
25-
45+ // Search from the project directory if we are live unit testing or if the initial search failed.
46+ if ( BuildVariables . TryGetValue ( "ProjectPath" , out string ? projectPath ) )
47+ {
48+ searchStartDirectory = new FileInfo ( projectPath ) . Directory ;
49+ if ( TrySearchForGitContainingDirectory ( searchStartDirectory , out gitDirectory )
50+ && ! string . IsNullOrWhiteSpace ( gitDirectory ) )
51+ {
52+ return gitDirectory ;
53+ }
54+ }
55+ // If all this fails, try returning the Solution Directory in hopes that is in the root of the repo.
56+ if ( BuildVariables . TryGetValue ( "SolutionDir" , out string ? solutionDir ) && ! string . IsNullOrWhiteSpace ( solutionDir ) )
57+ {
58+ return Directory . Exists ( solutionDir ) ? solutionDir : throw new InvalidOperationException ( $ "SolutionDir is not a valid directory.") ;
59+ }
2660 throw new InvalidOperationException ( "Could not find the repo root directory from the current directory. Current directory is expected to be the repoRoot sub directory." ) ;
2761 }
62+
63+ /// <summary>
64+ /// Searches up from the <paramref name="searchStartDirectory"/> looking for a .git directory.
65+ /// </summary>
66+ /// <param name="searchStartDirectory">The directory to start searching from, will search up.</param>
67+ /// <param name="gitParentDirectory">The parent directory to the .git directory.</param>
68+ /// <returns><c>true</c> if the directory <paramref name="gitParentDirectory" /> was found successfully; otherwise, false.</returns>
69+ public static bool TrySearchForGitContainingDirectory ( DirectoryInfo ? searchStartDirectory , out string gitParentDirectory )
70+ {
71+ while ( searchStartDirectory is not null )
72+ {
73+ DirectoryInfo [ ] subDirectories = searchStartDirectory . GetDirectories ( ".git" ) ;
74+ if ( subDirectories . Length > 0 )
75+ {
76+ gitParentDirectory = searchStartDirectory . FullName ;
77+ return true ;
78+ }
79+
80+ searchStartDirectory = searchStartDirectory . Parent ;
81+ }
82+ gitParentDirectory = string . Empty ;
83+ return false ;
84+ }
2885}
0 commit comments