Aegir 3 and Drupal 10: just about working
In my previous article I outlined that I really needed to get Drupal 10 sites running in Aegir 3. I had no time to wait around for other solutions, and I was going to try to decouple Aegir from running Drupal sites, so that it wouldn't be tied to Drupal versions.
Since writing that article and actually sitting down to do this work, I realised that it's quite an undertaking, and the approach outlined by Omega8cc in various github issues was worth a second look.
It works!
But it's wild. It comprises three main things:
- A custom/forked version of Drush 8.
- A custom/forked version of Provision 3.
- A custom/forked version of Drupal 10.
- (A sneaky fourth is that you absolutely do not want to have site-local Drush)
So...yeah...it's not going to be for the faint-hearted, but I'm going to detail out those three things a little, and how you might want to apply them to your situation.
Custom Drush 8
So the official Drush 8 doesn't support Drupal 10. But, it's actually not that much work to get this up and running, since Drush has pluggable 'engines' that load code based on the Drupal version that's detected when running commands.
Omega8cc has done a great job of doing the leg-work and providing a forked version of Drush, you can see the changes that have been made to support Drupal 10 here:
https://github.com/omega8cc/drush/compare/8.4.12...8-boa-micro
Although note, that there are some Aegir specific and non Drush 10 supporting changes in there too, so what I did was to make my own (private) fork of Drush and go through and apply the relevant changes to the files. If you don't know what the relevant changes are, then you probably are better off simply replacing your Drush with the Omega8cc fork, and it'll probably be fine.
Essentially this step is needed so that Drush sees the Drupal 10 codebase, and can interact with it correctly. It's likely that in Drupal 10's lifetime something will change, and Drush 8 will need some more work to be compatible with 10.3 and 10.4 etc.
If you were to run Drush 8 commands at this point, they'd start to bootstrap the site, but would fail with fatal errors. You need changes in Drupal 10 core too...
Custom Provision 3
Provision also makes use of Drush engines to load the correct code for the correct situation, so that if you ask Aegir to install a new site on a platform it'll load up the correct bit of code for the relevant Drupal version.
Again Omega8cc has done all the hard work here and provided the changes you need, but they are a bit harder to pick out of the repo. Try searching for files that contain '_10':
https://github.com/omega8cc/provision
And that should get you the files you need. I will note that unlike the Drush fork above, this really is a heavy fork. You are getting a lot more besides Drupal 10 support, if you can, I'd go for patching this into your existing Provision codebase.
I could add these to official provision 3 on Drupal.org, but without the other pieces they are useless and won't help you. Aegir 3 is essentially unmaintained, so while I've committed some PHP 8 fixes in the last few weeks, I'm not going to commit huge things like this.I suppose we could have some code maintained in an issue fork or a patch.
This step is need so that Provision will call the correct bits of code at the right time, as far as I can see, these are largely the same as Drupal 9 versions of the engines.
Custom Drupal 10
Now for the big compromise.
The main problem here is that Drupal 10 uses Symfony 6, which has type hints on various interfaces and methods, and Drush 8 uses Symfony 2, which does not.
So, if you load one before the other, then as soon as PHP tries to load the second, it'll die because either the types are there, or they aren't.
This is a bit of a showstopper and there's no decent way to get it to work nicely. Instead, Omega8cc has discovered some band-aids you can slap on and while it'll work, it's brittle!
Omega8cc's fork of Provision automatically tries to apply some of these patches to Drupal 10 platforms, and gives you a nice way to add/remove them. But again, also has a lot of other opinionated changes (to provision), so if you want to know what to do to Drupal 10 core...keep reading:
We need to:
- Remove a bunch of typehints from Drupal core's logging mechanisms.
- Downgrade psr/log
- Patch symfony/console
Removing the typehints
Omega8cc have got a nice patch that does this:
https://raw.githubusercontent.com/omega8cc/boa/5.x-dev/aegir/patches/drupal-ten-aegir-01.patch
And you can apply that using composer patches if you want.
Note that if you have any classes that extend these patched classes, they'll need patching too, so if you have any custom or contrib loggers, you'll need to go sort those out.
Downgrading psr/log
Composer makes this one super easy:
<span>composer require 'psr/log:1.1.4 as 3.0.0'</span>
Will do what you want. It's the companion to the first step, those classes implement these interfaces, so they need to get downgraded too. This might need to get adjusted if Drupal 10 core requires psr/log 3.1.0 or something like that, but the principles should still work.
If your Drupal 10 codebase isn't managed by Composer...well...getta out here and get that sorted first.
Patching symfony/console
Drush 8 only uses part of this package, so we can get away with patching just a tiny bit of it. Essentially you want to remove the 'Input' directory within the package. If you have a build system you could delete the files as part of your build process. Omega8cc's approach is to make the directory essentially unreadable.
Either way the result is that when PHP tries to load some code that uses version 6 of Symfony\console\Input
it'll fail to find the code in Drupal core, and instead fallback to the version that came with Drush 8. Luckily this code isn't used by Drupal core, but you'll need to check that your custom and contrib code doesn't use it either, or handles the case when it magically loads code from Symfony 2.
For me and my codebase this was fine. None of our custom or contrib code used the classes or interfaces, so all good.
That's it
For Drupal 10 support in Aegir, that should be it. You can run Aegir 3 in PHP 8.1 and Drupal 7 and Drupal 10 on the same box. Magic.
Make sure you don't have a site-local Drush in your composer require, otherwise, Drush 8 being the great tool that it is will find it, and pass execution over to it, but it's not the same Drush that Aegir has all it's claws/hooks in, so things will go badly quite quickly.
Gotchas
Probably many, we've not actually rolled this out into our production environment yet, but we're close.
The main thing I can think of is that Drupal 10 contrib modules are very much going to assume that there's a modern version of Drush running commands, and not Drush 8, so it's likely that they aren't going to provide Drush 8 commands. You might need to write your own shims that copy/paste large lumps of code, or call through the new style Drush commandfiles, but that means that Drush command hooks won't be working quite right etc.
So yeah, danger if you're doing anything interesting using Drush commands on your sites.
Oh, and I guess it's possible that this will all break hard in the Drupal 10 lifecycle. I mean, it probably won't because it'll always be a foundation of Symfony 6, but you never know, the Drop is always moving and all that.
Thanks to Omega8cc
This was all shown to be possible, and documented in code by the great team at Omega8cc, so thanks very much for the work they are doing. I have nothing against there heavy forks of Aegir, they just aren't for me, hence why I've tried to pull out just the bits you need into this post.
Future
I still think that Aegir 3 could be decoupled from hosting Drupal sites. So that it was hosting 'sites' and then one could have some well-defined way to interact with those sites via some command line tool depending on what they were. However, that's a big effort, and Aegir 3 is essentially unmaintained now, so that's not going to happen.
A number of others in the #aegir Drupal.org Slack channel have mentioned other alternatives, such as Aegir 5, or getting Drush 12 running Provision commands and running everything with Drush 12 instead of Drush 8, or using some other tool as the outer runner.I think they are all going to run into the same issues/have to deal with the same thing: abstracting the notion of the 'site'. Provision 3 takes a number of shortcuts to make it really easy to pass data around between itself and the site, and those shortcuts simply aren't possible in Modern Drupal.
However, in case there's someone out there with a big ol' budget, and a desire to keep Aegir 3 going, I think the 'decoupled' Aegir would look something like:
- A provision where the places that it calls through to functions executed in the Drupal context abstracted out into some kind of site specific 'plugin'. Instead of trying to use the nice Drush functions for calling a 'inner' Drush command, instead the usual command line interface would be used and data simply encoded on stdin/stdout/stderr in a format not tightly coupled to Drush 8 or Drush 12/13 etc.
- Provision calls into the Drupal site a lot and because it's never needed to be explicit about doing it, it's sometimes hard to spot where this is happening.
- Some kind of shim package that can be composer required into sites hosted on Aegir that would provide some way for the Provision plugins to call into the Drupal site and get the response it needs. Maybe this would merely provide some Drush commands.
Good luck if anyone ever embarks on such a project! Or contact us if you want a shoulder to cry on to hire us for a project!