How to join two addons foo.xpi and bar.xpi into foobar.xpi?

Say I have two addons foo.xpi and bar.xpi that have similar/related/overlapping functionality and I want to replace them with an addon foobar.xpi that joins the functionality of both. Preferably, the transition should happen by the standard update process.

Will this work as expected if I simply make the <em:updatelink> of both old addons point to the new addon? I am tempted to think so, but can think of a myriad of problems:

I suppose that I at least have to make the version number of foobar larger than the max of the versions of foo and bar, don’t I?
But will the changing id pose problems? E.g., I fear that someone with foobar installed might still be able to additionally (re-) install foo and/or bar.
How will install() and uninstall() of old and new bootstrap.js be invoked? In particular, what happens if someone happens to have both of the old addons installed upon upgrade?

So maybe I am all on the wrong track and there is a better way to achieve what I intend?

I’m trying to be tricky here. I would try this, I’m not sure if it would work:

Create a new addon listing with new id Z.

Make foo.xpi listing unlisted, and create a update it with a new xpi that points to the update url of Z.

Do same with bar.xpi.

I’m not sure if that will work but if it does, that should update everyone to Z.

As for bootstrap.js, you will have to rework how foo.xpi and bar.xpi work togather. No quick way about it. You might end up just copy pasting the startup and shutodwn procs into Z from both foo and bar xpi’s.

“I’m not sure if that will work” - that was the very reason why I posted my question :wink:
Nevertheless, the way I read it your suggestion looks just like what I had in mind, just with differnt words.

But what you say about bootstrap sounds particularly interesting: If I understand it right, you fear that install/startup of the combined addon will indeed be fired only once even if both old addons were present and therefore it should be capable of performing all cleanup actions of the old addons on its own?

updateLink is for “self-hosted” addons. It points to a special manifest file that you need to host somewhere. The manifest file lists all the versions of the addon and has links to each one. Generally this needs to be https:// or you have to go through a special key-generation process to ensure the xpi integrity. You still need to get your addon signed unless it is being used in a private environment where that isn’t necessary.

So if you’re hosting on AMO, updateLink isn’t even allowed in the xpi. Even if it was, you can’t force people to upgrade from one addon to a different addon, so I can’t see this approach working. You could just create (and maintain!) the same new codebase under the UUID for both the old addons. That’s deliberate, I’m sure you can see why.

You might get cute and do a sort of drive-by install, with the addon itself installing a new addon using javascript. The addon manager has APIs for installing addons from a file or URL. I haven’t ever done that, so I don’t know what sort of warnings or confirmation dialogs the user would see. Mozilla have tightened up on that sort of thing for obvious reasons, Give it a try and see what happens …

About conflicting addons: its a pain! First off, don’t make them conflict - use a different namespace. Then you can, if necessary, add code in your new addon to disable either of the old addons that it finds. You’ll also have to add listeners because you don’t know what order the addons will appear at startup, or whether some dodo might install one of the old ones at a later date. Sounds thoroughly dodgy, but it is entirely legal (make sure the reviewers realise they are all your addons!) to disable another addon.

I forgot to mention that my uses case is indeed about self-hosted (and only signed by AMO) addons.
Meanwhile I played around with the settings in a lab and observe the following:

  • It is possible to update either foo.xpi or bar.xpi to foobar.xpi by creating a suitable update.rdf
  • It is not even necessary that the version number of foobar is greater than that of foo and bar (so one might restart the version counter at 1.0.0, say, for foobar) if only the <em:version> entry in the update.rdf (of foo and bar) is larger than the currently installed foo and bar version number
  • if both foo and bar are installed, search for update will find updates for both. One of these will install and e.g. replace foo with foobar. However, bar remains installed because update fails. Retrying autoupdate after a restart of FF finds the update for bar again, downloads and starts installing again, but the installing stalls at the very beginning (thin blue progress bar)

So it seems that this attempt did not work and leaves a mess.

I guess I should first of all create updates of both foo and bar that would be “aware” of an installed foobar. These could than silently completely disable themselves if they sense foobar. Preferably they would even somehow uninstall themselves in that case. I’ll try and research if this is somehow possible.

Another issue I had was that it seems that during the (partial) update from foo to foobar, there seems to have been no call to install(data,reason) with ADDON_UPGRADE as reason. At least I had expected my code to copy prefeences extensions.foo.somepref to extensions.foobar.somepref, but it didn’t (whereas the copying does work when invoking install from the about:debugging console)

Is foobar a completely different UUID? Amazing that the update manifest will just install basically any old addon you tell it to. And leave the old one installed as well?

Looks like the cleanest solution is going to be to write a bit of javascript that will install the new addon, and perhaps another that uninstalls both the old ones once it is installed.