/// <summary> /// Prune feed packages without committing /// </summary> public static async Task <HashSet <PackageIdentity> > PrunePackagesNoCommit(SleetContext context, RetentionPruneCommandContext pruneContext) { var packageIndex = new PackageIndex(context); var existingPackageSets = await packageIndex.GetPackageSetsAsync(); var allPackages = await RetentionUtility.ResolvePackageSets(existingPackageSets); var stableMax = pruneContext.StableVersionMax == null ? context.SourceSettings.RetentionMaxStableVersions : pruneContext.StableVersionMax; var prerelMax = pruneContext.PrereleaseVersionMax == null ? context.SourceSettings.RetentionMaxPrereleaseVersions : pruneContext.PrereleaseVersionMax; if (stableMax == null || stableMax < 1) { throw new ArgumentException("Package retention must specify a maximum number of stable versions that is > 0"); } if (prerelMax == null || prerelMax < 1) { throw new ArgumentException("Package retention must specify a maximum number of prerelease versions that is > 0"); } if (pruneContext.PackageIds?.Count > 0) { allPackages.RemoveWhere(e => !pruneContext.PackageIds.Contains(e.Id)); } var toPrune = RetentionUtility.GetPackagesToPrune(allPackages, pruneContext.PinnedPackages, (int)stableMax, (int)prerelMax); await RemovePackages(context, existingPackageSets, toPrune, pruneContext.DryRun, context.Log); return(toPrune); }
public async Task RemovePackageAsync(PackageIdentity packageIdentity) { var packageIndex = new PackageIndex(_context); var versions = await packageIndex.GetPackageVersions(packageIdentity.Id); // Noop if the id does not exist if (!versions.Contains(packageIdentity.Version)) { return; } var file = RootIndexFile; var json = await file.GetJson(_context.Log, _context.Token); var data = GetData(json); data.RemoveAll(e => packageIdentity.Id.Equals(e.GetId(), StringComparison.OrdinalIgnoreCase)); if (versions.Count > 1) { // Remove the version if others still exist, otherwise leave the entire entry out var newEntry = await CreatePackageEntry(packageIdentity, add : false); data.Add(newEntry); } json = CreatePage(data); await file.Write(json, _context.Log, _context.Token); }
public async Task RemovePackageAsync(PackageIdentity packageIdentity) { var packageIndex = new PackageIndex(_context); var allPackagesForId = await packageIndex.GetPackagesByIdAsync(packageIdentity.Id); allPackagesForId.Remove(packageIdentity); // Only remove the package if all versions have been removed if (allPackagesForId.Count == 0) { var file = RootIndexFile; var json = await file.GetJson(_context.Log, _context.Token); var data = json["data"] as JArray; var ids = await GetPackageIds(); if (ids.Remove(packageIdentity.Id)) { data.Clear(); foreach (var id in ids.OrderBy(s => s, StringComparer.OrdinalIgnoreCase)) { data.Add(id); } json["totalHits"] = ids.Count; json = JsonLDTokenComparer.Format(json); await file.Write(json, _context.Log, _context.Token); } } }
/// <summary> /// Lock the feed and delete all packages given. /// </summary> public static async Task <bool> DeletePackagesAsync(LocalSettings settings, ISleetFileSystem source, IEnumerable <PackageIdentity> packagesToDelete, string reason, bool force, ILogger log) { var success = true; var token = CancellationToken.None; log.LogMinimal($"Reading feed {source.BaseURI.AbsoluteUri}"); // Check if already initialized using (var feedLock = await SourceUtility.VerifyInitAndLock(settings, source, "Delete", log, token)) { // Validate source await SourceUtility.ValidateFeedForClient(source, log, token); // Get sleet.settings.json var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; var packageIndex = new PackageIndex(context); var existingPackageSets = await packageIndex.GetPackageSetsAsync(); var packages = new HashSet <PackageIdentity>(packagesToDelete); if (string.IsNullOrEmpty(reason)) { reason = string.Empty; } await RemovePackages(force, log, context, existingPackageSets, packages); // Save all log.LogMinimal($"Committing changes to {source.BaseURI.AbsoluteUri}"); success &= await source.Commit(log, token); } if (success) { log.LogMinimal($"Successfully deleted packages."); } else { log.LogError($"Failed to delete packages."); } return(success); }
public static async Task <int> RunCore(LocalSettings settings, ISleetFileSystem source, List <string> inputs, bool force, ILogger log) { var exitCode = 0; var token = CancellationToken.None; var now = DateTimeOffset.UtcNow; // Get packages var packages = GetPackageInputs(inputs, now, log); // Check if already initialized using (var feedLock = await SourceUtility.VerifyInitAndLock(source, log, token)) { // Validate source await UpgradeUtility.UpgradeIfNeeded(source, log, token); // Get sleet.settings.json var sourceSettings = new SourceSettings(); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; var packageIndex = new PackageIndex(context); foreach (var package in packages) { if (await packageIndex.Exists(package.Identity)) { if (force) { log.LogInformation($"Package already exists, removing {package.ToString()}"); await SleetUtility.RemovePackage(context, package.Identity); } else { throw new InvalidOperationException($"Package already exists: '{package.Identity}'."); } } log.LogInformation($"Adding {package.Identity.ToString()}"); await SleetUtility.AddPackage(context, package); } // Save all await source.Commit(log, token); } return(exitCode); }
/// <summary> /// Push packages to a feed. /// This assumes the feed is already locked. /// </summary> public static async Task <bool> PushPackages(LocalSettings settings, ISleetFileSystem source, List <PackageInput> packages, bool force, bool skipExisting, ILogger log, CancellationToken token) { var exitCode = true; var now = DateTimeOffset.UtcNow; // Verify no duplicate packages CheckForDuplicates(packages); // Get sleet.settings.json await log.LogAsync(LogLevel.Minimal, "Reading feed"); var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token, PerfTracker = source.LocalCache.PerfTracker }; await log.LogAsync(LogLevel.Verbose, "Reading existing package index"); // Push var packageIndex = new PackageIndex(context); var existingPackageSets = await packageIndex.GetPackageSetsAsync(); await PushPackages(packages, context, existingPackageSets, force, skipExisting, log); // Prune packages await PrunePackages(packages, context); // Save all await log.LogAsync(LogLevel.Minimal, $"Committing changes to {source.BaseURI.AbsoluteUri}"); await source.Commit(log, token); if (exitCode) { await log.LogAsync(LogLevel.Minimal, "Successfully pushed packages."); } else { await log.LogAsync(LogLevel.Error, "Failed to push packages."); } return(exitCode); }
private static async Task <bool> CreatePackageIndexAsync(SleetContext context, JObject serviceIndexJson) { var packageIndex = context.Source.Get("sleet.packageindex.json"); AddServiceIndexEntry(context.Source.BaseURI, "sleet.packageindex.json", "http://schema.emgarten.com/sleet#PackageIndex/1.0.0", "Sleet package index.", serviceIndexJson); if (!await packageIndex.Exists(context.Log, context.Token)) { var index = new PackageIndex(context); await index.InitAsync(); return(true); } return(false); }
public static async Task <bool> RunAsync(LocalSettings settings, ISleetFileSystem source, ILogger log) { var exitCode = true; log.LogMinimal($"Stats for {source.BaseURI}"); var token = CancellationToken.None; // Check if already initialized using (var feedLock = await SourceUtility.VerifyInitAndLock(settings, source, "Stats", log, token)) { // Validate source await UpgradeUtility.EnsureFeedVersionMatchesTool(source, log, token); // Get sleet.settings.json var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; var packageIndex = new PackageIndex(context); var existingPackageSets = await packageIndex.GetPackageSetsAsync(); var uniqueIds = existingPackageSets.Packages.Index .Concat(existingPackageSets.Symbols.Index) .Select(e => e.Id).Distinct(StringComparer.OrdinalIgnoreCase); log.LogMinimal($"Packages: {existingPackageSets.Packages.Index.Count}"); log.LogMinimal($"Symbols Packages: {existingPackageSets.Symbols.Index.Count}"); log.LogMinimal($"Unique package ids: {uniqueIds.Count()}"); } return(exitCode); }
private async Task <List <ILogMessage> > ValidateWithFeedIndexAsync(ISet <PackageIdentity> packages, ISet <PackageIdentity> symbolsPackages) { var messages = new List <ILogMessage>(); var feedIndex = new PackageIndex(_context); if (await feedIndex.File.ExistsWithFetch(_context.Log, _context.Token)) { var feedPackages = await feedIndex.GetPackagesAsync(); var feedSymbolsPackages = await feedIndex.GetSymbolsPackagesAsync(); var extraPackages = packages.Except(feedPackages); var extraSymbolsPackages = symbolsPackages.Except(feedSymbolsPackages); var feedDiff = new PackageDiff(Enumerable.Empty <PackageIdentity>(), extraPackages); if (feedDiff.HasErrors) { var sb = new StringBuilder(); sb.AppendLine($"Checking packages in {PackageIndex.File.EntityUri.AbsoluteUri}"); sb.Append(feedDiff.ToString()); messages.Add(new LogMessage(LogLevel.Error, sb.ToString())); } var feedSymbolsDiff = new PackageDiff(Enumerable.Empty <PackageIdentity>(), extraSymbolsPackages); if (feedSymbolsDiff.HasErrors) { var sb = new StringBuilder(); sb.AppendLine($"Checking symbols packages in {PackageIndex.File.EntityUri.AbsoluteUri}"); sb.Append(feedSymbolsDiff.ToString()); messages.Add(new LogMessage(LogLevel.Error, sb.ToString())); } } return(messages); }
public static async Task <bool?> IsPackageIdenticalOnFeedAsync(string item, PackageIndex packageIndex, ISleetFileSystem source, FlatContainer flatContainer, ILogger log) { using (var package = new PackageArchiveReader(item)) { var id = await package.GetIdentityAsync(CancellationToken.None); if (await packageIndex.Exists(id)) { using (var remoteStream = await source.Get(flatContainer.GetNupkgPath(id)).GetStream(log, CancellationToken.None)) using (var remote = new MemoryStream()) { await remoteStream.CopyToAsync(remote); var existingBytes = remote.ToArray(); var localBytes = File.ReadAllBytes(item); return(existingBytes.SequenceEqual(localBytes)); } } return(null); } }
/// <summary> /// Download packages. This method does not lock the feed or verify the client version. /// </summary> public static async Task <bool> DownloadPackages(LocalSettings settings, ISleetFileSystem source, string outputPath, bool ignoreErrors, ILogger log, CancellationToken token) { if (string.IsNullOrEmpty(outputPath)) { throw new ArgumentException("Missing output path parameter!"); } var success = true; // Get sleet.settings.json var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; log.LogMinimal($"Reading feed {source.BaseURI.AbsoluteUri}"); // Find all packages var packageIndex = new PackageIndex(context); var flatContainer = new FlatContainer(context); var symbols = new Symbols(context); // Discover all packages var packages = new List <KeyValuePair <PackageIdentity, ISleetFile> >(); packages.AddRange((await packageIndex.GetPackagesAsync()).Select(e => new KeyValuePair <PackageIdentity, ISleetFile>(e, context.Source.Get(flatContainer.GetNupkgPath(e))))); packages.AddRange((await packageIndex.GetSymbolsPackagesAsync()).Select(e => new KeyValuePair <PackageIdentity, ISleetFile>(e, symbols.GetSymbolsNupkgFile(e)))); var tasks = new List <Task <bool> >(MaxThreads); var downloadSuccess = true; log.LogMinimal($"Downloading nupkgs to {outputPath}"); foreach (var pair in packages) { if (tasks.Count >= MaxThreads) { downloadSuccess &= await CompleteTask(tasks); } var package = pair.Key; var nupkgFile = pair.Value; var fileName = UriUtility.GetFileName(nupkgFile.EntityUri); // id/id.version.nupkg or id/id.version.symbols.nupkg var outputNupkgPath = Path.Combine(outputPath, package.Id.ToLowerInvariant(), fileName.ToLowerInvariant()); log.LogInformation($"Downloading {outputNupkgPath}"); tasks.Add(nupkgFile.CopyTo(outputNupkgPath, overwrite: true, log: log, token: token)); } while (tasks.Count > 0) { downloadSuccess &= await CompleteTask(tasks); } success &= downloadSuccess; if (packages.Count < 1) { log.LogWarning("The feed does not contain any packages."); } if (downloadSuccess) { if (packages.Count > 0) { log.LogMinimal("Successfully downloaded packages."); } } else { var message = $"Failed to download all packages!"; if (ignoreErrors) { log.LogWarning(message); } else { log.LogError(message); } } return(success); }
/// <summary> /// Validate packages. This does not lock or verify the version of the feed. /// </summary> public static async Task <bool> Validate(LocalSettings settings, ISleetFileSystem source, ILogger log, CancellationToken token) { var success = true; // Get sleet.settings.json var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; // Create all services var services = new List <ISleetService>(); var registrations = new Registrations(context); var flatContainer = new FlatContainer(context); var search = new Search(context); var autoComplete = new AutoComplete(context); var packageIndex = new PackageIndex(context); if (context.SourceSettings.CatalogEnabled) { // Add the catalog only if it is enabled var catalog = new Catalog(context); services.Add(catalog); } services.Add(registrations); services.Add(flatContainer); services.Add(search); if (context.SourceSettings.SymbolsEnabled) { var symbols = new Symbols(context); services.Add(symbols); } // Verify against the package index var indexedPackages = await packageIndex.GetPackagesAsync(); var allIndexIds = indexedPackages.Select(e => e.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); // Get symbols packages from index var indexedSymbolsPackages = await packageIndex.GetSymbolsPackagesAsync(); var allIndexSymbolsIds = indexedSymbolsPackages.Select(e => e.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); // Verify auto complete log.LogMinimal($"Validating {autoComplete.Name}"); var autoCompleteIds = await autoComplete.GetPackageIds(); var missingACIds = allIndexIds.Except(autoCompleteIds).ToList(); var extraACIds = autoCompleteIds.Except(allIndexIds).ToList(); if (missingACIds.Count() > 0 || extraACIds.Count() > 0) { log.LogError("Missing autocomplete packages: " + string.Join(", ", missingACIds)); log.LogError("Extra autocomplete packages: " + string.Join(", ", extraACIds)); success = false; } else { log.LogMinimal("Autocomplete packages valid"); } // Verify everything else foreach (var service in services) { log.LogMinimal($"Validating {service.Name}"); var validatableService = service as IValidatableService; if (validatableService != null) { // Run internal validations if the service supports it. var messages = await validatableService.ValidateAsync(); success &= messages.All(e => e.Level != LogLevel.Error); foreach (var message in messages) { await log.LogAsync(message); } } else { var allPackagesService = service as IPackagesLookup; var byIdService = service as IPackageIdLookup; var allSymbolsPackagesService = service as ISymbolsPackagesLookup; var symbolsByIdService = service as ISymbolsPackageIdLookup; var servicePackages = new HashSet <PackageIdentity>(); var serviceSymbolsPackages = new HashSet <PackageIdentity>(); // Non-Symbols packages if (allPackagesService != null) { // Use get all if possible servicePackages.UnionWith(await allPackagesService.GetPackagesAsync()); } else if (byIdService != null) { foreach (var id in allIndexIds) { servicePackages.UnionWith(await byIdService.GetPackagesByIdAsync(id)); } } else { log.LogError($"Unable to get packages for {service.Name}"); continue; } var diff = new PackageDiff(indexedPackages, servicePackages); if (diff.HasErrors) { log.LogError(diff.ToString()); success = false; } else { log.LogMinimal(diff.ToString()); log.LogMinimal($"{service.Name} packages valid"); } // Symbols packages if (allSymbolsPackagesService != null) { // Use get all if possible serviceSymbolsPackages.UnionWith(await allSymbolsPackagesService.GetSymbolsPackagesAsync()); } else if (symbolsByIdService != null) { foreach (var id in allIndexSymbolsIds) { serviceSymbolsPackages.UnionWith(await symbolsByIdService.GetSymbolsPackagesByIdAsync(id)); } } else { // Symbols are not supported by this service continue; } var symbolsDiff = new PackageDiff(indexedSymbolsPackages, serviceSymbolsPackages); if (symbolsDiff.HasErrors) { log.LogError(symbolsDiff.ToString()); success = false; } else { log.LogMinimal(symbolsDiff.ToString()); log.LogMinimal($"{service.Name} symbols packages valid"); } } } if (success) { log.LogMinimal($"Feed valid"); } else { log.LogError($"Feed invalid!"); } return(success); }
/// <summary> /// Download packages. This method does not lock the feed or verify the client version. /// </summary> public static async Task <bool> DownloadPackages(LocalSettings settings, ISleetFileSystem source, string outputPath, bool ignoreErrors, bool skipExisting, ILogger log, CancellationToken token) { if (string.IsNullOrEmpty(outputPath)) { throw new ArgumentException("Missing output path parameter!"); } var success = true; // Get sleet.settings.json var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; log.LogMinimal($"Reading feed {source.BaseURI.AbsoluteUri}"); // Find all packages var packageIndex = new PackageIndex(context); var flatContainer = new FlatContainer(context); var symbols = new Symbols(context); // Discover all packages var packages = new List <KeyValuePair <PackageIdentity, ISleetFile> >(); packages.AddRange((await packageIndex.GetPackagesAsync()).Select(e => new KeyValuePair <PackageIdentity, ISleetFile>(e, context.Source.Get(flatContainer.GetNupkgPath(e))))); packages.AddRange((await packageIndex.GetSymbolsPackagesAsync()).Select(e => new KeyValuePair <PackageIdentity, ISleetFile>(e, symbols.GetSymbolsNupkgFile(e)))); log.LogMinimal($"Downloading nupkgs to {outputPath}"); // Run downloads var tasks = packages.Select(e => new Func <Task <bool> >(() => DownloadPackageAsync(outputPath, skipExisting, log, e, token))); var results = await TaskUtils.RunAsync(tasks, useTaskRun : true, token : CancellationToken.None); var downloadSuccess = results.All(e => e); success &= downloadSuccess; if (packages.Count < 1) { log.LogWarning("The feed does not contain any packages."); } if (downloadSuccess) { if (packages.Count > 0) { log.LogMinimal("Successfully downloaded packages."); } } else { var message = $"Failed to download all packages!"; if (ignoreErrors) { log.LogWarning(message); } else { log.LogError(message); } } return(success); }
public static async Task <int> RunCore(LocalSettings settings, ISleetFileSystem source, ILogger log) { var exitCode = 0; var token = CancellationToken.None; // Check if already initialized using (var feedLock = await SourceUtility.VerifyInitAndLock(source, log, token)) { // Validate source await UpgradeUtility.UpgradeIfNeeded(source, log, token); // Get sleet.settings.json var sourceSettings = new SourceSettings(); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; // Create all services var catalog = new Catalog(context); var registrations = new Registrations(context); var flatContainer = new FlatContainer(context); var search = new Search(context); var autoComplete = new AutoComplete(context); var packageIndex = new PackageIndex(context); var services = new List <ISleetService>(); services.Add(catalog); services.Add(registrations); services.Add(flatContainer); services.Add(search); // Verify against the package index var indexedPackages = await packageIndex.GetPackages(); var allIndexIds = indexedPackages.Select(e => e.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); // Verify auto complete log.LogMinimal($"Validating {autoComplete.Name}"); var autoCompleteIds = await autoComplete.GetPackageIds(); var missingACIds = allIndexIds.Except(autoCompleteIds).ToList(); var extraACIds = autoCompleteIds.Except(allIndexIds).ToList(); if (missingACIds.Count() > 0 || extraACIds.Count() > 0) { log.LogError("Missing autocomplete packages: " + string.Join(", ", missingACIds)); log.LogError("Extra autocomplete packages: " + string.Join(", ", extraACIds)); exitCode = 1; } else { log.LogMinimal("Autocomplete packages valid"); } // Verify everything else foreach (var service in services) { log.LogMinimal($"Validating {service.Name}"); var allPackagesService = service as IPackagesLookup; var byIdService = service as IPackageIdLookup; var servicePackages = new HashSet <PackageIdentity>(); // Use get all if possible if (allPackagesService != null) { servicePackages.UnionWith(await allPackagesService.GetPackages()); } else if (byIdService != null) { foreach (var id in allIndexIds) { servicePackages.UnionWith(await byIdService.GetPackagesById(id)); } } else { log.LogError($"Unable to get packages for {service.Name}"); continue; } var diff = new PackageDiff(indexedPackages, servicePackages); if (diff.HasErrors) { log.LogError(diff.ToString()); exitCode = 1; } else { log.LogMinimal(diff.ToString()); log.LogMinimal($"{service.Name} packages valid"); } } if (exitCode != 0) { log.LogError($"Feed invalid!"); } else { log.LogMinimal($"Feed valid"); } } return(exitCode); }
public static async Task <bool> RunAsync(LocalSettings settings, ISleetFileSystem source, string packageId, string version, string reason, bool force, ILogger log) { var success = true; var token = CancellationToken.None; var now = DateTimeOffset.UtcNow; log.LogMinimal($"Reading feed {source.BaseURI.AbsoluteUri}"); // Check if already initialized using (var feedLock = await SourceUtility.VerifyInitAndLock(settings, source, log, token)) { // Validate source await SourceUtility.ValidateFeedForClient(source, log, token); // Get sleet.settings.json var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; var packageIndex = new PackageIndex(context); var packages = new List <PackageIdentity>(); if (!string.IsNullOrEmpty(version)) { // Delete a single version of the package var packageVersion = NuGetVersion.Parse(version); packages.Add(new PackageIdentity(packageId, packageVersion)); } else { // Delete all versions of the package packages.AddRange(await packageIndex.GetPackagesByIdAsync(packageId)); } if (string.IsNullOrEmpty(reason)) { reason = string.Empty; } foreach (var package in packages) { var exists = await packageIndex.Exists(package); var symbolsExists = await packageIndex.SymbolsExists(package); if (!exists && !symbolsExists) { log.LogInformation($"{package.ToString()} does not exist."); if (force) { // ignore failures continue; } else { throw new InvalidOperationException($"Package does not exists: {package.ToString()}"); } } var message = $"Removing {package.ToString()}"; if (exists && symbolsExists) { message = $"Removing {package.ToString()} and symbols package for {package.ToString()}"; } else if (symbolsExists) { message = $"Removing symbols package {package.ToString()}"; } await log.LogAsync(LogLevel.Information, message); await SleetUtility.RemovePackage(context, package); } // Save all log.LogMinimal($"Committing changes to {source.BaseURI.AbsoluteUri}"); success &= await source.Commit(log, token); } if (success) { log.LogMinimal($"Successfully deleted packages."); } else { log.LogError($"Failed to delete packages."); } return(success); }
private static async Task PushPackage(PackageInput package, SleetContext context, PackageIndex packageIndex, bool force, bool skipExisting, ILogger log) { var packageString = $"{package.Identity.Id} {package.Identity.Version.ToFullString()}"; if (package.IsSymbolsPackage) { packageString += " Symbols"; if (!context.SourceSettings.SymbolsEnabled) { await log.LogAsync(LogLevel.Warning, $"Skipping {packageString}, to push symbols packages enable the symbols server on this feed."); return; } } await log.LogAsync(LogLevel.Minimal, $"Pushing {packageString}"); await log.LogAsync(LogLevel.Information, $"Checking if package exists."); var exists = false; if (package.IsSymbolsPackage) { exists = await packageIndex.SymbolsExists(package.Identity); } else { exists = await packageIndex.Exists(package.Identity); } if (exists) { if (skipExisting) { await log.LogAsync(LogLevel.Minimal, $"Package already exists, skipping {packageString}"); return; } else if (force) { await log.LogAsync(LogLevel.Information, $"Package already exists, removing {packageString}"); // Avoid removing both the symbols and non-symbols packages, this should only // remove the package we are going to replace. if (package.IsSymbolsPackage) { await SleetUtility.RemoveSymbolsPackage(context, package.Identity); } else { await SleetUtility.RemoveNonSymbolsPackage(context, package.Identity); } } else { throw new InvalidOperationException($"Package already exists: {packageString}."); } } await log.LogAsync(LogLevel.Information, $"Adding {packageString}"); using (package) { package.Zip = new ZipArchive(File.OpenRead(package.PackagePath), ZipArchiveMode.Read, leaveOpen: false); package.Package = new PackageArchiveReader(package.Zip); await SleetUtility.AddPackage(context, package); } }
public static async Task <int> RunCore(LocalSettings settings, ISleetFileSystem source, string packageId, string version, string reason, bool force, ILogger log) { var exitCode = 0; var token = CancellationToken.None; var now = DateTimeOffset.UtcNow; // Check if already initialized using (var feedLock = await SourceUtility.VerifyInitAndLock(source, log, token)) { // Validate source await UpgradeUtility.UpgradeIfNeeded(source, log, token); // Get sleet.settings.json var sourceSettings = new SourceSettings(); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; var packageIndex = new PackageIndex(context); var packages = new List <PackageIdentity>(); if (!string.IsNullOrEmpty(version)) { // Delete a single version of the package var packageVersion = NuGetVersion.Parse(version); packages.Add(new PackageIdentity(packageId, packageVersion)); } else { // Delete all versions of the package packages.AddRange(await packageIndex.GetPackagesById(packageId)); } if (string.IsNullOrEmpty(reason)) { reason = string.Empty; } foreach (var package in packages) { if (!await packageIndex.Exists(package)) { log.LogInformation($"{package.ToString()} does not exist."); if (force) { // ignore failures continue; } else { throw new InvalidOperationException($"Package does not exists: {package.ToString()}"); } } log.LogInformation($"Removing {package.ToString()}"); await SleetUtility.RemovePackage(context, package); } // Save all await source.Commit(log, token); } return(exitCode); }
private static Task <PackageSets> GetPackageSets(SleetContext context) { var index = new PackageIndex(context); return(index.GetPackageSetsAsync()); }
/// <summary> /// Create a result containing all versions of the package. The passed in identity /// may or may not be the latest one that is shown. /// </summary> private async Task <JObject> CreatePackageEntry(PackageIdentity package, bool add) { var packageIndex = new PackageIndex(_context); var versions = await packageIndex.GetPackageVersions(package.Id); if (add) { versions.Add(package.Version); } else { versions.Remove(package.Version); } var latest = versions.Max(); var latestIdentity = new PackageIdentity(package.Id, latest); var packageUri = Registrations.GetPackageUri(_context.Source.BaseURI, latestIdentity); var packageEntry = JsonUtility.Create(packageUri, "Package"); var registrationUri = Registrations.GetIndexUri(_context.Source.BaseURI, package.Id); // Read the catalog entry from the package blob. The catalog may not be enabled. var registrations = new Registrations(_context); var catalogEntry = await registrations.GetCatalogEntryFromPackageBlob(latestIdentity); Debug.Assert(catalogEntry != null); packageEntry.Add("registration", registrationUri.AbsoluteUri); var copyProperties = new[] { "id", "version", "description", "summary", "title", "iconUrl", "licenseUrl", "projectUrl", "tags" }; JsonUtility.CopyProperties(catalogEntry, packageEntry, copyProperties, skipEmpty: false); var copyPropertiesDelimited = new[] { "authors", "owners" }; JsonUtility.CopyDelimitedProperties(catalogEntry, packageEntry, copyPropertiesDelimited, ','); JsonUtility.RequireArrayWithEmptyString(packageEntry, new[] { "tags", "authors" }); packageEntry.Add("totalDownloads", 0); var versionsArray = new JArray(); packageEntry.Add("versions", versionsArray); foreach (var version in versions.OrderBy(v => v)) { var versionIdentity = new PackageIdentity(package.Id, version); var versionUri = Registrations.GetPackageUri(_context.Source.BaseURI, versionIdentity); var versionEntry = JsonUtility.Create(versionUri, "Package"); versionEntry.Add("downloads", 0); versionEntry.Add("version", version.ToFullVersionString()); versionsArray.Add(versionEntry); } return(JsonLDTokenComparer.Format(packageEntry)); }
private static async Task PushPackages(List<PackageInput> packageInputs, SleetContext context, PackageIndex packageIndex, bool force, bool skipExisting, ILogger log) { var toAdd = new List<PackageInput>(); var toRemove = new List<PackageInput>(); var existingPackageSets = await packageIndex.GetPackageSetsAsync(); foreach (var package in packageInputs) { var packageString = $"{package.Identity.Id} {package.Identity.Version.ToFullString()}"; if (package.IsSymbolsPackage) { packageString += " Symbols"; if (!context.SourceSettings.SymbolsEnabled) { await log.LogAsync(LogLevel.Warning, $"Skipping {packageString}, to push symbols packages enable the symbols server on this feed."); // Skip this package continue; } } var exists = false; if (package.IsSymbolsPackage) { exists = existingPackageSets.Symbols.Exists(package.Identity); } else { exists = existingPackageSets.Packages.Exists(package.Identity); } if (exists) { if (skipExisting) { await log.LogAsync(LogLevel.Minimal, $"Skip exisiting package: {packageString}"); continue; } else if (force) { toRemove.Add(package); await log.LogAsync(LogLevel.Information, $"Replace existing package: {packageString}"); } else { throw new InvalidOperationException($"Package already exists: {packageString}."); } } else { await log.LogAsync(LogLevel.Minimal, $"Add new package: {packageString}"); } // Add to list of packages to push toAdd.Add(package); } await log.LogAsync(LogLevel.Minimal, $"Processing feed changes"); // Add/Remove packages var changeContext = SleetOperations.Create(existingPackageSets, toAdd, toRemove); await SleetUtility.ApplyPackageChangesAsync(context, changeContext); }
public static async Task <bool> PushPackages(LocalSettings settings, ISleetFileSystem source, List <string> inputs, bool force, bool skipExisting, ILogger log, CancellationToken token) { var exitCode = true; var now = DateTimeOffset.UtcNow; var packages = new List <PackageInput>(); try { // Get packages packages.AddRange(GetPackageInputs(inputs, now, log)); // Get sleet.settings.json await log.LogAsync(LogLevel.Minimal, "Reading feed"); var sourceSettings = await FeedSettingsUtility.GetSettingsOrDefault(source, log, token); // Settings context used for all operations var context = new SleetContext() { LocalSettings = settings, SourceSettings = sourceSettings, Log = log, Source = source, Token = token }; // Fetch feed await SleetUtility.FetchFeed(context); await log.LogAsync(LogLevel.Information, "Reading existing package index"); var packageIndex = new PackageIndex(context); foreach (var package in packages) { await PushPackage(package, context, packageIndex, force, skipExisting, log); } // Save all await log.LogAsync(LogLevel.Minimal, $"Committing changes to {source.BaseURI.AbsoluteUri}"); await source.Commit(log, token); } finally { // Close all zip readers foreach (var package in packages) { package.Dispose(); } } if (exitCode) { await log.LogAsync(LogLevel.Minimal, "Successfully pushed packages."); } else { await log.LogAsync(LogLevel.Error, "Failed to push packages."); } return(exitCode); }