Add a registry for SCMClient classes and move defaults into code.

Review Request #12525 — Created Aug. 10, 2022 and submitted — Latest diff uploaded


This introduces rbtools.clients.base.registry.SCMClientRegistry, which
keeps track of all the available BaseSCMClient subclasses. This
enables fetching a client by ID, iterating through all clients, and
registering new ones.

The registry is accessible via a rbtools.clients.scmclient_registry

SCMClient classes should now set a scmclient_id attribute. This will
be mandated in RBTools 5. For now, any loaded via entry point that lack
an ID will have one assigned, with a warning.

To improve performance and to avoid packaging-related complications,
the default list of clients are now fully inline, rather than
introspected via entrypoints. This matches what we've been doing within
Review Board. The registry still scans entrypoints for third-party
packages, but only when needed (if listing all clients or if a lookup
fails to find it in the built-in list).

Entry points use the modern importlib.metadata.entry_points API. This
has only solidified as of Python 3.10 (3.8/3.9 had it but it's not
compatible), so we pull in the official backport for those versions.

Unit tests pass.

Posted this change for review.

Ran mypy and pyright on the new registry code, with no errors
or warnings.