Example #1
0
 internal void Combine(PackagingResult other)
 {
     Successful  &= other.Successful;
     Terminated  |= other.Terminated;
     NeedRestart |= other.NeedRestart;
     Errors      += other.Errors;
 }
        internal static Dictionary <Version, PackagingResult> ExecuteAssemblyPatches(SnComponentInfo assemblyComponent,
                                                                                     RepositoryStartSettings settings = null)
        {
            var patchResults = new Dictionary <Version, PackagingResult>();

            // If there is no installed component for this id, skip patching.
            var installedComponent = RepositoryVersionInfo.Instance.Components.FirstOrDefault(c => c.ComponentId == assemblyComponent.ComponentId);

            if (installedComponent == null)
            {
                return(patchResults);
            }

            // check which db version is supported by the assembly
            if (assemblyComponent.SupportedVersion == null ||
                assemblyComponent.SupportedVersion <= installedComponent.Version)
            {
                return(patchResults);
            }

            // Supported version in the assembly is higher than
            // the physical version: there should be a patch.
            if (!(assemblyComponent.Patches?.Any() ?? false))
            {
                throw new InvalidOperationException($"Missing patch for component {installedComponent.ComponentId}. " +
                                                    $"Installed version is {installedComponent.Version}. " +
                                                    $"The assembly requires at least version {assemblyComponent.SupportedVersion}.");
            }

            foreach (var patch in assemblyComponent.Patches)
            {
                // this variable is refreshed in every cycle
                if (installedComponent == null)
                {
                    break;
                }

                if (patch.MinVersion > patch.MaxVersion ||
                    patch.MaxVersion > patch.Version)
                {
                    // the patch version numbers are the responsibility of the developer of the component
                    SnLog.WriteWarning(
                        $"Patch {patch.Version} for component {assemblyComponent.ComponentId} cannot be executed because it contains invalid version numbers.",
                        properties: new Dictionary <string, object>
                    {
                        { "MinVersion", patch.MinVersion },
                        { "MaxVersion", patch.MaxVersion }
                    });

                    continue;
                }

                if (!string.IsNullOrEmpty(patch.Contents) && patch.Execute != null)
                {
                    // ambigous patch definition
                    SnLog.WriteWarning(
                        $"Patch {patch.Version} for component {assemblyComponent.ComponentId} cannot be executed because it contains multiple patch definitions.");

                    continue;
                }

                // check if the patch is relevant for the currently installed component version
                if (patch.MinVersion > installedComponent.Version ||
                    patch.MinVersionIsExclusive && patch.MinVersion == installedComponent.Version ||
                    patch.MaxVersion < installedComponent.Version ||
                    patch.MaxVersionIsExclusive && patch.MaxVersion == installedComponent.Version)
                {
                    continue;
                }

                PackagingResult patchResult;

                try
                {
                    if (patch.Contents?.StartsWith("<?xml", StringComparison.InvariantCultureIgnoreCase) ?? false)
                    {
                        // execute manifest patch
                        patchResult = ExecutePatch(patch.Contents, settings);
                    }
                    else if (patch.Execute != null)
                    {
                        // execute code patch
                        patch.Execute(new PatchContext
                        {
                            Settings = settings
                        });

                        // save the new package info manually based on the patch version number
                        Storage.SavePackageAsync(new Package
                        {
                            ComponentId      = assemblyComponent.ComponentId,
                            ComponentVersion = patch.Version,
                            ExecutionResult  = ExecutionResult.Successful,
                            PackageType      = PackageType.Patch
                        }, CancellationToken.None).GetAwaiter().GetResult();

                        patchResult = new PackagingResult
                        {
                            NeedRestart = false,
                            Successful  = true,
                            Terminated  = false,
                            Errors      = 0
                        };
                    }
                    else
                    {
                        //TODO: handle other patch formats (resource or filesystem path)

                        // unknown patch format
                        patchResult = new PackagingResult
                        {
                            NeedRestart = false,
                            Successful  = false,
                            Terminated  = false,
                            Errors      = 0
                        };
                    }
                }
                catch (Exception ex)
                {
                    SnLog.WriteException(ex,
                                         $"Error during patch execution for component {assemblyComponent.ComponentId}. Patch target version: {patch.Version}.");

                    throw;
                }

                patchResults[patch.Version] = patchResult;

                // reload
                installedComponent = RepositoryVersionInfo.Instance.Components.FirstOrDefault(c =>
                                                                                              c.ComponentId == assemblyComponent.ComponentId);
            }

            return(patchResults);
        }