unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A friendlier API for operating-system declarations
@ 2023-03-23  8:06 Edouard Klein
  2023-03-23 18:48 ` Josselin Poiret
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Edouard Klein @ 2023-03-23  8:06 UTC (permalink / raw)
  To: guix-devel

Dear Guixers,

For my clients and my own use, I use a layer on top of operating-system
declarations in which I create functions that take an os as a first
argument, and return an os.

With the help of the handy -> macro, I can chain them, thus allowing an
easy stacking of multiple "roles" or "functionalities" on the same
machine, and an easy transfer of said functionality to another machine:
just cut and paste one line from one declaration to the other.

I have written a tutorial for my clients here:

https://guix-hosting.com/docs/tuto/getting-started.html

that gives an example of what an os configuration may look like:
#+begin_src scheme
(->
 (minimal-ovh "ssh-rsa AAASomethingSomething== root@minimal-ovh")
 (http-static-content "sub2.example.com" #:to-dir "/srv/sub2")
 (http-static-content "sub1.example.com" #:to-dir "/srv/sub1/")
 (add-services my-db))
#+end_src

The code of the function is on my channel:
https://gitlab.com/edouardklein/guix/-/blob/beaverlabs/beaver/system.scm

After a few months of experience, and positive feedback from my clients,
my question to you guys is: would you be interested in mainlining this,
or should I keep my development efforts separate in my channel ?

I do think this API is easier than manipulating services, and although
extendable services are awesome and a very nifty piece of engineering,
they require quite a good knowledge of scheme and take a while to be
used to, while this new API, while way less powerful, lowers the barrier
to entry for newcomers.

They are an easy way to maintain a declarative whole operating system
configuration, with a syntax similar enough to docker and ansible that
sysadmins familiar with it can quickly get up and running, thus exposing
more people to Guix.

What do you think ?

Cheers,

Edouard.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2023-03-23  8:06 Edouard Klein
@ 2023-03-23 18:48 ` Josselin Poiret
  2023-03-23 20:23   ` Edouard Klein
  2023-03-23 21:05 ` Liliana Marie Prikler
  2023-04-13  9:42 ` Ludovic Courtès
  2 siblings, 1 reply; 16+ messages in thread
From: Josselin Poiret @ 2023-03-23 18:48 UTC (permalink / raw)
  To: Edouard Klein, guix-devel

[-- Attachment #1: Type: text/plain, Size: 1742 bytes --]

Hi Edouard,

Edouard Klein <edk@beaver-labs.com> writes:

> #+begin_src scheme
> (->
>  (minimal-ovh "ssh-rsa AAASomethingSomething== root@minimal-ovh")
>  (http-static-content "sub2.example.com" #:to-dir "/srv/sub2")
>  (http-static-content "sub1.example.com" #:to-dir "/srv/sub1/")
>  (add-services my-db))
> #+end_src
>
> The code of the function is on my channel:
> https://gitlab.com/edouardklein/guix/-/blob/beaverlabs/beaver/system.scm
>
> After a few months of experience, and positive feedback from my clients,
> my question to you guys is: would you be interested in mainlining this,
> or should I keep my development efforts separate in my channel ?

I am quite in favor of using operating-system transformations rather
than inheritance, because they're composable!  This could be leveraged
to get a nice CLI API as well.

> I do think this API is easier than manipulating services, and although
> extendable services are awesome and a very nifty piece of engineering,
> they require quite a good knowledge of scheme and take a while to be
> used to, while this new API, while way less powerful, lowers the barrier
> to entry for newcomers.

By this, do you mean that there's no way with your syntax to modify a
given service?  Is there a reason for this?  It does seem to me that it
could probably be done.

> They are an easy way to maintain a declarative whole operating system
> configuration, with a syntax similar enough to docker and ansible that
> sysadmins familiar with it can quickly get up and running, thus exposing
> more people to Guix.
>
> What do you think ?

You've got me interested :) especially since you already have customer
feedback!

Best,
-- 
Josselin Poiret

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 682 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2023-03-23 18:48 ` Josselin Poiret
@ 2023-03-23 20:23   ` Edouard Klein
  0 siblings, 0 replies; 16+ messages in thread
From: Edouard Klein @ 2023-03-23 20:23 UTC (permalink / raw)
  To: Josselin Poiret; +Cc: guix-devel

Hi Josselin,

Josselin Poiret <dev@jpoiret.xyz> writes:

> [[PGP Signed Part:Undecided]]
> Hi Edouard,
>
> Edouard Klein <edk@beaver-labs.com> writes:
>
>> #+begin_src scheme
>> (->
>>  (minimal-ovh "ssh-rsa AAASomethingSomething== root@minimal-ovh")
>>  (http-static-content "sub2.example.com" #:to-dir "/srv/sub2")
>>  (http-static-content "sub1.example.com" #:to-dir "/srv/sub1/")
>>  (add-services my-db))
>> #+end_src
>>
>> The code of the function is on my channel:
>> https://gitlab.com/edouardklein/guix/-/blob/beaverlabs/beaver/system.scm
>>
>> After a few months of experience, and positive feedback from my clients,
>> my question to you guys is: would you be interested in mainlining this,
>> or should I keep my development efforts separate in my channel ?
>
> I am quite in favor of using operating-system transformations rather
> than inheritance, because they're composable!  This could be leveraged
> to get a nice CLI API as well.
>

I hadn't thought of that but now that you mention it, starting a basic
web server or database, isolated in a container, directly from the
command line may come in handy sometimes. This is a good idea ! I'll
think about how to achieve this :)

In the meantime something like:

#+begin_src bash
guix system container -e "(begin (use-modules (beaver system))
(http-static-content minimal-container))" --share=somedir=/var/www
#+end_src

Will spin up such a server. Kind of like python3 -m http.server, but
without the security flaws (you get a full blown nginx), and isolated in
a way that even if your process gets owned, it's only an unpriviledged
user in a container.


>> I do think this API is easier than manipulating services, and although
>> extendable services are awesome and a very nifty piece of engineering,
>> they require quite a good knowledge of scheme and take a while to be
>> used to, while this new API, while way less powerful, lowers the barrier
>> to entry for newcomers.
>
> By this, do you mean that there's no way with your syntax to modify a
> given service?  Is there a reason for this?  It does seem to me that it
> could probably be done.
>

I'm not sure I understand your question.

What I meant is that my proposal is only syntactic sugar over the
existing system, and not meant to replace it.

The existing system is actually very good and the way you
can define how to collate the instances of a given service type, even if
they are instanciated far away from one another, likely by different
authors is really clever and well made. I'm talking here about things
like how you can easily request that a new user be made for your
service, and account-service-type will collate all the users that need
to exist, and actually get the job done. Basically what fold-services does.

I just want to hide all of this complexity for people who just want to
activate one or more instances of a service coded up by somebody else.

If by modifying a service you mean the parameters like the port ones
listen to, or the directory the data should be put in etc. the functions
just take keyword parameters and pass them to the underlying
*-configuration scheme record. They are quite easy to edit and compose.
Maybe we could even devise a semi-automated way of generating one function
for every *-configuration structure that exists.

See
https://gitlab.com/edouardklein/guix/-/blob/beaverlabs/beaver/system.scm#L236

how http-static-content is basically just a wrapper over nginx-server-configuration.

If you meant editing the service after the function has run, you then
need to inspect the operating-system record and fall back to the
original API, by finding the service in the record and editing its
members, but that seems complex to me. I'm probably misunderstanding
the use case.



>> They are an easy way to maintain a declarative whole operating system
>> configuration, with a syntax similar enough to docker and ansible that
>> sysadmins familiar with it can quickly get up and running, thus exposing
>> more people to Guix.
>>
>> What do you think ?
>
> You've got me interested :) especially since you already have customer
> feedback!
>

Thanks :)



Cheers,

Edouard.
> Best,


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2023-03-23  8:06 Edouard Klein
  2023-03-23 18:48 ` Josselin Poiret
