/// <summary> /// Retrieves the specified component from NuGet. /// </summary> /// <param name="name">NuGet package name</param> /// <param name="version">Package version</param> /// <returns></returns> public async Task <Component> GetComponentAsync(string name, string version) { if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(version)) { return(null); } Console.WriteLine("Retrieving " + name + " " + version); var component = new Component { Name = name, Version = version, Purl = Utils.GeneratePackageUrl(name, version) }; var url = _baseUrl + name + "/" + version + "/" + name + ".nuspec"; var doc = await _httpClient.GetXmlAsync(url); if (doc == null) { return(component); } var root = doc.DocumentElement; var metadata = root.SelectSingleNode("/*[local-name() = 'package']/*[local-name() = 'metadata']"); component.Publisher = GetNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'authors']"); component.Copyright = GetNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'copyright']"); var title = GetNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'title']"); var summary = GetNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'summary']"); var description = GetNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'description']"); if (summary != null) { component.Description = summary; } else if (description != null) { component.Description = description; } else if (title != null) { component.Description = title; } // Utilize the new license expression field present in more recent packages // TODO: Need to have more robust parsing to support composite expressions seen in (https://github.com/NuGet/Home/wiki/Packaging-License-within-the-nupkg#project-properties) var licenseNode = metadata.SelectSingleNode("/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'license']"); var licenseUrlNode = metadata.SelectSingleNode("/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'licenseUrl']"); if (licenseNode?.Attributes["type"].Value == "expression") { var licenses = licenseNode.FirstChild.Value .Replace("AND", ";") .Replace("OR", ";") .Replace("WITH", ";") .Replace("+", "") .Split(';').ToList(); foreach (var license in licenses) { component.Licenses.Add(new Models.License { Id = license.Trim(), Name = license.Trim() }); } } else if (licenseUrlNode != null) { var licenseUrl = licenseUrlNode.FirstChild.Value; var license = await _githubService.GetLicenseAsync(licenseUrl.Trim()); component.Licenses.Add(license ?? new Models.License { Url = licenseUrl.Trim() }); } var projectUrl = GetNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'projectUrl']"); if (projectUrl != null) { var externalReference = new Models.ExternalReference(); externalReference.Type = Models.ExternalReference.WEBSITE; externalReference.Url = projectUrl; component.ExternalReferences.Add(externalReference); } var dependencies = metadata.SelectNodes("/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'dependencies']/*[local-name() = 'dependency']"); foreach (XmlNode dependency in dependencies) { var dependencyName = dependency.Attributes["id"]; var dependencyVersion = dependency.Attributes["version"]; if (dependencyName != null && dependencyVersion != null) { var nugetDependency = new NugetPackage { Name = dependencyName.Value, Version = dependencyVersion.Value, }; component.Dependencies.Add(nugetDependency); } } return(component); }
/// <summary> /// Retrieves the specified component from NuGet. /// </summary> /// <param name="name">NuGet package name</param> /// <param name="version">Package version</param> /// <returns></returns> public async Task <Component> GetComponentAsync(string name, string version, string scope) { if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(version)) { return(null); } Console.WriteLine("Retrieving " + name + " " + version); var component = new Component { Name = name, Version = version, Scope = scope, Purl = Utils.GeneratePackageUrl(name, version) }; var nuspecFilename = GetCachedNuspecFilename(name, version); NuspecReader nuspecReader = null; if (nuspecFilename == null) { var url = _baseUrl + name + "/" + version + "/" + name + ".nuspec"; using (var xmlStream = await _httpClient.GetXmlStreamAsync(url).ConfigureAwait(false)) { if (xmlStream != null) { nuspecReader = new NuspecReader(xmlStream); } } } else { using (var xmlStream = _fileSystem.File.Open(nuspecFilename, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { nuspecReader = new NuspecReader(xmlStream); } } if (nuspecReader == null) { return(component); } component.Publisher = nuspecReader.GetAuthors(); component.Copyright = nuspecReader.GetCopyright(); // this prevents empty copyright values in the JSON BOM if (string.IsNullOrEmpty(component.Copyright)) { component.Copyright = null; } var title = nuspecReader.GetTitle(); var summary = nuspecReader.GetSummary(); var description = nuspecReader.GetDescription(); if (!string.IsNullOrEmpty(summary)) { component.Description = summary; } else if (!string.IsNullOrEmpty(description)) { component.Description = description; } else if (!string.IsNullOrEmpty(title)) { component.Description = title; } var licenseMetadata = nuspecReader.GetLicenseMetadata(); if (licenseMetadata != null && licenseMetadata.Type == NuGet.Packaging.LicenseType.Expression) { Action <NuGetLicense> licenseProcessor = delegate(NuGetLicense nugetLicense) { var license = new Models.License { Id = nugetLicense.Identifier, Name = nugetLicense.Identifier }; component.Licenses.Add(new ComponentLicense { License = license }); }; licenseMetadata.LicenseExpression.OnEachLeafNode(licenseProcessor, null); } else { var licenseUrl = nuspecReader.GetLicenseUrl(); if (!string.IsNullOrEmpty(licenseUrl)) { Models.License license = null; if (_githubService != null) { license = await _githubService.GetLicenseAsync(licenseUrl).ConfigureAwait(false); } if (license == null) { license = new Models.License { Url = licenseUrl }; } component.Licenses.Add(new ComponentLicense { License = license }); } } var projectUrl = nuspecReader.GetProjectUrl(); if (projectUrl != null) { var externalReference = new Models.ExternalReference(); externalReference.Type = Models.ExternalReference.WEBSITE; externalReference.Url = projectUrl; component.ExternalReferences.Add(externalReference); } return(component); }