Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 2591 was 2527, checked in by gkronber, 15 years ago

Implemented changes as requested by swagner. #799

File size: 11.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using HeuristicLab.PluginInfrastructure.Manager;
6using System.IO;
7using System.ComponentModel;
8using HeuristicLab.PluginInfrastructure.UpdateLocationReference;
9
10namespace HeuristicLab.PluginInfrastructure.Advanced {
11  internal class InstallationManager {
12
13    internal event EventHandler<PluginInfrastructureCancelEventArgs> PreUpdatePlugin;
14    internal event EventHandler<PluginInfrastructureCancelEventArgs> PreRemovePlugin;
15    internal event EventHandler<PluginInfrastructureCancelEventArgs> PreInstallPlugin;
16
17    internal event EventHandler<PluginInfrastructureEventArgs> PluginUpdated;
18    internal event EventHandler<PluginInfrastructureEventArgs> PluginRemoved;
19    internal event EventHandler<PluginInfrastructureEventArgs> PluginInstalled;
20
21    private string pluginDir;
22    private string updateLocationUrl;
23    private PluginManager pluginManager;
24    public InstallationManager(string pluginDir) {
25      this.pluginDir = pluginDir;
26      this.updateLocationUrl = "http://localhost:59253/UpdateLocation.svc";
27      this.pluginManager = new PluginManager(pluginDir);
28      this.pluginManager.DiscoverAndCheckPlugins();
29    }
30
31    public IEnumerable<string> Show(IEnumerable<string> pluginNames) {
32      foreach (PluginDescription desc in GetPluginDescriptions(pluginNames)) {
33        yield return GetInformation(desc);
34      }
35    }
36
37    internal string GetInformation(string pluginName) {
38      return GetInformation(GetPluginDescription(pluginName));
39    }
40
41    private string GetInformation(PluginDescription desc) {
42      StringBuilder builder = new StringBuilder();
43      builder.Append("Name: ").AppendLine(desc.Name);
44      builder.Append("Version: ").AppendLine(desc.Version.ToString());
45      builder.AppendLine("Description:").AppendLine(desc.Description);
46      builder.Append("Build date: ").AppendLine(desc.BuildDate.ToString());
47      builder.AppendLine("Files: ");
48      foreach (string fileName in desc.Files) {
49        builder.AppendLine(fileName);
50      }
51      builder.AppendLine("Directly depends on:");
52      if (desc.Dependencies.Count() == 0) builder.AppendLine("None");
53      foreach (var dependency in desc.Dependencies) {
54        builder.AppendLine(dependency.Name);
55      }
56      builder.AppendFormat("Plugins directly dependent on {0}:\n", desc.Name);
57      var dependents = from x in pluginManager.Plugins
58                       where x.Dependencies.Contains(desc)
59                       select x.Name;
60      if (dependents.Count() == 0) builder.AppendLine("None");
61      foreach (var dependent in dependents) {
62        builder.AppendLine(dependent);
63      }
64      builder.AppendLine("This plugin is " + desc.PluginState.ToString().ToLowerInvariant() + ".");
65      if (desc.PluginState == PluginState.Disabled) {
66        builder.AppendLine(DetermineProblem(desc));
67      }
68
69      return builder.ToString();
70    }
71
72    private static string DetermineProblem(PluginDescription desc) {
73      // either any file is missing
74      StringBuilder builder = new StringBuilder();
75      var missingFiles = from x in desc.Files
76                         where !File.Exists(x)
77                         select x;
78      if (missingFiles.Count() > 0) {
79        foreach (string fileName in desc.Files) {
80          if (!File.Exists(fileName)) builder.Append("Missing file: ").AppendLine(fileName);
81        }
82        return builder.ToString();
83      } else {
84        // or any dependency is disabled
85        var disabledDependencies = from x in desc.Dependencies
86                                   where x.PluginState == PluginState.Disabled
87                                   select x;
88        if (disabledDependencies.Count() > 0) {
89          foreach (var dependency in disabledDependencies) {
90            builder.Append(dependency.Name).AppendLine(" is disabled.").AppendLine(DetermineProblem(dependency));
91          }
92          return builder.ToString();
93        } else {
94          // or any dependency is missing / not installed
95          var declaredDependencies = GetDeclaredDependencies(desc);
96          if (declaredDependencies.Count() != desc.Dependencies.Count()) {
97            var missingDependencies = from x in declaredDependencies
98                                      where !desc.Dependencies.Any(dep => dep.Name == x)
99                                      select x;
100            builder.AppendLine("Necessary dependencies are missing:");
101            foreach (string missingDependency in missingDependencies) {
102              builder.AppendLine(missingDependency);
103            }
104          } else {
105            // or there was a problem loading the assemblies
106            builder.AppendLine("There was a problem while loading assemblies: ");
107            foreach (string assembly in desc.Assemblies) {
108              builder.AppendLine(assembly);
109            }
110            return builder.ToString();
111          }
112        }
113      }
114      return "There is an unknown problem with plugin: " + desc.Name;
115    }
116
117    private static IEnumerable<string> GetDeclaredDependencies(PluginDescription desc) {
118      var plugin = ApplicationManager.GetInstances<IPlugin>(desc).Single();
119      return plugin.GetType().GetCustomAttributes(typeof(PluginDependencyAttribute), false).Cast<PluginDependencyAttribute>().Select(x => x.Dependency);
120    }
121
122    private PluginDescription GetPluginDescription(string pluginName) {
123      var exactMatch = from pluginDesc in pluginManager.Plugins
124                       where string.Equals(pluginName, pluginDesc.Name, StringComparison.InvariantCultureIgnoreCase)
125                       select pluginDesc;
126      var inexactMatch = from pluginDesc in pluginManager.Plugins
127                         where MatchPluginNameInexact(pluginName, pluginDesc.Name)
128                         select pluginDesc;
129      return exactMatch.Count() > 0 ? exactMatch.Single() : inexactMatch.First();
130    }
131
132    private IEnumerable<PluginDescription> GetPluginDescriptions(IEnumerable<string> pluginNames) {
133      return from pluginName in pluginNames
134             select GetPluginDescription(pluginName);
135    }
136
137    private static bool MatchPluginNameInexact(string similarName, string actualName) {
138      return
139        // Core-3.2 == HeuristicLab.Core-3.2
140        actualName.Equals("HeuristicLab." + similarName, StringComparison.InvariantCultureIgnoreCase) ||
141        // HeuristicLab.Core == HeuristicLab.Core-3.2 (this should be save because we checked for exact matches first)
142        (Math.Abs(actualName.Length - similarName.Length) <= 4 && actualName.StartsWith(similarName, StringComparison.InvariantCultureIgnoreCase)) ||
143        // Core == HeuristicLab.Core-3.2
144        (Math.Abs(actualName.Length - similarName.Length) <= 17 && actualName.StartsWith("HeuristicLab." + similarName, StringComparison.InvariantCultureIgnoreCase));
145    }
146
147    public void Install(IEnumerable<string> pluginNames) {
148      throw new NotImplementedException();
149      //IEnumerable<PluginInformation> pluginsToInstall;
150      //using (UpdateLocationClient updateLocation = new UpdateLocationClient()) {
151      //  pluginsToInstall = from pluginName in pluginNames
152      //                     from matchingPlugin in updateLocation.GetAvailablePluginsByName(pluginName)
153      //                     select matchingPlugin;
154
155      //  var args = new PluginInfrastructureCancelEventArgs("Installing", pluginsToInstall);
156      //  OnPreInstall(args);
157      //  foreach (var pluginInfo in pluginsToInstall) {
158      //    var s = updateLocation.GetPluginFiles(pluginInfo);
159      //    Console.WriteLine("Downloading: {0} {1} {2}", pluginInfo.Name, pluginInfo.Version, pluginInfo.BuildDate);
160      //  }
161      //}
162      //OnInstalled(new PluginInfrastructureEventArgs("Installed", pluginsToInstall));
163    }
164
165    //private static PluginInformation GetMatchingPluginInformation(string pluginName, IEnumerable<PluginInformation> plugins) {
166    //  var exactMatch = from pluginDesc in plugins
167    //                   where string.Equals(pluginName, pluginDesc.Name, StringComparison.InvariantCultureIgnoreCase)
168    //                   select pluginDesc;
169    //  var inexactMatch = from pluginDesc in plugins
170    //                     where MatchPluginNameInexact(pluginName, pluginDesc.Name)
171    //                     select pluginDesc;
172    //  return exactMatch.Count() > 0 ? exactMatch.Single() : inexactMatch.First();
173    //}
174
175    public void Remove(IEnumerable<string> pluginNames) {
176      var fileNames = from pluginToDelete in PluginDescriptionIterator.IterateDependentsTopDown(GetPluginDescriptions(pluginNames), pluginManager.Plugins)
177                      from fileName in pluginToDelete.Files
178                      select Path.Combine(pluginDir, fileName);
179      var args = new PluginInfrastructureCancelEventArgs("Deleting", fileNames);
180      OnPreDelete(args);
181      if (!args.Cancel) {
182        foreach (string fileName in fileNames) {
183          Console.WriteLine("Deleting file " + fileName);
184          // File.Delete(fileName);
185        }
186
187        OnDeleted(new PluginInfrastructureEventArgs("Deleted", fileNames));
188      }
189    }
190
191    public void Update(IEnumerable<string> pluginNames) {
192      var pluginDescriptions = from name in pluginNames
193                               select GetPluginDescription(name);
194      Dictionary<PluginInformation, string> matchingPlugins = new Dictionary<PluginInformation, string>();
195      foreach (var updateLocation in HeuristicLab.PluginInfrastructure.Properties.Settings.Default.UpdateLocations) {
196        using (UpdateLocationClient client = new UpdateLocationClient("", updateLocation)) {
197          var updateLocationMatchingPlugins = from desc in pluginDescriptions
198                                              from info in client.GetAvailablePluginsByName(desc.Name)
199                                              select info;
200          foreach (PluginInformation info in updateLocationMatchingPlugins) {
201            // keep only the highest version and most recent build of any plugin
202            var existingPlugin = matchingPlugins.Keys.FirstOrDefault(x => x.Name == info.Name);
203            if (existingPlugin == null || existingPlugin.Version < info.Version || (existingPlugin.Version == info.Version && existingPlugin.BuildDate < info.BuildDate)) {
204              matchingPlugins.Remove(existingPlugin);
205              matchingPlugins.Add(info, updateLocation);
206            }
207          }
208        }
209      }
210      PluginInfrastructureCancelEventArgs args = new PluginInfrastructureCancelEventArgs("Updating", matchingPlugins.Keys);
211      OnPreUpdate(args);
212      if (!args.Cancel) {
213        var groupedInfos = matchingPlugins.GroupBy(x => x.Value);
214        foreach (var group in groupedInfos) {
215          using (UpdateLocationClient client = new UpdateLocationClient(group.Key)) {
216            foreach (var info in group) {
217              client.GetPluginFiles(info.Key);
218            }
219          }
220        }
221        OnUpdated(new PluginInfrastructureEventArgs("Updated", matchingPlugins.Keys));
222      }
223    }
224
225    private void OnPreUpdate(PluginInfrastructureCancelEventArgs args) {
226      if (PreUpdatePlugin != null) PreUpdatePlugin(this, args);
227    }
228
229    private void OnUpdated(PluginInfrastructureEventArgs args) {
230      if (PluginUpdated != null) PluginUpdated(this, args);
231    }
232
233    private void OnPreDelete(PluginInfrastructureCancelEventArgs args) {
234      if (PreRemovePlugin != null) PreRemovePlugin(this, args);
235    }
236
237    private void OnDeleted(PluginInfrastructureEventArgs args) {
238      if (PluginRemoved != null) PluginRemoved(this, args);
239    }
240
241    private void OnPreInstall(PluginInfrastructureCancelEventArgs args) {
242      if (PreInstallPlugin != null) PreInstallPlugin(this, args);
243    }
244
245    private void OnInstalled(PluginInfrastructureEventArgs args) {
246      if (PluginInstalled != null) PluginInstalled(this, args);
247    }
248  }
249}
Note: See TracBrowser for help on using the repository browser.