예제 #1
0
        /// <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);
        }
예제 #2
0
파일: Search.cs 프로젝트: skarllot/Sleet
        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);
        }
예제 #3
0
        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);
                }
            }
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        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);
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
            }
        }
예제 #11
0
        /// <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);
        }
예제 #12
0
        /// <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);
        }
예제 #13
0
        /// <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);
        }
예제 #14
0
        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);
        }
예제 #15
0
파일: DeleteCommand.cs 프로젝트: gmfx/Sleet
        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);
        }
예제 #16
0
        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);
            }
        }
예제 #17
0
        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);
        }
예제 #18
0
        private static Task <PackageSets> GetPackageSets(SleetContext context)
        {
            var index = new PackageIndex(context);

            return(index.GetPackageSetsAsync());
        }
예제 #19
0
파일: Search.cs 프로젝트: skarllot/Sleet
        /// <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));
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
        }