@ 2023-03-23 21:05 ` Liliana Marie Prikler
  2023-04-13  9:42 ` Ludovic Courtès
  2 siblings, 0 replies; 16+ messages in thread
From: Liliana Marie Prikler @ 2023-03-23 21:05 UTC (permalink / raw)
  To: Edouard Klein, guix-devel

Am Donnerstag, dem 23.03.2023 um 09:06 +0100 schrieb Edouard Klein:
> After a few months of experience, and positive feedback from my
> clients, my question to you guys is: would you be interested in
> mainlining this, or should I keep my development efforts separate in
> my channel ?
Having just dropped a series of "old-style" service procedures, I don't
think that maintaining a separate API on the mainline is a good idea.

> I do think this API is easier than manipulating services, and
> although extendable services are awesome and a very nifty piece of
> engineering, they require quite a good knowledge of scheme and take a
> while to be used to, while this new API, while way less powerful,
> lowers the barrier to entry for newcomers.
I see how this style (and a similar one that has already been shown for
guix home) can improve configuration file clarity and that's a good
thing.  On the other hand, it looks like you currently have to manually
craft a lot of the procedures that go into the -> syntax and that's...
well, not so good.

If we could enable this style easier – say if we made it so that
define-configuration and service-type also emitted ready-to-use
constructors to use with a keyword style at little extra cost other
than compilation time, I think that'd be a net positive for everyone
involved.

