using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RepoUtil { /// /// This utility is used to verify the repo is in a consistent state with respect to NuGet references. /// internal sealed class VerifyCommand : ICommand { private readonly string _sourcesPath; private readonly RepoConfig _repoConfig; internal VerifyCommand(RepoConfig repoConfig, string sourcesPath) { _repoConfig = repoConfig; _sourcesPath = sourcesPath; } public bool Run(TextWriter writer, string[] args) { RepoData repoData; return VerifyProjectJsonContents(writer, out repoData) && VerifyRepoConfig(writer) && VerifyGeneratedFiles(writer, repoData); } /// /// Verify the packages listed in project.json are well formed. Packages should all either have the same version or /// be explicitly fixed in the config file. /// private bool VerifyProjectJsonContents(TextWriter writer, out RepoData repoData) { writer.WriteLine($"Verifying project.json contents"); List conflicts; repoData = RepoData.Create(_repoConfig, _sourcesPath, out conflicts); if (conflicts?.Count > 0) { foreach (var conflict in conflicts) { writer.WriteLine($"Error! Package {conflict.PackageName} has different versions:"); writer.WriteLine($"\t{conflict.Original.FileName} at {conflict.Original.NuGetPackage.Version}"); writer.WriteLine($"\t{conflict.Conflict.FileName} at {conflict.Conflict.NuGetPackage.Version}"); writer.WriteLine($"The versions must be the same or one must be explicitly listed as fixed in RepoData.json"); } return false; } return true; } /// /// Verify that all of the data contained in the repo configuration is valid. In particular that it hasn't gotten /// stale and referring to invalid packages. /// /// private bool VerifyRepoConfig(TextWriter writer) { writer.WriteLine($"Verifying RepoData.json"); var packages = ProjectJsonUtil .GetProjectJsonFiles(_sourcesPath) .SelectMany(x => ProjectJsonUtil.GetDependencies(x)); var set = new HashSet(packages); var allGood = true; foreach (var package in _repoConfig.FixedPackages) { if (!set.Contains(package)) { writer.WriteLine($"Error: Fixed package {package.Name} - {package.Version} is not used anywhere"); allGood = false; } } return allGood; } private bool VerifyGeneratedFiles(TextWriter writer, RepoData repoData) { var allGood = true; writer.WriteLine($"Verifying generated files"); if (_repoConfig.MSBuildGenerateData.HasValue) { var data = _repoConfig.MSBuildGenerateData.Value; var packages = GenerateUtil.GetFilteredPackages(data, repoData); // Need to verify the contents of the generated file are correct. var fileName = new FileName(_sourcesPath, data.RelativeFileName); var actualContent = File.ReadAllText(fileName.FullPath, GenerateUtil.Encoding); var expectedContent = GenerateUtil.GenerateMSBuildContent(packages); if (actualContent != expectedContent) { writer.WriteLine($"{fileName.RelativePath} does not have the expected contents"); allGood = false; } if (!allGood) { writer.WriteLine($@"Generated contents out of date. Run ""RepoUtil.change"" to correct"); return false; } // Verify none of the regex entries are stale. var staleRegexList = GenerateUtil.GetStaleRegex(data, repoData); foreach (var regex in staleRegexList) { writer.WriteLine($"Regex {regex} matches no packages"); allGood = false; } } return allGood; } } }