private void ValidateHarvestVersionForReport(string packageReportPath) { PackageReport packageReport = GetPackageReportFromPath(packageReportPath); bool isHarvestingAssetsFromPackage = TryGetHarvestVersionFromReport(packageReport, out string harvestVersion, out int harvestMajor, out int harvestMinor); if (isHarvestingAssetsFromPackage) { if (packageReport.Version.StartsWith($"{harvestMajor}.{harvestMinor}.")) { Log.LogError($"Validation Failed: {packageReport.Id} is harvesting package version {harvestVersion} which belongs to the current package release: {packageReport.Version}"); return; } string latestPatchVersion = GetLatestStableVersionForPackageRelease(packageReport.Id, harvestMajor, harvestMinor); if (latestPatchVersion.CompareTo(harvestVersion) != 0) { Log.LogError($"Validation Failed: {packageReport.Id} is harvesting assets from package version {harvestVersion} which is not the latest for that package release. Latest package version from that release is {latestPatchVersion}. In order to fix this, run `dotnet msbuild {packageReport.Id}.pkgproj /t:UpdateHarvestVersionOnPackageIndex /p:UpdateStablePackageInfo=true`"); } else { Log.LogMessage(LogImportance.Normal, $"Validation Succeeded: {packageReport.Id} is harvesting assets from package version {harvestVersion} which is the latest for that package erreleasea."); } } else { Log.LogMessage(LogImportance.Normal, $"Validation Succeeded: {packageReport.Id} is not harvesting any assets."); } }
private bool TryGetHarvestVersionFromReport(PackageReport report, out string harvestVersion, out int harvestEraMajor, out int harvestEraMinor) { harvestVersion = string.Empty; harvestEraMajor = harvestEraMinor = 0; foreach (KeyValuePair <string, Target> packageTarget in report.Targets.NullAsEmpty()) { foreach (PackageAsset compileAsset in packageTarget.Value.CompileAssets.NullAsEmpty()) { if (!string.IsNullOrEmpty(compileAsset.HarvestedFrom)) { return(GetHarvestVersionFromString(compileAsset.HarvestedFrom, report.Id, out harvestVersion, out harvestEraMajor, out harvestEraMinor)); } } foreach (PackageAsset runtimeAsset in packageTarget.Value.RuntimeAssets.NullAsEmpty()) { if (!string.IsNullOrEmpty(runtimeAsset.HarvestedFrom)) { return(GetHarvestVersionFromString(runtimeAsset.HarvestedFrom, report.Id, out harvestVersion, out harvestEraMajor, out harvestEraMinor)); } } foreach (PackageAsset nativeAsset in packageTarget.Value.NativeAssets.NullAsEmpty()) { if (!string.IsNullOrEmpty(nativeAsset.HarvestedFrom)) { return(GetHarvestVersionFromString(nativeAsset.HarvestedFrom, report.Id, out harvestVersion, out harvestEraMajor, out harvestEraMinor)); } } } return(false); }
/// <summary> /// Generates a table in markdown that lists the API version supported by /// various packages at all levels of NETStandard. /// </summary> /// <returns></returns> public override bool Execute() { if (PackageReports == null || PackageReports.Length == 0) { Log.LogError("PackageReports argument must be specified"); return(false); } if (TargetMoniker == null || TargetMoniker.Length == 0) { Log.LogError("TargetMoniker argument must be specified"); return(false); } NuGetFramework fx = NuGetFramework.Parse(TargetMoniker); string targetString = String.IsNullOrEmpty(TargetRuntime) ? fx.ToString() : $"{fx}/{TargetRuntime}"; var compileAssets = new List <ITaskItem>(); var runtimeAssets = new List <ITaskItem>(); var nativeAssets = new List <ITaskItem>(); var buildProjects = new List <BuildProject>(); foreach (var reportPath in PackageReports) { var report = PackageReport.Load(reportPath); Target target = null; if (report.Targets.TryGetValue(targetString, out target)) { compileAssets.AddRange(target.CompileAssets.Select(c => ItemFromApplicableAsset(c, report.Id, report.Version))); buildProjects.AddRange(target.CompileAssets.Select(c => c.SourceProject).Where(bp => bp != null)); runtimeAssets.AddRange(target.RuntimeAssets.Select(r => ItemFromApplicableAsset(r, report.Id, report.Version))); buildProjects.AddRange(target.RuntimeAssets.Select(r => r.SourceProject).Where(bp => bp != null)); nativeAssets.AddRange(target.NativeAssets.Select(r => ItemFromApplicableAsset(r, report.Id, report.Version))); buildProjects.AddRange(target.NativeAssets.Select(r => r.SourceProject).Where(bp => bp != null)); } else { Log.LogMessage($"No assets found for '{report.Id}' applicable to '{targetString}'."); } } CompileAssets = compileAssets.ToArray(); RuntimeAssets = runtimeAssets.ToArray(); NativeAssets = nativeAssets.ToArray(); BuildProjects = buildProjects.Distinct().Select(bp => bp.ToItem()).ToArray(); return(!Log.HasLoggedErrors); }
public override bool Execute() { PackageReport packageReport = GetPackageReportFromPath(); bool isHarvestingAssetsFromPackage = TryGetHarvestVersionFromReport(packageReport, out string harvestVersion, out int harvestEraMajor, out int harvestEraMinor); if (isHarvestingAssetsFromPackage) { if (packageReport.Version.StartsWith($"{harvestEraMajor}.{harvestEraMinor}.")) { Log.LogError($"Validation Failed: {packageReport.Id} is harvesting package version {harvestVersion} which belongs to the current package era: {packageReport.Version}"); return(false); } // If no package versions endpoints were provided, then default to use NuGet.org version endpoint. if (NugetPackageVersionsEndpoints == null || NugetPackageVersionsEndpoints.Length == 0) { NugetPackageVersionsEndpoints = new TaskItem[] { new TaskItem(NuGetDotOrgVersionEndpoint) }; } string latestPatchVersion = GetLatestStableVersionForEraAsync(packageReport.Id, harvestEraMajor, harvestEraMinor).GetAwaiter().GetResult(); if (latestPatchVersion.CompareTo(harvestVersion) != 0) { Log.LogError($"Validation Failed: {packageReport.Id} is harvesting assets from package version {harvestVersion} which is not the latest for that package era. Latest package version from that era is {latestPatchVersion}."); } else { Log.LogMessage(LogImportance.Normal, $"Validation Succeeded: {packageReport.Id} is harvesting assets from package version {harvestVersion} which is the latest for that package era."); } } else { Log.LogMessage(LogImportance.Normal, $"Validation Succeeded: {packageReport.Id} is not harvesting any assets."); } return(!Log.HasLoggedErrors); }
public override bool Execute() { var supportedPackages = new List <ITaskItem>(); foreach (var packageReport in PackageReports.NullAsEmpty()) { var report = PackageReport.Load(packageReport); var packageId = report.Id; var packageVersion = report.Version; var supportedTargets = report.Targets.Values.Where(target => report.SupportedFrameworks.ContainsKey(target.Framework)); var fxRIDGroupings = supportedTargets.GroupBy(target => target.Framework, target => target.RuntimeID); foreach (var fxRIDGrouping in fxRIDGroupings) { var fx = fxRIDGrouping.Key; var rids = fxRIDGrouping.ToArray(); var nugetFx = NuGetFramework.Parse(fx); var supportedPackage = new TaskItem(packageId); supportedPackage.SetMetadata("Version", packageVersion); supportedPackage.SetMetadata("TargetFramework", fx); supportedPackage.SetMetadata("TargetFrameworkShort", nugetFx.GetShortFolderName()); var ridList = string.Join(";", rids); if (!String.IsNullOrEmpty(ridList)) { supportedPackage.SetMetadata("RuntimeIdentifiers", ridList); } supportedPackages.Add(supportedPackage); } } SupportedPackages = supportedPackages.ToArray(); return(!Log.HasLoggedErrors); }
private void LoadReport() { _report = PackageReport.Load(ReportFile); }
public override bool Execute() { LoadFiles(); LoadFrameworks(); var report = new PackageReport() { Id = PackageId, Version = PackageVersion, SupportedFrameworks = new Dictionary <string, string>() }; string package = $"{PackageId}/{PackageVersion}"; foreach (var framework in _frameworks.OrderBy(f => f.Key.ToString())) { var fx = framework.Key; var runtimeIds = framework.Value; var compileAssets = _resolver.ResolveCompileAssets(fx, PackageId); bool hasCompileAsset, hasCompilePlaceHolder; NuGetAssetResolver.ExamineAssets(Log, "Compile", package, fx.ToString(), compileAssets, out hasCompileAsset, out hasCompilePlaceHolder); MarkUsed(compileAssets); // start by making sure it has some asset available for compile var isSupported = hasCompileAsset || hasCompilePlaceHolder; if (runtimeIds.All(rid => !String.IsNullOrEmpty(rid))) { // Add Framework only (compile) target if all RIDs are non-empty. // This acts as a compile target for a framework that requires a RID for runtime. var reportTarget = new Target() { Framework = fx.ToString(), RuntimeID = null, CompileAssets = compileAssets.Select(c => GetPackageAssetFromTargetPath(c)).ToArray() }; report.Targets.Add(fx.ToString(), reportTarget); } foreach (var runtimeId in runtimeIds) { string target = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}"; var runtimeAssets = _resolver.ResolveRuntimeAssets(fx, runtimeId); bool hasRuntimeAsset, hasRuntimePlaceHolder; NuGetAssetResolver.ExamineAssets(Log, "Runtime", package, target, runtimeAssets, out hasRuntimeAsset, out hasRuntimePlaceHolder); MarkUsed(runtimeAssets); if (!FrameworkUtilities.IsGenerationMoniker(fx) && !fx.IsPCL) { // only look at runtime assets for runnable frameworks. isSupported &= (hasCompileAsset && hasRuntimeAsset) || // matching assets (hasCompilePlaceHolder && hasRuntimeAsset) || // private runtime (hasCompilePlaceHolder && hasRuntimePlaceHolder); // placeholders } var nativeAssets = _resolver.ResolveNativeAssets(fx, runtimeId); MarkUsed(nativeAssets); var reportTarget = new Target() { Framework = fx.ToString(), RuntimeID = runtimeId, CompileAssets = compileAssets.Select(c => GetPackageAssetFromTargetPath(c)).ToArray(), RuntimeAssets = runtimeAssets.Select(r => GetPackageAssetFromTargetPath(r)).ToArray(), NativeAssets = nativeAssets.Select(n => GetPackageAssetFromTargetPath(n)).ToArray() }; report.Targets[target] = reportTarget; } if (isSupported) { // Find version // first try the resolved compile asset for this package var refAssm = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r))?.Substring(PackageId.Length + 1); if (refAssm == null) { // if we didn't have a compile asset it means this framework is supported inbox with a placeholder // resolve the assets without placeholders to pick up the netstandard reference assembly. compileAssets = _resolverWithoutPlaceholders.ResolveCompileAssets(fx); refAssm = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r)); } var version = "unknown"; if (refAssm != null) { version = _targetPathToPackageItem[AggregateNuGetAssetResolver.AsPackageSpecificTargetPath(PackageId, refAssm)].Version?.ToString() ?? version; } report.SupportedFrameworks.Add(fx.ToString(), version); } } report.UnusedAssets = _unusedTargetPaths.Select(tp => GetPackageAssetFromTargetPath(tp)).ToArray(); report.Save(ReportFile); return(!Log.HasLoggedErrors); }
/// <summary> /// Generates a table in markdown that lists the API version supported by /// various packages at all levels of NETStandard. /// </summary> /// <returns></returns> public override bool Execute() { if (Reports == null || Reports.Length == 0) { Log.LogError("Reports argument must be specified"); return(false); } if (String.IsNullOrEmpty(DocFilePath)) { Log.LogError("DocFilePath argument must be specified"); return(false); } string docDir = Path.GetDirectoryName(DocFilePath); if (!Directory.Exists(docDir)) { Directory.CreateDirectory(docDir); } SortedSet <Version> knownNetStandardVersions = new SortedSet <Version>(); List <SupportRow> rows = new List <SupportRow>(Reports.Length); foreach (var reportPath in Reports.Select(r => r.GetMetadata("FullPath"))) { SupportRow row = new SupportRow(); row.Name = Path.GetFileNameWithoutExtension(reportPath); row.SuportedVersions = new SortedSet <NETStandardApiVersion>(); var report = PackageReport.Load(reportPath); foreach (var supportedFramework in report.SupportedFrameworks) { var fx = NuGetFramework.Parse(supportedFramework.Key); if (fx.Framework == FrameworkConstants.FrameworkIdentifiers.NetStandard) { row.SuportedVersions.Add(new NETStandardApiVersion(fx.Version, new Version(supportedFramework.Value.ToString()))); knownNetStandardVersions.Add(fx.Version); } } rows.Add(row); } StringBuilder table = new StringBuilder(); table.AppendLine($"| Contract | {String.Join(" | ", knownNetStandardVersions.Select(v => v.ToString(2)))} |"); table.AppendLine($"| -------- | {String.Join(" | ", Enumerable.Repeat("---", knownNetStandardVersions.Count))}"); foreach (var row in rows.OrderBy(r => r.Name)) { if (row.SuportedVersions.Count == 0) { Log.LogMessage($"Skipping {row.Name} since it has no supported NETStandard versions"); continue; } table.Append($"| {row.Name} |"); foreach (var netStandardVersion in knownNetStandardVersions) { var apiVersion = row.SuportedVersions.LastOrDefault(a => a.NETStandardVersion <= netStandardVersion); table.Append(" "); if (apiVersion != null) { table.Append(apiVersion.APIVersion.ToString(3)); } table.Append(" |"); } table.AppendLine(); } if (!InsertIntoFile) { File.WriteAllText(DocFilePath, table.ToString()); } else { if (!File.Exists(DocFilePath)) { Log.LogError($"InsertIntoFile was specified as true but {DocFilePath} did not exist."); return(false); } string originalText = File.ReadAllText(DocFilePath); int startIndex = originalText.IndexOf(startMarker); if (startIndex < 0) { Log.LogError($"InsertIntoFile was specified as true but could not locate insertion start text \"{startMarker}\"."); return(false); } startIndex += startMarker.Length; // skip any white-space / new line while (startIndex < originalText.Length && Char.IsWhiteSpace(originalText[startIndex])) { startIndex++; } int endIndex = originalText.IndexOf(endMarker, startIndex); if (endIndex < 0) { Log.LogError($"InsertIntoFile was specified as true but could not locate insertion end text \"{endMarker}\"."); return(false); } var docText = new StringBuilder(originalText); docText.Remove(startIndex, endIndex - startIndex); docText.Insert(startIndex, table.ToString()); File.WriteAllText(DocFilePath, docText.ToString(), Encoding.UTF8); } return(!Log.HasLoggedErrors); }
public override bool Execute() { LoadFiles(); LoadFrameworks(); var report = new PackageReport() { Id = PackageId, Version = PackageVersion, SupportedFrameworks = new Dictionary<string, string>() }; string package = $"{PackageId}/{PackageVersion}"; foreach (var framework in _frameworks.OrderBy(f => f.Key.ToString())) { var fx = framework.Key; var runtimeIds = framework.Value; var compileAssets = _resolver.ResolveCompileAssets(fx, PackageId); bool hasCompileAsset, hasCompilePlaceHolder; NuGetAssetResolver.ExamineAssets(Log, "Compile", package, fx.ToString(), compileAssets, out hasCompileAsset, out hasCompilePlaceHolder); MarkUsed(compileAssets); // start by making sure it has some asset available for compile var isSupported = hasCompileAsset || hasCompilePlaceHolder; if (runtimeIds.All(rid => !String.IsNullOrEmpty(rid))) { // Add Framework only (compile) target if all RIDs are non-empty. // This acts as a compile target for a framework that requires a RID for runtime. var reportTarget = new Target() { Framework = fx.ToString(), RuntimeID = null, CompileAssets = compileAssets.Select(c => GetPackageAssetFromTargetPath(c)).ToArray() }; report.Targets.Add(fx.ToString(), reportTarget); } foreach (var runtimeId in runtimeIds) { string target = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}"; var runtimeAssets = _resolver.ResolveRuntimeAssets(fx, runtimeId); bool hasRuntimeAsset, hasRuntimePlaceHolder; NuGetAssetResolver.ExamineAssets(Log, "Runtime", package, target, runtimeAssets, out hasRuntimeAsset, out hasRuntimePlaceHolder); MarkUsed(runtimeAssets); if (!FrameworkUtilities.IsGenerationMoniker(fx) && !fx.IsPCL) { // only look at runtime assets for runnable frameworks. isSupported &= hasCompileAsset == hasRuntimeAsset; isSupported &= hasCompilePlaceHolder == hasRuntimePlaceHolder; } var nativeAssets = _resolver.ResolveNativeAssets(fx, runtimeId); MarkUsed(nativeAssets); var reportTarget = new Target() { Framework = fx.ToString(), RuntimeID = runtimeId, CompileAssets = compileAssets.Select(c => GetPackageAssetFromTargetPath(c)).ToArray(), RuntimeAssets = runtimeAssets.Select(r => GetPackageAssetFromTargetPath(r)).ToArray(), NativeAssets = nativeAssets.Select(n => GetPackageAssetFromTargetPath(n)).ToArray() }; report.Targets[target] = reportTarget; } if (isSupported) { // Find version // first try the resolved compile asset for this package var refAssm = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r))?.Substring(PackageId.Length + 1); if (refAssm == null) { // if we didn't have a compile asset it means this framework is supported inbox with a placeholder // resolve the assets without placeholders to pick up the netstandard reference assembly. compileAssets = _resolverWithoutPlaceholders.ResolveCompileAssets(fx); refAssm = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r)); } var version = "unknown"; if (refAssm != null) { version = _targetPathToPackageItem[AggregateNuGetAssetResolver.AsPackageSpecificTargetPath(PackageId, refAssm)].Version?.ToString() ?? version; } report.SupportedFrameworks.Add(fx.ToString(), version); } } report.UnusedAssets = _unusedTargetPaths.Select(tp => GetPackageAssetFromTargetPath(tp)).ToArray(); report.Save(ReportFile); return !Log.HasLoggedErrors; }
// Making this method protected virtual for tests. protected virtual PackageReport GetPackageReportFromPath() { return(PackageReport.Load(PackageReportPath)); }
// Making this method protected virtual for tests. protected virtual PackageReport GetPackageReportFromPath(string path) { return(PackageReport.Load(path)); }
public override bool Execute() { var frameworks = Frameworks.NullAsEmpty().ToDictionary( i => NuGetFramework.Parse(i.ItemSpec), i => { var rids = i.GetMetadata("RuntimeIds"); return(String.IsNullOrEmpty(rids) ? new HashSet <string>() : new HashSet <string>(rids.Split(';'))); }, NuGetFramework.Comparer); var layoutFiles = new List <ITaskItem>(); foreach (var packageReportFile in PackageReports) { var packageReport = PackageReport.Load(packageReportFile); foreach (var targetInfo in packageReport.Targets) { var targetName = targetInfo.Key; var target = targetInfo.Value; var targetParts = targetName.Split('/'); var fx = NuGetFramework.Parse(targetParts[0]); string rid = null; if (targetParts.Length > 1) { rid = targetParts[1]; } if (frameworks.Count != 0) { HashSet <string> rids = null; if (!frameworks.TryGetValue(fx, out rids)) { Log.LogMessage(LogImportance.Low, $"Skipping {fx} since it is not in {nameof(Frameworks)}"); continue; } if (rid != null && rids.Count > 0 && !rids.Contains(rid)) { Log.LogMessage(LogImportance.Low, $"Skipping {fx}/{rid} since it is not in {nameof(Frameworks)}"); continue; } } if (!packageReport.SupportedFrameworks.ContainsKey(fx.ToString())) { Log.LogMessage(LogImportance.Low, $"Skipping {fx} since it is not supported"); continue; } var fxFolder = fx.GetShortFolderName(); if (rid == null) { // only consider compile assets for RID-less target layoutFiles.AddRange(CreateLayoutFiles(target.CompileAssets, $"ref\\{fxFolder}", "Compile")); } layoutFiles.AddRange(CreateLayoutFiles(target.RuntimeAssets, $"runtimes\\{rid}\\lib\\{fxFolder}", "Runtime")); layoutFiles.AddRange(CreateLayoutFiles(target.NativeAssets, $"runtimes\\{rid}\\native", "Native")); } } LayoutFiles = layoutFiles.ToArray(); return(!Log.HasLoggedErrors); }