Cheers


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2023-03-23  8:06 Edouard Klein
  2023-03-23 18:48 ` Josselin Poiret
  2023-03-23 21:05 ` Liliana Marie Prikler
@ 2023-04-13  9:42 ` Ludovic Courtès
  2023-05-18 14:37   ` Edouard Klein
  2 siblings, 1 reply; 16+ messages in thread
From: Ludovic Courtès @ 2023-04-13  9:42 UTC (permalink / raw)
  To: Edouard Klein; +Cc: guix-devel

Hi Edouard,

Edouard Klein <edk@beaver-labs.com> skribis:

> For my clients and my own use, I use a layer on top of operating-system
> declarations in which I create functions that take an os as a first
> argument, and return an os.
>
> With the help of the handy -> macro, I can chain them, thus allowing an
> easy stacking of multiple "roles" or "functionalities" on the same
> machine, and an easy transfer of said functionality to another machine:
> just cut and paste one line from one declaration to the other.
>
> I have written a tutorial for my clients here:
>
> https://guix-hosting.com/docs/tuto/getting-started.html

Very nice!

> After a few months of experience, and positive feedback from my clients,
> my question to you guys is: would you be interested in mainlining this,
> or should I keep my development efforts separate in my channel ?

I think it’s worth considering, taking into account maintenance
considerations as Liliana wrote.

> I do think this API is easier than manipulating services, and although
> extendable services are awesome and a very nifty piece of engineering,
> they require quite a good knowledge of scheme and take a while to be
> used to, while this new API, while way less powerful, lowers the barrier
> to entry for newcomers.

Normally, adding a service amounts to adding a line in the ‘services’
field:

  (operating-system
    ;; …
    (services (append (list (service nginx-service-type) …)
                      %base-services)))

It is more verbose that what you have, but it’s still roughly one line
(or one entry) per service.

Another interesting bit in your channel are templates though: an OS
template for hosting at OVH, etc.  These are very valuable because they
take care of all the boilerplate.

Thanks for sharing!

Ludo’.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2023-04-13  9:42 ` Ludovic Courtès
@ 2023-05-18 14:37   ` Edouard Klein
  0 siblings, 0 replies; 16+ messages in thread
From: Edouard Klein @ 2023-05-18 14:37 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel

Hi !
Ludovic Courtès <ludo@gnu.org> writes:

> Hi Edouard,
>
> Edouard Klein <edk@beaver-labs.com> skribis:
>
>> For my clients and my own use, I use a layer on top of operating-system
>> declarations in which I create functions that take an os as a first
>> argument, and return an os.
>>
>> With the help of the handy -> macro, I can chain them, thus allowing an
>> easy stacking of multiple "roles" or "functionalities" on the same
>> machine, and an easy transfer of said functionality to another machine:
>> just cut and paste one line from one declaration to the other.
>>
>> I have written a tutorial for my clients here:
>>
>> https://guix-hosting.com/docs/tuto/getting-started.html
>
> Very nice!
>

:)

>> After a few months of experience, and positive feedback from my clients,
>> my question to you guys is: would you be interested in mainlining this,
>> or should I keep my development efforts separate in my channel ?
>
> I think it’s worth considering, taking into account maintenance
> considerations as Liliana wrote.
>

Indeed. This was started as a quick and dirty overlay over guix to make
it easier for people used to Ansible to deal with declarative OS
configuration with guix, but it now need to be easy to maintain.

