internal PluginAssemblyInfo FindOrCreate(Runner.PluginAssemblyInfo assembly) { Debug.Assert(assembly != null); PluginAssemblyInfo f; if (!_dicAssemblies.TryGetValue(assembly.AssemblyFileName, out f)) { f = new PluginAssemblyInfo(_discoverer); _dicAssemblies.Add(assembly.AssemblyFileName, f); _hasBeenDiscovered.Add(f); f.Initialize(this, assembly); _newAssemblies.Add(f); if (assembly.HasPluginsOrServices) { _discoverer._pluginOrServiceAssemblies.Add(f); } } else { Debug.Assert(f != null && (_hasBeenDiscovered.Contains(f) || (f.LastChangedVersion != _discoverer.CurrentVersion))); if (f.LastChangedVersion != _discoverer.CurrentVersion && !_hasBeenDiscovered.Contains(f)) { _hasBeenDiscovered.Add(f); if (f.Merge(this, assembly)) { _changedAssemblies.Add(f); } } } return(f); }
internal ServiceInfo(PluginAssemblyInfo a, Type t) { _assembly = a; _assemblyQualifiedName = t.AssemblyQualifiedName; _serviceFullName = t.FullName; _isDynamicService = PluginDiscoverer.IsIDynamicService(t); _impl = new List <PluginInfo>(); _eventsInfoCollection = new List <SimpleEventInfo>(); _methodsInfoCollection = new List <SimpleMethodInfo>(); _propertiesInfoCollection = new List <SimplePropertyInfo>(); }
// When a IServiceInfo (ex : interface ICommonTimer) is found in an assembly. ServiceInfo RegisterServiceInfo(PluginAssemblyInfo a, Type t) { string assemblyQualifiedName = t.AssemblyQualifiedName; ServiceInfo serv; if (!_dicAllServices.TryGetValue(assemblyQualifiedName, out serv)) { serv = new ServiceInfo(a, t); _dicAllServices.Add(assemblyQualifiedName, serv); _services.Add(serv); } else if (serv.AssemblyInfo == null) { serv.AssemblyInfo = a; _services.Add(serv); _notFoundServices.Remove(serv); } return(serv); }
internal void Initialize(PluginDiscoverer.Merger merger, Runner.PluginAssemblyInfo r) { base.Initialize(r); _fileName = r.AssemblyFileName; _assemblyName = r.AssemblyName; _fileSize = r.AssemblyFileSize; foreach (Runner.PluginInfo plugin in r.Plugins) { _pluginsCollection.Add(merger.FindOrCreate(plugin)); } foreach (Runner.ServiceInfo service in r.Services) { _servicesCollection.Add(merger.FindOrCreate(service)); } _plugins = new ReadOnlyListOnIList <PluginInfo>(_pluginsCollection); _services = new ReadOnlyListOnIList <ServiceInfo>(_servicesCollection); }
internal bool Merge(PluginDiscoverer.Merger merger, Runner.PluginAssemblyInfo r) { bool hasChanged = false; if (_fileName != r.AssemblyFileName) { _fileName = r.AssemblyFileName; hasChanged = true; } // AssemblyName does not override Equals. // We use the Fullname This is perfect for strongly signed assembly, not necessary // for unsigned ones. // This is why we added the file size to the AssemblyInfo: file size gives // us a way to detect file change even if its name (typically through its version) is not updated. bool rHasAssemblyName = r.AssemblyName != null; if ((_assemblyName != null) != rHasAssemblyName || (rHasAssemblyName && _assemblyName.FullName != r.AssemblyName.FullName)) { _assemblyName = r.AssemblyName; hasChanged = true; } if (_fileSize != r.AssemblyFileSize) { _fileSize = r.AssemblyFileSize; hasChanged = true; } if (PluginDiscoverer.Merger.GenericMergeLists(_pluginsCollection, r.Plugins, merger.FindOrCreate, null)) { hasChanged = true; } if (PluginDiscoverer.Merger.GenericMergeLists(_servicesCollection, r.Services, merger.FindOrCreate, null)) { hasChanged = true; } return(Merge(r, hasChanged)); }
/// <summary> /// For each FileInfo in _currentFiles, Process will try to create a new PluginAssemblyInfo /// based on the FileInfo (that is currently processed). /// After that, this method fill properties collections with IPluginInfo or IServiceInfo. /// </summary> public RunnerDataHolder Discover(IEnumerable <FileInfo> files) { // Transforms FileInfo into PluginAssemblyInfo. foreach (FileInfo f in files) { PluginAssemblyInfo a; string fName = f.FullName; if (!_filesProcessed.TryGetValue(fName, out a)) { Assembly assembly = null; try { assembly = Assembly.ReflectionOnlyLoadFrom(fName); a = new PluginAssemblyInfo(assembly, f); _assembliesByName.Add(assembly.FullName, a); } catch (Exception ex) { a = new PluginAssemblyInfo(fName); a.AddErrorLine(ex.Message); } _filesProcessed.Add(fName, a); } } foreach (var e in _assembliesByName) { e.Value.LoadDependencies(); } foreach (var e in _assembliesByName) { PluginAssemblyInfo a = e.Value; if (!a.HasError) { Debug.Assert(a.ErrorMessage == null); try { a.ReadAllTypes(RegisterServiceInfo, RegisterUseServiceInfo); } catch (Exception ex) { a.AddErrorLine(ex.Message); } } } // Consider DynamicService without any definition assembly as an error. foreach (ServiceInfo serviceInfo in _dicAllServices.Values) { if (serviceInfo.IsDynamicService && serviceInfo.AssemblyInfo == null) { serviceInfo.AddErrorLine(R.AssemblyNotFoundForDynamicService); } } // Fills _existingPlugins, updates _pluginsById (keep only the best version), removes old plugins from Assembly.Plugins collection. foreach (var e in _assembliesByName) { PluginAssemblyInfo a = e.Value; if (!a.HasError) { List <PluginInfo> toRemove = new List <PluginInfo>(); foreach (PluginInfo pluginInfo in a.Plugins) { // Transfer any pluginInfo.Service.HasError to pluginInfo.HasError. if (pluginInfo.Service != null && pluginInfo.Service.HasError) { pluginInfo.AddErrorLine(R.ImplementedServiceIsOnError); } // Errors on the ServiceReferences are propagated up to the plugin object // only if the reference "Must Exist": references that are optional do not transfer errors. foreach (var i in pluginInfo.ServiceReferences) { if (i.HasError && i.Requirements > RunningRequirement.OptionalTryStart) { pluginInfo.AddErrorLine(String.Format("Dependency {0} is on error: {1}", i.PropertyName, i.ErrorMessage)); } } _existingPlugins.Add(pluginInfo); PluginInfo dicPlugin; if (_pluginsById.TryGetValue(pluginInfo.PluginId, out dicPlugin)) { if (dicPlugin.Version >= pluginInfo.Version) { pluginInfo.IsOldVersion = true; if (pluginInfo.Service != null) { pluginInfo.Service.Implementations.Remove(pluginInfo); } _oldPlugins.Add(pluginInfo); toRemove.Add(pluginInfo); } else if (dicPlugin.Version < pluginInfo.Version) { _pluginsById.Remove(dicPlugin.PluginId); _pluginsById.Add(pluginInfo.PluginId, pluginInfo); dicPlugin.IsOldVersion = true; if (dicPlugin.Service != null) { dicPlugin.Service.Implementations.Remove(dicPlugin); } _oldPlugins.Add(dicPlugin); toRemove.Add(dicPlugin); } } else { _pluginsById.Add(pluginInfo.PluginId, pluginInfo); } } // We remove old plugins from assemblyInfo foreach (PluginInfo oldPlugin in toRemove) { a.Plugins.Remove(oldPlugin); } } } // Then we put the editors into edited plugins. foreach (PluginInfo plugin in _pluginsById.Values) { foreach (PluginConfigAccessorInfo editor in plugin.EditorsInfo) { PluginInfo editedPlugin; if (_pluginsById.TryGetValue(editor.Source, out editedPlugin)) { editedPlugin.EditableBy.Add(editor); } } } foreach (PluginAssemblyInfo assembly in _filesProcessed.Values) { assembly.NormalizeCollections(); } foreach (PluginInfo plugin in _oldPlugins) { plugin.NormalizeCollections(); } foreach (PluginInfo plugin in _existingPlugins) { plugin.NormalizeCollections(); } foreach (ServiceInfo service in _dicAllServices.Values) { service.NormalizeCollections(); } PluginAssemblyInfo[] allAssemblies = _filesProcessed.Values.ToArray(); Array.Sort(allAssemblies); PluginInfo[] oldPlugins = _oldPlugins.ToArray(); Array.Sort(oldPlugins); ServiceInfo[] notFoundServices = _notFoundServices.ToArray(); Array.Sort(notFoundServices); return(new RunnerDataHolder( allAssemblies, oldPlugins, notFoundServices )); }