Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.PluginInfrastructure/Advanced/InstallationManager.cs @ 2860

Last change on this file since 2860 was 2811, checked in by gkronber, 14 years ago

Fixed service references in plugin infrastructure. #860 (Deployment server for plugin installation from web locations)

File size: 11.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26using HeuristicLab.PluginInfrastructure.Manager;
27using System.IO;
28using System.ComponentModel;
29using System.Reflection;
30
31namespace HeuristicLab.PluginInfrastructure.Advanced {
32  internal class InstallationManager {
33
34    internal event EventHandler<PluginInfrastructureCancelEventArgs> PreUpdatePlugin;
35    internal event EventHandler<PluginInfrastructureCancelEventArgs> PreRemovePlugin;
36    internal event EventHandler<PluginInfrastructureCancelEventArgs> PreInstallPlugin;
37
38    internal event EventHandler<PluginInfrastructureEventArgs> PluginUpdated;
39    internal event EventHandler<PluginInfrastructureEventArgs> PluginRemoved;
40    internal event EventHandler<PluginInfrastructureEventArgs> PluginInstalled;
41
42
43    public IEnumerable<PluginDescription> Plugins {
44      get { return pluginManager.Plugins; }
45    }
46
47    private string pluginDir;
48    private string updateLocationUrl;
49    private PluginManager pluginManager;
50    public InstallationManager(string pluginDir) {
51      this.pluginDir = pluginDir;
52      this.updateLocationUrl = "http://localhost:59253/UpdateLocation.svc";
53      this.pluginManager = new PluginManager(pluginDir);
54      this.pluginManager.DiscoverAndCheckPlugins();
55    }
56
57    public IEnumerable<string> Show(IEnumerable<string> pluginNames) {
58      foreach (PluginDescription desc in GetPluginDescriptions(pluginNames)) {
59        yield return GetInformation(desc);
60      }
61    }
62
63    internal string GetInformation(string pluginName) {
64      return GetInformation(GetPluginDescription(pluginName));
65    }
66
67    private string GetInformation(PluginDescription desc) {
68      StringBuilder builder = new StringBuilder();
69      builder.Append("Name: ").AppendLine(desc.Name);
70      builder.Append("Version: ").AppendLine(desc.Version.ToString());
71      builder.AppendLine("Description:").AppendLine(desc.Description);
72      if (!string.IsNullOrEmpty(desc.ContactName)) {
73        builder.Append("Contact: ").Append(desc.ContactName).Append(", ").AppendLine(desc.ContactEmail);
74      }
75      builder.AppendLine("This plugin is " + desc.PluginState.ToString().ToLowerInvariant() + ".");
76      builder.AppendLine("Files: ");
77      foreach (var file in desc.Files) {
78        builder.AppendLine(file.Type + " " + file.Name);
79      }
80      builder.AppendLine().AppendLine("Directly depends on:");
81      if (desc.Dependencies.Count() == 0) builder.AppendLine("None");
82      foreach (var dependency in desc.Dependencies) {
83        builder.AppendLine(dependency.Name + " " + dependency.Version);
84      }
85      builder.AppendLine().AppendFormat("Plugins directly dependent on {0}:", desc.Name).AppendLine();
86      var dependents = from x in pluginManager.Plugins
87                       where x.Dependencies.Contains(desc)
88                       select x;
89      if (dependents.Count() == 0) builder.AppendLine("None");
90      foreach (var dependent in dependents) {
91        builder.AppendLine(dependent.Name + " " + dependent.Version);
92      }
93      builder.AppendLine();
94      if (desc.PluginState == PluginState.Disabled) {
95        builder.AppendLine(DetermineProblem(desc));
96      }
97
98      return builder.ToString();
99    }
100
101    private static string DetermineProblem(PluginDescription desc) {
102      // either any file is missing
103      StringBuilder builder = new StringBuilder();
104      builder.AppendLine("Problem report:");
105      builder.AppendLine(desc.LoadingErrorInformation);
106      return builder.ToString();
107    }
108
109    private static IEnumerable<string> GetDeclaredDependencies(PluginDescription desc) {
110      var plugin = ApplicationManager.GetInstances<IPlugin>(desc).Single();
111      return plugin.GetType().GetCustomAttributes(typeof(PluginDependencyAttribute), false).Cast<PluginDependencyAttribute>().Select(x => x.Dependency);
112    }
113
114    private PluginDescription GetPluginDescription(string pluginName) {
115      var exactMatch = from pluginDesc in pluginManager.Plugins
116                       where string.Equals(pluginName, pluginDesc.Name, StringComparison.InvariantCultureIgnoreCase)
117                       select pluginDesc;
118      var inexactMatch = from pluginDesc in pluginManager.Plugins
119                         where MatchPluginNameInexact(pluginName, pluginDesc.Name)
120                         select pluginDesc;
121      return exactMatch.Count() > 0 ? exactMatch.Single() : inexactMatch.First();
122    }
123
124    private IEnumerable<PluginDescription> GetPluginDescriptions(IEnumerable<string> pluginNames) {
125      return from pluginName in pluginNames
126             select GetPluginDescription(pluginName);
127    }
128
129    private static bool MatchPluginNameInexact(string similarName, string actualName) {
130      return
131        // Core-3.2 == HeuristicLab.Core-3.2
132        actualName.Equals("HeuristicLab." + similarName, StringComparison.InvariantCultureIgnoreCase) ||
133        // HeuristicLab.Core == HeuristicLab.Core-3.2 (this should be save because we checked for exact matches first)
134        (Math.Abs(actualName.Length - similarName.Length) <= 4 && actualName.StartsWith(similarName, StringComparison.InvariantCultureIgnoreCase)) ||
135        // Core == HeuristicLab.Core-3.2
136        (Math.Abs(actualName.Length - similarName.Length) <= 17 && actualName.StartsWith("HeuristicLab." + similarName, StringComparison.InvariantCultureIgnoreCase));
137    }
138
139    public void Install(IEnumerable<string> pluginNames) {
140      throw new NotImplementedException();
141      //IEnumerable<PluginInformation> pluginsToInstall;
142      //using (UpdateLocationClient updateLocation = new UpdateLocationClient()) {
143      //  pluginsToInstall = from pluginName in pluginNames
144      //                     from matchingPlugin in updateLocation.GetAvailablePluginsByName(pluginName)
145      //                     select matchingPlugin;
146
147      //  var args = new PluginInfrastructureCancelEventArgs("Installing", pluginsToInstall);
148      //  OnPreInstall(args);
149      //  foreach (var pluginInfo in pluginsToInstall) {
150      //    var s = updateLocation.GetPluginFiles(pluginInfo);
151      //    Console.WriteLine("Downloading: {0} {1} {2}", pluginInfo.Name, pluginInfo.Version, pluginInfo.BuildDate);
152      //  }
153      //}
154      //OnInstalled(new PluginInfrastructureEventArgs("Installed", pluginsToInstall));
155    }
156
157    //private static PluginInformation GetMatchingPluginInformation(string pluginName, IEnumerable<PluginInformation> plugins) {
158    //  var exactMatch = from pluginDesc in plugins
159    //                   where string.Equals(pluginName, pluginDesc.Name, StringComparison.InvariantCultureIgnoreCase)
160    //                   select pluginDesc;
161    //  var inexactMatch = from pluginDesc in plugins
162    //                     where MatchPluginNameInexact(pluginName, pluginDesc.Name)
163    //                     select pluginDesc;
164    //  return exactMatch.Count() > 0 ? exactMatch.Single() : inexactMatch.First();
165    //}
166
167    public void Remove(IEnumerable<string> pluginNames) {
168      var fileNames = from pluginToDelete in PluginDescriptionIterator.IterateDependentsTopDown(GetPluginDescriptions(pluginNames), pluginManager.Plugins)
169                      from file in pluginToDelete.Files
170                      select Path.Combine(pluginDir, file.Name);
171      var args = new PluginInfrastructureCancelEventArgs("Deleting", fileNames);
172      OnPreDelete(args);
173      if (!args.Cancel) {
174        foreach (string fileName in fileNames) {
175          Console.WriteLine("Deleting file " + fileName);
176          // File.Delete(fileName);
177        }
178
179        OnDeleted(new PluginInfrastructureEventArgs("Deleted", fileNames));
180      }
181    }
182
183    public void Update(IEnumerable<string> pluginNames) {
184      var pluginDescriptions = from name in pluginNames
185                               select GetPluginDescription(name);
186      Dictionary<DeploymentService.PluginDescription, string> matchingPlugins = new Dictionary<DeploymentService.PluginDescription, string>();
187      foreach (var updateLocation in HeuristicLab.PluginInfrastructure.Properties.Settings.Default.UpdateLocations) {
188        using (var client = new DeploymentService.UpdateClient("", updateLocation)) {
189          var updateLocationMatchingPlugins = from desc in pluginDescriptions
190                                              from info in client.GetPlugins()
191                                              where desc.Name == info.Name
192                                              select info;
193          foreach (DeploymentService.PluginDescription info in updateLocationMatchingPlugins) {
194            // keep only the highest version of any plugin
195            var existingPlugin = matchingPlugins.Keys.FirstOrDefault(x => x.Name == info.Name);
196            if (existingPlugin == null || existingPlugin.Version < info.Version) {
197              matchingPlugins.Remove(existingPlugin);
198              matchingPlugins.Add(info, updateLocation);
199            }
200          }
201        }
202      }
203      PluginInfrastructureCancelEventArgs args = new PluginInfrastructureCancelEventArgs("Updating", matchingPlugins.Keys);
204      OnPreUpdate(args);
205      if (!args.Cancel) {
206        var groupedInfos = matchingPlugins.GroupBy(x => x.Value);
207        foreach (var group in groupedInfos) {
208          using (var client = new DeploymentService.UpdateClient(group.Key)) {
209            foreach (var info in group) {
210              client.GetPlugin(info.Key);
211            }
212          }
213        }
214        OnUpdated(new PluginInfrastructureEventArgs("Updated", matchingPlugins.Keys));
215      }
216    }
217
218    private void OnPreUpdate(PluginInfrastructureCancelEventArgs args) {
219      if (PreUpdatePlugin != null) PreUpdatePlugin(this, args);
220    }
221
222    private void OnUpdated(PluginInfrastructureEventArgs args) {
223      if (PluginUpdated != null) PluginUpdated(this, args);
224    }
225
226    private void OnPreDelete(PluginInfrastructureCancelEventArgs args) {
227      if (PreRemovePlugin != null) PreRemovePlugin(this, args);
228    }
229
230    private void OnDeleted(PluginInfrastructureEventArgs args) {
231      if (PluginRemoved != null) PluginRemoved(this, args);
232    }
233
234    private void OnPreInstall(PluginInfrastructureCancelEventArgs args) {
235      if (PreInstallPlugin != null) PreInstallPlugin(this, args);
236    }
237
238    private void OnInstalled(PluginInfrastructureEventArgs args) {
239      if (PluginInstalled != null) PluginInstalled(this, args);
240    }
241  }
242}
Note: See TracBrowser for help on using the repository browser.