Index: install.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/install.cc,v
retrieving revision 2.72
diff -p -u -r2.72 install.cc
--- install.cc	5 Apr 2005 21:37:41 -0000	2.72
+++ install.cc	20 Apr 2005 14:13:50 -0000
@@ -447,6 +447,70 @@ check_for_old_cygwin ()
 }
 
 static void
+uninstall_if_needed (Installer &myInstaller, packagemeta & pkg)
+{
+  if (pkg.installed && (!pkg.desired
+    || (pkg.desired != pkg.installed && pkg.desired.picked ())))
+  {
+    myInstaller.uninstallOne (pkg);
+  }
+}
+
+/* Return value is number to increment error count by. */
+static int
+upgrade_if_needed (Installer &myInstaller, packagemeta & pkg, HWND owner)
+{
+  if (pkg.installed && pkg.desired.picked())
+  {
+    try
+    {
+      if (myInstaller.replaceOne (pkg))
+        return 1;
+    }
+    catch (exception *e)
+    {
+      if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES)
+      {
+        log (LOG_TIMESTAMP)
+          << "User cancelled setup after install error" << endLog;
+        LogSingleton::GetInstance().exit (1);
+        /* UNREACHED due to NORETURN function above. */
+      }
+      /* Otherwise may as well count it as an error. */
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* Return value is number to increment error count by. */
+static int
+install_if_needed (packagemeta & pkg, HWND owner)
+{
+  if (pkg.desired && pkg.desired.changeRequested())
+  {
+    try
+    {
+      if (install_one (pkg))
+        return 1;
+    }
+    catch (exception *e)
+    {
+      if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES)
+      {
+        log (LOG_TIMESTAMP)
+          << "User cancelled setup after install error" << endLog;
+        LogSingleton::GetInstance().exit (1);
+        /* UNREACHED due to NORETURN function above. */
+      }
+      /* Otherwise may as well count it as an error. */
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static void
 do_install_thread (HINSTANCE h, HWND owner)
 {
   int i;
@@ -527,70 +591,53 @@ do_install_thread (HINSTANCE h, HWND own
 	}
     }
 
+  /* save cygwin dll package for last so that the uninstall scripts
+   * are actually able to run! @todo: should we save maybe just a
+   * couple of other packages such as basefiles, [b]ash as well? */
+  packagemeta *cygwin_package = NULL;
   /* start with uninstalls - remove files that new packages may replace */
   for (vector <packagemeta *>::iterator i = db.packages.begin ();
        i != db.packages.end (); ++i)
     {
       packagemeta & pkg = **i;
-      if (pkg.installed && (!pkg.desired || (pkg.desired != pkg.installed &&
-	  pkg.desired.picked ())))
-	myInstaller.uninstallOne (pkg);
+      if (pkg.name == "cygwin")
+      {
+        cygwin_package = *i;
+        continue;
+      }
+      uninstall_if_needed (myInstaller, pkg);
     }
-
-  /* now in-place binary upgrades/reinstalls, as these may remove fils 
-   * that have been moved into new packages
-   */
-
+  /* now in-place binary upgrades/reinstalls, as these may remove files
+   * that have been moved into new packages.  */
   for (vector <packagemeta *>::iterator i = db.packages.begin ();
        i != db.packages.end (); ++i)
     {
       packagemeta & pkg = **i;
-      if (pkg.installed && pkg.desired.picked())
-	{
-	  try {
-	      int e = 0;
-	    e += myInstaller.replaceOne (pkg);
- 	    if (e)
-	      errors++;
-	  }
-	  catch (exception *e)
-	    {
-	      if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES)
-		{
-		  log (LOG_TIMESTAMP)
-                    << "User cancelled setup after install error" << endLog;
-		  LogSingleton::GetInstance().exit (1);
-		  return;
-		}
-	    }
-	}
+      /* Second time round, a quick pointer equality test is enough to
+       * spot the cygwin dll package. */
+      if (*i == cygwin_package)
+        continue;
+      errors += upgrade_if_needed (myInstaller, pkg, owner);
     }
-
+  /* Now, last of all, uinstall cygwin.  Hopefully leaving the old one
+   * until last should have been sufficient for the uninstall scripts to
+   * run.  We then make sure it's the very first thing that we re-install.
+   */
+  if (cygwin_package)
+  {
+    uninstall_if_needed (myInstaller, *cygwin_package);
+    errors += upgrade_if_needed (myInstaller, *cygwin_package, owner);
+    /* That either uninstalled it, or upgraded in place, now reinstall. */
+    errors += install_if_needed (*cygwin_package, owner);
+  }
+  /* Finally, it should be safe to run through the list one last
+   * time and install all the new or upgrade-after-uninstalling
+   * packages. */
   for (vector <packagemeta *>::iterator i = db.packages.begin ();
        i != db.packages.end (); ++i)
     {
       packagemeta & pkg = **i;
-
-      if (pkg.desired && pkg.desired.changeRequested())
-	{
-	  try
-	    {
-    	      int e = 0;
-    	      e += install_one (pkg);
-    	      if (e)
-		  errors++;
-	    }
-	  catch (exception *e)
-	    {
-	      if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES)
-		{
-		  log (LOG_TIMESTAMP)
-                    << "User cancelled setup after install error" << endLog;
-		  LogSingleton::GetInstance().exit (1);
-		  return;
-		}
-	    }
-	}
+      errors += install_if_needed (pkg, owner);
     }				// end of big package loop
 
   if (rebootneeded)