>> I do think this API is easier than manipulating services, and although
>> extendable services are awesome and a very nifty piece of engineering,
>> they require quite a good knowledge of scheme and take a while to be
>> used to, while this new API, while way less powerful, lowers the barrier
>> to entry for newcomers.
>
> Normally, adding a service amounts to adding a line in the ‘services’
> field:
>
>   (operating-system
>     ;; …
>     (services (append (list (service nginx-service-type) …)
>                       %base-services)))
>
> It is more verbose that what you have, but it’s still roughly one line
> (or one entry) per service.
>

You wouldn't believe the irrational fear of nested parentheses some
people have ;-)

I do agree a purely functional interface to OS declaration wouldn't
bring much over the existing one. My goal is to then compose those
primitive functions into usually-used-together bundles, such as e.g.
nginx+gunicorn+flask in a function called, maybe, 'python-webapp'.

This is kind of subjective, though. I have my own usage and some
customer feedback to guide me, but we can keep it on my channel until we
feel confident that the additional value is worth the maintenance cost.


> Another interesting bit in your channel are templates though: an OS
> template for hosting at OVH, etc.  These are very valuable because they
> take care of all the boilerplate.
>

I'd be happy to mainline it. I'll submit a patch when I get back home.


> Thanks for sharing!
>

Well thanks to you for starting the whole schmilblick.

> Ludo’.

Edouard.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
@ 2023-05-19  3:31 antlers
  0 siblings, 0 replies; 16+ messages in thread
From: antlers @ 2023-05-19  3:31 UTC (permalink / raw)
  To: guix-devel, dev, edk, liliana.prikler

