From bd440199ba16f62bdb0c157c69b6479f3e2aa9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= Date: Sun, 9 Feb 2020 19:23:03 -0800 Subject: [PATCH] Support embedded package icons (#469) NuGet supports embedding the package's icon into the package itself. This adds the necessary logic to support embedded icons in BaGet. This was a community contribution by @iodes --- src/BaGet.Azure/Search/AzureSearchService.cs | 6 +- src/BaGet.Azure/Search/IndexActionBuilder.cs | 1 + src/BaGet.Azure/Search/PackageDocument.cs | 1 + src/BaGet.Azure/Table/PackageEntity.cs | 1 + .../Table/TableOperationBuilder.cs | 1 + src/BaGet.Azure/Table/TablePackageService.cs | 1 + src/BaGet.Azure/Table/TableSearchService.cs | 7 +- src/BaGet.Core.Server/BaGetUrlGenerator.cs | 15 ++ .../Controllers/PackageContentController.cs | 16 ++ .../IEndpointRouteBuilderExtensions.cs | 5 + src/BaGet.Core.Server/Routes.cs | 1 + .../Content/DefaultPackageContentService.cs | 14 + .../Content/IPackageContentService.cs | 16 +- src/BaGet.Core/Entities/Package.cs | 1 + .../PackageArchiveReaderExtensions.cs | 11 + src/BaGet.Core/IUrlGenerator.cs | 7 + .../Indexing/PackageIndexingService.cs | 12 + .../Metadata/RegistrationBuilder.cs | 4 +- .../Search/DatabaseSearchService.cs | 5 +- .../Storage/IPackageStorageService.cs | 4 + .../Storage/PackageStorageService.cs | 42 +++ ...04047_AddHasEmbeddedIconColumn.Designer.cs | 241 +++++++++++++++++ ...20200210004047_AddHasEmbeddedIconColumn.cs | 43 +++ .../Migrations/MySqlContextModelSnapshot.cs | 78 ++++-- ...04256_AddHasEmbeddedIconColumn.Designer.cs | 248 ++++++++++++++++++ ...20200210004256_AddHasEmbeddedIconColumn.cs | 23 ++ .../PostgreSqlContextModelSnapshot.cs | 3 + ...04408_AddHasEmbeddedIconColumn.Designer.cs | 247 +++++++++++++++++ ...20200210004408_AddHasEmbeddedIconColumn.cs | 23 ++ .../SqlServerContextModelSnapshot.cs | 70 ++++- ...04344_AddHasEmbeddedIconColumn.Designer.cs | 240 +++++++++++++++++ ...20200210004344_AddHasEmbeddedIconColumn.cs | 23 ++ .../Migrations/SqliteContextModelSnapshot.cs | 3 + .../Catalog/NullCatalogClient.cs | 2 +- src/Directory.Build.props | 2 +- .../Services/PackageStorageServiceTests.cs | 37 ++- tests/Directory.Build.props | 2 +- 37 files changed, 1408 insertions(+), 48 deletions(-) create mode 100644 src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.Designer.cs create mode 100644 src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.cs create mode 100644 src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.Designer.cs create mode 100644 src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.cs create mode 100644 src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.Designer.cs create mode 100644 src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.cs create mode 100644 src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.Designer.cs create mode 100644 src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.cs diff --git a/src/BaGet.Azure/Search/AzureSearchService.cs b/src/BaGet.Azure/Search/AzureSearchService.cs index dfff4826..bbddb2ab 100644 --- a/src/BaGet.Azure/Search/AzureSearchService.cs +++ b/src/BaGet.Azure/Search/AzureSearchService.cs @@ -96,13 +96,17 @@ public async Task SearchAsync( }); } + var iconUrl = document.HasEmbeddedIcon + ? _url.GetPackageIconDownloadUrl(document.Id, NuGetVersion.Parse(document.Version)) + : document.IconUrl; + results.Add(new SearchResult { PackageId = document.Id, Version = document.Version, Description = document.Description, Authors = document.Authors, - IconUrl = document.IconUrl, + IconUrl = iconUrl, LicenseUrl = document.LicenseUrl, ProjectUrl = document.ProjectUrl, RegistrationIndexUrl = _url.GetRegistrationIndexUrl(document.Id), diff --git a/src/BaGet.Azure/Search/IndexActionBuilder.cs b/src/BaGet.Azure/Search/IndexActionBuilder.cs index a33e8880..4888e034 100644 --- a/src/BaGet.Azure/Search/IndexActionBuilder.cs +++ b/src/BaGet.Azure/Search/IndexActionBuilder.cs @@ -79,6 +79,7 @@ private IReadOnlyList> AddOrUpdatePackage( document.Version = latest.Version.ToFullString(); document.Description = latest.Description; document.Authors = latest.Authors; + document.HasEmbeddedIcon = latest.HasEmbeddedIcon; document.IconUrl = latest.IconUrlString; document.LicenseUrl = latest.LicenseUrlString; document.ProjectUrl = latest.ProjectUrlString; diff --git a/src/BaGet.Azure/Search/PackageDocument.cs b/src/BaGet.Azure/Search/PackageDocument.cs index a98f2a90..65c1c3b6 100644 --- a/src/BaGet.Azure/Search/PackageDocument.cs +++ b/src/BaGet.Azure/Search/PackageDocument.cs @@ -23,6 +23,7 @@ public class PackageDocument : KeyedDocument [IsSearchable] public string Description { get; set; } public string[] Authors { get; set; } + public bool HasEmbeddedIcon { get; set; } public string IconUrl { get; set; } public string LicenseUrl { get; set; } public string ProjectUrl { get; set; } diff --git a/src/BaGet.Azure/Table/PackageEntity.cs b/src/BaGet.Azure/Table/PackageEntity.cs index b3b133c9..46e9a053 100644 --- a/src/BaGet.Azure/Table/PackageEntity.cs +++ b/src/BaGet.Azure/Table/PackageEntity.cs @@ -22,6 +22,7 @@ public PackageEntity() public string Description { get; set; } public long Downloads { get; set; } public bool HasReadme { get; set; } + public bool HasEmbeddedIcon { get; set; } public bool IsPrerelease { get; set; } public string Language { get; set; } public bool Listed { get; set; } diff --git a/src/BaGet.Azure/Table/TableOperationBuilder.cs b/src/BaGet.Azure/Table/TableOperationBuilder.cs index dc4db2c2..db4742ad 100644 --- a/src/BaGet.Azure/Table/TableOperationBuilder.cs +++ b/src/BaGet.Azure/Table/TableOperationBuilder.cs @@ -29,6 +29,7 @@ public TableOperation AddPackage(Package package) Description = package.Description, Downloads = package.Downloads, HasReadme = package.HasReadme, + HasEmbeddedIcon = package.HasEmbeddedIcon, IsPrerelease = package.IsPrerelease, Language = package.Language, Listed = package.Listed, diff --git a/src/BaGet.Azure/Table/TablePackageService.cs b/src/BaGet.Azure/Table/TablePackageService.cs index 195e1499..9af6bab1 100644 --- a/src/BaGet.Azure/Table/TablePackageService.cs +++ b/src/BaGet.Azure/Table/TablePackageService.cs @@ -230,6 +230,7 @@ private Package AsPackage(PackageEntity entity) Description = entity.Description, Downloads = entity.Downloads, HasReadme = entity.HasReadme, + HasEmbeddedIcon = entity.HasEmbeddedIcon, IsPrerelease = entity.IsPrerelease, Language = entity.Language, Listed = entity.Listed, diff --git a/src/BaGet.Azure/Table/TableSearchService.cs b/src/BaGet.Azure/Table/TableSearchService.cs index 5d1ca0c0..d1f99cf4 100644 --- a/src/BaGet.Azure/Table/TableSearchService.cs +++ b/src/BaGet.Azure/Table/TableSearchService.cs @@ -234,16 +234,21 @@ private SearchResult ToSearchResult(IReadOnlyList packages) if (latestVersion == null || version > latestVersion) { latest = package; + latestVersion = version; } } + var iconUrl = latest.HasEmbeddedIcon + ? _url.GetPackageIconDownloadUrl(latest.Id, latestVersion) + : latest.IconUrl; + return new SearchResult { PackageId = latest.Id, Version = latest.NormalizedVersion, Description = latest.Description, Authors = JsonConvert.DeserializeObject(latest.Authors), - IconUrl = latest.IconUrl, + IconUrl = iconUrl, LicenseUrl = latest.LicenseUrl, ProjectUrl = latest.ProjectUrl, RegistrationIndexUrl = _url.GetRegistrationIndexUrl(latest.Id), diff --git a/src/BaGet.Core.Server/BaGetUrlGenerator.cs b/src/BaGet.Core.Server/BaGetUrlGenerator.cs index 5488358b..bfcc399e 100644 --- a/src/BaGet.Core.Server/BaGetUrlGenerator.cs +++ b/src/BaGet.Core.Server/BaGetUrlGenerator.cs @@ -126,6 +126,21 @@ public string GetPackageManifestDownloadUrl(string id, NuGetVersion version) }); } + public string GetPackageIconDownloadUrl(string id, NuGetVersion version) + { + id = id.ToLowerInvariant(); + var versionString = version.ToNormalizedString().ToLowerInvariant(); + + return _linkGenerator.GetUriByRouteValues( + _httpContextAccessor.HttpContext, + Routes.PackageDownloadIconRouteName, + values: new + { + Id = id, + Version = versionString + }); + } + private string AbsoluteUrl(string relativePath) { var request = _httpContextAccessor.HttpContext.Request; diff --git a/src/BaGet.Core.Server/Controllers/PackageContentController.cs b/src/BaGet.Core.Server/Controllers/PackageContentController.cs index adf7a38a..5ce4f5c3 100644 --- a/src/BaGet.Core.Server/Controllers/PackageContentController.cs +++ b/src/BaGet.Core.Server/Controllers/PackageContentController.cs @@ -79,5 +79,21 @@ public async Task DownloadReadmeAsync(string id, string version, return File(readmeStream, "text/markdown"); } + + public async Task DownloadIconAsync(string id, string version, CancellationToken cancellationToken) + { + if (!NuGetVersion.TryParse(version, out var nugetVersion)) + { + return NotFound(); + } + + var iconStream = await _content.GetPackageIconStreamOrNullAsync(id, nugetVersion, cancellationToken); + if (iconStream == null) + { + return NotFound(); + } + + return File(iconStream, "image/xyz"); + } } } diff --git a/src/BaGet.Core.Server/Extensions/IEndpointRouteBuilderExtensions.cs b/src/BaGet.Core.Server/Extensions/IEndpointRouteBuilderExtensions.cs index fb5c888f..e8c7dcd7 100644 --- a/src/BaGet.Core.Server/Extensions/IEndpointRouteBuilderExtensions.cs +++ b/src/BaGet.Core.Server/Extensions/IEndpointRouteBuilderExtensions.cs @@ -107,6 +107,11 @@ public static void MapPackageContentRoutes(this IEndpointRouteBuilder endpoints) name: Routes.PackageDownloadReadmeRouteName, pattern: "v3/package/{id}/{version}/readme", defaults: new { controller = "PackageContent", action = "DownloadReadme" }); + + endpoints.MapControllerRoute( + name: Routes.PackageDownloadIconRouteName, + pattern: "v3/package/{id}/{version}/icon", + defaults: new { controller = "PackageContent", action = "DownloadIcon" }); } } } diff --git a/src/BaGet.Core.Server/Routes.cs b/src/BaGet.Core.Server/Routes.cs index 899a4423..43062898 100644 --- a/src/BaGet.Core.Server/Routes.cs +++ b/src/BaGet.Core.Server/Routes.cs @@ -16,6 +16,7 @@ public class Routes public const string PackageDownloadRouteName = "package-download"; public const string PackageDownloadManifestRouteName = "package-download-manifest"; public const string PackageDownloadReadmeRouteName = "package-download-readme"; + public const string PackageDownloadIconRouteName = "package-download-icon"; public const string SymbolDownloadRouteName = "symbol-download"; public const string PrefixedSymbolDownloadRouteName = "prefixed-symbol-download"; } diff --git a/src/BaGet.Core/Content/DefaultPackageContentService.cs b/src/BaGet.Core/Content/DefaultPackageContentService.cs index b829275c..011714b7 100644 --- a/src/BaGet.Core/Content/DefaultPackageContentService.cs +++ b/src/BaGet.Core/Content/DefaultPackageContentService.cs @@ -100,5 +100,19 @@ public async Task GetPackageReadmeStreamOrNullAsync(string id, NuGetVers return await _storage.GetReadmeStreamAsync(id, version, cancellationToken); } + + public async Task GetPackageIconStreamOrNullAsync(string id, NuGetVersion version, CancellationToken cancellationToken = default) + { + // Allow read-through caching if it is configured. + await _mirror.MirrorAsync(id, version, cancellationToken); + + var package = await _packages.FindOrNullAsync(id, version, includeUnlisted: true, cancellationToken); + if (!package.HasEmbeddedIcon) + { + return null; + } + + return await _storage.GetIconStreamAsync(id, version, cancellationToken); + } } } diff --git a/src/BaGet.Core/Content/IPackageContentService.cs b/src/BaGet.Core/Content/IPackageContentService.cs index 3edce290..331c62e5 100644 --- a/src/BaGet.Core/Content/IPackageContentService.cs +++ b/src/BaGet.Core/Content/IPackageContentService.cs @@ -8,7 +8,7 @@ namespace BaGet.Core.Content { /// /// The Package Content resource, used to download NuGet packages and to fetch other metadata. - /// + /// /// See: https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource /// public interface IPackageContentService @@ -67,5 +67,19 @@ Task GetPackageReadmeStreamOrNullAsync( string id, NuGetVersion version, CancellationToken cancellationToken); + + /// + /// Download a package's icon, or null if the package or icon does not exist. + /// + /// The package id. + /// The package's version. + /// A token to cancel the task. + /// + /// The package's icon stream, or null if the package or icon does not exist. The stream may not be seekable. + /// + Task GetPackageIconStreamOrNullAsync( + string id, + NuGetVersion version, + CancellationToken cancellationToken); } } diff --git a/src/BaGet.Core/Entities/Package.cs b/src/BaGet.Core/Entities/Package.cs index d02f56f2..f9d64cce 100644 --- a/src/BaGet.Core/Entities/Package.cs +++ b/src/BaGet.Core/Entities/Package.cs @@ -34,6 +34,7 @@ public NuGetVersion Version public string Description { get; set; } public long Downloads { get; set; } public bool HasReadme { get; set; } + public bool HasEmbeddedIcon { get; set; } public bool IsPrerelease { get; set; } public string ReleaseNotes { get; set; } public string Language { get; set; } diff --git a/src/BaGet.Core/Extensions/PackageArchiveReaderExtensions.cs b/src/BaGet.Core/Extensions/PackageArchiveReaderExtensions.cs index 0b7180a2..7402bb4e 100644 --- a/src/BaGet.Core/Extensions/PackageArchiveReaderExtensions.cs +++ b/src/BaGet.Core/Extensions/PackageArchiveReaderExtensions.cs @@ -25,6 +25,9 @@ public static class PackageArchiveReaderExtensions public static bool HasReadme(this PackageArchiveReader package) => package.GetFiles().Any(ReadmeFileNames.Contains); + public static bool HasEmbeddedIcon(this PackageArchiveReader package) + => !string.IsNullOrEmpty(package.NuspecReader.GetIcon()); + public async static Task GetReadmeAsync( this PackageArchiveReader package, CancellationToken cancellationToken) @@ -44,6 +47,13 @@ public async static Task GetReadmeAsync( throw new InvalidOperationException("Package does not have a readme!"); } + public async static Task GetIconAsync( + this PackageArchiveReader package, + CancellationToken cancellationToken) + { + return await package.GetStreamAsync(package.NuspecReader.GetIcon(), cancellationToken); + } + public static Package GetPackageMetadata(this PackageArchiveReader packageReader) { var nuspec = packageReader.NuspecReader; @@ -57,6 +67,7 @@ public static Package GetPackageMetadata(this PackageArchiveReader packageReader Authors = ParseAuthors(nuspec.GetAuthors()), Description = nuspec.GetDescription(), HasReadme = packageReader.HasReadme(), + HasEmbeddedIcon = packageReader.HasEmbeddedIcon(), IsPrerelease = nuspec.GetVersion().IsPrerelease, Language = nuspec.GetLanguage() ?? string.Empty, ReleaseNotes = nuspec.GetReleaseNotes() ?? string.Empty, diff --git a/src/BaGet.Core/IUrlGenerator.cs b/src/BaGet.Core/IUrlGenerator.cs index 99a3e3e4..13ad12ec 100644 --- a/src/BaGet.Core/IUrlGenerator.cs +++ b/src/BaGet.Core/IUrlGenerator.cs @@ -88,5 +88,12 @@ public interface IUrlGenerator /// The package's ID /// The package's version string GetPackageManifestDownloadUrl(string id, NuGetVersion version); + + /// + /// Get the URL to download a package icon. + /// + /// The package's ID + /// The package's version + string GetPackageIconDownloadUrl(string id, NuGetVersion version); } } diff --git a/src/BaGet.Core/Indexing/PackageIndexingService.cs b/src/BaGet.Core/Indexing/PackageIndexingService.cs index d60bb408..17e8e97c 100644 --- a/src/BaGet.Core/Indexing/PackageIndexingService.cs +++ b/src/BaGet.Core/Indexing/PackageIndexingService.cs @@ -36,6 +36,7 @@ public async Task IndexAsync(Stream packageStream, Cancel Package package; Stream nuspecStream; Stream readmeStream; + Stream iconStream; try { @@ -54,6 +55,16 @@ public async Task IndexAsync(Stream packageStream, Cancel { readmeStream = null; } + + if (package.HasEmbeddedIcon) + { + iconStream = await packageReader.GetIconAsync(cancellationToken); + iconStream = await iconStream.AsTemporaryFileStreamAsync(); + } + else + { + iconStream = null; + } } } catch (Exception e) @@ -91,6 +102,7 @@ await _storage.SavePackageContentAsync( packageStream, nuspecStream, readmeStream, + iconStream, cancellationToken); } catch (Exception e) diff --git a/src/BaGet.Core/Metadata/RegistrationBuilder.cs b/src/BaGet.Core/Metadata/RegistrationBuilder.cs index b2a98d2c..04a8ffc0 100644 --- a/src/BaGet.Core/Metadata/RegistrationBuilder.cs +++ b/src/BaGet.Core/Metadata/RegistrationBuilder.cs @@ -71,7 +71,9 @@ private RegistrationIndexPageItem ToRegistrationIndexPageItem(Package package) = Description = package.Description, Downloads = package.Downloads, HasReadme = package.HasReadme, - IconUrl = package.IconUrlString, + IconUrl = package.HasEmbeddedIcon + ? _url.GetPackageIconDownloadUrl(package.Id, package.Version) + : package.IconUrlString, Language = package.Language, LicenseUrl = package.LicenseUrlString, Listed = package.Listed, diff --git a/src/BaGet.Core/Search/DatabaseSearchService.cs b/src/BaGet.Core/Search/DatabaseSearchService.cs index 83c7529a..ebebae69 100644 --- a/src/BaGet.Core/Search/DatabaseSearchService.cs +++ b/src/BaGet.Core/Search/DatabaseSearchService.cs @@ -70,6 +70,9 @@ public async Task SearchAsync( { var versions = package.OrderByDescending(p => p.Version).ToList(); var latest = versions.First(); + var iconUrl = latest.HasEmbeddedIcon + ? _url.GetPackageIconDownloadUrl(latest.Id, latest.Version) + : latest.IconUrlString; result.Add(new SearchResult { @@ -77,7 +80,7 @@ public async Task SearchAsync( Version = latest.Version.ToFullString(), Description = latest.Description, Authors = latest.Authors, - IconUrl = latest.IconUrlString, + IconUrl = iconUrl, LicenseUrl = latest.LicenseUrlString, ProjectUrl = latest.ProjectUrlString, RegistrationIndexUrl = _url.GetRegistrationIndexUrl(latest.Id), diff --git a/src/BaGet.Core/Storage/IPackageStorageService.cs b/src/BaGet.Core/Storage/IPackageStorageService.cs index aefae56c..e7608a95 100644 --- a/src/BaGet.Core/Storage/IPackageStorageService.cs +++ b/src/BaGet.Core/Storage/IPackageStorageService.cs @@ -19,6 +19,7 @@ public interface IPackageStorageService /// The package's nupkg stream. /// The package's nuspec stream. /// The package's readme stream, or null if none. + /// The package's icon stream, or null if none. /// /// Task SavePackageContentAsync( @@ -26,6 +27,7 @@ Task SavePackageContentAsync( Stream packageStream, Stream nuspecStream, Stream readmeStream, + Stream iconStream, CancellationToken cancellationToken); /// @@ -55,6 +57,8 @@ Task SavePackageContentAsync( /// The package's readme stream. Task GetReadmeStreamAsync(string id, NuGetVersion version, CancellationToken cancellationToken); + Task GetIconStreamAsync(string id, NuGetVersion version, CancellationToken cancellationToken); + /// /// Remove a package's content from storage. This operation SHOULD succeed /// even if the package does not exist. diff --git a/src/BaGet.Core/Storage/PackageStorageService.cs b/src/BaGet.Core/Storage/PackageStorageService.cs index 8b887676..55731b00 100644 --- a/src/BaGet.Core/Storage/PackageStorageService.cs +++ b/src/BaGet.Core/Storage/PackageStorageService.cs @@ -15,6 +15,7 @@ public class PackageStorageService : IPackageStorageService private const string PackageContentType = "binary/octet-stream"; private const string NuspecContentType = "text/plain"; private const string ReadmeContentType = "text/markdown"; + private const string IconContentType = "image/xyz"; private readonly IStorageService _storage; private readonly ILogger _logger; @@ -32,6 +33,7 @@ public async Task SavePackageContentAsync( Stream packageStream, Stream nuspecStream, Stream readmeStream, + Stream iconStream, CancellationToken cancellationToken = default) { package = package ?? throw new ArgumentNullException(nameof(package)); @@ -44,6 +46,7 @@ public async Task SavePackageContentAsync( var packagePath = PackagePath(lowercasedId, lowercasedNormalizedVersion); var nuspecPath = NuspecPath(lowercasedId, lowercasedNormalizedVersion); var readmePath = ReadmePath(lowercasedId, lowercasedNormalizedVersion); + var iconPath = IconPath(lowercasedId, lowercasedNormalizedVersion); _logger.LogInformation( "Storing package {PackageId} {PackageVersion} at {Path}...", @@ -108,6 +111,29 @@ public async Task SavePackageContentAsync( } } + // Store the package's icon, if one exists. + if (iconStream != null) + { + _logger.LogInformation( + "Storing package {PackageId} {PackageVersion} icon at {Path}...", + lowercasedId, + lowercasedNormalizedVersion, + iconPath); + + result = await _storage.PutAsync(iconPath, iconStream, IconContentType, cancellationToken); + if (result == StoragePutResult.Conflict) + { + // TODO: This should be returned gracefully with an enum. + _logger.LogInformation( + "Could not store package {PackageId} {PackageVersion} icon at {Path} due to conflict", + lowercasedId, + lowercasedNormalizedVersion, + iconPath); + + throw new InvalidOperationException($"Failed to store package {lowercasedId} {lowercasedNormalizedVersion} icon"); + } + } + _logger.LogInformation( "Finished storing package {PackageId} {PackageVersion}", lowercasedId, @@ -129,6 +155,11 @@ public async Task GetReadmeStreamAsync(string id, NuGetVersion version, return await GetStreamAsync(id, version, ReadmePath, cancellationToken); } + public async Task GetIconStreamAsync(string id, NuGetVersion version, CancellationToken cancellationToken) + { + return await GetStreamAsync(id, version, IconPath, cancellationToken); + } + public async Task DeleteAsync(string id, NuGetVersion version, CancellationToken cancellationToken) { var lowercasedId = id.ToLowerInvariant(); @@ -137,10 +168,12 @@ public async Task DeleteAsync(string id, NuGetVersion version, CancellationToken var packagePath = PackagePath(lowercasedId, lowercasedNormalizedVersion); var nuspecPath = NuspecPath(lowercasedId, lowercasedNormalizedVersion); var readmePath = ReadmePath(lowercasedId, lowercasedNormalizedVersion); + var iconPath = IconPath(lowercasedId, lowercasedNormalizedVersion); await _storage.DeleteAsync(packagePath, cancellationToken); await _storage.DeleteAsync(nuspecPath, cancellationToken); await _storage.DeleteAsync(readmePath, cancellationToken); + await _storage.DeleteAsync(iconPath, cancellationToken); } private async Task GetStreamAsync( @@ -197,5 +230,14 @@ private string ReadmePath(string lowercasedId, string lowercasedNormalizedVersio lowercasedNormalizedVersion, "readme"); } + + private string IconPath(string lowercasedId, string lowercasedNormalizedVersion) + { + return Path.Combine( + PackagesPathPrefix, + lowercasedId, + lowercasedNormalizedVersion, + "icon"); + } } } diff --git a/src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.Designer.cs b/src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.Designer.cs new file mode 100644 index 00000000..4ad12181 --- /dev/null +++ b/src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.Designer.cs @@ -0,0 +1,241 @@ +// +using System; +using BaGet.Database.MySql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace BaGet.Database.MySql.Migrations +{ + [DbContext(typeof(MySqlContext))] + [Migration("20200210004047_AddHasEmbeddedIconColumn")] + partial class AddHasEmbeddedIconColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.1") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("BaGet.Core.Package", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Authors") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Description") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Downloads") + .HasColumnType("bigint"); + + b.Property("HasEmbeddedIcon") + .HasColumnType("tinyint(1)"); + + b.Property("HasReadme") + .HasColumnType("tinyint(1)"); + + b.Property("IconUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Id") + .IsRequired() + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("IsPrerelease") + .HasColumnType("tinyint(1)"); + + b.Property("Language") + .HasColumnType("varchar(20) CHARACTER SET utf8mb4") + .HasMaxLength(20); + + b.Property("LicenseUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Listed") + .HasColumnType("tinyint(1)"); + + b.Property("MinClientVersion") + .HasColumnType("varchar(44) CHARACTER SET utf8mb4") + .HasMaxLength(44); + + b.Property("NormalizedVersionString") + .IsRequired() + .HasColumnName("Version") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("OriginalVersionString") + .HasColumnName("OriginalVersion") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("ProjectUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Published") + .HasColumnType("datetime(6)"); + + b.Property("ReleaseNotes") + .HasColumnName("ReleaseNotes") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("RepositoryType") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("RepositoryUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("RequireLicenseAcceptance") + .HasColumnType("tinyint(1)"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("timestamp(6)"); + + b.Property("SemVerLevel") + .HasColumnType("int"); + + b.Property("Summary") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Tags") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.Property("Title") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("Id", "NormalizedVersionString") + .IsUnique(); + + b.ToTable("Packages"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Id") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("PackageKey") + .HasColumnType("int"); + + b.Property("TargetFramework") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("VersionRange") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageDependencies"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("PackageKey") + .HasColumnType("int"); + + b.Property("Version") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.HasKey("Key"); + + b.HasIndex("Name"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageTypes"); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Moniker") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PackageKey") + .HasColumnType("int"); + + b.HasKey("Key"); + + b.HasIndex("Moniker"); + + b.HasIndex("PackageKey"); + + b.ToTable("TargetFrameworks"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("Dependencies") + .HasForeignKey("PackageKey"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("PackageTypes") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("TargetFrameworks") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.cs b/src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.cs new file mode 100644 index 00000000..d9b12c93 --- /dev/null +++ b/src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.cs @@ -0,0 +1,43 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace BaGet.Database.MySql.Migrations +{ + public partial class AddHasEmbeddedIconColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "RowVersion", + table: "Packages", + rowVersion: true, + nullable: true, + oldClrType: typeof(DateTime), + oldNullable: true) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn); + + migrationBuilder.AddColumn( + name: "HasEmbeddedIcon", + table: "Packages", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "HasEmbeddedIcon", + table: "Packages"); + + migrationBuilder.AlterColumn( + name: "RowVersion", + table: "Packages", + nullable: true, + oldClrType: typeof(DateTime), + oldRowVersion: true, + oldNullable: true) + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn); + } + } +} diff --git a/src/BaGet.Database.MySql/Migrations/MySqlContextModelSnapshot.cs b/src/BaGet.Database.MySql/Migrations/MySqlContextModelSnapshot.cs index c3d15249..363c445c 100644 --- a/src/BaGet.Database.MySql/Migrations/MySqlContextModelSnapshot.cs +++ b/src/BaGet.Database.MySql/Migrations/MySqlContextModelSnapshot.cs @@ -14,83 +14,111 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("ProductVersion", "3.1.1") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("BaGet.Core.Package", b => { b.Property("Key") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Authors") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); b.Property("Description") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); - b.Property("Downloads"); + b.Property("Downloads") + .HasColumnType("bigint"); - b.Property("HasReadme"); + b.Property("HasEmbeddedIcon") + .HasColumnType("tinyint(1)"); + + b.Property("HasReadme") + .HasColumnType("tinyint(1)"); b.Property("IconUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); b.Property("Id") .IsRequired() + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); - b.Property("IsPrerelease"); + b.Property("IsPrerelease") + .HasColumnType("tinyint(1)"); b.Property("Language") + .HasColumnType("varchar(20) CHARACTER SET utf8mb4") .HasMaxLength(20); b.Property("LicenseUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); - b.Property("Listed"); + b.Property("Listed") + .HasColumnType("tinyint(1)"); b.Property("MinClientVersion") + .HasColumnType("varchar(44) CHARACTER SET utf8mb4") .HasMaxLength(44); b.Property("NormalizedVersionString") .IsRequired() .HasColumnName("Version") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("OriginalVersionString") .HasColumnName("OriginalVersion") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.Property("ProjectUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); - b.Property("Published"); + b.Property("Published") + .HasColumnType("datetime(6)"); b.Property("ReleaseNotes") .HasColumnName("ReleaseNotes") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); b.Property("RepositoryType") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") .HasMaxLength(100); b.Property("RepositoryUrl") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); - b.Property("RequireLicenseAcceptance"); + b.Property("RequireLicenseAcceptance") + .HasColumnType("tinyint(1)"); b.Property("RowVersion") .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate(); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("timestamp(6)"); - b.Property("SemVerLevel"); + b.Property("SemVerLevel") + .HasColumnType("int"); b.Property("Summary") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); b.Property("Tags") + .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(4000); b.Property("Title") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Key"); @@ -106,17 +134,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("BaGet.Core.PackageDependency", b => { b.Property("Key") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Id") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") .HasMaxLength(128); - b.Property("PackageKey"); + b.Property("PackageKey") + .HasColumnType("int"); b.Property("TargetFramework") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.Property("VersionRange") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); b.HasKey("Key"); @@ -131,14 +164,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("BaGet.Core.PackageType", b => { b.Property("Key") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Name") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") .HasMaxLength(512); - b.Property("PackageKey"); + b.Property("PackageKey") + .HasColumnType("int"); b.Property("Version") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") .HasMaxLength(64); b.HasKey("Key"); @@ -153,12 +190,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("BaGet.Core.TargetFramework", b => { b.Property("Key") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Moniker") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") .HasMaxLength(256); - b.Property("PackageKey"); + b.Property("PackageKey") + .HasColumnType("int"); b.HasKey("Key"); @@ -181,7 +221,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("BaGet.Core.Package", "Package") .WithMany("PackageTypes") .HasForeignKey("PackageKey") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("BaGet.Core.TargetFramework", b => @@ -189,7 +230,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("BaGet.Core.Package", "Package") .WithMany("TargetFrameworks") .HasForeignKey("PackageKey") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.Designer.cs b/src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.Designer.cs new file mode 100644 index 00000000..aa9cfde3 --- /dev/null +++ b/src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.Designer.cs @@ -0,0 +1,248 @@ +// +using System; +using BaGet.Database.PostgreSql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace BaGet.Database.PostgreSql.Migrations +{ + [DbContext(typeof(PostgreSqlContext))] + [Migration("20200210004256_AddHasEmbeddedIconColumn")] + partial class AddHasEmbeddedIconColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:PostgresExtension:citext", ",,") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("BaGet.Core.Package", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Authors") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Description") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Downloads") + .HasColumnType("bigint"); + + b.Property("HasEmbeddedIcon") + .HasColumnType("boolean"); + + b.Property("HasReadme") + .HasColumnType("boolean"); + + b.Property("IconUrl") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Id") + .IsRequired() + .HasColumnType("citext") + .HasMaxLength(128); + + b.Property("IsPrerelease") + .HasColumnType("boolean"); + + b.Property("Language") + .HasColumnType("character varying(20)") + .HasMaxLength(20); + + b.Property("LicenseUrl") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Listed") + .HasColumnType("boolean"); + + b.Property("MinClientVersion") + .HasColumnType("character varying(44)") + .HasMaxLength(44); + + b.Property("NormalizedVersionString") + .IsRequired() + .HasColumnName("Version") + .HasColumnType("citext") + .HasMaxLength(64); + + b.Property("OriginalVersionString") + .HasColumnName("OriginalVersion") + .HasColumnType("character varying(64)") + .HasMaxLength(64); + + b.Property("ProjectUrl") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Published") + .HasColumnType("timestamp without time zone"); + + b.Property("ReleaseNotes") + .HasColumnName("ReleaseNotes") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("RepositoryType") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("RepositoryUrl") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("RequireLicenseAcceptance") + .HasColumnType("boolean"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea"); + + b.Property("SemVerLevel") + .HasColumnType("integer"); + + b.Property("Summary") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Tags") + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.Property("Title") + .HasColumnType("character varying(256)") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("Id", "NormalizedVersionString") + .IsUnique(); + + b.ToTable("Packages"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Id") + .HasColumnType("citext") + .HasMaxLength(128); + + b.Property("PackageKey") + .HasColumnType("integer"); + + b.Property("TargetFramework") + .HasColumnType("character varying(256)") + .HasMaxLength(256); + + b.Property("VersionRange") + .HasColumnType("character varying(256)") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageDependencies"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Name") + .HasColumnType("citext") + .HasMaxLength(512); + + b.Property("PackageKey") + .HasColumnType("integer"); + + b.Property("Version") + .HasColumnType("character varying(64)") + .HasMaxLength(64); + + b.HasKey("Key"); + + b.HasIndex("Name"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageTypes"); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Moniker") + .HasColumnType("citext") + .HasMaxLength(256); + + b.Property("PackageKey") + .HasColumnType("integer"); + + b.HasKey("Key"); + + b.HasIndex("Moniker"); + + b.HasIndex("PackageKey"); + + b.ToTable("TargetFrameworks"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("Dependencies") + .HasForeignKey("PackageKey"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("PackageTypes") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("TargetFrameworks") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.cs b/src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.cs new file mode 100644 index 00000000..704cc1ce --- /dev/null +++ b/src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace BaGet.Database.PostgreSql.Migrations +{ + public partial class AddHasEmbeddedIconColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "HasEmbeddedIcon", + table: "Packages", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "HasEmbeddedIcon", + table: "Packages"); + } + } +} diff --git a/src/BaGet.Database.PostgreSql/Migrations/PostgreSqlContextModelSnapshot.cs b/src/BaGet.Database.PostgreSql/Migrations/PostgreSqlContextModelSnapshot.cs index b8b94802..36ae9b63 100644 --- a/src/BaGet.Database.PostgreSql/Migrations/PostgreSqlContextModelSnapshot.cs +++ b/src/BaGet.Database.PostgreSql/Migrations/PostgreSqlContextModelSnapshot.cs @@ -38,6 +38,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Downloads") .HasColumnType("bigint"); + b.Property("HasEmbeddedIcon") + .HasColumnType("boolean"); + b.Property("HasReadme") .HasColumnType("boolean"); diff --git a/src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.Designer.cs b/src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.Designer.cs new file mode 100644 index 00000000..2bdbefa7 --- /dev/null +++ b/src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.Designer.cs @@ -0,0 +1,247 @@ +// +using System; +using BaGet.Database.SqlServer; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace BaGet.Database.SqlServer.Migrations +{ + [DbContext(typeof(SqlServerContext))] + [Migration("20200210004408_AddHasEmbeddedIconColumn")] + partial class AddHasEmbeddedIconColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("BaGet.Core.Package", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Authors") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Description") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Downloads") + .HasColumnType("bigint"); + + b.Property("HasEmbeddedIcon") + .HasColumnType("bit"); + + b.Property("HasReadme") + .HasColumnType("bit"); + + b.Property("IconUrl") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Id") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("IsPrerelease") + .HasColumnType("bit"); + + b.Property("Language") + .HasColumnType("nvarchar(20)") + .HasMaxLength(20); + + b.Property("LicenseUrl") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Listed") + .HasColumnType("bit"); + + b.Property("MinClientVersion") + .HasColumnType("nvarchar(44)") + .HasMaxLength(44); + + b.Property("NormalizedVersionString") + .IsRequired() + .HasColumnName("Version") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("OriginalVersionString") + .HasColumnName("OriginalVersion") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ProjectUrl") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Published") + .HasColumnType("datetime2"); + + b.Property("ReleaseNotes") + .HasColumnName("ReleaseNotes") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("RepositoryType") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("RepositoryUrl") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("RequireLicenseAcceptance") + .HasColumnType("bit"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("rowversion"); + + b.Property("SemVerLevel") + .HasColumnType("int"); + + b.Property("Summary") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Tags") + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.Property("Title") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("Id", "NormalizedVersionString") + .IsUnique(); + + b.ToTable("Packages"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Id") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("PackageKey") + .HasColumnType("int"); + + b.Property("TargetFramework") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("VersionRange") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageDependencies"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("PackageKey") + .HasColumnType("int"); + + b.Property("Version") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.HasKey("Key"); + + b.HasIndex("Name"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageTypes"); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Moniker") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PackageKey") + .HasColumnType("int"); + + b.HasKey("Key"); + + b.HasIndex("Moniker"); + + b.HasIndex("PackageKey"); + + b.ToTable("TargetFrameworks"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("Dependencies") + .HasForeignKey("PackageKey"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("PackageTypes") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("TargetFrameworks") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.cs b/src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.cs new file mode 100644 index 00000000..1cff5d14 --- /dev/null +++ b/src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace BaGet.Database.SqlServer.Migrations +{ + public partial class AddHasEmbeddedIconColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "HasEmbeddedIcon", + table: "Packages", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "HasEmbeddedIcon", + table: "Packages"); + } + } +} diff --git a/src/BaGet.Database.SqlServer/Migrations/SqlServerContextModelSnapshot.cs b/src/BaGet.Database.SqlServer/Migrations/SqlServerContextModelSnapshot.cs index db5fe22c..229a3002 100644 --- a/src/BaGet.Database.SqlServer/Migrations/SqlServerContextModelSnapshot.cs +++ b/src/BaGet.Database.SqlServer/Migrations/SqlServerContextModelSnapshot.cs @@ -15,7 +15,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("ProductVersion", "3.1.1") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -23,77 +23,105 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Key") .ValueGeneratedOnAdd() + .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("Authors") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); b.Property("Description") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); - b.Property("Downloads"); + b.Property("Downloads") + .HasColumnType("bigint"); - b.Property("HasReadme"); + b.Property("HasEmbeddedIcon") + .HasColumnType("bit"); + + b.Property("HasReadme") + .HasColumnType("bit"); b.Property("IconUrl") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); b.Property("Id") .IsRequired() + .HasColumnType("nvarchar(128)") .HasMaxLength(128); - b.Property("IsPrerelease"); + b.Property("IsPrerelease") + .HasColumnType("bit"); b.Property("Language") + .HasColumnType("nvarchar(20)") .HasMaxLength(20); b.Property("LicenseUrl") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); - b.Property("Listed"); + b.Property("Listed") + .HasColumnType("bit"); b.Property("MinClientVersion") + .HasColumnType("nvarchar(44)") .HasMaxLength(44); b.Property("NormalizedVersionString") .IsRequired() .HasColumnName("Version") + .HasColumnType("nvarchar(64)") .HasMaxLength(64); b.Property("OriginalVersionString") .HasColumnName("OriginalVersion") + .HasColumnType("nvarchar(64)") .HasMaxLength(64); b.Property("ProjectUrl") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); - b.Property("Published"); + b.Property("Published") + .HasColumnType("datetime2"); b.Property("ReleaseNotes") .HasColumnName("ReleaseNotes") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); b.Property("RepositoryType") + .HasColumnType("nvarchar(100)") .HasMaxLength(100); b.Property("RepositoryUrl") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); - b.Property("RequireLicenseAcceptance"); + b.Property("RequireLicenseAcceptance") + .HasColumnType("bit"); b.Property("RowVersion") .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate(); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("rowversion"); - b.Property("SemVerLevel"); + b.Property("SemVerLevel") + .HasColumnType("int"); b.Property("Summary") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); b.Property("Tags") + .HasColumnType("nvarchar(4000)") .HasMaxLength(4000); b.Property("Title") + .HasColumnType("nvarchar(256)") .HasMaxLength(256); b.HasKey("Key"); @@ -110,17 +138,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Key") .ValueGeneratedOnAdd() + .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("Id") + .HasColumnType("nvarchar(128)") .HasMaxLength(128); - b.Property("PackageKey"); + b.Property("PackageKey") + .HasColumnType("int"); b.Property("TargetFramework") + .HasColumnType("nvarchar(256)") .HasMaxLength(256); b.Property("VersionRange") + .HasColumnType("nvarchar(256)") .HasMaxLength(256); b.HasKey("Key"); @@ -136,14 +169,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Key") .ValueGeneratedOnAdd() + .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("Name") + .HasColumnType("nvarchar(512)") .HasMaxLength(512); - b.Property("PackageKey"); + b.Property("PackageKey") + .HasColumnType("int"); b.Property("Version") + .HasColumnType("nvarchar(64)") .HasMaxLength(64); b.HasKey("Key"); @@ -159,12 +196,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Key") .ValueGeneratedOnAdd() + .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("Moniker") + .HasColumnType("nvarchar(256)") .HasMaxLength(256); - b.Property("PackageKey"); + b.Property("PackageKey") + .HasColumnType("int"); b.HasKey("Key"); @@ -187,7 +227,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("BaGet.Core.Package", "Package") .WithMany("PackageTypes") .HasForeignKey("PackageKey") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("BaGet.Core.TargetFramework", b => @@ -195,7 +236,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("BaGet.Core.Package", "Package") .WithMany("TargetFrameworks") .HasForeignKey("PackageKey") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.Designer.cs b/src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.Designer.cs new file mode 100644 index 00000000..4dde2f2e --- /dev/null +++ b/src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.Designer.cs @@ -0,0 +1,240 @@ +// +using System; +using BaGet.Database.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace BaGet.Database.Sqlite.Migrations +{ + [DbContext(typeof(SqliteContext))] + [Migration("20200210004344_AddHasEmbeddedIconColumn")] + partial class AddHasEmbeddedIconColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.1"); + + modelBuilder.Entity("BaGet.Core.Package", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Authors") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Description") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Downloads") + .HasColumnType("INTEGER"); + + b.Property("HasEmbeddedIcon") + .HasColumnType("INTEGER"); + + b.Property("HasReadme") + .HasColumnType("INTEGER"); + + b.Property("IconUrl") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Id") + .IsRequired() + .HasColumnType("TEXT COLLATE NOCASE") + .HasMaxLength(128); + + b.Property("IsPrerelease") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT") + .HasMaxLength(20); + + b.Property("LicenseUrl") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Listed") + .HasColumnType("INTEGER"); + + b.Property("MinClientVersion") + .HasColumnType("TEXT") + .HasMaxLength(44); + + b.Property("NormalizedVersionString") + .IsRequired() + .HasColumnName("Version") + .HasColumnType("TEXT COLLATE NOCASE") + .HasMaxLength(64); + + b.Property("OriginalVersionString") + .HasColumnName("OriginalVersion") + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("ProjectUrl") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Published") + .HasColumnType("TEXT"); + + b.Property("ReleaseNotes") + .HasColumnName("ReleaseNotes") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("RepositoryType") + .HasColumnType("TEXT") + .HasMaxLength(100); + + b.Property("RepositoryUrl") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("RequireLicenseAcceptance") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("BLOB"); + + b.Property("SemVerLevel") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Tags") + .HasColumnType("TEXT") + .HasMaxLength(4000); + + b.Property("Title") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("Id", "NormalizedVersionString") + .IsUnique(); + + b.ToTable("Packages"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Id") + .HasColumnType("TEXT COLLATE NOCASE") + .HasMaxLength(128); + + b.Property("PackageKey") + .HasColumnType("INTEGER"); + + b.Property("TargetFramework") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("VersionRange") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.HasKey("Key"); + + b.HasIndex("Id"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageDependencies"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT COLLATE NOCASE") + .HasMaxLength(512); + + b.Property("PackageKey") + .HasColumnType("INTEGER"); + + b.Property("Version") + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.HasKey("Key"); + + b.HasIndex("Name"); + + b.HasIndex("PackageKey"); + + b.ToTable("PackageTypes"); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.Property("Key") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Moniker") + .HasColumnType("TEXT COLLATE NOCASE") + .HasMaxLength(256); + + b.Property("PackageKey") + .HasColumnType("INTEGER"); + + b.HasKey("Key"); + + b.HasIndex("Moniker"); + + b.HasIndex("PackageKey"); + + b.ToTable("TargetFrameworks"); + }); + + modelBuilder.Entity("BaGet.Core.PackageDependency", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("Dependencies") + .HasForeignKey("PackageKey"); + }); + + modelBuilder.Entity("BaGet.Core.PackageType", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("PackageTypes") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BaGet.Core.TargetFramework", b => + { + b.HasOne("BaGet.Core.Package", "Package") + .WithMany("TargetFrameworks") + .HasForeignKey("PackageKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.cs b/src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.cs new file mode 100644 index 00000000..df4897b4 --- /dev/null +++ b/src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace BaGet.Database.Sqlite.Migrations +{ + public partial class AddHasEmbeddedIconColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "HasEmbeddedIcon", + table: "Packages", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "HasEmbeddedIcon", + table: "Packages"); + } + } +} diff --git a/src/BaGet.Database.Sqlite/Migrations/SqliteContextModelSnapshot.cs b/src/BaGet.Database.Sqlite/Migrations/SqliteContextModelSnapshot.cs index 38c08607..1d99d5cd 100644 --- a/src/BaGet.Database.Sqlite/Migrations/SqliteContextModelSnapshot.cs +++ b/src/BaGet.Database.Sqlite/Migrations/SqliteContextModelSnapshot.cs @@ -33,6 +33,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Downloads") .HasColumnType("INTEGER"); + b.Property("HasEmbeddedIcon") + .HasColumnType("INTEGER"); + b.Property("HasReadme") .HasColumnType("INTEGER"); diff --git a/src/BaGet.Protocol/Catalog/NullCatalogClient.cs b/src/BaGet.Protocol/Catalog/NullCatalogClient.cs index dac19bf7..b77dc15b 100644 --- a/src/BaGet.Protocol/Catalog/NullCatalogClient.cs +++ b/src/BaGet.Protocol/Catalog/NullCatalogClient.cs @@ -18,7 +18,7 @@ public Task GetIndexAsync(CancellationToken cancellationToken = de }); } - public async Task GetPageAsync(string pageUrl, CancellationToken cancellationToken = default) + public Task GetPageAsync(string pageUrl, CancellationToken cancellationToken = default) { throw new NotSupportedException($"{nameof(NullCatalogClient)} does not support loading catalog pages."); } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ec5bb265..11d01067 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -30,7 +30,7 @@ 3.1.1 3.1.1 3.1.1 - 5.0.0-rtm.5856 + 5.4.0 diff --git a/tests/BaGet.Core.Tests/Services/PackageStorageServiceTests.cs b/tests/BaGet.Core.Tests/Services/PackageStorageServiceTests.cs index 5d36f464..da246691 100644 --- a/tests/BaGet.Core.Tests/Services/PackageStorageServiceTests.cs +++ b/tests/BaGet.Core.Tests/Services/PackageStorageServiceTests.cs @@ -23,7 +23,8 @@ await Assert.ThrowsAsync( null, packageStream: Stream.Null, nuspecStream: Stream.Null, - readmeStream: Stream.Null)); + readmeStream: Stream.Null, + iconStream: Stream.Null)); } [Fact] @@ -34,7 +35,8 @@ await Assert.ThrowsAsync( _package, packageStream: null, nuspecStream: Stream.Null, - readmeStream: Stream.Null)); + readmeStream: Stream.Null, + iconStream: Stream.Null)); } [Fact] @@ -45,7 +47,8 @@ await Assert.ThrowsAsync( _package, packageStream: Stream.Null, nuspecStream: null, - readmeStream: Stream.Null)); + readmeStream: Stream.Null, + iconStream: Stream.Null)); } [Fact] @@ -57,13 +60,15 @@ public async Task SavesContent() using (var packageStream = StringStream("My package")) using (var nuspecStream = StringStream("My nuspec")) using (var readmeStream = StringStream("My readme")) + using (var iconStream = StringStream("My icon")) { // Act await _target.SavePackageContentAsync( _package, packageStream: packageStream, nuspecStream: nuspecStream, - readmeStream: readmeStream); + readmeStream: readmeStream, + iconStream: iconStream); // Assert Assert.True(_puts.ContainsKey(PackagePath)); @@ -77,6 +82,10 @@ await _target.SavePackageContentAsync( Assert.True(_puts.ContainsKey(ReadmePath)); Assert.Equal("My readme", await ToStringAsync(_puts[ReadmePath].Content)); Assert.Equal("text/markdown", _puts[ReadmePath].ContentType); + + Assert.True(_puts.ContainsKey(IconPath)); + Assert.Equal("My icon", await ToStringAsync(_puts[IconPath].Content)); + Assert.Equal("image/xyz", _puts[IconPath].ContentType); } } @@ -94,7 +103,8 @@ await _target.SavePackageContentAsync( _package, packageStream: packageStream, nuspecStream: nuspecStream, - readmeStream: null); + readmeStream: null, + iconStream: null); } // Assert @@ -111,13 +121,15 @@ public async Task NormalizesVersionWhenContentIsSaved() using (var packageStream = StringStream("My package")) using (var nuspecStream = StringStream("My nuspec")) using (var readmeStream = StringStream("My readme")) + using (var iconStream = StringStream("My icon")) { // Act await _target.SavePackageContentAsync( _package, packageStream: packageStream, nuspecStream: nuspecStream, - readmeStream: readmeStream); + readmeStream: readmeStream, + iconStream: iconStream); } // Assert @@ -135,12 +147,14 @@ public async Task DoesNotThrowIfContentAlreadyExistsAndContentsMatch() using (var packageStream = StringStream("My package")) using (var nuspecStream = StringStream("My nuspec")) using (var readmeStream = StringStream("My readme")) + using (var iconStream = StringStream("My icon")) { await _target.SavePackageContentAsync( _package, packageStream: packageStream, nuspecStream: nuspecStream, - readmeStream: readmeStream); + readmeStream: readmeStream, + iconStream: iconStream); // Assert Assert.True(_puts.ContainsKey(PackagePath)); @@ -154,6 +168,10 @@ await _target.SavePackageContentAsync( Assert.True(_puts.ContainsKey(ReadmePath)); Assert.Equal("My readme", await ToStringAsync(_puts[ReadmePath].Content)); Assert.Equal("text/markdown", _puts[ReadmePath].ContentType); + + Assert.True(_puts.ContainsKey(IconPath)); + Assert.Equal("My icon", await ToStringAsync(_puts[IconPath].Content)); + Assert.Equal("image/icon", _puts[IconPath].ContentType); } } @@ -166,6 +184,7 @@ public async Task ThrowsIfContentAlreadyExistsButContentsDoNotMatch() using (var packageStream = StringStream("My package")) using (var nuspecStream = StringStream("My nuspec")) using (var readmeStream = StringStream("My readme")) + using (var iconStream = StringStream("My icon")) { // Act await Assert.ThrowsAsync(() => @@ -173,7 +192,8 @@ await Assert.ThrowsAsync(() => _package, packageStream: packageStream, nuspecStream: nuspecStream, - readmeStream: readmeStream)); + readmeStream: readmeStream, + iconStream: iconStream)); } } } @@ -331,6 +351,7 @@ public FactsBase() protected string PackagePath => Path.Combine("packages", "my.package", "1.2.3", "my.package.1.2.3.nupkg"); protected string NuspecPath => Path.Combine("packages", "my.package", "1.2.3", "my.package.nuspec"); protected string ReadmePath => Path.Combine("packages", "my.package", "1.2.3", "readme"); + protected string IconPath => Path.Combine("packages", "my.package", "1.2.3", "icon"); protected Stream StringStream(string input) { diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 1dec614f..bece70dc 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -15,7 +15,7 @@ 3.0.2 4.10.0 12.0.2 - 5.0.0-rtm.5856 + 5.4.0 2.4.1