in build/Xamarin.Build/MSBuild/UpdateInvertedDependencies.cs [97:260]
IEnumerable<InvertedDependency> GetNuGetDependencies ()
{
var packagesToProjects = new Dictionary<PackageReference, List<Project>> ();
var packageRoots = new HashSet<string> ();
List<string> nugetFlatContainerBaseUris = null;
IEnumerable<PackageReference> SelectPackages (Project project)
{
var packageReferences = project
.GetItems ("PackageReference")
.Select (pr => new PackageReference (
pr.EvaluatedInclude,
pr.GetMetadataValue ("Version")));
var packageRoot = project.GetPropertyValue ("NuGetPackageRoot");
if (!string.IsNullOrEmpty (packageRoot))
packageRoots.Add (packageRoot);
foreach (var packageReference in packageReferences) {
if (ExcludePackageReferences.Any (excluded => string.Equals (
excluded, packageReference.Id, StringComparison.OrdinalIgnoreCase)))
continue;
if (!packagesToProjects.TryGetValue (packageReference, out var projects))
packagesToProjects.Add (packageReference, projects = new List<Project> ());
projects.Add (project);
yield return packageReference;
}
}
string MakePackagePath (PackageReference packageReference)
=> Path.Combine (
packageReference.Id,
packageReference.Version,
packageReference.Id + ".nuspec");
string GetNuSpecPath (PackageReference packageReference)
{
var packagePath = MakePackagePath (packageReference);
var searchPaths = new List<string> (packageRoots);
if (NuspecCacheDirectory != null)
searchPaths.Add (NuspecCacheDirectory);
return searchPaths
.SelectMany (packageRoot => new [] {
Path.Combine (packageRoot, packagePath.ToLowerInvariant ()),
Path.Combine (packageRoot, packagePath)
})
.FirstOrDefault (File.Exists);
}
void DownloadNuSpec (PackageReference packageReference)
{
if (NuGetTool == null || NuspecCacheDirectory == null)
return;
if (nugetFlatContainerBaseUris == null) {
var serializer = JsonSerializer.CreateDefault ();
nugetFlatContainerBaseUris = Exec
.Run (NuGetTool, "sources", "-Format", "Short")
.Where (source => source.StartsWith ("E ", StringComparison.Ordinal))
.Select (source => source.Substring (2))
.Select (source => {
try {
var (stream, contentType) = HttpGet (source);
using (stream)
using (var streamReader = new StreamReader (stream))
using (var jsonReader = new JsonTextReader (streamReader))
return serializer
.Deserialize<NuGetResources> (jsonReader)
.Resources
.Where (resource => resource.Type == "PackageBaseAddress/3.0.0")
.Select (resource => resource.Id)
.SingleOrDefault ();
} catch (HttpRequestException) {
return null;
}
})
.Where (source => source != null)
.ToList ();
}
foreach (var baseUri in nugetFlatContainerBaseUris) {
var relativePath = MakePackagePath (packageReference).ToLowerInvariant ();
var localPath = Path.Combine (NuspecCacheDirectory, relativePath);
var uri = $"{baseUri}{relativePath.Replace (Path.DirectorySeparatorChar, '/')}";
try {
Directory.CreateDirectory (Path.GetDirectoryName (localPath));
var (stream, contentType) = HttpGet (uri);
using (stream) {
if (contentType.EndsWith ("/xml", StringComparison.OrdinalIgnoreCase)) {
using (var fileStream = File.Create (localPath))
stream.CopyTo (fileStream);
} else {
// MyGet does not implement NuGet v3 PackageBaseAddress/3.0.0 at all and will
// only and always return the nupkg as content and never the nuspec :(
// https://twitter.com/MyGetTeam/status/1011688120121810944
Log.LogMessage ("-> non-nuspec/XML detected; assuming nupkg archive");
using (var archive = new SIOCZipArchive (stream, ZipArchiveMode.Read))
archive
.Entries
.First (entry => string.Equals (
entry.FullName,
packageReference.Id + ".nuspec",
StringComparison.OrdinalIgnoreCase))
.ExtractToFile (
localPath,
overwrite: true);
}
}
break;
} catch (HttpRequestException) {
}
}
}
var projectCollection = new ProjectCollection ();
return Exec.Run (
new ProcessStartInfo {
FileName = "git",
WorkingDirectory = WorkingDirectory
}, "ls-files", "--recurse-submodules", "*.csproj", "*.fsproj", "*.vbproj")
.Where (projectPath => !ExcludeProjectNames.Contains (Path.GetFileNameWithoutExtension (projectPath)))
.OrderBy (projectPath => projectPath)
.Select (projectPath => projectCollection.LoadProject (projectPath))
.SelectMany (SelectPackages)
.OrderBy (pr => pr)
.Distinct ()
.Select (packageReference => {
var invertedDependency = InvertedDependency.Create (
this,
DependencyKind.NuGet,
packageReference.Id,
packageReference.Version);
invertedDependency.DependentProjects = packagesToProjects [packageReference]
.Select (p => Path.GetFileNameWithoutExtension (p.FullPath))
.ToArray ();
var nuspecPath = GetNuSpecPath (packageReference);
if (nuspecPath == null) {
DownloadNuSpec (packageReference);
nuspecPath = GetNuSpecPath (packageReference);
}
if (nuspecPath != null) {
Log.LogMessage ("-> Parsing nuspec {0}", nuspecPath);
var nuspec = XDocument.Load (nuspecPath);
var ns = nuspec.Root.GetDefaultNamespace ();
var metadata = nuspec.Root.Element (ns + "metadata");
invertedDependency.ProjectUrl = metadata?.Element (ns + "projectUrl")?.Value;
invertedDependency.LicenseUrl = metadata?.Element (ns + "licenseUrl")?.Value;
}
return invertedDependency;
});
}