Fix handling of multi-step upgrades that need to happen in lock-step
authorTim Düsterhus <duesterhus@woltlab.com>
Thu, 15 Sep 2022 10:34:11 +0000 (12:34 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 15 Sep 2022 10:34:11 +0000 (12:34 +0200)
Consider the following situation:

- Package com.example.foo is installed in version 1.0.0.
- Version 1.0.1 can be upgraded from 1.0.0.
- Version 1.0.2 can be upgraded from 1.0.1 and adds a dependency on
  com.woltlab.bar which is not yet installed.
- Version 1.0.3 can be upgraded from 1.0.2.

Now the PackageinstallationScheduler will build the following plan when it's
desired to upgrade com.woltlab.foo from 1.0.0 to 1.0.2:

- Upgrade com.woltlab.foo to 1.0.1
- Install com.woltlab.bar to satisfy the dependencies for 1.0.2
- Upgrade com.woltlab.foo to 1.0.2
- Upgrade com.woltlab.foo to 1.0.3

Now when build the nodes for this plan, the upgrade instructions for 1.0.2 will
not be detected, as the "previous package" logic used for iterative upgrades
will set the previous package of com.woltlab.foo in 1.0.2 to com.woltlab.bar.
Thus when upgrading to 1.0.2 the node builder will believe that com.woltlab.foo
is installed in 1.0.0 when it actually is already upgraded to 1.0.1.

Fix this by leveraging the $pendingPackages list which is already kept up to
date for dependency resolution.

wcfsetup/install/files/lib/system/package/PackageInstallationNodeBuilder.class.php

index 589831f0e8f5ee77e56620872fed95d98b5ed9e4..de9fca7311406024566d6011a06389be01762000 100644 (file)
@@ -774,10 +774,10 @@ class PackageInstallationNodeBuilder
             $installation = new PackageInstallationDispatcher($queue);
 
             // work-around for iterative package updates
-            if ($this->installation->queue->action == 'update' && $queue->package == $this->installation->queue->package) {
+            if (isset(self::$pendingPackages[$queue->package])) {
                 $installation->setPreviousPackage([
-                    'package' => $this->installation->getArchive()->getPackageInfo('name'),
-                    'packageVersion' => $this->installation->getArchive()->getPackageInfo('version'),
+                    'package' => $queue->package,
+                    'packageVersion' => self::$pendingPackages[$queue->package],
                 ]);
             }