* Problem description
There are use cases, which hard to solve with guix's service extension
mechanism, I'll demonstrate it with following examples:
1. Imagine, we have home-bash, home-zsh and home-direnv services in our
home-environment. To make direnv work, we need to add `eval "$(direnv
hook bash)"` and eval `"$(direnv hook zsh)"` to ~/.bashrc and ~/.zshrc
respectively. Ideally, it should be done automatically, when home-direnv
added to list of services (and this code should dissapear from rc files
automatically, when home-direnv removed from the list).
Also, it's important to add those evals only to shells, which are
declared in service list, because if service is extended
instantiate-missing-services will try to instantiate it even if it's not
declared in the list.
2. Another hypothetical case is home-color-scheme-service-type, which
can affect any other application. Every instantiated service supporting
color-schemes can "take" values from home-color-scheme. Obviously we
can't just extend all service-types for apps supporting color-schemes.
* Possible solutions
** Straightforward idea
The easy solution is to make home-direnv-service-type extend all
possible shell's service types, problem here is already
mentioned. Services for ALL shells will be automatically instantiated by
instantiate-missing-services, which is not desired if I use only bash.
Also, it necessary to know all the services to extend upfront (which
probably we need to know anyway, because they extends differently, but
maybe not the case in some other situations).
** Manual intermediate service
Create and manually manage home-direnv-extends-bash-service,
home-direnv-extends-zsh-service, ... services.
#+begin_src scheme
(define home-direnv-extends-bash-service
(simple-service
'direnv-for-bash home-bash-service-type
update-bashrc-for-direnv))
#+end_src
Now you define:
#+begin_src scheme
((service home-bash-service-type)
home-direnv-extends-bash-service
(service home-direnv-service-type))
#+end_src
But you need to control manually if home-bash-service is removed
to also remove home-direnv-extends-bash-service.
** Runtime extension
To create home-direnv-configuration field, which accepts a list of
shell service types to extend. A little more manual, but what really
important - very impossible without major modification of service
extension mechanism. All extensions are defined "compile/declare-time"
and can't be modified during runtime.
** Home services service
If home-services-service-type existed it would be possible to provide
a list of service to it instantiate and this list can be generated
runtime based on configuration fields. It's almost what we wanted in
previous section, but home-services-service-type itself is impossible
with current implementation of instantiate-missing-services function.
It's kinda cool to have ability to decide which services to extend
based on service configuration's values, but also a little dangerous
and complicated, because it creates indirect extension (service
conditionally declares a service, which extends another service).
Overall, it is a good feature, will work for system services as well.
** Extension point by Julien Lepiller
Another interesting approach is implemented in guix-home-manager.
https://lists.gnu.org/archive/html/guix-devel/2019-09/msg00185.html
Instead of extending the services itself we can extend extension-point
and services, which implements this extension-point will get necessary
data if it provided. Nothing will be instantiated automatically.
On one side services, which "read" from extension-point on the other
services, which "write" data to it.
Very elegant solution, solves use case with color-scheme, but requires
to implement extension-point's upfront. AFAIK, it's not possible to
extend the service, which doesn't implement an extension-point,
whithout instantiating it. It means that it still impossible to extend
only instantiated services.
Partially can be workarounded with proxy-service: For example
home-emacs doesn't implement color-scheme extension-point, we can make
home-emacs-color-scheme services, which implements color-scheme
extension point and extends home-emacs. Now we have to manually
control pressense of both home-emacs and home-emacs-color-scheme
services, which is not critical, but a still little annoying.
NOTE: The current implementation won't be upstreamed, because it's not
backward compatible with guix system services, but with some work it
probably can be.
** Finalize by Ludovic Courtès
https://issues.guix.gnu.org/issue/27155
Adds optional finalize function to service-type-extension. Finalize in
addition to value of extending service takes the final value of a
target service. It gives ability to service not only provide some data
to target service, but also inspect it's value.
* Summary
The ultimate solution can be a combination of Ludo's finalize + Home
services service (which is basically the same as Runtime extensions,
but implemented as a separate service and thus providing a very
important capability to inspect list of services during extension
phase for #3). It will allow to:
1. inspect value of the target service;
2. make conditional extensions;
3. control instantiation of target service;
4. keep backward compatibility.
Such approach will allow to implement very flexible configuration
schemas, similar to polymorphic capabilities of extension-points, as
well as many other, still providing original extension mechanism without
breaking changes. Maybe will describe some useful emerging
patterns/usage scenarios later.
For nearest future I'll be using Manual intermidiate service and will
come back to the topic once symlink-manager finished
(activation+cleanup) and maybe some other important features of `guix
home`. Stay tuned.
--
Best regards,
Andrew Tropin
Very interesting write-up! I wasn't aware Julien's extension point
implementation nor the patch Ludovic proposed, I will have to read up on
the threads.
On Sun, Mar 07 2021, Andrew Tropin wrote:
> For nearest future I'll be using Manual intermidiate service and will
> come back to the topic once symlink-manager finished
> (activation+cleanup) and maybe some other important features of `guix
> home`. Stay tuned.
I agree that we should first finish the symlink-manager before thinking
too much about the service extension mechanism.
Thanks for the write-up!