Beispiel #1
0
        static string GetDomain(string path)
        {
            path = Util.GetFullPath(path);
            string s = path.Replace(Path.DirectorySeparatorChar, '_');

            s = s.Replace(Path.AltDirectorySeparatorChar, '_');
            s = s.Replace(Path.VolumeSeparatorChar, '_');
            s = s.Trim('_');
            return(s);
        }
Beispiel #2
0
        static string GetFolderId(string path)
        {
            path = Util.GetFullPath(path);
            string s = path.Replace(Path.DirectorySeparatorChar, '_');

            s = s.Replace(Path.AltDirectorySeparatorChar, '_');
            s = s.Replace(Path.VolumeSeparatorChar, '_');
            s = s.Trim('_');
            if (s.Length > 200)
            {
                s = s.Substring(s.Length - 200);
            }
            return(s);
        }
Beispiel #3
0
        public void RemoveHostData(string addinId, string addinLocation)
        {
            string    loc      = addinId + " " + Util.GetFullPath(addinLocation) + " ";
            ArrayList todelete = new ArrayList();

            foreach (DictionaryEntry e in index)
            {
                if (((string)e.Value).StartsWith(loc))
                {
                    todelete.Add(e.Key);
                }
            }
            foreach (string s in todelete)
            {
                index.Remove(s);
            }
        }
        public bool GetAddinForAssembly(string assemblyLocation, out string addinId, out string addinLocation)
        {
            assemblyLocation = NormalizeFileName(assemblyLocation);
            string s = index [Util.GetFullPath(assemblyLocation)] as string;

            if (s == null)
            {
                addinId       = null;
                addinLocation = null;
                return(false);
            }
            else
            {
                int i = s.IndexOf(' ');
                addinId       = s.Substring(0, i);
                addinLocation = s.Substring(i + 1);
                return(true);
            }
        }
        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);
        }
        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 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 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 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");
            }
        }
Beispiel #10
0
 public void Write(FileDatabase filedb, string basePath)
 {
     filedb.WriteSharedObject(basePath, GetDomain(folder), ".data", Util.GetFullPath(folder), fileName, typeMap, this);
 }
Beispiel #11
0
        public static AddinScanFolderInfo Read(FileDatabase filedb, string basePath, string folderPath)
        {
            string fileName;
            AddinScanFolderInfo finfo = (AddinScanFolderInfo)filedb.ReadSharedObject(basePath, GetDomain(folderPath), ".data", Util.GetFullPath(folderPath), typeMap, out fileName);

            if (finfo != null)
            {
                finfo.fileName = fileName;
            }
            return(finfo);
        }
Beispiel #12
0
 public void RegisterAssembly(string assemblyLocation, string addinId, string addinLocation, string domain)
 {
     assemblyLocation = NormalizeFileName(assemblyLocation);
     index [Util.GetFullPath(assemblyLocation)] = addinId + " " + addinLocation + " " + domain;
 }
Beispiel #13
0
        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);
        }