1
1
using System ;
2
+ using System . Collections . Generic ;
2
3
using System . Diagnostics ;
3
4
using System . IO ;
4
5
using System . Linq ;
5
- using Microsoft . Build . Framework ;
6
6
using Semmle . Util ;
7
7
8
8
namespace Semmle . Extraction . CSharp . DependencyFetching
@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
12
12
/// Locates packages in a source tree and downloads all of the
13
13
/// referenced assemblies to a temp folder.
14
14
/// </summary>
15
- internal class NugetPackages
15
+ internal class NugetPackages : IDisposable
16
16
{
17
17
private readonly string ? nugetExe ;
18
18
private readonly Util . Logging . ILogger logger ;
@@ -24,6 +24,9 @@ internal class NugetPackages
24
24
25
25
public int PackageCount => packageFiles . Length ;
26
26
27
+ private readonly string ? backupNugetConfig ;
28
+ private readonly string ? nugetConfigPath ;
29
+
27
30
/// <summary>
28
31
/// The computed packages directory.
29
32
/// This will be in the Temp location
@@ -47,6 +50,41 @@ public NugetPackages(string sourceDir, TemporaryDirectory packageDirectory, Util
47
50
{
48
51
logger . LogInfo ( $ "Found { packageFiles . Length } packages.config files, trying to use nuget.exe for package restore") ;
49
52
nugetExe = ResolveNugetExe ( sourceDir ) ;
53
+ if ( HasNoPackageSource ( ) )
54
+ {
55
+ // We only modify or add a top level nuget.config file
56
+ nugetConfigPath = Path . Combine ( sourceDir , "nuget.config" ) ;
57
+ try
58
+ {
59
+ if ( File . Exists ( nugetConfigPath ) )
60
+ {
61
+ var tempFolderPath = FileUtils . GetTemporaryWorkingDirectory ( out var _ ) ;
62
+
63
+ do
64
+ {
65
+ backupNugetConfig = Path . Combine ( tempFolderPath , Path . GetRandomFileName ( ) ) ;
66
+ }
67
+ while ( File . Exists ( backupNugetConfig ) ) ;
68
+ File . Copy ( nugetConfigPath , backupNugetConfig , true ) ;
69
+ }
70
+ else
71
+ {
72
+ File . WriteAllText ( nugetConfigPath ,
73
+ """
74
+ <?xml version="1.0" encoding="utf-8"?>
75
+ <configuration>
76
+ <packageSources>
77
+ </packageSources>
78
+ </configuration>
79
+ """ ) ;
80
+ }
81
+ AddDefaultPackageSource ( nugetConfigPath ) ;
82
+ }
83
+ catch ( Exception e )
84
+ {
85
+ logger . LogError ( $ "Failed to add default package source to { nugetConfigPath } : { e } ") ;
86
+ }
87
+ }
50
88
}
51
89
else
52
90
{
@@ -118,15 +156,15 @@ private bool TryRestoreNugetPackage(string package)
118
156
*/
119
157
120
158
string exe , args ;
121
- if ( Util . Win32 . IsWindows ( ) )
159
+ if ( Win32 . IsWindows ( ) )
122
160
{
123
161
exe = nugetExe ! ;
124
- args = string . Format ( "install -OutputDirectory {0 } {1}" , packageDirectory , package ) ;
162
+ args = $ "install -OutputDirectory { packageDirectory } { package } " ;
125
163
}
126
164
else
127
165
{
128
166
exe = "mono" ;
129
- args = string . Format ( "{0 } install -OutputDirectory {1 } {2}" , nugetExe , packageDirectory , package ) ;
167
+ args = $ " { nugetExe } install -OutputDirectory { packageDirectory } { package } " ;
130
168
}
131
169
132
170
var pi = new ProcessStartInfo ( exe , args )
@@ -159,5 +197,75 @@ public int InstallPackages()
159
197
{
160
198
return packageFiles . Count ( package => TryRestoreNugetPackage ( package . FullName ) ) ;
161
199
}
200
+
201
+ private bool HasNoPackageSource ( )
202
+ {
203
+ if ( Win32 . IsWindows ( ) )
204
+ {
205
+ return false ;
206
+ }
207
+
208
+ try
209
+ {
210
+ logger . LogInfo ( "Checking if default package source is available..." ) ;
211
+ RunMonoNugetCommand ( "sources list -ForceEnglishOutput" , out var stdout ) ;
212
+ if ( stdout . All ( line => line != "No sources found." ) )
213
+ {
214
+ return false ;
215
+ }
216
+
217
+ return true ;
218
+ }
219
+ catch ( Exception e )
220
+ {
221
+ logger . LogWarning ( $ "Failed to check if default package source is added: { e } ") ;
222
+ return false ;
223
+ }
224
+ }
225
+
226
+ private void RunMonoNugetCommand ( string command , out IList < string > stdout )
227
+ {
228
+ var exe = "mono" ;
229
+ var args = $ "{ nugetExe } { command } ";
230
+ var pi = new ProcessStartInfo ( exe , args )
231
+ {
232
+ RedirectStandardOutput = true ,
233
+ RedirectStandardError = true ,
234
+ UseShellExecute = false
235
+ } ;
236
+
237
+ var threadId = Environment . CurrentManagedThreadId ;
238
+ void onOut ( string s ) => logger . LogInfo ( s , threadId ) ;
239
+ void onError ( string s ) => logger . LogError ( s , threadId ) ;
240
+ pi . ReadOutput ( out stdout , onOut , onError ) ;
241
+ }
242
+
243
+ private void AddDefaultPackageSource ( string nugetConfig )
244
+ {
245
+ logger . LogInfo ( "Adding default package source..." ) ;
246
+ RunMonoNugetCommand ( $ "sources add -Name DefaultNugetOrg -Source https://api.nuget.org/v3/index.json -ConfigFile \" { nugetConfig } \" ", out var _ ) ;
247
+ }
248
+
249
+ public void Dispose ( )
250
+ {
251
+ if ( nugetConfigPath is null )
252
+ {
253
+ return ;
254
+ }
255
+
256
+ try
257
+ {
258
+ File . Delete ( nugetConfigPath ) ;
259
+
260
+ if ( backupNugetConfig is not null )
261
+ {
262
+ File . Move ( backupNugetConfig , nugetConfigPath ) ;
263
+ }
264
+ }
265
+ catch ( Exception exc )
266
+ {
267
+ logger . LogError ( $ "Failed to restore original nuget.config file: { exc } ") ;
268
+ }
269
+ }
162
270
}
163
271
}
0 commit comments