* 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!