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);
            }
Exemple #2
0
 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
                       ));
        }