private async Task VerifyExpectedLeafUrlAsync(CatalogEntry entry, CatalogLeafEntity leafEntity) { var entryUrl = entry.Uri.OriginalString; var catalogBaseUrl = await GetCatalogBaseUrlAsync(); if (!entryUrl.StartsWith(catalogBaseUrl)) { throw new InvalidOperationException("The catalog leaf URL should start with the catalog base URL."); } var actualPath = entryUrl.Substring(catalogBaseUrl.Length); var expectedPath = string.Join("/", new[] { "data", entry.CommitTimeStamp.ToString("yyyy.MM.dd.HH.mm.ss"), $"{Uri.EscapeDataString(entry.Id.ToLowerInvariant())}.{entry.Version.ToNormalizedString().ToLowerInvariant()}.json", }); // This should always be true, but we have an oddball: // https://api.nuget.org/v3/catalog0/page848.json // https://api.nuget.org/v3/catalog0/data/2015.04.03.23.35.56/xunit.core.2.0.0.json // Timestamp is 2015-04-03T23:14:16.0340591Z if (actualPath != expectedPath) { leafEntity.RelativePath = actualPath; } else { leafEntity.RelativePath = null; } }
private async Task <CatalogPageEntity> InitializeAsync( string pageUrl, IReadOnlyList <CatalogEntry> leaves, IReadOnlyDictionary <string, long> identityToPackageKey) { await VerifyExpectedPageUrlAsync(pageUrl); var pageEntity = new CatalogPageEntity { Url = pageUrl, CatalogCommits = new List <CatalogCommitEntity>(), }; var commits = leaves .GroupBy(x => x.CommitTimeStamp.ToUniversalTime()); foreach (var commit in commits) { var commitLeaves = commit.ToList(); // This really only every be one, but there is an oddball: // https://api.nuget.org/v3/catalog0/page868.json, timestamp: 2015-04-17T23:24:26.0796162Z var commitId = string.Join(" ", commit .Select(x => Guid.Parse(x.CommitId)) .OrderBy(x => x) .Distinct() .ToList()); var commitEntity = new CatalogCommitEntity { CatalogPage = pageEntity, CommitId = commitId, CommitTimestamp = commit.Key.UtcTicks, CatalogLeaves = new List <CatalogLeafEntity>(), Count = commitLeaves.Count, }; pageEntity.CatalogCommits.Add(commitEntity); foreach (var leaf in commitLeaves) { var identity = $"{leaf.Id}/{leaf.Version.ToNormalizedString()}"; var packageKey = identityToPackageKey[identity]; if (leaf.Types.Count != 1) { throw new InvalidOperationException($"Found a catalog leaf with {leaf.Types.Count} types instead of 1."); } CatalogLeafType type; if (leaf.IsAddOrUpdate) { type = CatalogLeafType.PackageDetails; } else if (leaf.IsDelete) { type = CatalogLeafType.PackageDelete; } else { throw new InvalidOperationException("Unexpected catalog leaf type."); } var leafEntity = new CatalogLeafEntity { CatalogCommit = commitEntity, PackageKey = packageKey, Type = type, }; await VerifyExpectedLeafUrlAsync(leaf, leafEntity); commitEntity.CatalogLeaves.Add(leafEntity); } } return(pageEntity); }