Free cookie consent management tool by TermsFeed Policy Generator

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

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

Added missing license header. #799

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