2
2
using System . Collections . Generic ;
3
3
using System . Diagnostics ;
4
4
using System . IO ;
5
+ using System . Linq ;
6
+ using System . Text . RegularExpressions ;
5
7
using Semmle . Util ;
6
8
7
9
namespace Semmle . Extraction . CSharp . DependencyFetching
8
10
{
9
11
/// <summary>
10
12
/// Utilities to run the "dotnet" command.
11
13
/// </summary>
12
- internal class DotNet : IDotNet
14
+ internal partial class DotNet : IDotNet
13
15
{
14
16
private readonly ProgressMonitor progressMonitor ;
15
17
private readonly string dotnet ;
@@ -31,17 +33,22 @@ private void Info()
31
33
}
32
34
}
33
35
34
- private ProcessStartInfo MakeDotnetStartInfo ( string args , bool redirectStandardOutput ) =>
35
- new ProcessStartInfo ( dotnet , args )
36
+ private ProcessStartInfo MakeDotnetStartInfo ( string args , bool redirectStandardOutput )
37
+ {
38
+ var startInfo = new ProcessStartInfo ( dotnet , args )
36
39
{
37
40
UseShellExecute = false ,
38
41
RedirectStandardOutput = redirectStandardOutput
39
42
} ;
43
+ // Set the .NET CLI language to English to avoid localized output.
44
+ startInfo . EnvironmentVariables [ "DOTNET_CLI_UI_LANGUAGE" ] = "en" ;
45
+ return startInfo ;
46
+ }
40
47
41
48
private bool RunCommand ( string args )
42
49
{
43
50
progressMonitor . RunningProcess ( $ "{ dotnet } { args } ") ;
44
- using var proc = Process . Start ( this . MakeDotnetStartInfo ( args , redirectStandardOutput : false ) ) ;
51
+ using var proc = Process . Start ( MakeDotnetStartInfo ( args , redirectStandardOutput : false ) ) ;
45
52
proc ? . WaitForExit ( ) ;
46
53
var exitCode = proc ? . ExitCode ?? - 1 ;
47
54
if ( exitCode != 0 )
@@ -52,12 +59,50 @@ private bool RunCommand(string args)
52
59
return true ;
53
60
}
54
61
55
- public bool RestoreToDirectory ( string projectOrSolutionFile , string packageDirectory , string ? pathToNugetConfig = null )
62
+ private bool RunCommand ( string args , out IList < string > output )
63
+ {
64
+ progressMonitor . RunningProcess ( $ "{ dotnet } { args } ") ;
65
+ var pi = MakeDotnetStartInfo ( args , redirectStandardOutput : true ) ;
66
+ var exitCode = pi . ReadOutput ( out output ) ;
67
+ if ( exitCode != 0 )
68
+ {
69
+ progressMonitor . CommandFailed ( dotnet , args , exitCode ) ;
70
+ return false ;
71
+ }
72
+ return true ;
73
+ }
74
+
75
+ private static string GetRestoreArgs ( string projectOrSolutionFile , string packageDirectory ) =>
76
+ $ "restore --no-dependencies \" { projectOrSolutionFile } \" --packages \" { packageDirectory } \" /p:DisableImplicitNuGetFallbackFolder=true";
77
+
78
+ public bool RestoreProjectToDirectory ( string projectFile , string packageDirectory , out string stdout , string ? pathToNugetConfig = null )
56
79
{
57
- var args = $ "restore --no-dependencies \" { projectOrSolutionFile } \" --packages \" { packageDirectory } \" /p:DisableImplicitNuGetFallbackFolder=true" ;
80
+ var args = GetRestoreArgs ( projectFile , packageDirectory ) ;
58
81
if ( pathToNugetConfig != null )
82
+ {
59
83
args += $ " --configfile \" { pathToNugetConfig } \" ";
60
- return RunCommand ( args ) ;
84
+ }
85
+ var success = RunCommand ( args , out var output ) ;
86
+ stdout = string . Join ( "\n " , output ) ;
87
+ return success ;
88
+ }
89
+
90
+ public bool RestoreSolutionToDirectory ( string solutionFile , string packageDirectory , out IEnumerable < string > projects )
91
+ {
92
+ var args = GetRestoreArgs ( solutionFile , packageDirectory ) ;
93
+ args += " --verbosity normal" ;
94
+ if ( RunCommand ( args , out var output ) )
95
+ {
96
+ var regex = RestoreProjectRegex ( ) ;
97
+ projects = output
98
+ . Select ( line => regex . Match ( line ) )
99
+ . Where ( match => match . Success )
100
+ . Select ( match => match . Groups [ 1 ] . Value ) ;
101
+ return true ;
102
+ }
103
+
104
+ projects = Array . Empty < string > ( ) ;
105
+ return false ;
61
106
}
62
107
63
108
public bool New ( string folder )
@@ -78,22 +123,21 @@ public bool AddPackage(string folder, string package)
78
123
79
124
private IList < string > GetListed ( string args , string artifact )
80
125
{
81
- progressMonitor . RunningProcess ( $ "{ dotnet } { args } ") ;
82
- var pi = this . MakeDotnetStartInfo ( args , redirectStandardOutput : true ) ;
83
- var exitCode = pi . ReadOutput ( out var artifacts ) ;
84
- if ( exitCode != 0 )
126
+ if ( RunCommand ( args , out var artifacts ) )
85
127
{
86
- progressMonitor . CommandFailed ( dotnet , args , exitCode ) ;
87
- return new List < string > ( ) ;
128
+ progressMonitor . LogInfo ( $ "Found { artifact } s: { string . Join ( " \n " , artifacts ) } " ) ;
129
+ return artifacts ;
88
130
}
89
- progressMonitor . LogInfo ( $ "Found { artifact } s: { string . Join ( "\n " , artifacts ) } ") ;
90
- return artifacts ;
131
+ return new List < string > ( ) ;
91
132
}
92
133
93
134
public bool Exec ( string execArgs )
94
135
{
95
136
var args = $ "exec { execArgs } ";
96
137
return RunCommand ( args ) ;
97
138
}
139
+
140
+ [ GeneratedRegex ( "Restored\\ s+(.+\\ .csproj)" , RegexOptions . Compiled ) ]
141
+ private static partial Regex RestoreProjectRegex ( ) ;
98
142
}
99
143
}
0 commit comments