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.AddFileToIgnore(Util.GetFullPath(file)); } foreach (string s in config.MainModule.Assemblies) { string asmFile = Path.Combine(config.BasePath, s); asmFiles.Add(asmFile); Assembly asm = Util.LoadAssemblyForReflection(asmFile); assemblies.Add(asm); scanResult.AddFileToIgnore(Util.GetFullPath(asmFile)); } 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); } } catch (Exception ex) { ReportReflectionException(monitor, ex, config, scanResult); 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(); 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); Assembly asm = Util.LoadAssemblyForReflection(asmFile); assemblies.Add(asm); scanResult.AddFileToIgnore(Util.GetFullPath(asmFile)); } foreach (Assembly asm in assemblies) { ScanAssemblyContents(config, asm, null, scanResult); } } catch (Exception ex) { ReportReflectionException(monitor, ex, config, scanResult); } } } config.StoreFileInfo(); return(true); }
public void ScanAddinsFile(IProgressStatus monitor, string file, string domain, AddinScanResult scanResult) { XmlTextReader r = null; ArrayList directories = new ArrayList(); ArrayList directoriesWithSubdirs = new ArrayList(); 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) { 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.GetGacPath(aname); if (aname != null) { // Gac assemblies always use the global domain directories.Add(new string[] { aname, AddinDatabase.GlobalDomain }); } } } 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(Path.GetDirectoryName(file), dir); } ScanFolder(monitor, dir, d[1], scanResult); } foreach (string[] d in directoriesWithSubdirs) { string dir = d[0]; if (!Path.IsPathRooted(dir)) { dir = Path.Combine(Path.GetDirectoryName(file), 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; } 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); }
public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult) { if (scanResult.IgnoreFile(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; 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 = 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) { 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); } } 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); monitor.Log("plog:endscan"); } }