[-- Attachment #1: Type: text/plain, Size: 2540 bytes --]

Anecdotally, my personal configurations are built out of composable
operating-system transformers that add packages, services, etc. through
trees of inherited records.

That's fairly straightforward for eg. adding packages, but becomes more
complicated when you consider modifying service configurations (which you
might want to inherit from when present and create when absent), nested
service configurations (inheriting multiple times, the whole away down), or
modifying kernel-arguments (where you might want to strip values for the
option that you're setting from existing strings).

I feel that operating-system record fields should be `extendable` in the
same way as services, and have always assumed that that's basically what
RDE's `features` are.

It would be great to have structure that eliminates some of the nesting and
boilerplate of an expression like this:
```
;; imagine if this was (imperative-ness aside) as simple as:
;; lambda os: os.services(foo).z.foo += bar

(lambda (os)
  (operating-system
    (inherit os)
    (sevices
      (modify-services
        (operating-system-services os)
        (y-service-type
          config => (y-configuration
                      (inherit config)
                      (z-configuration
                        (z-configuration
                         (inherit (y-configuration-z config)
                         (foo (cons bar
                                    (z-configuration-foo
                                      (y-configuration-z config)))))))))))))

;; And if we want to create the service when it doesn't exist?

(lambda (os)
  (operating-system
    (inherit os)
    (sevices
      (if (find (lambda (s)
                  (eq (service-kind s) y))
                (operating-system-services os))
          (modify-services
            (operating-system-services os)
            (y-service-type
              config => (y-configuration
                          (inherit config)
                          (z-configuration
                            (z-configuration
                             (inherit (y-configuration-z config)
                             (foo (cons bar
                                        (z-configuration-foo
                                          (y-configuration-z
config))))))))))
          (cons (service y-service-type
                  (y-configuration
                    (z-configuration
                      (z-configuration
                        (foo (list bar))))))
                (operating-system-services os))))))
```

[-- Attachment #2: Type: text/html, Size: 3256 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
@ 2024-02-19 22:25 antlers
       [not found] ` <87plwrj3w9.fsf@rdklein.fr>
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: antlers @ 2024-02-19 22:25 UTC (permalink / raw)
  To: edk; +Cc: guix-devel

Hi!

Just wanted to say that I really admire your take on end-user service configuration in the Beaver Labs channel.

I gravitated towards composing functions over `operating-systems` myself, though my config is probably only ""notable"" for the moderately-cursed `modify-record` macro that I use to derive/configure/wrap the services[1]:

```
(define (os-with-yubi parent users*)
  (modify-record parent
    (groups -> (cons (user-group (name "plugdev")) <>))
    (users  -> (map (lambda (user)
                      (if (member (user-account-name user)
                                  users*)
                          (modify-record user
                            (supplementary-groups -> (cons "plugdev" <>)))
                          user))
                    <>))
    (services => (append <> (list
      (service pcscd-service-type)
      (simple-service 'u2f-udev-rules udev-service-type
                      (list (specification->package "libu2f-host")))
      (simple-service 'yubi-udev-rules udev-service-type
                      (list (specification->package "yubikey-personalization"))))))))
```

It's like if `modify-services` was generalized over any kind of record, but instead of using pre-defined verbs like `remove`, the `body` component of each `(field-name -> body)` clause is wrapped in an implicit SRFI-26 `cut`-like[2] form to create an anonymous function that's applied to the field's value. It's a super leaky abstraction because I use a different symbol for `->` depending on whether that record-field is a plain value, a thunk, or a `delay`-ed form (and it could be implemented more efficiently), but it greatly reduces the length and indentation level of repeatedly nested, inherited record variations.

```
((compose os-with-yubi
          [...])
   [operative-system])
```

I only wrote a handful of top-level `operating-system transformation` functions, and IIRC I only composed them at that top level; I think the way that you've broken them up into smaller forms and composed them out of each other though deeper, standard-functional composition gives you that same additive benefit over would-be nested forms, with each definition roughly matching up to one my "anonymous" invocations.

What I still dwell on is whether there's a way to further minimize the code-volume of including additional functionality (as was pondered in a prior response, and as `modify-record` does in obsoleting `modify-services`'s verbs), and how best to avoid order-dependencies and expose inherit inter-service-configuration dependencies and conflicts. Tropin's RDE uses an emacs or systemd-esque `provides`/`requires` system which is satisfying, but introduces implicit standardization on the symbols associated with software roles and builds a significant graph of them, which I feel adds to the "bulk" of the (still very elegant) solution and embraces the need to wrap every service and transformation into their cohesive system-- that's part of what's kept me on plain Guix with my bandaid-solutions (in the spirit of learning the standard approach before exploring larger systems built on top of it).

Anyway, I like your take, just fount it today and got to thinking-- thanks for putting it out there~

1: From: https://github.com/AutumnalAntlers/old-guix-config/blob/main/modules/antlers/systems/transformations/yubi.scm
2: Like `cut`, but deeper: see the `<>` symbol nested deep within in the `users` clause of the Yubi example.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
       [not found] ` <87plwrj3w9.fsf@rdklein.fr>
@ 2024-02-20  3:42   ` antlers
  0 siblings, 0 replies; 16+ messages in thread
From: antlers @ 2024-02-20  3:42 UTC (permalink / raw)
  To: Edouard Klein, guix-devel

Oh, thank you! Don't study too closely-- I'm quite the novice myself,
having come upon your work in search of better solutions, and the
drawbacks I described are rather notable; but I appreciate that you
see what I was going for.

(I'd be much happier with it if I could interrogate `(guix record)`
structures for the `plain | thunked | delayed` distinction and hide
that from the user, as that's what really prevents me from
recommending wider use, but understanding of the module eludes me.)

On Mon, Feb 19, 2024, at 5:53 PM, Edouard Klein wrote:
> This is awesome. I need to study your macro to understand how you wrote
> it. I've only written a handful of macro in my life, and came to lisp
> via common lisp, from which I've learned quite a lot apprently bad
> habits, so I'm lost in scheme-land.
>
> I'll study your system, thant _you_ for your reply !
>
> Cheers,
>
> Edouard.
>
>
> antlers <antlers@illucid.net> writes:
>
>> Hi!
>>
>> Just wanted to say that I really admire your take on end-user service configuration in the Beaver Labs channel.
>>
>> I gravitated towards composing functions over `operating-systems` myself, though
>> my config is probably only ""notable"" for the moderately-cursed `modify-record`
>> macro that I use to derive/configure/wrap the services[1]:
>>
>> ```
>> (define (os-with-yubi parent users*)
>>   (modify-record parent
>>     (groups -> (cons (user-group (name "plugdev")) <>))
>>     (users  -> (map (lambda (user)
>>                       (if (member (user-account-name user)
>>                                   users*)
>>                           (modify-record user
>>                             (supplementary-groups -> (cons "plugdev" <>)))
>>                           user))
>>                     <>))
>>     (services => (append <> (list
>>       (service pcscd-service-type)
>>       (simple-service 'u2f-udev-rules udev-service-type
>>                       (list (specification->package "libu2f-host")))
>>       (simple-service 'yubi-udev-rules udev-service-type
>>                       (list (specification->package "yubikey-personalization"))))))))
>> ```
>>
>>
>> It's like if `modify-services` was generalized over any kind of record, but
>> instead of using pre-defined verbs like `remove`, the `body` component of each
>> `(field-name -> body)` clause is wrapped in an implicit SRFI-26 `cut`-like[2]
>> form to create an anonymous function that's applied to the field's value. It's a
>> super leaky abstraction because I use a different symbol for `->` depending on
>> whether that record-field is a plain value, a thunk, or a `delay`-ed form (and
>> it could be implemented more efficiently), but it greatly reduces the length and
>> indentation level of repeatedly nested, inherited record variations.
>>
>> ```
>> ((compose os-with-yubi
>>           [...])
>>    [operative-system])
>> ```
>>
>> I only wrote a handful of top-level `operating-system transformation` functions,
>> and IIRC I only composed them at that top level; I think the way that you've
>> broken them up into smaller forms and composed them out of each other though
>> deeper, standard-functional composition gives you that same additive benefit
>> over would-be nested forms, with each definition roughly matching up to one my
>> "anonymous" invocations.
>>
>> What I still dwell on is whether there's a way to further minimize the
>> code-volume of including additional functionality (as was pondered in a prior
>> response, and as `modify-record` does in obsoleting `modify-services`'s verbs),
>> and how best to avoid order-dependencies and expose inherit
>> inter-service-configuration dependencies and conflicts. Tropin's RDE uses an
>> emacs or systemd-esque `provides`/`requires` system which is satisfying, but
>> introduces implicit standardization on the symbols associated with software
>> roles and builds a significant graph of them, which I feel adds to the "bulk" of
>> the (still very elegant) solution and embraces the need to wrap every service
>> and transformation into their cohesive system-- that's part of what's kept me on
>> plain Guix with my bandaid-solutions (in the spirit of learning the standard
>> approach before exploring larger systems built on top of it).
>>
>> Anyway, I like your take, just fount it today and got to thinking-- thanks for putting it out there~
>>
>> 1: From: https://github.com/AutumnalAntlers/old-guix-config/blob/main/modules/antlers/systems/transformations/yubi.scm
>> 2: Like `cut`, but deeper: see the `<>` symbol nested deep within in the `users` clause of the Yubi example.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-19 22:25 A friendlier API for operating-system declarations antlers
       [not found] ` <87plwrj3w9.fsf@rdklein.fr>
@ 2024-02-25  9:26 ` Liliana Marie Prikler
  2024-02-25 18:49   ` antlers
  2024-03-01 16:44 ` Hartmut Goebel
  2 siblings, 1 reply; 16+ messages in thread
From: Liliana Marie Prikler @ 2024-02-25  9:26 UTC (permalink / raw)
  To: antlers, edk; +Cc: guix-devel

Am Montag, dem 19.02.2024 um 14:25 -0800 schrieb antlers:
> ```
> (define (os-with-yubi parent users*)
>   (modify-record parent
>     (groups -> (cons (user-group (name "plugdev")) <>))
>     (users  -> (map (lambda (user)
>                       (if (member (user-account-name user)
>                                   users*)
>                           (modify-record user
>                             (supplementary-groups -> (cons "plugdev"
> <>)))
>                           user))
>                     <>))
>     (services => (append <> (list
>       (service pcscd-service-type)
>       (simple-service 'u2f-udev-rules udev-service-type
>                       (list (specification->package "libu2f-host")))
>       (simple-service 'yubi-udev-rules udev-service-type
>                       (list (specification->package "yubikey-
> personalization"))))))))
> ```
That looks like a nice syntax indeed.  Is the code behind it small
enough to include it in (guix records)?  If so, would you care to
submit it via the usual contribution channels?

Cheers

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-25  9:26 ` Liliana Marie Prikler
@ 2024-02-25 18:49   ` antlers
  2024-02-25 20:47     ` antlers
  2024-02-25 20:50     ` Liliana Marie Prikler
  0 siblings, 2 replies; 16+ messages in thread
From: antlers @ 2024-02-25 18:49 UTC (permalink / raw)
  To: Liliana Marie Prikler, guix-devel

> That looks like a nice syntax indeed. Is the code behind it small
> enough to include it in (guix records)?

Small enough? Yes (<100 LOC, inc. a handful of comments and tests).
Suitable? No, I introduced it as "moderately-cursed" for a reason >u<
But I appreciate the sentiment c:



1.) It leaks `(guix records)`'s thunked/delayed field abstraction to
the end-user, which will confuse and regularly bite absolutely anyone
who tries to use it.

2.) Ideally we'd check that modified fields exist at compile-time.
This could require users to provide the record-type, which is not
always public, but could also be optional.

3) The `cut`-like transformation is recursive and, while it has
well-defined and tested behavior, the semantics are non-standard. I
don't believe that the syntax achieves its goals without this
mechanism, but there are remaining sub-concerns to address before I'd
consider it ready to formalize and document.

4) The syntax expands modifications of multiple fields into recursive
expansions (ie: calls to the record constructor) when it would be more
efficient (especially for thunked/delayed fields) to accumulate
transformations by target field and `compose' them over a single call
to the record constructor. This hasn't been an issue in practice, but
would be the "right thing to do".



#3 and #4 are a light refactoring and feedback-round away (#3 could be
 controversial), but #1 and #2 require deeper understanding and
 (especially for #1) modification of `(guix records)' than I'm
 comfortable with at the moment.

If I do raise the possibility of up-streaming it would be with these
issues addressed, and would still have substantial cause to warrant
discretionary discussion then. Really a scratching-my-own-itch solution
atm.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-25 18:49   ` antlers
@ 2024-02-25 20:47     ` antlers
  2024-02-25 20:50     ` Liliana Marie Prikler
  1 sibling, 0 replies; 16+ messages in thread
From: antlers @ 2024-02-25 20:47 UTC (permalink / raw)
  To: Liliana Marie Prikler, guix-devel

> I don't believe that the syntax achieves its goals without this
> mechanism

I just realized my example doesn't actually include a use of recursive
cut after all (whoops), and finding only 2 uses in my code-base, am open to
considering SRFI-26 sufficient. This helps somewhat, but was not the blocking
issue.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-25 18:49   ` antlers
  2024-02-25 20:47     ` antlers
@ 2024-02-25 20:50     ` Liliana Marie Prikler
  2024-02-25 21:27       ` antlers
  1 sibling, 1 reply; 16+ messages in thread
From: Liliana Marie Prikler @ 2024-02-25 20:50 UTC (permalink / raw)
  To: antlers, guix-devel

Am Sonntag, dem 25.02.2024 um 10:49 -0800 schrieb antlers:
> 
> 1.) It leaks `(guix records)`'s thunked/delayed field abstraction to
> the end-user, which will confuse and regularly bite absolutely anyone
> who tries to use it.
> 
> 2.) Ideally we'd check that modified fields exist at compile-time.
> This could require users to provide the record-type, which is not
> always public, but could also be optional.
You can get the record type of a record at run-time, so at least you
can synthesize a check that gives you a helpful message if that's what
you're gunning for.

> 3) The `cut`-like transformation is recursive and, while it has
> well-defined and tested behavior, the semantics are non-standard. I
> don't believe that the syntax achieves its goals without this
> mechanism, but there are remaining sub-concerns to address before I'd
> consider it ready to formalize and document.
Perhaps we can make it like modify-services where we take a value
updater instead of evaluating the forms directly?  This would fix both
#3 and #1 (since we'd unwrap the thunked/delayed field silently).
That would also make it so that we can use a single set of arrows (=>)
for both.

> 4) The syntax expands modifications of multiple fields into recursive
> expansions (ie: calls to the record constructor) when it would be
> more efficient (especially for thunked/delayed fields) to accumulate
> transformations by target field and `compose' them over a single call
> to the record constructor. This hasn't been an issue in practice, but
> would be the "right thing to do".
That's a minor detail, but it might be a syntax-rules → syntax-case
change.

> If I do raise the possibility of up-streaming it would be with these
> issues addressed, and would still have substantial cause to warrant
> discretionary discussion then. Really a scratching-my-own-itch
> solution atm.
Of course it'd go through the proper review channels first, but from
personal experience talk over at guix-devel is less likely to cause the
change you want over submitting an actual patch :)

Cheers


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-25 20:50     ` Liliana Marie Prikler
@ 2024-02-25 21:27       ` antlers
  2024-02-26 19:58         ` Liliana Marie Prikler
  0 siblings, 1 reply; 16+ messages in thread
From: antlers @ 2024-02-25 21:27 UTC (permalink / raw)
  To: Liliana Marie Prikler, guix-devel

Thanks for the detailed response c:

The blocker is that AFAIK we can't tell if a record-field was defined as
thunk-ed or delay-ed outside of the expansion of the `define-record-type*'
form that defines it, nor programatically access it's getter/setter (the pair
`(guix records)` defines, which accounts for eg. thunk-ing, and is distinct from the
underlying pair returned by eg. `record-accessor').


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-25 21:27       ` antlers
@ 2024-02-26 19:58         ` Liliana Marie Prikler
  0 siblings, 0 replies; 16+ messages in thread
From: Liliana Marie Prikler @ 2024-02-26 19:58 UTC (permalink / raw)
  To: antlers, guix-devel

Am Sonntag, dem 25.02.2024 um 13:27 -0800 schrieb antlers:
> Thanks for the detailed response c:
> 
> The blocker is that AFAIK we can't tell if a record-field was defined
> as thunk-ed or delay-ed outside of the expansion of the
> `define-record-type*' form that defines it, nor programatically
> access it's getter/setter (the pair `(guix records)` defines, which
> accounts for eg. thunk-ing, and is distinct from the underlying pair
> returned by eg. `record-accessor').
You might want to have a look at match-record or even define your
modify-record in terms of it.  IIUC it ought to handle exactly the
problem you're talking about while also making it slightly easier for
you to structure your updating code.

Cheers


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: A friendlier API for operating-system declarations
  2024-02-19 22:25 A friendlier API for operating-system declarations antlers
       [not found] ` <87plwrj3w9.fsf@rdklein.fr>
  2024-02-25  9:26 ` Liliana Marie Prikler
@ 2024-03-01 16:44 ` Hartmut Goebel
  2 siblings, 0 replies; 16+ messages in thread
From: Hartmut Goebel @ 2024-03-01 16:44 UTC (permalink / raw)
  To: antlers, edk; +Cc: guix-devel

Hi,

Am 19.02.24 um 23:25 schrieb antlers:
> (define (os-with-yubi parent users*)
>    (modify-record parent
>      (groups -> (cons (user-group (name "plugdev")) <>))
>      (users  -> (map (lambda (user)
>                        (if (member (user-account-name user)
>                                    users*)
>                            (modify-record user
>                              (supplementary-groups -> (cons "plugdev" <>)))
>                            user))
>                      <>))
>      (services => (append <> (list
>        (service pcscd-service-type)
>        (simple-service 'u2f-udev-rules udev-service-type
>                        (list (specification->package "libu2f-host")))
>        (simple-service 'yubi-udev-rules udev-service-type
>                        (list (specification->package "yubikey-personalization"))))))))

I'd appreciate such a mechanism, as it fits my mental model of how to 
compose a system out of reusable components (much like "roles" in 
Ansible resp. Debop).

-- 
Regards
Hartmut Goebel

| Hartmut Goebel          | h.goebel@crazy-compilers.com               |
| www.crazy-compilers.com | compilers which you thought are impossible |



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2024-03-01 16:44 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-19 22:25 A friendlier API for operating-system declarations antlers
     [not found] ` <87plwrj3w9.fsf@rdklein.fr>
2024-02-20  3:42   ` antlers
2024-02-25  9:26 ` Liliana Marie Prikler
2024-02-25 18:49   ` antlers
2024-02-25 20:47     ` antlers
2024-02-25 20:50     ` Liliana Marie Prikler
2024-02-25 21:27       ` antlers
2024-02-26 19:58         ` Liliana Marie Prikler
2024-03-01 16:44 ` Hartmut Goebel
  -- strict thread matches above, loose matches on Subject: below --
2023-05-19  3:31 antlers
2023-03-23  8:06 Edouard Klein
2023-03-23 18:48 ` Josselin Poiret
2023-03-23 20:23   ` Edouard Klein
2023-03-23 21:05 ` Liliana Marie Prikler
2023-04-13  9:42 ` Ludovic Courtès
2023-05-18 14:37   ` Edouard Klein

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).