List:Commits« Previous MessageNext Message »
From:Mike Lischke Date:March 22 2011 11:40am
Subject:bzr commit into wex-installer-1.0 branch (mike.lischke:377)
View as plain text  
#At file:///D:/Work/MySQL/installer/ based on revid:mike.lischke@stripped

  377 Mike Lischke	2011-03-22
      - ConfigurationController: avoid duplicate initialization.
      - Package: improved log output if a package is not yet installed and hence no feature for it found.
      - Product: improved check for related products (better version number parsing). Removed error message if a product with the same version number is already installed.
      - ProductManager: reordered product initialization. First initialize its controller then the package itself to have certain values already set when the package and its features are processed.

    added:
      WexInstaller.Core/Utilities.cs
    modified:
      StandardPlugins/Server/ConfigurationController.cs
      StandardPlugins/Server/ServerConfigPanel2.cs
      WexInstaller.Core/Package.cs
      WexInstaller.Core/PluginManager.cs
      WexInstaller.Core/Product.cs
      WexInstaller.Core/ProductManager.cs
      WexInstaller.Core/WexInstaller.Core.csproj
=== modified file 'StandardPlugins/Server/ConfigurationController.cs'
=== modified file 'StandardPlugins/Server/ConfigurationController.cs'
--- a/StandardPlugins/Server/ConfigurationController.cs	2011-03-17 15:51:58 +0000
+++ b/StandardPlugins/Server/ConfigurationController.cs	2011-03-22 11:40:09 +0000
@@ -43,7 +43,7 @@
     {
       CurrentState = ConfigState.ConfigurationRequired;
       Logger.LogInformation("Product configuration controller created.");
-      Initialize();
+      //Initialize(); Triggered by the product manager.
 
       processedTemplate = false;
       processedService = false;

=== modified file 'StandardPlugins/Server/ServerConfigPanel2.cs'
--- a/StandardPlugins/Server/ServerConfigPanel2.cs	2011-03-18 10:29:04 +0000
+++ b/StandardPlugins/Server/ServerConfigPanel2.cs	2011-03-22 11:40:09 +0000
@@ -55,7 +55,8 @@
       // test active listeners
       IPEndPoint[] endPoints = ipGlobalProperties.GetActiveTcpListeners();
       foreach (IPEndPoint endPoint in endPoints)
-        if (endPoint.Port == port) return false;
+        if (endPoint.Port == port)
+          return false;
 
       return true;
     }

