1818using System . Text . RegularExpressions ;
1919using System . Collections ;
2020using System . Xml ;
21+ using System . Text . Json ;
2122
2223namespace Amazon . Common . DotNetCli . Tools
2324{
@@ -205,72 +206,136 @@ public static string DeterminePublishLocation(string workingDirectory, string pr
205206 return path ;
206207 }
207208
208- public static string LookupTargetFrameworkFromProjectFile ( string projectLocation )
209- {
210- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
211209
212- var xdoc = XDocument . Load ( projectFile ) ;
213-
214- var element = xdoc . XPathSelectElement ( "//PropertyGroup/TargetFramework" ) ;
215- return element ? . Value ;
216- }
217-
218- /// <summary>
219- /// Retrieve the `OutputType` property of a given project
210+ // <summary>
211+ /// Looks up specified properties from a project.
220212 /// </summary>
221- /// <param name="projectLocation">Path of the project</param>
222- /// <returns>The value of the `OutputType` property</returns>
223- public static string LookupOutputTypeFromProjectFile ( string projectLocation )
213+ /// <param name="projectLocation">The location of the project file.</param>
214+ /// <param name="propertyNames">The names of the properties to look up.</param>
215+ /// <returns>A dictionary of property names and their values.</returns>
216+ public static Dictionary < string , string > LookupProjectProperties ( string projectLocation , params string [ ] propertyNames )
224217 {
225- var process = new Process ( ) ;
226- var output = string . Empty ;
227- var msbuildProcessFailed = false ;
228- try
218+ var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
219+ var properties = new Dictionary < string , string > ( ) ;
220+ var arguments = new List < string >
229221 {
230- process . StartInfo = new ProcessStartInfo ( )
222+ "msbuild" ,
223+ projectFile ,
224+ "-nologo" ,
225+ $ "--getProperty:{ string . Join ( ',' , propertyNames ) } "
226+ } ;
227+
228+ var process = new Process
229+ {
230+ StartInfo = new ProcessStartInfo
231231 {
232232 FileName = "dotnet" ,
233- Arguments = $ "msbuild { projectLocation } -getProperty:OutputType" ,
233+ Arguments = string . Join ( " " , arguments ) ,
234234 RedirectStandardOutput = true ,
235+ RedirectStandardError = true ,
235236 UseShellExecute = false ,
236- WindowStyle = ProcessWindowStyle . Hidden
237- } ;
238-
237+ CreateNoWindow = true
238+ }
239+ } ;
240+ try
241+ {
239242 process . Start ( ) ;
240- output = process . StandardOutput . ReadToEnd ( ) ;
241- var hasExited = process . WaitForExit ( 5000 ) ;
243+ string output = process . StandardOutput . ReadToEnd ( ) . Trim ( ) ;
244+ string error = process . StandardError . ReadToEnd ( ) ;
245+ process . WaitForExit ( 5000 ) ;
242246
243- // If it hasn't completed in the specified timeout, stop the process and give up
244- if ( ! hasExited )
247+ if ( process . ExitCode == 0 )
245248 {
246- process . Kill ( ) ;
247- msbuildProcessFailed = true ;
249+ if ( propertyNames . Length == 1 )
250+ {
251+ // If only one property was requested, the output is the direct value
252+ properties [ propertyNames [ 0 ] ] = output ;
253+ }
254+ else
255+ {
256+ // Multiple properties were requested, so we expect JSON output
257+ using JsonDocument doc = JsonDocument . Parse ( output ) ;
258+ JsonElement root = doc . RootElement ;
259+ JsonElement propertiesElement = root . GetProperty ( "Properties" ) ;
260+
261+ foreach ( var property in propertyNames )
262+ {
263+ if ( propertiesElement . TryGetProperty ( property , out JsonElement propertyValue ) )
264+ {
265+ properties [ property ] = propertyValue . GetString ( ) ;
266+ }
267+ }
268+ }
248269 }
249-
250- // If it has completed but unsuccessfully, give up
251- if ( process . ExitCode != 0 )
270+ else
252271 {
253- msbuildProcessFailed = true ;
272+ // Fallback to XML parsing
273+ properties = LookupProjectPropertiesFromXml ( projectFile , propertyNames ) ;
254274 }
255275 }
256276 catch ( Exception )
257277 {
258- // swallow any exceptions related to `dotnet msbuild`
259- msbuildProcessFailed = true ;
278+ // Fallback to XML parsing
279+ properties = LookupProjectPropertiesFromXml ( projectFile , propertyNames ) ;
260280 }
261281
262- if ( msbuildProcessFailed )
282+ return properties ;
283+ }
284+
285+
286+ private static Dictionary < string , string > LookupProjectPropertiesFromXml ( string projectFile , string [ ] propertyNames )
287+ {
288+ var properties = new Dictionary < string , string > ( ) ;
289+ try
263290 {
264- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
265291 var xdoc = XDocument . Load ( projectFile ) ;
266- var element = xdoc . XPathSelectElement ( "//PropertyGroup/OutputType" ) ;
267- output = element ? . Value ;
292+ foreach ( var propertyName in propertyNames )
293+ {
294+ var element = xdoc . XPathSelectElement ( $ "//PropertyGroup/{ propertyName } ") ;
295+ if ( element != null && ! string . IsNullOrWhiteSpace ( element . Value ) )
296+ {
297+ properties [ propertyName ] = element . Value ;
298+ }
299+ }
300+ }
301+ catch ( Exception )
302+ {
303+ }
304+ return properties ;
305+ }
306+
307+ /// <summary>
308+ /// Looks up the target framework from a project file.
309+ /// </summary>
310+ /// <param name="projectLocation">The location of the project file.</param>
311+ /// <returns>The target framework of the project.</returns>
312+ public static string LookupTargetFrameworkFromProjectFile ( string projectLocation )
313+ {
314+ var properties = LookupProjectProperties ( projectLocation , "TargetFramework" , "TargetFrameworks" ) ;
315+ if ( properties . TryGetValue ( "TargetFramework" , out var targetFramework ) && ! string . IsNullOrEmpty ( targetFramework ) )
316+ {
317+ return targetFramework ;
268318 }
319+ if ( properties . TryGetValue ( "TargetFrameworks" , out var targetFrameworks ) && ! string . IsNullOrEmpty ( targetFrameworks ) )
320+ {
321+ var frameworks = targetFrameworks . Split ( ';' ) ;
322+ if ( frameworks . Length > 1 ) {
323+ return null ;
324+ }
325+ return frameworks [ 0 ] ;
326+ }
327+ return null ;
328+ }
269329
270- return
271- string . IsNullOrEmpty ( output ) ?
272- null :
273- output . Trim ( ) ;
330+ /// <summary>
331+ /// Retrieve the `OutputType` property of a given project
332+ /// </summary>
333+ /// <param name="projectLocation">Path of the project</param>
334+ /// <returns>The value of the `OutputType` property</returns>
335+ public static string LookupOutputTypeFromProjectFile ( string projectLocation )
336+ {
337+ var properties = LookupProjectProperties ( projectLocation , "OutputType" ) ;
338+ return properties . TryGetValue ( "OutputType" , out var outputType ) ? outputType . Trim ( ) : null ;
274339 }
275340
276341 public static bool LookPublishAotFlag ( string projectLocation , string msBuildParameters )
@@ -288,43 +353,32 @@ public static bool LookPublishAotFlag(string projectLocation, string msBuildPara
288353 }
289354 }
290355
291- // If the property wasn't provided in msBuildParameters, fall back to searching project file
292- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
293-
294- var xdoc = XDocument . Load ( projectFile ) ;
295-
296- var element = xdoc . XPathSelectElement ( "//PropertyGroup/PublishAot" ) ;
297-
298- if ( bool . TryParse ( element ? . Value , out bool result ) )
356+ var properties = LookupProjectProperties ( projectLocation , "PublishAot" ) ;
357+ if ( properties . TryGetValue ( "PublishAot" , out var publishAot ) )
299358 {
300- return result ;
359+ return bool . TryParse ( publishAot , out var result ) && result ;
301360 }
302-
303361 return false ;
304362 }
363+
364+
305365 public static bool HasExplicitSelfContainedFlag ( string projectLocation , string msBuildParameters )
306366 {
307367 if ( msBuildParameters != null && msBuildParameters . IndexOf ( "--self-contained" , StringComparison . InvariantCultureIgnoreCase ) != - 1 )
308368 {
309369 return true ;
310370 }
311371
312- // If the property wasn't provided in msBuildParameters, fall back to searching project file
313- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
314-
315- var xdoc = XDocument . Load ( projectFile ) ;
316-
317- var element = xdoc . XPathSelectElement ( "//PropertyGroup/SelfContained" ) ;
318-
319- if ( bool . TryParse ( element ? . Value , out _ ) )
372+ var properties = LookupProjectProperties ( projectLocation , "SelfContained" ) ;
373+ if ( properties . TryGetValue ( "SelfContained" , out var selfContained ) )
320374 {
321- return true ;
375+ return bool . TryParse ( selfContained , out var isSelfContained ) && isSelfContained ;
322376 }
323377
324378 return false ;
325379 }
326380
327- public static string FindProjectFileInDirectory ( string directory )
381+ private static string FindProjectFileInDirectory ( string directory )
328382 {
329383 if ( File . Exists ( directory ) )
330384 return directory ;
0 commit comments