public AddinScanner(AddinDatabase database, AddinScanResult scanResult, IProgressStatus monitor) { this.database = database; if (!scanResult.CheckOnly) { // If there is a local copy of the cecil reflector, use it instead of the one in the gac Type t; string asmFile = Path.Combine (Path.GetDirectoryName (GetType().Assembly.Location), "Mono.Addins.CecilReflector.dll"); if (File.Exists (asmFile)) { Assembly asm = Assembly.LoadFrom (asmFile); t = asm.GetType ("Mono.Addins.CecilReflector.Reflector"); } else { string refName = GetType().Assembly.FullName; int i = refName.IndexOf (','); refName = "Mono.Addins.CecilReflector.Reflector, Mono.Addins.CecilReflector" + refName.Substring (i); t = Type.GetType (refName, false); } if (t != null) reflector = (IAssemblyReflector) Activator.CreateInstance (t); else reflector = new DefaultAssemblyReflector (); if (monitor.LogLevel > 1) monitor.Log ("Using assembly reflector: " + reflector.GetType ()); reflector.Initialize (scanResult); coreAssembly = reflector.LoadAssembly (GetType().Assembly.Location); } }
public AddinScanner(AddinDatabase database, AddinScanResult scanResult, IProgressStatus monitor) { this.database = database; if (!scanResult.CheckOnly) { string refName = GetType().Assembly.FullName; int i = refName.IndexOf(','); refName = "Mono.Addins.CecilReflector.Reflector, Mono.Addins.CecilReflector" + refName.Substring(i); Type t = Type.GetType(refName, false); if (t != null) { reflector = (IAssemblyReflector)Activator.CreateInstance(t); } else { reflector = new DefaultAssemblyReflector(); } if (monitor.LogLevel > 1) { monitor.Log("Using assembly reflector: " + reflector.GetType()); } reflector.Initialize(scanResult); coreAssembly = reflector.LoadAssembly(GetType().Assembly.Location); } }
void ScanAssemblyAddinHeaders(AddinDescription config, Assembly asm, AddinScanResult scanResult) { // Get basic add-in information AddinAttribute att = (AddinAttribute)Attribute.GetCustomAttribute(asm, typeof(AddinAttribute), false); if (att != null) { if (att.Id.Length > 0) { config.LocalId = att.Id; } if (att.Version.Length > 0) { config.Version = att.Version; } if (att.Namespace.Length > 0) { config.Namespace = att.Namespace; } if (att.Category.Length > 0) { config.Category = att.Category; } config.IsRoot = att is AddinRootAttribute; } }
bool ScanAssembly(IProgressStatus monitor, string filePath, AddinScanResult scanResult, out AddinDescription config) { config = null; try { Assembly asm = Util.LoadAssemblyForReflection(filePath); // Get the config file from the resources, if there is one string configFile = null; foreach (string res in asm.GetManifestResourceNames()) { if (res.EndsWith(".addin") || res.EndsWith(".addin.xml")) { configFile = res; break; } } if (configFile != null) { using (Stream s = asm.GetManifestResourceStream(configFile)) { string asmFile = new Uri(asm.CodeBase).LocalPath; config = AddinDescription.Read(s, Path.GetDirectoryName(asmFile)); } } else { // On this case, only scan the assembly if it has the Addin attribute. AddinAttribute att = (AddinAttribute)Attribute.GetCustomAttribute(asm, typeof(AddinAttribute), false); if (att == null) { config = null; return(true); } config = new AddinDescription(); } config.BasePath = Path.GetDirectoryName(filePath); config.AddinFile = filePath; string rasmFile = Path.GetFileName(filePath); if (!config.MainModule.Assemblies.Contains(rasmFile)) { config.MainModule.Assemblies.Add(rasmFile); } return(ScanDescription(monitor, config, asm, scanResult)); } catch (Exception ex) { // Something went wrong while scanning the assembly. We'll ignore it for now. monitor.ReportError("There was an error while scanning assembly: " + filePath, ex); return(false); } }
public static void AddDependencies (AddinDescription desc, AddinScanResult scanResult) { // Not implemented in AddinScanResult to avoid making AddinDescription remotable foreach (ModuleDescription mod in desc.AllModules) { foreach (Dependency dep in mod.Dependencies) { AddinDependency adep = dep as AddinDependency; if (adep == null) continue; string depid = Addin.GetFullId (desc.Namespace, adep.AddinId, adep.Version); scanResult.AddAddinToUpdateRelations (depid); } } }
public void ScanFolderRec(IProgressStatus monitor, string dir, AddinScanResult scanResult) { ScanFolder(monitor, dir, scanResult); if (!Directory.Exists(dir)) { return; } foreach (string sd in Directory.GetDirectories(dir)) { ScanFolderRec(monitor, sd, scanResult); } }
void RegisterFileToScan(IProgressStatus monitor, string file, AddinScanResult scanResult, AddinScanFolderInfo folderInfo) { if (scanResult.LocateAssembliesOnly) { return; } AddinFileInfo finfo = folderInfo.GetAddinFileInfo(file); bool added = false; if (finfo != null && File.GetLastWriteTime(file) == finfo.LastScan && !scanResult.RegenerateAllData) { if (finfo.ScanError) { // Always schedule the file for scan if there was an error in a previous scan. // However, don't set ChangesFound=true, in this way if there isn't any other // change in the registry, the file won't be scanned again. scanResult.AddFileToScan(file, folderInfo); added = true; } if (finfo.AddinId == null || finfo.AddinId.Length == 0) { return; } if (!finfo.IsRoot) { if (database.AddinDescriptionExists(finfo.AddinId)) { return; } } else { if (database.HostDescriptionExists(finfo.AddinId, file)) { return; } } } scanResult.ChangesFound = true; if (!scanResult.CheckOnly && !added) { scanResult.AddFileToScan(file, folderInfo); } }
public AddinDescription ScanSingleFile(IProgressStatus monitor, string file, AddinScanResult scanResult) { AddinDescription config = null; if (monitor.LogLevel > 1) { monitor.Log("Scanning file: " + file); } monitor.Log("plog:scan:" + file); try { string ext = Path.GetExtension(file); bool scanSuccessful; if (ext == ".dll" || ext == ".exe") { scanSuccessful = ScanAssembly(monitor, file, scanResult, out config); } else { scanSuccessful = ScanConfigAssemblies(monitor, file, scanResult, out config); } if (scanSuccessful && config != null) { config.Domain = "global"; if (config.Version.Length == 0) { config.Version = "0.0.0.0"; } if (config.LocalId.Length == 0) { // Generate an internal id for this add-in config.LocalId = database.GetUniqueAddinId(file, "", config.Namespace, config.Version); } } } catch (Exception ex) { monitor.ReportError("Unexpected error while scanning file: " + file, ex); } finally { monitor.Log("plog:endscan"); } return(config); }
public static void AddDependencies(AddinDescription desc, AddinScanResult scanResult) { // Not implemented in AddinScanResult to avoid making AddinDescription remotable foreach (ModuleDescription mod in desc.AllModules) { foreach (Dependency dep in mod.Dependencies) { AddinDependency adep = dep as AddinDependency; if (adep == null) { continue; } string depid = Addin.GetFullId(desc.Namespace, adep.AddinId, adep.Version); scanResult.AddAddinToUpdateRelations(depid); } } }
void RegisterFileToScan(IProgressStatus monitor, string file, AddinScanResult scanResult, AddinScanFolderInfo folderInfo) { if (scanResult.LocateAssembliesOnly) { return; } AddinFileInfo finfo = folderInfo.GetAddinFileInfo(file); bool added = false; if (finfo != null && (!finfo.IsAddin || finfo.Domain == folderInfo.GetDomain(finfo.IsRoot)) && File.GetLastWriteTime(file) == finfo.LastScan && !scanResult.RegenerateAllData) { if (finfo.ScanError) { // Always schedule the file for scan if there was an error in a previous scan. // However, don't set ChangesFound=true, in this way if there isn't any other // change in the registry, the file won't be scanned again. scanResult.AddFileToScan(file, folderInfo); added = true; } if (!finfo.IsAddin) { return; } if (database.AddinDescriptionExists(finfo.Domain, finfo.AddinId)) { // It is an add-in and it has not changed. Paths in the ignore list // are still valid, so they can be used. if (finfo.IgnorePaths != null) { scanResult.AddPathsToIgnore(finfo.IgnorePaths); } return; } } scanResult.ChangesFound = true; if (!scanResult.CheckOnly && !added) { scanResult.AddFileToScan(file, folderInfo); } }
bool ScanConfigAssemblies(IProgressStatus monitor, string filePath, AddinScanResult scanResult, out AddinDescription config) { config = null; try { string basePath = Path.GetDirectoryName(filePath); config = AddinDescription.Read(filePath); config.BasePath = basePath; config.AddinFile = filePath; return(ScanDescription(monitor, config, null, scanResult)); } catch (Exception ex) { // Something went wrong while scanning the assembly. We'll ignore it for now. monitor.ReportError("There was an error while scanning add-in: " + filePath, ex); return(false); } }
void ScanAssemblyAddinHeaders(IAssemblyReflector reflector, AddinDescription config, object asm, AddinScanResult scanResult) { // Get basic add-in information AddinAttribute att = (AddinAttribute) reflector.GetCustomAttribute (asm, typeof(AddinAttribute), false); if (att != null) { if (att.Id.Length > 0) config.LocalId = att.Id; if (att.Version.Length > 0) config.Version = att.Version; if (att.Namespace.Length > 0) config.Namespace = att.Namespace; if (att.Category.Length > 0) config.Category = att.Category; if (att.CompatVersion.Length > 0) config.CompatVersion = att.CompatVersion; if (att.Url.Length > 0) config.Url = att.Url; config.IsRoot = att is AddinRootAttribute; config.EnabledByDefault = att.EnabledByDefault; config.Flags = att.Flags; } // Author attributes object[] atts = reflector.GetCustomAttributes (asm, typeof(AddinAuthorAttribute), false); foreach (AddinAuthorAttribute author in atts) { if (config.Author.Length == 0) config.Author = author.Name; else config.Author += ", " + author.Name; } // Name atts = reflector.GetCustomAttributes (asm, typeof(AddinNameAttribute), false); foreach (AddinNameAttribute at in atts) { if (string.IsNullOrEmpty (at.Locale)) config.Name = at.Name; else config.Properties.SetPropertyValue ("Name", at.Name, at.Locale); } // Description object catt = reflector.GetCustomAttribute (asm, typeof(AssemblyDescriptionAttribute), false); if (catt != null && config.Description.Length == 0) config.Description = ((AssemblyDescriptionAttribute)catt).Description; atts = reflector.GetCustomAttributes (asm, typeof(AddinDescriptionAttribute), false); foreach (AddinDescriptionAttribute at in atts) { if (string.IsNullOrEmpty (at.Locale)) config.Description = at.Description; else config.Properties.SetPropertyValue ("Description", at.Description, at.Locale); } // Copyright catt = reflector.GetCustomAttribute (asm, typeof(AssemblyCopyrightAttribute), false); if (catt != null && config.Copyright.Length == 0) config.Copyright = ((AssemblyCopyrightAttribute)catt).Copyright; // Localizer AddinLocalizerGettextAttribute locat = (AddinLocalizerGettextAttribute) reflector.GetCustomAttribute (asm, typeof(AddinLocalizerGettextAttribute), false); if (locat != null) { ExtensionNodeDescription node = new ExtensionNodeDescription (); if (!string.IsNullOrEmpty (locat.Catalog)) node.SetAttribute ("catalog", locat.Catalog); if (!string.IsNullOrEmpty (locat.Location)) node.SetAttribute ("location", locat.Catalog); config.Localizer = node; } // Optional modules atts = reflector.GetCustomAttributes (asm, typeof(AddinModuleAttribute), false); foreach (AddinModuleAttribute mod in atts) { if (mod.AssemblyFile.Length > 0) { ModuleDescription module = new ModuleDescription (); module.Assemblies.Add (mod.AssemblyFile); config.OptionalModules.Add (module); } } }
void ReportReflectionException(IProgressStatus monitor, Exception ex, AddinDescription config, AddinScanResult scanResult) { scanResult.AddFileToWithFailure(config.AddinFile); monitor.ReportWarning("[" + config.AddinId + "] Could not load some add-in assemblies: " + ex.Message); if (monitor.LogLevel <= 1) { return; } ReflectionTypeLoadException rex = ex as ReflectionTypeLoadException; if (rex != null) { foreach (Exception e in rex.LoaderExceptions) { monitor.Log("Load exception: " + e); } } }
void RegisterFileToScan(IProgressStatus monitor, string file, AddinScanResult scanResult, AddinScanFolderInfo folderInfo) { if (scanResult.LocateAssembliesOnly) return; AddinFileInfo finfo = folderInfo.GetAddinFileInfo (file); bool added = false; if (finfo != null && (!finfo.IsAddin || finfo.Domain == folderInfo.GetDomain (finfo.IsRoot)) && fs.GetLastWriteTime (file) == finfo.LastScan && !scanResult.RegenerateAllData) { if (finfo.ScanError) { // Always schedule the file for scan if there was an error in a previous scan. // However, don't set ChangesFound=true, in this way if there isn't any other // change in the registry, the file won't be scanned again. scanResult.AddFileToScan (file, folderInfo); added = true; } if (!finfo.IsAddin) return; if (database.AddinDescriptionExists (finfo.Domain, finfo.AddinId)) { // It is an add-in and it has not changed. Paths in the ignore list // are still valid, so they can be used. if (finfo.IgnorePaths != null) scanResult.AddPathsToIgnore (finfo.IgnorePaths); return; } } scanResult.ChangesFound = true; if (!scanResult.CheckOnly && !added) scanResult.AddFileToScan (file, folderInfo); }
void ReportReflectionException(IProgressStatus monitor, Exception ex, AddinDescription config, AddinScanResult scanResult) { scanResult.AddFileToWithFailure (config.AddinFile); monitor.ReportWarning ("[" + config.AddinId + "] Could not load some add-in assemblies: " + ex.Message); if (monitor.LogLevel <= 1) return; ReflectionTypeLoadException rex = ex as ReflectionTypeLoadException; if (rex != null) { foreach (Exception e in rex.LoaderExceptions) monitor.Log ("Load exception: " + e); } }
public void ScanFolderRec(IProgressStatus monitor, string dir, string domain, AddinScanResult scanResult) { ScanFolder (monitor, dir, domain, scanResult); if (!fs.DirectoryExists (dir)) return; foreach (string sd in fs.GetDirectories (dir)) ScanFolderRec (monitor, sd, domain, scanResult); }
public void UpdateDeletedAddins(IProgressStatus monitor, AddinScanFolderInfo folderInfo, AddinScanResult scanResult) { ArrayList missing = folderInfo.GetMissingAddins (fs); if (missing.Count > 0) { if (fs.DirectoryExists (folderInfo.Folder)) scanResult.RegisterModifiedFolderInfo (folderInfo); scanResult.ChangesFound = true; if (scanResult.CheckOnly) return; foreach (AddinFileInfo info in missing) { database.UninstallAddin (monitor, info.Domain, info.AddinId, info.File, scanResult); } } }
internal void ScanFolders(IProgressStatus monitor, string currentDomain, string folderToScan, StringCollection filesToIgnore) { AddinScanResult res = new AddinScanResult (); res.Domain = currentDomain; res.AddPathsToIgnore (filesToIgnore); ScanFolders (monitor, res); }
public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult) { if (scanResult.IgnorePath (file)) { // The file must be ignored. Maybe it caused a crash in a previous scan, or it // might be included by a .addin file (in which case it will be scanned when processing // the .addin file). folderInfo.SetLastScanTime (file, null, false, fs.GetLastWriteTime (file), true); return; } if (monitor.LogLevel > 1) monitor.Log ("Scanning file: " + file); // Log the file to be scanned, so in case of a process crash the main process // will know what crashed monitor.Log ("plog:scan:" + file); string scannedAddinId = null; bool scannedIsRoot = false; bool scanSuccessful = false; AddinDescription config = null; try { string ext = Path.GetExtension (file).ToLower (); if (ext == ".dll" || ext == ".exe") scanSuccessful = ScanAssembly (monitor, file, scanResult, out config); else scanSuccessful = ScanConfigAssemblies (monitor, file, scanResult, out config); if (config != null) { AddinFileInfo fi = folderInfo.GetAddinFileInfo (file); // If version is not specified, make up one if (config.Version.Length == 0) { config.Version = "0.0.0.0"; } if (config.LocalId.Length == 0) { // Generate an internal id for this add-in config.LocalId = database.GetUniqueAddinId (file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version); config.HasUserId = false; } // Check errors in the description StringCollection errors = config.Verify (fs); if (database.IsGlobalRegistry && config.AddinId.IndexOf ('.') == -1) { errors.Add ("Add-ins registered in the global registry must have a namespace."); } if (errors.Count > 0) { scanSuccessful = false; monitor.ReportError ("Errors found in add-in '" + file + ":", null); foreach (string err in errors) monitor.ReportError (err, null); } // Make sure all extensions sets are initialized with the correct add-in id config.SetExtensionsAddinId (config.AddinId); scanResult.ChangesFound = true; // If the add-in already existed, try to reuse the relation data it had. // Also, the dependencies of the old add-in need to be re-analized AddinDescription existingDescription = null; bool res = database.GetAddinDescription (monitor, folderInfo.Domain, config.AddinId, config.AddinFile, out existingDescription); // If we can't get information about the old assembly, just regenerate all relation data if (!res) scanResult.RegenerateRelationData = true; string replaceFileName = null; if (existingDescription != null) { // Reuse old relation data config.MergeExternalData (existingDescription); Util.AddDependencies (existingDescription, scanResult); replaceFileName = existingDescription.FileName; } // If the scanned file results in an add-in version different from the one obtained from // previous scans, the old add-in needs to be uninstalled. if (fi != null && fi.IsAddin && fi.AddinId != config.AddinId) { database.UninstallAddin (monitor, folderInfo.Domain, fi.AddinId, fi.File, scanResult); // If the add-in version has changed, regenerate everything again since old data can't be reused if (Addin.GetIdName (fi.AddinId) == Addin.GetIdName (config.AddinId)) scanResult.RegenerateRelationData = true; } // If a description could be generated, save it now (if the scan was successful) if (scanSuccessful) { // Assign the domain if (config.IsRoot) { if (folderInfo.RootsDomain == null) { if (scanResult.Domain != null && scanResult.Domain != AddinDatabase.UnknownDomain && scanResult.Domain != AddinDatabase.GlobalDomain) folderInfo.RootsDomain = scanResult.Domain; else folderInfo.RootsDomain = database.GetUniqueDomainId (); } config.Domain = folderInfo.RootsDomain; } else config.Domain = folderInfo.Domain; if (config.IsRoot && scanResult.HostIndex != null) { // If the add-in is a root, register its assemblies foreach (string f in config.MainModule.Assemblies) { string asmFile = Path.Combine (config.BasePath, f); scanResult.HostIndex.RegisterAssembly (asmFile, config.AddinId, config.AddinFile, config.Domain); } } // Finally save if (database.SaveDescription (monitor, config, replaceFileName)) { // The new dependencies also have to be updated Util.AddDependencies (config, scanResult); scanResult.AddAddinToUpdate (config.AddinId); scannedAddinId = config.AddinId; scannedIsRoot = config.IsRoot; return; } } } } catch (Exception ex) { monitor.ReportError ("Unexpected error while scanning file: " + file, ex); } finally { AddinFileInfo ainfo = folderInfo.SetLastScanTime (file, scannedAddinId, scannedIsRoot, fs.GetLastWriteTime (file), !scanSuccessful); if (scanSuccessful && config != null) { // Update the ignore list in the folder info object. To be used in the next scan foreach (string df in config.AllIgnorePaths) { string path = Path.Combine (config.BasePath, df); ainfo.AddPathToIgnore (Path.GetFullPath (path)); } } monitor.Log ("plog:endscan"); } }
public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult) { if (scanResult.IgnorePath(file)) { // The file must be ignored. Maybe it caused a crash in a previous scan, or it // might be included by a .addin file (in which case it will be scanned when processing // the .addin file). folderInfo.SetLastScanTime(file, null, false, File.GetLastWriteTime(file), true); return; } if (monitor.LogLevel > 1) { monitor.Log("Scanning file: " + file); } // Log the file to be scanned, so in case of a process crash the main process // will know what crashed monitor.Log("plog:scan:" + file); string scannedAddinId = null; bool scannedIsRoot = false; bool scanSuccessful = false; AddinDescription config = null; try { string ext = Path.GetExtension(file); if (ext == ".dll" || ext == ".exe") { scanSuccessful = ScanAssembly(monitor, file, scanResult, out config); } else { scanSuccessful = ScanConfigAssemblies(monitor, file, scanResult, out config); } if (config != null) { AddinFileInfo fi = folderInfo.GetAddinFileInfo(file); // If version is not specified, make up one if (config.Version.Length == 0) { config.Version = "0.0.0.0"; } if (config.LocalId.Length == 0) { // Generate an internal id for this add-in config.LocalId = database.GetUniqueAddinId(file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version); config.HasUserId = false; } // Check errors in the description StringCollection errors = config.Verify(); if (database.IsGlobalRegistry && config.AddinId.IndexOf('.') == -1) { errors.Add("Add-ins registered in the global registry must have a namespace."); } if (errors.Count > 0) { scanSuccessful = false; monitor.ReportError("Errors found in add-in '" + file + ":", null); foreach (string err in errors) { monitor.ReportError(err, null); } } // Make sure all extensions sets are initialized with the correct add-in id config.SetExtensionsAddinId(config.AddinId); scanResult.ChangesFound = true; // If the add-in already existed, try to reuse the relation data it had. // Also, the dependencies of the old add-in need to be re-analized AddinDescription existingDescription = null; bool res = database.GetAddinDescription(monitor, folderInfo.Domain, config.AddinId, out existingDescription); // If we can't get information about the old assembly, just regenerate all relation data if (!res) { scanResult.RegenerateRelationData = true; } string replaceFileName = null; if (existingDescription != null) { // Reuse old relation data config.MergeExternalData(existingDescription); Util.AddDependencies(existingDescription, scanResult); replaceFileName = existingDescription.FileName; } // If the scanned file results in an add-in version different from the one obtained from // previous scans, the old add-in needs to be uninstalled. if (fi != null && fi.IsAddin && fi.AddinId != config.AddinId) { database.UninstallAddin(monitor, folderInfo.Domain, fi.AddinId, scanResult); // If the add-in version has changed, regenerate everything again since old data can't be reused if (Addin.GetIdName(fi.AddinId) == Addin.GetIdName(config.AddinId)) { scanResult.RegenerateRelationData = true; } } // If a description could be generated, save it now (if the scan was successful) if (scanSuccessful) { // Assign the domain if (config.IsRoot) { if (folderInfo.RootsDomain == null) { if (scanResult.Domain != null && scanResult.Domain != AddinDatabase.UnknownDomain && scanResult.Domain != AddinDatabase.GlobalDomain) { folderInfo.RootsDomain = scanResult.Domain; } else { folderInfo.RootsDomain = database.GetUniqueDomainId(); } } config.Domain = folderInfo.RootsDomain; } else { config.Domain = folderInfo.Domain; } if (config.IsRoot && scanResult.HostIndex != null) { // If the add-in is a root, register its assemblies foreach (string f in config.MainModule.Assemblies) { string asmFile = Path.Combine(config.BasePath, f); scanResult.HostIndex.RegisterAssembly(asmFile, config.AddinId, config.AddinFile, config.Domain); } } // Finally save if (database.SaveDescription(monitor, config, replaceFileName)) { // The new dependencies also have to be updated Util.AddDependencies(config, scanResult); scanResult.AddAddinToUpdateRelations(config.AddinId); scannedAddinId = config.AddinId; scannedIsRoot = config.IsRoot; return; } } } } catch (Exception ex) { monitor.ReportError("Unexpected error while scanning file: " + file, ex); } finally { AddinFileInfo ainfo = folderInfo.SetLastScanTime(file, scannedAddinId, scannedIsRoot, File.GetLastWriteTime(file), !scanSuccessful); if (scanSuccessful && config != null) { // Update the ignore list in the folder info object. To be used in the next scan foreach (string df in config.AllIgnorePaths) { string path = Path.Combine(config.BasePath, df); ainfo.AddPathToIgnore(Util.GetFullPath(path)); } } monitor.Log("plog:endscan"); } }
public AddinRegistryUpdater(AddinDatabase database, AddinScanResult scanResult) : base(database) { this.database = database; this.scanResult = scanResult; ScanContext = scanResult.ScanContext; }
public void ScanAddinsFile(IProgressStatus monitor, string file, AddinScanResult scanResult) { XmlTextReader r = null; StringCollection directories = new StringCollection(); StringCollection directoriesWithSubdirs = new StringCollection(); try { r = new XmlTextReader(new StreamReader(file)); r.MoveToContent(); if (r.IsEmptyElement) { return; } r.ReadStartElement(); r.MoveToContent(); while (r.NodeType != XmlNodeType.EndElement) { if (r.NodeType == XmlNodeType.Element && r.LocalName == "Directory") { string subs = r.GetAttribute("include-subdirs"); string path = r.ReadElementString().Trim(); if (path.Length > 0) { if (subs == "true") { directoriesWithSubdirs.Add(path); } else { directories.Add(path); } } } else { r.Skip(); } r.MoveToContent(); } } catch (Exception ex) { monitor.ReportError("Could not process addins file: " + file, ex); return; } finally { if (r != null) { r.Close(); } } foreach (string d in directories) { string dir = d; if (!Path.IsPathRooted(dir)) { dir = Path.Combine(Path.GetDirectoryName(file), dir); } ScanFolder(monitor, dir, scanResult); } foreach (string d in directoriesWithSubdirs) { string dir = d; if (!Path.IsPathRooted(dir)) { dir = Path.Combine(Path.GetDirectoryName(file), dir); } ScanFolderRec(monitor, dir, scanResult); } }
public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult) { if (monitor.VerboseLog) { monitor.Log("Scanning file: " + file); } string scannedAddinId = null; bool scannedIsRoot = false; bool scanSuccessful = false; try { string ext = Path.GetExtension(file); AddinDescription config = null; if (ext == ".dll" || ext == ".exe") { scanSuccessful = ScanAssembly(monitor, file, scanResult, out config); } else { scanSuccessful = ScanConfigAssemblies(monitor, file, scanResult, out config); } if (config != null) { AddinFileInfo fi = folderInfo.GetAddinFileInfo(file); // If version is not specified, make up one if (config.Version.Length == 0) { config.Version = "0.0.0.0"; } if (config.LocalId.Length == 0) { // Generate an internal id for this add-in config.LocalId = database.GetUniqueAddinId(file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version); config.HasUserId = false; } // Check errors in the description StringCollection errors = config.Verify(); if (database.IsGlobalRegistry && config.AddinId.IndexOf('.') == -1) { errors.Add("Add-ins registered in the global registry must have a namespace."); } if (errors.Count > 0) { scanSuccessful = false; monitor.ReportError("Errors found in add-in '" + file + ":", null); foreach (string err in errors) { monitor.ReportError(err, null); } } // Make sure all extensions sets are initialized with the correct add-in id config.SetExtensionsAddinId(config.AddinId); scanResult.ChangesFound = true; // If the add-in already existed, try to reuse the relation data it had. // Also, the dependencies of the old add-in need to be re-analized AddinDescription existingDescription = null; bool res; if (config.IsRoot) { res = database.GetHostDescription(monitor, config.AddinId, config.AddinFile, out existingDescription); } else { res = database.GetAddinDescription(monitor, config.AddinId, out existingDescription); } // If we can't get information about the old assembly, just regenerate all relation data if (!res) { scanResult.RegenerateRelationData = true; } string replaceFileName = null; if (existingDescription != null) { // Reuse old relation data config.MergeExternalData(existingDescription); Util.AddDependencies(existingDescription, scanResult); replaceFileName = existingDescription.FileName; } // If the scanned file results in an add-in version different from the one obtained from // previous scans, the old add-in needs to be uninstalled. if (fi != null && fi.AddinId != null && fi.AddinId != config.AddinId) { if (fi.IsRoot) { database.UninstallRootAddin(monitor, fi.AddinId, file, scanResult); } else { database.UninstallAddin(monitor, fi.AddinId, scanResult); } // If the add-in version has changed, regenerate everything again since old data can't be reused if (Addin.GetIdName(fi.AddinId) == Addin.GetIdName(config.AddinId)) { scanResult.RegenerateRelationData = true; } } // If a description could be generated, save it now (if the scan was successful) if (scanSuccessful) { if (database.SaveDescription(monitor, config, replaceFileName)) { // The new dependencies also have to be updated Util.AddDependencies(config, scanResult); scanResult.AddAddinToUpdateRelations(config.AddinId); scannedAddinId = config.AddinId; scannedIsRoot = config.IsRoot; return; } } } } catch (Exception ex) { monitor.ReportError("Unexpected error while scanning file: " + file, ex); } finally { folderInfo.SetLastScanTime(file, scannedAddinId, scannedIsRoot, File.GetLastWriteTime(file), !scanSuccessful); } }
public void ScanAddinsFile(IProgressStatus monitor, string file, string domain, AddinScanResult scanResult) { XmlTextReader r = null; ArrayList directories = new ArrayList(); ArrayList directoriesWithSubdirs = new ArrayList(); string basePath = Path.GetDirectoryName(file); try { r = new XmlTextReader(new StreamReader(file)); r.MoveToContent(); if (r.IsEmptyElement) { return; } r.ReadStartElement(); r.MoveToContent(); while (r.NodeType != XmlNodeType.EndElement) { if (r.NodeType == XmlNodeType.Element && r.LocalName == "Directory") { string subs = r.GetAttribute("include-subdirs"); string sdom; string share = r.GetAttribute("shared"); if (share == "true") { sdom = AddinDatabase.GlobalDomain; } else if (share == "false") { sdom = null; } else { sdom = domain; // Inherit the domain } string path = r.ReadElementString().Trim(); if (path.Length > 0) { path = Util.NormalizePath(path); if (subs == "true") { directoriesWithSubdirs.Add(new string[] { path, sdom }); } else { directories.Add(new string[] { path, sdom }); } } } else if (r.NodeType == XmlNodeType.Element && r.LocalName == "GacAssembly") { string aname = r.ReadElementString().Trim(); if (aname.Length > 0) { aname = Util.NormalizePath(aname); aname = Util.GetGacPath(aname); if (aname != null) { // Gac assemblies always use the global domain directories.Add(new string[] { aname, AddinDatabase.GlobalDomain }); } } } else if (r.NodeType == XmlNodeType.Element && r.LocalName == "Exclude") { string path = r.ReadElementString().Trim(); if (path.Length > 0) { path = Util.NormalizePath(path); if (!Path.IsPathRooted(path)) { path = Path.Combine(basePath, path); } scanResult.AddPathToIgnore(Util.GetFullPath(path)); } } else { r.Skip(); } r.MoveToContent(); } } catch (Exception ex) { monitor.ReportError("Could not process addins file: " + file, ex); return; } finally { if (r != null) { r.Close(); } } foreach (string[] d in directories) { string dir = d[0]; if (!Path.IsPathRooted(dir)) { dir = Path.Combine(basePath, dir); } ScanFolder(monitor, dir, d[1], scanResult); } foreach (string[] d in directoriesWithSubdirs) { string dir = d[0]; if (!Path.IsPathRooted(dir)) { dir = Path.Combine(basePath, dir); } ScanFolderRec(monitor, dir, d[1], scanResult); } }
public void UpdateDeletedAddins(IProgressStatus monitor, AddinScanFolderInfo folderInfo, AddinScanResult scanResult) { ArrayList missing = folderInfo.GetMissingAddins(); if (missing.Count > 0) { if (Directory.Exists(folderInfo.Folder)) { scanResult.ModifiedFolderInfos.Add(folderInfo); } scanResult.ChangesFound = true; if (scanResult.CheckOnly) { return; } foreach (AddinFileInfo info in missing) { if (info.IsRoot) { database.UninstallRootAddin(monitor, info.AddinId, info.File, scanResult); } else { database.UninstallAddin(monitor, info.AddinId, scanResult); } } } }
bool ScanDescription(IProgressStatus monitor, AddinDescription config, Assembly rootAssembly, AddinScanResult scanResult) { // First of all scan the main module ArrayList assemblies = new ArrayList(); ArrayList asmFiles = new ArrayList(); ArrayList hostExtensionClasses = new ArrayList(); try { // Add all data files to the ignore file list. It avoids scanning assemblies // which are included as 'data' in an add-in. foreach (string df in config.AllFiles) { string file = Path.Combine(config.BasePath, df); scanResult.AddPathToIgnore(Util.GetFullPath(file)); } foreach (string df in config.AllIgnorePaths) { string path = Path.Combine(config.BasePath, df); scanResult.AddPathToIgnore(Util.GetFullPath(path)); } foreach (string s in config.MainModule.Assemblies) { string asmFile = Path.Combine(config.BasePath, s); asmFiles.Add(asmFile); object asm = reflector.LoadAssembly(asmFile); assemblies.Add(asm); scanResult.AddPathToIgnore(Util.GetFullPath(asmFile)); } foreach (object asm in assemblies) { ScanAssemblyAddinHeaders(config, asm, scanResult); } // The add-in id and version must be already assigned at this point // Clean host data from the index. New data will be added. if (scanResult.HostIndex != null) { scanResult.HostIndex.RemoveHostData(config.AddinId, config.AddinFile); } foreach (object asm in assemblies) { ScanAssemblyContents(config, asm, hostExtensionClasses, scanResult); } } catch (Exception ex) { ReportReflectionException(monitor, ex, config, scanResult); return(false); } foreach (object t in hostExtensionClasses) { RegisterHostTypeNode(config, t, assemblies); } // Extension node types may have child nodes declared as attributes. Find them. Hashtable internalNodeSets = new Hashtable(); ArrayList setsCopy = new ArrayList(); setsCopy.AddRange(config.ExtensionNodeSets); foreach (ExtensionNodeSet eset in setsCopy) { ScanNodeSet(config, eset, assemblies, internalNodeSets); } foreach (ExtensionPoint ep in config.ExtensionPoints) { ScanNodeSet(config, ep.NodeSet, assemblies, internalNodeSets); } // Now scan all modules if (!config.IsRoot) { foreach (ModuleDescription mod in config.OptionalModules) { try { assemblies.Clear(); asmFiles.Clear(); foreach (string s in mod.Assemblies) { string asmFile = Path.Combine(config.BasePath, s); asmFiles.Add(asmFile); object asm = reflector.LoadAssembly(asmFile); assemblies.Add(asm); scanResult.AddPathToIgnore(Util.GetFullPath(asmFile)); } foreach (object asm in assemblies) { ScanAssemblyContents(config, asm, null, scanResult); } } catch (Exception ex) { ReportReflectionException(monitor, ex, config, scanResult); } } } config.StoreFileInfo(); return(true); }
public void ParseAddin(IProgressStatus progressStatus, string domain, string file, string outFile, bool inProcess) { if (!inProcess) { ISetupHandler setup = GetSetupHandler (); setup.GetAddinDescription (progressStatus, registry, Path.GetFullPath (file), outFile); return; } using (fileDatabase.LockRead ()) { // First of all, check if the file belongs to a registered add-in AddinScanFolderInfo finfo; if (GetFolderInfoForPath (progressStatus, Path.GetDirectoryName (file), out finfo) && finfo != null) { AddinFileInfo afi = finfo.GetAddinFileInfo (file); if (afi != null && afi.IsAddin) { AddinDescription adesc; GetAddinDescription (progressStatus, afi.Domain, afi.AddinId, file, out adesc); if (adesc != null) adesc.Save (outFile); return; } } AddinScanResult sr = new AddinScanResult (); sr.Domain = domain; AddinScanner scanner = new AddinScanner (this, sr, progressStatus); SingleFileAssemblyResolver res = new SingleFileAssemblyResolver (progressStatus, registry, scanner); ResolveEventHandler resolver = new ResolveEventHandler (res.Resolve); EventInfo einfo = typeof(AppDomain).GetEvent ("ReflectionOnlyAssemblyResolve"); try { AppDomain.CurrentDomain.AssemblyResolve += resolver; if (einfo != null) einfo.AddEventHandler (AppDomain.CurrentDomain, resolver); AddinDescription desc = scanner.ScanSingleFile (progressStatus, file, sr); if (desc != null) { // Reset the xml doc so that it is not reused when saving. We want a brand new document desc.ResetXmlDoc (); desc.Save (outFile); } } finally { AppDomain.CurrentDomain.AssemblyResolve -= resolver; if (einfo != null) einfo.RemoveEventHandler (AppDomain.CurrentDomain, resolver); } } }
public void ScanFolder(IProgressStatus monitor, string path, AddinScanResult scanResult) { path = Util.GetFullPath(path); // Avoid folders including each other if (!scanResult.VisitFolder(path)) { return; } if (monitor.VerboseLog && !scanResult.LocateAssembliesOnly) { monitor.Log("Checking: " + path); } AddinScanFolderInfo folderInfo; if (!database.GetFolderInfoForPath(monitor, path, out folderInfo)) { // folderInfo file was corrupt. // Just in case, we are going to regenerate all relation data. if (!Directory.Exists(path)) { scanResult.RegenerateRelationData = true; } } else { if (folderInfo == null && !Directory.Exists(path)) { return; } } if (folderInfo == null) { folderInfo = new AddinScanFolderInfo(path); } if (Directory.Exists(path)) { foreach (string file in Directory.GetFiles(path)) { if (file.EndsWith(".addin.xml")) { RegisterFileToScan(monitor, file, scanResult, folderInfo); continue; } switch (Path.GetExtension(file)) { case ".dll": case ".exe": RegisterFileToScan(monitor, file, scanResult, folderInfo); scanResult.AddAssemblyLocation(file); break; case ".addin": RegisterFileToScan(monitor, file, scanResult, folderInfo); break; case ".addins": ScanAddinsFile(monitor, file, scanResult); break; } } } else if (!scanResult.LocateAssembliesOnly) { // The folder has been deleted. All add-ins defined in that folder should also be deleted. scanResult.RegenerateRelationData = true; scanResult.ChangesFound = true; if (scanResult.CheckOnly) { return; } database.DeleteFolderInfo(monitor, folderInfo); } if (scanResult.LocateAssembliesOnly) { return; } // Look for deleted add-ins. UpdateDeletedAddins(monitor, folderInfo, scanResult); }
internal void UninstallAddin(IProgressStatus monitor, string domain, string addinId, string addinFile, AddinScanResult scanResult) { AddinDescription desc; if (!GetAddinDescription (monitor, domain, addinId, addinFile, out desc)) { // If we can't get information about the old assembly, just regenerate all relation data scanResult.RegenerateRelationData = true; return; } scanResult.AddRemovedAddin (addinId); // If the add-in didn't exist, there is nothing left to do if (desc == null) return; // If the add-in already existed, the dependencies of the old add-in need to be re-analyzed Util.AddDependencies (desc, scanResult); if (desc.IsRoot) scanResult.HostIndex.RemoveHostData (desc.AddinId, desc.AddinFile); RemoveAddinDescriptionFile (monitor, desc.FileName); }
bool ScanDescription(IProgressStatus monitor, AddinDescription config, Assembly rootAssembly, AddinScanResult scanResult) { // First of all scan the main module ArrayList assemblies = new ArrayList(); ArrayList hostExtensionClasses = new ArrayList(); try { foreach (string s in config.MainModule.Assemblies) { string asmFile = Path.Combine(config.BasePath, s); Assembly asm = Util.LoadAssemblyForReflection(asmFile); assemblies.Add(asm); } foreach (Assembly asm in assemblies) { ScanAssemblyAddinHeaders(config, asm, scanResult); } // The add-in id and version must be already assigned at this point // Clean host data from the index. New data will be added. if (scanResult.HostIndex != null) { scanResult.HostIndex.RemoveHostData(config.AddinId, config.AddinFile); } foreach (Assembly asm in assemblies) { ScanAssemblyContents(config, asm, hostExtensionClasses, scanResult); } if (config.IsRoot && scanResult.HostIndex != null) { // If the add-in is a root, register its assemblies foreach (Assembly asm in assemblies) { string asmFile = new Uri(asm.CodeBase).LocalPath; scanResult.HostIndex.RegisterAssembly(asmFile, config.AddinId, config.AddinFile); } } } catch (Exception ex) { if (monitor.VerboseLog) { monitor.Log("Could not load some add-in assemblies: " + ex.Message); } scanResult.AddFileToWithFailure(config.AddinFile); return(false); } foreach (Type t in hostExtensionClasses) { RegisterHostTypeNode(config, t, assemblies); } // Extension node types may have child nodes declared as attributes. Find them. Hashtable internalNodeSets = new Hashtable(); foreach (ExtensionNodeSet eset in config.ExtensionNodeSets) { ScanNodeSet(config, eset, assemblies, internalNodeSets); } foreach (ExtensionPoint ep in config.ExtensionPoints) { ScanNodeSet(config, ep.NodeSet, assemblies, internalNodeSets); } // Now scan all modules if (!config.IsRoot) { foreach (ModuleDescription mod in config.OptionalModules) { try { assemblies.Clear(); foreach (string s in mod.Assemblies) { string asmFile = Path.Combine(config.BasePath, s); Assembly asm = Util.LoadAssemblyForReflection(asmFile); assemblies.Add(asm); } foreach (Assembly asm in assemblies) { ScanAssemblyContents(config, asm, null, scanResult); } if (config.IsRoot && scanResult.HostIndex != null) { // If the add-in is a root, register its assemblies foreach (Assembly asm in assemblies) { string asmFile = new Uri(asm.CodeBase).LocalPath; scanResult.HostIndex.RegisterAssembly(asmFile, config.AddinId, config.AddinFile); } } } catch (Exception ex) { if (monitor.VerboseLog) { monitor.Log("Could not load some add-in assemblies: " + ex.Message); } scanResult.AddFileToWithFailure(config.AddinFile); } } } return(true); }
public void ScanFolder(IProgressStatus monitor, string path, string domain, AddinScanResult scanResult) { path = Path.GetFullPath (path); // Avoid folders including each other if (!scanResult.VisitFolder (path)) return; AddinScanFolderInfo folderInfo; if (!database.GetFolderInfoForPath (monitor, path, out folderInfo)) { // folderInfo file was corrupt. // Just in case, we are going to regenerate all relation data. if (!fs.DirectoryExists (path)) scanResult.RegenerateRelationData = true; } else { // Directory is included but it doesn't exist. Ignore it. if (folderInfo == null && !fs.DirectoryExists (path)) return; } // if domain is null it means that a new domain has to be created. bool sharedFolder = domain == AddinDatabase.GlobalDomain; bool isNewFolder = folderInfo == null; if (isNewFolder) { // No folder info. It is the first time this folder is scanned. // There is no need to store this object if the folder does not // contain add-ins. folderInfo = new AddinScanFolderInfo (path); } if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain)) { // If the folder already has a domain, reuse it if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain) domain = folderInfo.RootsDomain; else if (domain == null) { folderInfo.Domain = domain = database.GetUniqueDomainId (); scanResult.RegenerateRelationData = true; } else { folderInfo.Domain = domain; if (!isNewFolder) { // Domain has changed. Update the folder info and regenerate everything. scanResult.RegenerateRelationData = true; scanResult.RegisterModifiedFolderInfo (folderInfo); } } } else if (!folderInfo.SharedFolder && sharedFolder) { scanResult.RegenerateRelationData = true; } folderInfo.SharedFolder = sharedFolder; // If there is no domain assigned to the host, get one now if (scanResult.Domain == AddinDatabase.UnknownDomain) scanResult.Domain = domain; // Discard folders not belonging to the required domain if (scanResult.Domain != null && domain != scanResult.Domain && domain != AddinDatabase.GlobalDomain) { return; } if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly) monitor.Log ("Checking: " + path); if (fs.DirectoryExists (path)) { IEnumerable<string> files = fs.GetFiles (path); // First of all, look for .addin files. Addin files must be processed before // assemblies, because they may add files to the ignore list (i.e., assemblies // included in .addin files won't be scanned twice). foreach (string file in files) { if (file.EndsWith (".addin.xml") || file.EndsWith (".addin")) { RegisterFileToScan (monitor, file, scanResult, folderInfo); } } // Now scan assemblies. They can also add files to the ignore list. foreach (string file in files) { string ext = Path.GetExtension (file).ToLower (); if (ext == ".dll" || ext == ".exe") { RegisterFileToScan (monitor, file, scanResult, folderInfo); scanResult.AddAssemblyLocation (file); } } // Finally scan .addins files foreach (string file in files) { if (Path.GetExtension (file).EndsWith (".addins")) { ScanAddinsFile (monitor, file, domain, scanResult); } } } else if (!scanResult.LocateAssembliesOnly) { // The folder has been deleted. All add-ins defined in that folder should also be deleted. scanResult.RegenerateRelationData = true; scanResult.ChangesFound = true; if (scanResult.CheckOnly) return; database.DeleteFolderInfo (monitor, folderInfo); } if (scanResult.LocateAssembliesOnly) return; // Look for deleted add-ins. UpdateDeletedAddins (monitor, folderInfo, scanResult); }
void ScanAssemblyContents(IAssemblyReflector reflector, AddinDescription config, ModuleDescription module, object asm, AddinScanResult scanResult) { bool isMainModule = module == config.MainModule; // Get dependencies object[] deps = reflector.GetCustomAttributes (asm, typeof(AddinDependencyAttribute), false); foreach (AddinDependencyAttribute dep in deps) { AddinDependency adep = new AddinDependency (); adep.AddinId = dep.Id; adep.Version = dep.Version; module.Dependencies.Add (adep); } if (isMainModule) { // Get properties object[] props = reflector.GetCustomAttributes (asm, typeof(AddinPropertyAttribute), false); foreach (AddinPropertyAttribute prop in props) config.Properties.SetPropertyValue (prop.Name, prop.Value, prop.Locale); // Get extension points object[] extPoints = reflector.GetCustomAttributes (asm, typeof(ExtensionPointAttribute), false); foreach (ExtensionPointAttribute ext in extPoints) { ExtensionPoint ep = config.AddExtensionPoint (ext.Path); ep.Description = ext.Description; ep.Name = ext.Name; ExtensionNodeType nt = ep.AddExtensionNode (ext.NodeName, ext.NodeTypeName); nt.ExtensionAttributeTypeName = ext.ExtensionAttributeTypeName; } } // Look for extension nodes declared using assembly attributes foreach (CustomAttribute att in reflector.GetRawCustomAttributes (asm, typeof(CustomExtensionAttribute), true)) AddCustomAttributeExtension (module, att, "Type"); // Get extensions or extension points applied to types foreach (object t in reflector.GetAssemblyTypes (asm)) { string typeFullName = reflector.GetTypeFullName (t); // Look for extensions object[] extensionAtts = reflector.GetCustomAttributes (t, typeof(ExtensionAttribute), false); if (extensionAtts.Length > 0) { Dictionary<string,ExtensionNodeDescription> nodes = new Dictionary<string, ExtensionNodeDescription> (); ExtensionNodeDescription uniqueNode = null; foreach (ExtensionAttribute eatt in extensionAtts) { string path; string nodeName = eatt.NodeName; if (eatt.TypeName.Length > 0) { path = "$" + eatt.TypeName; } else if (eatt.Path.Length == 0) { path = GetBaseTypeNameList (reflector, t); if (path == "$") { // The type does not implement any interface and has no superclass. // Will be reported later as an error. path = "$" + typeFullName; } } else { path = eatt.Path; } ExtensionNodeDescription elem = module.AddExtensionNode (path, nodeName); nodes [path] = elem; uniqueNode = elem; if (eatt.Id.Length > 0) { elem.SetAttribute ("id", eatt.Id); elem.SetAttribute ("type", typeFullName); } else { elem.SetAttribute ("id", typeFullName); } if (eatt.InsertAfter.Length > 0) elem.SetAttribute ("insertafter", eatt.InsertAfter); if (eatt.InsertBefore.Length > 0) elem.SetAttribute ("insertbefore", eatt.InsertBefore); } // Get the node attributes foreach (ExtensionAttributeAttribute eat in reflector.GetCustomAttributes (t, typeof(ExtensionAttributeAttribute), false)) { ExtensionNodeDescription node; if (!string.IsNullOrEmpty (eat.Path)) nodes.TryGetValue (eat.Path, out node); else if (eat.TypeName.Length > 0) nodes.TryGetValue ("$" + eat.TypeName, out node); else { if (nodes.Count > 1) throw new Exception ("Missing type or extension path value in ExtensionAttribute for type '" + typeFullName + "'."); node = uniqueNode; } if (node == null) throw new Exception ("Invalid type or path value in ExtensionAttribute for type '" + typeFullName + "'."); node.SetAttribute (eat.Name ?? string.Empty, eat.Value ?? string.Empty); } } else { // Look for extension points extensionAtts = reflector.GetCustomAttributes (t, typeof(TypeExtensionPointAttribute), false); if (extensionAtts.Length > 0 && isMainModule) { foreach (TypeExtensionPointAttribute epa in extensionAtts) { ExtensionPoint ep; ExtensionNodeType nt = new ExtensionNodeType (); if (epa.Path.Length > 0) { ep = config.AddExtensionPoint (epa.Path); } else { ep = config.AddExtensionPoint (GetDefaultTypeExtensionPath (config, typeFullName)); nt.ObjectTypeName = typeFullName; } nt.Id = epa.NodeName; nt.TypeName = epa.NodeTypeName; nt.ExtensionAttributeTypeName = epa.ExtensionAttributeTypeName; ep.NodeSet.NodeTypes.Add (nt); ep.Description = epa.Description; ep.Name = epa.Name; ep.RootAddin = config.AddinId; ep.SetExtensionsAddinId (config.AddinId); } } else { // Look for custom extension attribtues foreach (CustomAttribute att in reflector.GetRawCustomAttributes (t, typeof(CustomExtensionAttribute), false)) { ExtensionNodeDescription elem = AddCustomAttributeExtension (module, att, "Type"); elem.SetAttribute ("type", typeFullName); if (string.IsNullOrEmpty (elem.GetAttribute ("id"))) elem.SetAttribute ("id", typeFullName); } } } } }
public AddinDescription ScanSingleFile(IProgressStatus monitor, string file, AddinScanResult scanResult) { AddinDescription config = null; if (monitor.LogLevel > 1) monitor.Log ("Scanning file: " + file); monitor.Log ("plog:scan:" + file); try { string ext = Path.GetExtension (file).ToLower (); bool scanSuccessful; if (ext == ".dll" || ext == ".exe") scanSuccessful = ScanAssembly (monitor, file, scanResult, out config); else scanSuccessful = ScanConfigAssemblies (monitor, file, scanResult, out config); if (scanSuccessful && config != null) { config.Domain = "global"; if (config.Version.Length == 0) config.Version = "0.0.0.0"; if (config.LocalId.Length == 0) { // Generate an internal id for this add-in config.LocalId = database.GetUniqueAddinId (file, "", config.Namespace, config.Version); } } } catch (Exception ex) { monitor.ReportError ("Unexpected error while scanning file: " + file, ex); } finally { monitor.Log ("plog:endscan"); } return config; }
bool ScanDescription(IProgressStatus monitor, IAssemblyReflector reflector, AddinDescription config, object rootAssembly, AddinScanResult scanResult) { // First of all scan the main module ArrayList assemblies = new ArrayList (); try { string rootAsmFile = null; if (rootAssembly != null) { ScanAssemblyAddinHeaders (reflector, config, rootAssembly, scanResult); ScanAssemblyImports (reflector, config.MainModule, rootAssembly); assemblies.Add (rootAssembly); rootAsmFile = Path.GetFileName (config.AddinFile); } // The assembly list may be modified while scanning the headears, so // we use a for loop instead of a foreach for (int n=0; n<config.MainModule.Assemblies.Count; n++) { string s = config.MainModule.Assemblies [n]; string asmFile = Path.GetFullPath (Path.Combine (config.BasePath, s)); scanResult.AddPathToIgnore (asmFile); if (s == rootAsmFile || config.MainModule.IgnorePaths.Contains (s)) continue; object asm = reflector.LoadAssembly (asmFile); assemblies.Add (asm); ScanAssemblyAddinHeaders (reflector, config, asm, scanResult); ScanAssemblyImports (reflector, config.MainModule, asm); } // Add all data files to the ignore file list. It avoids scanning assemblies // which are included as 'data' in an add-in. foreach (string df in config.MainModule.DataFiles) { string file = Path.Combine (config.BasePath, df); scanResult.AddPathToIgnore (Path.GetFullPath (file)); } foreach (string df in config.MainModule.IgnorePaths) { string path = Path.Combine (config.BasePath, df); scanResult.AddPathToIgnore (Path.GetFullPath (path)); } // The add-in id and version must be already assigned at this point // Clean host data from the index. New data will be added. if (scanResult.HostIndex != null) scanResult.HostIndex.RemoveHostData (config.AddinId, config.AddinFile); foreach (object asm in assemblies) ScanAssemblyContents (reflector, config, config.MainModule, asm, scanResult); } catch (Exception ex) { ReportReflectionException (monitor, ex, config, scanResult); return false; } // Extension node types may have child nodes declared as attributes. Find them. Hashtable internalNodeSets = new Hashtable (); ArrayList setsCopy = new ArrayList (); setsCopy.AddRange (config.ExtensionNodeSets); foreach (ExtensionNodeSet eset in setsCopy) ScanNodeSet (reflector, config, eset, assemblies, internalNodeSets); foreach (ExtensionPoint ep in config.ExtensionPoints) { ScanNodeSet (reflector, config, ep.NodeSet, assemblies, internalNodeSets); } // Now scan all modules if (!config.IsRoot) { foreach (ModuleDescription mod in config.OptionalModules) { try { assemblies.Clear (); for (int n=0; n<mod.Assemblies.Count; n++) { string s = mod.Assemblies [n]; if (mod.IgnorePaths.Contains (s)) continue; string asmFile = Path.Combine (config.BasePath, s); object asm = reflector.LoadAssembly (asmFile); assemblies.Add (asm); scanResult.AddPathToIgnore (Path.GetFullPath (asmFile)); ScanAssemblyImports (reflector, mod, asm); } // Add all data files to the ignore file list. It avoids scanning assemblies // which are included as 'data' in an add-in. foreach (string df in mod.DataFiles) { string file = Path.Combine (config.BasePath, df); scanResult.AddPathToIgnore (Path.GetFullPath (file)); } foreach (string df in mod.IgnorePaths) { string path = Path.Combine (config.BasePath, df); scanResult.AddPathToIgnore (Path.GetFullPath (path)); } foreach (object asm in assemblies) ScanAssemblyContents (reflector, config, mod, asm, scanResult); } catch (Exception ex) { ReportReflectionException (monitor, ex, config, scanResult); } } } config.StoreFileInfo (); return true; }
IAssemblyReflector GetReflector(IProgressStatus monitor, AddinScanResult scanResult, string filePath) { IAssemblyReflector reflector = fs.GetReflectorForFile (scanResult, filePath); object coreAssembly; if (!coreAssemblies.TryGetValue (reflector, out coreAssembly)) { if (monitor.LogLevel > 1) monitor.Log ("Using assembly reflector: " + reflector.GetType ()); coreAssemblies [reflector] = coreAssembly = reflector.LoadAssembly (GetType().Assembly.Location); } return reflector; }
internal void UninstallRootAddin (IProgressStatus monitor, string addinId, string addinFile, AddinScanResult scanResult) { string file = fileDatabase.GetSharedObjectFile (AddinCachePath, addinId, ".mroot", addinFile); DeleteAddin (monitor, file, scanResult); }
public AddinScanner(AddinDatabase database, AddinScanResult scanResult, IProgressStatus monitor) { this.database = database; fs = database.FileSystem; }
public Assembly Resolve (object s, ResolveEventArgs args) { if (scanResult == null) { scanResult = new AddinScanResult (); scanResult.LocateAssembliesOnly = true; foreach (string dir in registry.AddinDirectories) scanner.ScanFolder (progressStatus, dir, scanResult); } string afile = scanResult.GetAssemblyLocation (args.Name); if (afile != null) return Util.LoadAssemblyForReflection (afile); else return null; }
bool ScanAssembly(IProgressStatus monitor, string filePath, AddinScanResult scanResult, out AddinDescription config) { config = null; try { IAssemblyReflector reflector = GetReflector (monitor, scanResult, filePath); object asm = reflector.LoadAssembly (filePath); if (asm == null) throw new Exception ("Could not load assembly: " + filePath); // Get the config file from the resources, if there is one foreach (string res in reflector.GetResourceNames (asm)) { if (res.EndsWith (".addin") || res.EndsWith (".addin.xml")) { using (Stream s = reflector.GetResourceStream (asm, res)) { AddinDescription ad = AddinDescription.Read (s, Path.GetDirectoryName (filePath)); if (config != null) { if (!config.IsExtensionModel && !ad.IsExtensionModel) { // There is more than one add-in definition monitor.ReportError ("Duplicate add-in definition found in assembly: " + filePath, null); return false; } config = AddinDescription.Merge (config, ad); } else config = ad; } } } if (config == null) { // In this case, only scan the assembly if it has the Addin attribute. AddinAttribute att = (AddinAttribute) reflector.GetCustomAttribute (asm, typeof(AddinAttribute), false); if (att == null) return true; config = new AddinDescription (); } config.SetBasePath (Path.GetDirectoryName (filePath)); config.AddinFile = filePath; string rasmFile = Path.GetFileName (filePath); if (!config.MainModule.Assemblies.Contains (rasmFile)) config.MainModule.Assemblies.Add (rasmFile); return ScanDescription (monitor, reflector, config, asm, scanResult); } catch (Exception ex) { // Something went wrong while scanning the assembly. We'll ignore it for now. monitor.ReportError ("There was an error while scanning assembly: " + filePath, ex); return false; } }
internal void ScanFolders (IProgressStatus monitor, AddinScanResult scanResult) { IDisposable checkLock = null; if (scanResult.CheckOnly) checkLock = fileDatabase.LockRead (); else { // All changes are done in a transaction, which won't be committed until // all files have been updated. if (!fileDatabase.BeginTransaction ()) { // The database is already being updated. Can't do anything for now. return; } } EventInfo einfo = typeof(AppDomain).GetEvent ("ReflectionOnlyAssemblyResolve"); ResolveEventHandler resolver = new ResolveEventHandler (OnResolveAddinAssembly); try { // Perform the add-in scan if (!scanResult.CheckOnly) { AppDomain.CurrentDomain.AssemblyResolve += resolver; if (einfo != null) einfo.AddEventHandler (AppDomain.CurrentDomain, resolver); } InternalScanFolders (monitor, scanResult); if (!scanResult.CheckOnly) fileDatabase.CommitTransaction (); } catch { if (!scanResult.CheckOnly) fileDatabase.RollbackTransaction (); throw; } finally { currentScanResult = null; if (scanResult.CheckOnly) checkLock.Dispose (); else { AppDomain.CurrentDomain.AssemblyResolve -= resolver; if (einfo != null) einfo.RemoveEventHandler (AppDomain.CurrentDomain, resolver); } } }
public void ScanAddinsFile(IProgressStatus monitor, string file, string domain, AddinScanResult scanResult) { XmlTextReader r = null; ArrayList directories = new ArrayList (); ArrayList directoriesWithSubdirs = new ArrayList (); string basePath = Path.GetDirectoryName (file); try { r = new XmlTextReader (fs.OpenTextFile (file)); r.MoveToContent (); if (r.IsEmptyElement) return; r.ReadStartElement (); r.MoveToContent (); while (r.NodeType != XmlNodeType.EndElement) { if (r.NodeType == XmlNodeType.Element && r.LocalName == "Directory") { string subs = r.GetAttribute ("include-subdirs"); string sdom; string share = r.GetAttribute ("shared"); if (share == "true") sdom = AddinDatabase.GlobalDomain; else if (share == "false") sdom = null; else sdom = domain; // Inherit the domain string path = r.ReadElementString ().Trim (); if (path.Length > 0) { path = Util.NormalizePath (path); if (subs == "true") directoriesWithSubdirs.Add (new string[] {path, sdom}); else directories.Add (new string[] {path, sdom}); } } else if (r.NodeType == XmlNodeType.Element && r.LocalName == "GacAssembly") { string aname = r.ReadElementString ().Trim (); if (aname.Length > 0) { aname = Util.NormalizePath (aname); aname = Util.GetGacPath (aname); if (aname != null) { // Gac assemblies always use the global domain directories.Add (new string[] {aname, AddinDatabase.GlobalDomain}); } } } else if (r.NodeType == XmlNodeType.Element && r.LocalName == "Exclude") { string path = r.ReadElementString ().Trim (); if (path.Length > 0) { path = Util.NormalizePath (path); if (!Path.IsPathRooted (path)) path = Path.Combine (basePath, path); scanResult.AddPathToIgnore (Path.GetFullPath (path)); } } else r.Skip (); r.MoveToContent (); } } catch (Exception ex) { monitor.ReportError ("Could not process addins file: " + file, ex); return; } finally { if (r != null) r.Close (); } foreach (string[] d in directories) { string dir = d[0]; if (!Path.IsPathRooted (dir)) dir = Path.Combine (basePath, dir); ScanFolder (monitor, dir, d[1], scanResult); } foreach (string[] d in directoriesWithSubdirs) { string dir = d[0]; if (!Path.IsPathRooted (dir)) dir = Path.Combine (basePath, dir); ScanFolderRec (monitor, dir, d[1], scanResult); } }
public void ScanFolder(IProgressStatus monitor, string path, string domain, AddinScanResult scanResult) { path = Util.GetFullPath(path); // Avoid folders including each other if (!scanResult.VisitFolder(path)) { return; } AddinScanFolderInfo folderInfo; if (!database.GetFolderInfoForPath(monitor, path, out folderInfo)) { // folderInfo file was corrupt. // Just in case, we are going to regenerate all relation data. if (!Directory.Exists(path)) { scanResult.RegenerateRelationData = true; } } else { // Directory is included but it doesn't exist. Ignore it. if (folderInfo == null && !Directory.Exists(path)) { return; } } // if domain is null it means that a new domain has to be created. bool sharedFolder = domain == AddinDatabase.GlobalDomain; bool isNewFolder = folderInfo == null; if (isNewFolder) { // No folder info. It is the first time this folder is scanned. // There is no need to store this object if the folder does not // contain add-ins. folderInfo = new AddinScanFolderInfo(path); } if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain)) { // If the folder already has a domain, reuse it if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain) { domain = folderInfo.RootsDomain; } else if (domain == null) { folderInfo.Domain = domain = database.GetUniqueDomainId(); scanResult.RegenerateRelationData = true; } else { folderInfo.Domain = domain; if (!isNewFolder) { // Domain has changed. Update the folder info and regenerate everything. scanResult.RegenerateRelationData = true; scanResult.RegisterModifiedFolderInfo(folderInfo); } } } else if (!folderInfo.SharedFolder && sharedFolder) { scanResult.RegenerateRelationData = true; } folderInfo.SharedFolder = sharedFolder; // If there is no domain assigned to the host, get one now if (scanResult.Domain == AddinDatabase.UnknownDomain) { scanResult.Domain = domain; } // Discard folders not belonging to the required domain if (scanResult.Domain != null && domain != scanResult.Domain && domain != AddinDatabase.GlobalDomain) { return; } if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly) { monitor.Log("Checking: " + path); } if (Directory.Exists(path)) { string[] files = Directory.GetFiles(path); // First of all, look for .addin files. Addin files must be processed before // assemblies, because they may add files to the ignore list (i.e., assemblies // included in .addin files won't be scanned twice). foreach (string file in files) { if (file.EndsWith(".addin.xml") || file.EndsWith(".addin")) { RegisterFileToScan(monitor, file, scanResult, folderInfo); } } // Now scan assemblies. They can also add files to the ignore list. foreach (string file in files) { string ext = Path.GetExtension(file).ToLower(); if (ext == ".dll" || ext == ".exe") { RegisterFileToScan(monitor, file, scanResult, folderInfo); scanResult.AddAssemblyLocation(file); } } // Finally scan .addins files foreach (string file in files) { if (Path.GetExtension(file).EndsWith(".addins")) { ScanAddinsFile(monitor, file, domain, scanResult); } } } else if (!scanResult.LocateAssembliesOnly) { // The folder has been deleted. All add-ins defined in that folder should also be deleted. scanResult.RegenerateRelationData = true; scanResult.ChangesFound = true; if (scanResult.CheckOnly) { return; } database.DeleteFolderInfo(monitor, folderInfo); } if (scanResult.LocateAssembliesOnly) { return; } // Look for deleted add-ins. UpdateDeletedAddins(monitor, folderInfo, scanResult); }
bool ScanConfigAssemblies(IProgressStatus monitor, string filePath, AddinScanResult scanResult, out AddinDescription config) { config = null; try { IAssemblyReflector reflector = GetReflector (monitor, scanResult, filePath); string basePath = Path.GetDirectoryName (filePath); using (var s = fs.OpenFile (filePath)) { config = AddinDescription.Read (s, basePath); } config.FileName = filePath; config.SetBasePath (basePath); config.AddinFile = filePath; return ScanDescription (monitor, reflector, config, null, scanResult); } catch (Exception ex) { // Something went wrong while scanning the assembly. We'll ignore it for now. monitor.ReportError ("There was an error while scanning add-in: " + filePath, ex); return false; } }
void ScanAssemblyContents(AddinDescription config, Assembly asm, ArrayList hostExtensionClasses, AddinScanResult scanResult) { // Get dependencies object[] deps = asm.GetCustomAttributes(typeof(AddinDependencyAttribute), false); foreach (AddinDependencyAttribute dep in deps) { AddinDependency adep = new AddinDependency(); adep.AddinId = dep.Id; adep.Version = dep.Version; config.MainModule.Dependencies.Add(adep); } // Get extension points object[] extPoints = asm.GetCustomAttributes(typeof(ExtensionPointAttribute), false); foreach (ExtensionPointAttribute ext in extPoints) { ExtensionPoint ep = config.AddExtensionPoint(ext.Path); ep.Description = ext.Description; ep.Name = ext.Name; ep.AddExtensionNode(ext.NodeName, ext.NodeType.FullName); } foreach (Type t in asm.GetTypes()) { if (Attribute.IsDefined(t, typeof(ExtensionAttribute))) { foreach (ExtensionAttribute eatt in t.GetCustomAttributes(typeof(ExtensionAttribute), false)) { string path; string nodeName; if (eatt.Path.Length == 0) { if (config.IsRoot) { // The extension point must be one of the defined by the assembly // Look for it later, when the assembly has been fully scanned. hostExtensionClasses.Add(t); continue; } else { path = GetBaseTypeNameList(t); if (path == "$") { // The type does not implement any interface and has no superclass. // Will be reported later as an error. path = "$" + t.FullName; } nodeName = "Type"; } } else { path = eatt.Path; nodeName = eatt.NodeName; } ExtensionNodeDescription elem = config.MainModule.AddExtensionNode(path, nodeName); if (eatt.Id.Length > 0) { elem.SetAttribute("id", eatt.Id); elem.SetAttribute("type", t.FullName); } else { elem.SetAttribute("id", t.FullName); } if (eatt.InsertAfter.Length > 0) { elem.SetAttribute("insertafter", eatt.InsertAfter); } if (eatt.InsertBefore.Length > 0) { elem.SetAttribute("insertbefore", eatt.InsertAfter); } } } else if (Attribute.IsDefined(t, typeof(TypeExtensionPointAttribute))) { foreach (TypeExtensionPointAttribute epa in t.GetCustomAttributes(typeof(TypeExtensionPointAttribute), false)) { ExtensionPoint ep; ExtensionNodeType nt = new ExtensionNodeType(); if (epa.Path.Length > 0) { ep = config.AddExtensionPoint(epa.Path); } else { ep = config.AddExtensionPoint(GetDefaultTypeExtensionPath(config, t)); nt.ObjectTypeName = t.FullName; } nt.Id = epa.NodeName; nt.TypeName = epa.NodeType.FullName; ep.NodeSet.NodeTypes.Add(nt); ep.Description = epa.Description; ep.Name = epa.Name; ep.RootAddin = config.AddinId; ep.SetExtensionsAddinId(config.AddinId); } } } }
internal void UninstallAddin (IProgressStatus monitor, string addinId, AddinScanResult scanResult) { scanResult.AddRemovedAddin (addinId); string file = GetDescriptionPath (addinId); DeleteAddin (monitor, file, scanResult); }
bool ScanAssembly (IProgressStatus monitor, string filePath, AddinScanResult scanResult, out AddinDescription config) { config = null; try { IAssemblyReflector reflector = GetReflector (monitor, scanResult, filePath); object asm = reflector.LoadAssembly (filePath); if (asm == null) throw new Exception ("Could not load assembly: " + filePath); // Get the config file from the resources, if there is one if (!ScanEmbeddedDescription (monitor, filePath, reflector, asm, out config)) return false; if (config == null || config.IsExtensionModel) { // In this case, only scan the assembly if it has the Addin attribute. AddinAttribute att = (AddinAttribute) reflector.GetCustomAttribute (asm, typeof(AddinAttribute), false); if (att == null) { config = null; return true; } if (config == null) config = new AddinDescription (); } config.SetBasePath (Path.GetDirectoryName (filePath)); config.AddinFile = filePath; string rasmFile = Path.GetFileName (filePath); if (!config.MainModule.Assemblies.Contains (rasmFile)) config.MainModule.Assemblies.Add (rasmFile); return ScanDescription (monitor, reflector, config, asm, scanResult); } catch (Exception ex) { // Something went wrong while scanning the assembly. We'll ignore it for now. monitor.ReportError ("There was an error while scanning assembly: " + filePath, ex); return false; } }
void DeleteAddin (IProgressStatus monitor, string file, AddinScanResult scanResult) { if (!fileDatabase.Exists (file)) return; // Add-in already existed. The dependencies of the old add-in need to be re-analized AddinDescription desc; if (ReadAddinDescription (monitor, file, out desc)) { Util.AddDependencies (desc, scanResult); if (desc.IsRoot) scanResult.HostIndex.RemoveHostData (desc.AddinId, desc.AddinFile); } else // If we can't get information about the old assembly, just regenerate all relation data scanResult.RegenerateRelationData = true; SafeDelete (monitor, file); }
bool ScanSubmodule (IProgressStatus monitor, ModuleDescription mod, IAssemblyReflector reflector, AddinDescription config, AddinScanResult scanResult, string assemblyName, object asm) { AddinDescription mconfig; ScanEmbeddedDescription (monitor, assemblyName, reflector, asm, out mconfig); if (mconfig != null) { if (!mconfig.IsExtensionModel) { monitor.ReportError ("Submodules can't define new add-ins: " + assemblyName, null); return false; } if (mconfig.OptionalModules.Count != 0) { monitor.ReportError ("Submodules can't define nested submodules: " + assemblyName, null); return false; } if (mconfig.ConditionTypes.Count != 0) { monitor.ReportError ("Submodules can't define condition types: " + assemblyName, null); return false; } if (mconfig.ExtensionNodeSets.Count != 0) { monitor.ReportError ("Submodules can't define extension node sets: " + assemblyName, null); return false; } if (mconfig.ExtensionPoints.Count != 0) { monitor.ReportError ("Submodules can't define extension points sets: " + assemblyName, null); return false; } mod.MergeWith (mconfig.MainModule); } ScanAssemblyContents (reflector, config, mod, asm, scanResult); return true; }
internal bool CheckFolders (IProgressStatus monitor) { using (fileDatabase.LockRead ()) { AddinScanResult scanResult = new AddinScanResult (); scanResult.CheckOnly = true; InternalScanFolders (monitor, scanResult); return scanResult.ChangesFound; } }
void InternalScanFolders(IProgressStatus monitor, AddinScanResult scanResult) { try { fs.ScanStarted (); InternalScanFolders2 (monitor, scanResult); } finally { fs.ScanFinished (); } }
void InternalScanFolders (IProgressStatus monitor, AddinScanResult scanResult) { DateTime tim = DateTime.Now; DatabaseInfrastructureCheck (monitor); if (monitor.IsCanceled) return; try { scanResult.HostIndex = GetAddinHostIndex (); } catch (Exception ex) { if (scanResult.CheckOnly) { scanResult.ChangesFound = true; return; } monitor.ReportError ("Add-in root index is corrupt. The add-in database will be regenerated.", ex); scanResult.RegenerateAllData = true; } AddinScanner scanner = new AddinScanner (this); // Check if any of the previously scanned folders has been deleted foreach (string file in Directory.GetFiles (AddinFolderCachePath, "*.data")) { AddinScanFolderInfo folderInfo; bool res = ReadFolderInfo (monitor, file, out folderInfo); if (!res || !Directory.Exists (folderInfo.Folder)) { if (res) { // Folder has been deleted. Remove the add-ins it had. scanner.UpdateDeletedAddins (monitor, folderInfo, scanResult); } else { // Folder info file corrupt. Regenerate all. scanResult.ChangesFound = true; scanResult.RegenerateRelationData = true; } if (!scanResult.CheckOnly) SafeDelete (monitor, file); else return; } } // Look for changes in the add-in folders foreach (string dir in registry.AddinDirectories) { if (dir == registry.DefaultAddinsFolder) scanner.ScanFolderRec (monitor, dir, scanResult); else scanner.ScanFolder (monitor, dir, scanResult); if (scanResult.CheckOnly) { if (scanResult.ChangesFound || monitor.IsCanceled) return; } } if (scanResult.CheckOnly) return; // Scan the files which have been modified currentScanResult = scanResult; foreach (FileToScan file in scanResult.FilesToScan) scanner.ScanFile (monitor, file.File, file.AddinScanFolderInfo, scanResult); // Save folder info foreach (AddinScanFolderInfo finfo in scanResult.ModifiedFolderInfos) SaveFolderInfo (monitor, finfo); if (monitor.VerboseLog) monitor.Log ("Folders scan completed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)"); SaveAddinHostIndex (); ResetCachedData (); if (!scanResult.ChangesFound) { if (monitor.VerboseLog) monitor.Log ("No changes found"); return; } tim = DateTime.Now; try { if (scanResult.RegenerateRelationData) scanResult.AddinsToUpdateRelations = null; GenerateAddinExtensionMapsInternal (monitor, scanResult.AddinsToUpdateRelations, scanResult.RemovedAddins); } catch (Exception ex) { fatalDatabseError = true; monitor.ReportError ("The add-in database could not be updated. It may be due to file corruption. Try running the setup repair utility", ex); } if (monitor.VerboseLog) monitor.Log ("Add-in relations analyzed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)"); SaveAddinHostIndex (); }
public void ScanFolder(IProgressStatus monitor, string path, string domain, AddinScanResult scanResult) { path = Util.GetFullPath(path); // Avoid folders including each other if (!scanResult.VisitFolder(path)) { return; } if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly) { monitor.Log("Checking: " + path); } AddinScanFolderInfo folderInfo; if (!database.GetFolderInfoForPath(monitor, path, out folderInfo)) { // folderInfo file was corrupt. // Just in case, we are going to regenerate all relation data. if (!Directory.Exists(path)) { scanResult.RegenerateRelationData = true; } } else { if (folderInfo == null && !Directory.Exists(path)) { return; } } // if domain is null it means that a new domain has to be created. bool sharedFolder = domain == AddinDatabase.GlobalDomain; if (folderInfo == null) { folderInfo = new AddinScanFolderInfo(path); } if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain)) { // If the folder already has a domain, reuse it if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain) { domain = folderInfo.RootsDomain; } else if (domain == null) { folderInfo.Domain = domain = database.GetUniqueDomainId(); scanResult.RegenerateRelationData = true; } else { folderInfo.Domain = domain; scanResult.RegenerateRelationData = true; } } else if (!folderInfo.SharedFolder && sharedFolder) { scanResult.RegenerateRelationData = true; } folderInfo.SharedFolder = sharedFolder; if (Directory.Exists(path)) { string[] files = Directory.GetFiles(path); // First of all, look for .addin files. Addin files must be processed before // assemblies, because they may add files to the ignore list (i.e., assemblies // included in .addin files won't be scanned twice). foreach (string file in files) { if (file.EndsWith(".addin.xml") || file.EndsWith(".addin")) { RegisterFileToScan(monitor, file, scanResult, folderInfo); } } foreach (string file in files) { switch (Path.GetExtension(file)) { case ".dll": case ".exe": RegisterFileToScan(monitor, file, scanResult, folderInfo); scanResult.AddAssemblyLocation(file); break; case ".addins": ScanAddinsFile(monitor, file, domain, scanResult); break; } } } else if (!scanResult.LocateAssembliesOnly) { // The folder has been deleted. All add-ins defined in that folder should also be deleted. scanResult.RegenerateRelationData = true; scanResult.ChangesFound = true; if (scanResult.CheckOnly) { return; } database.DeleteFolderInfo(monitor, folderInfo); } if (scanResult.LocateAssembliesOnly) { return; } // Look for deleted add-ins. UpdateDeletedAddins(monitor, folderInfo, scanResult); }