public override bool Execute() { DateTime startTime = DateTime.Now; Log.LogMessage(MessageImportance.High, "Writing package usage data..."); string[] projectDirectoriesOutsideRoot = ProjectDirectories.NullAsEmpty() .Where(dir => !dir.StartsWith(RootDir, StringComparison.Ordinal)) .ToArray(); if (projectDirectoriesOutsideRoot.Any()) { throw new ArgumentException( $"All ProjectDirectories must be in RootDir '{RootDir}', but found " + string.Join(", ", projectDirectoriesOutsideRoot)); } Log.LogMessage(MessageImportance.Low, "Finding set of RIDs..."); string[] possibleRids = PlatformsRuntimeJsonFiles.NullAsEmpty() .SelectMany(ReadRidsFromRuntimeJson) .Distinct() .ToArray(); Log.LogMessage(MessageImportance.Low, "Reading package identities..."); PackageIdentity[] restored = RestoredPackageFiles.NullAsEmpty() .Select(ReadNuGetPackageInfos.ReadIdentity) .Distinct() .ToArray(); PackageIdentity[] tarballPrebuilt = TarballPrebuiltPackageFiles.NullAsEmpty() .Select(ReadNuGetPackageInfos.ReadIdentity) .Distinct() .ToArray(); PackageIdentity[] sourceBuilt = SourceBuiltPackageFiles.NullAsEmpty() .Select(ReadNuGetPackageInfos.ReadIdentity) .Distinct() .ToArray(); IEnumerable <PackageIdentity> prebuilt = restored.Except(sourceBuilt); PackageIdentity[] toCheck = NuGetPackageInfos.NullAsEmpty() .Select(item => new PackageIdentity( item.GetMetadata("PackageId"), NuGetVersion.Parse(item.GetMetadata("PackageVersion")))) .Concat(prebuilt) .ToArray(); Log.LogMessage(MessageImportance.Low, "Finding project.assets.json files..."); string[] assetFiles = Directory.GetFiles( RootDir, "project.assets.json", SearchOption.AllDirectories); Log.LogMessage(MessageImportance.Low, "Reading usage info..."); var usages = new ConcurrentBag <Usage>(); Parallel.ForEach( assetFiles, assetFile => { var properties = new HashSet <string>(StringComparer.OrdinalIgnoreCase); using (var file = File.OpenRead(assetFile)) using (var reader = new StreamReader(file)) using (var jsonReader = new JsonTextReader(reader)) { while (jsonReader.Read()) { if (jsonReader.TokenType == JsonToken.PropertyName && jsonReader.Value is string value) { properties.Add(value); } } } foreach (var identity in toCheck .Where(id => properties.Contains(id.Id + "/" + id.Version.OriginalVersion))) { usages.Add(Usage.Create( // Store relative path for future report generation. assetFile.Substring(RootDir.Length), identity, possibleRids)); } }); Log.LogMessage(MessageImportance.Low, "Searching for unused packages..."); foreach (PackageIdentity restoredWithoutUsagesFound in toCheck.Except(usages.Select(u => u.PackageIdentity))) { usages.Add(Usage.Create( null, restoredWithoutUsagesFound, possibleRids)); } // Packages that were included in the tarball as prebuilts, but weren't even restored. PackageIdentity[] neverRestoredTarballPrebuilts = tarballPrebuilt .Except(restored) .ToArray(); Log.LogMessage(MessageImportance.Low, $"Writing data to '{DataFile}'..."); var data = new UsageData { CreatedByRid = TargetRid, Usages = usages.ToArray(), NeverRestoredTarballPrebuilts = neverRestoredTarballPrebuilts, ProjectDirectories = ProjectDirectories ?.Select(dir => dir.Substring(RootDir.Length)) .ToArray() }; Directory.CreateDirectory(Path.GetDirectoryName(DataFile)); File.WriteAllText(DataFile, data.ToXml().ToString()); Log.LogMessage( MessageImportance.High, $"Writing package usage data... done. Took {DateTime.Now - startTime}"); return(!Log.HasLoggedErrors); }