Transaction: Change how dependencies are resolved

Instead of resolving dependencies when adding refs to the list we make
adding refs trivial, and then add a dependency-resolving and ordering
phase to the start of flatpak_transaction_run().

Instead of resolving dependencies for each ref by itself this means
that we have a long list of refs we can work on. For the moment this
isn't really used, but it will later allow us to be much more
efficient in the p2p codepath because we can hand over a lot of refs
in a single p2p operation.

There are some complexities, for instance, we don't know initially
which the final refs will be, because the dependency resolving will
add new ones, yet we must still start with some operation.

The way this works is by repeated stages:

 * Resolve the operatations for all the initially specified
   refs. Resolve means doing i/o to determine the latest available
   commit id, and the corresponding metadata for that commit.

 * Add dependencies for all resolved ops, this typically means looking
   at the apps and finding which runtime they need, and then finding a
   runtime to install or update.

 * Resolve all new refs, meaning we now load the metadata for the
   runtime dependencies we added before.

 * Add related refs for all resolved ops, i.e. extensions for apps
   and runtimes. These are marked for install/update as needed.

 * Resolve the final refs.

Now we have a full list of things that we need to install or update,
and for each the commit id and the corresponding metadata. We can at
this point:

 * Verify that the metadata is valid for this version of flatpak
 * Verify that the metadata permissions are not greater than the
   previous version on updates (confirm if so).
 * Guarantee that the above verification will be correct becase
   we resolved each operation to a particular commit it that we
   will pull.
 * Quickly decide which update operations to skip because they
   are no-ops (same as installed version).

There are also some complexities wrt operation ordering. Previously
we decided the ordering when emitting the dependencies, but now
we can't do that since the dependencies are added in non-ordered chunks.
Instead we add some dependency information during the dependency
gathering and do a topological sort at the end.

This is the first step towards a better transaction handling, but here
are still some things left to do:

 * resolve_ops() calls flatpak_dir_find_latest_rev() for each
   operation, which is fine in the normal case as it just looks
   at the summary cached in the RemoteState. However in the p2p
   case it is very inefficient. Now that we have a chunk of
   refs we could resolve in parallel we should instead do a
   single find_remotes() + pull_remotes(COMMITS_ONLY) operation which
   will be much faster.
 * In the p2p case we're still using the metadata from the ostree-metadata
   branch, which may not be the same as the version we will actually be
   pulling. The above COMMITS_ONLY pull operation will allow us to instead
   read the metadata from the real commit objects (which we're guaranteed
   to actually get due to us locking down the commit id when pulling).
 * Even in the non-p2p case we get the wrong metadata when doing an
   explicit downgrade (update --commit=...) because we're using the
   metadata from the summary which only applies to the latest commit.
   This needs to be changed to also pull the commit object.
 * After resolve, but before pulling the full ref we are not currently
   doing metadata permission verification (vs last installed version)
   to see if new permissions need to be requested. This needs to be
   added. We could also let the user pass in pre-acked permissions so
   that a UI can show permissions ahead of time and then avoid
   confirming them again.

Closes: #1787
Approved by: alexlarsson
This commit is contained in:
Internal Server Error - Gitea: Git with a cup of tea
500 Internal Server Error

Gitea Version: 1.28.0+dev-477-g8b6ad49a5f