├── .devcontainer ├── Dockerfile ├── devcontainer.json └── scripts │ └── container-creation.sh ├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── BaGet.sln ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── docs ├── advanced │ ├── debugging.md │ └── sdk.md ├── configuration.md ├── import │ ├── local-feeds.md │ ├── nugetorg.md │ └── nugetserver.md ├── index.md ├── installation │ ├── aliyun.md │ ├── aws.md │ ├── azure.md │ ├── docker.md │ ├── gcp.md │ ├── iis-proxy.md │ └── local.md ├── readme.md └── vs │ ├── artifactory.md │ ├── azure-artifacts.md │ ├── liget.md │ ├── local-feeds.md │ ├── myget.md │ ├── nexus.md │ ├── nugetorg.md │ ├── nugetserver.md │ └── teamcity.md ├── mkdocs.yml ├── nuget.config ├── readme.md ├── samples ├── BaGet.Protocol.Samples.Tests │ ├── BaGet.Protocol.Samples.Tests.csproj │ ├── Sample01_Download.cs │ ├── Sample02_Search.cs │ └── Sample03_Metadata.cs ├── BaGetWebApplication │ ├── BaGetWebApplication.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.Development.json │ └── appsettings.json └── readme.md ├── src ├── BaGet.Aliyun │ ├── AliyunApplicationExtensions.cs │ ├── AliyunStorageOptions.cs │ ├── AliyunStorageService.cs │ └── BaGet.Aliyun.csproj ├── BaGet.Aws │ ├── AwsApplicationExtensions.cs │ ├── BaGet.Aws.csproj │ ├── S3StorageOptions.cs │ └── S3StorageService.cs ├── BaGet.Azure │ ├── AzureApplicationExtensions.cs │ ├── BaGet.Azure.csproj │ ├── Configuration │ │ ├── AzureBlobStorageOptions.cs │ │ ├── AzureSearchOptions.cs │ │ └── AzureTableOptions.cs │ ├── Extensions │ │ └── StorageExceptionExtensions.cs │ ├── Search │ │ ├── AzureSearchBatchIndexer.cs │ │ ├── AzureSearchIndexer.cs │ │ ├── AzureSearchService.cs │ │ ├── ExactMatchCustomAnalyzer.cs │ │ ├── IndexActionBuilder.cs │ │ ├── PackageDocument.cs │ │ └── SearchFilters.cs │ ├── Storage │ │ └── BlobStorageService.cs │ └── Table │ │ ├── PackageEntity.cs │ │ ├── PackageEntityExtensions.cs │ │ ├── TableOperationBuilder.cs │ │ ├── TablePackageDatabase.cs │ │ └── TableSearchService.cs ├── BaGet.Core │ ├── Authentication │ │ ├── ApiKeyAuthenticationService.cs │ │ └── IAuthenticationService.cs │ ├── BaGet.Core.csproj │ ├── BaGetApplication.cs │ ├── Configuration │ │ ├── BaGetOptions.cs │ │ ├── BindOptions.cs │ │ ├── DatabaseOptions.cs │ │ ├── FileSystemStorageOptions.cs │ │ ├── MirrorOptions.cs │ │ ├── PackageDeletionBehavior.cs │ │ ├── SearchOptions.cs │ │ └── StorageOptions.cs │ ├── Content │ │ ├── DefaultPackageContentService.cs │ │ └── IPackageContentService.cs │ ├── Entities │ │ ├── AbstractContext.cs │ │ ├── Converters │ │ │ ├── StringArrayComparer.cs │ │ │ ├── StringArrayToJsonConverter.cs │ │ │ └── UriToStringConverter.cs │ │ ├── IContext.cs │ │ ├── NullContext.cs │ │ ├── Package.cs │ │ ├── PackageDependency.cs │ │ ├── PackageType.cs │ │ ├── SemVerLevel.cs │ │ └── TargetFramework.cs │ ├── Extensions │ │ ├── BaGetApplicationExtensions.cs │ │ ├── DependencyInjectionExtensions.Providers.cs │ │ ├── DependencyInjectionExtensions.cs │ │ ├── IProvider.cs │ │ ├── PackageArchiveReaderExtensions.cs │ │ ├── StreamExtensions.cs │ │ └── SystemTime.cs │ ├── IPackageDatabase.cs │ ├── IPackageService.cs │ ├── IUrlGenerator.cs │ ├── Indexing │ │ ├── FrameworkCompatibilityService.cs │ │ ├── IFrameworkCompatibilityService.cs │ │ ├── IPackageDeletionService.cs │ │ ├── IPackageIndexingService.cs │ │ ├── ISymbolIndexingService.cs │ │ ├── PackageDeletionService.cs │ │ ├── PackageIndexingService.cs │ │ └── SymbolIndexingService.cs │ ├── Metadata │ │ ├── BaGetPackageMetadata.cs │ │ ├── BaGetRegistrationIndexPage.cs │ │ ├── BaGetRegistrationIndexPageItem.cs │ │ ├── BaGetRegistrationIndexResponse.cs │ │ ├── DefaultPackageMetadataService.cs │ │ ├── IPackageMetadataService.cs │ │ ├── PackageRegistration.cs │ │ └── RegistrationBuilder.cs │ ├── PackageDatabase.cs │ ├── PackageService.cs │ ├── Search │ │ ├── AutocompleteRequest.cs │ │ ├── DatabaseSearchService.cs │ │ ├── DependentsResponse.cs │ │ ├── ISearchIndexer.cs │ │ ├── ISearchResponseBuilder.cs │ │ ├── ISearchService.cs │ │ ├── NullSearchIndexer.cs │ │ ├── NullSearchService.cs │ │ ├── SearchRequest.cs │ │ ├── SearchResponseBuilder.cs │ │ └── VersionsRequest.cs │ ├── ServiceIndex │ │ ├── BaGetServiceIndex.cs │ │ └── IServiceIndexService.cs │ ├── Storage │ │ ├── FileStorageService.cs │ │ ├── IPackageStorageService.cs │ │ ├── IStorageService.cs │ │ ├── ISymbolStorageService.cs │ │ ├── NullStorageService.cs │ │ ├── PackageStorageService.cs │ │ └── SymbolStorageService.cs │ ├── Upstream │ │ ├── Clients │ │ │ ├── DisabledUpstreamClient.cs │ │ │ ├── V2UpstreamClient.cs │ │ │ └── V3UpstreamClient.cs │ │ ├── DownloadsImporter.cs │ │ ├── IPackageDownloadsSource.cs │ │ ├── IUpstreamClient.cs │ │ └── PackageDownloadsJsonSource.cs │ ├── Validation │ │ ├── RequiredIfAttribute.cs │ │ ├── ValidateBaGetOptions.cs │ │ └── ValidateStartupOptions.cs │ └── readme.md ├── BaGet.Database.MySql │ ├── BaGet.Database.MySql.csproj │ ├── Migrations │ │ ├── 20181212113156_Initial.Designer.cs │ │ ├── 20181212113156_Initial.cs │ │ ├── 20190303071640_AddSearchDimensions.Designer.cs │ │ ├── 20190303071640_AddSearchDimensions.cs │ │ ├── 20190914215810_AddOriginalVersionStringColumn.Designer.cs │ │ ├── 20190914215810_AddOriginalVersionStringColumn.cs │ │ ├── 20200109085155_AddReleaseNotesStringColumn.Designer.cs │ │ ├── 20200109085155_AddReleaseNotesStringColumn.cs │ │ ├── 20200210004047_AddHasEmbeddedIconColumn.Designer.cs │ │ ├── 20200210004047_AddHasEmbeddedIconColumn.cs │ │ ├── 20210919191554_RemoveReleaseNotesMaxLength.Designer.cs │ │ ├── 20210919191554_RemoveReleaseNotesMaxLength.cs │ │ └── MySqlContextModelSnapshot.cs │ ├── MySqlApplicationExtensions.cs │ ├── MySqlContext.cs │ └── readme.md ├── BaGet.Database.PostgreSql │ ├── BaGet.Database.PostgreSql.csproj │ ├── Migrations │ │ ├── 20190311172227_Initial.Designer.cs │ │ ├── 20190311172227_Initial.cs │ │ ├── 20190914220105_AddOriginalVersionStringColumn.Designer.cs │ │ ├── 20190914220105_AddOriginalVersionStringColumn.cs │ │ ├── 20200109085355_AddReleaseNotesStringColumn.Designer.cs │ │ ├── 20200109085355_AddReleaseNotesStringColumn.cs │ │ ├── 20200208053115_FixVersionCaseSensitivity.Designer.cs │ │ ├── 20200208053115_FixVersionCaseSensitivity.cs │ │ ├── 20200210004256_AddHasEmbeddedIconColumn.Designer.cs │ │ ├── 20200210004256_AddHasEmbeddedIconColumn.cs │ │ ├── 20210919191649_RemoveReleaseNotesMaxLength.Designer.cs │ │ ├── 20210919191649_RemoveReleaseNotesMaxLength.cs │ │ └── PostgreSqlContextModelSnapshot.cs │ ├── PostgreSqlApplicationExtensions.cs │ ├── PostgreSqlContext.cs │ └── readme.md ├── BaGet.Database.SqlServer │ ├── BaGet.Database.SqlServer.csproj │ ├── Migrations │ │ ├── 20180804082816_Initial.Designer.cs │ │ ├── 20180804082816_Initial.cs │ │ ├── 20190303071621_AddSearchDimensions.Designer.cs │ │ ├── 20190303071621_AddSearchDimensions.cs │ │ ├── 20190914215959_AddOriginalVersionStringColumn.Designer.cs │ │ ├── 20190914215959_AddOriginalVersionStringColumn.cs │ │ ├── 20200109085508_AddReleaseNotesStringColumn.Designer.cs │ │ ├── 20200109085508_AddReleaseNotesStringColumn.cs │ │ ├── 20200210004408_AddHasEmbeddedIconColumn.Designer.cs │ │ ├── 20200210004408_AddHasEmbeddedIconColumn.cs │ │ ├── 20210919191928_RemoveReleaseNotesMaxLength.Designer.cs │ │ ├── 20210919191928_RemoveReleaseNotesMaxLength.cs │ │ └── SqlServerContextModelSnapshot.cs │ ├── SqlServerApplicationExtensions.cs │ ├── SqlServerContext.cs │ └── readme.md ├── BaGet.Database.Sqlite │ ├── BaGet.Database.Sqlite.csproj │ ├── Migrations │ │ ├── 20180804082808_Initial.Designer.cs │ │ ├── 20180804082808_Initial.cs │ │ ├── 20190303072658_AddSearchDimensions.Designer.cs │ │ ├── 20190303072658_AddSearchDimensions.cs │ │ ├── 20190914215110_AddOriginalVersionStringColumn.Designer.cs │ │ ├── 20190914215110_AddOriginalVersionStringColumn.cs │ │ ├── 20200109071618_AddReleaseNotesStringColumn.Designer.cs │ │ ├── 20200109071618_AddReleaseNotesStringColumn.cs │ │ ├── 20200208044959_FixVersionCaseSensitivity.Designer.cs │ │ ├── 20200208044959_FixVersionCaseSensitivity.cs │ │ ├── 20200210004344_AddHasEmbeddedIconColumn.Designer.cs │ │ ├── 20200210004344_AddHasEmbeddedIconColumn.cs │ │ ├── 20210919190849_RemoveReleaseNotesMaxLength.Designer.cs │ │ ├── 20210919190849_RemoveReleaseNotesMaxLength.cs │ │ └── SqliteContextModelSnapshot.cs │ ├── SqliteApplicationExtensions.cs │ ├── SqliteContext.cs │ └── readme.md ├── BaGet.Gcp │ ├── BaGet.Gcp.csproj │ ├── GoogleCloudApplicationExtensions.cs │ ├── GoogleCloudStorageOptions.cs │ └── GoogleCloudStorageService.cs ├── BaGet.Protocol │ ├── BaGet.Protocol.csproj │ ├── Catalog │ │ ├── CatalogClient.cs │ │ ├── CatalogProcessor.cs │ │ ├── CatalogProcessorOptions.cs │ │ ├── FileCursor.cs │ │ ├── ICatalogClient.cs │ │ ├── ICatalogLeafProcessor.cs │ │ ├── ICursor.cs │ │ ├── NullCatalogClient.cs │ │ ├── NullCursor.cs │ │ └── RawCatalogClient.cs │ ├── Converters │ │ ├── PackageDependencyRangeJsonConverter.cs │ │ └── StringOrStringArrayJsonConverter.cs │ ├── Extensions │ │ ├── CatalogModelExtensions.cs │ │ ├── HttpClientExtensions.cs │ │ ├── NuGetClientFactoryExtensions.cs │ │ ├── PackageContentModelExtensions.cs │ │ ├── PackageMetadataModelExtensions.cs │ │ ├── SearchModelExtensions.cs │ │ └── ServiceIndexModelExtensions.cs │ ├── Models │ │ ├── AlternatePackage.cs │ │ ├── AutocompleteContext.cs │ │ ├── AutocompleteResponse.cs │ │ ├── CatalogIndex.cs │ │ ├── CatalogLeaf.cs │ │ ├── CatalogLeafItem.cs │ │ ├── CatalogPage.cs │ │ ├── CatalogPageItem.cs │ │ ├── DependencyGroupItem.cs │ │ ├── DependencyItem.cs │ │ ├── ICatalogLeafItem.cs │ │ ├── PackageDeleteCatalogLeaf.cs │ │ ├── PackageDeprecation.cs │ │ ├── PackageDetailsCatalogLeaf.cs │ │ ├── PackageMetadata.cs │ │ ├── PackageNotFoundException.cs │ │ ├── PackageVersionsResponse.cs │ │ ├── ProtocolException.cs │ │ ├── RegistrationIndexPage.cs │ │ ├── RegistrationIndexPageItem.cs │ │ ├── RegistrationIndexResponse.cs │ │ ├── RegistrationLeafResponse.cs │ │ ├── RegistrationPageResponse.cs │ │ ├── SearchContext.cs │ │ ├── SearchResponse.cs │ │ ├── SearchResult.cs │ │ ├── SearchResultPackageType.cs │ │ ├── SearchResultVersion.cs │ │ ├── ServiceIndexItem.cs │ │ └── ServiceIndexResponse.cs │ ├── NuGetClient.cs │ ├── NuGetClientFactory.cs │ ├── PackageContent │ │ ├── IPackageContentClient.cs │ │ ├── PackageContentClient.cs │ │ └── RawPackageContentClient.cs │ ├── PackageMetadata │ │ ├── IPackageMetadataClient.cs │ │ ├── PackageMetadataClient.cs │ │ └── RawPackageMetadataClient.cs │ ├── Search │ │ ├── AutocompleteClient.cs │ │ ├── IAutocompleteClient.cs │ │ ├── ISearchClient.cs │ │ ├── NullAutocompleteClient.cs │ │ ├── RawAutocompleteClient.cs │ │ ├── RawSearchClient.cs │ │ └── SearchClient.cs │ ├── ServiceIndex │ │ ├── IServiceIndexClient.cs │ │ ├── RawServiceIndexClient.cs │ │ └── ServiceIndexClient.cs │ └── readme.md ├── BaGet.Web │ ├── BaGet.Web.csproj │ ├── BaGetEndpointBuilder.cs │ ├── BaGetUrlGenerator.cs │ ├── Controllers │ │ ├── PackageContentController.cs │ │ ├── PackageMetadataController.cs │ │ ├── PackagePublishController.cs │ │ ├── SearchController.cs │ │ ├── ServiceIndexController.cs │ │ └── SymbolController.cs │ ├── Extensions │ │ ├── HttpRequestExtensions.cs │ │ ├── IApplicationBuilderExtensions.cs │ │ ├── IHostExtensions.cs │ │ ├── IServiceCollectionExtensions.cs │ │ └── RazorExtensions.cs │ ├── NavLinkTagHelper.cs │ ├── OperationCancelledMiddleware.cs │ ├── Pages │ │ ├── Index.cshtml │ │ ├── Index.cshtml.cs │ │ ├── Package.cshtml │ │ ├── Package.cshtml.cs │ │ ├── Shared │ │ │ └── _Layout.cshtml │ │ ├── Upload.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml │ ├── Routes.cs │ ├── libman.json │ └── wwwroot │ │ ├── css │ │ └── site.css │ │ ├── favicon.ico │ │ ├── images │ │ ├── default-package-icon-256x256.png │ │ └── github-32x32.png │ │ ├── js │ │ └── site.js │ │ └── lib │ │ ├── alpinejs │ │ ├── LICENSE.md │ │ ├── README.md │ │ └── dist │ │ │ ├── alpine-ie11.js │ │ │ └── alpine.js │ │ ├── bootstrap │ │ ├── LICENSE │ │ ├── README.md │ │ └── dist │ │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap-theme.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ │ ├── jquery │ │ ├── AUTHORS.txt │ │ ├── LICENSE.txt │ │ ├── README.md │ │ └── dist │ │ │ ├── jquery.js │ │ │ └── jquery.min.js │ │ └── office-ui-fabric-core │ │ ├── LICENSE │ │ ├── README.md │ │ └── dist │ │ └── css │ │ ├── fabric-11.0.0.scoped.css │ │ ├── fabric-11.0.0.scoped.min.css │ │ ├── fabric.css │ │ └── fabric.min.css ├── BaGet │ ├── BaGet.csproj │ ├── ConfigureBaGetOptions.cs │ ├── ConfigureRazorRuntimeCompilation.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── readme.md │ └── wwwroot │ │ └── .gitignore ├── Directory.Build.props ├── packageIcon.png └── readme.md └── tests ├── BaGet.Core.Tests ├── BaGet.Core.Tests.csproj ├── Metadata │ ├── ModelTests.cs │ └── RegistrationBuilderTests.cs ├── Services │ ├── FileStorageServiceTests.cs │ ├── PackageDatabaseTests.cs │ ├── PackageDeletionServiceTests.cs │ ├── PackageIndexingServiceTests.cs │ ├── PackageServiceTests.cs │ ├── PackageStorageServiceTests.cs │ ├── SymbolIndexingServiceTests.cs │ └── SymbolStorageServiceTests.cs └── Upstream │ └── V3UpstreamClientTests.cs ├── BaGet.Protocol.Tests ├── BaGet.Protocol.Tests.csproj ├── Converters │ ├── PackageDependencyRangeJsonConverterTests.cs │ └── StringOrStringArrayJsonConverterTests.cs ├── NuGetClientFactoryTests.cs ├── NuGetClientTests.cs ├── RawAutocompleteClientTests.cs ├── RawCatalogClientTests.cs ├── RawPackageContentClientTests.cs ├── RawPackageMetadataClientTests.cs ├── RawSearchClientTests.cs ├── RawServiceIndexClientTests.cs ├── Support │ ├── ProtocolFixture.cs │ └── TestDataHttpMessageHandler.cs ├── TestData.Designer.cs └── TestData.resx ├── BaGet.Tests ├── ApiIntegrationTests.cs ├── BaGet.Tests.csproj ├── BaGetClientIntegrationTests.cs ├── HostIntegrationTests.cs ├── MirrorIntegrationTests.cs ├── NuGetClientIntegrationTests.cs ├── Support │ ├── BaGetApplication.cs │ ├── HttpSourceResourceProviderTestHost.cs │ ├── StreamExtensions.cs │ ├── TestResources.cs │ ├── TestableHttpSource.cs │ ├── XunitLogger.cs │ └── XunitLoggerProvider.cs └── TestData │ ├── TestData.1.2.3.nupkg │ ├── TestData.1.2.3.snupkg │ ├── TestData.Designer.cs │ └── TestData.resx ├── BaGet.Web.Tests ├── BaGet.Web.Tests.csproj └── Pages │ ├── IndexModelFacts.cs │ └── PackageModelFacts.cs └── Directory.Build.props /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.177.0/containers/dotnet/.devcontainer/base.Dockerfile 3 | 4 | # [Choice] .NET version: 5.0, 3.1, 2.1 5 | ARG VARIANT=3.1 6 | FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT} 7 | -------------------------------------------------------------------------------- /.devcontainer/scripts/container-creation.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See: https://github.com/dotnet/aspnetcore/blob/4b4265972d1155e415633a4a177f159b940cf3bb/.devcontainer/scripts/container-creation.sh 4 | 5 | set -e 6 | 7 | # Install SDK and tool dependencies before container starts 8 | # Also run the full restore on the repo so that go-to definition 9 | # and other language features will be available in C# files 10 | dotnet restore 11 | 12 | # Add .NET Dev Certs to environment to facilitate debugging. 13 | # Do **NOT** do this in a public base image as all images inheriting 14 | # from the base image would inherit these dev certs as well. 15 | dotnet dev-certs https 16 | 17 | # The container creation script is executed in a new Bash instance 18 | # so we exit at the end to avoid the creation process lingering. 19 | exit 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.cs text=auto diff=csharp 17 | *.vb text=auto 18 | *.resx text=auto 19 | *.c text=auto 20 | *.cpp text=auto 21 | *.cxx text=auto 22 | *.h text=auto 23 | *.hxx text=auto 24 | *.py text=auto 25 | *.rb text=auto 26 | *.java text=auto 27 | *.html text=auto 28 | *.htm text=auto 29 | *.css text=auto 30 | *.scss text=auto 31 | *.sass text=auto 32 | *.less text=auto 33 | *.js text=auto 34 | *.lisp text=auto 35 | *.clj text=auto 36 | *.sql text=auto 37 | *.php text=auto 38 | *.lua text=auto 39 | *.m text=auto 40 | *.asm text=auto 41 | *.erl text=auto 42 | *.fs text=auto 43 | *.fsx text=auto 44 | *.hs text=auto 45 | *.tsx text=auto 46 | 47 | *.csproj text=auto 48 | *.vbproj text=auto 49 | *.fsproj text=auto 50 | *.dbproj text=auto 51 | *.sln text=auto eol=crlf 52 | 53 | *.sh eol=lf -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report about something that is not working 4 | --- 5 | 6 | ### Describe the bug 7 | A clear and concise description of what the bug is. 8 | 9 | ### To Reproduce 10 | Steps to reproduce the behavior: 11 | 1. Using this version of BaGet '...' 12 | 2. Run this code '....' 13 | 3. With these arguments '....' 14 | 4. See error 15 | 16 | ### Expected behavior 17 | A clear and concise description of what you expected to happen. 18 | 19 | ### Screenshots 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | ### Additional context 23 | Add any other context about the problem here. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | --- 5 | 6 | ### Is your feature request related to a problem? Please describe. 7 | A clear and concise description of what the problem is. 8 | Example. I'm am trying to do [...] but [...] 9 | 10 | ### Describe the solution you'd like 11 | A clear and concise description of what you want to happen. 12 | 13 | ### Describe alternatives you've considered 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | ### Additional context 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Summary of the changes (in less than 80 chars) 2 | 3 | * Detail 1 4 | * Detail 2 5 | 6 | Addresses https://github.com/loic-sharma/BaGet/issues/123 7 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | # Triggers the workflow on push or pull request events but only for the main branch 5 | push: 6 | branches: [ main ] 7 | pull_request: 8 | branches: [ main ] 9 | 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: 3.1.x 23 | - name: Restore dependencies 24 | run: dotnet restore 25 | - name: Build 26 | run: dotnet build --no-restore 27 | - name: Test 28 | run: dotnet test --no-build --verbosity normal 29 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (web)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/src/BaGet/bin/Debug/netcoreapp3.1/BaGet.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/src/BaGet", 16 | "stopAtEntry": false, 17 | "internalConsoleOptions": "openOnSessionStart", 18 | "launchBrowser": { 19 | "enabled": true, 20 | "args": "${auto-detect-url}", 21 | "windows": { 22 | "command": "cmd.exe", 23 | "args": "/C start ${auto-detect-url}" 24 | }, 25 | "osx": { 26 | "command": "open" 27 | }, 28 | "linux": { 29 | "command": "xdg-open" 30 | } 31 | }, 32 | "env": { 33 | "ASPNETCORE_ENVIRONMENT": "Development" 34 | }, 35 | "sourceFileMap": { 36 | "/Views": "${workspaceFolder}/Views" 37 | } 38 | }, 39 | { 40 | "name": ".NET Core Attach", 41 | "type": "coreclr", 42 | "request": "attach", 43 | "processId": "${command:pickProcess}" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "taskName": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/src/BaGet/BaGet.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contribute 2 | 3 | Please read the [code of conduct] before contributing. 4 | 5 | If you want to run from BaGet's source code: 6 | 7 | 1. Install the [.NET SDK] and [Node.js] 8 | 2. Run `git clone https://github.com/loic-sharma/BaGet.git` 9 | 3. Navigate to `./BaGet/src/BaGet` 10 | 4. Start the service with `dotnet run` 11 | 5. Open the URL `http://localhost:5000/v3/index.json` in your browser 12 | 13 | [Code of conduct]: CODE_OF_CONDUCT.md 14 | [.NET SDK]: https://www.microsoft.com/net/download 15 | [Node.js]: https://nodejs.org/ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | 5 | FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build 6 | WORKDIR /src 7 | COPY /src . 8 | RUN dotnet restore BaGet 9 | RUN dotnet build BaGet -c Release -o /app 10 | 11 | FROM build AS publish 12 | RUN dotnet publish BaGet -c Release -o /app 13 | 14 | FROM base AS final 15 | LABEL org.opencontainers.image.source="https://github.com/loic-sharma/BaGet" 16 | WORKDIR /app 17 | COPY --from=publish /app . 18 | ENTRYPOINT ["dotnet", "BaGet.dll"] 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Loic Sharma 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /docs/advanced/debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging BaGet 2 | 3 | !!! warning 4 | This page is a work in progress! 5 | -------------------------------------------------------------------------------- /docs/import/local-feeds.md: -------------------------------------------------------------------------------- 1 | # Import packages from a local feed 2 | 3 | [Local feeds](https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds) let you use a folder as a NuGet package source. 4 | 5 | !!! info 6 | Please refer to the [BaGet vs local feeds](../vs/local-feeds.md) page for reasons to upgrade to BaGet. 7 | 8 | ## Steps 9 | 10 | Make sure that you've installed [nuget.exe](https://www.nuget.org/downloads). In PowerShell, run: 11 | 12 | ```ps1 13 | $source = "C:\path\to\local\feed" 14 | $destination = "http://localhost:5000/v3/index.json" 15 | ``` 16 | 17 | If you've [configured BaGet to require an API Key](https://loic-sharma.github.io/BaGet/configuration/#requiring-an-api-key), set it using [the `setapikey` command](https://docs.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-setapikey): 18 | 19 | ```ps1 20 | & nuget.exe setapikey "MY-API-KEY" -Source $destination 21 | ``` 22 | 23 | Now run the following PowerShell script: 24 | 25 | ```ps1 26 | $packages = nuget list -AllVersions -Source $source 27 | 28 | $packages | % { 29 | $id, $version = $_ -Split " " 30 | $nupkg = $id + "." + $version + ".nupkg" 31 | $path = [IO.Path]::Combine($source, $id, $version, $nupkg) 32 | 33 | Write-Host "nuget.exe push -Source $destination ""$path""" 34 | & nuget.exe push -Source $destination $path 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/import/nugetorg.md: -------------------------------------------------------------------------------- 1 | # Import nuget.org packages 2 | 3 | !!! warning 4 | This page is a work in progress! 5 | 6 | ## Mirroring 7 | 8 | You can configure BaGet to mirror nuget.org. For example, say you install BaGet, enable mirroring, and try to install the package 9 | [`Newtonsoft.Json`](https://www.nuget.org/packages/Newtonsoft.Json/). BaGet doesn't have this package yet, so it will 10 | automatically index this package from nuget.org. This is also known as "read-through caching". 11 | 12 | For more information, please see [Enable read-through caching](../configuration#enable-read-through-caching). 13 | 14 | ## Importing package downloads from nuget.org 15 | 16 | You can import package downloads from nuget.org: 17 | 18 | 1. Navigate to `.\BaGet\src\BaGet` 19 | 2. Run: 20 | 21 | ``` 22 | dotnet run -- import-downloads 23 | ``` 24 | 25 | ## Importing all nuget.org packages 26 | 27 | * TODO Check-in code 28 | * Explain scaling 29 | * Rebuild indexes at end 30 | * Importing downloads from nuget.org 31 | -------------------------------------------------------------------------------- /docs/import/nugetserver.md: -------------------------------------------------------------------------------- 1 | # Import NuGet.Server packages 2 | 3 | [NuGet.Server](https://github.com/NuGet/NuGet.Server) is a lightweight standalone NuGet server. It is strongly recommended that you upgrade to BaGet if you use NuGet.Server. Feel free to open a [GitHub issue](https://github.com/loic-sharma/BaGet/issues) if you need help migrating. 4 | 5 | !!! info 6 | Please refer to the [BaGet vs NuGet.Server](../vs/nugetserver.md) page for reasons to upgrade to BaGet. 7 | 8 | ## Steps 9 | 10 | Make sure that you've installed [nuget.exe](https://www.nuget.org/downloads). In PowerShell, run: 11 | 12 | ```ps1 13 | $source = "" 14 | $destination = "" 15 | ``` 16 | 17 | If you've [configured BaGet to require an API Key](https://loic-sharma.github.io/BaGet/configuration/#requiring-an-api-key), set it using [the `setapikey` command](https://docs.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-setapikey): 18 | 19 | ```ps1 20 | & nuget.exe setapikey "MY-API-KEY" -Source $destination 21 | ``` 22 | 23 | Now run the following PowerShell script: 24 | 25 | ```ps1 26 | if (!(Test-Path "Web.config")) { 27 | throw "Please run this script in the same directory as NuGet.Server's Web.config file" 28 | } 29 | 30 | (& nuget.exe list -AllVersions -Source $source).Split([Environment]::NewLine) | % { 31 | $id = $_.Split(" ")[0].Trim() 32 | $version = $_.Split(" ")[1].Trim() 33 | 34 | $path = [IO.Path]::Combine("Packages", $id, $version, "${id}.${version}.nupkg") 35 | 36 | Write-Host "nuget.exe push -Source $destination ""$path""" 37 | & nuget.exe push -Source $destination $path 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # BaGet 2 | 3 | BaGet (pronounced "baguette") is a lightweight NuGet and symbol server. It is [open source](https://github.com/loic-sharma/BaGet), cross-platform, and cloud ready! 4 | 5 |

