Esempio n. 1
0
        public ISnPatch[] GetExecutablePatches(IEnumerable <ISnPatch> candidates,
                                               SnComponentDescriptor[] installedComponents, PatchExecutionContext context, out SnComponentDescriptor[] componentsAfter)
        {
            var patches = candidates.ToArray();

            var installedIds = installedComponents
                               .Where(x => x.Version != null && x.Version > NullVersion)
                               .Select(x => x.ComponentId)
                               .ToArray();

            var installers = patches
                             .Where(x => x.Type == PackageType.Install && !installedIds.Contains(x.ComponentId))
                             .OrderBy(x => x.ComponentId)
                             .ToArray();
            var installerGroups = installers.GroupBy(x => x.ComponentId);
            var duplicates      = installerGroups.Where(x => x.Count() > 1).Select(x => x.Key).ToArray();

            if (duplicates.Length > 0)
            {
                // Duplicates are not allowed
                foreach (var id in duplicates)
                {
                    var message       = "There is a duplicated installer for the component " + id;
                    var faultyPatches = installers.Where(inst => inst.ComponentId == id).ToArray();
                    var error         = new PatchExecutionError(PatchExecutionErrorType.DuplicatedInstaller, faultyPatches, message);
                    var logRecord     = new PatchExecutionLogRecord(PatchExecutionEventType.DuplicatedInstaller, faultyPatches.First(), message);
                    context.Errors.Add(error);
                    context.LogCallback(logRecord);
                }

                // Set unchanged list as output
                componentsAfter = installedComponents.ToArray();
                return(new ISnPatch[0]);
            }

            // Order patches by componentId and versions
            var orderedSnPatches = patches
                                   .Where(x => x.Type == PackageType.Patch)
                                   .OrderBy(x => x.ComponentId).ThenBy(x => x.Version)
                                   .ToArray();

            // ------------------------------------------------------------ sorting by dependencies
            var inputList        = installers.Union(orderedSnPatches).ToList();
            var outputList       = new List <ISnPatch>();                                 // patches in right order to execute
            var installed        = new List <SnComponentDescriptor>(installedComponents); // all simulated components.
            var currentlyManaged = new List <ISnPatch>();                                 // temporary list in one iteration.

            while (true)
            {
                foreach (var item in inputList)
                {
                    if (CheckPrerequisites(item, installed, out var skipExecution, out var error))
                    {
                        currentlyManaged.Add(item);
                        outputList.Add(item);

                        if (item is SnPatch snPatch)
                        {
                            // Modify version and dependencies of the installed components.
                            var patchedComponent = installed.Single(x => x.ComponentId == snPatch.ComponentId);
                            patchedComponent.Version      = (Version)snPatch.Version.Clone();
                            patchedComponent.Dependencies = snPatch.Dependencies?.ToArray();
                        }
                        else if (item is ComponentInstaller installer)
                        {
                            // Add to installed components.
                            installed.Add(new SnComponentDescriptor(installer.ComponentId, installer.Version,
                                                                    installer.Description, installer.Dependencies?.ToArray()));
                        }
                        else
                        {
                            throw new SnNotSupportedException();
                        }
                    }
 private static void DefaultLogCallback(PatchExecutionLogRecord msg)
 {
     // do nothing
 }
Esempio n. 3
0
        private void RecognizeErrors(List <ISnPatch> notExecutables, List <ISnPatch> candidates, List <SnComponentDescriptor> installed, bool onBefore)
        {
            // Recognize duplicated installers
            var installers = notExecutables
                             .Where(x => x.Type == PackageType.Install)
                             .OrderBy(x => x.ComponentId)
                             .ToArray();
            var installerGroups = installers.GroupBy(x => x.ComponentId);
            var duplicates      = installerGroups.Where(x => x.Count() > 1).Select(x => x.Key).ToArray();

            if (duplicates.Length > 0)
            {
                // Duplicates are not allowed
                foreach (var id in duplicates)
                {
                    var message       = "There is a duplicated installer for the component " + id;
                    var faultyPatches = installers.Where(inst => inst.ComponentId == id).ToArray();
                    var error         = new PatchExecutionError(PatchExecutionErrorType.DuplicatedInstaller, faultyPatches, message);
                    var logRecord     = new PatchExecutionLogRecord(PatchExecutionEventType.DuplicatedInstaller, faultyPatches.First(), message);
                    _context.Errors.Add(error);
                    _context.LogCallback(logRecord);
                    notExecutables = notExecutables.Except(faultyPatches).ToList();
                    foreach (var item in faultyPatches)
                    {
                        // notExecutables and candidates maybe the same
                        notExecutables.Remove(item);
                        candidates.Remove(item);
                    }
                }
            }

            // Recognize remaining items
            var toRemove = new List <ISnPatch>();

            foreach (var patch in notExecutables)
            {
                if (!onBefore)
                {
                    toRemove.Add(patch);
                }

                if (patch is SnPatch snPatch)
                {
                    if (!installed.Any(comp => comp.ComponentId == snPatch.ComponentId &&
                                       (comp.Version == null || comp.Version < patch.Version) &&
                                       snPatch.Boundary.ContainsVersion(comp.Version)))
                    {
                        var component = installed.FirstOrDefault(c => c.ComponentId == patch.ComponentId);
                        var message   = component == null
                            ? $"Cannot execute the patch [{patch}] {(onBefore ? "before" : "after")} " +
                                        "repository start because the component is not yet installed."
                            : $"Cannot execute the patch [{patch}] {(onBefore ? "before" : "after")} " +
                                        $"repository start because the component's version is small: [{component}].";
                        _context.LogCallback(
                            new PatchExecutionLogRecord(PatchExecutionEventType.CannotExecuteMissingVersion,
                                                        patch, message));
                        _context.Errors.Add(new PatchExecutionError(PatchExecutionErrorType.MissingVersion,
                                                                    patch, message));
                    }
                }
                else
                {
                    var message = $"Cannot execute the patch [{patch}] {(onBefore ? "before" : "after")} repository start.";
                    _context.LogCallback(new PatchExecutionLogRecord(
                                             onBefore
                            ? PatchExecutionEventType.CannotExecuteOnBefore
                            : PatchExecutionEventType.CannotExecuteOnAfter,
                                             patch, message));
                    _context.Errors.Add(new PatchExecutionError(
                                            onBefore
                            ? PatchExecutionErrorType.CannotExecuteOnBefore
                            : PatchExecutionErrorType.CannotExecuteOnAfter,
                                            patch, message + $" [{patch}]"));
                }
            }
            foreach (var item in toRemove)
            {
                candidates.Remove(item);
            }
        }