guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: XWayland, /tmp/.X11-unix


From: Chris Marusich
Subject: Re: XWayland, /tmp/.X11-unix
Date: Thu, 29 Mar 2018 08:18:25 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.3 (gnu/linux)

Thorsten Wilms <address@hidden> writes:

> On 22.03.2018 00:00, Ricardo Wurmus wrote:
>>
>> Thorsten Wilms <address@hidden> writes:
>>
>>> Initially I thought creation of /tmp/.X11-unix should be tied to the
>>> xorg-server-xwayland package, but since it is more generic: which
>>> component should create that dir on Guix SD (based on what)?
>>
>> It is needed at run-time (because packages cannot create files outside
>> of their store prefix at build time), so it should be created by a
>> system service.  A service is not the same as a shepherd service; we
>> also have activation services that run once and only create a file or a
>> directory.
>
> After 2 to 3 hours of research, going through documentation and
> various .scm, I still don't even manage to write a service for my
> system configuration that just does a (mkdir-p "/tmp/.X11-uni"), so
> figuring out how to make that dependent on the actual need is way
> outside my capabilities.

Take heart: it is not easy for me, either.  :-)

> Should I file a bug, and if so, against what?

If this is a problem that is preventing you from building something new,
then discussing it here is probably the right approach.  If it's
affecting an existing package or service in Guix, then you might want to
create a bug for it by emailing address@hidden

By the way, to create a "service" that does what you need, you might
find it useful to look at an existing example service.  For example, the
procedure nscd-activation in gnu/services/base.scm does something
similar.  So does the procedure exim-activation in
gnu/services/mail.scm.

The manual does explain what is going on (see: (guix) Service
Reference), but I have read it multiple times and examined the source
multiple times, and I still have trouble remembering exactly how it all
fits together.

I'll try to explain how I understand it.  In Guix, a service is a
<service> object; sometimes this is also referred to as a service
"instance".  A <service> object contains two other objects: a "type" and
a "value".  The "type" is a <service-type> object and is sometimes
referred to as the service "kind" (because it represents what kind of
service it is).  The "value" is whatever that particular service type
requires, and sometimes it is also referred to as a service's
"parameter", "parameters", or "parameter value".  Usually the value is a
configuration object of some kind.  For example, the Guix service
expects its value to be a <guix-configuration> object.

By the way, these objects with angle brackets, like <service>, are
defined using the define-record-type* syntax (which itself is defined in
guix/records.scm).  They are similar to normal Scheme records (see:
(guile) Record Overview), if you're familiar with those.

Guix has an "activation service".  Its purpose, as described in the
manual (see: (guix) Service Types and Services), is to run a code
snippet "at activation time - e.g., when the service is booted".  The
basic contract for extending the "activation service" is that if you
define an extension of the activation service which specifies a
"compute" procedure foo, where foo is a procedure that returns a
G-Expression that takes some action (e.g., create the "/tmp/.X11-uni"
directory), then that action will be taken at activation time.  The
"foo" procedure will receive a single argument as input: the argument
will be the value of the service (your service!) that is extending the
activation service.

Confused?  I know I was when I first looked into this.  But stay with me
- together we can make it through!  The mechanism that implements the
extension logic can be found in the fold-services procedure in
gnu/services.scm.  Specifically, when a service like the Guix service
extends an extensible service like the activation service, we have the
following situation:

* A guix-service-type is defined (in gnu/services/base.scm).  It
  contains a <service-extension> for which the "target" is the
  activation-service-type and the "compute" is the guix-activation
  procedure.

* We add an instance of the Guix service to the %base-services list by
  calling the guix-service procedure.  This procedure creates an
  instance of the service and uses %default-guix-configuration as its
  value (which is a <guix-configuration> object).

* The activation-service-type is defined (in gnu/services.scm).  Its
  "compose" is the append procedure (see: (guile) Append/Reverse), and
  its "extend" is the second-argument procedure.

* We add an instance of the activation service to the essential-services
  list.  The activation service's initial value is #t.

When Guix builds all the system services, it will do the following:

* Guix will find a service of the activation-service-type.  This is the
  activation service.

* Guix will find a service of the guix-service-type.  This is the Guix
  service.

* Guix will recognize that the Guix service extends the activation
  service.

* Guix will pass the Guix service's value to the guix-service-type's
  "compute" procedure defined earlier.  This means that Guix will call
  the guix-activation procedure with a single argument: the
  %default-guix-configuration.  The guix-activation procedure returns an
  appropriate G-Expression that takes steps to activate Guix according
  to the provided configuration.

* If there are any other services that extend the
  activation-service-type, Guix will call their "compute" procedures in
  a similar fashion.

* Guix will collect all of the objects returned by the various "compute"
  procedures in a list.  The G-Expression returned by guix-activation
  will be one element of this list.  Guix will pass this list to the
  activation-service-type's "compose" procedure.  This means that it
  will call append with a single argument: the list.  This will actually
  return the same list, since appending a single list returns the same
  list.  (As explained elsewhere on the guix-devel email list, this
  should really be the "identity" procedure, not the "append" procedure,
  since it more accurately reflects the intent [1].)

* Guix will call the activation-service-type's "extend" procedure with
  two arguments: the first argument is the value of the activation
  service found earlier, and the second argument is the result of the
  "compose" procedure from the previous step.  This means that Guix will
  call the second-argument procedure with the value #t as its first
  argument, and the list of G-Expressions from above as its second
  argument.  Because the second-argument procedure simply returns the
  second argument, the value #t will be ignored, and the result will be
  the list of G-Expressions.

* Guix replaces the activation service with a new service instance that
  has the same type but a new value.  The new value is set to the result
  of calling the "extend" procedure.  This means that the activation
  service will be replaced with a new activation service that uses the
  list of G-Expressions from the previous step as its value.

Guix repeats this process recursively for all services defined in your
<operating-system> declaration.  In this way, even though the high-level
contract for how services extend one another is dictated by Guix, the
interpretation of the objects and procedures involved is largely
determined by the service that is being extended.  For example, Guix
promises the activation service that it will collect objects from
services that extend the activation service and then call the activation
service's "compose" and "extend" procedures as described above to create
a new, modified activation service.  However, the structure of those
objects and the behavior of those procedures are largely determined by
the activation-service-type itself.  A different type of service may
very well define a different contract.

To re-iterate what I wrote earlier, the activation-service-type's
contract is as follows: when you define a service that extends it (i.e.,
when you define a <service-type> that extends the
activation-service-type), your service will define a "compute" procedure
that returns a G-Expression that performs some action (e.g., create a
directory).  The activation service will then arrange to run that action
at activation time.  This means that if your service needs a
"/tmp/.X11-uni" directory to exist before it runs, you need to define a
"compute" procedure that accepts a single argument (which will be your
service's value) and returns a G-Expression that creates the directory.
Different extensible services have different expectations, so you would
need to implement different "compute" procedures to extend them.
Thankfully, even if an extensible service is not clearly documented, you
can usually tell what its contract is by looking at some services that
extend it already.

I hope that helps!

Footnotes: 
[1]  https://lists.gnu.org/archive/html/guix-devel/2018-03/msg00307.html

-- 
Chris

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]