=== modified file 'WexInstaller.Core/Package.cs'
--- a/WexInstaller.Core/Package.cs	2011-03-21 10:34:56 +0000
+++ b/WexInstaller.Core/Package.cs	2011-03-22 11:40:09 +0000
@@ -138,7 +138,7 @@
     {
       bool success = false;
 
-      if (Id != String.Empty)
+      if (!string.IsNullOrEmpty(Id))
       {
         DisplayName = GetMSIProductInfo("ProductName");
         Publisher = GetMSIProductInfo("Publisher");
@@ -148,7 +148,7 @@
         if (FileName == null)
           FileName = GetMSIProductInfo("PackageName");
 
-        if (DisplayName != String.Empty && Publisher != String.Empty)
+        if (!string.IsNullOrEmpty(DisplayName) && !string.IsNullOrEmpty(Publisher))
         {
           if (RegistryEntries.Count > 0)
             RegistryEntries.Clear();
@@ -311,7 +311,7 @@
 
     public void PostInitialize()
     {
-      if (String.IsNullOrEmpty(Id) == false)  // Valid Package.
+      if (!String.IsNullOrEmpty(Id))  // Valid Package.

       {
         // Synchronize Installed Feature state.
         StringBuilder FeatureCode = new StringBuilder(256);
@@ -365,7 +365,8 @@
         if (rc != MSIEnumError.NoMoreItems)
         {
           // Record the real error.
-          Logger.LogError(String.Format("Found error: {0}", rc.ToString()));
+          Logger.LogWarning(String.Format("Package initialization for {0} returned:\n\t{1} (" +
+            "expected if the product is not installed yet).", packageCode, rc.ToString()));
         }
       }
     }

=== modified file 'WexInstaller.Core/PluginManager.cs'
--- a/WexInstaller.Core/PluginManager.cs	2011-02-09 13:49:30 +0000
+++ b/WexInstaller.Core/PluginManager.cs	2011-03-22 11:40:09 +0000
@@ -1,146 +1,146 @@
 using System;
 using System.Collections.Generic;
-using System.Text;
-using WexInstaller.Core;
+using System.IO;
 using System.Reflection;
-using System.IO;
 
 namespace WexInstaller.Core
 {
-    public class PluginManager
-    {
-        private bool loadedPlugins;
-        private Dictionary<string, ControllerType> controllerTypes =
-            new Dictionary<string, ControllerType>();
-        private Dictionary<string, ProductConfigurationController> controllerCache = 
-            new Dictionary<string,ProductConfigurationController>();
-
-        public static PluginManager Instance = new PluginManager();
-
-        /// <summary>
-        /// Retrieves the latest controller plugin (if any) associated with the given product name
-        /// </summary>
-        /// <param name="productName"></param>
-        /// <returns></returns>
-        public static ProductConfigurationController GetController(string productName)
-        {
-            return Instance.GetControllerInternal(productName);
-        }
-
-        private ProductConfigurationController GetControllerInternal(string productName)
-        {
-            if (!loadedPlugins)
-                LoadPlugins();
-
-            // first look to see if we have created this controller before
-            if (controllerCache.ContainsKey(productName))
-                return controllerCache[productName];
-
-            // now find the best match between the product name and our controller product names
-            string longestKey = String.Empty;
-            foreach (string key in controllerTypes.Keys)
-                if (productName.StartsWith(key) && key.Length > longestKey.Length)
-                    longestKey = key;
-            if (!String.IsNullOrEmpty(longestKey))
-            {
-                ControllerType cType = controllerTypes[longestKey];
-                ProductConfigurationController c = (ProductConfigurationController)
-                    cType.HostingAssembly.CreateInstance(cType.TypeName, false);
-                if (c != null)
-                {
-                    controllerCache[productName] = c;
-                    return c;
-                }
-            }
-
-            return null;
-        }
-
-        private void LoadControllersFromAssembly(Assembly assembly)
-        {
-            Type interfaceType = typeof(ProductConfigurationController);
-            Type[] types = assembly.GetTypes();
-
-            Logger.LogInformation(String.Format("Loading controllers from {0}", assembly.Location));
-
-            foreach (Type t in types)
-            {
-                if (!t.IsAbstract && interfaceType.IsAssignableFrom(t))
-                {
-                    object[] attr = t.GetCustomAttributes(typeof(ProductConfigurationAttribute), false);
-
-                    // if the type doesn't have the right attribute, we ignore it
-                    if (attr == null || attr.Length != 1) continue;
-
-                    ProductConfigurationAttribute a = (ProductConfigurationAttribute)attr[0];
-
-                    // if this is the first controller for this product name, then add it to our
-                    // dictionary
-                    if (!controllerTypes.ContainsKey(a.ProductName))
-                        controllerTypes[a.ProductName] = new ControllerType(assembly, t.FullName, a.Version);
-                    else
-                    {
-                        ControllerType existingType = controllerTypes[a.ProductName];
-                        if (a.Version > existingType.Version)
-                            controllerTypes[a.ProductName] = new ControllerType(assembly, t.FullName, a.Version);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Loads all the plugins from the executing assembly and all assemblies in the same folder
-        /// that end in -plugin.dll
-        /// </summary>
-        private void LoadPlugins()
-        {
-            if (loadedPlugins) return;
-
-            // first load the plugins that are baked in
-            LoadControllersFromAssembly(Assembly.GetExecutingAssembly());
-
-            string pluginsDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
-            string[] plugins = Directory.GetFiles(pluginsDir, "*Plugins.dll");
-            foreach (string plugin in plugins)
-            {
-                Assembly a = Assembly.LoadFile(plugin);
-                LoadControllersFromAssembly(a);
-            }
-
-            loadedPlugins = true;
-        }
-
-        /// <summary>
-        ///  Returns a list of server controllers, possibly running
-        /// </summary>
-        /// <param name="running">If true only return the controllers whose servers are running</param>
-        /// <returns></returns>
-        public List<ServerProductConfigurationController> GetServerControllers(bool running)
-        {
-            List<ServerProductConfigurationController> servers = new List<ServerProductConfigurationController>();
-
-            foreach (ProductConfigurationController controller in controllerCache.Values)
-            {
-                if (!(controller is ServerProductConfigurationController)) continue;
-                ServerProductConfigurationController s = controller as ServerProductConfigurationController;
-                if (running && !s.IsRunning) continue;
-                servers.Add(s);
-            }
-            return servers;
-        }
-    }
-
-    struct ControllerType 
-    {
-        public Assembly HostingAssembly;
-        public string TypeName;
-        public int Version;
-
-        public ControllerType(Assembly a, string type, int version)
-        {
-            HostingAssembly = a;
-            TypeName = type;
-            Version = version;
-        }
-    }
+  public class PluginManager
+  {
+    private bool loadedPlugins;
+    private Dictionary<string, ControllerType> controllerTypes =
+        new Dictionary<string, ControllerType>();
+    private Dictionary<string, ProductConfigurationController> controllerCache = 
+        new Dictionary<string,ProductConfigurationController>();
+
+    public static PluginManager Instance = new PluginManager();
+
+    /// <summary>
+    /// Retrieves the latest controller plugin (if any) associated with the given product name
+    /// </summary>
+    public static ProductConfigurationController GetController(string productName)
+    {
+      return Instance.GetControllerInternal(productName);
+    }
+
+    private ProductConfigurationController GetControllerInternal(string productName)
+    {
+      if (!loadedPlugins)
+        LoadPlugins();
+
+      // first look to see if we have created this controller before
+      if (controllerCache.ContainsKey(productName))
+        return controllerCache[productName];
+
+      // now find the best match between the product name and our controller product names
+      string longestKey = String.Empty;
+      foreach (string key in controllerTypes.Keys)
+        if (productName.StartsWith(key) && key.Length > longestKey.Length)
+          longestKey = key;
+      if (!String.IsNullOrEmpty(longestKey))
+      {
+        Logger.LogInformation(String.Format("Creating configuration controller for: {0}.", productName));
+        ControllerType cType = controllerTypes[longestKey];
+        ProductConfigurationController c = (ProductConfigurationController)
+          cType.HostingAssembly.CreateInstance(cType.TypeName, false);
+        if (c != null)
+        {
+          controllerCache[productName] = c;
+          return c;
+        }
+      }
+
+      return null;
+    }
+
+    private void LoadControllersFromAssembly(Assembly assembly)
+    {
+      Type interfaceType = typeof(ProductConfigurationController);
+      Type[] types = assembly.GetTypes();
+
+      Logger.LogInformation(String.Format("Loading controllers from {0}", assembly.Location));
+
+      foreach (Type t in types)
+      {
+        if (!t.IsAbstract && interfaceType.IsAssignableFrom(t))
+        {
+          object[] attr = t.GetCustomAttributes(typeof(ProductConfigurationAttribute), false);
+
+          // if the type doesn't have the right attribute, we ignore it
+          if (attr == null || attr.Length != 1)
+            continue;
+
+          ProductConfigurationAttribute a = (ProductConfigurationAttribute)attr[0];
+
+          // if this is the first controller for this product name, then add it to our
+          // dictionary
+          if (!controllerTypes.ContainsKey(a.ProductName))
+            controllerTypes[a.ProductName] = new ControllerType(assembly, t.FullName, a.Version);
+          else
+          {
+            ControllerType existingType = controllerTypes[a.ProductName];
+            if (a.Version > existingType.Version)
+              controllerTypes[a.ProductName] = new ControllerType(assembly, t.FullName, a.Version);
+          }
+        }
+      }
+    }
+
+    /// <summary>
+    /// Loads all the plugins from the executing assembly and all assemblies in the same folder
+    /// that end in -plugin.dll
+    /// </summary>
+    private void LoadPlugins()
+    {
+      if (loadedPlugins)
+        return;
+
+      // first load the plugins that are baked in
+      LoadControllersFromAssembly(Assembly.GetExecutingAssembly());
+
+      string pluginsDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+      string[] plugins = Directory.GetFiles(pluginsDir, "*Plugins.dll");
+      foreach (string plugin in plugins)
+      {
+        Assembly a = Assembly.LoadFile(plugin);
+        LoadControllersFromAssembly(a);
+      }
+
+      loadedPlugins = true;
+    }
+
+    /// <summary>
+    ///  Returns a list of server controllers, possibly running
+    /// </summary>
+    /// <param name="running">If true only return the controllers whose servers are running</param>
+    public List<ServerProductConfigurationController> GetServerControllers(bool running)
+    {
+      List<ServerProductConfigurationController> servers = new List<ServerProductConfigurationController>();
+
+      foreach (ProductConfigurationController controller in controllerCache.Values)
+      {
+        if (!(controller is ServerProductConfigurationController))
+          continue;
+        ServerProductConfigurationController s = controller as ServerProductConfigurationController;
+        if (running && !s.IsRunning)
+          continue;
+        servers.Add(s);
+      }
+      return servers;
+    }
+  }
+
+  struct ControllerType 
+  {
+    public Assembly HostingAssembly;
+    public string TypeName;
+    public int Version;
+
+    public ControllerType(Assembly a, string type, int version)
+    {
+        HostingAssembly = a;
+        TypeName = type;
+        Version = version;
+    }
+  }
 }

=== modified file 'WexInstaller.Core/Product.cs'
--- a/WexInstaller.Core/Product.cs	2011-03-21 12:59:48 +0000
+++ b/WexInstaller.Core/Product.cs	2011-03-22 11:40:09 +0000
@@ -130,10 +130,10 @@
     {
       Package p = GetPackage();
       if (initalizePackage)
-          p.PostInitialize();
+        p.PostInitialize();
       p.UrlBase = UrlBase;
 
-      if (String.IsNullOrEmpty(p.Id) == false)  // Valid Package.
+      if (!String.IsNullOrEmpty(p.Id))  // Valid Package.
       {
         // Is the package in our cache?
         CurrentState = (p.FoundLocal) ? ProductState.FoundLocal : ProductState.WebRemote;
@@ -511,7 +511,8 @@
           else
             type = ChangeType.Removal;
         else
-          type = ChangeType.Installation;
+          if (ProposedInstalled)
+            type = ChangeType.Installation;
       }
 
       // If there was no change for the product as such go through the features to find changes.
@@ -528,7 +529,10 @@
               else
                 type = ChangeType.Removal;
             else
-              type = ChangeType.Installation;
+              if (ProposedInstalled)
+                type = ChangeType.Installation;
+
+            break;
           }
       }
 
@@ -683,77 +687,115 @@
 
     private bool FindReleatedInstalledProducts()
     {
-        bool FoundUpgradeableProducts = false;
-
-        if (UpgradeId.Length > 0)
+      bool foundUpgradeableProducts = false;
+
+      if (UpgradeId.Length > 0)
+      {
+        StringBuilder productCode = new StringBuilder(39);
+        uint currentIndex = 0;
+        MSIEnumError rc = MSIEnumError.Success;
+
+        do
         {
-            StringBuilder ProductCode = new StringBuilder(39);
-            uint CurrentIndex = 0;
-            MSIEnumError rc = MSIEnumError.Success;
-
-            do
+          if (productCode.Length > 0)  // else this.Installed == true;
+          {
+            Package p = GetPackage();
+            string relatedProductCode = productCode.ToString();
+            if (relatedProductCode != p.Id)
             {
-                if (ProductCode.Length > 0)  // else this.Installed == true;
+              if (Packages.Count == 2)
+              {
+                // No need to search again because there can be only 2 packages.
+                foundUpgradeableProducts = true;
+              }
+              else
+              {
+                Package possibleOlderPackage = new Package();
+                possibleOlderPackage.Id = relatedProductCode;
+
+                if (p.ThisVersion != possibleOlderPackage.ThisVersion)
                 {
-                    Package p = GetPackage();
-                    string relatedProductCode = ProductCode.ToString();
-                    if (relatedProductCode != p.Id)
+                  // Compare only products with same major and minor number.
+                  Regex regex = new Regex(@"(?<main>(\d+\.){2})(?<build>\d+[a-z]?)(?<revision>\.\d+)?");
+                  Match thisMatch = regex.Match(p.ThisVersion);
+                  Match otherMatch = regex.Match(possibleOlderPackage.ThisVersion);
+                  if (thisMatch.Success && otherMatch.Success)
+                  {
+                    if (thisMatch.Groups["main"].Value == otherMatch.Groups["main"].Value)
                     {
-                        if (Packages.Count == 2)
-                        {
-                            // No need to search again because there can be only 2 packages.
-                            FoundUpgradeableProducts = true;
-                        }
-                        else
-                        {
-                            Package possibleOlderVersion = new Package();
-                            possibleOlderVersion.Id = relatedProductCode;
-
-                            if (p.ThisVersion.Substring(0, 3) == possibleOlderVersion.ThisVersion.Substring(0, 3)) // Same MAJOR.MINOR family
-                            {
-                                int olderMinor = Convert.ToInt32(possibleOlderVersion.ThisVersion.Substring(possibleOlderVersion.ThisVersion.LastIndexOf('.') + 1));
-                                int thisMinor = Convert.ToInt32(p.ThisVersion.Substring(p.ThisVersion.LastIndexOf('.') + 1));
-
-                                if (thisMinor > olderMinor)
-                                {
-                                    FoundUpgradeableProducts = PopulateRelatePackageFeatures(possibleOlderVersion);
-                                    if (FoundUpgradeableProducts == true)
-                                    {
-                                        possibleOlderVersion.PostInitialize();
-                                        possibleOlderVersion.UrlBase = p.UrlBase;
-                                        Packages.Add(possibleOlderVersion);
-                                    }
-                                }
-                                else
-                                {
-                                    // The install will fail because a newer version of the MSI is available.  
-                                    // Maybe, the current package should be replaced with a from memory version since everything is INSTALLED?
-                                    Logger.LogError("A newer product has been found but we're not sure what to do with it yet so hold this place.");
-                                }
-                            }
-                        }
+                      // Unfortunately we have to do string comparisons instead just using numbers here
+                      // as it can happen there are additional letters in a number (<sic>).
+                      string thisBuild = thisMatch.Groups["build"].Value;
+                      string otherBuild = otherMatch.Groups["build"].Value;
+
+                      int comparison = Utilities.CompareAsNumbers(thisBuild, otherBuild);
+                      bool haveNewer = false;
+                      if (comparison > 0)
+                        haveNewer = true;
+                      else
+                        if (comparison == 0)
+                        {
+                          // Same build numbers too. So compare finally the release numbers.
+                          // This also works if one or both values are missing.
+                          // If both are missing then they are considered equal, otherwise the missing
+                          // one represents the older version.
+                          string thisRelease = thisMatch.Groups["build"].Value;
+                          string otherRelease = otherMatch.Groups["build"].Value;
+
+                          if (Utilities.CompareAsNumbers(thisRelease, otherRelease) > 0)
+                            haveNewer = true;
+                        }
+
+                      if (haveNewer)
+                      {
+                        foundUpgradeableProducts = PopulateRelatePackageFeatures(possibleOlderPackage);
+                        if (foundUpgradeableProducts)
+                        {
+                          possibleOlderPackage.PostInitialize();
+                          possibleOlderPackage.UrlBase = p.UrlBase;
+                          Packages.Add(possibleOlderPackage);
+                        }
+                      }
+                      else
+                      {
+                        // The install will fail because a newer version of the product is already installed.  
+                        // Maybe, the current package should be replaced with a from memory version since everything is INSTALLED?
+                        // TODO: warn the user that this product is already installed and won't be installed again by this installer.
+                        Logger.LogError("A newer product is already installed but we're not sure what to do with it yet so hold this place.");
+                      }
                     }
-                    ProductCode.Remove(0, ProductCode.Length);
-                }
-                try
-                {
-                    rc = (MSIEnumError)MsiInterop.MsiEnumRelatedProducts(UpgradeId, 0, CurrentIndex++, ProductCode);
-                }
-                catch (Exception e)
-                {
-                    InstallActionLog.AppendLine(e.Message);
-                }
-            }
-            while (rc == MSIEnumError.Success);
-
-            if (rc != MSIEnumError.NoMoreItems)
-            {
-                // Record the real error.
-                InstallActionLog.AppendLine(String.Format("Found error: {0}", rc.ToString()));
-            }
-        }
-
-        return FoundUpgradeableProducts;
+                  }
+                  else
+                  {
+                    if (!thisMatch.Success)
+                      Logger.LogError(string.Format("Version of this package ({0}) is invalid.", p.ThisVersion));
+                    if (!otherMatch.Success)
+                      Logger.LogError(string.Format("Version of related package ({0}) is invalid.", possibleOlderPackage.ThisVersion));
+                  }
+                }
+              }
+            }
+            productCode.Remove(0, productCode.Length);
+          }
+          try
+          {
+            rc = (MSIEnumError)MsiInterop.MsiEnumRelatedProducts(UpgradeId, 0, currentIndex++, productCode);
+          }
+          catch (Exception e)
+          {
+            InstallActionLog.AppendLine(e.Message);
+          }
+        }
+        while (rc == MSIEnumError.Success);
+
+        if (rc != MSIEnumError.NoMoreItems)
+        {
+          // Record the real error.
+          InstallActionLog.AppendLine(String.Format("Found error: {0}", rc.ToString()));
+        }
+      }
+
+      return foundUpgradeableProducts;
     }
 
     // Download

=== modified file 'WexInstaller.Core/ProductManager.cs'
--- a/WexInstaller.Core/ProductManager.cs	2011-03-21 15:29:28 +0000
+++ b/WexInstaller.Core/ProductManager.cs	2011-03-22 11:40:09 +0000
@@ -80,14 +80,14 @@
         pc.Type = (ProductCategoryType)Enum.Parse(typeof(ProductCategoryType), pc.Name);
         foreach (Product p in pc.Products)
         {
+          // Initialize the controller if there is any.
+          if (p.Controller != null)
+            p.Controller.Initialize();
+
           p.PostInitialize(true);
           p.SetParent(pc);
           foreach (ProductFeature feature in p.GetProductFeatures())
             feature.SetParent(p);
-
-          // Initialize the controller if there are any
-          if (p.Controller != null)
-            p.Controller.Initialize();
         }
       }
 

=== added file 'WexInstaller.Core/Utilities.cs'
--- a/WexInstaller.Core/Utilities.cs	1970-01-01 00:00:00 +0000
+++ b/WexInstaller.Core/Utilities.cs	2011-03-22 11:40:09 +0000
@@ -0,0 +1,21 @@
+
+namespace WexInstaller.Core
+{
+  class Utilities
+  {
+    /// <summary>
+    /// Compares two strings containing numbers and optionally additional content lexically.
+    /// </summary>
+    /// <returns>Same as string.CompareTo.</returns>
+    public static int CompareAsNumbers(string s1, string s2)
+    {
+      // Make strings comparable as numbers (they must have the same length to work properly).
+      while (s1.Length < s2.Length)
+        s1.Insert(0, "0");
+      while (s2.Length < s1.Length)
+        s2.Insert(0, "0");
+
+      return s1.CompareTo(s2);
+    }
+  }
+}

=== modified file 'WexInstaller.Core/WexInstaller.Core.csproj'
--- a/WexInstaller.Core/WexInstaller.Core.csproj	2011-03-18 10:29:04 +0000
+++ b/WexInstaller.Core/WexInstaller.Core.csproj	2011-03-22 11:40:09 +0000
@@ -79,6 +79,7 @@
       <DesignTime>True</DesignTime>
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
+    <Compile Include="Utilities.cs" />
     <Compile Include="Win32.cs" />
   </ItemGroup>
   <ItemGroup>

Attachment: [text/bzr-bundle] bzr/mike.lischke@oracle.com-20110322114009-7ca4p2imyu0nemxk.bundle
Thread
bzr commit into wex-installer-1.0 branch (mike.lischke:377) Mike Lischke22 Mar