/trunk/managed/Mono.Addins.Lite/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
C# | 1964 lines | 1550 code | 291 blank | 123 comment | 400 complexity | 1d0882a95da15096cbb471b4e81baf8b MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, MIT, LGPL-2.1, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, GPL-3.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- //
- // AddinDatabase.cs
- //
- // Author:
- // Lluis Sanchez Gual
- //
- // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Threading;
- using System.Collections;
- using System.Collections.Specialized;
- using System.IO;
- using System.Xml;
- using System.Reflection;
- using Mono.Addins.Description;
- using System.Collections.Generic;
- using System.Linq;
- namespace Mono.Addins.Database
- {
- class AddinDatabase
- {
- public const string GlobalDomain = "global";
- public const string UnknownDomain = "unknown";
-
- public const string VersionTag = "001";
- List<Addin> allSetupInfos;
- List<Addin> addinSetupInfos;
- List<Addin> rootSetupInfos;
- internal static bool RunningSetupProcess;
- bool fatalDatabseError;
- Hashtable cachedAddinSetupInfos = new Hashtable ();
- AddinScanResult currentScanResult;
- AddinHostIndex hostIndex;
- FileDatabase fileDatabase;
- string addinDbDir;
- DatabaseConfiguration config = null;
- AddinRegistry registry;
- int lastDomainId;
- AddinEngine addinEngine;
- AddinFileSystemExtension fs = new AddinFileSystemExtension ();
- List<object> extensions = new List<object> ();
-
- public AddinDatabase (AddinEngine addinEngine, AddinRegistry registry)
- {
- this.addinEngine = addinEngine;
- this.registry = registry;
- addinDbDir = Path.Combine (registry.AddinCachePath, "addin-db-" + VersionTag);
- fileDatabase = new FileDatabase (AddinDbDir);
- }
-
- string AddinDbDir {
- get { return addinDbDir; }
- }
-
- public AddinFileSystemExtension FileSystem {
- get { return fs; }
- }
-
- public string AddinCachePath {
- get { return Path.Combine (AddinDbDir, "addin-data"); }
- }
-
- public string AddinFolderCachePath {
- get { return Path.Combine (AddinDbDir, "addin-dir-data"); }
- }
-
- public string AddinPrivateDataPath {
- get { return Path.Combine (AddinDbDir, "addin-priv-data"); }
- }
-
- public string HostsPath {
- get { return Path.Combine (AddinDbDir, "hosts"); }
- }
-
- string HostIndexFile {
- get { return Path.Combine (AddinDbDir, "host-index"); }
- }
-
- string ConfigFile {
- get { return Path.Combine (AddinDbDir, "config.xml"); }
- }
-
- internal bool IsGlobalRegistry {
- get {
- return registry.RegistryPath == AddinRegistry.GlobalRegistryPath;
- }
- }
-
- public AddinRegistry Registry {
- get {
- return this.registry;
- }
- }
-
- public void Clear ()
- {
- if (Directory.Exists (AddinCachePath))
- Directory.Delete (AddinCachePath, true);
- if (Directory.Exists (AddinFolderCachePath))
- Directory.Delete (AddinFolderCachePath, true);
- }
-
- public void CopyExtensions (AddinDatabase other)
- {
- foreach (object o in other.extensions)
- RegisterExtension (o);
- }
-
- public void RegisterExtension (object extension)
- {
- extensions.Add (extension);
- if (extension is AddinFileSystemExtension)
- fs = (AddinFileSystemExtension) extension;
- else
- throw new NotSupportedException ();
- }
-
- public void UnregisterExtension (object extension)
- {
- extensions.Remove (extension);
- if ((extension as AddinFileSystemExtension) == fs)
- fs = new AddinFileSystemExtension ();
- else
- throw new InvalidOperationException ();
- }
-
- public ExtensionNodeSet FindNodeSet (string domain, string addinId, string id)
- {
- return FindNodeSet (domain, addinId, id, new Hashtable ());
- }
-
- ExtensionNodeSet FindNodeSet (string domain, string addinId, string id, Hashtable visited)
- {
- if (visited.Contains (addinId))
- return null;
- visited.Add (addinId, addinId);
- Addin addin = GetInstalledAddin (domain, addinId, true, false);
- if (addin == null)
- return null;
- AddinDescription desc = addin.Description;
- if (desc == null)
- return null;
- foreach (ExtensionNodeSet nset in desc.ExtensionNodeSets)
- if (nset.Id == id)
- return nset;
-
- // Not found in the add-in. Look on add-ins on which it depends
-
- foreach (Dependency dep in desc.MainModule.Dependencies) {
- AddinDependency adep = dep as AddinDependency;
- if (adep == null) continue;
-
- string aid = Addin.GetFullId (desc.Namespace, adep.AddinId, adep.Version);
- ExtensionNodeSet nset = FindNodeSet (domain, aid, id, visited);
- if (nset != null)
- return nset;
- }
- return null;
- }
-
- public IEnumerable<Addin> GetInstalledAddins (string domain, AddinSearchFlagsInternal flags)
- {
- if (domain == null)
- domain = registry.CurrentDomain;
-
- // Get the cached list if the add-in list has already been loaded.
- // The domain doesn't have to be checked again, since it is always the same
-
- IEnumerable<Addin> result = null;
-
- if ((flags & AddinSearchFlagsInternal.IncludeAll) == AddinSearchFlagsInternal.IncludeAll) {
- if (allSetupInfos != null)
- result = allSetupInfos;
- }
- else if ((flags & AddinSearchFlagsInternal.IncludeAddins) == AddinSearchFlagsInternal.IncludeAddins) {
- if (addinSetupInfos != null)
- result = addinSetupInfos;
- }
- else {
- if (rootSetupInfos != null)
- result = rootSetupInfos;
- }
-
- if (result == null) {
- InternalCheck (domain);
- using (fileDatabase.LockRead ()) {
- result = InternalGetInstalledAddins (domain, null, flags & ~AddinSearchFlagsInternal.LatestVersionsOnly);
- }
- }
-
- if ((flags & AddinSearchFlagsInternal.LatestVersionsOnly) == AddinSearchFlagsInternal.LatestVersionsOnly)
- result = result.Where (a => a.IsLatestVersion);
-
- if ((flags & AddinSearchFlagsInternal.ExcludePendingUninstall) == AddinSearchFlagsInternal.ExcludePendingUninstall)
- result = result.Where (a => !IsRegisteredForUninstall (a.Description.Domain, a.Id));
-
- return result;
- }
-
- IEnumerable<Addin> InternalGetInstalledAddins (string domain, AddinSearchFlagsInternal type)
- {
- return InternalGetInstalledAddins (domain, null, type);
- }
-
- IEnumerable<Addin> InternalGetInstalledAddins (string domain, string idFilter, AddinSearchFlagsInternal type)
- {
- if ((type & AddinSearchFlagsInternal.LatestVersionsOnly) != 0)
- throw new InvalidOperationException ("LatestVersionsOnly flag not supported here");
-
- if (allSetupInfos == null) {
- Dictionary<string,Addin> adict = new Dictionary<string, Addin> ();
- // Global add-ins are valid for any private domain
- if (domain != AddinDatabase.GlobalDomain)
- FindInstalledAddins (adict, AddinDatabase.GlobalDomain, idFilter);
- FindInstalledAddins (adict, domain, idFilter);
- List<Addin> alist = new List<Addin> (adict.Values);
- UpdateLastVersionFlags (alist);
- if (idFilter != null)
- return alist;
- allSetupInfos = alist;
- }
- if ((type & AddinSearchFlagsInternal.IncludeAll) == AddinSearchFlagsInternal.IncludeAll)
- return FilterById (allSetupInfos, idFilter);
-
- if ((type & AddinSearchFlagsInternal.IncludeAddins) == AddinSearchFlagsInternal.IncludeAddins) {
- if (addinSetupInfos == null) {
- addinSetupInfos = new List<Addin> ();
- foreach (Addin adn in allSetupInfos)
- if (!adn.Description.IsRoot)
- addinSetupInfos.Add (adn);
- }
- return FilterById (addinSetupInfos, idFilter);
- }
- else {
- if (rootSetupInfos == null) {
- rootSetupInfos = new List<Addin> ();
- foreach (Addin adn in allSetupInfos)
- if (adn.Description.IsRoot)
- rootSetupInfos.Add (adn);
- }
- return FilterById (rootSetupInfos, idFilter);
- }
- }
-
- IEnumerable<Addin> FilterById (List<Addin> addins, string id)
- {
- if (id == null)
- return addins;
- return addins.Where (a => Addin.GetIdName (a.Id) == id);
- }
- void FindInstalledAddins (Dictionary<string,Addin> result, string domain, string idFilter)
- {
- if (idFilter == null)
- idFilter = "*";
- string dir = Path.Combine (AddinCachePath, domain);
- if (Directory.Exists (dir)) {
- foreach (string file in fileDatabase.GetDirectoryFiles (dir, idFilter + ",*.maddin")) {
- string id = Path.GetFileNameWithoutExtension (file);
- if (!result.ContainsKey (id)) {
- var adesc = GetInstalledDomainAddin (domain, id, true, false, false);
- if (adesc != null)
- result.Add (id, adesc);
- }
- }
- }
- }
-
- void UpdateLastVersionFlags (List<Addin> addins)
- {
- Dictionary<string,string> versions = new Dictionary<string, string> ();
- foreach (Addin a in addins) {
- string last;
- string id, version;
- Addin.GetIdParts (a.Id, out id, out version);
- if (!versions.TryGetValue (id, out last) || Addin.CompareVersions (last, version) > 0)
- versions [id] = version;
- }
- foreach (Addin a in addins) {
- string id, version;
- Addin.GetIdParts (a.Id, out id, out version);
- a.IsLatestVersion = versions [id] == version;
- }
- }
- public Addin GetInstalledAddin (string domain, string id)
- {
- return GetInstalledAddin (domain, id, false, false);
- }
-
- public Addin GetInstalledAddin (string domain, string id, bool exactVersionMatch)
- {
- return GetInstalledAddin (domain, id, exactVersionMatch, false);
- }
-
- public Addin GetInstalledAddin (string domain, string id, bool exactVersionMatch, bool enabledOnly)
- {
- // Try the given domain, and if not found, try the shared domain
- Addin ad = GetInstalledDomainAddin (domain, id, exactVersionMatch, enabledOnly, true);
- if (ad != null)
- return ad;
- if (domain != AddinDatabase.GlobalDomain)
- return GetInstalledDomainAddin (AddinDatabase.GlobalDomain, id, exactVersionMatch, enabledOnly, true);
- else
- return null;
- }
-
- Addin GetInstalledDomainAddin (string domain, string id, bool exactVersionMatch, bool enabledOnly, bool dbLockCheck)
- {
- Addin sinfo = null;
- string idd = id + " " + domain;
- object ob = cachedAddinSetupInfos [idd];
- if (ob != null) {
- sinfo = ob as Addin;
- if (sinfo != null) {
- if (!enabledOnly || sinfo.Enabled)
- return sinfo;
- if (exactVersionMatch)
- return null;
- }
- else if (enabledOnly)
- // Ignore the 'not installed' flag when disabled add-ins are allowed
- return null;
- }
-
- if (dbLockCheck)
- InternalCheck (domain);
-
- using ((dbLockCheck ? fileDatabase.LockRead () : null))
- {
- string path = GetDescriptionPath (domain, id);
- if (sinfo == null && fileDatabase.Exists (path)) {
- sinfo = new Addin (this, path);
- cachedAddinSetupInfos [idd] = sinfo;
- if (!enabledOnly || sinfo.Enabled)
- return sinfo;
- if (exactVersionMatch) {
- // Cache lookups with negative result
- cachedAddinSetupInfos [idd] = this;
- return null;
- }
- }
-
- // Exact version not found. Look for a compatible version
- if (!exactVersionMatch) {
- sinfo = null;
- string version, name, bestVersion = null;
- Addin.GetIdParts (id, out name, out version);
-
- foreach (Addin ia in InternalGetInstalledAddins (domain, name, AddinSearchFlagsInternal.IncludeAll))
- {
- if ((!enabledOnly || ia.Enabled) &&
- (version.Length == 0 || ia.SupportsVersion (version)) &&
- (bestVersion == null || Addin.CompareVersions (bestVersion, ia.Version) > 0))
- {
- bestVersion = ia.Version;
- sinfo = ia;
- }
- }
- if (sinfo != null) {
- cachedAddinSetupInfos [idd] = sinfo;
- return sinfo;
- }
- }
-
- // Cache lookups with negative result
- // Ignore the 'not installed' flag when disabled add-ins are allowed
- if (enabledOnly)
- cachedAddinSetupInfos [idd] = this;
- return null;
- }
- }
-
- public void Shutdown ()
- {
- ResetCachedData ();
- }
-
- public Addin GetAddinForHostAssembly (string domain, string assemblyLocation)
- {
- InternalCheck (domain);
- Addin ainfo = null;
-
- object ob = cachedAddinSetupInfos [assemblyLocation];
- if (ob != null)
- return ob as Addin; // Don't use a cast here is ob may not be an Addin.
- AddinHostIndex index = GetAddinHostIndex ();
- string addin, addinFile, rdomain;
- if (index.GetAddinForAssembly (assemblyLocation, out addin, out addinFile, out rdomain)) {
- string sid = addin + " " + rdomain;
- ainfo = cachedAddinSetupInfos [sid] as Addin;
- if (ainfo == null)
- ainfo = new Addin (this, GetDescriptionPath (rdomain, addin));
- cachedAddinSetupInfos [assemblyLocation] = ainfo;
- cachedAddinSetupInfos [addin + " " + rdomain] = ainfo;
- }
-
- return ainfo;
- }
-
-
- public bool IsAddinEnabled (string domain, string id)
- {
- Addin ainfo = GetInstalledAddin (domain, id);
- if (ainfo != null)
- return ainfo.Enabled;
- else
- return false;
- }
-
- internal bool IsAddinEnabled (string domain, string id, bool exactVersionMatch)
- {
- if (!exactVersionMatch)
- return IsAddinEnabled (domain, id);
- Addin ainfo = GetInstalledAddin (domain, id, exactVersionMatch, false);
- if (ainfo == null)
- return false;
- return Configuration.IsEnabled (id, ainfo.AddinInfo.EnabledByDefault);
- }
-
- public void EnableAddin (string domain, string id)
- {
- EnableAddin (domain, id, true);
- }
-
- internal void EnableAddin (string domain, string id, bool exactVersionMatch)
- {
- Addin ainfo = GetInstalledAddin (domain, id, exactVersionMatch, false);
- if (ainfo == null)
- // It may be an add-in root
- return;
- if (IsAddinEnabled (domain, id))
- return;
-
- // Enable required add-ins
-
- foreach (Dependency dep in ainfo.AddinInfo.Dependencies) {
- if (dep is AddinDependency) {
- AddinDependency adep = dep as AddinDependency;
- string adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, adep.Version);
- EnableAddin (domain, adepid, false);
- }
- }
- Configuration.SetStatus (id, true, ainfo.AddinInfo.EnabledByDefault);
- SaveConfiguration ();
- if (addinEngine != null && addinEngine.IsInitialized)
- addinEngine.ActivateAddin (id);
- }
-
- public void DisableAddin (string domain, string id)
- {
- Addin ai = GetInstalledAddin (domain, id, true);
- if (ai == null)
- throw new InvalidOperationException ("Add-in '" + id + "' not installed.");
- if (!IsAddinEnabled (domain, id))
- return;
-
- Configuration.SetStatus (id, false, ai.AddinInfo.EnabledByDefault);
- SaveConfiguration ();
-
- // Disable all add-ins which depend on it
-
- try {
- string idName = Addin.GetIdName (id);
-
- foreach (Addin ainfo in GetInstalledAddins (domain, AddinSearchFlagsInternal.IncludeAddins)) {
- foreach (Dependency dep in ainfo.AddinInfo.Dependencies) {
- AddinDependency adep = dep as AddinDependency;
- if (adep == null)
- continue;
-
- string adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, null);
- if (adepid != idName)
- continue;
-
- // The add-in that has been disabled, might be a requeriment of this one, or maybe not
- // if there is an older version available. Check it now.
-
- adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, adep.Version);
- Addin adepinfo = GetInstalledAddin (domain, adepid, false, true);
-
- if (adepinfo == null) {
- DisableAddin (domain, ainfo.Id);
- break;
- }
- }
- }
- }
- catch {
- // If something goes wrong, enable the add-in again
- Configuration.SetStatus (id, true, ai.AddinInfo.EnabledByDefault);
- SaveConfiguration ();
- throw;
- }
- if (addinEngine != null && addinEngine.IsInitialized)
- addinEngine.UnloadAddin (id);
- }
-
- public void RegisterForUninstall (string domain, string id, IEnumerable<string> files)
- {
- DisableAddin (domain, id);
- Configuration.RegisterForUninstall (id, files);
- SaveConfiguration ();
- }
- public bool IsRegisteredForUninstall (string domain, string addinId)
- {
- return Configuration.IsRegisteredForUninstall (addinId);
- }
-
- internal bool HasPendingUninstalls (string domain)
- {
- return Configuration.HasPendingUninstalls;
- }
-
- internal string GetDescriptionPath (string domain, string id)
- {
- return Path.Combine (Path.Combine (AddinCachePath, domain), id + ".maddin");
- }
-
- void InternalCheck (string domain)
- {
- // If the database is broken, don't try to regenerate it at every check.
- if (fatalDatabseError)
- return;
- bool update = false;
- using (fileDatabase.LockRead ()) {
- if (!Directory.Exists (AddinCachePath)) {
- update = true;
- }
- }
- if (update)
- Update (null, domain);
- }
-
- void GenerateAddinExtensionMapsInternal (IProgressStatus monitor, List<string> addinsToUpdate, List<string> addinsToUpdateRelations, List<string> removedAddins)
- {
- AddinUpdateData updateData = new AddinUpdateData (this, monitor);
-
- // Clear cached data
- cachedAddinSetupInfos.Clear ();
-
- // Collect all information
-
- AddinIndex addinHash = new AddinIndex ();
-
- if (monitor.LogLevel > 1)
- monitor.Log ("Generating add-in extension maps");
-
- Hashtable changedAddins = null;
- ArrayList descriptionsToSave = new ArrayList ();
- ArrayList files = new ArrayList ();
-
- bool partialGeneration = addinsToUpdate != null;
- string[] domains = GetDomains ();
-
- // Get the files to be updated
-
- if (partialGeneration) {
- changedAddins = new Hashtable ();
-
- if (monitor.LogLevel > 2)
- monitor.Log ("Doing a partial registry update.\nAdd-ins to be updated:");
- // Get the files and ids of all add-ins that have to be updated
- // Include removed add-ins: if there are several instances of the same add-in, removing one of
- // them will make other instances to show up. If there is a single instance, its files are
- // already removed.
- foreach (string sa in addinsToUpdate.Union (removedAddins)) {
- changedAddins [sa] = sa;
- if (monitor.LogLevel > 2)
- monitor.Log (" - " + sa);
- foreach (string file in GetAddinFiles (sa, domains)) {
- if (!files.Contains (file)) {
- files.Add (file);
- string an = Path.GetFileNameWithoutExtension (file);
- changedAddins [an] = an;
- if (monitor.LogLevel > 2 && an != sa)
- monitor.Log (" - " + an);
- }
- }
- }
-
- if (monitor.LogLevel > 2)
- monitor.Log ("Add-ins whose relations have to be updated:");
-
- // Get the files and ids of all add-ins whose relations have to be updated
- foreach (string sa in addinsToUpdateRelations) {
- foreach (string file in GetAddinFiles (sa, domains)) {
- if (!files.Contains (file)) {
- if (monitor.LogLevel > 2) {
- string an = Path.GetFileNameWithoutExtension (file);
- monitor.Log (" - " + an);
- }
- files.Add (file);
- }
- }
- }
- }
- else {
- foreach (string dom in domains)
- files.AddRange (fileDatabase.GetDirectoryFiles (Path.Combine (AddinCachePath, dom), "*.maddin"));
- }
-
- // Load the descriptions.
- foreach (string file in files) {
-
- AddinDescription conf;
- if (!ReadAddinDescription (monitor, file, out conf)) {
- SafeDelete (monitor, file);
- continue;
- }
- // If the original file does not exist, the description can be deleted
- if (!fs.FileExists (conf.AddinFile)) {
- SafeDelete (monitor, file);
- continue;
- }
-
- // Remove old data from the description. Remove the data of the add-ins that
- // have changed. This data will be re-added later.
-
- conf.UnmergeExternalData (changedAddins);
- descriptionsToSave.Add (conf);
-
- addinHash.Add (conf);
- }
- // Sort the add-ins, to make sure add-ins are processed before
- // all their dependencies
-
- var sorted = addinHash.GetSortedAddins ();
-
- // Register extension points and node sets
- foreach (AddinDescription conf in sorted)
- CollectExtensionPointData (conf, updateData);
-
- if (monitor.LogLevel > 2)
- monitor.Log ("Registering new extensions:");
-
- // Register extensions
- foreach (AddinDescription conf in sorted) {
- if (changedAddins == null || changedAddins.ContainsKey (conf.AddinId)) {
- if (monitor.LogLevel > 2)
- monitor.Log ("- " + conf.AddinId + " (" + conf.Domain + ")");
- CollectExtensionData (monitor, addinHash, conf, updateData);
- }
- }
-
- // Save the maps
- foreach (AddinDescription conf in descriptionsToSave) {
- ConsolidateExtensions (conf);
- conf.SaveBinary (fileDatabase);
- }
-
- if (monitor.LogLevel > 1) {
- monitor.Log ("Addin relation map generated.");
- monitor.Log (" Addins Updated: " + descriptionsToSave.Count);
- monitor.Log (" Extension points: " + updateData.RelExtensionPoints);
- monitor.Log (" Extensions: " + updateData.RelExtensions);
- monitor.Log (" Extension nodes: " + updateData.RelExtensionNodes);
- monitor.Log (" Node sets: " + updateData.RelNodeSetTypes);
- }
- }
-
- void ConsolidateExtensions (AddinDescription conf)
- {
- // Merges extensions with the same path
-
- foreach (ModuleDescription module in conf.AllModules) {
- Dictionary<string,Extension> extensions = new Dictionary<string, Extension> ();
- foreach (Extension ext in module.Extensions) {
- Extension mainExt;
- if (extensions.TryGetValue (ext.Path, out mainExt)) {
- ArrayList list = new ArrayList ();
- EnsureInsertionsSorted (ext.ExtensionNodes);
- list.AddRange (ext.ExtensionNodes);
- int pos = -1;
- foreach (ExtensionNodeDescription node in list) {
- ext.ExtensionNodes.Remove (node);
- AddNodeSorted (mainExt.ExtensionNodes, node, ref pos);
- }
- } else {
- extensions [ext.Path] = ext;
- EnsureInsertionsSorted (ext.ExtensionNodes);
- }
- }
-
- // Sort the nodes
- }
- }
-
- void EnsureInsertionsSorted (ExtensionNodeDescriptionCollection list)
- {
- // Makes sure that the nodes in the collections are properly sorted wrt insertafter and insertbefore attributes
- Dictionary<string,ExtensionNodeDescription> added = new Dictionary<string, ExtensionNodeDescription> ();
- List<ExtensionNodeDescription> halfSorted = new List<ExtensionNodeDescription> ();
- bool orderChanged = false;
-
- for (int n = list.Count - 1; n >= 0; n--) {
- ExtensionNodeDescription node = list [n];
- if (node.Id.Length > 0)
- added [node.Id] = node;
- if (node.InsertAfter.Length > 0) {
- ExtensionNodeDescription relNode;
- if (added.TryGetValue (node.InsertAfter, out relNode)) {
- // Out of order. Move it before the referenced node
- int i = halfSorted.IndexOf (relNode);
- halfSorted.Insert (i, node);
- orderChanged = true;
- } else {
- halfSorted.Add (node);
- }
- } else
- halfSorted.Add (node);
- }
- halfSorted.Reverse ();
- List<ExtensionNodeDescription> fullSorted = new List<ExtensionNodeDescription> ();
- added.Clear ();
-
- foreach (ExtensionNodeDescription node in halfSorted) {
- if (node.Id.Length > 0)
- added [node.Id] = node;
- if (node.InsertBefore.Length > 0) {
- ExtensionNodeDescription relNode;
- if (added.TryGetValue (node.InsertBefore, out relNode)) {
- // Out of order. Move it before the referenced node
- int i = fullSorted.IndexOf (relNode);
- fullSorted.Insert (i, node);
- orderChanged = true;
- } else {
- fullSorted.Add (node);
- }
- } else
- fullSorted.Add (node);
- }
- if (orderChanged) {
- list.Clear ();
- foreach (ExtensionNodeDescription node in fullSorted)
- list.Add (node);
- }
- }
-
- void AddNodeSorted (ExtensionNodeDescriptionCollection list, ExtensionNodeDescription node, ref int curPos)
- {
- // Adds the node at the correct position, taking into account insertbefore and insertafter
-
- if (node.InsertAfter.Length > 0) {
- string afterId = node.InsertAfter;
- for (int n=0; n<list.Count; n++) {
- if (list[n].Id == afterId) {
- list.Insert (n + 1, node);
- curPos = n + 2;
- return;
- }
- }
- }
- else if (node.InsertBefore.Length > 0) {
- string beforeId = node.InsertBefore;
- for (int n=0; n<list.Count; n++) {
- if (list[n].Id == beforeId) {
- list.Insert (n, node);
- curPos = n + 1;
- return;
- }
- }
- }
- if (curPos == -1)
- list.Add (node);
- else
- list.Insert (curPos++, node);
- }
-
- IEnumerable GetAddinFiles (string fullId, string[] domains)
- {
- // Look for all versions of the add-in, because this id may be the id of a reference,
- // and the exact reference version may not be installed.
- string s = fullId;
- int i = s.LastIndexOf (',');
- if (i != -1)
- s = s.Substring (0, i);
- s += ",*";
-
- // Look for the add-in in any of the existing folders
- foreach (string domain in domains) {
- string mp = GetDescriptionPath (domain, s);
- string dir = Path.GetDirectoryName (mp);
- string pat = Path.GetFileName (mp);
- foreach (string fmp in fileDatabase.GetDirectoryFiles (dir, pat))
- yield return fmp;
- }
- }
-
- // Collects extension data in a hash table. The key is the path, the value is a list
- // of add-ins ids that extend that path
-
- void CollectExtensionPointData (AddinDescription conf, AddinUpdateData updateData)
- {
- foreach (ExtensionNodeSet nset in conf.ExtensionNodeSets) {
- try {
- updateData.RegisterNodeSet (conf, nset);
- updateData.RelNodeSetTypes++;
- } catch (Exception ex) {
- throw new InvalidOperationException ("Error reading node set: " + nset.Id, ex);
- }
- }
-
- foreach (ExtensionPoint ep in conf.ExtensionPoints) {
- try {
- updateData.RegisterExtensionPoint (conf, ep);
- updateData.RelExtensionPoints++;
- } catch (Exception ex) {
- throw new InvalidOperationException ("Error reading extension point: " + ep.Path, ex);
- }
- }
- }
-
- void CollectExtensionData (IProgressStatus monitor, AddinIndex addinHash, AddinDescription conf, AddinUpdateData updateData)
- {
- IEnumerable<string> missingDeps = addinHash.GetMissingDependencies (conf, conf.MainModule);
- if (missingDeps.Any ()) {
- string w = "The add-in '" + conf.AddinId + "' could not be updated because some of its dependencies are missing or not compatible:";
- w += BuildMissingAddinsList (addinHash, conf, missingDeps);
- monitor.ReportWarning (w);
- return;
- }
-
- CollectModuleExtensionData (conf, conf.MainModule, updateData);
-
- foreach (ModuleDescription module in conf.OptionalModules) {
- missingDeps = addinHash.GetMissingDependencies (conf, module);
- if (missingDeps.Any ()) {
- if (monitor.LogLevel > 1) {
- string w = "An optional module of the add-in '" + conf.AddinId + "' could not be updated because some of its dependencies are missing or not compatible:";
- w += BuildMissingAddinsList (addinHash, conf, missingDeps);
- }
- }
- else
- CollectModuleExtensionData (conf, module, updateData);
- }
- }
-
- string BuildMissingAddinsList (AddinIndex addinHash, AddinDescription conf, IEnumerable<string> missingDeps)
- {
- string w = "";
- foreach (string dep in missingDeps) {
- var found = addinHash.GetSimilarExistingAddin (conf, dep);
- if (found == null)
- w += "\n missing: " + dep;
- else
- w += "\n required: " + dep + ", found: " + found.AddinId;
- }
- return w;
- }
-
- void CollectModuleExtensionData (AddinDescription conf, ModuleDescription module, AddinUpdateData updateData)
- {
- foreach (Extension ext in module.Extensions) {
- updateData.RelExtensions++;
- updateData.RegisterExtension (conf, module, ext);
- AddChildExtensions (conf, module, updateData, ext.Path, ext.ExtensionNodes, false);
- }
- }
-
- void AddChildExtensions (AddinDescription conf, ModuleDescription module, AddinUpdateData updateData, string path, ExtensionNodeDescriptionCollection nodes, bool conditionChildren)
- {
- // Don't register conditions as extension nodes.
- if (!conditionChildren)
- updateData.RegisterExtension (conf, module, path);
-
- foreach (ExtensionNodeDescription node in nodes) {
- if (node.NodeName == "ComplexCondition")
- continue;
- updateData.RelExtensionNodes++;
- string id = node.GetAttribute ("id");
- if (id.Length != 0)
- AddChildExtensions (conf, module, updateData, path + "/" + id, node.ChildNodes, node.NodeName == "Condition");
- }
- }
-
- string[] GetDomains ()
- {
- string[] dirs = fileDatabase.GetDirectories (AddinCachePath);
- string[] ids = new string [dirs.Length];
- for (int n=0; n<dirs.Length; n++)
- ids [n] = Path.GetFileName (dirs [n]);
- return ids;
- }
- public string GetUniqueDomainId ()
- {
- if (lastDomainId != 0) {
- lastDomainId++;
- return lastDomainId.ToString ();
- }
- lastDomainId = 1;
- foreach (string s in fileDatabase.GetDirectories (AddinCachePath)) {
- string dn = Path.GetFileName (s);
- if (dn == GlobalDomain)
- continue;
- try {
- int n = int.Parse (dn);
- if (n >= lastDomainId)
- lastDomainId = n + 1;
- } catch {
- }
- }
- return lastDomainId.ToString ();
- }
- internal void ResetBasicCachedData ()
- {
- allSetupInfos = null;
- addinSetupInfos = null;
- rootSetupInfos = null;
- }
- internal void ResetCachedData ()
- {
- ResetBasicCachedData ();
- hostIndex = null;
- cachedAddinSetupInfos.Clear ();
- if (addinEngine != null)
- addinEngine.ResetCachedData ();
- }
-
-
- public bool AddinDependsOn (string domain, string id1, string id2)
- {
- Hashtable visited = new Hashtable ();
- return AddinDependsOn (visited, domain, id1, id2);
- }
-
- bool AddinDependsOn (Hashtable visited, string domain, string id1, string id2)
- {
- if (visited.Contains (id1))
- return false;
-
- visited.Add (id1, id1);
-
- Addin addin1 = GetInstalledAddin (domain, id1, false);
-
- // We can assumbe that if the add-in is not returned here, it may be a root addin.
- if (addin1 == null)
- return false;
- id2 = Addin.GetIdName (id2);
- foreach (Dependency dep in addin1.AddinInfo.Dependencies) {
- AddinDependency adep = dep as AddinDependency;
- if (adep == null)
- continue;
- string depid = Addin.GetFullId (addin1.AddinInfo.Namespace, adep.AddinId, null);
- if (depid == id2)
- return true;
- else if (AddinDependsOn (visited, domain, depid, id2))
- return true;
- }
- return false;
- }
-
- public void Repair (IProgressStatus monitor, string domain)
- {
- using (fileDatabase.LockWrite ()) {
- try {
- if (Directory.Exists (AddinCachePath))
- Directory.Delete (AddinCachePath, true);
- if (Directory.Exists (AddinFolderCachePath))
- Directory.Delete (AddinFolderCachePath, true);
- if (File.Exists (HostIndexFile))
- File.Delete (HostIndexFile);
- }
- catch (Exception ex) {
- monitor.ReportError ("The add-in registry could not be rebuilt. It may be due to lack of write permissions to the directory: " + AddinDbDir, ex);
- }
- }
- ResetBasicCachedData ();
-
- Update (monitor, domain);
- }
-
- public void Update (IProgressStatus monitor, string domain)
- {
- if (monitor == null)
- monitor = new ConsoleProgressStatus (false);
- if (RunningSetupProcess)
- return;
-
- fatalDatabseError = false;
-
- DateTime tim = DateTime.Now;
-
- RunPendingUninstalls (monitor);
-
- Hashtable installed = new Hashtable ();
- bool changesFound = CheckFolders (monitor, domain);
-
- if (monitor.IsCanceled)
- return;
-
- if (monitor.LogLevel > 1)
- monitor.Log ("Folders checked (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
-
- if (changesFound) {
- // Something has changed, the add-ins need to be re-scanned, but it has
- // to be done in an external process
-
- if (domain != null) {
- using (fileDatabase.LockRead ()) {
- foreach (Addin ainfo in InternalGetInstalledAddins (domain, AddinSearchFlagsInternal.IncludeAddins)) {
- installed [ainfo.Id] = ainfo.Id;
- }
- }
- }
-
- RunScannerProcess (monitor);
-
- ResetCachedData ();
-
- registry.NotifyDatabaseUpdated ();
- }
-
- if (fatalDatabseError)
- monitor.ReportError ("The add-in database could not be updated. It may be due to file corruption. Try running the setup repair utility", null);
-
- // Update the currently loaded add-ins
- if (changesFound && domain != null && addinEngine != null && addinEngine.IsInitialized) {
- Hashtable newInstalled = new Hashtable ();
- foreach (Addin ainfo in GetInstalledAddins (domain, AddinSearchFlagsInternal.IncludeAddins)) {
- newInstalled [ainfo.Id] = ainfo.Id;
- }
-
- foreach (string aid in installed.Keys) {
- // Always try to unload, event if the add-in was not currently loaded.
- // Required since the add-ins has to be marked as 'disabled', to avoid
- // extensions from this add-in to be loaded
- if (!newInstalled.Contains (aid))
- addinEngine.UnloadAddin (aid);
- }
-
- foreach (string aid in newInstalled.Keys) {
- if (!installed.Contains (aid)) {
- Addin addin = addinEngine.Registry.GetAddin (aid);
- if (addin != null)
- addinEngine.ActivateAddin (aid);
- }
- }
- }
- }
-
- void RunPendingUninstalls (IProgressStatus monitor)
- {
- bool changesDone = false;
-
- foreach (var adn in Configuration.GetPendingUninstalls ()) {
- HashSet<string> files = new HashSet<string> (adn.Files);
- if (AddinManager.CheckAssembliesLoaded (files))
- continue;
-
- if (monitor.LogLevel > 1)
- monitor.Log ("Uninstalling " + adn.AddinId);
-
- // Make sure all files can be deleted before doing so
- bool canUninstall = true;
- foreach (string f in adn.Files) {
- if (!File.Exists (f))
- continue;
- try {
- File.OpenWrite (f).Close ();
- } catch {
- canUninstall = false;
- break;
- }
- }
-
- if (!canUninstall)
- continue;
-
- foreach (string f in adn.Files) {
- try {
- if (File.Exists (f))
- File.Delete (f);
- } catch {
- canUninstall = false;
- }
- }
-
- if (canUninstall) {
- Configuration.UnregisterForUninstall (adn.AddinId);
- changesDone = true;
- }
- }
- if (changesDone)
- SaveConfiguration ();
- }
-
- void RunScannerProcess (IProgressStatus monitor)
- {
- ISetupHandler setup = GetSetupHandler ();
-
- IProgressStatus scanMonitor = monitor;
- ArrayList pparams = new ArrayList ();
-
- bool retry = false;
- do {
- try {
- if (monitor.LogLevel > 1)
- monitor.Log ("Looking for addins");
- setup.Scan (scanMonitor, registry, null, (string[]) pparams.ToArray (typeof(string)));
- retry = false;
- }
- catch (Exception ex) {
- ProcessFailedException pex = ex as ProcessFailedException;
- if (pex != null) {
- // Get the last logged operation.
- if (pex.LastLog.StartsWith ("scan:")) {
- // It crashed while scanning a file. Add the file to the ignore list and try again.
- string file = pex.LastLog.Substring (5);
- pparams.Add (file);
- monitor.ReportWarning ("Could not scan file: " + file);
- retry = true;
- continue;
- }
- }
- fatalDatabseError = true;
- // If the process has crashed, try to do a new scan, this time using verbose log,
- // to give the user more information about the origin of the crash.
- if (pex != null && !retry) {
- monitor.ReportError ("Add-in scan operation failed. The Mono runtime may have encountered an error while trying to load an assembly.", null);
- if (monitor.LogLevel <= 1) {
- // Re-scan again using verbose log, to make it easy to find the origin of the error.
- retry = true;
- scanMonitor = new ConsoleProgressStatus (true);
- }
- } else
- retry = false;
-
- if (!retry) {
- monitor.ReportError ("Add-in scan operation failed", (ex is ProcessFailedException ? null : ex));
- monitor.Cancel ();
- return;
- }
- }
- }
- while (retry);
- }
-
- bool DatabaseInfrastructureCheck (IProgressStatus monitor)
- {
- // Do some sanity check, to make sure the basic database infrastructure can be created
-
- bool hasChanges = false;
-
- try {
-
- if (!Directory.Exists (AddinCachePath)) {
- Directory.CreateDirectory (AddinCachePath);
- hasChanges = true;
- }
-
- if (!Directory.Exists (AddinFolderCachePath)) {
- Directory.CreateDirectory (AddinFolderCachePath);
- hasChanges = true;
- }
-
- // Make sure we can write in those folders
- Util.CheckWrittableFloder (AddinCachePath);
- Util.CheckWrittableFloder (AddinFolderCachePath);
-
- fatalDatabseError = false;
- }
- catch (Exception ex) {
- monitor.ReportError ("Add-in cache directory could not be created", ex);
- fatalDatabseError = true;
- monitor.Cancel ();
- }
- return hasChanges;
- }
-
-
- internal bool CheckFolders (IProgressStatus monitor, string domain)
- {
- using (fileDatabase.LockRead ()) {
- AddinScanResult scanResult = new AddinScanResult ();
- scanResult.CheckOnly = true;
- scanResult.Domain = domain;
- InternalScanFolders (monitor, scanResult);
- return scanResult.ChangesFound;
- }
- }
-
- internal void ScanFolders (IProgressStatus monitor, string currentDomain, string folderToScan, StringCollection filesToIgnore)
- {
- AddinScanResult res = new AddinScanResult ();
- res.Domain = currentDomain;
- res.AddPathsToIgnore (filesToIgnore);
- ScanFolders (monitor, res);
- }
-
- 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);
- }
- }
- }
-
- void InternalScanFolders (IProgressStatus monitor, AddinScanResult scanResult)
- {
- try {
- fs.ScanStarted ();
- InternalScanFolders2 (monitor, scanResult);
- } finally {
- fs.ScanFinished ();
- }
- }
-
- void InternalScanFolders2 (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, scanResult, monitor);
-
- // 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);
- bool validForDomain = scanResult.Domain == null || folderInfo.Domain == GlobalDomain || folderInfo.Domain == scanResult.Domain;
- if (!res || (validForDomain && !fs.DirectoryExists (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 if (scanResult.ChangesFound)
- return;
- }
- }
-
- // Look for changes in the add-in folders
-
- if (registry.StartupDirectory != null)
- scanner.ScanFolder (monitor, registry.StartupDirectory, null, scanResult);
-
- if (scanResult.CheckOnly && (scanResult.ChangesFound || monitor.IsCanceled))
- return;
-
- if (scanResult.Domain == null)
- scanner.ScanFolder (monitor, HostsPath, GlobalDomain, scanResult);
-
- if (scanResult.CheckOnly && (scanResult.ChangesFound || monitor.IsCanceled))
- return;
-
- foreach (string dir in registry.GlobalAddinDirectories) {
- if (scanResult.CheckOnly && (scanResult.ChangesFound || monitor.IsCanceled))
- return;
- scanner.ScanFolderRec (monitor, dir, GlobalDomain, scanResult);
- }
-
- if (scanResult.CheckOnly || !scanResult.ChangesFound)
- 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.LogLevel > 1)
- monitor.Log ("Folders scan completed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
- SaveAddinHostIndex ();
- ResetCachedData ();
-
- if (!scanResult.ChangesFound) {
- if (monitor.LogLevel > 1)
- monitor.Log ("No changes found");
- return;
- }
-
- tim = DateTime.Now;
- try {
- if (scanResult.RegenerateRelationData) {
- if (monitor.LogLevel > 1)
- monitor.Log ("Regenerating all add-in relations.");
- scanResult.AddinsToUpdate = null;
- scanResult.AddinsToUpdateRelations = null;
- }
-
- GenerateAddinExtensionMapsInternal (monitor, scanResult.AddinsToUpdate, 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.LogLevel > 1)
- monitor.Log ("Add-in relations analyzed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
-
- SaveAddinHostIndex ();
- }
-
- 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)
- desc.Save (outFile);
- }
- finally {
- AppDomain.CurrentDomain.AssemblyResolve -= resolver;
- if (einfo != null) einfo.RemoveEventHandler (AppDomain.CurrentDomain, resolver);
- }
- }
- }
-
- public string GetFolderDomain (IProgressStatus progressStatus, string path)
- {
- AddinScanFolderInfo folderInfo;
- if (GetFolderInfoForPath (progressStatus, path, out folderInfo) && folderInfo != null && !folderInfo.SharedFolder)
- return folderInfo.Domain;
- else
- return UnknownDomain;
- }
-
- Assembly OnResolveAddinAssembly (object s, ResolveEventArgs args)
- {
- string file = currentScanResult != null ? currentScanResult.GetAssemblyLocation (args.Name) : null;
- if (file != null)
- return Util.LoadAssemblyForReflection (file);
- else {
- if (!args.Name.StartsWith ("Mono.Addins.CecilReflector"))
- Console.WriteLine ("Assembly not found: " + args.Name);
- return null;
- }
- }
-
- public string GetFolderConfigFile (string path)
- {
- path = Path.GetFullPath (path);
-
- string s = path.Replace ("_", "__");
- s = s.Replace (Path.DirectorySeparatorChar, '_');
- s = s.Replace (Path.AltDirectorySeparatorChar, '_');
- s = s.Replace (Path.VolumeSeparatorChar, '_');
-
- return Path.Combine (AddinFolderCachePath, s + ".data");
- }
-
- 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-analized
-
- Util.AddDependencies (desc, scanResult);
- if (desc.IsRoot)
- scanResult.HostIndex.RemoveHostData (desc.AddinId, desc.AddinFile);
- RemoveAddinDescriptionFile (monitor, desc.FileName);
- }
-
- public bool GetAddinDescription (IProgressStatus monitor, string domain, string addinId, string addinFile, out AddinDescription description)
- {
- // If the same add-in is installed in different folders (in the same domain) there will be several .maddin files for it,
- // using the suffix "_X" where X is a number > 1 (for example: someAddin,1.0.maddin, someAddin,1.0.maddin_2, someAddin,1.0.maddin_3, ...)
- // We need to return the .maddin whose AddinFile matches the one being requested
-
- addinFile = Path.GetFullPath (addinFile);
- int altNum = 1;
- string baseFile = GetDescriptionPath (domain, addinId);
- string file = baseFile;
- bool failed = false;
-
- do {
- if (!ReadAddinDescription (monitor, file, out description)) {
- // Remove the AddinDescription here since it is corrupted.
- // Avoids creating alternate versions of corrupted files when later calling SaveDescription.
- RemoveAddinDescriptionFile (monitor, file);
- failed = true;
- continue;
- }
- if (description == null)
- break;
- if (Path.GetFullPath (description.AddinFile) == addinFile)
- return true;
- file = baseFile + "_" + (++altNum);
- }
- while (fileDatabase.Exists (file));
-
- // File not found. Return false only if there has been any read error.
- description = null;
- return failed;
- }
-
- bool RemoveAddinDescriptionFile (IProgressStatus monitor, string file)
- {
- // Removes an add-in description and shifts up alternate instances of the description file
- // (so xxx,1.0.maddin_2 will become xxx,1.0.maddin, xxx,1.0.maddin_3 -> xxx,1.0.maddin_2, etc)
-
- if (!SafeDelete (monitor, file))
- return false;
-
- int dversion;
- if (file.EndsWith (".maddin"))
- dversion = 2;
- else {
- int i = file.LastIndexOf ('_');
- dversion = 1 + int.Parse (file.Substring (i + 1));
- file = file.Substring (0, i);
- }
- while (fileDatabase.Exists (file + "_" + dversion)) {
- string newFile = dversion == 2 ? file : file + "_" + (dversion-1);
- try {
- fileDatabase.Rename (file + "_" + dversion, newFile);
- } catch (Exception ex) {
- if (monitor.LogLevel > 1) {
- monitor.Log ("Could not rename file '" + file + "_" + dversion + "' to '" + newFile + "'");
- monitor.Log (ex.ToString ());
- }
- }
- dversion++;
- }
- string dir = Path.GetDirectoryName (file);
- if (fileDatabase.DirectoryIsEmpty (dir))
- SafeDeleteDir (monitor, dir);
-
- if (dversion == 2) {
- // All versions of the add-in removed.
- SafeDeleteDir (monitor, Path.Combine (AddinPrivateDataPath, Path.GetFileNameWithoutExtension (file)));
- }
-
- return true;
- }
-
- public bool ReadAddinDescription (IProgressStatus monitor, string file, out AddinDescription description)
- {
- try {
- description = AddinDescription.ReadBinary (fileDatabase, file);
- if (description != null)
- description.OwnerDatabase = this;
- return true;
- }
- catch (Exception ex) {
- if (monitor == null)
- throw;
- description = null;
- monitor.Rep…
Large files files are truncated, but you can click here to view the full file