Skip to content

Commit 029db21

Browse files
authored
Merge pull request github#15650 from tamasvajk/buildless/fallback-nuget-install
C#: Add fallback logic to `nuget install`
2 parents e6f9ef5 + d3ba33d commit 029db21

File tree

2 files changed

+69
-13
lines changed

2 files changed

+69
-13
lines changed

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Security.Cryptography;
77
using System.Text;
8+
using System.Text.RegularExpressions;
89
using System.Threading.Tasks;
910
using Semmle.Util;
1011
using Semmle.Util.Logging;
@@ -14,7 +15,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
1415
/// <summary>
1516
/// Main implementation of the build analysis.
1617
/// </summary>
17-
public sealed class DependencyManager : IDisposable
18+
public sealed partial class DependencyManager : IDisposable
1819
{
1920
private readonly AssemblyCache assemblyCache;
2021
private readonly ILogger logger;
@@ -783,13 +784,53 @@ private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<strin
783784
CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
784785
}
785786

786-
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths)
787+
[GeneratedRegex(@"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
788+
private static partial Regex LegacyNugetPackage();
789+
790+
791+
private static IEnumerable<string> GetRestoredPackageDirectoryNames(DirectoryInfo root)
787792
{
788-
var alreadyDownloadedPackages = Directory.GetDirectories(packageDirectory.DirInfo.FullName)
793+
return Directory.GetDirectories(root.FullName)
789794
.Select(d => Path.GetFileName(d).ToLowerInvariant());
790-
var notYetDownloadedPackages = fileContent.AllPackages
791-
.Except(alreadyDownloadedPackages)
792-
.ToList();
795+
}
796+
797+
private IEnumerable<string> GetRestoredLegacyPackageNames()
798+
{
799+
var oldPackageDirectories = GetRestoredPackageDirectoryNames(legacyPackageDirectory.DirInfo);
800+
foreach (var oldPackageDirectory in oldPackageDirectories)
801+
{
802+
// nuget install restores packages to 'packagename.version' folders (dotnet restore to 'packagename/version' folders)
803+
// typical folder names look like:
804+
// newtonsoft.json.13.0.3
805+
// there are more complex ones too, such as:
806+
// runtime.tizen.4.0.0-armel.Microsoft.NETCore.DotNetHostResolver.2.0.0-preview2-25407-01
807+
808+
var match = LegacyNugetPackage().Match(oldPackageDirectory);
809+
if (!match.Success)
810+
{
811+
logger.LogWarning($"Package directory '{oldPackageDirectory}' doesn't match the expected pattern.");
812+
continue;
813+
}
814+
815+
yield return match.Groups[1].Value.ToLowerInvariant();
816+
}
817+
}
818+
819+
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths)
820+
{
821+
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(packageDirectory.DirInfo);
822+
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();
823+
824+
var notYetDownloadedPackages = new HashSet<string>(fileContent.AllPackages);
825+
foreach (var alreadyDownloadedPackage in alreadyDownloadedPackages)
826+
{
827+
notYetDownloadedPackages.Remove(alreadyDownloadedPackage);
828+
}
829+
foreach (var alreadyDownloadedLegacyPackage in alreadyDownloadedLegacyPackages)
830+
{
831+
notYetDownloadedPackages.Remove(alreadyDownloadedLegacyPackage);
832+
}
833+
793834
if (notYetDownloadedPackages.Count == 0)
794835
{
795836
return;

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FileContent.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,23 +157,35 @@ private static bool IsGroupMatch(ReadOnlySpan<char> line, Regex regex, string gr
157157
return false;
158158
}
159159

160+
private void AddPackageReference(ReadOnlySpan<char> line, string groupName, Func<Regex> regex)
161+
{
162+
foreach (var valueMatch in regex().EnumerateMatches(line))
163+
{
164+
// We can't get the group from the ValueMatch, so doing it manually:
165+
var packageName = GetGroup(line, valueMatch, groupName).ToLowerInvariant();
166+
if (!string.IsNullOrEmpty(packageName))
167+
{
168+
allPackages.Add(packageName);
169+
}
170+
}
171+
}
172+
160173
private void DoInitialize()
161174
{
162175
foreach (var file in files)
163176
{
164177
try
165178
{
179+
var isPackagesConfig = file.EndsWith("packages.config", StringComparison.OrdinalIgnoreCase);
180+
166181
foreach (ReadOnlySpan<char> line in unsafeFileReader.ReadLines(file))
167182
{
168183
// Find all the packages.
169-
foreach (var valueMatch in PackageReference().EnumerateMatches(line))
184+
AddPackageReference(line, "Include", PackageReference);
185+
186+
if (isPackagesConfig)
170187
{
171-
// We can't get the group from the ValueMatch, so doing it manually:
172-
var packageName = GetGroup(line, valueMatch, "Include").ToLowerInvariant();
173-
if (!string.IsNullOrEmpty(packageName))
174-
{
175-
allPackages.Add(packageName);
176-
}
188+
AddPackageReference(line, "id", LegacyPackageReference);
177189
}
178190

179191
// Determine if ASP.NET is used.
@@ -223,6 +235,9 @@ private void DoInitialize()
223235
[GeneratedRegex("(?<!<!--.*)<PackageReference.*\\sInclude=\"(.*?)\".*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
224236
private static partial Regex PackageReference();
225237

238+
[GeneratedRegex("(?<!<!--.*)<package.*\\sid=\"(.*?)\".*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
239+
private static partial Regex LegacyPackageReference();
240+
226241
[GeneratedRegex("(?<!<!--.*)<FrameworkReference.*\\sInclude=\"(.*?)\".*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
227242
private static partial Regex FrameworkReference();
228243

0 commit comments

Comments
 (0)