6 | 7 |

8 | 9 | ## Run BaGet 10 | 11 | You can run BaGet on your preferred platform: 12 | 13 | * [On your computer](installation/local.md) 14 | * [Docker](installation/docker.md) 15 | * [Azure](installation/azure.md) 16 | * [AWS](installation/aws.md) 17 | * [Google Cloud](installation/gcp.md) 18 | * [Alibaba Cloud (Aliyun)](installation/aliyun.md) 19 | 20 | ## BaGet SDK 21 | 22 | You can also use the [`BaGet.Protocol`](https://www.nuget.org/packages/BaGet.Protocol) package to interact with a NuGet server. For more information, please refer to the [BaGet SDK](advanced/sdk.md) guide. 23 | -------------------------------------------------------------------------------- /docs/installation/aliyun.md: -------------------------------------------------------------------------------- 1 | # Use Alibaba (Aliyun) Object Storage Service 2 | 3 | You can store packages to [Alibaba(Aliyun) OSS](https://www.alibabacloud.com/product/oss). 4 | 5 | ## Configure BaGet 6 | 7 | You can modify BaGet's configurations by editing the `appsettings.json` file. For the full list of configurations, please refer to [BaGet's configuration](../configuration.md) guide. 8 | 9 | ### Aliyun OSS Storage 10 | 11 | Update the `appsettings.json` file: 12 | 13 | ```json 14 | { 15 | ... 16 | 17 | "Storage": { 18 | "Type": "AliyunOss", 19 | "Endpoint": "oss-us-west-1.aliyuncs.com", 20 | "Bucket": "foo", 21 | "AccessKey": "", 22 | "AccessKeySecret": "", 23 | "Prefix": "lib/baget" // optional 24 | }, 25 | 26 | ... 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | Please use the [documentation website](https://loic-sharma.github.io/BaGet/) 2 | for the best browsing experience. -------------------------------------------------------------------------------- /docs/vs/artifactory.md: -------------------------------------------------------------------------------- 1 | # Artifactory 2 | 3 | !!! warning 4 | This page is a work in progress! -------------------------------------------------------------------------------- /docs/vs/azure-artifacts.md: -------------------------------------------------------------------------------- 1 | # Azure Artifacts 2 | 3 | !!! warning 4 | This page is a work in progress! -------------------------------------------------------------------------------- /docs/vs/liget.md: -------------------------------------------------------------------------------- 1 | # LiGet 2 | 3 | !!! warning 4 | This page is a work in progress! 5 | 6 | [LiGet](https://github.com/ai-traders/liget) is a NuGet server created with a linux-first approach. 7 | 8 | * LiGet 9 | * Strong support for Paket 10 | * Only supports NuGet's v2 APIs (missing verified packages, signed packages, etc...) 11 | * Stores all packages' metadata using a single JSON file 12 | * BaGet 13 | * Supports NuGet's v3 APIs 14 | * Stores packages' metadata in a database 15 | * Capable of ingesting all packages on nuget.org 16 | * Can run on Azure -------------------------------------------------------------------------------- /docs/vs/local-feeds.md: -------------------------------------------------------------------------------- 1 | # Local Feeds 2 | 3 | !!! warning 4 | This page is a work in progress! 5 | 6 | [Local feeds](https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds), also known as "folder feeds", let you 7 | use a folder as a NuGet package source. You can access these packages using a network share. 8 | 9 | # BaGet vs local feeds 10 | 11 | Local feeds are very simple and are lack features like: 12 | 13 | 1. Search functionality 14 | 1. A user interface to browse your packages 15 | 1. Authentication for package uploads 16 | 1. Cloud storage for large feeds 17 | -------------------------------------------------------------------------------- /docs/vs/myget.md: -------------------------------------------------------------------------------- 1 | # MyGet 2 | 3 | !!! warning 4 | This page is a work in progress! -------------------------------------------------------------------------------- /docs/vs/nexus.md: -------------------------------------------------------------------------------- 1 | # Nexus 2 | 3 | !!! warning 4 | This page is a work in progress! -------------------------------------------------------------------------------- /docs/vs/nugetserver.md: -------------------------------------------------------------------------------- 1 | # NuGet.Server 2 | 3 | !!! warning 4 | This page is a work in progress! 5 | 6 | [NuGet.Server](https://github.com/NuGet/NuGet.Server) is a lightweight standalone NuGet server. It is strongly recommended that you upgrade to BaGet if you use NuGet.Server. Feel free to open [GitHub issues](https://github.com/loic-sharma/BaGet/issues) if you need help migrating. 7 | 8 | * NuGet.Server 9 | * Only runs on Windows 10 | * Supports NuGet v2 APIs (missing verified packages, signed packages, etc...) 11 | * Doesn't support NuGet's v3 APIs 12 | * Does not scale well 13 | * Not well documented 14 | * Not well maintained 15 | * BaGet 16 | * Cross-platform 17 | * Supports NuGet v3 APIs 18 | 19 | ## Migration Guide 20 | 21 | You can use the [NuGet.Server migration](../import/nugetserver.md) guide to import your NuGet.Server packages into BaGet. -------------------------------------------------------------------------------- /docs/vs/teamcity.md: -------------------------------------------------------------------------------- 1 | # TeamCity 2 | 3 | !!! warning 4 | This page is a work in progress! -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: BaGet 2 | site_description: A lightweight NuGet and symbol server 3 | site_author: Loic Sharma 4 | site_url: https://loic-sharma.github.io/BaGet/ 5 | 6 | repo_name: loic-sharma/BaGet 7 | repo_url: https://github.com/loic-sharma/BaGet 8 | 9 | copyright: 'Copyright © 2020 Loic Sharma' 10 | 11 | theme: 12 | name: material 13 | language: en 14 | palette: 15 | primary: yellow 16 | accent: yellow 17 | font: 18 | text: Roboto 19 | code: Roboto Mono 20 | 21 | extra: 22 | social: 23 | - type: github-alt 24 | link: https://github.com/loic-sharma 25 | - type: twitter 26 | link: https://twitter.com/bagetapp 27 | 28 | markdown_extensions: 29 | - markdown.extensions.admonition 30 | - markdown.extensions.codehilite: 31 | guess_lang: false 32 | - markdown.extensions.toc: 33 | permalink: true 34 | 35 | pages: 36 | - Overview: index.md 37 | - Installation: 38 | - On your computer: installation/local.md 39 | - Docker: installation/docker.md 40 | - Azure: installation/azure.md 41 | - AWS: installation/aws.md 42 | - Google cloud: installation/gcp.md 43 | - Alibaba cloud: installation/aliyun.md 44 | - Windows IIS proxy: installation/iis-proxy.md 45 | - Configuration: configuration.md 46 | - Import: 47 | - Local feeds: import/local-feeds.md 48 | - NuGet.Server: import/nugetserver.md 49 | - NuGet.org: import/nugetorg.md 50 | - Advanced: 51 | - Debugging: advanced/debugging.md 52 | - BaGet SDK: advanced/sdk.md 53 | - BaGet vs. other: 54 | - nuget.org: vs/nugetorg.md 55 | - NuGet.Server: vs/nugetserver.md 56 | - Local feeds: vs/local-feeds.md 57 | - Azure Artifacts: vs/azure-artifacts.md 58 | - MyGet: vs/myget.md 59 | - LiGet: vs/liget.md 60 | - Artifactory: vs/artifactory.md 61 | - Nexus: vs/nexus.md 62 | - TeamCity: vs/teamcity.md 63 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/BaGet.Protocol.Samples.Tests/BaGet.Protocol.Samples.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | IDE0007 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/BaGet.Protocol.Samples.Tests/Sample01_Download.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using NuGet.Versioning; 5 | using Xunit; 6 | 7 | namespace BaGet.Protocol.Samples.Tests 8 | { 9 | public class Sample01_Download 10 | { 11 | [Fact] 12 | public async Task DownloadPackage() 13 | { 14 | // Downloads a package file (.nupkg) 15 | NuGetClient client = new NuGetClient("https://api.nuget.org/v3/index.json"); 16 | 17 | string packageId = "Newtonsoft.Json"; 18 | NuGetVersion packageVersion = new NuGetVersion("12.0.1"); 19 | 20 | using (Stream packageStream = await client.DownloadPackageAsync(packageId, packageVersion)) 21 | { 22 | Console.WriteLine($"Downloaded package {packageId} {packageVersion}"); 23 | } 24 | } 25 | 26 | [Fact] 27 | public async Task DownloadPackageManifest() 28 | { 29 | // Downloads a package manifest (.nuspec) 30 | NuGetClient client = new NuGetClient("https://api.nuget.org/v3/index.json"); 31 | 32 | string packageId = "Newtonsoft.Json"; 33 | NuGetVersion packageVersion = new NuGetVersion("12.0.1"); 34 | 35 | using (Stream manifestStream = await client.DownloadPackageManifestAsync(packageId, packageVersion)) 36 | { 37 | Console.WriteLine($"Downloaded package {packageId} {packageVersion}'s nuspec"); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /samples/BaGetWebApplication/BaGetWebApplication.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/BaGetWebApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using BaGet.Web; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Hosting; 5 | 6 | namespace BaGetWebApplication 7 | { 8 | public class Program 9 | { 10 | public static async Task Main(string[] args) 11 | { 12 | var host = CreateHostBuilder(args).Build(); 13 | 14 | await host.RunMigrationsAsync(); 15 | await host.RunAsync(); 16 | } 17 | 18 | public static IHostBuilder CreateHostBuilder(string[] args) => 19 | Host.CreateDefaultBuilder(args) 20 | .ConfigureWebHostDefaults(webBuilder => 21 | { 22 | webBuilder.UseStartup(); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/BaGetWebApplication/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:60558", 7 | "sslPort": 44309 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "BaGetWebApplication": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /samples/BaGetWebApplication/Startup.cs: -------------------------------------------------------------------------------- 1 | using BaGet; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace BaGetWebApplication 8 | { 9 | public class Startup 10 | { 11 | public void ConfigureServices(IServiceCollection services) 12 | { 13 | services.AddBaGetWebApplication(app => 14 | { 15 | // Use SQLite as BaGet's database and store packages on the local file system. 16 | app.AddSqliteDatabase(); 17 | app.AddFileStorage(); 18 | }); 19 | } 20 | 21 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 22 | { 23 | if (env.IsDevelopment()) 24 | { 25 | app.UseDeveloperExceptionPage(); 26 | } 27 | 28 | app.UseStaticFiles(); 29 | app.UseRouting(); 30 | 31 | app.UseEndpoints(endpoints => 32 | { 33 | // Add BaGet's endpoints. 34 | var baget = new BaGetEndpointBuilder(); 35 | 36 | baget.MapEndpoints(endpoints); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/BaGetWebApplication/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/BaGetWebApplication/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Database": { 3 | "ConnectionString": "Data Source=baget.db" 4 | }, 5 | 6 | "Logging": { 7 | "LogLevel": { 8 | "Default": "Information", 9 | "Microsoft": "Warning", 10 | "Microsoft.Hosting.Lifetime": "Information" 11 | } 12 | }, 13 | "AllowedHosts": "*" 14 | } 15 | -------------------------------------------------------------------------------- /samples/readme.md: -------------------------------------------------------------------------------- 1 | # Samples 2 | 3 | Here you can find samples that show you how to use BaGet in your own projects: 4 | 5 | * `BaGetWebApplication` - Embed BaGet into your own ASP.NET Core project 6 | * `BaGet.Protocol.Samples.Tests` - Interact with a NuGet V3 API 7 | -------------------------------------------------------------------------------- /src/BaGet.Aliyun/AliyunApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Aliyun.OSS; 3 | using BaGet.Aliyun; 4 | using BaGet.Core; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.DependencyInjection.Extensions; 7 | using Microsoft.Extensions.Options; 8 | 9 | namespace BaGet 10 | { 11 | public static class AliyunApplicationExtensions 12 | { 13 | public static BaGetApplication AddAliyunOssStorage(this BaGetApplication app) 14 | { 15 | app.Services.AddBaGetOptions(nameof(BaGetOptions.Storage)); 16 | 17 | app.Services.AddTransient(); 18 | app.Services.TryAddTransient(provider => provider.GetRequiredService()); 19 | 20 | app.Services.AddSingleton(provider => 21 | { 22 | var options = provider.GetRequiredService>().Value; 23 | 24 | return new OssClient(options.Endpoint, options.AccessKey, options.AccessKeySecret); 25 | }); 26 | 27 | app.Services.AddProvider((provider, config) => 28 | { 29 | if (!config.HasStorageType("AliyunOss")) return null; 30 | 31 | return provider.GetRequiredService(); 32 | }); 33 | 34 | return app; 35 | } 36 | 37 | public static BaGetApplication AddAliyunOssStorage( 38 | this BaGetApplication app, 39 | Action configure) 40 | { 41 | app.AddAliyunOssStorage(); 42 | app.Services.Configure(configure); 43 | return app; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/BaGet.Aliyun/AliyunStorageOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BaGet.Aliyun 4 | { 5 | public class AliyunStorageOptions 6 | { 7 | [Required] 8 | public string AccessKey { get; set; } 9 | 10 | [Required] 11 | public string AccessKeySecret { get; set; } 12 | 13 | [Required] 14 | public string Endpoint { get; set; } 15 | 16 | [Required] 17 | public string Bucket { get; set; } 18 | 19 | public string Prefix { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BaGet.Aliyun/BaGet.Aliyun.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | NuGet;Alibaba;Cloud 4 | The libraries to host BaGet on Alibaba Cloud (Aliyun). 5 | netstandard2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/BaGet.Aws/BaGet.Aws.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet;Amazon;Cloud 7 | The libraries to host BaGet on AWS. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/BaGet.Aws/S3StorageOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using BaGet.Core; 3 | 4 | namespace BaGet.Aws 5 | { 6 | public class S3StorageOptions 7 | { 8 | [RequiredIf(nameof(SecretKey), null, IsInverted = true)] 9 | public string AccessKey { get; set; } 10 | 11 | [RequiredIf(nameof(AccessKey), null, IsInverted = true)] 12 | public string SecretKey { get; set; } 13 | 14 | [Required] 15 | public string Region { get; set; } 16 | 17 | [Required] 18 | public string Bucket { get; set; } 19 | 20 | public string Prefix { get; set; } 21 | 22 | public bool UseInstanceProfile { get; set; } 23 | 24 | public string AssumeRoleArn { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BaGet.Azure/BaGet.Azure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet;Azure;Cloud 7 | The libraries to host BaGet on Azure. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/BaGet.Azure/Configuration/AzureSearchOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BaGet.Azure 4 | { 5 | public class AzureSearchOptions 6 | { 7 | [Required] 8 | public string AccountName { get; set; } 9 | 10 | [Required] 11 | public string ApiKey { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/BaGet.Azure/Configuration/AzureTableOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BaGet.Azure 4 | { 5 | public class AzureTableOptions 6 | { 7 | [Required] 8 | public string ConnectionString { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/BaGet.Azure/Extensions/StorageExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace BaGet.Azure 4 | { 5 | using StorageException = Microsoft.WindowsAzure.Storage.StorageException; 6 | using TableStorageException = Microsoft.Azure.Cosmos.Table.StorageException; 7 | 8 | internal static class StorageExceptionExtensions 9 | { 10 | public static bool IsAlreadyExistsException(this StorageException e) 11 | { 12 | return e?.RequestInformation?.HttpStatusCode == (int?)HttpStatusCode.Conflict; 13 | } 14 | 15 | public static bool IsNotFoundException(this TableStorageException e) 16 | { 17 | return e?.RequestInformation?.HttpStatusCode == (int?)HttpStatusCode.NotFound; 18 | } 19 | 20 | public static bool IsAlreadyExistsException(this TableStorageException e) 21 | { 22 | return e?.RequestInformation?.HttpStatusCode == (int?)HttpStatusCode.Conflict; 23 | } 24 | 25 | public static bool IsPreconditionFailedException(this TableStorageException e) 26 | { 27 | return e?.RequestInformation?.HttpStatusCode == (int?)HttpStatusCode.PreconditionFailed; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Azure/Search/AzureSearchIndexer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Core; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace BaGet.Azure 8 | { 9 | public class AzureSearchIndexer : ISearchIndexer 10 | { 11 | private readonly IPackageDatabase _packages; 12 | private readonly IndexActionBuilder _actionBuilder; 13 | private readonly AzureSearchBatchIndexer _batchIndexer; 14 | private readonly ILogger _logger; 15 | 16 | public AzureSearchIndexer( 17 | IPackageDatabase packages, 18 | IndexActionBuilder actionBuilder, 19 | AzureSearchBatchIndexer batchIndexer, 20 | ILogger logger) 21 | { 22 | _packages = packages ?? throw new ArgumentNullException(nameof(packages)); 23 | _actionBuilder = actionBuilder ?? throw new ArgumentNullException(nameof(actionBuilder)); 24 | _batchIndexer = batchIndexer ?? throw new ArgumentNullException(nameof(batchIndexer)); 25 | _logger = logger ?? throw new ArgumentNullException(nameof(logger)); 26 | } 27 | 28 | public async Task IndexAsync(Package package, CancellationToken cancellationToken) 29 | { 30 | var packages = await _packages.FindAsync(package.Id, includeUnlisted: false, cancellationToken); 31 | 32 | var actions = _actionBuilder.UpdatePackage( 33 | new PackageRegistration( 34 | package.Id, 35 | packages)); 36 | 37 | await _batchIndexer.IndexAsync(actions, cancellationToken); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/BaGet.Azure/Search/ExactMatchCustomAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.Azure.Search.Models; 3 | 4 | namespace BaGet.Azure 5 | { 6 | /// 7 | /// A custom analyzer for case insensitive exact match. 8 | /// 9 | public static class ExactMatchCustomAnalyzer 10 | { 11 | public const string Name = "baget-exact-match-analyzer"; 12 | 13 | public static CustomAnalyzer Instance = new CustomAnalyzer( 14 | Name, 15 | TokenizerName.Keyword, 16 | new List 17 | { 18 | TokenFilterName.Lowercase 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BaGet.Azure/Search/SearchFilters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace BaGet.Azure 4 | { 5 | // Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/d3e6b7a3aa8ec9cb8b32bf860f2d4f0d6766ed92/src/NuGet.Services.AzureSearch/VersionList/SearchFilters.cs#L9 6 | [Flags] 7 | public enum SearchFilters 8 | { 9 | /// 10 | /// Exclude SemVer 2.0.0 and prerelease packages. 11 | /// 12 | Default = 0, 13 | 14 | /// 15 | /// Include packages that have prerelease versions. Note that a package's dependency version ranges do not 16 | /// affect the prerelease status of the package. This is in contrast of . 17 | /// 18 | IncludePrerelease = 1 << 0, 19 | 20 | /// 21 | /// Include SemVer 2.0.0 packages. Note that SemVer 2.0.0 dependency version ranges make a package into a SemVer 22 | /// 2.0.0 even if the package's own version string is SemVer 1.0.0. 23 | /// 24 | IncludeSemVer2 = 1 << 1, 25 | 26 | /// 27 | /// Include package that have prerelease versions and include SemVer 2.0.0 packages. 28 | /// 29 | IncludePrereleaseAndSemVer2 = IncludePrerelease | IncludeSemVer2, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BaGet.Core/Authentication/ApiKeyAuthenticationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace BaGet.Core 7 | { 8 | public class ApiKeyAuthenticationService : IAuthenticationService 9 | { 10 | private readonly string _apiKey; 11 | 12 | public ApiKeyAuthenticationService(IOptionsSnapshot options) 13 | { 14 | if (options == null) throw new ArgumentNullException(nameof(options)); 15 | 16 | _apiKey = string.IsNullOrEmpty(options.Value.ApiKey) ? null : options.Value.ApiKey; 17 | } 18 | 19 | public Task AuthenticateAsync(string apiKey, CancellationToken cancellationToken) 20 | => Task.FromResult(Authenticate(apiKey)); 21 | 22 | private bool Authenticate(string apiKey) 23 | { 24 | // No authentication is necessary if there is no required API key. 25 | if (_apiKey == null) return true; 26 | 27 | return _apiKey == apiKey; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Core/Authentication/IAuthenticationService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace BaGet.Core 5 | { 6 | public interface IAuthenticationService 7 | { 8 | Task AuthenticateAsync(string apiKey, CancellationToken cancellationToken); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/BaGet.Core/BaGet.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet 7 | The core libraries that power BaGet. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/BaGet.Core/BaGetApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace BaGet.Core 5 | { 6 | public class BaGetApplication 7 | { 8 | public BaGetApplication(IServiceCollection services) 9 | { 10 | Services = services ?? throw new ArgumentNullException(nameof(services)); 11 | } 12 | 13 | public IServiceCollection Services { get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/BindOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// Automatically binds configs to options. 9 | /// 10 | /// The options to bind to. 11 | public class BindOptions : IConfigureOptions where TOptions : class 12 | { 13 | private readonly IConfiguration _config; 14 | 15 | /// 16 | /// Automatically bind these configurations to the options. 17 | /// 18 | /// The configs to automatically bind to options. 19 | public BindOptions(IConfiguration config) 20 | { 21 | _config = config ?? throw new ArgumentNullException(nameof(config)); 22 | } 23 | 24 | public void Configure(TOptions options) => _config.Bind(options); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/DatabaseOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BaGet.Core 4 | { 5 | public class DatabaseOptions 6 | { 7 | public string Type { get; set; } 8 | 9 | [Required] 10 | public string ConnectionString { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/FileSystemStorageOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace BaGet.Core 7 | { 8 | public class FileSystemStorageOptions : IValidatableObject 9 | { 10 | /// 11 | /// The path at which content will be stored. Defaults to the same path 12 | /// as the main BaGet executable. This path will be created if it does not 13 | /// exist at startup. Packages will be stored in a subfolder named "packages". 14 | /// 15 | public string Path { get; set; } 16 | 17 | public IEnumerable Validate(ValidationContext validationContext) 18 | { 19 | // Convert an empty storage path to the current working directory. 20 | if (string.IsNullOrEmpty(Path)) 21 | { 22 | Path = Directory.GetCurrentDirectory(); 23 | } 24 | 25 | return Enumerable.Empty(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/MirrorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace BaGet.Core 6 | { 7 | public class MirrorOptions : IValidatableObject 8 | { 9 | /// 10 | /// If true, packages that aren't found locally will be indexed 11 | /// using the upstream source. 12 | /// 13 | public bool Enabled { get; set; } 14 | 15 | /// 16 | /// The v3 index that will be mirrored. 17 | /// 18 | public Uri PackageSource { get; set; } 19 | 20 | /// 21 | /// Whether or not the package source is a v2 package source feed. 22 | /// 23 | public bool Legacy { get; set; } 24 | 25 | /// 26 | /// The time before a download from the package source times out. 27 | /// 28 | [Range(0, int.MaxValue)] 29 | public int PackageDownloadTimeoutSeconds { get; set; } = 600; 30 | 31 | public IEnumerable Validate(ValidationContext validationContext) 32 | { 33 | if (Enabled && PackageSource == null) 34 | { 35 | yield return new ValidationResult( 36 | $"The {nameof(PackageSource)} configuration is required if mirroring is enabled", 37 | new[] { nameof(PackageSource) }); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/PackageDeletionBehavior.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | /// 4 | /// How BaGet should interpret package deletion requests. 5 | /// See: https://docs.microsoft.com/en-us/nuget/api/package-publish-resource#delete-a-package 6 | /// 7 | public enum PackageDeletionBehavior 8 | { 9 | /// 10 | /// Package "deletions" make the package undiscoverable. The package is still restorable 11 | /// by consumers that know its id and version. This is the recommended behavior as it prevents 12 | /// the "left pad" problem. 13 | /// 14 | Unlist, 15 | 16 | /// 17 | /// Removes the package from the database and storage. Existing consumers will no longer 18 | /// be able to restore the package. 19 | /// 20 | HardDelete, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/SearchOptions.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | public class SearchOptions 4 | { 5 | public string Type { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/BaGet.Core/Configuration/StorageOptions.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | public class StorageOptions 4 | { 5 | public string Type { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/Converters/StringArrayComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.EntityFrameworkCore.ChangeTracking; 4 | 5 | namespace BaGet.Core 6 | { 7 | public class StringArrayComparer : ValueComparer 8 | { 9 | public static readonly StringArrayComparer Instance = new StringArrayComparer(); 10 | 11 | public StringArrayComparer() 12 | : base( 13 | (c1, c2) => c1.SequenceEqual(c2), 14 | c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())), 15 | c => c.ToArray()) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/Converters/StringArrayToJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 2 | using Newtonsoft.Json; 3 | 4 | namespace BaGet.Core 5 | { 6 | public class StringArrayToJsonConverter : ValueConverter 7 | { 8 | public static readonly StringArrayToJsonConverter Instance = new StringArrayToJsonConverter(); 9 | 10 | public StringArrayToJsonConverter() 11 | : base( 12 | v => JsonConvert.SerializeObject(v), 13 | v => (!string.IsNullOrEmpty(v)) ? JsonConvert.DeserializeObject(v) : new string[0]) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/Converters/UriToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 3 | 4 | namespace BaGet.Core 5 | { 6 | public class UriToStringConverter : ValueConverter 7 | { 8 | public static readonly UriToStringConverter Instance = new UriToStringConverter(); 9 | 10 | public UriToStringConverter() 11 | : base( 12 | v => v.AbsoluteUri, 13 | v => new Uri(v)) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/IContext.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | 6 | namespace BaGet.Core 7 | { 8 | public interface IContext 9 | { 10 | DatabaseFacade Database { get; } 11 | 12 | DbSet Packages { get; set; } 13 | 14 | /// 15 | /// Check whether a is due to a SQL unique constraint violation. 16 | /// 17 | /// The exception to inspect. 18 | /// Whether the exception was caused to SQL unique constraint violation. 19 | bool IsUniqueConstraintViolationException(DbUpdateException exception); 20 | 21 | /// 22 | /// Whether this database engine supports LINQ "Take" in subqueries. 23 | /// 24 | bool SupportsLimitInSubqueries { get; } 25 | 26 | Task SaveChangesAsync(CancellationToken cancellationToken); 27 | 28 | /// 29 | /// Applies any pending migrations for the context to the database. 30 | /// Creates the database if it does not already exist. 31 | /// 32 | /// A token to cancel the task. 33 | /// A task that completes once migrations are applied. 34 | Task RunMigrationsAsync(CancellationToken cancellationToken); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/NullContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | 7 | namespace BaGet.Core 8 | { 9 | public class NullContext : IContext 10 | { 11 | public DatabaseFacade Database => throw new NotImplementedException(); 12 | 13 | public DbSet Packages { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 14 | 15 | public bool SupportsLimitInSubqueries => throw new NotImplementedException(); 16 | 17 | public bool IsUniqueConstraintViolationException(DbUpdateException exception) 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | 22 | public Task RunMigrationsAsync(CancellationToken cancellationToken) 23 | { 24 | return Task.CompletedTask; 25 | } 26 | 27 | public Task SaveChangesAsync(CancellationToken cancellationToken) 28 | { 29 | throw new NotImplementedException(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/PackageDependency.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | // See NuGetGallery.Core's: https://github.com/NuGet/NuGetGallery/blob/master/src/NuGetGallery.Core/Entities/PackageDependency.cs 4 | public class PackageDependency 5 | { 6 | public int Key { get; set; } 7 | 8 | /// 9 | /// The dependency's package ID. Null if this is a dependency group without any dependencies. 10 | /// 11 | public string Id { get; set; } 12 | 13 | /// 14 | /// The dependency's package version. Null if this is a dependency group without any dependencies. 15 | /// 16 | public string VersionRange { get; set; } 17 | 18 | public string TargetFramework { get; set; } 19 | 20 | public Package Package { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/PackageType.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | // See NuGetGallery.Core's: https://github.com/NuGet/NuGetGallery/blob/master/src/NuGetGallery.Core/Entities/PackageType.cs 4 | public class PackageType 5 | { 6 | public int Key { get; set; } 7 | 8 | public string Name { get; set; } 9 | public string Version { get; set; } 10 | 11 | public Package Package { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/SemVerLevel.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | public enum SemVerLevel 4 | { 5 | /// 6 | /// Either an invalid semantic version or a semantic version v1.0.0 7 | /// 8 | Unknown = 0, 9 | 10 | /// 11 | /// A valid semantic version v2.0.0 12 | /// 13 | SemVer2 = 2 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BaGet.Core/Entities/TargetFramework.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | public class TargetFramework 4 | { 5 | public int Key { get; set; } 6 | 7 | public string Moniker { get; set; } 8 | 9 | public Package Package { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BaGet.Core/Extensions/BaGetApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.DependencyInjection.Extensions; 5 | 6 | namespace BaGet 7 | { 8 | public static class BaGetApplicationExtensions 9 | { 10 | public static BaGetApplication AddFileStorage(this BaGetApplication app) 11 | { 12 | app.Services.TryAddTransient(provider => provider.GetRequiredService()); 13 | return app; 14 | } 15 | 16 | public static BaGetApplication AddFileStorage( 17 | this BaGetApplication app, 18 | Action configure) 19 | { 20 | app.AddFileStorage(); 21 | app.Services.Configure(configure); 22 | return app; 23 | } 24 | 25 | public static BaGetApplication AddNullStorage(this BaGetApplication app) 26 | { 27 | app.Services.TryAddTransient(provider => provider.GetRequiredService()); 28 | return app; 29 | } 30 | 31 | public static BaGetApplication AddNullSearch(this BaGetApplication app) 32 | { 33 | app.Services.TryAddTransient(provider => provider.GetRequiredService()); 34 | app.Services.TryAddTransient(provider => provider.GetRequiredService()); 35 | return app; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/BaGet.Core/Extensions/SystemTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace BaGet.Core 4 | { 5 | /// 6 | /// A wrapper that allows for unit tests related to system time. 7 | /// 8 | public class SystemTime 9 | { 10 | public virtual DateTime UtcNow => DateTime.UtcNow; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/BaGet.Core/Indexing/IFrameworkCompatibilityService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace BaGet.Core 4 | { 5 | /// 6 | /// Used to determine the compatibility matrix between frameworks. 7 | /// 8 | public interface IFrameworkCompatibilityService 9 | { 10 | /// 11 | /// Given a framework, find all other compatible frameworks. 12 | /// 13 | /// The input framework. 14 | /// The list of compatible frameworks. 15 | IReadOnlyList FindAllCompatibleFrameworks(string framework); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/BaGet.Core/Indexing/IPackageDeletionService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using NuGet.Versioning; 4 | 5 | namespace BaGet.Core 6 | { 7 | public interface IPackageDeletionService 8 | { 9 | /// 10 | /// Attempt to delete a package. 11 | /// 12 | /// The id of the package to delete. 13 | /// The version of the package to delete. 14 | /// 15 | /// False if the package does not exist. 16 | Task TryDeletePackageAsync(string id, NuGetVersion version, CancellationToken cancellationToken); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/BaGet.Core/Indexing/IPackageIndexingService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// The result of attempting to index a package. 9 | /// See . 10 | /// 11 | public enum PackageIndexingResult 12 | { 13 | /// 14 | /// The package is malformed. This may also happen if BaGet is in a corrupted state. 15 | /// 16 | InvalidPackage, 17 | 18 | /// 19 | /// The package has already been indexed. 20 | /// 21 | PackageAlreadyExists, 22 | 23 | /// 24 | /// The package has been indexed successfully. 25 | /// 26 | Success, 27 | } 28 | 29 | /// 30 | /// The service used to accept new packages. 31 | /// 32 | public interface IPackageIndexingService 33 | { 34 | /// 35 | /// Attempt to index a new package. 36 | /// 37 | /// The stream containing the package's content. 38 | /// 39 | /// The result of the attempted indexing operation. 40 | Task IndexAsync(Stream stream, CancellationToken cancellationToken); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/BaGet.Core/Indexing/ISymbolIndexingService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// The result of attempting to index a symbol package. 9 | /// See . 10 | /// 11 | public enum SymbolIndexingResult 12 | { 13 | /// 14 | /// The symbol package is malformed. 15 | /// 16 | InvalidSymbolPackage, 17 | 18 | /// 19 | /// A corresponding package with the provided ID and version does not exist. 20 | /// 21 | PackageNotFound, 22 | 23 | /// 24 | /// The symbol package has been indexed successfully. 25 | /// 26 | Success, 27 | } 28 | 29 | /// 30 | /// The service used to accept new symbol packages. 31 | /// 32 | public interface ISymbolIndexingService 33 | { 34 | /// 35 | /// Attempt to index a new symbol package. 36 | /// 37 | /// The stream containing the symbol package's content. 38 | /// 39 | /// The result of the attempted indexing operation. 40 | Task IndexAsync(Stream stream, CancellationToken cancellationToken); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/BaGetPackageMetadata.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | using BaGet.Protocol.Models; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// BaGet's extensions to the package metadata model. These additions 9 | /// are not part of the official protocol. 10 | /// 11 | public class BaGetPackageMetadata : PackageMetadata 12 | { 13 | [JsonPropertyName("downloads")] 14 | public long Downloads { get; set; } 15 | 16 | [JsonPropertyName("hasReadme")] 17 | public bool HasReadme { get; set; } 18 | 19 | [JsonPropertyName("packageTypes")] 20 | public IReadOnlyList PackageTypes { get; set; } 21 | 22 | /// 23 | /// The package's release notes. 24 | /// 25 | [JsonPropertyName("releaseNotes")] 26 | public string ReleaseNotes { get; set; } 27 | 28 | [JsonPropertyName("repositoryUrl")] 29 | public string RepositoryUrl { get; set; } 30 | 31 | [JsonPropertyName("repositoryType")] 32 | public string RepositoryType { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/BaGetRegistrationIndexPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | using BaGet.Protocol.Models; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// BaGet's extensions to a registration index page. 9 | /// Extends . 10 | /// 11 | /// 12 | /// TODO: After this project is updated to .NET 5, make 13 | /// extend and remove identical properties. 14 | /// Properties that are modified should be marked with the "new" modified. 15 | /// See: https://github.com/dotnet/runtime/pull/32107 16 | /// 17 | public class BaGetRegistrationIndexPage 18 | { 19 | #region Original properties from RegistrationIndexPage. 20 | [JsonPropertyName("@id")] 21 | public string RegistrationPageUrl { get; set; } 22 | 23 | [JsonPropertyName("count")] 24 | public int Count { get; set; } 25 | 26 | [JsonPropertyName("lower")] 27 | public string Lower { get; set; } 28 | 29 | [JsonPropertyName("upper")] 30 | public string Upper { get; set; } 31 | #endregion 32 | 33 | /// 34 | /// This was modified to use BaGet's extended registration index page item model. 35 | /// 36 | [JsonPropertyName("items")] 37 | public IReadOnlyList ItemsOrNull { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/BaGetRegistrationIndexPageItem.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | using BaGet.Protocol.Models; 3 | 4 | namespace BaGet.Core 5 | { 6 | /// 7 | /// BaGet's extensions to a registration index page. 8 | /// Extends . 9 | /// 10 | /// 11 | /// TODO: After this project is updated to .NET 5, make 12 | /// extend and remove identical properties. 13 | /// Properties that are modified should be marked with the "new" modified. 14 | /// See: https://github.com/dotnet/runtime/pull/32107 15 | /// 16 | public class BaGetRegistrationIndexPageItem 17 | { 18 | #region Original properties from RegistrationIndexPageItem. 19 | [JsonPropertyName("@id")] 20 | public string RegistrationLeafUrl { get; set; } 21 | 22 | [JsonPropertyName("packageContent")] 23 | public string PackageContentUrl { get; set; } 24 | #endregion 25 | 26 | /// 27 | /// The catalog entry containing the package metadata. 28 | /// This was modified to use BaGet's extended package metadata model. 29 | /// 30 | [JsonPropertyName("catalogEntry")] 31 | public BaGetPackageMetadata PackageMetadata { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/BaGetRegistrationIndexResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | using BaGet.Protocol.Models; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// BaGet's extensions to a registration index response. 9 | /// Extends . 10 | /// 11 | /// 12 | /// TODO: After this project is updated to .NET 5, make 13 | /// extend and remove identical properties. 14 | /// Properties that are modified should be marked with the "new" modified. 15 | /// See: https://github.com/dotnet/runtime/pull/32107 16 | /// 17 | public class BaGetRegistrationIndexResponse 18 | { 19 | #region Original properties from RegistrationIndexResponse. 20 | [JsonPropertyName("@id")] 21 | public string RegistrationIndexUrl { get; set; } 22 | 23 | [JsonPropertyName("@type")] 24 | public IReadOnlyList Type { get; set; } 25 | 26 | [JsonPropertyName("count")] 27 | public int Count { get; set; } 28 | #endregion 29 | 30 | /// 31 | /// The pages that contain all of the versions of the package, ordered 32 | /// by the package's version. This was modified to use BaGet's extended 33 | /// registration index page model. 34 | /// 35 | [JsonPropertyName("items")] 36 | public IReadOnlyList Pages { get; set; } 37 | 38 | /// 39 | /// The package's total downloads across all versions. 40 | /// This is not part of the official NuGet protocol. 41 | /// 42 | [JsonPropertyName("totalDownloads")] 43 | public long TotalDownloads { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/DefaultPackageMetadataService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using BaGet.Protocol.Models; 6 | using NuGet.Versioning; 7 | 8 | namespace BaGet.Core 9 | { 10 | /// 11 | public class DefaultPackageMetadataService : IPackageMetadataService 12 | { 13 | private readonly IPackageService _packages; 14 | private readonly RegistrationBuilder _builder; 15 | 16 | public DefaultPackageMetadataService( 17 | IPackageService packages, 18 | RegistrationBuilder builder) 19 | { 20 | _packages = packages ?? throw new ArgumentNullException(nameof(packages)); 21 | _builder = builder ?? throw new ArgumentNullException(nameof(builder)); 22 | } 23 | 24 | public async Task GetRegistrationIndexOrNullAsync( 25 | string packageId, 26 | CancellationToken cancellationToken = default) 27 | { 28 | var packages = await _packages.FindPackagesAsync(packageId, cancellationToken); 29 | if (!packages.Any()) 30 | { 31 | return null; 32 | } 33 | 34 | return _builder.BuildIndex( 35 | new PackageRegistration( 36 | packageId, 37 | packages)); 38 | } 39 | 40 | public async Task GetRegistrationLeafOrNullAsync( 41 | string id, 42 | NuGetVersion version, 43 | CancellationToken cancellationToken = default) 44 | { 45 | var package = await _packages.FindPackageOrNullAsync(id, version, cancellationToken); 46 | if (package == null) 47 | { 48 | return null; 49 | } 50 | 51 | return _builder.BuildLeaf(package); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/IPackageMetadataService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using BaGet.Protocol.Models; 4 | using NuGet.Versioning; 5 | 6 | namespace BaGet.Core 7 | { 8 | /// 9 | /// The Package Metadata client, used to fetch packages' metadata. 10 | /// 11 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource 12 | /// 13 | public interface IPackageMetadataService 14 | { 15 | /// 16 | /// Attempt to get a package's registration index, if it exists. 17 | /// See: https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-page 18 | /// 19 | /// The package's ID. 20 | /// A token to cancel the task. 21 | /// The package's registration index, or null if the package does not exist 22 | Task GetRegistrationIndexOrNullAsync(string packageId, CancellationToken cancellationToken = default); 23 | 24 | /// 25 | /// Get the metadata for a single package version, if the package exists. 26 | /// 27 | /// The package's id. 28 | /// The package's version. 29 | /// A token to cancel the task. 30 | /// The registration leaf, or null if the package does not exist. 31 | Task GetRegistrationLeafOrNullAsync( 32 | string packageId, 33 | NuGetVersion packageVersion, 34 | CancellationToken cancellationToken = default); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BaGet.Core/Metadata/PackageRegistration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace BaGet.Core 5 | { 6 | /// 7 | /// The information on all versions of a package. 8 | /// 9 | public class PackageRegistration 10 | { 11 | /// 12 | /// Create a new registration object. 13 | /// 14 | /// 15 | /// All versions of the package. 16 | public PackageRegistration( 17 | string packageId, 18 | IReadOnlyList packages) 19 | { 20 | PackageId = packageId ?? throw new ArgumentNullException(nameof(packageId)); 21 | Packages = packages ?? throw new ArgumentNullException(nameof(packages)); 22 | } 23 | 24 | /// 25 | /// The package's ID. 26 | /// 27 | public string PackageId { get; } 28 | 29 | /// 30 | /// The information for each version of the package. 31 | /// 32 | public IReadOnlyList Packages { get; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/AutocompleteRequest.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | /// 4 | /// The NuGet V3 search request. 5 | /// See: https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#request-parameters 6 | /// 7 | public class AutocompleteRequest 8 | { 9 | /// 10 | /// The number of results to skip, for pagination. 11 | /// 12 | public int Skip { get; set; } 13 | 14 | /// 15 | /// The number of results to return, for pagination. 16 | /// 17 | public int Take { get; set; } 18 | 19 | /// 20 | /// Whether to include pre-release packages. 21 | /// 22 | public bool IncludePrerelease { get; set; } 23 | 24 | /// 25 | /// Whether to include SemVer 2.0.0 compatible packages. 26 | /// 27 | public bool IncludeSemVer2 { get; set; } 28 | 29 | /// 30 | /// Filter results to a package type. If null, no filter is applied. 31 | /// 32 | public string PackageType { get; set; } 33 | 34 | /// 35 | /// The search query. 36 | /// 37 | public string Query { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/DependentsResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Core 5 | { 6 | /// 7 | /// The package ids that depend on the queried package. 8 | /// This is an unofficial API that isn't part of the NuGet protocol. 9 | /// 10 | public class DependentsResponse 11 | { 12 | /// 13 | /// The total number of matches, disregarding skip and take. 14 | /// 15 | [JsonPropertyName("totalHits")] 16 | public long TotalHits { get; set; } 17 | 18 | /// 19 | /// The package IDs matched by the dependent query. 20 | /// 21 | [JsonPropertyName("data")] 22 | public IReadOnlyList Data { get; set; } 23 | } 24 | 25 | /// 26 | /// A package that depends on the queried package. 27 | /// 28 | public class PackageDependent 29 | { 30 | /// 31 | /// The dependent package id. 32 | /// 33 | [JsonPropertyName("id")] 34 | public string Id { get; set; } 35 | 36 | /// 37 | /// The description of the dependent package. 38 | /// 39 | [JsonPropertyName("description")] 40 | public string Description { get; set; } 41 | 42 | /// 43 | /// The total downloads for the dependent package. 44 | /// 45 | [JsonPropertyName("totalDownloads")] 46 | public long TotalDownloads { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/ISearchIndexer.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace BaGet.Core 5 | { 6 | public interface ISearchIndexer 7 | { 8 | /// 9 | /// Add a package to the search index. 10 | /// 11 | /// The package to add. 12 | /// A token to cancel the task. 13 | /// A task that completes once the package has been added. 14 | Task IndexAsync(Package package, CancellationToken cancellationToken); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/ISearchResponseBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using BaGet.Protocol.Models; 3 | 4 | namespace BaGet.Core 5 | { 6 | public interface ISearchResponseBuilder 7 | { 8 | SearchResponse BuildSearch(IReadOnlyList results); 9 | AutocompleteResponse BuildAutocomplete(IReadOnlyList data); 10 | DependentsResponse BuildDependents(IReadOnlyList results); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/NullSearchIndexer.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace BaGet.Core 5 | { 6 | /// 7 | /// A no-op indexer, used when search does not need to index packages. 8 | /// 9 | public class NullSearchIndexer : ISearchIndexer 10 | { 11 | public Task IndexAsync(Package package, CancellationToken cancellationToken = default) 12 | { 13 | return Task.CompletedTask; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/SearchRequest.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | /// 4 | /// The NuGet V3 search request. 5 | /// See: https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#request-parameters 6 | /// 7 | public class SearchRequest 8 | { 9 | /// 10 | /// The number of results to skip, for pagination. 11 | /// 12 | public int Skip { get; set; } 13 | 14 | /// 15 | /// The number of results to return, for pagination. 16 | /// 17 | public int Take { get; set; } 18 | 19 | /// 20 | /// Whether to include pre-release packages. 21 | /// 22 | public bool IncludePrerelease { get; set; } 23 | 24 | /// 25 | /// Whether to include SemVer 2.0.0 compatible packages. 26 | /// 27 | public bool IncludeSemVer2 { get; set; } 28 | 29 | /// 30 | /// Filter results to a package type. If null, no filter is applied. 31 | /// 32 | public string PackageType { get; set; } 33 | 34 | /// 35 | /// Filters results to a target framework. If null, no filter is applied. 36 | /// 37 | public string Framework { get; set; } 38 | 39 | /// 40 | /// The search query. 41 | /// 42 | public string Query { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/BaGet.Core/Search/VersionsRequest.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Core 2 | { 3 | /// 4 | /// The NuGet V3 enumerate package versions request. 5 | /// See: https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#request-parameters-1 6 | /// 7 | public class VersionsRequest 8 | { 9 | /// 10 | /// Whether to include pre-release packages. 11 | /// 12 | public bool IncludePrerelease { get; set; } 13 | 14 | /// 15 | /// Whether to include SemVer 2.0.0 compatible packages. 16 | /// 17 | public bool IncludeSemVer2 { get; set; } 18 | 19 | /// 20 | /// The package ID whose versions should be fetched. 21 | /// 22 | public string PackageId { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/BaGet.Core/ServiceIndex/IServiceIndexService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using BaGet.Protocol.Models; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// The NuGet Service Index service, used to discover other resources. 9 | /// 10 | /// See https://docs.microsoft.com/en-us/nuget/api/service-index 11 | /// 12 | public interface IServiceIndexService 13 | { 14 | /// 15 | /// Get the resources available on this package feed. 16 | /// See: https://docs.microsoft.com/en-us/nuget/api/service-index#resources 17 | /// 18 | /// The resources available on this package feed. 19 | Task GetAsync(CancellationToken cancellationToken = default); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BaGet.Core/Storage/ISymbolStorageService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace BaGet.Core 6 | { 7 | /// 8 | /// Stores the content of symbols, also known as PDBs. 9 | /// 10 | public interface ISymbolStorageService 11 | { 12 | /// 13 | /// Persist a portable PDB's content to storage. This operation MUST fail if a PDB 14 | /// with the same key but different content has already been stored. 15 | /// 16 | /// The portable PDB's file name. 17 | /// The portable PDB's Signature GUID followed by its age. 18 | /// The PDB's content stream. 19 | /// 20 | /// 21 | Task SavePortablePdbContentAsync( 22 | string file, 23 | string key, 24 | Stream pdbStream, 25 | CancellationToken cancellationToken); 26 | 27 | /// 28 | /// Retrieve a portable PDB's content stream. 29 | /// 30 | /// The portable PDB's file name. 31 | /// The portable PDB's Signature GUID followed by its age. 32 | /// The portable PDB's stream, or null if it does not exist. 33 | Task GetPortablePdbContentStreamOrNullAsync(string file, string key); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Core/Storage/NullStorageService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace BaGet.Core 7 | { 8 | /// 9 | /// A minimal storage implementation, used for advanced scenarios. 10 | /// 11 | public class NullStorageService : IStorageService 12 | { 13 | public Task DeleteAsync(string path, CancellationToken cancellationToken = default) 14 | { 15 | return Task.CompletedTask; 16 | } 17 | 18 | public Task GetAsync(string path, CancellationToken cancellationToken = default) 19 | { 20 | return Task.FromResult(null); 21 | } 22 | 23 | public Task GetDownloadUriAsync(string path, CancellationToken cancellationToken = default) 24 | { 25 | return Task.FromResult(null); 26 | } 27 | 28 | public Task PutAsync( 29 | string path, 30 | Stream content, 31 | string contentType, 32 | CancellationToken cancellationToken = default) 33 | { 34 | return Task.FromResult(StoragePutResult.Success); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/BaGet.Core/Upstream/Clients/DisabledUpstreamClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using NuGet.Versioning; 6 | 7 | namespace BaGet.Core 8 | { 9 | /// 10 | /// The client used when there are no upstream package sources. 11 | /// 12 | public class DisabledUpstreamClient : IUpstreamClient 13 | { 14 | private readonly IReadOnlyList _emptyVersionList = new List(); 15 | private readonly IReadOnlyList _emptyPackageList = new List(); 16 | 17 | public Task> ListPackageVersionsAsync(string id, CancellationToken cancellationToken) 18 | { 19 | return Task.FromResult(_emptyVersionList); 20 | } 21 | 22 | public Task> ListPackagesAsync(string id, CancellationToken cancellationToken) 23 | { 24 | return Task.FromResult(_emptyPackageList); 25 | } 26 | 27 | public Task DownloadPackageOrNullAsync( 28 | string id, 29 | NuGetVersion version, 30 | CancellationToken cancellationToken) 31 | { 32 | return Task.FromResult(null); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Core/Upstream/IPackageDownloadsSource.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace BaGet.Core 5 | { 6 | public interface IPackageDownloadsSource 7 | { 8 | Task>> GetPackageDownloadsAsync(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/BaGet.Core/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet.Core 2 | 3 | Contains BaGet's core logic. The important folders are: 4 | 5 | * Indexing - Logic to upload packages and symbols 6 | * Metadata - Used to track packages' metadata, usually in a database 7 | * Storage - Stores the content of packages and symbols 8 | * Search - Used to search for packages 9 | * Mirror - Interactions with an upstream NuGet feed 10 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/BaGet.Database.MySql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet 7 | The libraries to host BaGet on MySQL. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/Migrations/20190914215810_AddOriginalVersionStringColumn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace BaGet.Database.MySql.Migrations 5 | { 6 | public partial class AddOriginalVersionStringColumn : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.AlterColumn( 11 | name: "RowVersion", 12 | table: "Packages", 13 | rowVersion: true, 14 | nullable: true, 15 | oldClrType: typeof(DateTime), 16 | oldNullable: true); 17 | 18 | migrationBuilder.AddColumn( 19 | name: "OriginalVersion", 20 | table: "Packages", 21 | maxLength: 64, 22 | nullable: true); 23 | } 24 | 25 | protected override void Down(MigrationBuilder migrationBuilder) 26 | { 27 | migrationBuilder.DropColumn( 28 | name: "OriginalVersion", 29 | table: "Packages"); 30 | 31 | migrationBuilder.AlterColumn( 32 | name: "RowVersion", 33 | table: "Packages", 34 | nullable: true, 35 | oldClrType: typeof(DateTime), 36 | oldRowVersion: true, 37 | oldNullable: true); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/Migrations/20200109085155_AddReleaseNotesStringColumn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace BaGet.Database.MySql.Migrations 5 | { 6 | public partial class AddReleaseNotesStringColumn : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.AlterColumn( 11 | name: "RowVersion", 12 | table: "Packages", 13 | rowVersion: true, 14 | nullable: true, 15 | oldClrType: typeof(DateTime), 16 | oldNullable: true); 17 | 18 | migrationBuilder.AddColumn( 19 | name: "ReleaseNotes", 20 | table: "Packages", 21 | maxLength: 4000, 22 | nullable: true); 23 | } 24 | 25 | protected override void Down(MigrationBuilder migrationBuilder) 26 | { 27 | migrationBuilder.DropColumn( 28 | name: "ReleaseNotes", 29 | table: "Packages"); 30 | 31 | migrationBuilder.AlterColumn( 32 | name: "RowVersion", 33 | table: "Packages", 34 | nullable: true, 35 | oldClrType: typeof(DateTime), 36 | oldRowVersion: true, 37 | oldNullable: true); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/Migrations/20200210004047_AddHasEmbeddedIconColumn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Metadata; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace BaGet.Database.MySql.Migrations 6 | { 7 | public partial class AddHasEmbeddedIconColumn : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AlterColumn( 12 | name: "RowVersion", 13 | table: "Packages", 14 | rowVersion: true, 15 | nullable: true, 16 | oldClrType: typeof(DateTime), 17 | oldNullable: true) 18 | .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn); 19 | 20 | migrationBuilder.AddColumn( 21 | name: "HasEmbeddedIcon", 22 | table: "Packages", 23 | nullable: false, 24 | defaultValue: false); 25 | } 26 | 27 | protected override void Down(MigrationBuilder migrationBuilder) 28 | { 29 | migrationBuilder.DropColumn( 30 | name: "HasEmbeddedIcon", 31 | table: "Packages"); 32 | 33 | migrationBuilder.AlterColumn( 34 | name: "RowVersion", 35 | table: "Packages", 36 | nullable: true, 37 | oldClrType: typeof(DateTime), 38 | oldRowVersion: true, 39 | oldNullable: true) 40 | .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/Migrations/20210919191554_RemoveReleaseNotesMaxLength.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Metadata; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace BaGet.Database.MySql.Migrations 6 | { 7 | public partial class RemoveReleaseNotesMaxLength : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AlterColumn( 12 | name: "RowVersion", 13 | table: "Packages", 14 | rowVersion: true, 15 | nullable: true, 16 | oldClrType: typeof(DateTime), 17 | oldType: "timestamp(6)", 18 | oldNullable: true) 19 | .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn); 20 | } 21 | 22 | protected override void Down(MigrationBuilder migrationBuilder) 23 | { 24 | migrationBuilder.AlterColumn( 25 | name: "RowVersion", 26 | table: "Packages", 27 | type: "timestamp(6)", 28 | nullable: true, 29 | oldClrType: typeof(DateTime), 30 | oldRowVersion: true, 31 | oldNullable: true) 32 | .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/MySqlApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using BaGet.Database.MySql; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace BaGet 9 | { 10 | public static class MySqlApplicationExtensions 11 | { 12 | public static BaGetApplication AddMySqlDatabase(this BaGetApplication app) 13 | { 14 | app.Services.AddBaGetDbContextProvider("MySql", (provider, options) => 15 | { 16 | var databaseOptions = provider.GetRequiredService>(); 17 | 18 | options.UseMySql(databaseOptions.Value.ConnectionString); 19 | }); 20 | 21 | return app; 22 | } 23 | 24 | public static BaGetApplication AddMySqlDatabase( 25 | this BaGetApplication app, 26 | Action configure) 27 | { 28 | app.AddMySqlDatabase(); 29 | app.Services.Configure(configure); 30 | return app; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/MySqlContext.cs: -------------------------------------------------------------------------------- 1 | using BaGet.Core; 2 | using Microsoft.EntityFrameworkCore; 3 | using MySql.Data.MySqlClient; 4 | 5 | namespace BaGet.Database.MySql 6 | { 7 | public class MySqlContext : AbstractContext 8 | { 9 | /// 10 | /// The MySQL Server error code for when a unique constraint is violated. 11 | /// 12 | private const int UniqueConstraintViolationErrorCode = 1062; 13 | 14 | public MySqlContext(DbContextOptions options) : base(options) 15 | { 16 | } 17 | 18 | public override bool IsUniqueConstraintViolationException(DbUpdateException exception) 19 | { 20 | return exception.InnerException is MySqlException mysqlException && 21 | mysqlException.Number == UniqueConstraintViolationErrorCode; 22 | } 23 | 24 | /// 25 | /// MySQL does not support LIMIT clauses in subqueries for certain subquery operators. 26 | /// See: https://dev.mysql.com/doc/refman/8.0/en/subquery-restrictions.html 27 | /// 28 | public override bool SupportsLimitInSubqueries => false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Database.MySql/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet's MySQL Database Provider 2 | 3 | This project contains BaGet's MySQL database provider. 4 | 5 | ## Migrations 6 | 7 | Add a migration with: 8 | 9 | ``` 10 | dotnet ef migrations add MigrationName --context MySqlContext --output-dir Migrations --startup-project ..\BaGet\BaGet.csproj 11 | 12 | dotnet ef database update --context MySqlContext 13 | ``` 14 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/BaGet.Database.PostgreSql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet 7 | The libraries to host BaGet on PostgreSQL. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/Migrations/20190914220105_AddOriginalVersionStringColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.PostgreSql.Migrations 4 | { 5 | public partial class AddOriginalVersionStringColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "OriginalVersion", 11 | table: "Packages", 12 | maxLength: 64, 13 | nullable: true); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "OriginalVersion", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/Migrations/20200109085355_AddReleaseNotesStringColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.PostgreSql.Migrations 4 | { 5 | public partial class AddReleaseNotesStringColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "ReleaseNotes", 11 | table: "Packages", 12 | maxLength: 4000, 13 | nullable: true); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "ReleaseNotes", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/Migrations/20200210004256_AddHasEmbeddedIconColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.PostgreSql.Migrations 4 | { 5 | public partial class AddHasEmbeddedIconColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "HasEmbeddedIcon", 11 | table: "Packages", 12 | nullable: false, 13 | defaultValue: false); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "HasEmbeddedIcon", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/Migrations/20210919191649_RemoveReleaseNotesMaxLength.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.PostgreSql.Migrations 4 | { 5 | public partial class RemoveReleaseNotesMaxLength : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AlterColumn( 10 | name: "ReleaseNotes", 11 | table: "Packages", 12 | nullable: true, 13 | oldClrType: typeof(string), 14 | oldType: "character varying(4000)", 15 | oldMaxLength: 4000, 16 | oldNullable: true); 17 | } 18 | 19 | protected override void Down(MigrationBuilder migrationBuilder) 20 | { 21 | migrationBuilder.AlterColumn( 22 | name: "ReleaseNotes", 23 | table: "Packages", 24 | type: "character varying(4000)", 25 | maxLength: 4000, 26 | nullable: true, 27 | oldClrType: typeof(string), 28 | oldNullable: true); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/PostgreSqlApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using BaGet.Database.PostgreSql; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace BaGet 9 | { 10 | public static class PostgreSqlApplicationExtensions 11 | { 12 | public static BaGetApplication AddPostgreSqlDatabase(this BaGetApplication app) 13 | { 14 | app.Services.AddBaGetDbContextProvider("PostgreSql", (provider, options) => 15 | { 16 | var databaseOptions = provider.GetRequiredService>(); 17 | 18 | options.UseNpgsql(databaseOptions.Value.ConnectionString); 19 | }); 20 | 21 | return app; 22 | } 23 | 24 | public static BaGetApplication AddPostgreSqlDatabase( 25 | this BaGetApplication app, 26 | Action configure) 27 | { 28 | app.AddPostgreSqlDatabase(); 29 | app.Services.Configure(configure); 30 | return app; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Database.PostgreSql/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet's PostgreSql Database Provider 2 | 3 | This project contains BaGet's PostgreSql database provider. 4 | 5 | ## Migrations 6 | 7 | Add a migration with: 8 | 9 | ``` 10 | dotnet ef migrations add MigrationName --context PostgreSqlContext --output-dir Migrations --startup-project ..\BaGet\BaGet.csproj 11 | 12 | dotnet ef database update --context PostgreSqlContext 13 | ``` 14 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/BaGet.Database.SqlServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet 7 | The libraries to host BaGet on SQL Server. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/Migrations/20190914215959_AddOriginalVersionStringColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.SqlServer.Migrations 4 | { 5 | public partial class AddOriginalVersionStringColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "OriginalVersion", 11 | table: "Packages", 12 | maxLength: 64, 13 | nullable: true); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "OriginalVersion", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/Migrations/20200109085508_AddReleaseNotesStringColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.SqlServer.Migrations 4 | { 5 | public partial class AddReleaseNotesStringColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "ReleaseNotes", 11 | table: "Packages", 12 | maxLength: 4000, 13 | nullable: true); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "ReleaseNotes", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/Migrations/20200210004408_AddHasEmbeddedIconColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.SqlServer.Migrations 4 | { 5 | public partial class AddHasEmbeddedIconColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "HasEmbeddedIcon", 11 | table: "Packages", 12 | nullable: false, 13 | defaultValue: false); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "HasEmbeddedIcon", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/Migrations/20210919191928_RemoveReleaseNotesMaxLength.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.SqlServer.Migrations 4 | { 5 | public partial class RemoveReleaseNotesMaxLength : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AlterColumn( 10 | name: "ReleaseNotes", 11 | table: "Packages", 12 | nullable: true, 13 | oldClrType: typeof(string), 14 | oldType: "nvarchar(4000)", 15 | oldMaxLength: 4000, 16 | oldNullable: true); 17 | } 18 | 19 | protected override void Down(MigrationBuilder migrationBuilder) 20 | { 21 | migrationBuilder.AlterColumn( 22 | name: "ReleaseNotes", 23 | table: "Packages", 24 | type: "nvarchar(4000)", 25 | maxLength: 4000, 26 | nullable: true, 27 | oldClrType: typeof(string), 28 | oldNullable: true); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/SqlServerApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using BaGet.Database.SqlServer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace BaGet 9 | { 10 | public static class SqlServerApplicationExtensions 11 | { 12 | public static BaGetApplication AddSqlServerDatabase(this BaGetApplication app) 13 | { 14 | app.Services.AddBaGetDbContextProvider("SqlServer", (provider, options) => 15 | { 16 | var databaseOptions = provider.GetRequiredService>(); 17 | 18 | options.UseSqlServer(databaseOptions.Value.ConnectionString); 19 | }); 20 | 21 | return app; 22 | } 23 | 24 | public static BaGetApplication AddSqlServerDatabase( 25 | this BaGetApplication app, 26 | Action configure) 27 | { 28 | app.AddSqlServerDatabase(); 29 | app.Services.Configure(configure); 30 | return app; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/SqlServerContext.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using BaGet.Core; 3 | using Microsoft.Data.SqlClient; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace BaGet.Database.SqlServer 7 | { 8 | public class SqlServerContext : AbstractContext 9 | { 10 | /// 11 | /// The SQL Server error code for when a unique contraint is violated. 12 | /// 13 | private const int UniqueConstraintViolationErrorCode = 2627; 14 | 15 | public SqlServerContext(DbContextOptions options) 16 | : base(options) 17 | { } 18 | 19 | /// 20 | /// Check whether a is due to a SQL unique constraint violation. 21 | /// 22 | /// The exception to inspect. 23 | /// Whether the exception was caused to SQL unique constraint violation. 24 | public override bool IsUniqueConstraintViolationException(DbUpdateException exception) 25 | { 26 | if (exception.GetBaseException() is SqlException sqlException) 27 | { 28 | return sqlException.Errors 29 | .OfType() 30 | .Any(error => error.Number == UniqueConstraintViolationErrorCode); 31 | } 32 | 33 | return false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BaGet.Database.SqlServer/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet's SQL Server Database Provider 2 | 3 | This project contains BaGet's Microsoft SQL Server database provider. 4 | 5 | ## Migrations 6 | 7 | Add a migration with: 8 | 9 | ``` 10 | dotnet ef migrations add MigrationName --context SqlServerContext --output-dir Migrations --startup-project ..\BaGet\BaGet.csproj 11 | 12 | dotnet ef database update --context SqlServerContext 13 | ``` 14 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/BaGet.Database.Sqlite.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet 7 | The libraries to host BaGet on SQLite. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/Migrations/20190914215110_AddOriginalVersionStringColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.Sqlite.Migrations 4 | { 5 | public partial class AddOriginalVersionStringColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "OriginalVersion", 11 | table: "Packages", 12 | maxLength: 64, 13 | nullable: true); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "OriginalVersion", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/Migrations/20200109071618_AddReleaseNotesStringColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.Sqlite.Migrations 4 | { 5 | public partial class AddReleaseNotesStringColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "ReleaseNotes", 11 | table: "Packages", 12 | maxLength: 4000, 13 | nullable: true); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "ReleaseNotes", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/Migrations/20200208044959_FixVersionCaseSensitivity.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.Sqlite.Migrations 4 | { 5 | public partial class FixVersionCaseSensitivity : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | // Disable this migration as SQLite does not support altering columns. 10 | // Customers will need to create a new database and reupload their packages. 11 | // See: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#migrations-limitations 12 | //migrationBuilder.AlterColumn( 13 | // name: "Version", 14 | // table: "Packages", 15 | // type: "TEXT COLLATE NOCASE", 16 | // maxLength: 64, 17 | // nullable: false, 18 | // oldClrType: typeof(string), 19 | // oldMaxLength: 64); 20 | } 21 | 22 | protected override void Down(MigrationBuilder migrationBuilder) 23 | { 24 | //migrationBuilder.AlterColumn( 25 | // name: "Version", 26 | // table: "Packages", 27 | // maxLength: 64, 28 | // nullable: false, 29 | // oldClrType: typeof(string), 30 | // oldType: "TEXT COLLATE NOCASE", 31 | // oldMaxLength: 64); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/Migrations/20200210004344_AddHasEmbeddedIconColumn.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.Sqlite.Migrations 4 | { 5 | public partial class AddHasEmbeddedIconColumn : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "HasEmbeddedIcon", 11 | table: "Packages", 12 | nullable: false, 13 | defaultValue: false); 14 | } 15 | 16 | protected override void Down(MigrationBuilder migrationBuilder) 17 | { 18 | migrationBuilder.DropColumn( 19 | name: "HasEmbeddedIcon", 20 | table: "Packages"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/Migrations/20210919190849_RemoveReleaseNotesMaxLength.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace BaGet.Database.Sqlite.Migrations 4 | { 5 | public partial class RemoveReleaseNotesMaxLength : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | 10 | } 11 | 12 | protected override void Down(MigrationBuilder migrationBuilder) 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/SqliteApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using BaGet.Database.Sqlite; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace BaGet 9 | { 10 | public static class SqliteApplicationExtensions 11 | { 12 | public static BaGetApplication AddSqliteDatabase(this BaGetApplication app) 13 | { 14 | app.Services.AddBaGetDbContextProvider("Sqlite", (provider, options) => 15 | { 16 | var databaseOptions = provider.GetRequiredService>(); 17 | 18 | options.UseSqlite(databaseOptions.Value.ConnectionString); 19 | }); 20 | 21 | return app; 22 | } 23 | 24 | public static BaGetApplication AddSqliteDatabase( 25 | this BaGetApplication app, 26 | Action configure) 27 | { 28 | app.AddSqliteDatabase(); 29 | app.Services.Configure(configure); 30 | return app; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/SqliteContext.cs: -------------------------------------------------------------------------------- 1 | using BaGet.Core; 2 | using Microsoft.Data.Sqlite; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace BaGet.Database.Sqlite 6 | { 7 | public class SqliteContext : AbstractContext 8 | { 9 | /// 10 | /// The Sqlite error code for when a unique constraint is violated. 11 | /// 12 | private const int SqliteUniqueConstraintViolationErrorCode = 19; 13 | 14 | public SqliteContext(DbContextOptions options) 15 | : base(options) 16 | { } 17 | 18 | public override bool IsUniqueConstraintViolationException(DbUpdateException exception) 19 | { 20 | return exception.InnerException is SqliteException sqliteException && 21 | sqliteException.SqliteErrorCode == SqliteUniqueConstraintViolationErrorCode; 22 | } 23 | 24 | protected override void OnModelCreating(ModelBuilder builder) 25 | { 26 | base.OnModelCreating(builder); 27 | 28 | builder.Entity() 29 | .Property(p => p.Id) 30 | .HasColumnType("TEXT COLLATE NOCASE"); 31 | 32 | builder.Entity() 33 | .Property(p => p.NormalizedVersionString) 34 | .HasColumnType("TEXT COLLATE NOCASE"); 35 | 36 | builder.Entity() 37 | .Property(d => d.Id) 38 | .HasColumnType("TEXT COLLATE NOCASE"); 39 | 40 | builder.Entity() 41 | .Property(t => t.Name) 42 | .HasColumnType("TEXT COLLATE NOCASE"); 43 | 44 | builder.Entity() 45 | .Property(f => f.Moniker) 46 | .HasColumnType("TEXT COLLATE NOCASE"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/BaGet.Database.Sqlite/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet's SQLite Database Provider 2 | 3 | This project contains BaGet's SQLite database provider. 4 | 5 | ## Migrations 6 | 7 | Add a migration with: 8 | 9 | ``` 10 | dotnet ef migrations add MigrationName --context SqliteContext --output-dir Migrations --startup-project ..\BaGet\BaGet.csproj 11 | 12 | dotnet ef database update --context SqliteContext 13 | ``` 14 | -------------------------------------------------------------------------------- /src/BaGet.Gcp/BaGet.Gcp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet;Google;Cloud 7 | The libraries to host BaGet on the Google Cloud Platform. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/BaGet.Gcp/GoogleCloudApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using BaGet.Gcp; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.DependencyInjection.Extensions; 6 | 7 | namespace BaGet 8 | { 9 | public static class GoogleCloudApplicationExtensions 10 | { 11 | public static BaGetApplication AddGoogleCloudStorage(this BaGetApplication app) 12 | { 13 | app.Services.AddBaGetOptions(nameof(BaGetOptions.Storage)); 14 | app.Services.AddTransient(); 15 | 16 | app.Services.TryAddTransient(provider => provider.GetRequiredService()); 17 | 18 | app.Services.AddProvider((provider, config) => 19 | { 20 | if (!config.HasStorageType("GoogleCloud")) return null; 21 | 22 | return provider.GetRequiredService(); 23 | }); 24 | 25 | return app; 26 | } 27 | 28 | public static BaGetApplication AddGoogleCloudStorage( 29 | this BaGetApplication app, 30 | Action configure) 31 | { 32 | app.AddGoogleCloudStorage(); 33 | app.Services.Configure(configure); 34 | return app; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/BaGet.Gcp/GoogleCloudStorageOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using BaGet.Core; 3 | 4 | namespace BaGet.Gcp 5 | { 6 | public class GoogleCloudStorageOptions : StorageOptions 7 | { 8 | [Required] 9 | public string BucketName { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/BaGet.Protocol.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | NuGet;Protocol 7 | Libraries to interact with NuGet server APIs. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Catalog/CatalogProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace BaGet.Protocol.Catalog 4 | { 5 | /// 6 | /// The options to configure . 7 | /// Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/3a468fe534a03dcced897eb5992209fdd3c4b6c9/src/NuGet.Protocol.Catalog/CatalogProcessorSettings.cs 8 | /// 9 | public class CatalogProcessorOptions 10 | { 11 | /// 12 | /// The minimum commit timestamp to use when no cursor value has been saved. 13 | /// 14 | public DateTimeOffset? DefaultMinCommitTimestamp { get; set; } 15 | 16 | /// 17 | /// The absolute minimum (exclusive) commit timestamp to process in the catalog. 18 | /// Use this to filter out catalog items that are "too old". 19 | /// Set this to to process all catalog items. 20 | /// 21 | public DateTimeOffset MinCommitTimestamp { get; set; } 22 | 23 | /// 24 | /// The absolute maximum (inclusive) commit timestamp to process in the catalog. 25 | /// Use this to filter out catalog items that are "too new". 26 | /// Set this to to process all catalog items. 27 | /// 28 | public DateTimeOffset MaxCommitTimestamp { get; set; } 29 | 30 | /// 31 | /// If multiple catalog leaves are found in a page concerning the same package ID and version, only the latest 32 | /// is processed. 33 | /// 34 | public bool ExcludeRedundantLeaves { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Catalog/ICursor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace BaGet.Protocol.Catalog 6 | { 7 | /// 8 | /// The NuGet Catalog resource is an append-only data structure indexed by time. 9 | /// The tracks up to what point in the catalog has been successfully 10 | /// processed. The value is a catalog commit timestamp. 11 | /// See: https://docs.microsoft.com/en-us/nuget/api/catalog-resource#cursor 12 | /// Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/3a468fe534a03dcced897eb5992209fdd3c4b6c9/src/NuGet.Protocol.Catalog/ICursor.cs 13 | /// 14 | public interface ICursor 15 | { 16 | /// 17 | /// Get the value of the cursor. 18 | /// 19 | /// A token to cancel the task. 20 | /// The cursor value. Null if the cursor has no value yet. 21 | Task GetAsync(CancellationToken cancellationToken = default); 22 | 23 | /// 24 | /// Set the value of the cursor. 25 | /// 26 | /// The new cursor value. 27 | /// A token to cancel the task. 28 | Task SetAsync(DateTimeOffset value, CancellationToken cancellationToken = default); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Catalog/NullCatalogClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using BaGet.Protocol.Models; 6 | 7 | namespace BaGet.Protocol.Internal 8 | { 9 | public class NullCatalogClient : ICatalogClient 10 | { 11 | public Task GetIndexAsync(CancellationToken cancellationToken = default) 12 | { 13 | return Task.FromResult(new CatalogIndex 14 | { 15 | CommitTimestamp = DateTimeOffset.MinValue, 16 | Count = 0, 17 | Items = new List() 18 | }); 19 | } 20 | 21 | public Task GetPageAsync(string pageUrl, CancellationToken cancellationToken = default) 22 | { 23 | throw new NotSupportedException($"{nameof(NullCatalogClient)} does not support loading catalog pages."); 24 | } 25 | 26 | public Task GetPackageDeleteLeafAsync(string leafUrl, CancellationToken cancellationToken = default) 27 | { 28 | throw new NotSupportedException($"{nameof(NullCatalogClient)} does not support loading catalog leaves."); 29 | } 30 | 31 | public Task GetPackageDetailsLeafAsync(string leafUrl, CancellationToken cancellationToken = default) 32 | { 33 | throw new NotSupportedException($"{nameof(NullCatalogClient)} does not support loading catalog leaves."); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Catalog/NullCursor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace BaGet.Protocol.Catalog 6 | { 7 | /// 8 | /// A cursor that does not persist any state. Use this with a 9 | /// to process all leafs each time 10 | /// is called. 11 | /// 12 | public class NullCursor : ICursor 13 | { 14 | public Task GetAsync(CancellationToken cancellationToken = default) 15 | { 16 | return Task.FromResult(null); 17 | } 18 | 19 | public Task SetAsync(DateTimeOffset value, CancellationToken cancellationToken = default) 20 | { 21 | return Task.CompletedTask; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Extensions/NuGetClientFactoryExtensions.cs: -------------------------------------------------------------------------------- 1 | using BaGet.Protocol.Catalog; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace BaGet.Protocol 5 | { 6 | public static class NuGetClientFactoryExtensions 7 | { 8 | /// 9 | /// Create a new to discover and download catalog leafs. 10 | /// Leafs are processed by the . 11 | /// 12 | /// The factory used to create NuGet clients. 13 | /// Cursor to track succesfully processed leafs. Leafs before the cursor are skipped. 14 | /// The leaf processor. 15 | /// The options to configure catalog processing. 16 | /// The logger used for telemetry. 17 | /// The catalog processor. 18 | public static CatalogProcessor CreateCatalogProcessor( 19 | this NuGetClientFactory clientFactory, 20 | ICursor cursor, 21 | ICatalogLeafProcessor leafProcessor, 22 | CatalogProcessorOptions options, 23 | ILogger logger) 24 | { 25 | var catalogClient = clientFactory.CreateCatalogClient(); 26 | 27 | return new CatalogProcessor( 28 | cursor, 29 | catalogClient, 30 | leafProcessor, 31 | options, 32 | logger); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Extensions/PackageContentModelExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using BaGet.Protocol.Models; 4 | using NuGet.Versioning; 5 | 6 | namespace BaGet.Protocol 7 | { 8 | /// 9 | /// These are documented interpretations of values returned by the Package Content resource. 10 | /// 11 | public static class PackageContentModelExtensions 12 | { 13 | /// 14 | /// Parse the package versions as s. 15 | /// 16 | /// The package versions response. 17 | /// The package versions. 18 | public static IReadOnlyList ParseVersions(this PackageVersionsResponse response) 19 | { 20 | return response 21 | .Versions 22 | .Select(NuGetVersion.Parse) 23 | .ToList(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Extensions/SearchModelExtensions.cs: -------------------------------------------------------------------------------- 1 | using BaGet.Protocol.Models; 2 | using NuGet.Versioning; 3 | 4 | namespace BaGet.Protocol 5 | { 6 | /// 7 | /// These are documented interpretations of values returned by the Search resource. 8 | /// 9 | public static class SearchModelExtensions 10 | { 11 | /// 12 | /// Parse the search result's version as a . 13 | /// 14 | /// The search result. 15 | /// The search result's version. 16 | public static NuGetVersion ParseVersion(this SearchResult result) 17 | { 18 | return NuGetVersion.Parse(result.Version); 19 | } 20 | 21 | /// 22 | /// Parse the search result's version as a . 23 | /// 24 | /// The search result. 25 | /// The search result's version. 26 | public static NuGetVersion ParseVersion(this SearchResultVersion result) 27 | { 28 | return NuGetVersion.Parse(result.Version); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/AlternatePackage.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | /// 6 | /// The alternate package that should be used instead of a deprecated package. 7 | /// 8 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation 9 | /// 10 | public class AlternatePackage 11 | { 12 | [JsonPropertyName("@id")] 13 | public string Url { get; set; } 14 | 15 | [JsonPropertyName("@type")] 16 | public string Type { get; set; } 17 | 18 | /// 19 | /// The ID of the alternate package. 20 | /// 21 | [JsonPropertyName("id")] 22 | public string Id { get; set; } 23 | 24 | /// 25 | /// The allowed version range, or * if any version is allowed. 26 | /// 27 | [JsonPropertyName("range")] 28 | public string Range { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/AutocompleteContext.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | public class AutocompleteContext 6 | { 7 | public static readonly AutocompleteContext Default = new AutocompleteContext 8 | { 9 | Vocab = "http://schema.nuget.org/schema#" 10 | }; 11 | 12 | [JsonPropertyName("@vocab")] 13 | public string Vocab { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/AutocompleteResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The package ids that matched the autocomplete query. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#search-for-package-ids 10 | /// 11 | public class AutocompleteResponse 12 | { 13 | [JsonPropertyName("@context")] 14 | public AutocompleteContext Context { get; set; } 15 | 16 | /// 17 | /// The total number of matches, disregarding skip and take. 18 | /// 19 | [JsonPropertyName("totalHits")] 20 | public long TotalHits { get; set; } 21 | 22 | /// 23 | /// The package IDs matched by the autocomplete query. 24 | /// 25 | [JsonPropertyName("data")] 26 | public IReadOnlyList Data { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/CatalogIndex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace BaGet.Protocol.Models 6 | { 7 | // This class is based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogIndex.cs 8 | 9 | /// 10 | /// The catalog index is the entry point for the catalog resource. 11 | /// Use this to discover catalog pages, which in turn can be used to discover catalog leafs. 12 | /// 13 | /// See https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-index 14 | /// 15 | public class CatalogIndex 16 | { 17 | /// 18 | /// A timestamp of the most recent commit. 19 | /// 20 | [JsonPropertyName("commitTimeStamp")] 21 | public DateTimeOffset CommitTimestamp { get; set; } 22 | 23 | /// 24 | /// The number of catalog pages in the catalog index. 25 | /// 26 | [JsonPropertyName("count")] 27 | public int Count { get; set; } 28 | 29 | /// 30 | /// The items used to discover s. 31 | /// 32 | [JsonPropertyName("items")] 33 | public List Items { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/CatalogLeafItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | // This class is based off https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogLeafItem.cs 7 | 8 | /// 9 | /// An item in a that references a . 10 | /// 11 | /// See https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-item-object-in-a-page 12 | /// 13 | public class CatalogLeafItem : ICatalogLeafItem 14 | { 15 | /// 16 | /// The URL to the current catalog leaf. 17 | /// 18 | [JsonPropertyName("@id")] 19 | public string CatalogLeafUrl { get; set; } 20 | 21 | /// 22 | /// The type of the current catalog leaf. 23 | /// 24 | [JsonPropertyName("@type")] 25 | public string Type { get; set; } 26 | 27 | /// 28 | /// The commit timestamp of this catalog item. 29 | /// 30 | [JsonPropertyName("commitTimeStamp")] 31 | public DateTimeOffset CommitTimestamp { get; set; } 32 | 33 | /// 34 | /// The package ID of the catalog item. 35 | /// 36 | [JsonPropertyName("nuget:id")] 37 | public string PackageId { get; set; } 38 | 39 | /// 40 | /// The package version of the catalog item. 41 | /// 42 | [JsonPropertyName("nuget:version")] 43 | public string PackageVersion { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/CatalogPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace BaGet.Protocol.Models 6 | { 7 | // This class is based off https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogPage.cs 8 | 9 | /// 10 | /// A catalog page, used to discover catalog leafs. 11 | /// Pages can be discovered from a . 12 | /// 13 | /// See https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-page 14 | /// 15 | public class CatalogPage 16 | { 17 | /// 18 | /// A unique ID associated with the most recent commit in this page. 19 | /// 20 | [JsonPropertyName("commitTimeStamp")] 21 | public DateTimeOffset CommitTimestamp { get; set; } 22 | 23 | /// 24 | /// The number of items in the page. 25 | /// 26 | [JsonPropertyName("count")] 27 | public int Count { get; set; } 28 | 29 | /// 30 | /// The items used to discover s. 31 | /// 32 | [JsonPropertyName("items")] 33 | public List Items { get; set; } 34 | 35 | /// 36 | /// The URL to the Catalog Index. 37 | /// 38 | [JsonPropertyName("parent")] 39 | public string CatalogIndexUrl { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/CatalogPageItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | // This class is based off https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogPageItem.cs 7 | 8 | /// 9 | /// An item in the that references a . 10 | /// 11 | /// See https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-page-object-in-the-index 12 | /// 13 | public class CatalogPageItem 14 | { 15 | /// 16 | /// The URL to this item's corresponding . 17 | /// 18 | [JsonPropertyName("@id")] 19 | public string CatalogPageUrl { get; set; } 20 | 21 | /// 22 | /// A timestamp of the most recent commit in this page. 23 | /// 24 | [JsonPropertyName("commitTimeStamp")] 25 | public DateTimeOffset CommitTimestamp { get; set; } 26 | 27 | /// 28 | /// The number of items in the page. 29 | /// 30 | [JsonPropertyName("count")] 31 | public int Count { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/DependencyGroupItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The dependencies of the package for a specific target framework. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-dependency-group 10 | /// 11 | public class DependencyGroupItem 12 | { 13 | /// 14 | /// The target framework that these dependencies are applicable to. 15 | /// 16 | [JsonPropertyName("targetFramework")] 17 | public string TargetFramework { get; set; } 18 | 19 | /// 20 | /// A list of dependencies. 21 | /// 22 | [JsonPropertyName("dependencies")] 23 | public List Dependencies { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/DependencyItem.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | using BaGet.Protocol.Internal; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// Represents a package dependency. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-dependency 10 | /// 11 | public class DependencyItem 12 | { 13 | /// 14 | /// The ID of the package dependency. 15 | /// 16 | [JsonPropertyName("id")] 17 | public string Id { get; set; } 18 | 19 | /// 20 | /// The allowed version range of the dependency. 21 | /// 22 | [JsonPropertyName("range")] 23 | [JsonConverter(typeof(PackageDependencyRangeJsonConverter))] 24 | public string Range { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/ICatalogLeafItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | // This class is based off https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/ICatalogLeafItem.cs 6 | 7 | /// 8 | /// A catalog leaf. Represents a single package event. 9 | /// Leafs can be discovered from a . 10 | /// 11 | /// See https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-leaf 12 | /// 13 | public interface ICatalogLeafItem 14 | { 15 | /// 16 | /// The commit timestamp of this catalog item. 17 | /// 18 | DateTimeOffset CommitTimestamp { get; } 19 | 20 | /// 21 | /// The package ID of the catalog item. 22 | /// 23 | string PackageId { get; } 24 | 25 | /// 26 | /// The package version of the catalog item. 27 | /// 28 | string PackageVersion { get; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/PackageDeleteCatalogLeaf.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Protocol.Models 2 | { 3 | // This class is based off https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/PackageDeleteCatalogLeaf.cs 4 | 5 | /// 6 | /// A "package delete" catalog leaf. Represents a single package deletion event. 7 | /// Leafs can be discovered from a . 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-leaf 10 | /// 11 | public class PackageDeleteCatalogLeaf : CatalogLeaf 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/PackageDeprecation.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// A package's metadata. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation 10 | /// 11 | public class PackageDeprecation 12 | { 13 | /// 14 | /// The URL to the document used to produce this object. 15 | /// 16 | [JsonPropertyName("@id")] 17 | public string CatalogLeafUrl { get; set; } 18 | 19 | /// 20 | /// The reasons why the package was deprecated. 21 | /// Deprecation reasons include: "Legacy", "CriticalBugs", and "Other". 22 | /// 23 | [JsonPropertyName("reasons")] 24 | public IReadOnlyList Reasons { get; set; } 25 | 26 | /// 27 | /// The additional details about this deprecation. 28 | /// 29 | [JsonPropertyName("message")] 30 | public string Message { get; set; } 31 | 32 | /// 33 | /// The alternate package that should be used instead. 34 | /// 35 | [JsonPropertyName("alternatePackage")] 36 | public AlternatePackage AlternatePackage { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/PackageNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NuGet.Versioning; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// An exception thrown when a package could not be found on the NuGet server. 8 | /// 9 | public class PackageNotFoundException : Exception 10 | { 11 | /// 12 | /// Create a new instance of the . 13 | /// 14 | /// The ID of the package that could not be found. 15 | /// The version of the package that could not be found. 16 | public PackageNotFoundException(string packageId, NuGetVersion packageVersion) 17 | : base($"Could not find package {packageId} {packageVersion}") 18 | { 19 | PackageId = packageId ?? throw new ArgumentNullException(nameof(packageId)); 20 | PackageVersion = packageVersion ?? throw new ArgumentNullException(nameof(packageVersion)); 21 | } 22 | 23 | /// 24 | /// The package ID that could not be found. 25 | /// 26 | public string PackageId { get; } 27 | 28 | /// 29 | /// The package version that could not be found. 30 | /// 31 | public NuGetVersion PackageVersion { get; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/PackageVersionsResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The full list of versions for a single package. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#enumerate-package-versions 10 | /// 11 | public class PackageVersionsResponse 12 | { 13 | /// 14 | /// The versions, lowercased and normalized. 15 | /// 16 | [JsonPropertyName("versions")] 17 | public IReadOnlyList Versions { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/RegistrationIndexPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The registration page object found in the registration index. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-page-object 10 | /// 11 | public class RegistrationIndexPage 12 | { 13 | /// 14 | /// The URL to the registration page. 15 | /// 16 | [JsonPropertyName("@id")] 17 | public string RegistrationPageUrl { get; set; } 18 | 19 | /// 20 | /// The number of registration leafs in the page. 21 | /// 22 | [JsonPropertyName("count")] 23 | public int Count { get; set; } 24 | 25 | /// 26 | /// if this package's registration is paged. The items can be found 27 | /// by following the page's . 28 | /// 29 | [JsonPropertyName("items")] 30 | public IReadOnlyList ItemsOrNull { get; set; } 31 | 32 | /// 33 | /// This page's lowest package version. The version should be lowercased, normalized, 34 | /// and the SemVer 2.0.0 build metadata removed, if any. 35 | /// 36 | [JsonPropertyName("lower")] 37 | public string Lower { get; set; } 38 | 39 | /// 40 | /// This page's highest package version. The version should be lowercased, normalized, 41 | /// and the SemVer 2.0.0 build metadata removed, if any. 42 | /// 43 | [JsonPropertyName("upper")] 44 | public string Upper { get; set; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/RegistrationIndexPageItem.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | /// 6 | /// An item in the that references a . 7 | /// 8 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-leaf-object-in-a-page 9 | /// 10 | public class RegistrationIndexPageItem 11 | { 12 | /// 13 | /// The URL to the registration leaf. 14 | /// 15 | [JsonPropertyName("@id")] 16 | public string RegistrationLeafUrl { get; set; } 17 | 18 | /// 19 | /// The catalog entry containing the package metadata. 20 | /// 21 | [JsonPropertyName("catalogEntry")] 22 | public PackageMetadata PackageMetadata { get; set; } 23 | 24 | /// 25 | /// The URL to the package content (.nupkg) 26 | /// 27 | [JsonPropertyName("packageContent")] 28 | public string PackageContentUrl { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/RegistrationIndexResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The metadata for a package and all of its versions. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-index 10 | /// 11 | public class RegistrationIndexResponse 12 | { 13 | public static readonly IReadOnlyList DefaultType = new List 14 | { 15 | "catalog:CatalogRoot", 16 | "PackageRegistration", 17 | "catalog:Permalink" 18 | }; 19 | 20 | /// 21 | /// The URL to the registration index. 22 | /// 23 | [JsonPropertyName("@id")] 24 | public string RegistrationIndexUrl { get; set; } 25 | 26 | /// 27 | /// The registration index's type. 28 | /// 29 | [JsonPropertyName("@type")] 30 | public IReadOnlyList Type { get; set; } 31 | 32 | /// 33 | /// The number of registration pages. See . 34 | /// 35 | [JsonPropertyName("count")] 36 | public int Count { get; set; } 37 | 38 | /// 39 | /// The pages that contain all of the versions of the package, ordered 40 | /// by the package's version. 41 | /// 42 | [JsonPropertyName("items")] 43 | public IReadOnlyList Pages { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/RegistrationPageResponse.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Protocol.Models 2 | { 3 | /// 4 | /// A page of package metadata entries. 5 | /// 6 | /// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-page 7 | /// 8 | public class RegistrationPageResponse : RegistrationIndexPage 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/SearchContext.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | public class SearchContext 6 | { 7 | public static SearchContext Default(string registrationBaseUrl) 8 | { 9 | return new SearchContext 10 | { 11 | Vocab = "http://schema.nuget.org/schema#", 12 | Base = registrationBaseUrl 13 | }; 14 | } 15 | 16 | [JsonPropertyName("@vocab")] 17 | public string Vocab { get; set; } 18 | 19 | [JsonPropertyName("@base")] 20 | public string Base { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/SearchResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The response to a search query. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#response 10 | /// 11 | public class SearchResponse 12 | { 13 | [JsonPropertyName("@context")] 14 | public SearchContext Context { get; set; } 15 | 16 | /// 17 | /// The total number of matches, disregarding skip and take. 18 | /// 19 | [JsonPropertyName("totalHits")] 20 | public long TotalHits { get; set; } 21 | 22 | /// 23 | /// The packages that matched the search query. 24 | /// 25 | [JsonPropertyName("data")] 26 | public IReadOnlyList Data { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/SearchResultPackageType.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | /// 6 | /// A single package type from a . 7 | /// 8 | /// See https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-result 9 | /// 10 | public class SearchResultPackageType 11 | { 12 | /// 13 | /// The name of the package type. 14 | /// 15 | [JsonPropertyName("name")] 16 | public string Name { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/SearchResultVersion.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | /// 6 | /// A single version from a . 7 | /// 8 | /// See https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-result 9 | /// 10 | public class SearchResultVersion 11 | { 12 | /// 13 | /// The registration leaf URL for this single version of the matched package. 14 | /// 15 | [JsonPropertyName("@id")] 16 | public string RegistrationLeafUrl { get; set; } 17 | 18 | /// 19 | /// The package's full NuGet version after normalization, including any SemVer 2.0.0 build metadata. 20 | /// 21 | [JsonPropertyName("version")] 22 | public string Version { get; set; } 23 | 24 | /// 25 | /// The downloads for this single version of the matched package. 26 | /// 27 | [JsonPropertyName("downloads")] 28 | public long Downloads { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/ServiceIndexItem.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace BaGet.Protocol.Models 4 | { 5 | /// 6 | /// A resource in the . 7 | /// 8 | /// See https://docs.microsoft.com/en-us/nuget/api/service-index#resources 9 | /// 10 | public class ServiceIndexItem 11 | { 12 | /// 13 | /// The resource's base URL. 14 | /// 15 | [JsonPropertyName("@id")] 16 | public string ResourceUrl { get; set; } 17 | 18 | /// 19 | /// The resource's type. 20 | /// 21 | [JsonPropertyName("@type")] 22 | public string Type { get; set; } 23 | 24 | /// 25 | /// Human readable comments about the resource. 26 | /// 27 | [JsonPropertyName("comment")] 28 | public string Comment { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Models/ServiceIndexResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace BaGet.Protocol.Models 5 | { 6 | /// 7 | /// The entry point for a NuGet package source used by the client to discover NuGet APIs. 8 | /// 9 | /// See https://docs.microsoft.com/en-us/nuget/api/overview 10 | /// 11 | public class ServiceIndexResponse 12 | { 13 | /// 14 | /// The service index's version. 15 | /// 16 | [JsonPropertyName("version")] 17 | public string Version { get; set; } 18 | 19 | /// 20 | /// The resources declared by this service index. 21 | /// 22 | [JsonPropertyName("resources")] 23 | public IReadOnlyList Resources { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Search/ISearchClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using BaGet.Protocol.Models; 4 | 5 | namespace BaGet.Protocol 6 | { 7 | /// 8 | /// The client used to search for packages. 9 | /// 10 | /// See https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource 11 | /// 12 | public interface ISearchClient 13 | { 14 | /// 15 | /// Perform a search query. 16 | /// See: https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages 17 | /// 18 | /// The search query. 19 | /// How many results to skip. 20 | /// How many results to return. 21 | /// Whether pre-release packages should be returned. 22 | /// Whether packages that require SemVer 2.0.0 compatibility should be returned. 23 | /// A token to cancel the task. 24 | /// The search response. 25 | Task SearchAsync( 26 | string query = null, 27 | int skip = 0, 28 | int take = 20, 29 | bool includePrerelease = true, 30 | bool includeSemVer2 = true, 31 | CancellationToken cancellationToken = default); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Search/NullAutocompleteClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Protocol.Models; 5 | 6 | namespace BaGet.Protocol.Internal 7 | { 8 | public class NullAutocompleteClient : IAutocompleteClient 9 | { 10 | public Task AutocompleteAsync(string query = null, int skip = 0, int take = 20, bool includePrerelease = true, bool includeSemVer2 = true, CancellationToken cancellationToken = default) 11 | { 12 | return Task.FromResult(new AutocompleteResponse 13 | { 14 | TotalHits = 0, 15 | Data = new List() 16 | }); 17 | } 18 | 19 | public Task ListPackageVersionsAsync(string packageId, bool includePrerelease = true, bool includeSemVer2 = true, CancellationToken cancellationToken = default) 20 | { 21 | return Task.FromResult(new AutocompleteResponse 22 | { 23 | TotalHits = 0, 24 | Data = new List() 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/Search/SearchClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Protocol.Models; 5 | 6 | namespace BaGet.Protocol 7 | { 8 | public partial class NuGetClientFactory 9 | { 10 | private class SearchClient : ISearchClient 11 | { 12 | private readonly NuGetClientFactory _clientfactory; 13 | 14 | public SearchClient(NuGetClientFactory clientFactory) 15 | { 16 | _clientfactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory)); 17 | } 18 | 19 | public async Task SearchAsync( 20 | string query = null, 21 | int skip = 0, 22 | int take = 20, 23 | bool includePrerelease = true, 24 | bool includeSemVer2 = true, 25 | CancellationToken cancellationToken = default) 26 | { 27 | // TODO: Support search failover. 28 | // See: https://github.com/loic-sharma/BaGet/issues/314 29 | var client = await _clientfactory.GetSearchClientAsync(cancellationToken); 30 | 31 | return await client.SearchAsync(query, skip, take, includePrerelease, includeSemVer2); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/ServiceIndex/IServiceIndexClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using BaGet.Protocol.Models; 4 | 5 | namespace BaGet.Protocol 6 | { 7 | /// 8 | /// The NuGet Service Index client, used to discover other resources. 9 | /// 10 | /// See https://docs.microsoft.com/en-us/nuget/api/service-index 11 | /// 12 | public interface IServiceIndexClient 13 | { 14 | /// 15 | /// Get the resources available on this package feed. 16 | /// See: https://docs.microsoft.com/en-us/nuget/api/service-index#resources 17 | /// 18 | /// The resources available on this package feed. 19 | Task GetAsync(CancellationToken cancellationToken = default); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/ServiceIndex/RawServiceIndexClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using BaGet.Protocol.Models; 6 | 7 | namespace BaGet.Protocol.Internal 8 | { 9 | /// 10 | /// The NuGet Service Index client, used to discover other resources. 11 | /// 12 | /// See https://docs.microsoft.com/en-us/nuget/api/service-index 13 | /// 14 | public class RawServiceIndexClient : IServiceIndexClient 15 | { 16 | private readonly HttpClient _httpClient; 17 | private readonly string _serviceIndexUrl; 18 | 19 | /// 20 | /// Create a service index for the upstream source. 21 | /// 22 | /// The HTTP client used to send requests. 23 | /// The NuGet server's service index URL. 24 | public RawServiceIndexClient(HttpClient httpClient, string serviceIndexUrl) 25 | { 26 | _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); 27 | _serviceIndexUrl = serviceIndexUrl ?? throw new ArgumentNullException(nameof(serviceIndexUrl)); 28 | } 29 | 30 | /// 31 | public async Task GetAsync(CancellationToken cancellationToken = default) 32 | { 33 | return await _httpClient.GetFromJsonAsync( 34 | _serviceIndexUrl, 35 | cancellationToken); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/BaGet.Protocol/ServiceIndex/ServiceIndexClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Protocol.Models; 5 | 6 | namespace BaGet.Protocol 7 | { 8 | public partial class NuGetClientFactory 9 | { 10 | private class ServiceIndexClient : IServiceIndexClient 11 | { 12 | private readonly NuGetClientFactory _clientFactory; 13 | 14 | public ServiceIndexClient(NuGetClientFactory clientFactory) 15 | { 16 | _clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory)); 17 | } 18 | 19 | public async Task GetAsync(CancellationToken cancellationToken = default) 20 | { 21 | return await _clientFactory.GetServiceIndexAsync(cancellationToken); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/BaGet.Web/BaGet.Web.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 6 | NuGet 7 | BaGet's NuGet server implementation 8 | BaGet.Web 9 | 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/BaGet.Web/Controllers/ServiceIndexController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Core; 5 | using BaGet.Protocol.Models; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace BaGet.Web 9 | { 10 | /// 11 | /// The NuGet Service Index. This aids NuGet client to discover this server's services. 12 | /// 13 | public class ServiceIndexController : Controller 14 | { 15 | private readonly IServiceIndexService _serviceIndex; 16 | 17 | public ServiceIndexController(IServiceIndexService serviceIndex) 18 | { 19 | _serviceIndex = serviceIndex ?? throw new ArgumentNullException(nameof(serviceIndex)); 20 | } 21 | 22 | // GET v3/index 23 | [HttpGet] 24 | public async Task GetAsync(CancellationToken cancellationToken) 25 | { 26 | return await _serviceIndex.GetAsync(cancellationToken); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/BaGet.Web/Extensions/HttpRequestExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Core; 5 | using Microsoft.AspNetCore.Http; 6 | 7 | namespace BaGet.Web 8 | { 9 | public static class HttpRequestExtensions 10 | { 11 | public const string ApiKeyHeader = "X-NuGet-ApiKey"; 12 | 13 | public static async Task GetUploadStreamOrNullAsync(this HttpRequest request, CancellationToken cancellationToken) 14 | { 15 | // Try to get the nupkg from the multipart/form-data. If that's empty, 16 | // fallback to the request's body. 17 | Stream rawUploadStream = null; 18 | try 19 | { 20 | if (request.HasFormContentType && request.Form.Files.Count > 0) 21 | { 22 | rawUploadStream = request.Form.Files[0].OpenReadStream(); 23 | } 24 | else 25 | { 26 | rawUploadStream = request.Body; 27 | } 28 | 29 | // Convert the upload stream into a temporary file stream to 30 | // minimize memory usage. 31 | return await rawUploadStream?.AsTemporaryFileStreamAsync(cancellationToken); 32 | } 33 | finally 34 | { 35 | rawUploadStream?.Dispose(); 36 | } 37 | } 38 | 39 | public static string GetApiKey(this HttpRequest request) 40 | { 41 | return request.Headers[ApiKeyHeader]; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/BaGet.Web/Extensions/IApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | 4 | namespace BaGet.Web 5 | { 6 | public static class IApplicationBuilderExtensions 7 | { 8 | public static IApplicationBuilder UseOperationCancelledMiddleware(this IApplicationBuilder app) 9 | { 10 | if (app == null) throw new ArgumentNullException(nameof(app)); 11 | 12 | return app.UseMiddleware(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BaGet.Web/Extensions/IHostExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using BaGet.Core; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Hosting; 7 | using Microsoft.Extensions.Options; 8 | 9 | namespace BaGet.Web 10 | { 11 | public static class IHostExtensions 12 | { 13 | public static IHostBuilder UseBaGet(this IHostBuilder host, Action configure) 14 | { 15 | return host.ConfigureServices(services => 16 | { 17 | services.AddBaGetWebApplication(configure); 18 | }); 19 | } 20 | 21 | public static async Task RunMigrationsAsync( 22 | this IHost host, 23 | CancellationToken cancellationToken = default) 24 | { 25 | // Run migrations if necessary. 26 | var options = host.Services.GetRequiredService>(); 27 | 28 | if (options.Value.RunMigrationsAtStartup) 29 | { 30 | using (var scope = host.Services.CreateScope()) 31 | { 32 | var ctx = scope.ServiceProvider.GetService(); 33 | if (ctx != null) 34 | { 35 | await ctx.RunMigrationsAsync(cancellationToken); 36 | } 37 | } 38 | } 39 | } 40 | 41 | public static bool ValidateStartupOptions(this IHost host) 42 | { 43 | return host 44 | .Services 45 | .GetRequiredService() 46 | .Validate(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/BaGet.Web/Extensions/IServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BaGet.Core; 3 | using BaGet.Web; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace BaGet 8 | { 9 | public static class IServiceCollectionExtensions 10 | { 11 | public static IServiceCollection AddBaGetWebApplication( 12 | this IServiceCollection services, 13 | Action configureAction) 14 | { 15 | services 16 | .AddRouting(options => options.LowercaseUrls = true) 17 | .AddControllers() 18 | .AddApplicationPart(typeof(PackageContentController).Assembly) 19 | .SetCompatibilityVersion(CompatibilityVersion.Version_3_0) 20 | .AddJsonOptions(options => 21 | { 22 | options.JsonSerializerOptions.IgnoreNullValues = true; 23 | }); 24 | 25 | services.AddRazorPages(); 26 | 27 | services.AddHttpContextAccessor(); 28 | services.AddTransient(); 29 | 30 | services.AddBaGetApplication(configureAction); 31 | 32 | return services; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BaGet.Web/Extensions/RazorExtensions.cs: -------------------------------------------------------------------------------- 1 | using Humanizer; 2 | 3 | namespace BaGet.Web 4 | { 5 | public static class RazorExtensions 6 | { 7 | public static string ToMetric(this long value) 8 | { 9 | return ((double) value).ToMetric(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/BaGet.Web/NavLinkTagHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | using Microsoft.AspNetCore.Razor.TagHelpers; 5 | 6 | namespace BaGet.Web 7 | { 8 | [HtmlTargetElement(Attributes = "nav-link")] 9 | public class NavLinkTagHelper : TagHelper 10 | { 11 | private readonly IHttpContextAccessor _accessor; 12 | 13 | public NavLinkTagHelper(IHttpContextAccessor accessor) 14 | { 15 | _accessor = accessor ?? throw new ArgumentNullException(nameof(accessor)); 16 | } 17 | 18 | [HtmlAttributeName("asp-page")] 19 | public string Page { get; set; } 20 | 21 | public override void Process(TagHelperContext context, TagHelperOutput output) 22 | { 23 | if (IsActiveLink()) 24 | { 25 | output.Attributes.SetAttribute("class", "active"); 26 | } 27 | } 28 | 29 | private bool IsActiveLink() 30 | { 31 | var endpoint = _accessor.HttpContext?.GetEndpoint(); 32 | var pageDescriptor = endpoint?.Metadata.GetMetadata(); 33 | 34 | if (pageDescriptor == null) return false; 35 | if (pageDescriptor.AreaName != null) return false; 36 | if (pageDescriptor.ViewEnginePath != Page) return false; 37 | 38 | return true; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/BaGet.Web/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using BaGet 2 | @using BaGet.Core 3 | @using Humanizer 4 | @using Microsoft.AspNetCore.Html 5 | @namespace BaGet.Web 6 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 7 | @addTagHelper *, BaGet.Web 8 | -------------------------------------------------------------------------------- /src/BaGet.Web/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/BaGet.Web/Routes.cs: -------------------------------------------------------------------------------- 1 | namespace BaGet.Web 2 | { 3 | public class Routes 4 | { 5 | public const string IndexRouteName = "index"; 6 | public const string UploadPackageRouteName = "upload-package"; 7 | public const string UploadSymbolRouteName = "upload-symbol"; 8 | public const string DeleteRouteName = "delete"; 9 | public const string RelistRouteName = "relist"; 10 | public const string SearchRouteName = "search"; 11 | public const string AutocompleteRouteName = "autocomplete"; 12 | public const string DependentsRouteName = "dependents"; 13 | public const string RegistrationIndexRouteName = "registration-index"; 14 | public const string RegistrationLeafRouteName = "registration-leaf"; 15 | public const string PackageVersionsRouteName = "package-versions"; 16 | public const string PackageDownloadRouteName = "package-download"; 17 | public const string PackageDownloadManifestRouteName = "package-download-manifest"; 18 | public const string PackageDownloadReadmeRouteName = "package-download-readme"; 19 | public const string PackageDownloadIconRouteName = "package-download-icon"; 20 | public const string SymbolDownloadRouteName = "symbol-download"; 21 | public const string PrefixedSymbolDownloadRouteName = "prefixed-symbol-download"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/images/default-package-icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/images/default-package-icon-256x256.png -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/images/github-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/images/github-32x32.png -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/alpinejs/LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright © 2019-2020 Caleb Porzio and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2019 Twitter, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/BaGet.Web/wwwroot/lib/office-ui-fabric-core/LICENSE: -------------------------------------------------------------------------------- 1 | Office UI Fabric 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | Note: Usage of the assets referenced in Office UI Fabric files is subject to the terms listed at https://aka.ms/fabric-assets-license 16 | -------------------------------------------------------------------------------- /src/BaGet/BaGet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/BaGet/ConfigureRazorRuntimeCompilation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; 4 | using Microsoft.Extensions.FileProviders; 5 | using Microsoft.Extensions.Hosting; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace BaGet 9 | { 10 | public class ConfigureRazorRuntimeCompilation : IConfigureOptions 11 | { 12 | private readonly IHostEnvironment _env; 13 | 14 | public ConfigureRazorRuntimeCompilation(IHostEnvironment env) 15 | { 16 | _env = env ?? throw new ArgumentNullException(nameof(env)); 17 | } 18 | 19 | public void Configure(MvcRazorRuntimeCompilationOptions options) 20 | { 21 | var path = Path.Combine(_env.ContentRootPath, "..", "BaGet.Web"); 22 | 23 | // Try to enable Razor "hot reload". 24 | if (!_env.IsDevelopment()) return; 25 | if (!Directory.Exists(path)) return; 26 | 27 | var provider = new PhysicalFileProvider(Path.GetFullPath(path)); 28 | 29 | options.FileProviders.Add(provider); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/BaGet/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:50557/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development", 16 | "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" 17 | } 18 | }, 19 | "BaGet": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development", 24 | "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" 25 | }, 26 | "applicationUrl": "http://localhost:50561/" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/BaGet/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/BaGet/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApiKey": "", 3 | "PackageDeletionBehavior": "Unlist", 4 | "AllowPackageOverwrites": false, 5 | 6 | "Database": { 7 | "Type": "Sqlite", 8 | "ConnectionString": "Data Source=baget.db" 9 | }, 10 | 11 | "Storage": { 12 | "Type": "FileSystem", 13 | "Path": "" 14 | }, 15 | 16 | "Search": { 17 | "Type": "Database" 18 | }, 19 | 20 | "Mirror": { 21 | "Enabled": false, 22 | 23 | // Uncomment this to use the NuGet v2 protocol 24 | //"Legacy": true, 25 | "PackageSource": "https://api.nuget.org/v3/index.json" 26 | }, 27 | 28 | // Uncomment this to configure BaGet to listen to port 8080. 29 | // See: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#listenoptionsusehttps 30 | //"Kestrel": { 31 | // "Endpoints": { 32 | // "Http": { 33 | // "Url": "http://localhost:8080" 34 | // } 35 | // } 36 | //}, 37 | 38 | "Logging": { 39 | "IncludeScopes": false, 40 | "Debug": { 41 | "LogLevel": { 42 | "Default": "Warning" 43 | } 44 | }, 45 | "Console": { 46 | "LogLevel": { 47 | "Microsoft.Hosting.Lifetime": "Information", 48 | "Default": "Warning" 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/BaGet/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet 2 | 3 | This is the project that implements [NuGet service APIs](https://docs.microsoft.com/en-us/nuget/api/overview). Most of the core logic is contained within the `BaGet.Core` project. 4 | -------------------------------------------------------------------------------- /src/BaGet/wwwroot/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/BaGet/wwwroot/.gitignore -------------------------------------------------------------------------------- /src/packageIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/src/packageIcon.png -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | # BaGet Source Code 2 | 3 | These folders contain the core components of BaGet: 4 | 5 | * `BaGet` - The app's entry point that glues everything together. 6 | * `BaGet.Core` - BaGet's core logic and services. 7 | * `BaGet.Web` - The [NuGet server APIs](https://docs.microsoft.com/en-us/nuget/api/overview) and web UI. 8 | * `BaGet.Protocol` - Libraries to interact with [NuGet servers' APIs](https://docs.microsoft.com/en-us/nuget/api/overview). 9 | 10 | These folders contain database-specific components of BaGet: 11 | 12 | * `BaGet.Database.MySql` - BaGet's MySQL database provider. 13 | * `BaGet.Database.PostgreSql` - BaGet's PostgreSql database provider. 14 | * `BaGet.Database.Sqlite` - BaGet's SQLite database provider. 15 | * `BaGet.Database.SqlServer` - BaGet's Microsoft SQL Server database provider. 16 | 17 | These folders contain cloud-specific components of BaGet: 18 | 19 | * `BaGet.Aliyun` - BaGet's Alibaba Cloud(Aliyun) provider. 20 | * `BaGet.Aws` - BaGet's Amazon Web Services provider. 21 | * `BaGet.Azure` - BaGet's Azure provider. 22 | * `BaGet.Gcp` - BaGet's Google Cloud Platform provider. 23 | 24 | -------------------------------------------------------------------------------- /tests/BaGet.Core.Tests/BaGet.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/BaGet.Core.Tests/Services/SymbolIndexingServiceTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Xunit; 3 | 4 | namespace BaGet.Core.Tests.Services 5 | { 6 | public class SymbolIndexingServiceTests 7 | { 8 | [Fact] 9 | public async Task IfSnupkgHasEntryThatExtractsOutsideOfExtractionPath_ReturnsInvalidSymbolPackage() 10 | { 11 | await Task.CompletedTask; 12 | } 13 | 14 | [Fact] 15 | public async Task IfSnupkgContainsEntryWithInvalidExtension_ReturnsInvalidSymbolPackage() 16 | { 17 | await Task.CompletedTask; 18 | } 19 | 20 | [Fact] 21 | public async Task IfSnupkgDoesNotHaveCorrespondingNupkg_ReturnsPackageNotFound() 22 | { 23 | await Task.CompletedTask; 24 | } 25 | 26 | [Fact] 27 | public async Task IfSnupkgContainsInvalidPortablePdb_ReturnsInvalidSymbolPackage() 28 | { 29 | // Have two pdb entries, the first of which is valid. Ensure nothing is persisted. 30 | await Task.CompletedTask; 31 | } 32 | 33 | [Fact] 34 | public async Task IfSnupkgPdbDoesNotHaveCorrespondingNupkgDll_ReturnsInvalidSymbolPackage() 35 | { 36 | await Task.CompletedTask; 37 | } 38 | 39 | [Fact] 40 | public async Task SavesPdbs() 41 | { 42 | await Task.CompletedTask; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/BaGet.Protocol.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | TestData.resx 14 | True 15 | True 16 | 17 | 18 | 19 | 20 | 21 | TestData.Designer.cs 22 | ResXFileCodeGenerator 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/NuGetClientFactoryTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace BaGet.Protocol.Tests 4 | { 5 | public class NuGetClientFactoryTests : IClassFixture 6 | { 7 | private readonly NuGetClientFactory _target; 8 | 9 | public NuGetClientFactoryTests(ProtocolFixture fixture) 10 | { 11 | _target = fixture.NuGetClientFactory; 12 | } 13 | 14 | // TODO: Test package download 15 | // TODO: Test package manifest download 16 | // TODO: List package versions 17 | // TODO: List package versions #2 18 | // TODO: List all package versions 19 | // TODO: Get package metadata inlined 20 | // TODO: Get package metadata paged 21 | // TODO: Get single package metadata inlined 22 | // TODO: Get single package metadata paged 23 | // TODO: Search 24 | // TODO: Autocomplete 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/NuGetClientTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace BaGet.Protocol.Tests 4 | { 5 | public class NuGetClientTests : IClassFixture 6 | { 7 | private readonly NuGetClient _target; 8 | 9 | public NuGetClientTests(ProtocolFixture fixture) 10 | { 11 | _target = fixture.NuGetClient; 12 | } 13 | 14 | // TODO: Test package download 15 | // TODO: Test package manifest download 16 | // TODO: List package versions 17 | // TODO: List package versions #2 18 | // TODO: List all package versions 19 | // TODO: Get package metadata inlined 20 | // TODO: Get package metadata paged 21 | // TODO: Get single package metadata inlined 22 | // TODO: Get single package metadata paged 23 | // TODO: Search 24 | // TODO: Autocomplete 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/RawPackageContentClientTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using BaGet.Protocol.Internal; 4 | using Xunit; 5 | 6 | namespace BaGet.Protocol.Tests 7 | { 8 | public class RawPackageContentTests : IClassFixture 9 | { 10 | private readonly RawPackageContentClient _target; 11 | 12 | public RawPackageContentTests(ProtocolFixture fixture) 13 | { 14 | _target = fixture.ContentClient; 15 | } 16 | 17 | [Fact] 18 | public async Task GetsPackageVersions() 19 | { 20 | var result = await _target.GetPackageVersionsOrNullAsync("Test.Package"); 21 | 22 | Assert.NotNull(result); 23 | Assert.Equal(2, result.Versions.Count); 24 | Assert.Equal("1.0.0", result.Versions[0]); 25 | Assert.Equal("2.0.0", result.Versions[1]); 26 | } 27 | 28 | [Fact] 29 | public async Task ReturnsNullIfPackageDoesNotExist() 30 | { 31 | var result = await _target.GetPackageVersionsOrNullAsync(Guid.NewGuid().ToString()); 32 | 33 | Assert.Null(result); 34 | } 35 | 36 | // TODO: Test package download 37 | // TODO: Test package manifest download 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/RawSearchClientTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using BaGet.Protocol.Internal; 3 | using Xunit; 4 | 5 | namespace BaGet.Protocol.Tests 6 | { 7 | public class RawSearchClientTests : IClassFixture 8 | { 9 | private readonly RawSearchClient _target; 10 | 11 | public RawSearchClientTests(ProtocolFixture fixture) 12 | { 13 | _target = fixture.SearchClient; 14 | } 15 | 16 | [Fact] 17 | public async Task GetDefaultSearchResults() 18 | { 19 | var response = await _target.SearchAsync(); 20 | 21 | Assert.NotNull(response); 22 | Assert.Equal(1, response.TotalHits); 23 | 24 | var result = Assert.Single(response.Data); 25 | Assert.Equal("Test.Package", result.PackageId); 26 | Assert.Equal("Package Authors", Assert.Single(result.Authors)); 27 | Assert.Equal(TestData.RegistrationIndexInlinedItemsUrl, result.RegistrationIndexUrl); 28 | 29 | var packageType = Assert.Single(result.PackageTypes); 30 | Assert.Equal("Dependency", packageType.Name); 31 | } 32 | 33 | [Fact] 34 | public async Task AddsParameters() 35 | { 36 | await Task.Yield(); 37 | 38 | // TODO: Assert request URL query parameters. 39 | // var response = await _target.SearchAsync( 40 | // "query", 41 | // skip: 2, 42 | // take: 5, 43 | // includePrerelease: false, 44 | // includeSemVer2: false); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/RawServiceIndexClientTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using BaGet.Protocol.Internal; 3 | using Xunit; 4 | 5 | namespace BaGet.Protocol.Tests 6 | { 7 | public class RawServiceIndexClientTests : IClassFixture 8 | { 9 | private readonly RawServiceIndexClient _target; 10 | 11 | public RawServiceIndexClientTests(ProtocolFixture fixture) 12 | { 13 | _target = fixture.ServiceIndexClient; 14 | } 15 | 16 | [Fact] 17 | public async Task GetsServiceIndex() 18 | { 19 | var result = await _target.GetAsync(); 20 | 21 | Assert.Equal("3.0.0", result.Version); 22 | Assert.Equal(5, result.Resources.Count); 23 | 24 | Assert.Equal(TestData.CatalogIndexUrl, result.GetCatalogResourceUrl()); 25 | Assert.Equal(TestData.PackageMetadataUrl, result.GetPackageMetadataResourceUrl()); 26 | Assert.Equal(TestData.PackageContentUrl, result.GetPackageContentResourceUrl()); 27 | Assert.Equal(TestData.SearchUrl, result.GetSearchQueryResourceUrl()); 28 | Assert.Equal(TestData.AutocompleteUrl, result.GetSearchAutocompleteResourceUrl()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/BaGet.Protocol.Tests/Support/ProtocolFixture.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using BaGet.Protocol.Internal; 4 | 5 | namespace BaGet.Protocol.Tests 6 | { 7 | public class ProtocolFixture 8 | { 9 | public ProtocolFixture() 10 | { 11 | var httpClient = new HttpClient(new TestDataHttpMessageHandler()); 12 | 13 | NuGetClientFactory = new NuGetClientFactory(httpClient, TestData.ServiceIndexUrl); 14 | NuGetClient = new NuGetClient(NuGetClientFactory); 15 | 16 | ServiceIndexClient = new RawServiceIndexClient(httpClient, TestData.ServiceIndexUrl); 17 | ContentClient = new RawPackageContentClient(httpClient, TestData.PackageContentUrl); 18 | MetadataClient = new RawPackageMetadataClient(httpClient, TestData.PackageMetadataUrl); 19 | SearchClient = new RawSearchClient(httpClient, TestData.SearchUrl); 20 | AutocompleteClient = new RawAutocompleteClient(httpClient, TestData.AutocompleteUrl); 21 | CatalogClient = new RawCatalogClient(httpClient, TestData.CatalogIndexUrl); 22 | } 23 | 24 | public NuGetClient NuGetClient { get; } 25 | public NuGetClientFactory NuGetClientFactory { get; } 26 | 27 | public RawServiceIndexClient ServiceIndexClient { get; } 28 | public RawPackageContentClient ContentClient { get; } 29 | public RawPackageMetadataClient MetadataClient { get; } 30 | public RawSearchClient SearchClient { get; } 31 | public RawAutocompleteClient AutocompleteClient { get; } 32 | public RawCatalogClient CatalogClient { get; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/BaGet.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | True 25 | True 26 | TestData.resx 27 | 28 | 29 | 30 | 31 | 32 | TestData.Designer.cs 33 | ResXFileCodeGenerator 34 | BaGet.Tests 35 | 36 | 37 | Never 38 | 39 | 40 | Never 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/Support/HttpSourceResourceProviderTestHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using NuGet.Configuration; 8 | using NuGet.Protocol; 9 | using NuGet.Protocol.Core.Types; 10 | 11 | namespace BaGet.Tests 12 | { 13 | /// 14 | /// Similar to official HttpSourceResourceProvider, but uses test host. 15 | /// 16 | public class HttpSourceResourceProviderTestHost : ResourceProvider 17 | { 18 | // Only one HttpSource per source should exist. This is to reduce the number of TCP connections. 19 | private readonly ConcurrentDictionary _cache 20 | = new ConcurrentDictionary(); 21 | private readonly HttpClient _httpClient; 22 | 23 | public HttpSourceResourceProviderTestHost(HttpClient httpClient) 24 | : base(typeof(HttpSourceResource), 25 | nameof(HttpSourceResource), 26 | NuGetResourceProviderPositions.Last) 27 | { 28 | _httpClient = httpClient; 29 | } 30 | 31 | public override Task> TryCreate(SourceRepository source, CancellationToken token) 32 | { 33 | Debug.Assert(source.PackageSource.IsHttp, "HTTP source requested for a non-http source."); 34 | 35 | HttpSourceResource curResource = null; 36 | 37 | if (source.PackageSource.IsHttp) 38 | { 39 | curResource = _cache.GetOrAdd( 40 | source.PackageSource, 41 | packageSource => new HttpSourceResource(TestableHttpSource.Create(source, _httpClient))); 42 | } 43 | 44 | return Task.FromResult(new Tuple(curResource != null, curResource)); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/Support/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Newtonsoft.Json; 3 | 4 | namespace BaGet.Tests 5 | { 6 | public static class StreamExtensions 7 | { 8 | public static string ToPrettifiedJson(this Stream jsonStream) 9 | { 10 | using var writer = new StringWriter(); 11 | using var jsonWriter = new JsonTextWriter(writer) 12 | { 13 | Formatting = Formatting.Indented, 14 | DateTimeZoneHandling = DateTimeZoneHandling.Utc 15 | }; 16 | 17 | using var reader = new StreamReader(jsonStream); 18 | using var jsonReader = new JsonTextReader(reader); 19 | 20 | jsonWriter.WriteToken(jsonReader); 21 | return writer.ToString(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/Support/TestResources.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace BaGet.Tests 4 | { 5 | public static class TestResources 6 | { 7 | private const string ResourcePrefix = "BaGet.Tests.TestData."; 8 | 9 | /// 10 | /// Test package created with the following properties: 11 | /// 12 | /// Test author 13 | /// Test description 14 | /// 1.2.3 15 | /// true 16 | /// snupkg 17 | /// 18 | public const string Package = "TestData.1.2.3.nupkg"; 19 | public const string SymbolPackage = "TestData.1.2.3.snupkg"; 20 | 21 | /// 22 | /// Buffer the resource stream into memory so the caller doesn't have to dispose. 23 | /// 24 | public static MemoryStream GetResourceStream(string resourceName) 25 | { 26 | using var resourceStream = typeof(TestResources) 27 | .Assembly 28 | .GetManifestResourceStream(ResourcePrefix + resourceName); 29 | 30 | if (resourceStream == null) 31 | { 32 | return null; 33 | } 34 | 35 | var bufferedStream = new MemoryStream(); 36 | using (resourceStream) 37 | { 38 | resourceStream.CopyTo(bufferedStream); 39 | } 40 | 41 | bufferedStream.Position = 0; 42 | return bufferedStream; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/Support/XunitLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Xunit.Abstractions; 4 | 5 | namespace BaGet.Tests 6 | { 7 | // Based off: 8 | // https://stackoverflow.com/questions/46169169/net-core-2-0-configurelogging-xunit-test 9 | public class XunitLogger : ILogger 10 | { 11 | private readonly ITestOutputHelper _output; 12 | private readonly string _category; 13 | 14 | public XunitLogger(ITestOutputHelper output, string category) 15 | { 16 | _output = output ?? throw new ArgumentNullException(nameof(output)); 17 | _category = category ?? throw new ArgumentNullException(nameof(category)); 18 | } 19 | 20 | public IDisposable BeginScope(TState state) => NullScope.Instance; 21 | public bool IsEnabled(LogLevel logLevel) => true; 22 | 23 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 24 | { 25 | _output.WriteLine($"{_category} [{eventId}] {formatter(state, exception)}"); 26 | 27 | if (exception != null) 28 | { 29 | _output.WriteLine(exception.ToString()); 30 | } 31 | } 32 | 33 | private class NullScope : IDisposable 34 | { 35 | public static readonly NullScope Instance = new NullScope(); 36 | 37 | public void Dispose() { } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/Support/XunitLoggerProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Xunit.Abstractions; 4 | 5 | namespace BaGet.Tests 6 | { 7 | // Based off: 8 | // https://stackoverflow.com/questions/46169169/net-core-2-0-configurelogging-xunit-test 9 | public class XunitLoggerProvider : ILoggerProvider 10 | { 11 | private readonly ITestOutputHelper _output; 12 | 13 | public XunitLoggerProvider(ITestOutputHelper output) 14 | { 15 | _output = output ?? throw new ArgumentNullException(nameof(output)); 16 | } 17 | 18 | public ILogger CreateLogger(string category) => new XunitLogger(_output, category); 19 | 20 | public void Dispose() { } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/BaGet.Tests/TestData/TestData.1.2.3.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/tests/BaGet.Tests/TestData/TestData.1.2.3.nupkg -------------------------------------------------------------------------------- /tests/BaGet.Tests/TestData/TestData.1.2.3.snupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loic-sharma/BaGet/5a8502ca4e3b21acd369d4a98c2529dac2d81cfe/tests/BaGet.Tests/TestData/TestData.1.2.3.snupkg -------------------------------------------------------------------------------- /tests/BaGet.Web.Tests/BaGet.Web.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7.2 5 | false 6 | 7 | 8 | 9 | portable 10 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 11 | 12 | 13 | 14 | 15 | 3.1.18 16 | 12.0.2 17 | 5.10.0 18 | 2.4.1 19 | 20 | 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers 25 | 26 | 27 | 28 | 29 | 30 | all 31 | runtime; build; native; contentfiles; analyzers 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------