66using Microsoft . Build . Execution ;
77using Microsoft . Build . Framework ;
88using Microsoft . Build . Logging ;
9+ using Microsoft . DotNet . Tools . Test ;
910
1011namespace Microsoft . DotNet . Cli
1112{
@@ -18,8 +19,6 @@ internal sealed class MSBuildHandler : IDisposable
1819 private readonly ConcurrentBag < TestApplication > _testApplications = new ( ) ;
1920 private bool _areTestingPlatformApplications = true ;
2021
21- private const string BinLogFileName = "msbuild.binlog" ;
22- private const string Separator = ";" ;
2322 private static readonly Lock buildLock = new ( ) ;
2423
2524 public MSBuildHandler ( List < string > args , TestApplicationActionQueue actionQueue , int degreeOfParallelism )
@@ -29,9 +28,86 @@ public MSBuildHandler(List<string> args, TestApplicationActionQueue actionQueue,
2928 _degreeOfParallelism = degreeOfParallelism ;
3029 }
3130
32- public async Task < int > RunWithMSBuild ( )
31+ public async Task < bool > RunMSBuild ( BuildPathsOptions buildPathOptions )
3332 {
34- bool solutionOrProjectFileFound = SolutionAndProjectUtility . TryGetProjectOrSolutionFilePath ( Directory . GetCurrentDirectory ( ) , out string projectOrSolutionFilePath , out bool isSolution ) ;
33+ if ( ! ValidateBuildPathOptions ( buildPathOptions ) )
34+ {
35+ return false ;
36+ }
37+
38+ int msbuildExitCode ;
39+
40+ if ( ! string . IsNullOrEmpty ( buildPathOptions . ProjectPath ) )
41+ {
42+ msbuildExitCode = await RunBuild ( buildPathOptions . ProjectPath , isSolution : false ) ;
43+ }
44+ else if ( ! string . IsNullOrEmpty ( buildPathOptions . SolutionPath ) )
45+ {
46+ msbuildExitCode = await RunBuild ( buildPathOptions . SolutionPath , isSolution : true ) ;
47+ }
48+ else
49+ {
50+ msbuildExitCode = await RunBuild ( buildPathOptions . DirectoryPath ?? Directory . GetCurrentDirectory ( ) ) ;
51+ }
52+
53+ if ( msbuildExitCode != ExitCodes . Success )
54+ {
55+ VSTestTrace . SafeWriteTrace ( ( ) => string . Format ( LocalizableStrings . CmdMSBuildProjectsPropertiesErrorDescription , msbuildExitCode ) ) ;
56+ return false ;
57+ }
58+
59+ return true ;
60+ }
61+
62+ private bool ValidateBuildPathOptions ( BuildPathsOptions buildPathOptions )
63+ {
64+ if ( ( ! string . IsNullOrEmpty ( buildPathOptions . ProjectPath ) && ! string . IsNullOrEmpty ( buildPathOptions . SolutionPath ) ) ||
65+ ( ! string . IsNullOrEmpty ( buildPathOptions . ProjectPath ) && ! string . IsNullOrEmpty ( buildPathOptions . DirectoryPath ) ) ||
66+ ( ! string . IsNullOrEmpty ( buildPathOptions . SolutionPath ) && ! string . IsNullOrEmpty ( buildPathOptions . DirectoryPath ) ) )
67+ {
68+ VSTestTrace . SafeWriteTrace ( ( ) => LocalizableStrings . CmdMultipleBuildPathOptionsErrorDescription ) ;
69+ return false ;
70+ }
71+
72+ if ( ! string . IsNullOrEmpty ( buildPathOptions . ProjectPath ) )
73+ {
74+ return ValidateFilePath ( buildPathOptions . ProjectPath , CliConstants . ProjectExtensions , LocalizableStrings . CmdInvalidProjectFileExtensionErrorDescription ) ;
75+ }
76+
77+ if ( ! string . IsNullOrEmpty ( buildPathOptions . SolutionPath ) )
78+ {
79+ return ValidateFilePath ( buildPathOptions . SolutionPath , CliConstants . SolutionExtensions , LocalizableStrings . CmdInvalidSolutionFileExtensionErrorDescription ) ;
80+ }
81+
82+ if ( ! string . IsNullOrEmpty ( buildPathOptions . DirectoryPath ) && ! Directory . Exists ( buildPathOptions . DirectoryPath ) )
83+ {
84+ VSTestTrace . SafeWriteTrace ( ( ) => string . Format ( LocalizableStrings . CmdNonExistentDirectoryErrorDescription , Path . GetFullPath ( buildPathOptions . DirectoryPath ) ) ) ;
85+ return false ;
86+ }
87+
88+ return true ;
89+ }
90+
91+ private static bool ValidateFilePath ( string filePath , string [ ] validExtensions , string errorMessage )
92+ {
93+ if ( ! validExtensions . Contains ( Path . GetExtension ( filePath ) ) )
94+ {
95+ VSTestTrace . SafeWriteTrace ( ( ) => string . Format ( errorMessage , filePath ) ) ;
96+ return false ;
97+ }
98+
99+ if ( ! File . Exists ( filePath ) )
100+ {
101+ VSTestTrace . SafeWriteTrace ( ( ) => string . Format ( LocalizableStrings . CmdNonExistentFileErrorDescription , Path . GetFullPath ( filePath ) ) ) ;
102+ return false ;
103+ }
104+
105+ return true ;
106+ }
107+
108+ private async Task < int > RunBuild ( string directoryPath )
109+ {
110+ bool solutionOrProjectFileFound = SolutionAndProjectUtility . TryGetProjectOrSolutionFilePath ( directoryPath , out string projectOrSolutionFilePath , out bool isSolution ) ;
35111
36112 if ( ! solutionOrProjectFileFound )
37113 {
@@ -45,9 +121,9 @@ public async Task<int> RunWithMSBuild()
45121 return restored ? ExitCodes . Success : ExitCodes . GenericFailure ;
46122 }
47123
48- public async Task < int > RunWithMSBuild ( string filePath )
124+ private async Task < int > RunBuild ( string filePath , bool isSolution )
49125 {
50- ( IEnumerable < Module > modules , bool restored ) = await GetProjectsProperties ( filePath , false ) ;
126+ ( IEnumerable < Module > modules , bool restored ) = await GetProjectsProperties ( filePath , isSolution ) ;
51127
52128 InitializeTestApplications ( modules ) ;
53129
@@ -92,7 +168,12 @@ public bool EnqueueTestApplications()
92168
93169 if ( isSolution )
94170 {
95- var projects = await SolutionAndProjectUtility . ParseSolution ( solutionOrProjectFilePath ) ;
171+ string fileDirectory = Path . GetDirectoryName ( solutionOrProjectFilePath ) ;
172+ string rootDirectory = string . IsNullOrEmpty ( fileDirectory )
173+ ? Directory . GetCurrentDirectory ( )
174+ : fileDirectory ;
175+
176+ var projects = await SolutionAndProjectUtility . ParseSolution ( solutionOrProjectFilePath , rootDirectory ) ;
96177 ProcessProjectsInParallel ( projects , allProjects , ref restored ) ;
97178 }
98179 else
@@ -178,7 +259,7 @@ private static IEnumerable<Module> ExtractModulesFromProject(Project project)
178259 }
179260 else
180261 {
181- var frameworks = targetFrameworks . Split ( Separator , StringSplitOptions . RemoveEmptyEntries ) ;
262+ var frameworks = targetFrameworks . Split ( CliConstants . SemiColon , StringSplitOptions . RemoveEmptyEntries ) ;
182263 foreach ( var framework in frameworks )
183264 {
184265 project . SetProperty ( ProjectProperties . TargetFramework , framework ) ;
@@ -225,8 +306,7 @@ private static BuildResult RestoreProject(string projectFilePath, ProjectCollect
225306
226307 private static bool IsBinaryLoggerEnabled ( List < string > args , out string binLogFileName )
227308 {
228- binLogFileName = BinLogFileName ;
229-
309+ binLogFileName = string . Empty ;
230310 var binLogArgs = new List < string > ( ) ;
231311
232312 foreach ( var arg in args )
@@ -248,10 +328,16 @@ private static bool IsBinaryLoggerEnabled(List<string> args, out string binLogFi
248328 // Get BinLog filename
249329 var binLogArg = binLogArgs . LastOrDefault ( ) ;
250330
251- if ( binLogArg . Contains ( ':' ) )
331+ if ( binLogArg . Contains ( CliConstants . Colon ) )
252332 {
253- binLogFileName = binLogArg . Split ( ':' ) [ 1 ] ;
333+ var parts = binLogArg . Split ( CliConstants . Colon , 2 ) ;
334+ binLogFileName = ! string . IsNullOrEmpty ( parts [ 1 ] ) ? parts [ 1 ] : CliConstants . BinLogFileName ;
254335 }
336+ else
337+ {
338+ binLogFileName = CliConstants . BinLogFileName ;
339+ }
340+
255341 return true ;
256342 }
257343
0 commit comments