protected bool TryRegisterAddin(ResolutionResult resolutionResult, ResolutionContext ctx, AddinResolution adnResolution, AddinCollision addinCollision) { AddinResolution existingAddin; if (ctx.TryRegisterAddin(resolutionResult, adnResolution.AddinId, adnResolution, out existingAddin)) { return(true); } var key = new AddinCollisionKey(existingAddin.Guid); addinCollision.Add(key, adnResolution, existingAddin); return(false); }
// this method should split the existing addins into the following kind: // 1. updated addins // 2. unaffected addins // 3. directly affected addins // 4. indirectly affected addins // then, decide how to register assets of these addins and whether they need resolution, according to each kind. // and finally, return the addin list that need to be resolved. protected List <AddinResolution> RegisterExistingAssets(ResolutionResult resolutionResult, ResolutionContext ctx, AddinCollision addinCollision) { // ================================================= // 1. 首先确定 AddinStorage 中各个现有 addin 的状态:未受影响的、已更新的、间接受影响的 // check whether there are updated addins. // and if there are any, mark their operation status as updated. List <AddinRecord> updatedAddins = null; for (int i = AddinStorage.AddinRecordCount - 1; i >= 0; i--) { var existingAddin = AddinStorage.Get(i); var addinId = existingAddin.AddinId; AddinResolution adnResolution; // 如果 ResolutionContext 中已存在相同 guid 的插件,则表明这是一个更新的插件 if (!ctx.TryGetAddin(addinId, out adnResolution)) { continue; } AddinStorage.Remove(existingAddin); //AddinRelationManager.RemoveRelationMap(existingAddin); //adnResolution.OperationStatus = AddinOperationStatus.Updated; updatedAddins = updatedAddins ?? new List <AddinRecord>(); updatedAddins.Add(existingAddin); } if (AddinStorage.AddinRecordCount == 0) { return(null); // all addins are updated addins. } // mark directly affected and indirectly affected addins. List <AddinRecord> directlyAffectedAddins = null, indirectlyAffectedAddins = null; if (updatedAddins != null) { directlyAffectedAddins = AddinRelationManager.TryGetAffectingAddins(updatedAddins); if (directlyAffectedAddins != null) { indirectlyAffectedAddins = AddinRelationManager.TryGetAllAffectingAddins(directlyAffectedAddins); //if (indirectlyAffectedAddins != null) //{ // for (int i = indirectlyAffectedAddins.Count - 1; i >= 0; i--) // { // if (directlyAffectedAddins.Contains(indirectlyAffectedAddins[i])) // indirectlyAffectedAddins.RemoveAt(i); // } //} } } // ================================================= // 2. 根据 AddinStorage 中各个现有 addin 的状态,将它们注册到 ResolutionContext if (updatedAddins != null) { foreach (var updatedAddin in updatedAddins) { var ebs = updatedAddin.GetAllExtensionBuilders(); if (ebs != null) { foreach (var eb in ebs) { if (eb.ExtensionBuilderKind == ExtensionBuilderKind.Declared) { // 将已更新插件的 ExtensionBuilderPath 映射注册到 context。 // 因为在解析 Extension 时,是根据 ExtensionBuilderPath 查找 ExtensionBuilder 的,但对于 [directlyAffectedAddins 插件的 Extension] 来说,它们并不 // 保存自身依赖的 updateAddins 的 ExtensionBuilder 的 ExtensionBuilderPath。 // 所以,只能在解析前先将 updateAddins 的 ExtensionBuilder 的 ExtensionBuilderPath 注册到 context,后面解析 [directlyAffectedAddins 插件的 Extension] // 时,才能通过 uid 获得目标 ExtensionBuilder 的 path,继而找到 ExtensionBuilder ctx.RegisterExtensionBuilderPath(eb.Uid, eb.GetPath()); } } } } } List <AddinResolution> resolableAddins = null; // decide how to register assets of these addins and whether to resolve these addins according to their operation status. if (directlyAffectedAddins != null) { foreach (var directlyAffectedAddin in directlyAffectedAddins) { AddinStorage.Remove(directlyAffectedAddin); var resolvableAddin = DoRegisterExistingAddin(resolutionResult, ctx, addinCollision, directlyAffectedAddin, AddinOperationStatus.DirectlyAffected); resolableAddins = resolableAddins ?? new AddinResolutionSet(); resolableAddins.Add(resolvableAddin); } } if (indirectlyAffectedAddins != null) { foreach (var indirectlyAffectedAddin in indirectlyAffectedAddins) { AddinStorage.Remove(indirectlyAffectedAddin); var resolvableAddin = DoRegisterExistingAddin(resolutionResult, ctx, addinCollision, indirectlyAffectedAddin, AddinOperationStatus.IndirectlyAffected); resolableAddins = resolableAddins ?? new AddinResolutionSet(); resolableAddins.Add(resolvableAddin); } } // since the updated, directly affected and indirectly affected, they are all removed, so the rest is unaffected for (int i = AddinStorage.AddinRecordCount - 1; i >= 0; i--) { var unaffectedAddin = AddinStorage.Get(i); AddinStorage.Remove(unaffectedAddin); var resolvableAddin = DoRegisterExistingAddin(resolutionResult, ctx, addinCollision, unaffectedAddin, AddinOperationStatus.Unaffected); resolableAddins = resolableAddins ?? new AddinResolutionSet(); resolableAddins.Add(resolvableAddin); } return(resolableAddins); }
// @return: whether there is collisions. protected bool TryRegisterAssets(ResolutionResult resolutionResult, ResolutionContext ctx, AddinResolution adnResolution, AddinCollision addinCollision) { var success = true; if (adnResolution.Assemblies != null) { for (int i = 0; i < adnResolution.Assemblies.Count; i++) { var asm = adnResolution.Assemblies[i]; if (ctx.TryRegisterAssembly(resolutionResult, asm)) { continue; } // if the assembly loading (with mono.cecil) is failed, it's because this is not a valid managed assembly (might be a native library), // just remove it from the assembly list, and add it to the data file list instead. adnResolution.Assemblies.RemoveAt(i); i -= 1; adnResolution.DataFiles.Add(new DataFileResolution { FilePath = asm.AssemblyFile.FilePath }); } //foreach (var asm in adnResolution.Assemblies) // ctx.TryRegisterAssembly(resolutionResult, asm); } if (adnResolution.ExtensionPoints != null) { foreach (var extensionPoint in adnResolution.ExtensionPoints) { ExtensionPointResolution existingExtensionPoint; if (!ctx.TryRegisterExtensionPoint(resolutionResult, extensionPoint, out existingExtensionPoint)) { var key = new ExtensionPointCollisionKey(existingExtensionPoint.Name); addinCollision.Add(key, adnResolution, existingExtensionPoint.DeclaringAddin); success = false; } } } // get all extension builders defined under extension point and extension builder set var extensionBuilders = adnResolution.GetAllExtensionBuilders(); if (extensionBuilders != null) { foreach (var extensionBuilder in extensionBuilders) { if (extensionBuilder.ExtensionBuilderKind == ExtensionBuilderKind.Referenced) { continue; } ExtensionBuilderResolution existingExtensionBuilder; if (!ctx.TryRegisterExtensionBuilder(resolutionResult, extensionBuilder, out existingExtensionBuilder)) { var key = new ExtensionBuilderCollisionKey(existingExtensionBuilder.Name); addinCollision.Add(key, adnResolution, existingExtensionBuilder.DeclaringAddin); success = false; } } } var extensions = adnResolution.GetAllExtensions(); if (extensions != null) { foreach (var extension in extensions) { ExtensionResolution existingExtension; if (!ctx.TryRegisterExtension(resolutionResult, extension, out existingExtension)) { var key = new ExtensionCollisionKey(existingExtension.Head.Path); addinCollision.Add(key, adnResolution, existingExtension.DeclaringAddin); success = false; } } } return(success); }
// 根据 existingAddin 的状态,将其 Assets 注册到 ResolutionContext AddinResolution DoRegisterExistingAddin(ResolutionResult resolutionResult, ResolutionContext ctx, AddinCollision addinCollision, AddinRecord existingAddin, AddinOperationStatus operationStatus) { //AddinRecord addinRecord; //if (!AddinRelationManager.TryGetAddin(existingAddin.Guid, out addinRecord)) // throw new InconsistentStateException(); ////AddinRelationManager.RemoveAddin(existingAddin); //AddinStorage.Remove(existingAddin); //if (operationStatus == AddinOperationStatus.NewOrUpdated) //{ // var ebs = existingAddin.GetAllExtensionBuilders(); // if (ebs != null) // { // foreach (var eb in ebs) // { // if (eb.ExtensionBuilderKind == ExtensionBuilderKind.Declared) // ctx.RegisterExtensionBuilderPath(eb.Uid, eb.GetPath()); // } // } // return null; //} var adnResolution = FromPersistentObject(existingAddin, operationStatus); TryRegisterAddin(resolutionResult, ctx, adnResolution, addinCollision); DoRegisterExistingAssets(resolutionResult, ctx, adnResolution); // if the operation status of an addin not equals to unaffected (i.e, directly/indirectly affected addin), it need to // be resolved, so we add it to the addin resolution list. return(adnResolution); //return operationStatus == AddinOperationStatus.Unaffected ? null : adnResolution; }
// this method should split the existing addins into the following kind: // 1. updated addins // 2. unaffected addins // 3. directly affected addins // 4. indirectly affected addins // then, decide how to register assets of these addins and whether they need resolution, according to each kind. // and finally, return the addin list that need to be resolved. protected List <AddinResolution> RegisterExistingAssets(IMessageDialog dialog, ResolutionContext ctx, AddinCollision addinCollision, List <AddinResolution> adnResolutions) { // check whether there are updated addins. // and if there are any, mark their operation status as updated. List <AddinIndexRecord> updatedAddins = null; for (int i = 0; i < _indexManager.AddinCount; i++) { var addin = _indexManager.GetAddin(i); var addinId = addin.AddinId; AddinResolution adnResolution; if (!ctx.TryGetAddin(addinId, out adnResolution)) { continue; } updatedAddins = updatedAddins ?? new List <AddinIndexRecord>(); updatedAddins.Add(addin); addin.OperationStatus = AddinOperationStatus.Updated; } // mark directly affected and indirectly affected addins. if (updatedAddins != null) { var directlyAffectedAddins = _indexManager.TryGetAffectedAddins(updatedAddins); if (directlyAffectedAddins != null) { foreach (var directlyAffectedAddin in directlyAffectedAddins) { if (directlyAffectedAddin.OperationStatus != AddinOperationStatus.Updated) { directlyAffectedAddin.OperationStatus = AddinOperationStatus.DirectlyAffected; } } var indirectlyAffectedAddins = _indexManager.TryGetAllAffectedAddins(directlyAffectedAddins); if (indirectlyAffectedAddins != null) { foreach (var indirectlyAffectedAddin in indirectlyAffectedAddins) { if (indirectlyAffectedAddin.OperationStatus == AddinOperationStatus.Unaffected) { indirectlyAffectedAddin.OperationStatus = AddinOperationStatus.IndirectlyAffected; } } } } } List <AddinResolution> resolableAddins = null; // decide how to register assets of these addins and whether to resolve these addins according to their operation status. for (int i = _indexManager.AddinCount - 1; i >= 0; i--) { var addin = _indexManager.GetAddin(i); var resolvableAddin = DoRegisterExistingAddin(dialog, ctx, addinCollision, addin, adnResolutions); if (resolvableAddin != null) { resolableAddins = resolableAddins ?? new AddinResolutionSet(); resolableAddins.Add(resolvableAddin); } } return(resolableAddins); }
// @return: whether there is collisions. protected bool TryRegisterAssets(IMessageDialog dialog, ResolutionContext ctx, AddinResolution adnResolution, AddinCollision addinCollision) { var success = true; if (adnResolution.Assemblies != null) { foreach (var asm in adnResolution.Assemblies) { ctx.TryRegisterAssembly(dialog, asm); } } if (adnResolution.ExtensionPoints != null) { foreach (var extensionPoint in adnResolution.ExtensionPoints) { ExtensionPointResolution existingExtensionPoint; if (!ctx.TryRegisterExtensionPoint(dialog, extensionPoint, out existingExtensionPoint)) { var key = new ExtensionPointCollisionKey(existingExtensionPoint.Id); addinCollision.Add(key, adnResolution, existingExtensionPoint.DeclaringAddin); success = false; } } } // get all extension builders defined under extension point and extension builder set var extensionBuilders = adnResolution.GetAllExtensionBuilders(); if (extensionBuilders != null) { foreach (var extensionBuilder in extensionBuilders) { if (extensionBuilder.ExtensionBuilderKind == ExtensionBuilderKind.Referenced) { continue; } ExtensionBuilderResolution existingExtensionBuilder; if (!ctx.TryRegisterExtensionBuilder(dialog, extensionBuilder, out existingExtensionBuilder)) { var key = new ExtensionBuilderCollisionKey(existingExtensionBuilder.Id); addinCollision.Add(key, adnResolution, existingExtensionBuilder.DeclaringAddin); success = false; } } } var extensions = adnResolution.GetAllExtensions(); if (extensions != null) { foreach (var extension in extensions) { ExtensionResolution existingExtension; if (!ctx.TryRegisterExtension(dialog, extension, out existingExtension)) { var key = new ExtensionCollisionKey(existingExtension.Head.Path); addinCollision.Add(key, adnResolution, existingExtension.DeclaringAddin); success = false; } } } return(success); }
AddinResolution DoRegisterExistingAddin(IMessageDialog dialog, ResolutionContext ctx, AddinCollision addinCollision, AddinIndexRecord existingAddin, List <AddinResolution> adnResolutions) { AddinBodyRecord addinBody; if (!_bodyRepo.TryGet(existingAddin.Guid, out addinBody)) { throw new InconsistentStateException(); } _indexManager.RemoveAddin(existingAddin); _bodyRepo.Remove(addinBody); if (existingAddin.OperationStatus == AddinOperationStatus.Updated) { var ebs = addinBody.GetAllExtensionBuilders(); if (ebs != null) { foreach (var eb in ebs) { if (eb.ExtensionBuilderKind == ExtensionBuilderKind.Declared) { ctx.RegisterExtensionBuilderPath(eb.Uid, eb.GetPath()); } } } return(null); } var adnResolution = FromPersistentObject(new AddinRecord { AddinBody = addinBody, AddinIndex = existingAddin }); TryRegisterAddin(dialog, ctx, adnResolution, addinCollision); DoRegisterExistingAssets(dialog, ctx, adnResolution); // if the operation status of an addin not equals to unaffected (i.e, directly/indirectly affected addin), it need to // be resolved, so we add it to the addin resolution list. return(existingAddin.OperationStatus == AddinOperationStatus.Unaffected ? null : adnResolution); }
internal override bool Resolve(IMessageDialog dialog, FilePackResult filePackResult) { // try parsing the new (or updated) addin manifests (configuration) var adnResolutions = TryParseAddins(dialog, filePackResult.AddinFilePacks); if (adnResolutions == null) { return(false); } var ctx = new ResolutionContext(); var addinCollision = new AddinCollision(); // try to register id of new addins at first, so that we can tell whether there are // any updated addins when registering that of the existing addins. foreach (var adnResolution in adnResolutions) { TryRegisterAddin(dialog, ctx, adnResolution, addinCollision); } // register all assets of existing addins to the context (skipping updated addins) List <AddinResolution> resolableAddins = null; if (_indexManager.AddinCount > 0) { resolableAddins = RegisterExistingAssets(dialog, ctx, addinCollision, adnResolutions); } // try to register assets of new and updated addins to the context foreach (var adnResolution in adnResolutions) { TryRegisterAssets(dialog, ctx, adnResolution, addinCollision); } if (resolableAddins != null) { adnResolutions.AddRange(resolableAddins); } // tries to resolve all addin, and make sure: // 1. there is no cirular dependencies between the resolved addins. // 2. the resolved addin list is sorted by the dependency. adnResolutions = TryResolveAddins(dialog, _convertionManager, ctx, adnResolutions); if (ResolutionFailed(dialog, ctx, adnResolutions)) { return(false); } // if there is any conflicting addins, trim them and all addins that depends on them. if (addinCollision.Count > 0) { TrimConflictingAddins(addinCollision, adnResolutions); if (ResolutionFailed(dialog, ctx, adnResolutions)) { return(false); } } // save all new and/or updated addin records to persistent file. PersistAddinRecords(ctx, adnResolutions); ctx.Dispose(); return(true); }
internal override ResolutionResult Resolve(INameConvention nameConvention, ResolutionContext ctx, ScanFilePackResult scanFilePackResult) { var resolutionResult = new ResolutionResult(); // try parsing the new (or updated) addin manifests (configuration) var adnResolutions = TryParseAddins(nameConvention, resolutionResult, scanFilePackResult.ScanFilePacks); if (adnResolutions == null) { resolutionResult.NewAddinsFound = false; return(resolutionResult); } var addinCollision = new AddinCollision(); // try to register id of new addins at first, so that we can tell whether there are // any updated addins when registering that of the existing addins. foreach (var adnResolution in adnResolutions) { TryRegisterAddin(resolutionResult, ctx, adnResolution, addinCollision); } // register all assets of existing addins to the context (skipping updated addins) List <AddinResolution> resolableAddins = null; if (AddinStorage.AddinRecordCount > 0) { resolableAddins = RegisterExistingAssets(resolutionResult, ctx, addinCollision); } // try to register assets of new and updated addins to the context foreach (var adnResolution in adnResolutions) { TryRegisterAssets(resolutionResult, ctx, adnResolution, addinCollision); } if (resolableAddins != null) { adnResolutions.AddRange(resolableAddins); } // tries to resolve all addin, and make sure: // 1. there is no cirular dependencies between the resolved addins. // 2. the resolved addin list is sorted by the dependency. var resolvedAddins = TryResolveAddins(resolutionResult, ConvertionManager, ctx, adnResolutions); if (adnResolutions.Count > 0) { StoreUnresolvableAddins(adnResolutions); // 剩余的 adnResolutions 即为未成功解析的插件,此处也要将它们持久化 } if (ResolutionFailed(resolutionResult, ctx, resolvedAddins)) { resolutionResult.NewAddinsFound = false; return(resolutionResult); } // if there is any conflicting addins, trim them and all addins that depends on them. if (addinCollision.Count > 0) { TrimConflictingAddins(addinCollision, resolvedAddins); // recursively if (ResolutionFailed(resolutionResult, ctx, resolvedAddins)) { resolutionResult.NewAddinsFound = false; return(resolutionResult); } } // save all resolvable addin records to persistent file. StoreResolvedAddins(resolutionResult, ctx, resolvedAddins); PersistAddinStorage(resolutionResult); ctx.Dispose(); resolutionResult.NewAddinsFound = true; return(resolutionResult); }