Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-addins.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLluis Sanchez Gual <lluis@novell.com>2011-04-07 16:14:02 +0400
committerLluis Sanchez Gual <lluis@novell.com>2011-04-07 16:14:02 +0400
commita3bf1a090e4e0c2caea0e859b88f7c2c659322ea (patch)
tree026776292aa72d63155c7c95ee341d2f5d7ebbb8
parent340763ff61088c80a7bff3778a7484f71c874758 (diff)
Properly handle multiple installed instances of the same add-in version
Multiple installed instances of the same add-in version are now tolerated, an won't cause add-in database inconsistencies anymore.
-rw-r--r--Mono.Addins/Mono.Addins.Database/AddinDatabase.cs143
-rw-r--r--Mono.Addins/Mono.Addins.Database/AddinScanResult.cs13
-rw-r--r--Mono.Addins/Mono.Addins.Database/AddinScanner.cs6
-rw-r--r--Mono.Addins/Mono.Addins.Database/FileDatabase.cs14
4 files changed, 134 insertions, 42 deletions
diff --git a/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs b/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
index 3e57ea1..acff88a 100644
--- a/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
+++ b/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
@@ -229,13 +229,14 @@ namespace Mono.Addins.Database
throw new InvalidOperationException ("LatestVersionsOnly flag not supported here");
if (allSetupInfos == null) {
- List<Addin> alist = new List<Addin> ();
+ Dictionary<string,Addin> adict = new Dictionary<string, Addin> ();
// Global add-ins are valid for any private domain
if (domain != AddinDatabase.GlobalDomain)
- FindInstalledAddins (alist, AddinDatabase.GlobalDomain, idFilter);
+ FindInstalledAddins (adict, AddinDatabase.GlobalDomain, idFilter);
- FindInstalledAddins (alist, domain, idFilter);
+ FindInstalledAddins (adict, domain, idFilter);
+ List<Addin> alist = new List<Addin> (adict.Values);
UpdateLastVersionFlags (alist);
if (idFilter != null)
return alist;
@@ -271,7 +272,7 @@ namespace Mono.Addins.Database
return addins.Where (a => Addin.GetIdName (a.Id) == id);
}
- void FindInstalledAddins (List<Addin> result, string domain, string idFilter)
+ void FindInstalledAddins (Dictionary<string,Addin> result, string domain, string idFilter)
{
if (idFilter == null)
idFilter = "*";
@@ -279,7 +280,11 @@ namespace Mono.Addins.Database
if (Directory.Exists (dir)) {
foreach (string file in fileDatabase.GetDirectoryFiles (dir, idFilter + ",*.maddin")) {
string id = Path.GetFileNameWithoutExtension (file);
- result.Add (GetInstalledDomainAddin (domain, id, true, false, false));
+ if (!result.ContainsKey (id)) {
+ var adesc = GetInstalledDomainAddin (domain, id, true, false, false);
+ if (adesc != null)
+ result.Add (id, adesc);
+ }
}
}
}
@@ -541,7 +546,7 @@ namespace Mono.Addins.Database
Update (null, domain);
}
- void GenerateAddinExtensionMapsInternal (IProgressStatus monitor, ArrayList addinsToUpdate, ArrayList addinsToUpdateRelations, ArrayList removedAddins)
+ void GenerateAddinExtensionMapsInternal (IProgressStatus monitor, List<string> addinsToUpdate, List<string> addinsToUpdateRelations, List<string> removedAddins)
{
AddinUpdateData updateData = new AddinUpdateData (this, monitor);
@@ -570,7 +575,10 @@ namespace Mono.Addins.Database
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
- foreach (string sa in addinsToUpdate) {
+ // 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);
@@ -600,9 +608,6 @@ namespace Mono.Addins.Database
}
}
}
-
- foreach (string s in removedAddins)
- changedAddins [s] = s;
}
else {
foreach (string dom in domains)
@@ -1342,7 +1347,7 @@ namespace Mono.Addins.Database
AddinFileInfo afi = finfo.GetAddinFileInfo (file);
if (afi != null && afi.IsAddin) {
AddinDescription adesc;
- GetAddinDescription (progressStatus, afi.Domain, afi.AddinId, out adesc);
+ GetAddinDescription (progressStatus, afi.Domain, afi.AddinId, file, out adesc);
if (adesc != null)
adesc.Save (outFile);
return;
@@ -1406,36 +1411,102 @@ namespace Mono.Addins.Database
return Path.Combine (AddinFolderCachePath, s + ".data");
}
- internal void UninstallAddin (IProgressStatus monitor, string domain, string addinId, AddinScanResult scanResult)
+ internal void UninstallAddin (IProgressStatus monitor, string domain, string addinId, string addinFile, AddinScanResult scanResult)
{
- scanResult.AddRemovedAddin (addinId);
- string file = GetDescriptionPath (domain, addinId);
- if (!fileDatabase.Exists (file)) {
+ 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;
}
- // Add-in already existed. The dependencies of the old add-in need to be re-analized
+ // 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);
- 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;
+ 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);
+ }
- SafeDelete (monitor, file);
+ 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);
- SafeDeleteDir (monitor, Path.Combine (AddinPrivateDataPath, Path.GetFileNameWithoutExtension (file)));
- }
-
- public bool GetAddinDescription (IProgressStatus monitor, string domain, string addinId, out AddinDescription description)
- {
- string file = GetDescriptionPath (domain, addinId);
- return ReadAddinDescription (monitor, file, out description);
+
+ 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)
@@ -1465,6 +1536,14 @@ namespace Mono.Addins.Database
string dir = Path.GetDirectoryName (file);
if (!fileDatabase.DirExists (dir))
fileDatabase.CreateDir (dir);
+ if (fileDatabase.Exists (file)) {
+ // Another AddinDescription already exists with the same name.
+ // Create an alternate AddinDescription file
+ int altNum = 2;
+ while (fileDatabase.Exists (file + "_" + altNum))
+ altNum++;
+ file = file + "_" + altNum;
+ }
desc.SaveBinary (fileDatabase, file);
}
return true;
diff --git a/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs b/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs
index f69bec8..4a3fbf5 100644
--- a/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs
+++ b/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs
@@ -28,24 +28,23 @@
using System;
-using System.Reflection;
-using System.IO;
using System.Collections;
-using System.Collections.Specialized;
-using Mono.Addins.Description;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
namespace Mono.Addins.Database
{
internal class AddinScanResult: MarshalByRefObject, IAssemblyLocator
{
internal ArrayList AddinsToScan = new ArrayList ();
- internal ArrayList AddinsToUpdateRelations = new ArrayList ();
- internal ArrayList AddinsToUpdate = new ArrayList ();
+ internal List<string> AddinsToUpdateRelations = new List<string> ();
+ internal List<string> AddinsToUpdate = new List<string> ();
internal ArrayList FilesToScan = new ArrayList ();
internal ArrayList ModifiedFolderInfos = new ArrayList ();
internal ArrayList FilesWithScanFailure = new ArrayList ();
internal AddinHostIndex HostIndex;
- internal ArrayList RemovedAddins = new ArrayList ();
+ internal List<string> RemovedAddins = new List<string> ();
Hashtable visitedFolders = new Hashtable ();
Hashtable assemblyLocations = new Hashtable ();
diff --git a/Mono.Addins/Mono.Addins.Database/AddinScanner.cs b/Mono.Addins/Mono.Addins.Database/AddinScanner.cs
index 613610b..2b5db01 100644
--- a/Mono.Addins/Mono.Addins.Database/AddinScanner.cs
+++ b/Mono.Addins/Mono.Addins.Database/AddinScanner.cs
@@ -179,7 +179,7 @@ namespace Mono.Addins.Database
return;
foreach (AddinFileInfo info in missing) {
- database.UninstallAddin (monitor, info.Domain, info.AddinId, scanResult);
+ database.UninstallAddin (monitor, info.Domain, info.AddinId, info.File, scanResult);
}
}
}
@@ -288,7 +288,7 @@ namespace Mono.Addins.Database
// 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);
+ 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)
@@ -306,7 +306,7 @@ namespace Mono.Addins.Database
// 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);
+ 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))
diff --git a/Mono.Addins/Mono.Addins.Database/FileDatabase.cs b/Mono.Addins/Mono.Addins.Database/FileDatabase.cs
index ac4f626..b96f33d 100644
--- a/Mono.Addins/Mono.Addins.Database/FileDatabase.cs
+++ b/Mono.Addins/Mono.Addins.Database/FileDatabase.cs
@@ -153,6 +153,20 @@ namespace Mono.Addins.Database
return File.Create (fileName);
}
+ public void Rename (string fileName, string newName)
+ {
+ if (inTransaction) {
+ deletedFiles.Remove (newName);
+ deletedDirs.Remove (Path.GetDirectoryName (newName));
+ foldersToUpdate [Path.GetDirectoryName (newName)] = null;
+ string s = File.Exists (fileName + ".new") ? fileName + ".new" : fileName;
+ File.Copy (s, newName + ".new");
+ Delete (fileName);
+ }
+ else
+ File.Move (fileName, newName);
+ }
+
public Stream OpenRead (string fileName)
{
if (inTransaction) {