Browse Source

Added support for installing and uninstalling user AddIns.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@809 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
dd7dcdbb0a
  1. 37
      src/AddIns/Misc/AddInManager/Project/Src/AddInControl.cs
  2. 82
      src/AddIns/Misc/AddInManager/Project/Src/InstallableAddIn.cs
  3. 31
      src/AddIns/Misc/AddInManager/Project/Src/ManagerForm.cs
  4. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.addin
  5. 4
      src/Main/Core/Project/Src/AddInTree/AddIn/AddIn.cs
  6. 157
      src/Main/Core/Project/Src/AddInTree/AddInManager.cs
  7. 5
      src/Main/Core/Project/Src/AddInTree/AddInTree.cs
  8. 31
      src/Main/Core/Project/Src/AddInTree/CoreStartup.cs
  9. 9
      src/Main/StartUp/Project/SharpDevelopMain.cs

37
src/AddIns/Misc/AddInManager/Project/Src/AddInControl.cs

@ -17,6 +17,7 @@ namespace ICSharpCode.AddInManager @@ -17,6 +17,7 @@ namespace ICSharpCode.AddInManager
public class AddInControl : Control
{
AddIn addIn;
bool isExternal;
public AddIn AddIn {
get {
@ -28,7 +29,11 @@ namespace ICSharpCode.AddInManager @@ -28,7 +29,11 @@ namespace ICSharpCode.AddInManager
{
this.addIn = addIn;
this.BackColor = SystemColors.Window;
this.Size = new Size(100, 40);
isExternal = !FileUtility.IsBaseDirectory(FileUtility.ApplicationRootPath, addIn.FileName)
&& !FileUtility.IsBaseDirectory(PropertyService.ConfigDirectory, addIn.FileName);
this.ClientSize = new Size(100, isExternal ? 35 + pathHeight : 35);
this.SetStyle(ControlStyles.Selectable, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
@ -107,9 +112,29 @@ namespace ICSharpCode.AddInManager @@ -107,9 +112,29 @@ namespace ICSharpCode.AddInManager
}
RectangleF textBounds = bounds;
textBounds.Offset(innerMargin, innerMargin);
textBounds.Inflate(-innerMargin * 2, -innerMargin * 2);
g.DrawString(description, Font, textBrush, textBounds);
textBounds.Inflate(-innerMargin * 2, -innerMargin * 2 + 2);
if (isExternal)
textBounds.Height -= pathHeight;
using (StringFormat sf = new StringFormat(StringFormatFlags.LineLimit)) {
sf.Trimming = StringTrimming.EllipsisWord;
g.DrawString(description, Font, textBrush, textBounds, sf);
}
if (isExternal) {
textBounds.Y = textBounds.Bottom + 2;
textBounds.Height = pathHeight + 2;
using (Font font = new Font(Font.Name, 7, FontStyle.Italic)) {
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) {
sf.Trimming = StringTrimming.EllipsisPath;
sf.Alignment = StringAlignment.Far;
g.DrawString(addIn.FileName, font,
selected ? SystemBrushes.HighlightText : SystemBrushes.ControlText,
textBounds, sf);
}
}
}
}
const int pathHeight = 10;
string GetText(out Brush textBrush)
{
@ -137,6 +162,12 @@ namespace ICSharpCode.AddInManager @@ -137,6 +162,12 @@ namespace ICSharpCode.AddInManager
case AddInAction.Update:
textBrush = SystemBrushes.ActiveCaption;
return "AddIn will be updated after restarting SharpDevelop";
case AddInAction.InstalledTwice:
textBrush = Brushes.Red;
return "Duplicate installation";
case AddInAction.DependencyError:
textBrush = Brushes.Red;
return "Dependency failed";
default:
textBrush = Brushes.Yellow;
return addIn.Action.ToString();

82
src/AddIns/Misc/AddInManager/Project/Src/InstallableAddIn.cs

@ -1,12 +1,15 @@ @@ -1,12 +1,15 @@
/*
* Created by SharpDevelop.
* User: Daniel Grunwald
* Date: 27.11.2005
* Time: 11:42
*/
// <file>
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
// <license see="prj:///doc/license.txt">GNU General Public License</license>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpZipLib.Zip;
namespace ICSharpCode.AddInManager
{
@ -27,7 +30,12 @@ namespace ICSharpCode.AddInManager @@ -27,7 +30,12 @@ namespace ICSharpCode.AddInManager
this.fileName = fileName;
this.isPackage = isPackage;
if (isPackage) {
throw new NotImplementedException();
ZipFile file = new ZipFile(fileName);
try {
LoadAddInFromZip(file);
} finally {
file.Close();
}
} else {
addIn = AddIn.Load(fileName);
}
@ -35,13 +43,71 @@ namespace ICSharpCode.AddInManager @@ -35,13 +43,71 @@ namespace ICSharpCode.AddInManager
throw new AddInLoadException("The AddIn must have an <Identity> for use with the AddIn-Manager.");
}
void LoadAddInFromZip(ZipFile file)
{
ZipEntry addInEntry = null;
foreach (ZipEntry entry in file) {
if (entry.Name.EndsWith(".addin")) {
if (addInEntry != null)
throw new AddInLoadException("The package may only contain one .addin file.");
addInEntry = entry;
}
}
if (addInEntry == null)
throw new AddInLoadException("The package must contain one .addin file.");
using (Stream s = file.GetInputStream(addInEntry)) {
using (StreamReader r = new StreamReader(s)) {
addIn = AddIn.Load(r);
}
}
}
public void Install()
{
foreach (string identity in addIn.Manifest.Identities.Keys) {
ICSharpCode.Core.AddInManager.AbortRemoveUserAddInOnNextStart(identity);
}
if (isPackage) {
throw new NotImplementedException();
string targetDir = Path.Combine(ICSharpCode.Core.AddInManager.AddInInstallTemp,
addIn.Manifest.PrimaryIdentity);
if (Directory.Exists(targetDir))
Directory.Delete(targetDir, true);
Directory.CreateDirectory(targetDir);
FastZip fastZip = new FastZip();
fastZip.CreateEmptyDirectories = true;
fastZip.ExtractZip(fileName, targetDir, null);
addIn.Action = AddInAction.Install;
AddInTree.InsertAddIn(addIn);
} else {
ICSharpCode.Core.AddInManager.AddExternalAddIns(new AddIn[] { addIn });
}
}
public static void Uninstall(IList<AddIn> addIns)
{
foreach (AddIn addIn in addIns) {
foreach (string identity in addIn.Manifest.Identities.Keys) {
// delete from installation temp (if installation or update is pending)
string targetDir = Path.Combine(ICSharpCode.Core.AddInManager.AddInInstallTemp,
identity);
if (Directory.Exists(targetDir))
Directory.Delete(targetDir, true);
// remove the user AddIn
targetDir = Path.Combine(ICSharpCode.Core.AddInManager.UserAddInPath, identity);
if (Directory.Exists(targetDir)) {
if (!addIn.Enabled) {
try {
Directory.Delete(targetDir, true);
continue;
} catch {
}
}
ICSharpCode.Core.AddInManager.RemoveUserAddInOnNextStart(identity);
}
}
}
}
}
}

31
src/AddIns/Misc/AddInManager/Project/Src/ManagerForm.cs

@ -47,7 +47,10 @@ namespace ICSharpCode.AddInManager @@ -47,7 +47,10 @@ namespace ICSharpCode.AddInManager
ICSharpCode.SharpDevelop.Gui.FormLocationHelper.Apply(this, "AddInManager.WindowBounds", true);
CreateAddInList();
splitContainer.Panel1.Paint += delegate(object sender, PaintEventArgs e) {
}
void OnSplitContainerPanel1Paint(object sender, PaintEventArgs e)
{
if (visibleAddInCount == 0) {
Rectangle rect = splitContainer.Panel1.ClientRectangle;
rect.Offset(16, 16);
@ -57,7 +60,6 @@ namespace ICSharpCode.AddInManager @@ -57,7 +60,6 @@ namespace ICSharpCode.AddInManager
"choose the downloaded file to install it.",
Font, SystemBrushes.ControlText, rect);
}
};
}
void CreateAddInList()
@ -189,8 +191,6 @@ namespace ICSharpCode.AddInManager @@ -189,8 +191,6 @@ namespace ICSharpCode.AddInManager
splitContainer.Panel2Collapsed = selected.Count == 0;
if (selected.Count > 0) {
dependencyTable.Visible = false;
uninstallButton.Enabled = false;
runActionButton.Enabled = false;
runActionButton.Visible = true;
uninstallButton.Visible = true;
@ -199,8 +199,12 @@ namespace ICSharpCode.AddInManager @@ -199,8 +199,12 @@ namespace ICSharpCode.AddInManager
bool allInstalling = true;
bool allUninstalling = true;
bool allUninstallable = true;
bool hasErrors = false;
foreach (AddIn addIn in selected) {
allEnabled &= addIn.Action == AddInAction.Enable;
if (addIn.Action == AddInAction.DependencyError || addIn.Action == AddInAction.InstalledTwice)
hasErrors = true;
else
allDisabled &= addIn.Action == AddInAction.Disable;
allInstalling &= addIn.Action == AddInAction.Install;
allUninstalling &= addIn.Action == AddInAction.Uninstall;
@ -221,6 +225,8 @@ namespace ICSharpCode.AddInManager @@ -221,6 +225,8 @@ namespace ICSharpCode.AddInManager
actionGroupBox.Text = runActionButton.Text = "Enable";
actionDescription.Text = "Enables the selected AddIns.";
runActionButton.Enabled = ShowDependencies(selected, true);
if (hasErrors)
runActionButton.Enabled = false;
uninstallButton.Enabled = allUninstallable;
} else if (allInstalling) {
selectedAction = AddInAction.Uninstall;
@ -443,7 +449,7 @@ namespace ICSharpCode.AddInManager @@ -443,7 +449,7 @@ namespace ICSharpCode.AddInManager
void UninstallButtonClick(object sender, EventArgs e)
{
ICSharpCode.Core.AddInManager.RemoveExternalAddIns(selected);
// TODO: delete user addins
InstallableAddIn.Uninstall(selected);
RefreshAddInList();
}
#endregion
@ -461,20 +467,24 @@ namespace ICSharpCode.AddInManager @@ -461,20 +467,24 @@ namespace ICSharpCode.AddInManager
void RunActionButtonClick(object sender, EventArgs e)
{
if (selectedAction == AddInAction.Disable) {
switch (selectedAction) {
case AddInAction.Disable:
ICSharpCode.Core.AddInManager.Disable(selected);
} else if (selectedAction == AddInAction.Enable) {
break;
case AddInAction.Enable:
ICSharpCode.Core.AddInManager.Enable(selected);
} else if (selectedAction == AddInAction.Install) {
break;
case AddInAction.Install:
// install new AddIns
foreach (InstallableAddIn addInPackage in shownAddInPackages) {
addInPackage.Install();
}
RefreshAddInList();
} else if (selectedAction == AddInAction.Uninstall) {
return;
case AddInAction.Uninstall:
UninstallButtonClick(sender, e);
return;
} else {
default:
throw new NotImplementedException();
}
foreach (AddInControl ctl in splitContainer.Panel1.Controls) {
@ -579,6 +589,7 @@ namespace ICSharpCode.AddInManager @@ -579,6 +589,7 @@ namespace ICSharpCode.AddInManager
//
this.splitContainer.Panel1.AutoScroll = true;
this.splitContainer.Panel1.BackColor = System.Drawing.SystemColors.Window;
this.splitContainer.Panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.OnSplitContainerPanel1Paint);
this.splitContainer.Panel1MinSize = 100;
//
// splitContainer.Panel2

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.addin

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<AddIn name="SharpDevelop Debugger" author="David Srbecký" copyright="GPL" url="" description="SharpDevelop Managed Debugger">
<AddIn name="Debugger" author="David Srbecký" copyright="GPL" url="" description="SharpDevelop Managed Debugger">
<Manifest>
<Identity name = "ICSharpCode.Debugger"/>
</Manifest>

4
src/Main/Core/Project/Src/AddInTree/AddIn/AddIn.cs

@ -19,8 +19,8 @@ namespace ICSharpCode.Core @@ -19,8 +19,8 @@ namespace ICSharpCode.Core
string addInFileName = null;
AddInManifest manifest = new AddInManifest();
Dictionary<string, ExtensionPath> paths = new Dictionary<string, ExtensionPath>();
AddInAction action = AddInAction.Enable;
bool enabled = true;
AddInAction action = AddInAction.Disable;
bool enabled;
static bool hasShownErrorMessage = false;

157
src/Main/Core/Project/Src/AddInTree/AddInManager.cs

@ -19,12 +19,34 @@ namespace ICSharpCode.Core @@ -19,12 +19,34 @@ namespace ICSharpCode.Core
Disable,
Install,
Uninstall,
Update
Update,
InstalledTwice,
DependencyError
}
public static class AddInManager
{
static string configurationFileName;
static string addInInstallTemp;
static string userAddInPath;
public static string UserAddInPath {
get {
return userAddInPath;
}
set {
userAddInPath = value;
}
}
public static string AddInInstallTemp {
get {
return addInInstallTemp;
}
set {
addInInstallTemp = value;
}
}
public static string ConfigurationFileName {
get {
@ -35,6 +57,133 @@ namespace ICSharpCode.Core @@ -35,6 +57,133 @@ namespace ICSharpCode.Core
}
}
/// <summary>
/// Installs the AddIns from AddInInstallTemp to the UserAddInPath.
/// In case of installation errors, a error message is displayed to the user
/// and the affected AddIn is added to the disabled list.
/// </summary>
public static void InstallAddIns(List<string> disabled)
{
if (!Directory.Exists(addInInstallTemp))
return;
LoggingService.Info("AddInManager.InstallAddIns started");
if (!Directory.Exists(userAddInPath))
Directory.CreateDirectory(userAddInPath);
string removeFile = Path.Combine(addInInstallTemp, "remove.txt");
bool allOK = true;
List<string> notRemoved = new List<string>();
if (File.Exists(removeFile)) {
using (StreamReader r = new StreamReader(removeFile)) {
string addInName;
while ((addInName = r.ReadLine()) != null) {
addInName = addInName.Trim();
if (addInName.Length == 0)
continue;
string targetDir = Path.Combine(userAddInPath, addInName);
if (!UninstallAddIn(disabled, addInName, targetDir)) {
notRemoved.Add(addInName);
allOK = false;
}
}
}
if (notRemoved.Count == 0) {
LoggingService.Info("Deleting remove.txt");
File.Delete(removeFile);
} else {
LoggingService.Info("Rewriting remove.txt");
using (StreamWriter w = new StreamWriter(removeFile)) {
notRemoved.ForEach(w.WriteLine);
}
}
}
foreach (string sourceDir in Directory.GetDirectories(addInInstallTemp)) {
string addInName = Path.GetFileName(sourceDir);
string targetDir = Path.Combine(userAddInPath, addInName);
if (notRemoved.Contains(addInName)) {
LoggingService.Info("Skipping installation of " + addInName + " because deinstallation failed.");
continue;
}
if (UninstallAddIn(disabled, addInName, targetDir)) {
LoggingService.Info("Installing " + addInName + "...");
Directory.Move(sourceDir, targetDir);
} else {
allOK = false;
}
}
if (allOK) {
try {
Directory.Delete(addInInstallTemp, false);
} catch (Exception ex) {
LoggingService.Warn("Error removing install temp", ex);
}
}
LoggingService.Info("AddInManager.InstallAddIns finished");
}
static bool UninstallAddIn(List<string> disabled, string addInName, string targetDir)
{
if (Directory.Exists(targetDir)) {
LoggingService.Info("Removing " + addInName + "...");
try {
Directory.Delete(targetDir, true);
} catch (Exception ex) {
disabled.Add(addInName);
MessageService.ShowError("Error removing " + addInName + ":\n" +
ex.Message + "\nThe AddIn will be " +
"removed on the next start of SharpDevelop and is disabled " +
"for now.");
return false;
}
}
return true;
}
public static void RemoveUserAddInOnNextStart(string identity)
{
List<string> removeEntries = new List<string>();
string removeFile = Path.Combine(addInInstallTemp, "remove.txt");
if (File.Exists(removeFile)) {
using (StreamReader r = new StreamReader(removeFile)) {
string addInName;
while ((addInName = r.ReadLine()) != null) {
addInName = addInName.Trim();
if (addInName.Length > 0)
removeEntries.Add(addInName);
}
}
if (removeEntries.Contains(identity))
return;
}
removeEntries.Add(identity);
if (!Directory.Exists(addInInstallTemp))
Directory.CreateDirectory(addInInstallTemp);
using (StreamWriter w = new StreamWriter(removeFile)) {
removeEntries.ForEach(w.WriteLine);
}
}
public static void AbortRemoveUserAddInOnNextStart(string identity)
{
string removeFile = Path.Combine(addInInstallTemp, "remove.txt");
if (!File.Exists(removeFile)) {
return;
}
List<string> removeEntries = new List<string>();
using (StreamReader r = new StreamReader(removeFile)) {
string addInName;
while ((addInName = r.ReadLine()) != null) {
addInName = addInName.Trim();
if (addInName.Length > 0)
removeEntries.Add(addInName);
}
}
if (removeEntries.Remove(identity)) {
using (StreamWriter w = new StreamWriter(removeFile)) {
removeEntries.ForEach(w.WriteLine);
}
}
}
public static void AddExternalAddIns(IList<AddIn> addIns)
{
List<string> addInFiles = new List<string>();
@ -83,9 +232,15 @@ namespace ICSharpCode.Core @@ -83,9 +232,15 @@ namespace ICSharpCode.Core
disabled.Remove(identity);
}
if (addIn.Action == AddInAction.Uninstall) {
if (FileUtility.IsBaseDirectory(userAddInPath, addIn.FileName)) {
foreach (string identity in addIn.Manifest.Identities.Keys) {
AbortRemoveUserAddInOnNextStart(identity);
}
} else {
if (!addInFiles.Contains(addIn.FileName))
addInFiles.Add(addIn.FileName);
}
}
addIn.Action = AddInAction.Enable;
}

5
src/Main/Core/Project/Src/AddInTree/AddInTree.cs

@ -214,6 +214,7 @@ namespace ICSharpCode.Core @@ -214,6 +214,7 @@ namespace ICSharpCode.Core
static void DisableAddin(AddIn addIn, Dictionary<string, Version> dict, Dictionary<string, AddIn> addInDict)
{
addIn.Enabled = false;
addIn.Action = AddInAction.DependencyError;
foreach (string name in addIn.Manifest.Identities.Keys) {
dict.Remove(name);
addInDict.Remove(name);
@ -227,6 +228,7 @@ namespace ICSharpCode.Core @@ -227,6 +228,7 @@ namespace ICSharpCode.Core
Dictionary<string, AddIn> addInDict = new Dictionary<string, AddIn>();
foreach (string fileName in addInFiles) {
AddIn addIn = AddIn.Load(fileName);
addIn.Enabled = true;
if (disabledAddIns != null && disabledAddIns.Count > 0) {
foreach (string name in addIn.Manifest.Identities.Keys) {
if (disabledAddIns.Contains(name)) {
@ -240,7 +242,8 @@ namespace ICSharpCode.Core @@ -240,7 +242,8 @@ namespace ICSharpCode.Core
if (dict.ContainsKey(pair.Key)) {
MessageService.ShowError("Name '" + pair.Key + "' is used by " +
"'" + addInDict[pair.Key].FileName + "' and '" + fileName + "'");
DisableAddin(addIn, dict, addInDict);
addIn.Enabled = false;
addIn.Action = AddInAction.InstalledTwice;
break;
} else {
dict.Add(pair.Key, pair.Value);

31
src/Main/Core/Project/Src/AddInTree/CoreStartup.cs

@ -22,7 +22,6 @@ namespace ICSharpCode.Core @@ -22,7 +22,6 @@ namespace ICSharpCode.Core
string configDirectory;
string dataDirectory;
string applicationName;
string addInConfigurationFile;
/// <summary>
/// Sets the name used for the properties (only name, without path or extension).
@ -67,18 +66,6 @@ namespace ICSharpCode.Core @@ -67,18 +66,6 @@ namespace ICSharpCode.Core
}
}
/// <summary>
/// Gets/Sets the configuration file used to store the enabled/disabled state of the AddIns.
/// </summary>
public string AddInConfigurationFile {
get {
return addInConfigurationFile;
}
set {
addInConfigurationFile = value;
}
}
public CoreStartup(string applicationName)
{
if (applicationName == null)
@ -93,12 +80,26 @@ namespace ICSharpCode.Core @@ -93,12 +80,26 @@ namespace ICSharpCode.Core
addInFiles.AddRange(FileUtility.SearchDirectory(addInDir, "*.addin"));
}
public void RunInitialization()
public void ConfigureExternalAddIns(string addInConfigurationFile)
{
if (addInConfigurationFile != null) {
AddInManager.ConfigurationFileName = addInConfigurationFile;
AddInManager.LoadAddInConfiguration(addInFiles, disabledAddIns);
}
public void ConfigureUserAddIns(string addInInstallTemp, string userAddInPath)
{
AddInManager.AddInInstallTemp = addInInstallTemp;
AddInManager.UserAddInPath = userAddInPath;
if (Directory.Exists(addInInstallTemp)) {
AddInManager.InstallAddIns(disabledAddIns);
}
if (Directory.Exists(userAddInPath)) {
AddAddInsFromDirectory(userAddInPath);
}
}
public void RunInitialization()
{
AddInTree.Load(addInFiles, disabledAddIns);
// run workspace autostart commands

9
src/Main/StartUp/Project/SharpDevelopMain.cs

@ -177,11 +177,10 @@ namespace ICSharpCode.SharpDevelop @@ -177,11 +177,10 @@ namespace ICSharpCode.SharpDevelop
LoggingService.Info("Looking for AddIns...");
c.AddAddInsFromDirectory(Path.Combine(FileUtility.ApplicationRootPath, "AddIns"));
string fileName = Path.Combine(PropertyService.ConfigDirectory, "AddIns");
if (Directory.Exists(fileName)) {
c.AddAddInsFromDirectory(fileName);
}
c.AddInConfigurationFile = Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml");
c.ConfigureExternalAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml"));
c.ConfigureUserAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddInInstallTemp"),
Path.Combine(PropertyService.ConfigDirectory, "AddIns"));
LoggingService.Info("Loading AddInTree...");
c.RunInitialization();

Loading…
Cancel
Save