unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#30809] [PATCH] Gitolite service
@ 2018-03-13 21:35 Christopher Baines
  2018-03-13 21:39 ` [bug#30809] [PATCH 1/2] services: Add gitolite Christopher Baines
                   ` (7 more replies)
  0 siblings, 8 replies; 32+ messages in thread
From: Christopher Baines @ 2018-03-13 21:35 UTC (permalink / raw)
  To: 30809

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

Tags: moreinfo

About a month ago, I managed to write a somewhat working Gitolite
service. This still needs a bit of work, as the service needs cleaning
up, and the documentation writing. I also need to actually try using it
for real, rather than just assuming it'll work because of the system
test.

Anyway, I haven't got around to doing any of these things in the
intervening month, so here is a bug to track adding a Gitolite service,
and I'll send the current patches I've got.

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

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

* [bug#30809] [PATCH 1/2] services: Add gitolite.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
@ 2018-03-13 21:39 ` Christopher Baines
  2018-03-13 21:39   ` [bug#30809] [PATCH 2/2] WIP: gitolite package changes to make the service work Christopher Baines
  2018-07-13 19:41 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-03-13 21:39 UTC (permalink / raw)
  To: 30809

---
 gnu/services/version-control.scm | 158 ++++++++++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 103 ++++++++++++++++++++++++-
 2 files changed, 259 insertions(+), 2 deletions(-)

diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index afead87ec..60c3f8b81 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -40,7 +40,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +213,143 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ".*"))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package      gitolite-configuration-package
+                (default gitolite))
+  (user         gitolite-configuration-user
+                (default "git"))
+  (rc-file      gitolite-configuration-rc-file
+                (default (gitolite-rc-file)))
+  (admin-pubkey gitolite-configuration-admin-pubkey
+                (default #f)))
+
+(define (gitolite-accounts config)
+  (let ((user (gitolite-configuration-user config)))
+    ;; User group and account to run Gitolite.
+    (list (user-group (name user) (system? #t))
+          (user-account
+           (name user)
+           (group user)
+           (system? #t)
+           (comment "Gitolite daemon user")
+           (home-directory "/var/lib/gitolite")))))
+
+(define gitolite-setup
+  (match-lambda
+    (($ <gitolite-configuration> package user rc-file admin-pubkey)
+     #~(begin
+         (use-modules (ice-9 match)
+                      (guix build utils))
+         (if (not (file-exists? "/var/lib/gitolite/.gitolite"))
+             (let ((user-info (getpwnam #$user)))
+               (simple-format #t "guix: gitolite: installing ~A\n"
+                              #$rc-file)
+               (symlink #$rc-file "/var/lib/gitolite/.gitolite.rc")
+
+               ;; The key must be writable, so copy it from the store
+               (copy-file #$admin-pubkey "/var/lib/gitolite/id_rsa.pub")
+
+               (chmod "/var/lib/gitolite/id_rsa.pub" #o500)
+               (chown "/var/lib/gitolite/id_rsa.pub"
+                      (passwd:uid user-info)
+                      (passwd:gid user-info))
+
+               ;; Set the git configuration, to avoid gitolite trying to use
+               ;; the hostname command, as the network might not be up yet
+               (with-output-to-file "/var/lib/gitolite/.gitconfig"
+                 (lambda ()
+                   (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+")))
+
+               (match (primitive-fork)
+                 (0
+                  ;; Exit with a non-zero status code if an exception is thrown.
+                  (dynamic-wind
+                    (const #t)
+                    (lambda ()
+                      (setenv "HOME" (passwd:dir user-info))
+                      (setenv "USER" #$user)
+                      (setgid (passwd:gid user-info))
+                      (setuid (passwd:uid user-info))
+                      (primitive-exit
+                       (system* #$(file-append package "/bin/gitolite")
+                                "setup"
+                                "-pk" "/var/lib/gitolite/id_rsa.pub")))
+                    (lambda ()
+                      (primitive-exit 1))))
+                 (pid (waitpid pid)))
+
+               (delete-file "/var/lib/gitolite/id_rsa.pub")))))))
+
+(define (gitolite-activation config)
+  (if (gitolite-configuration-admin-pubkey config)
+      (gitolite-setup config)
+      #~(display
+         "guix: Skipping gitolite setup as the admin-pubkey has not been provided\n")))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)))
+   (default-value (gitolite-configuration))
+   (description
+    "")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 802473973..c6dc0457c 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -27,14 +27,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -306,3 +309,101 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                            '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/id_rsa")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/id_rsa.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-eq "service running"
+            'running!
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon)
+                'running!)
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair "/id_rsa")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          ;; Make sure we can clone the repo from the host.
+          (test-eq "clone"
+            #t
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Connect to a running Git HTTP server.")
+   (value (run-gitolite-test))))
-- 
2.16.2

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

* [bug#30809] [PATCH 2/2] WIP: gitolite package changes to make the service work.
  2018-03-13 21:39 ` [bug#30809] [PATCH 1/2] services: Add gitolite Christopher Baines
@ 2018-03-13 21:39   ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-03-13 21:39 UTC (permalink / raw)
  To: 30809

---
 gnu/packages/version-control.scm | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index a3f4a4dd4..4af41b37e 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -958,9 +958,9 @@ also walk each side of a merge and test those changes individually.")
 
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
-                        (substitute* "src/triggers/post-compile/ssh-authkeys"
-                          (("\\$glshell \\$user")
-                           "gitolite-shell $user"))
+                        ;; (substitute* "src/triggers/post-compile/ssh-authkeys"
+                        ;;   (("\\$glshell \\$user")
+                        ;;    "gitolite-shell $user"))
                         #t)))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
@@ -975,9 +975,36 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
-                        #t))))))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (wrap-program (string-append (assoc-ref outputs "out")
+                                                   "/share/gitolite/gitolite-shell")
+                        `("PATH" ":" prefix
+                          (,(string-append (assoc-ref inputs "git")
+                                           "/bin"))))
+                      (wrap-program (string-append (assoc-ref outputs "out")
+                                                   "/bin/gitolite")
+                        `("PATH" ":" prefix
+                          (,(string-append (assoc-ref outputs "out")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "coreutils")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "findutils")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "openssh")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "git")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "inetutils")
+                                           "/bin")))))))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("git" ,git)
+       ("openssh" ,openssh)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.16.2

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
  2018-03-13 21:39 ` [bug#30809] [PATCH 1/2] services: Add gitolite Christopher Baines
@ 2018-07-13 19:41 ` Christopher Baines
  2018-07-13 19:41   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
  2018-07-13 20:01 ` [bug#30809] Fwd: " Christopher Baines
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-13 19:41 UTC (permalink / raw)
  To: 30809

Previously the gitolite package worked, but there were problems using it for
the service where you might have a minimal PATH. This commit patches the
source and scripts where possible to use store paths, and also wraps the
gitolite script to handle the harder dependencies.

* gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
the patch-scripts phase, and add two new phases (patch-source and
wrap-scripts).
[inputs]: Add coreutils, findutils and inetutils.
---
 gnu/packages/version-control.scm | 53 ++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 2bd59ae95..3bbc586e1 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -1026,12 +1026,42 @@ also walk each side of a merge and test those changes individually.")
                           ((" perl -")
                            (string-append " " perl " -")))
 
+                        (substitute* (find-files "src/triggers" ".*")
+                          ((" sed ")
+                           (string-append " " (which "sed") " ")))
+
+                        (substitute*
+                            '("src/triggers/post-compile/update-gitweb-access-list"
+                              "src/triggers/post-compile/ssh-authkeys-split"
+                              "src/triggers/upstream")
+                          ((" grep ")
+                           (string-append " " (which "grep") " ")))
+
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
                         (substitute* "src/triggers/post-compile/ssh-authkeys"
                           (("\\$glshell \\$user")
                            "gitolite-shell $user"))
                         #t)))
+                  (add-before 'install 'patch-source
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      ;; Gitolite uses cat to test the readability of the
+                      ;; pubkey
+                      (substitute* "src/lib/Gitolite/Setup.pm"
+                        (("\"cat ")
+                         (string-append "\"" (which "cat") " "))
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen"))))
+
+                      (substitute* "src/lib/Gitolite/Common.pm"
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen")))
+                        (("\"logger\"")
+                         (string-append "\""
+                                        (assoc-ref inputs "inetutils")
+                                        "/bin/logger\"")))
+
+                      #t))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
@@ -1045,9 +1075,28 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
-                        #t))))))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (wrap-program (string-append (assoc-ref outputs "out")
+                                                   "/bin/gitolite")
+                        `("PATH" ":" prefix
+                          (,(string-append (assoc-ref outputs "out")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "coreutils")
+                                           "/bin")
+                           ;; find is used in quite a few places
+                           ,(string-append (assoc-ref inputs "findutils")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "git")
+                                           "/bin"))))
+
+                      #t)))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.17.1

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-13 19:41 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-13 19:41   ` Christopher Baines
  2018-07-13 23:15     ` Oleg Pykhalov
  0 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-13 19:41 UTC (permalink / raw)
  To: 30809

* gnu/services/version-control.scm (<gitolite-configuration>,
<gitolite-rc-file>): New record types.
(gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
(gitolite-service-type): New variables.
* gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
%test-gitolite): New variables.
(run-gitolite-test): New procedure.
* doc/guix.texi (Version Control): Document the gitolite service.
---
 doc/guix.texi                    |  91 +++++++++++++++++
 gnu/services/version-control.scm | 169 ++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 103 ++++++++++++++++++-
 3 files changed, 361 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 7ce364b0a..a54dd6800 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -20127,6 +20127,97 @@ could instantiate a cgit service like this:
           (cgitrc "")))
 @end example
 
+@subsubheading Gitolite Service
+
+@cindex Gitolite service
+@cindex Git, hosting
+@uref{http://gitolite.com/gitolite/, Gitolite} is a tool for hosting Git
+repositories on a central server.
+
+Gitolite can handle multiple repositories and users, and supports flexible
+configuration of the permissions for the users on the repositories.
+
+The following example will configure Gitolite using the default @code{git}
+user, and the SSH public key located at @code{~/.ssh/id_rsa.pub}. A public key
+is necessary to setup Gitolite initially, but can be omitted once Gitolite is
+setup.
+
+@example
+(service gitolite-service-type
+         (gitolite-configuration
+           (admin-pubkey (plain-file
+                           "id_rsa.pub"
+                           "ssh-rsa AAAA... guix@@example.com"))))
+@end example
+
+Gitolite is configured through a special admin repository which you can clone,
+for example, if you setup Gitolite on @code{example.com}, you would run the
+following command to clone the admin repository.
+
+@example
+git clone git@@example.com:gitolite-admin
+@end example
+
+@deftp {Data Type} gitolite-configuration
+Data type representing the configuration for @code{gitolite-service-type}.
+
+@table @asis
+@item @code{package} (default: @var{gitolite})
+Gitolite package to use.
+
+@item @code{user} (default: @var{git})
+User to use for Gitolite.  This will be user that you use when accessing
+Gitolite over SSH.
+
+@item @code{rc-file} (default: @var{(gitolite-rc-file)})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
+representing the configuration for Gitolite.
+
+@item @code{admin-pubkey} (default: @var{#f})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
+setup Gitolite.  This can be omitted once Gitolite has successfully been
+setup.
+
+The following G-exp would use the @file{~/.ssh/id_rsa.pub} file.
+
+@example
+(local-file "~/.ssh/id_rsa.pub")
+@end example
+
+To specify the SSH key as a string, use the @code{plain-file} function.
+
+@example
+(plain-file "id_rsa.pub" "ssh-rsa AAAA... guix@@example.com")
+@end example
+
+@end table
+@end deftp
+
+@deftp {Data Type} gitolite-rc-file
+Data type representing the Gitolite RC file.
+
+@table @asis
+@item @code{umask} (default: @code{#o0077})
+This controls the permissions Gitolite sets on the repositories and their
+contents.
+
+A value like @code{#o0027} will give read access to the group used by Gitolite
+(by default: @code{git}). This is necessary when using Gitolite with software
+like cgit or gitweb.
+
+@item @code{git-config-keys} (default: @code{""})
+Gitolite allows you to set git config values using the "config" keyword. This
+setting allows control over the config keys to accept.
+
+@item @code{roles} (default: @code{'(("READERS" . 1) ("WRITERS" . ))})
+Set the role names allowed to be used by users running the perms command.
+
+@item @code{enable} (default: @code{'("help" "desc" "info" "perms" "writable" "ssh-authkeys" "git-config" "daemon" "gitweb")})
+This setting controls the commands and features to enable within Gitolite.
+
+@end table
+@end deftp
+
 
 @node Game Services
 @subsubsection Game Services
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index 58274c8be..1000207ed 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -40,7 +40,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +213,154 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ""))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package      gitolite-configuration-package
+                (default gitolite))
+  (user         gitolite-configuration-user
+                (default "git"))
+  (rc-file      gitolite-configuration-rc-file
+                (default (gitolite-rc-file)))
+  (admin-pubkey gitolite-configuration-admin-pubkey
+                (default #f)))
+
+(define (gitolite-accounts config)
+  (let ((user (gitolite-configuration-user config)))
+    ;; User group and account to run Gitolite.
+    (list (user-group (name user) (system? #t))
+          (user-account
+           (name user)
+           (group user)
+           (system? #t)
+           (comment "Gitolite user")
+           (home-directory "/var/lib/gitolite")))))
+
+(define gitolite-setup
+  (match-lambda
+    (($ <gitolite-configuration> package user rc-file admin-pubkey)
+     #~(begin
+         (use-modules (ice-9 match)
+                      (guix build utils))
+         (if (not (file-exists? "/var/lib/gitolite/.gitolite"))
+             (let ((user-info (getpwnam #$user)))
+               (simple-format #t "guix: gitolite: installing ~A\n"
+                              #$rc-file)
+               (symlink #$rc-file "/var/lib/gitolite/.gitolite.rc")
+
+               ;; The key must be writable, so copy it from the store
+               (copy-file #$admin-pubkey "/var/lib/gitolite/id_rsa.pub")
+
+               (chmod "/var/lib/gitolite/id_rsa.pub" #o500)
+               (chown "/var/lib/gitolite/id_rsa.pub"
+                      (passwd:uid user-info)
+                      (passwd:gid user-info))
+
+               ;; Set the git configuration, to avoid gitolite trying to use
+               ;; the hostname command, as the network might not be up yet
+               (with-output-to-file "/var/lib/gitolite/.gitconfig"
+                 (lambda ()
+                   (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+")))
+
+               (match (primitive-fork)
+                 (0
+                  ;; Exit with a non-zero status code if an exception is thrown.
+                  (dynamic-wind
+                    (const #t)
+                    (lambda ()
+                      (setenv "HOME" (passwd:dir user-info))
+                      (setenv "USER" #$user)
+                      (setgid (passwd:gid user-info))
+                      (setuid (passwd:uid user-info))
+                      (primitive-exit
+                       (system* #$(file-append package "/bin/gitolite")
+                                "setup"
+                                "-pk" "/var/lib/gitolite/id_rsa.pub")))
+                    (lambda ()
+                      (primitive-exit 1))))
+                 (pid (waitpid pid)))
+
+               (delete-file "/var/lib/gitolite/id_rsa.pub")))))))
+
+(define (gitolite-activation config)
+  (if (gitolite-configuration-admin-pubkey config)
+      (gitolite-setup config)
+      #~(display
+         "guix: Skipping gitolite setup as the admin-pubkey has not been provided\n")))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)
+          (service-extension profile-service-type
+                             ;; The Gitolite package in Guix uses
+                             ;; gitolite-shell in the authorized_keys file, so
+                             ;; gitolite-shell needs to be on the PATH for
+                             ;; gitolite to work.
+                             (lambda (config)
+                               (list
+                                (gitolite-configuration-package config))))))
+   (default-value (gitolite-configuration))
+   (description
+    "Setup @command{gitolite}, a Git hosting tool providing access over SSH..
+By default, the @code{git} user is used, but this is configurable.
+Additionally, Gitolite can integrate with with tools like gitweb or cgit to
+provide a web interface to view selected repositories.")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 3b935a1b4..e4cd3fc3f 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -27,14 +27,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -300,3 +303,101 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                            '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/id_rsa")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/id_rsa.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-eq "service running"
+            'running!
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon)
+                'running!)
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair "/id_rsa")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          ;; Make sure we can clone the repo from the host.
+          (test-eq "clone"
+            #t
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Clone the Gitolite admin repository.")
+   (value (run-gitolite-test))))
-- 
2.17.1

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

* [bug#30809] Fwd: [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
  2018-03-13 21:39 ` [bug#30809] [PATCH 1/2] services: Add gitolite Christopher Baines
  2018-07-13 19:41 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-13 20:01 ` Christopher Baines
  2018-07-14  6:28 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-13 20:01 UTC (permalink / raw)
  To: 30809; +Cc: clement, davet

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


Christopher Baines <mail@cbaines.net> writes:

> * gnu/services/version-control.scm (<gitolite-configuration>,
> <gitolite-rc-file>): New record types.
> (gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
> (gitolite-service-type): New variables.
> * gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
> %test-gitolite): New variables.
> (run-gitolite-test): New procedure.
> * doc/guix.texi (Version Control): Document the gitolite service.
> ---
>  doc/guix.texi                    |  91 +++++++++++++++++
>  gnu/services/version-control.scm | 169 ++++++++++++++++++++++++++++++-
>  gnu/tests/version-control.scm    | 103 ++++++++++++++++++-
>  3 files changed, 361 insertions(+), 2 deletions(-)

So, this patch has been sitting around for a while, but I've got around
to writing some docs now, and making the service compatible with the
package, and I think it's ready.

I've CC'ed both David and Clément, as I see you've been involved in
packaging Gitolite before, so maybe this will interest you.

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

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-13 19:41   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
@ 2018-07-13 23:15     ` Oleg Pykhalov
  2018-07-14  6:31       ` Christopher Baines
  0 siblings, 1 reply; 32+ messages in thread
From: Oleg Pykhalov @ 2018-07-13 23:15 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

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

Hello Christopher,

Not a full review, just want to note issue in the documentation and say
thank you.  The gitolite service works for me.

Christopher Baines <mail@cbaines.net> writes:

> * gnu/services/version-control.scm (<gitolite-configuration>,
> <gitolite-rc-file>): New record types.
> (gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
> (gitolite-service-type): New variables.
> * gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
> %test-gitolite): New variables.
> (run-gitolite-test): New procedure.
> * doc/guix.texi (Version Control): Document the gitolite service.
> ---
>  doc/guix.texi                    |  91 +++++++++++++++++
>  gnu/services/version-control.scm | 169 ++++++++++++++++++++++++++++++-
>  gnu/tests/version-control.scm    | 103 ++++++++++++++++++-
>  3 files changed, 361 insertions(+), 2 deletions(-)

[…]

> +The following G-exp would use the @file{~/.ssh/id_rsa.pub} file.
> +
> +@example
> +(local-file "~/.ssh/id_rsa.pub")
> +@end example

‘~/.ssh/id_rsa.pub’ doesn't work for me, because with ‘./pre-inst-env
guix system vm ./test.scm’ it will be expanded to
‘/home/natsu/src/guix/~/.ssh/id_rsa.pub’.

Specifing full path ‘/home/natsu/.ssh/id_rsa.pub’ is required for me.

[…]

Oleg.

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

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
                   ` (2 preceding siblings ...)
  2018-07-13 20:01 ` [bug#30809] Fwd: " Christopher Baines
@ 2018-07-14  6:28 ` Christopher Baines
  2018-07-14  6:28   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
  2018-07-22 22:26   ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Clément Lassieur
  2018-07-23 21:43 ` Christopher Baines
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-14  6:28 UTC (permalink / raw)
  To: 30809

Previously the gitolite package worked, but there were problems using it for
the service where you might have a minimal PATH. This commit patches the
source and scripts where possible to use store paths, and also wraps the
gitolite script to handle the harder dependencies.

* gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
the patch-scripts phase, and add two new phases (patch-source and
wrap-scripts).
[inputs]: Add coreutils, findutils and inetutils.
---
 gnu/packages/version-control.scm | 53 ++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 2bd59ae95..3bbc586e1 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -1026,12 +1026,42 @@ also walk each side of a merge and test those changes individually.")
                           ((" perl -")
                            (string-append " " perl " -")))
 
+                        (substitute* (find-files "src/triggers" ".*")
+                          ((" sed ")
+                           (string-append " " (which "sed") " ")))
+
+                        (substitute*
+                            '("src/triggers/post-compile/update-gitweb-access-list"
+                              "src/triggers/post-compile/ssh-authkeys-split"
+                              "src/triggers/upstream")
+                          ((" grep ")
+                           (string-append " " (which "grep") " ")))
+
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
                         (substitute* "src/triggers/post-compile/ssh-authkeys"
                           (("\\$glshell \\$user")
                            "gitolite-shell $user"))
                         #t)))
+                  (add-before 'install 'patch-source
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      ;; Gitolite uses cat to test the readability of the
+                      ;; pubkey
+                      (substitute* "src/lib/Gitolite/Setup.pm"
+                        (("\"cat ")
+                         (string-append "\"" (which "cat") " "))
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen"))))
+
+                      (substitute* "src/lib/Gitolite/Common.pm"
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen")))
+                        (("\"logger\"")
+                         (string-append "\""
+                                        (assoc-ref inputs "inetutils")
+                                        "/bin/logger\"")))
+
+                      #t))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
@@ -1045,9 +1075,28 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
-                        #t))))))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (wrap-program (string-append (assoc-ref outputs "out")
+                                                   "/bin/gitolite")
+                        `("PATH" ":" prefix
+                          (,(string-append (assoc-ref outputs "out")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "coreutils")
+                                           "/bin")
+                           ;; find is used in quite a few places
+                           ,(string-append (assoc-ref inputs "findutils")
+                                           "/bin")
+                           ,(string-append (assoc-ref inputs "git")
+                                           "/bin"))))
+
+                      #t)))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.17.1

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-14  6:28 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-14  6:28   ` Christopher Baines
  2018-07-22 22:30     ` Clément Lassieur
  2018-07-22 22:26   ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Clément Lassieur
  1 sibling, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-14  6:28 UTC (permalink / raw)
  To: 30809

* gnu/services/version-control.scm (<gitolite-configuration>,
<gitolite-rc-file>): New record types.
(gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
(gitolite-service-type): New variables.
* gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
%test-gitolite): New variables.
(run-gitolite-test): New procedure.
* doc/guix.texi (Version Control): Document the gitolite service.
---
 doc/guix.texi                    |  90 ++++++++++++++++
 gnu/services/version-control.scm | 169 ++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 103 ++++++++++++++++++-
 3 files changed, 360 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 7ce364b0a..b43f43bb9 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -20127,6 +20127,96 @@ could instantiate a cgit service like this:
           (cgitrc "")))
 @end example
 
+@subsubheading Gitolite Service
+
+@cindex Gitolite service
+@cindex Git, hosting
+@uref{http://gitolite.com/gitolite/, Gitolite} is a tool for hosting Git
+repositories on a central server.
+
+Gitolite can handle multiple repositories and users, and supports flexible
+configuration of the permissions for the users on the repositories.
+
+The following example will configure Gitolite using the default @code{git}
+user, and the provided SSH public key. A public key is necessary to setup
+Gitolite initially, but can be omitted once Gitolite is setup.
+
+@example
+(service gitolite-service-type
+         (gitolite-configuration
+           (admin-pubkey (plain-file
+                           "id_rsa.pub"
+                           "ssh-rsa AAAA... guix@@example.com"))))
+@end example
+
+Gitolite is configured through a special admin repository which you can clone,
+for example, if you setup Gitolite on @code{example.com}, you would run the
+following command to clone the admin repository.
+
+@example
+git clone git@@example.com:gitolite-admin
+@end example
+
+@deftp {Data Type} gitolite-configuration
+Data type representing the configuration for @code{gitolite-service-type}.
+
+@table @asis
+@item @code{package} (default: @var{gitolite})
+Gitolite package to use.
+
+@item @code{user} (default: @var{git})
+User to use for Gitolite.  This will be user that you use when accessing
+Gitolite over SSH.
+
+@item @code{rc-file} (default: @var{(gitolite-rc-file)})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
+representing the configuration for Gitolite.
+
+@item @code{admin-pubkey} (default: @var{#f})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
+setup Gitolite.  This can be omitted once Gitolite has successfully been
+setup.
+
+The following G-exp would use the @file{/home/user/.ssh/id_rsa.pub} file.
+
+@example
+(local-file "/home/user/.ssh/id_rsa.pub")
+@end example
+
+To specify the SSH key as a string, use the @code{plain-file} function.
+
+@example
+(plain-file "id_rsa.pub" "ssh-rsa AAAA... guix@@example.com")
+@end example
+
+@end table
+@end deftp
+
+@deftp {Data Type} gitolite-rc-file
+Data type representing the Gitolite RC file.
+
+@table @asis
+@item @code{umask} (default: @code{#o0077})
+This controls the permissions Gitolite sets on the repositories and their
+contents.
+
+A value like @code{#o0027} will give read access to the group used by Gitolite
+(by default: @code{git}). This is necessary when using Gitolite with software
+like cgit or gitweb.
+
+@item @code{git-config-keys} (default: @code{""})
+Gitolite allows you to set git config values using the "config" keyword. This
+setting allows control over the config keys to accept.
+
+@item @code{roles} (default: @code{'(("READERS" . 1) ("WRITERS" . ))})
+Set the role names allowed to be used by users running the perms command.
+
+@item @code{enable} (default: @code{'("help" "desc" "info" "perms" "writable" "ssh-authkeys" "git-config" "daemon" "gitweb")})
+This setting controls the commands and features to enable within Gitolite.
+
+@end table
+@end deftp
+
 
 @node Game Services
 @subsubsection Game Services
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index 58274c8be..1000207ed 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -40,7 +40,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +213,154 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ""))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package      gitolite-configuration-package
+                (default gitolite))
+  (user         gitolite-configuration-user
+                (default "git"))
+  (rc-file      gitolite-configuration-rc-file
+                (default (gitolite-rc-file)))
+  (admin-pubkey gitolite-configuration-admin-pubkey
+                (default #f)))
+
+(define (gitolite-accounts config)
+  (let ((user (gitolite-configuration-user config)))
+    ;; User group and account to run Gitolite.
+    (list (user-group (name user) (system? #t))
+          (user-account
+           (name user)
+           (group user)
+           (system? #t)
+           (comment "Gitolite user")
+           (home-directory "/var/lib/gitolite")))))
+
+(define gitolite-setup
+  (match-lambda
+    (($ <gitolite-configuration> package user rc-file admin-pubkey)
+     #~(begin
+         (use-modules (ice-9 match)
+                      (guix build utils))
+         (if (not (file-exists? "/var/lib/gitolite/.gitolite"))
+             (let ((user-info (getpwnam #$user)))
+               (simple-format #t "guix: gitolite: installing ~A\n"
+                              #$rc-file)
+               (symlink #$rc-file "/var/lib/gitolite/.gitolite.rc")
+
+               ;; The key must be writable, so copy it from the store
+               (copy-file #$admin-pubkey "/var/lib/gitolite/id_rsa.pub")
+
+               (chmod "/var/lib/gitolite/id_rsa.pub" #o500)
+               (chown "/var/lib/gitolite/id_rsa.pub"
+                      (passwd:uid user-info)
+                      (passwd:gid user-info))
+
+               ;; Set the git configuration, to avoid gitolite trying to use
+               ;; the hostname command, as the network might not be up yet
+               (with-output-to-file "/var/lib/gitolite/.gitconfig"
+                 (lambda ()
+                   (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+")))
+
+               (match (primitive-fork)
+                 (0
+                  ;; Exit with a non-zero status code if an exception is thrown.
+                  (dynamic-wind
+                    (const #t)
+                    (lambda ()
+                      (setenv "HOME" (passwd:dir user-info))
+                      (setenv "USER" #$user)
+                      (setgid (passwd:gid user-info))
+                      (setuid (passwd:uid user-info))
+                      (primitive-exit
+                       (system* #$(file-append package "/bin/gitolite")
+                                "setup"
+                                "-pk" "/var/lib/gitolite/id_rsa.pub")))
+                    (lambda ()
+                      (primitive-exit 1))))
+                 (pid (waitpid pid)))
+
+               (delete-file "/var/lib/gitolite/id_rsa.pub")))))))
+
+(define (gitolite-activation config)
+  (if (gitolite-configuration-admin-pubkey config)
+      (gitolite-setup config)
+      #~(display
+         "guix: Skipping gitolite setup as the admin-pubkey has not been provided\n")))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)
+          (service-extension profile-service-type
+                             ;; The Gitolite package in Guix uses
+                             ;; gitolite-shell in the authorized_keys file, so
+                             ;; gitolite-shell needs to be on the PATH for
+                             ;; gitolite to work.
+                             (lambda (config)
+                               (list
+                                (gitolite-configuration-package config))))))
+   (default-value (gitolite-configuration))
+   (description
+    "Setup @command{gitolite}, a Git hosting tool providing access over SSH..
+By default, the @code{git} user is used, but this is configurable.
+Additionally, Gitolite can integrate with with tools like gitweb or cgit to
+provide a web interface to view selected repositories.")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 3b935a1b4..e4cd3fc3f 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -27,14 +27,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -300,3 +303,101 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                            '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/id_rsa")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/id_rsa.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-eq "service running"
+            'running!
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon)
+                'running!)
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair "/id_rsa")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          ;; Make sure we can clone the repo from the host.
+          (test-eq "clone"
+            #t
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Clone the Gitolite admin repository.")
+   (value (run-gitolite-test))))
-- 
2.17.1

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-13 23:15     ` Oleg Pykhalov
@ 2018-07-14  6:31       ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-14  6:31 UTC (permalink / raw)
  To: Oleg Pykhalov; +Cc: 30809

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


Oleg Pykhalov <go.wigust@gmail.com> writes:

> Hello Christopher,
>
> Not a full review, just want to note issue in the documentation and say
> thank you.  The gitolite service works for me.

Awesome, thanks for taking a look :)

> Christopher Baines <mail@cbaines.net> writes:
>
>> +The following G-exp would use the @file{~/.ssh/id_rsa.pub} file.
>> +
>> +@example
>> +(local-file "~/.ssh/id_rsa.pub")
>> +@end example
>
> ‘~/.ssh/id_rsa.pub’ doesn't work for me, because with ‘./pre-inst-env
> guix system vm ./test.scm’ it will be expanded to
> ‘/home/natsu/src/guix/~/.ssh/id_rsa.pub’.
>
> Specifing full path ‘/home/natsu/.ssh/id_rsa.pub’ is required for me.

Ok, I've changed the docs to use a absolute filename instead.

Thanks,

Chris

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

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-07-14  6:28 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
  2018-07-14  6:28   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
@ 2018-07-22 22:26   ` Clément Lassieur
  2018-07-23 22:10     ` Christopher Baines
  1 sibling, 1 reply; 32+ messages in thread
From: Clément Lassieur @ 2018-07-22 22:26 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

Hi Christopher!

Christopher Baines <mail@cbaines.net> writes:

> Previously the gitolite package worked, but there were problems using it for
> the service where you might have a minimal PATH. This commit patches the
> source and scripts where possible to use store paths, and also wraps the
> gitolite script to handle the harder dependencies.
>
> * gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
> the patch-scripts phase, and add two new phases (patch-source and
> wrap-scripts).
> [inputs]: Add coreutils, findutils and inetutils.
> ---
>  gnu/packages/version-control.scm | 53 ++++++++++++++++++++++++++++++--
>  1 file changed, 51 insertions(+), 2 deletions(-)

[...]

>                    (replace 'install
>                      (lambda* (#:key outputs #:allow-other-keys)
>                        (let* ((output (assoc-ref outputs "out"))
> @@ -1045,9 +1075,28 @@ also walk each side of a merge and test those changes individually.")
>                                      (symlink (string-append sharedir "/" script)
>                                               (string-append bindir "/" script)))
>                                    '("gitolite" "gitolite-shell"))
> -                        #t))))))
> +                        #t)))
> +                  (add-after 'install 'wrap-scripts
> +                    (lambda* (#:key inputs outputs #:allow-other-keys)
> +                      (wrap-program (string-append (assoc-ref outputs "out")
> +                                                   "/bin/gitolite")
> +                        `("PATH" ":" prefix
> +                          (,(string-append (assoc-ref outputs "out")
> +                                           "/bin")
> +                           ,(string-append (assoc-ref inputs "coreutils")
> +                                           "/bin")
> +                           ;; find is used in quite a few places
> +                           ,(string-append (assoc-ref inputs "findutils")
> +                                           "/bin")
> +                           ,(string-append (assoc-ref inputs "git")
> +                                           "/bin"))))

Here you can avoid some repetitions like this:

(let ((out (assoc-ref outputs "out"))
      (coreutils (assoc-ref inputs "coreutils"))
      (findutils (assoc-ref inputs "findutils"))
      (git (assoc-ref inputs "git")))
  (wrap-program (string-append out "/bin/gitolite")
    `("PATH" ":" prefix
      ,(map (lambda (dir)
              (string-append dir "/bin"))
            (list out coreutils findutils git))))
  #t)

> +
> +                      #t)))))
>      (inputs
> -     `(("perl" ,perl)))
> +     `(("perl" ,perl)
> +       ("coreutils" ,coreutils)
> +       ("findutils" ,findutils)
> +       ("inetutils" ,inetutils)))
>      ;; git and openssh are propagated because trying to patch the source via
>      ;; regexp matching is too brittle and prone to false positives.
>      (propagated-inputs

Otherwise, LGTM, thank you!

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-14  6:28   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
@ 2018-07-22 22:30     ` Clément Lassieur
  2018-07-23 22:06       ` Christopher Baines
  0 siblings, 1 reply; 32+ messages in thread
From: Clément Lassieur @ 2018-07-22 22:30 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

Christopher Baines <mail@cbaines.net> writes:

> * gnu/services/version-control.scm (<gitolite-configuration>,
> <gitolite-rc-file>): New record types.
> (gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
> (gitolite-service-type): New variables.
> * gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
> %test-gitolite): New variables.
> (run-gitolite-test): New procedure.
> * doc/guix.texi (Version Control): Document the gitolite service.
> ---
>  doc/guix.texi                    |  90 ++++++++++++++++
>  gnu/services/version-control.scm | 169 ++++++++++++++++++++++++++++++-
>  gnu/tests/version-control.scm    | 103 ++++++++++++++++++-
>  3 files changed, 360 insertions(+), 2 deletions(-)

Great :-)

[...]

> +@item @code{admin-pubkey} (default: @var{#f})
> +A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
> +setup Gitolite.  This can be omitted once Gitolite has successfully been
> +setup.

It looks like almost everything else can be ommited once Gitolite has
successfully been setup :-), I put another comment about it below.

[...]

> +(define-record-type* <gitolite-configuration>
> +  gitolite-configuration make-gitolite-configuration
> +  gitolite-configuration?
> +  (package      gitolite-configuration-package
> +                (default gitolite))
> +  (user         gitolite-configuration-user
> +                (default "git"))
> +  (rc-file      gitolite-configuration-rc-file
> +                (default (gitolite-rc-file)))
> +  (admin-pubkey gitolite-configuration-admin-pubkey
> +                (default #f)))
> +
> +(define (gitolite-accounts config)
> +  (let ((user (gitolite-configuration-user config)))
> +    ;; User group and account to run Gitolite.
> +    (list (user-group (name user) (system? #t))
> +          (user-account
> +           (name user)
> +           (group user)

It would be great to make the group and home directory configurable
too.  I personally use other settings for them.

> +           (system? #t)
> +           (comment "Gitolite user")
> +           (home-directory "/var/lib/gitolite")))))
> +
> +(define gitolite-setup
> +  (match-lambda
> +    (($ <gitolite-configuration> package user rc-file admin-pubkey)
> +     #~(begin
> +         (use-modules (ice-9 match)
> +                      (guix build utils))
> +         (if (not (file-exists? "/var/lib/gitolite/.gitolite"))

'unless', instead of 'if not'.

Also, is there a way to update the config once .gitolite exists?  If the
users update their config, they'd expect the new config to be applied I
guess.  Maybe we could override the symlink in that case.  Would that be
safe?  WDYT?

> +             (let ((user-info (getpwnam #$user)))
> +               (simple-format #t "guix: gitolite: installing ~A\n"
> +                              #$rc-file)
> +               (symlink #$rc-file "/var/lib/gitolite/.gitolite.rc")
> +
> +               ;; The key must be writable, so copy it from the store
> +               (copy-file #$admin-pubkey "/var/lib/gitolite/id_rsa.pub")
> +
> +               (chmod "/var/lib/gitolite/id_rsa.pub" #o500)
> +               (chown "/var/lib/gitolite/id_rsa.pub"
> +                      (passwd:uid user-info)
> +                      (passwd:gid user-info))
> +
> +               ;; Set the git configuration, to avoid gitolite trying to use
> +               ;; the hostname command, as the network might not be up yet
> +               (with-output-to-file "/var/lib/gitolite/.gitconfig"
> +                 (lambda ()
> +                   (display "[user]
> +        name = GNU Guix
> +        email = guix@localhost
> +")))
> +
> +               (match (primitive-fork)
> +                 (0
> +                  ;; Exit with a non-zero status code if an exception is thrown.
> +                  (dynamic-wind
> +                    (const #t)
> +                    (lambda ()
> +                      (setenv "HOME" (passwd:dir user-info))
> +                      (setenv "USER" #$user)
> +                      (setgid (passwd:gid user-info))
> +                      (setuid (passwd:uid user-info))
> +                      (primitive-exit
> +                       (system* #$(file-append package "/bin/gitolite")
> +                                "setup"
> +                                "-pk" "/var/lib/gitolite/id_rsa.pub")))
> +                    (lambda ()
> +                      (primitive-exit 1))))
> +                 (pid (waitpid pid)))
> +
> +               (delete-file "/var/lib/gitolite/id_rsa.pub")))))))

[...]

> diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm

Could you add your copyright header for this file?

> index 3b935a1b4..e4cd3fc3f 100644
> --- a/gnu/tests/version-control.scm
> +++ b/gnu/tests/version-control.scm
> @@ -27,14 +27,17 @@
>    #:use-module (gnu services)
>    #:use-module (gnu services version-control)
>    #:use-module (gnu services cgit)
> +  #:use-module (gnu services ssh)
>    #:use-module (gnu services web)
>    #:use-module (gnu services networking)
>    #:use-module (gnu packages version-control)
> +  #:use-module (gnu packages ssh)
>    #:use-module (guix gexp)
>    #:use-module (guix store)
>    #:use-module (guix modules)
>    #:export (%test-cgit
> -            %test-git-http))
> +            %test-git-http
> +            %test-gitolite))
>  
>  (define README-contents
>    "Hello!  This is what goes inside the 'README' file.")
> @@ -300,3 +303,101 @@ HTTP-PORT."
>     (name "git-http")
>     (description "Connect to a running Git HTTP server.")
>     (value (run-git-http-test))))
> +
> +\f
> +;;;
> +;;; Gitolite.
> +;;;
> +
> +(define %gitolite-test-admin-keypair
> +  (computed-file
> +   "gitolite-test-admin-keypair"
> +   (with-imported-modules (source-module-closure
> +                            '((guix build utils)))
                              ^
Here indentation is not correct ;-)

> +     #~(begin
> +         (use-modules (ice-9 match) (srfi srfi-26)
> +                      (guix build utils))
> +
> +         (mkdir #$output)
> +         (invoke #$(file-append openssh "/bin/ssh-keygen")
> +                 "-f" (string-append #$output "/id_rsa")
> +                 "-t" "rsa"
> +                 "-q"
> +                 "-N" "")))))

[...]

> +  (define test
> +    (with-imported-modules '((gnu build marionette)
> +                             (guix build utils))
> +      #~(begin
> +          (use-modules (srfi srfi-64)
> +                       (rnrs io ports)
> +                       (gnu build marionette)
> +                       (guix build utils))
> +
> +          (define marionette
> +            (make-marionette (list #$vm)))
> +
> +          (mkdir #$output)
> +          (chdir #$output)
> +
> +          (test-begin "gitolite")
> +
> +          ;; Wait for sshd to be up and running.
> +          (test-eq "service running"
> +            'running!
> +            (marionette-eval
> +             '(begin
> +                (use-modules (gnu services herd))
> +                (start-service 'ssh-daemon)
> +                'running!)
> +             marionette))

Here the test produces a false positive because the return value of
'start-service' isn't used.  It should be

(test-assert ... (start-service ...))

instead.

> +          (display #$%gitolite-test-admin-keypair)
> +
> +          (setenv "GIT_SSH_VARIANT" "ssh")
> +          (setenv "GIT_SSH_COMMAND"
> +                  (string-join
> +                   '(#$(file-append openssh "/bin/ssh")
> +                     "-i" #$(file-append %gitolite-test-admin-keypair "/id_rsa")
> +                     "-o" "UserKnownHostsFile=/dev/null"
> +                     "-o" "StrictHostKeyChecking=no")))
> +
> +          ;; Make sure we can clone the repo from the host.
> +          (test-eq "clone"
> +            #t
> +            (invoke #$(file-append git "/bin/git")
> +                    "clone" "-v"
> +                    "ssh://git@localhost:2222/gitolite-admin"
> +                    "/tmp/clone"))
> +
> +          (test-end)
> +          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
> +
> +  (gexp->derivation "gitolite" test))
> +
> +(define %test-gitolite
> +  (system-test
> +   (name "gitolite")
> +   (description "Clone the Gitolite admin repository.")
> +   (value (run-gitolite-test))))

Also, did you encounter bugs https://bugs.gnu.org/25957 and
https://bugs.gnu.org/30401?  Do you know if they are still here?

Thank you very much!
Clément

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
                   ` (3 preceding siblings ...)
  2018-07-14  6:28 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-23 21:43 ` Christopher Baines
  2018-07-23 21:43   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
  2018-07-29 20:18 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-23 21:43 UTC (permalink / raw)
  To: 30809

Previously the gitolite package worked, but there were problems using it for
the service where you might have a minimal PATH. This commit patches the
source and scripts where possible to use store paths, and also wraps the
gitolite script to handle the harder dependencies.

* gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
the patch-scripts phase, and add two new phases (patch-source and
wrap-scripts).
[inputs]: Add coreutils, findutils and inetutils.
---
 gnu/packages/version-control.scm | 53 +++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 6cb335420..ca765be1a 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -1026,12 +1026,48 @@ also walk each side of a merge and test those changes individually.")
                           ((" perl -")
                            (string-append " " perl " -")))
 
+                        (substitute* (find-files "src/triggers" ".*")
+                          ((" sed ")
+                           (string-append " " (which "sed") " ")))
+
+                        (substitute*
+                            '("src/triggers/post-compile/update-gitweb-access-list"
+                              "src/triggers/post-compile/ssh-authkeys-split"
+                              "src/triggers/upstream")
+                          ((" grep ")
+                           (string-append " " (which "grep") " ")))
+
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
                         (substitute* "src/triggers/post-compile/ssh-authkeys"
                           (("\\$glshell \\$user")
                            "gitolite-shell $user"))
                         #t)))
+                  (add-before 'install 'patch-source
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      ;; Gitolite uses cat to test the readability of the
+                      ;; pubkey
+                      (substitute* "src/lib/Gitolite/Setup.pm"
+                        (("\"cat ")
+                         (string-append "\"" (which "cat") " "))
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen"))))
+
+                      (substitute* '("src/lib/Gitolite/Hooks/PostUpdate.pm"
+                                     "src/lib/Gitolite/Hooks/Update.pm")
+                        (("/usr/bin/perl")
+                         (string-append (assoc-ref inputs "perl")
+                                        "/bin/perl")))
+
+                      (substitute* "src/lib/Gitolite/Common.pm"
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen")))
+                        (("\"logger\"")
+                         (string-append "\""
+                                        (assoc-ref inputs "inetutils")
+                                        "/bin/logger\"")))
+
+                      #t))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
@@ -1045,9 +1081,24 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let ((out (assoc-ref outputs "out"))
+                            (coreutils (assoc-ref inputs "coreutils"))
+                            (findutils (assoc-ref inputs "findutils"))
+                            (git (assoc-ref inputs "git")))
+                        (wrap-program (string-append out "/bin/gitolite")
+                          `("PATH" ":" prefix
+                            ,(map (lambda (dir)
+                                    (string-append dir "/bin"))
+                                  (list out coreutils findutils git))))
                         #t))))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-23 21:43 ` Christopher Baines
@ 2018-07-23 21:43   ` Christopher Baines
  2018-07-24  9:23     ` Clément Lassieur
  0 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-23 21:43 UTC (permalink / raw)
  To: 30809

* gnu/services/version-control.scm (<gitolite-configuration>,
<gitolite-rc-file>): New record types.
(gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
(gitolite-service-type): New variables.
* gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
%test-gitolite): New variables.
(run-gitolite-test): New procedure.
* doc/guix.texi (Version Control): Document the gitolite service.
---
 doc/guix.texi                    |  90 +++++++++++++++
 gnu/services/version-control.scm | 185 ++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 112 ++++++++++++++++++-
 3 files changed, 385 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 84347d156..8618f4cdb 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -20217,6 +20217,96 @@ could instantiate a cgit service like this:
           (cgitrc "")))
 @end example
 
+@subsubheading Gitolite Service
+
+@cindex Gitolite service
+@cindex Git, hosting
+@uref{http://gitolite.com/gitolite/, Gitolite} is a tool for hosting Git
+repositories on a central server.
+
+Gitolite can handle multiple repositories and users, and supports flexible
+configuration of the permissions for the users on the repositories.
+
+The following example will configure Gitolite using the default @code{git}
+user, and the provided SSH public key. A public key is necessary to setup
+Gitolite initially, but can be omitted once Gitolite is setup.
+
+@example
+(service gitolite-service-type
+         (gitolite-configuration
+           (admin-pubkey (plain-file
+                           "id_rsa.pub"
+                           "ssh-rsa AAAA... guix@@example.com"))))
+@end example
+
+Gitolite is configured through a special admin repository which you can clone,
+for example, if you setup Gitolite on @code{example.com}, you would run the
+following command to clone the admin repository.
+
+@example
+git clone git@@example.com:gitolite-admin
+@end example
+
+@deftp {Data Type} gitolite-configuration
+Data type representing the configuration for @code{gitolite-service-type}.
+
+@table @asis
+@item @code{package} (default: @var{gitolite})
+Gitolite package to use.
+
+@item @code{user} (default: @var{git})
+User to use for Gitolite.  This will be user that you use when accessing
+Gitolite over SSH.
+
+@item @code{rc-file} (default: @var{(gitolite-rc-file)})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
+representing the configuration for Gitolite.
+
+@item @code{admin-pubkey} (default: @var{#f})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
+setup Gitolite.  This can be omitted once Gitolite has successfully been
+setup.
+
+The following G-exp would use the @file{/home/user/.ssh/id_rsa.pub} file.
+
+@example
+(local-file "/home/user/.ssh/id_rsa.pub")
+@end example
+
+To specify the SSH key as a string, use the @code{plain-file} function.
+
+@example
+(plain-file "id_rsa.pub" "ssh-rsa AAAA... guix@@example.com")
+@end example
+
+@end table
+@end deftp
+
+@deftp {Data Type} gitolite-rc-file
+Data type representing the Gitolite RC file.
+
+@table @asis
+@item @code{umask} (default: @code{#o0077})
+This controls the permissions Gitolite sets on the repositories and their
+contents.
+
+A value like @code{#o0027} will give read access to the group used by Gitolite
+(by default: @code{git}). This is necessary when using Gitolite with software
+like cgit or gitweb.
+
+@item @code{git-config-keys} (default: @code{""})
+Gitolite allows you to set git config values using the "config" keyword. This
+setting allows control over the config keys to accept.
+
+@item @code{roles} (default: @code{'(("READERS" . 1) ("WRITERS" . ))})
+Set the role names allowed to be used by users running the perms command.
+
+@item @code{enable} (default: @code{'("help" "desc" "info" "perms" "writable" "ssh-authkeys" "git-config" "daemon" "gitweb")})
+This setting controls the commands and features to enable within Gitolite.
+
+@end table
+@end deftp
+
 
 @node Game Services
 @subsubsection Game Services
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index 58274c8be..367ea3a38 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
 ;;; Copyright © 2017 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -40,7 +41,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +214,169 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ""))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package        gitolite-configuration-package
+                  (default gitolite))
+  (user           gitolite-configuration-user
+                  (default "git"))
+  (group          gitolite-configuration-group
+                  (default "git"))
+  (home-directory gitolite-configuration-home-directory
+                  (default "/var/lib/gitolite"))
+  (rc-file        gitolite-configuration-rc-file
+                  (default (gitolite-rc-file)))
+  (admin-pubkey   gitolite-configuration-admin-pubkey
+                  (default #f)))
+
+(define gitolite-accounts
+  (match-lambda
+    (($ <gitolite-configuration> package user group home-directory
+                                 rc-file admin-pubkey)
+     ;; User group and account to run Gitolite.
+     (list (user-group (name user) (system? #t))
+           (user-account
+            (name user)
+            (group group)
+            (system? #t)
+            (comment "Gitolite user")
+            (home-directory home-directory))))))
+
+(define gitolite-setup
+  (match-lambda
+    (($ <gitolite-configuration> package user group home
+                                 rc-file admin-pubkey)
+     #~(let ((user-info (getpwnam #$user)))
+         (use-modules (guix build utils))
+
+         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
+         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
+
+         (let ((admin-pubkey #$admin-pubkey)
+               (pubkey-file #$(string-append home "/id_rsa.pub")))
+           (when admin-pubkey
+             ;; The key must be writable, so copy it from the store
+             (copy-file #$admin-pubkey pubkey-file)
+
+             (chmod pubkey-file #o500)
+             (chown pubkey-file
+                    (passwd:uid user-info)
+                    (passwd:gid user-info))
+
+             ;; Set the git configuration, to avoid gitolite trying to use
+             ;; the hostname command, as the network might not be up yet
+             (with-output-to-file #$(string-append home "/.gitconfig")
+               (lambda ()
+                 (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+"))))
+           ;; Run Gitolite setup, as this updates the hooks and include the
+           ;; admin pubkey if specified. The admin pubkey is required for
+           ;; initial setup, and will replace the previous key if run after
+           ;; initial setup
+           (let ((pid (primitive-fork)))
+             (if (eq? pid 0)
+                 (begin
+                   ;; Exit with a non-zero status code if an exception is thrown.
+                   (dynamic-wind
+                     (const #t)
+                     (lambda ()
+                       (setenv "HOME" (passwd:dir user-info))
+                       (setenv "USER" #$user)
+                       (setgid (passwd:gid user-info))
+                       (setuid (passwd:uid user-info))
+                       (primitive-exit
+                        (apply system*
+                               #$(file-append package "/bin/gitolite")
+                               "setup"
+                               (if admin-pubkey
+                                   `("-pk" ,pubkey-file)
+                                   '()))))
+                     (lambda ()
+                       (primitive-exit 1))))
+                 (waitpid pid)))
+
+           (when (file-exists? pubkey-file)
+             (delete-file pubkey-file)))))))
+
+(define (gitolite-activation config)
+  (if (gitolite-configuration-admin-pubkey config)
+      (gitolite-setup config)
+      #~(display
+         "guix: Skipping gitolite setup as the admin-pubkey has not been provided\n")))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)
+          (service-extension profile-service-type
+                             ;; The Gitolite package in Guix uses
+                             ;; gitolite-shell in the authorized_keys file, so
+                             ;; gitolite-shell needs to be on the PATH for
+                             ;; gitolite to work.
+                             (lambda (config)
+                               (list
+                                (gitolite-configuration-package config))))))
+   (default-value (gitolite-configuration))
+   (description
+    "Setup @command{gitolite}, a Git hosting tool providing access over SSH..
+By default, the @code{git} user is used, but this is configurable.
+Additionally, Gitolite can integrate with with tools like gitweb or cgit to
+provide a web interface to view selected repositories.")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 3b935a1b4..f2935b166 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017, 2018 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -27,14 +28,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -300,3 +304,109 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                           '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/id_rsa")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/id_rsa.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-assert "service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon))
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair "/id_rsa")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          (test-eq "cloning the admin repository"
+            #t
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (with-directory-excursion "/tmp/clone"
+            (invoke #$(file-append git "/bin/git")
+                    "-c" "user.name=Guix" "-c" "user.email=guix"
+                    "commit"
+                    "-m" "Test commit"
+                    "--allow-empty")
+
+            (test-eq "pushing, and the associated hooks"
+              #t
+              (invoke #$(file-append git "/bin/git") "push")))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Clone the Gitolite admin repository.")
+   (value (run-gitolite-test))))
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-22 22:30     ` Clément Lassieur
@ 2018-07-23 22:06       ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-23 22:06 UTC (permalink / raw)
  To: Clément Lassieur; +Cc: 30809

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


Clément Lassieur <clement@lassieur.org> writes:

> Christopher Baines <mail@cbaines.net> writes:
>
>> * gnu/services/version-control.scm (<gitolite-configuration>,
>> <gitolite-rc-file>): New record types.
>> (gitolite-accounts, gitolite-setup, gitolite-activation): New procedures.
>> (gitolite-service-type): New variables.
>> * gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
>> %test-gitolite): New variables.
>> (run-gitolite-test): New procedure.
>> * doc/guix.texi (Version Control): Document the gitolite service.
>> ---
>>  doc/guix.texi                    |  90 ++++++++++++++++
>>  gnu/services/version-control.scm | 169 ++++++++++++++++++++++++++++++-
>>  gnu/tests/version-control.scm    | 103 ++++++++++++++++++-
>>  3 files changed, 360 insertions(+), 2 deletions(-)
>
> Great :-)

Thanks for taking a look Clément, I too was looking at the these patches
over the last few days, and I've sent some updated patches with some
changes.

>> +@item @code{admin-pubkey} (default: @var{#f})
>> +A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
>> +setup Gitolite.  This can be omitted once Gitolite has successfully been
>> +setup.
>
> It looks like almost everything else can be ommited once Gitolite has
> successfully been setup :-), I put another comment about it below.

Well, maybe things like the rc-file could be omitted, but that's
probably worth keeping.

>> +(define-record-type* <gitolite-configuration>
>> +  gitolite-configuration make-gitolite-configuration
>> +  gitolite-configuration?
>> +  (package      gitolite-configuration-package
>> +                (default gitolite))
>> +  (user         gitolite-configuration-user
>> +                (default "git"))
>> +  (rc-file      gitolite-configuration-rc-file
>> +                (default (gitolite-rc-file)))
>> +  (admin-pubkey gitolite-configuration-admin-pubkey
>> +                (default #f)))
>> +
>> +(define (gitolite-accounts config)
>> +  (let ((user (gitolite-configuration-user config)))
>> +    ;; User group and account to run Gitolite.
>> +    (list (user-group (name user) (system? #t))
>> +          (user-account
>> +           (name user)
>> +           (group user)
>
> It would be great to make the group and home directory configurable
> too.  I personally use other settings for them.

Sure, I've made those configurable now.

>> +           (system? #t)
>> +           (comment "Gitolite user")
>> +           (home-directory "/var/lib/gitolite")))))
>> +
>> +(define gitolite-setup
>> +  (match-lambda
>> +    (($ <gitolite-configuration> package user rc-file admin-pubkey)
>> +     #~(begin
>> +         (use-modules (ice-9 match)
>> +                      (guix build utils))
>> +         (if (not (file-exists? "/var/lib/gitolite/.gitolite"))
>
> 'unless', instead of 'if not'.
>
> Also, is there a way to update the config once .gitolite exists?  If the
> users update their config, they'd expect the new config to be applied I
> guess.  Maybe we could override the symlink in that case.  Would that be
> safe?  WDYT?

So, I've rewritten some of this now. gitolite setup will be run each
time the service is activated, and this is important to ensure that the
hooks are updated.

>> +             (let ((user-info (getpwnam #$user)))
>> +               (simple-format #t "guix: gitolite: installing ~A\n"
>> +                              #$rc-file)
>> +               (symlink #$rc-file "/var/lib/gitolite/.gitolite.rc")
>> +
>> +               ;; The key must be writable, so copy it from the store
>> +               (copy-file #$admin-pubkey "/var/lib/gitolite/id_rsa.pub")
>> +
>> +               (chmod "/var/lib/gitolite/id_rsa.pub" #o500)
>> +               (chown "/var/lib/gitolite/id_rsa.pub"
>> +                      (passwd:uid user-info)
>> +                      (passwd:gid user-info))
>> +
>> +               ;; Set the git configuration, to avoid gitolite trying to use
>> +               ;; the hostname command, as the network might not be up yet
>> +               (with-output-to-file "/var/lib/gitolite/.gitconfig"
>> +                 (lambda ()
>> +                   (display "[user]
>> +        name = GNU Guix
>> +        email = guix@localhost
>> +")))
>> +
>> +               (match (primitive-fork)
>> +                 (0
>> +                  ;; Exit with a non-zero status code if an exception is thrown.
>> +                  (dynamic-wind
>> +                    (const #t)
>> +                    (lambda ()
>> +                      (setenv "HOME" (passwd:dir user-info))
>> +                      (setenv "USER" #$user)
>> +                      (setgid (passwd:gid user-info))
>> +                      (setuid (passwd:uid user-info))
>> +                      (primitive-exit
>> +                       (system* #$(file-append package "/bin/gitolite")
>> +                                "setup"
>> +                                "-pk" "/var/lib/gitolite/id_rsa.pub")))
>> +                    (lambda ()
>> +                      (primitive-exit 1))))
>> +                 (pid (waitpid pid)))
>> +
>> +               (delete-file "/var/lib/gitolite/id_rsa.pub")))))))
>
> [...]
>
>> diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
>
> Could you add your copyright header for this file?

I've done this now :)

>> index 3b935a1b4..e4cd3fc3f 100644
>> --- a/gnu/tests/version-control.scm
>> +++ b/gnu/tests/version-control.scm
>> @@ -27,14 +27,17 @@
>>    #:use-module (gnu services)
>>    #:use-module (gnu services version-control)
>>    #:use-module (gnu services cgit)
>> +  #:use-module (gnu services ssh)
>>    #:use-module (gnu services web)
>>    #:use-module (gnu services networking)
>>    #:use-module (gnu packages version-control)
>> +  #:use-module (gnu packages ssh)
>>    #:use-module (guix gexp)
>>    #:use-module (guix store)
>>    #:use-module (guix modules)
>>    #:export (%test-cgit
>> -            %test-git-http))
>> +            %test-git-http
>> +            %test-gitolite))
>>
>>  (define README-contents
>>    "Hello!  This is what goes inside the 'README' file.")
>> @@ -300,3 +303,101 @@ HTTP-PORT."
>>     (name "git-http")
>>     (description "Connect to a running Git HTTP server.")
>>     (value (run-git-http-test))))
>> +
>> +\f
>> +;;;
>> +;;; Gitolite.
>> +;;;
>> +
>> +(define %gitolite-test-admin-keypair
>> +  (computed-file
>> +   "gitolite-test-admin-keypair"
>> +   (with-imported-modules (source-module-closure
>> +                            '((guix build utils)))
>                               ^
> Here indentation is not correct ;-)

Ah, yep, I've corrected this.

>> +          ;; Wait for sshd to be up and running.
>> +          (test-eq "service running"
>> +            'running!
>> +            (marionette-eval
>> +             '(begin
>> +                (use-modules (gnu services herd))
>> +                (start-service 'ssh-daemon)
>> +                'running!)
>> +             marionette))
>
> Here the test produces a false positive because the return value of
> 'start-service' isn't used.  It should be
>
> (test-assert ... (start-service ...))
>
> instead.

Ok, I've made this change now.

>> +          (display #$%gitolite-test-admin-keypair)
>> +
>> +          (setenv "GIT_SSH_VARIANT" "ssh")
>> +          (setenv "GIT_SSH_COMMAND"
>> +                  (string-join
>> +                   '(#$(file-append openssh "/bin/ssh")
>> +                     "-i" #$(file-append %gitolite-test-admin-keypair "/id_rsa")
>> +                     "-o" "UserKnownHostsFile=/dev/null"
>> +                     "-o" "StrictHostKeyChecking=no")))
>> +
>> +          ;; Make sure we can clone the repo from the host.
>> +          (test-eq "clone"
>> +            #t
>> +            (invoke #$(file-append git "/bin/git")
>> +                    "clone" "-v"
>> +                    "ssh://git@localhost:2222/gitolite-admin"
>> +                    "/tmp/clone"))
>> +
>> +          (test-end)
>> +          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
>> +
>> +  (gexp->derivation "gitolite" test))
>> +
>> +(define %test-gitolite
>> +  (system-test
>> +   (name "gitolite")
>> +   (description "Clone the Gitolite admin repository.")
>> +   (value (run-gitolite-test))))
>
> Also, did you encounter bugs https://bugs.gnu.org/25957 and
> https://bugs.gnu.org/30401?  Do you know if they are still here?

So, 25957 should be fixed. That's now handled in the 'patch-source phase
of the package.

As for 30401, I'm not too sure.

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

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-07-22 22:26   ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Clément Lassieur
@ 2018-07-23 22:10     ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-23 22:10 UTC (permalink / raw)
  To: Clément Lassieur; +Cc: 30809

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


Clément Lassieur <clement@lassieur.org> writes:

>>                    (replace 'install
>>                      (lambda* (#:key outputs #:allow-other-keys)
>>                        (let* ((output (assoc-ref outputs "out"))
>> @@ -1045,9 +1075,28 @@ also walk each side of a merge and test those changes individually.")
>>                                      (symlink (string-append sharedir "/" script)
>>                                               (string-append bindir "/" script)))
>>                                    '("gitolite" "gitolite-shell"))
>> -                        #t))))))
>> +                        #t)))
>> +                  (add-after 'install 'wrap-scripts
>> +                    (lambda* (#:key inputs outputs #:allow-other-keys)
>> +                      (wrap-program (string-append (assoc-ref outputs "out")
>> +                                                   "/bin/gitolite")
>> +                        `("PATH" ":" prefix
>> +                          (,(string-append (assoc-ref outputs "out")
>> +                                           "/bin")
>> +                           ,(string-append (assoc-ref inputs "coreutils")
>> +                                           "/bin")
>> +                           ;; find is used in quite a few places
>> +                           ,(string-append (assoc-ref inputs "findutils")
>> +                                           "/bin")
>> +                           ,(string-append (assoc-ref inputs "git")
>> +                                           "/bin"))))
>
> Here you can avoid some repetitions like this:
>
> (let ((out (assoc-ref outputs "out"))
>       (coreutils (assoc-ref inputs "coreutils"))
>       (findutils (assoc-ref inputs "findutils"))
>       (git (assoc-ref inputs "git")))
>   (wrap-program (string-append out "/bin/gitolite")
>     `("PATH" ":" prefix
>       ,(map (lambda (dir)
>               (string-append dir "/bin"))
>             (list out coreutils findutils git))))
>   #t)

Thanks, I've used this in the updated patch now.

>> +
>> +                      #t)))))
>>      (inputs
>> -     `(("perl" ,perl)))
>> +     `(("perl" ,perl)
>> +       ("coreutils" ,coreutils)
>> +       ("findutils" ,findutils)
>> +       ("inetutils" ,inetutils)))
>>      ;; git and openssh are propagated because trying to patch the source via
>>      ;; regexp matching is too brittle and prone to false positives.
>>      (propagated-inputs
>
> Otherwise, LGTM, thank you!

Great :) I've made quite a few changes in the most recent update, so if
you have some time to look at those, that would be useful. The system
test is more rigorous now, pushing to the repository to test the hooks,
and I've rewritten most of the activation code.

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

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-23 21:43   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
@ 2018-07-24  9:23     ` Clément Lassieur
  2018-07-29 20:45       ` Christopher Baines
  0 siblings, 1 reply; 32+ messages in thread
From: Clément Lassieur @ 2018-07-24  9:23 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

Hi Christopher, thank you for the update!

Christopher Baines <mail@cbaines.net> writes:

[...]

> +(define gitolite-setup
> +  (match-lambda
> +    (($ <gitolite-configuration> package user group home
> +                                 rc-file admin-pubkey)
> +     #~(let ((user-info (getpwnam #$user)))
> +         (use-modules (guix build utils))
> +
> +         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
> +         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
> +
> +         (let ((admin-pubkey #$admin-pubkey)

What's the point of that 'let'?  Afterwards you reuse '$admin-pubkey'
:-).

> +               (pubkey-file #$(string-append home "/id_rsa.pub")))
> +           (when admin-pubkey

If we are 'gitolite-setup', that means 'admin-pubkey' is true, I think,
so that 'when' is useless.

> +             ;; The key must be writable, so copy it from the store
> +             (copy-file #$admin-pubkey pubkey-file)
> +
> +             (chmod pubkey-file #o500)
> +             (chown pubkey-file
> +                    (passwd:uid user-info)
> +                    (passwd:gid user-info))
> +
> +             ;; Set the git configuration, to avoid gitolite trying to use
> +             ;; the hostname command, as the network might not be up yet
> +             (with-output-to-file #$(string-append home "/.gitconfig")
> +               (lambda ()
> +                 (display "[user]
> +        name = GNU Guix
> +        email = guix@localhost
> +"))))
> +           ;; Run Gitolite setup, as this updates the hooks and include the
> +           ;; admin pubkey if specified. The admin pubkey is required for
> +           ;; initial setup, and will replace the previous key if run after
> +           ;; initial setup
> +           (let ((pid (primitive-fork)))
> +             (if (eq? pid 0)

I have a slight preference for the previous 'match' expression you used
before, because it's used elsewhere this way and it requires less code.

> +                 (begin

I think that 'begin' is useless.

> +                   ;; Exit with a non-zero status code if an exception is thrown.
> +                   (dynamic-wind
> +                     (const #t)
> +                     (lambda ()
> +                       (setenv "HOME" (passwd:dir user-info))
> +                       (setenv "USER" #$user)
> +                       (setgid (passwd:gid user-info))
> +                       (setuid (passwd:uid user-info))
> +                       (primitive-exit
> +                        (apply system*
> +                               #$(file-append package "/bin/gitolite")
> +                               "setup"
> +                               (if admin-pubkey
> +                                   `("-pk" ,pubkey-file)
> +                                   '()))))
> +                     (lambda ()
> +                       (primitive-exit 1))))
> +                 (waitpid pid)))
> +
> +           (when (file-exists? pubkey-file)
> +             (delete-file pubkey-file)))))))
> +
> +(define (gitolite-activation config)
> +  (if (gitolite-configuration-admin-pubkey config)
> +      (gitolite-setup config)
> +      #~(display
> +         "guix: Skipping gitolite setup as the admin-pubkey has not been provided\n")))

I'm not fan of the idea that a user might:
  1. setup an initial configuration with 'admin-pubkey',
  2. change that configuration once the initial activation has been
     done.

What is the drawback to forcing the user to setup an 'admin-pubkey'?
Maybe you think that doing the activation is annoying and it should only
be done when necessary?  If that's the case, maybe what we need is an
ad-hoc command instead of the activation, a bit like the
'certbot-command' of the Certbot service.

[...]

> +          (test-eq "cloning the admin repository"
> +            #t

test-assert

> +            (invoke #$(file-append git "/bin/git")
> +                    "clone" "-v"
> +                    "ssh://git@localhost:2222/gitolite-admin"
> +                    "/tmp/clone"))
> +
> +          (with-directory-excursion "/tmp/clone"
> +            (invoke #$(file-append git "/bin/git")
> +                    "-c" "user.name=Guix" "-c" "user.email=guix"
> +                    "commit"
> +                    "-m" "Test commit"
> +                    "--allow-empty")
> +
> +            (test-eq "pushing, and the associated hooks"
> +              #t

test-assert

> +              (invoke #$(file-append git "/bin/git") "push")))

Could you confirm that if a hook fails, that test will fail?

> +          (test-end)
> +          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
> +
> +  (gexp->derivation "gitolite" test))
> +
> +(define %test-gitolite
> +  (system-test
> +   (name "gitolite")
> +   (description "Clone the Gitolite admin repository.")
> +   (value (run-gitolite-test))))

Thanks!
Clément

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
                   ` (4 preceding siblings ...)
  2018-07-23 21:43 ` Christopher Baines
@ 2018-07-29 20:18 ` Christopher Baines
  2018-07-29 20:18   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
  2018-07-31 21:39 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
  2018-09-22 15:14 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
  7 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-29 20:18 UTC (permalink / raw)
  To: 30809

Previously the gitolite package worked, but there were problems using it for
the service where you might have a minimal PATH. This commit patches the
source and scripts where possible to use store paths, and also wraps the
gitolite script to handle the harder dependencies.

* gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
the patch-scripts phase, and add two new phases (patch-source and
wrap-scripts).
[inputs]: Add coreutils, findutils and inetutils.
---
 gnu/packages/version-control.scm | 53 +++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 6cb335420..ca765be1a 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -1026,12 +1026,48 @@ also walk each side of a merge and test those changes individually.")
                           ((" perl -")
                            (string-append " " perl " -")))
 
+                        (substitute* (find-files "src/triggers" ".*")
+                          ((" sed ")
+                           (string-append " " (which "sed") " ")))
+
+                        (substitute*
+                            '("src/triggers/post-compile/update-gitweb-access-list"
+                              "src/triggers/post-compile/ssh-authkeys-split"
+                              "src/triggers/upstream")
+                          ((" grep ")
+                           (string-append " " (which "grep") " ")))
+
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
                         (substitute* "src/triggers/post-compile/ssh-authkeys"
                           (("\\$glshell \\$user")
                            "gitolite-shell $user"))
                         #t)))
+                  (add-before 'install 'patch-source
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      ;; Gitolite uses cat to test the readability of the
+                      ;; pubkey
+                      (substitute* "src/lib/Gitolite/Setup.pm"
+                        (("\"cat ")
+                         (string-append "\"" (which "cat") " "))
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen"))))
+
+                      (substitute* '("src/lib/Gitolite/Hooks/PostUpdate.pm"
+                                     "src/lib/Gitolite/Hooks/Update.pm")
+                        (("/usr/bin/perl")
+                         (string-append (assoc-ref inputs "perl")
+                                        "/bin/perl")))
+
+                      (substitute* "src/lib/Gitolite/Common.pm"
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen")))
+                        (("\"logger\"")
+                         (string-append "\""
+                                        (assoc-ref inputs "inetutils")
+                                        "/bin/logger\"")))
+
+                      #t))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
@@ -1045,9 +1081,24 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let ((out (assoc-ref outputs "out"))
+                            (coreutils (assoc-ref inputs "coreutils"))
+                            (findutils (assoc-ref inputs "findutils"))
+                            (git (assoc-ref inputs "git")))
+                        (wrap-program (string-append out "/bin/gitolite")
+                          `("PATH" ":" prefix
+                            ,(map (lambda (dir)
+                                    (string-append dir "/bin"))
+                                  (list out coreutils findutils git))))
                         #t))))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-29 20:18 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-29 20:18   ` Christopher Baines
  2018-07-30 23:39     ` Clément Lassieur
  0 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-29 20:18 UTC (permalink / raw)
  To: 30809

* gnu/services/version-control.scm (<gitolite-configuration>,
<gitolite-rc-file>): New record types.
(gitolite-accounts, gitolite-activation): New procedures.
(gitolite-service-type): New variables.
* gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
%test-gitolite): New variables.
(run-gitolite-test): New procedure.
* doc/guix.texi (Version Control): Document the gitolite service.
---
 doc/guix.texi                    |  94 +++++++++++++++++
 gnu/services/version-control.scm | 176 ++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 114 +++++++++++++++++++-
 3 files changed, 382 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index d5588066b..9b8e482d8 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -20246,6 +20246,100 @@ could instantiate a cgit service like this:
           (cgitrc "")))
 @end example
 
+@subsubheading Gitolite Service
+
+@cindex Gitolite service
+@cindex Git, hosting
+@uref{http://gitolite.com/gitolite/, Gitolite} is a tool for hosting Git
+repositories on a central server.
+
+Gitolite can handle multiple repositories and users, and supports flexible
+configuration of the permissions for the users on the repositories.
+
+The following example will configure Gitolite using the default @code{git}
+user, and the provided SSH public key.
+
+@example
+(service gitolite-service-type
+         (gitolite-configuration
+           (admin-pubkey (plain-file
+                           "yourname.pub"
+                           "ssh-rsa AAAA... guix@@example.com"))))
+@end example
+
+Gitolite is configured through a special admin repository which you can clone,
+for example, if you setup Gitolite on @code{example.com}, you would run the
+following command to clone the admin repository.
+
+@example
+git clone git@@example.com:gitolite-admin
+@end example
+
+When the Gitolite service is activated, the provided @code{admin-pubkey} will
+be inserted in to the @file{keydir} directory in the gitolite-admin
+repository.  If this results in a change in the repository, it will be
+committed using the message ``gitolite setup by GNU Guix''.
+
+@deftp {Data Type} gitolite-configuration
+Data type representing the configuration for @code{gitolite-service-type}.
+
+@table @asis
+@item @code{package} (default: @var{gitolite})
+Gitolite package to use.
+
+@item @code{user} (default: @var{git})
+User to use for Gitolite.  This will be user that you use when accessing
+Gitolite over SSH.
+
+@item @code{group} (default: @var{git})
+Group to use for Gitolite.
+
+@item @code{home-directory} (default: @var{"/var/lib/gitolite"})
+Directory in which to store the Gitolite configuration and repositories.
+
+@item @code{rc-file} (default: @var{(gitolite-rc-file)})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
+representing the configuration for Gitolite.
+
+@item @code{admin-pubkey} (default: @var{#f})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
+setup Gitolite.  This will be inserted in to the @file{keydir} directory
+within the gitolite-admin repository.
+
+To specify the SSH key as a string, use the @code{plain-file} function.
+
+@example
+(plain-file "yourname.pub" "ssh-rsa AAAA... guix@@example.com")
+@end example
+
+@end table
+@end deftp
+
+@deftp {Data Type} gitolite-rc-file
+Data type representing the Gitolite RC file.
+
+@table @asis
+@item @code{umask} (default: @code{#o0077})
+This controls the permissions Gitolite sets on the repositories and their
+contents.
+
+A value like @code{#o0027} will give read access to the group used by Gitolite
+(by default: @code{git}). This is necessary when using Gitolite with software
+like cgit or gitweb.
+
+@item @code{git-config-keys} (default: @code{""})
+Gitolite allows you to set git config values using the "config" keyword. This
+setting allows control over the config keys to accept.
+
+@item @code{roles} (default: @code{'(("READERS" . 1) ("WRITERS" . ))})
+Set the role names allowed to be used by users running the perms command.
+
+@item @code{enable} (default: @code{'("help" "desc" "info" "perms" "writable" "ssh-authkeys" "git-config" "daemon" "gitweb")})
+This setting controls the commands and features to enable within Gitolite.
+
+@end table
+@end deftp
+
 
 @node Game Services
 @subsubsection Game Services
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index 58274c8be..2afdf4a29 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
 ;;; Copyright © 2017 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -40,7 +41,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +214,160 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ""))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package        gitolite-configuration-package
+                  (default gitolite))
+  (user           gitolite-configuration-user
+                  (default "git"))
+  (group          gitolite-configuration-group
+                  (default "git"))
+  (home-directory gitolite-configuration-home-directory
+                  (default "/var/lib/gitolite"))
+  (rc-file        gitolite-configuration-rc-file
+                  (default (gitolite-rc-file)))
+  (admin-pubkey   gitolite-configuration-admin-pubkey))
+
+(define gitolite-accounts
+  (match-lambda
+    (($ <gitolite-configuration> package user group home-directory
+                                 rc-file admin-pubkey)
+     ;; User group and account to run Gitolite.
+     (list (user-group (name user) (system? #t))
+           (user-account
+            (name user)
+            (group group)
+            (system? #t)
+            (comment "Gitolite user")
+            (home-directory home-directory))))))
+
+(define gitolite-activation
+  (match-lambda
+    (($ <gitolite-configuration> package user group home
+                                 rc-file admin-pubkey)
+     #~(let* ((user-info (getpwnam #$user))
+              (admin-pubkey #$admin-pubkey)
+              (pubkey-file (string-append
+                            #$home "/"
+                            (basename
+                             (strip-store-file-name admin-pubkey)))))
+         (use-modules (guix build utils))
+
+         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
+         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
+
+         ;; The key must be writable, so copy it from the store
+         (copy-file admin-pubkey pubkey-file)
+
+         (chmod pubkey-file #o500)
+         (chown pubkey-file
+                (passwd:uid user-info)
+                (passwd:gid user-info))
+
+         ;; Set the git configuration, to avoid gitolite trying to use
+         ;; the hostname command, as the network might not be up yet
+         (with-output-to-file #$(string-append home "/.gitconfig")
+           (lambda ()
+             (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+")))
+         ;; Run Gitolite setup, as this updates the hooks and include the
+         ;; admin pubkey if specified. The admin pubkey is required for
+         ;; initial setup, and will replace the previous key if run after
+         ;; initial setup
+         (let ((pid (primitive-fork)))
+           (if (eq? pid 0)
+               ;; Exit with a non-zero status code if an exception is thrown.
+               (dynamic-wind
+                 (const #t)
+                 (lambda ()
+                   (setenv "HOME" (passwd:dir user-info))
+                   (setenv "USER" #$user)
+                   (setgid (passwd:gid user-info))
+                   (setuid (passwd:uid user-info))
+                   (primitive-exit
+                    (system* #$(file-append package "/bin/gitolite")
+                             "setup"
+                             "-m" "gitolite setup by GNU Guix"
+                             "-pk" pubkey-file)))
+                 (lambda ()
+                   (primitive-exit 1)))
+               (waitpid pid)))
+
+         (when (file-exists? pubkey-file)
+           (delete-file pubkey-file))))))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)
+          (service-extension profile-service-type
+                             ;; The Gitolite package in Guix uses
+                             ;; gitolite-shell in the authorized_keys file, so
+                             ;; gitolite-shell needs to be on the PATH for
+                             ;; gitolite to work.
+                             (lambda (config)
+                               (list
+                                (gitolite-configuration-package config))))))
+   (description
+    "Setup @command{gitolite}, a Git hosting tool providing access over SSH..
+By default, the @code{git} user is used, but this is configurable.
+Additionally, Gitolite can integrate with with tools like gitweb or cgit to
+provide a web interface to view selected repositories.")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 3b935a1b4..4409b8a12 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017, 2018 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -27,14 +28,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -300,3 +304,111 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                           '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/test-admin")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/test-admin.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-assert "service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon))
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair
+                                         "/test-admin")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          (test-assert "cloning the admin repository"
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (test-assert "admin key exists"
+            (file-exists? "/tmp/clone/keydir/test-admin.pub"))
+
+          (with-directory-excursion "/tmp/clone"
+            (invoke #$(file-append git "/bin/git")
+                    "-c" "user.name=Guix" "-c" "user.email=guix"
+                    "commit"
+                    "-m" "Test commit"
+                    "--allow-empty")
+
+            (test-assert "pushing, and the associated hooks"
+              (invoke #$(file-append git "/bin/git") "push")))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Clone the Gitolite admin repository.")
+   (value (run-gitolite-test))))
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-24  9:23     ` Clément Lassieur
@ 2018-07-29 20:45       ` Christopher Baines
  2018-07-30 18:26         ` Clément Lassieur
  0 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-29 20:45 UTC (permalink / raw)
  To: Clément Lassieur; +Cc: 30809

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


Clément Lassieur <clement@lassieur.org> writes:

> Hi Christopher, thank you for the update!

Thanks for taking another look. I've just send another set of revised
patches.

> Christopher Baines <mail@cbaines.net> writes:
>
> [...]
>
>> +(define gitolite-setup
>> +  (match-lambda
>> +    (($ <gitolite-configuration> package user group home
>> +                                 rc-file admin-pubkey)
>> +     #~(let ((user-info (getpwnam #$user)))
>> +         (use-modules (guix build utils))
>> +
>> +         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
>> +         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
>> +
>> +         (let ((admin-pubkey #$admin-pubkey)
>
> What's the point of that 'let'?  Afterwards you reuse '$admin-pubkey'
> :-).

Ah yeah, I've fixed that now.

>> +               (pubkey-file #$(string-append home "/id_rsa.pub")))
>> +           (when admin-pubkey
>
> If we are 'gitolite-setup', that means 'admin-pubkey' is true, I think,
> so that 'when' is useless.

Indeed. I've removed the gitolite-setup function now, along with this
conditional.

>> +             ;; The key must be writable, so copy it from the store
>> +             (copy-file #$admin-pubkey pubkey-file)
>> +
>> +             (chmod pubkey-file #o500)
>> +             (chown pubkey-file
>> +                    (passwd:uid user-info)
>> +                    (passwd:gid user-info))
>> +
>> +             ;; Set the git configuration, to avoid gitolite trying to use
>> +             ;; the hostname command, as the network might not be up yet
>> +             (with-output-to-file #$(string-append home "/.gitconfig")
>> +               (lambda ()
>> +                 (display "[user]
>> +        name = GNU Guix
>> +        email = guix@localhost
>> +"))))
>> +           ;; Run Gitolite setup, as this updates the hooks and include the
>> +           ;; admin pubkey if specified. The admin pubkey is required for
>> +           ;; initial setup, and will replace the previous key if run after
>> +           ;; initial setup
>> +           (let ((pid (primitive-fork)))
>> +             (if (eq? pid 0)
>
> I have a slight preference for the previous 'match' expression you used
> before, because it's used elsewhere this way and it requires less code.

While I agree with both your points, I tried for quite a while last
weekend to get match to work, and couldn't. I couldn't even tell why it
suddenly wasn't. Unfortunately, Linux panicing when anything fails makes
debugging the system test a bit tricky.

>> +                 (begin
>
> I think that 'begin' is useless.

Yeah, I think I added that while trying to get match to work. I've
removed it now.

>> +                   ;; Exit with a non-zero status code if an exception is thrown.
>> +                   (dynamic-wind
>> +                     (const #t)
>> +                     (lambda ()
>> +                       (setenv "HOME" (passwd:dir user-info))
>> +                       (setenv "USER" #$user)
>> +                       (setgid (passwd:gid user-info))
>> +                       (setuid (passwd:uid user-info))
>> +                       (primitive-exit
>> +                        (apply system*
>> +                               #$(file-append package "/bin/gitolite")
>> +                               "setup"
>> +                               (if admin-pubkey
>> +                                   `("-pk" ,pubkey-file)
>> +                                   '()))))
>> +                     (lambda ()
>> +                       (primitive-exit 1))))
>> +                 (waitpid pid)))
>> +
>> +           (when (file-exists? pubkey-file)
>> +             (delete-file pubkey-file)))))))
>> +
>> +(define (gitolite-activation config)
>> +  (if (gitolite-configuration-admin-pubkey config)
>> +      (gitolite-setup config)
>> +      #~(display
>> +         "guix: Skipping gitolite setup as the admin-pubkey has not been provided\n")))
>
> I'm not fan of the idea that a user might:
>   1. setup an initial configuration with 'admin-pubkey',
>   2. change that configuration once the initial activation has been
>      done.
>
> What is the drawback to forcing the user to setup an 'admin-pubkey'?
> Maybe you think that doing the activation is annoying and it should only
> be done when necessary?  If that's the case, maybe what we need is an
> ad-hoc command instead of the activation, a bit like the
> 'certbot-command' of the Certbot service.

I wrote it this way as this is how I've been using Gitolite so far. On
Debian, I think debconf prompts you for the key when you install the
package, and runs gitolite setup.

I've actually read the gitolite setup script now, and its behaviour it
pretty reasonable if it's run frequently. As I understand it, it ensures
that the provided admin-pubkey exists in the keydir directory in the
gitolite-admin repository, and will commit to the repository if it
changes anything.

So, I think I've now changed both the service and the documentation to
describe adding the admin-pubkey always.

>> +          (test-eq "cloning the admin repository"
>> +            #t
>
> test-assert
>
>> +            (test-eq "pushing, and the associated hooks"
>> +              #t
>
> test-assert

I've changed these now :)

>> +              (invoke #$(file-append git "/bin/git") "push")))
>
> Could you confirm that if a hook fails, that test will fail?

Yep, I added this check when I realised that the hooks were broken.

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

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-29 20:45       ` Christopher Baines
@ 2018-07-30 18:26         ` Clément Lassieur
  0 siblings, 0 replies; 32+ messages in thread
From: Clément Lassieur @ 2018-07-30 18:26 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

Christopher Baines <mail@cbaines.net> writes:

[...]

>>> +(define gitolite-setup
>>> +  (match-lambda
>>> +    (($ <gitolite-configuration> package user group home
>>> +                                 rc-file admin-pubkey)
>>> +     #~(let ((user-info (getpwnam #$user)))
>>> +         (use-modules (guix build utils))

-----------------(ice-9 match)----^

>>> +
>>> +         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
>>> +         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
>>> +
>>> +         (let ((admin-pubkey #$admin-pubkey)

[...]

>> I have a slight preference for the previous 'match' expression you used
>> before, because it's used elsewhere this way and it requires less code.
>
> While I agree with both your points, I tried for quite a while last
> weekend to get match to work, and couldn't. I couldn't even tell why it
> suddenly wasn't. Unfortunately, Linux panicing when anything fails makes
> debugging the system test a bit tricky.

Maybe you forgot to add the (ice-9 match) module?

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-29 20:18   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
@ 2018-07-30 23:39     ` Clément Lassieur
  2018-07-31 21:40       ` Christopher Baines
  0 siblings, 1 reply; 32+ messages in thread
From: Clément Lassieur @ 2018-07-30 23:39 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

Hey Christopher!

Thank you for the update.

Christopher Baines <mail@cbaines.net> writes:

[...]

> +@example
> +git clone git@@example.com:gitolite-admin
> +@end example
> +
> +When the Gitolite service is activated, the provided @code{admin-pubkey} will
> +be inserted in to the @file{keydir} directory in the gitolite-admin
> +repository.  If this results in a change in the repository, it will be
> +committed using the message ``gitolite setup by GNU Guix''.
> +
> +@deftp {Data Type} gitolite-configuration
> +Data type representing the configuration for @code{gitolite-service-type}.
> +
> +@table @asis
> +@item @code{package} (default: @var{gitolite})
> +Gitolite package to use.
> +
> +@item @code{user} (default: @var{git})
                                    ^
It should be a string ---------------

I don't think you should use @var for default values.  @code would be better.

> +User to use for Gitolite.  This will be user that you use when accessing
> +Gitolite over SSH.
> +
> +@item @code{group} (default: @var{git})
                                    ^
It should be a string ---------------

> +Group to use for Gitolite.
> +
> +@item @code{home-directory} (default: @var{"/var/lib/gitolite"})
> +Directory in which to store the Gitolite configuration and repositories.
> +
> +@item @code{rc-file} (default: @var{(gitolite-rc-file)})
> +A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
> +representing the configuration for Gitolite.
> +
> +@item @code{admin-pubkey} (default: @var{#f})

Actually, there is no default :-)

[...]

> +  (match-lambda
> +    (($ <gitolite-configuration> package user group home
> +                                 rc-file admin-pubkey)
> +     #~(let* ((user-info (getpwnam #$user))
> +              (admin-pubkey #$admin-pubkey)
> +              (pubkey-file (string-append
> +                            #$home "/"
> +                            (basename
> +                             (strip-store-file-name admin-pubkey)))))
> +         (use-modules (guix build utils))
> +
> +         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
> +         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
                 ^
Maybe a symlink here?

> +         ;; The key must be writable, so copy it from the store
> +         (copy-file admin-pubkey pubkey-file)
> +
> +         (chmod pubkey-file #o500)

I don't think it must be writable, because #o500 isn't writable.

> +         (chown pubkey-file
> +                (passwd:uid user-info)
> +                (passwd:gid user-info))
> +
> +         ;; Set the git configuration, to avoid gitolite trying to use
> +         ;; the hostname command, as the network might not be up yet
> +         (with-output-to-file #$(string-append home "/.gitconfig")
> +           (lambda ()
> +             (display "[user]
> +        name = GNU Guix
> +        email = guix@localhost
> +")))
> +         ;; Run Gitolite setup, as this updates the hooks and include the
> +         ;; admin pubkey if specified. The admin pubkey is required for
> +         ;; initial setup, and will replace the previous key if run after
> +         ;; initial setup
> +         (let ((pid (primitive-fork)))
> +           (if (eq? pid 0)
> +               ;; Exit with a non-zero status code if an exception is thrown.
> +               (dynamic-wind
> +                 (const #t)
> +                 (lambda ()
> +                   (setenv "HOME" (passwd:dir user-info))
> +                   (setenv "USER" #$user)
> +                   (setgid (passwd:gid user-info))
> +                   (setuid (passwd:uid user-info))
> +                   (primitive-exit
> +                    (system* #$(file-append package "/bin/gitolite")
> +                             "setup"
> +                             "-m" "gitolite setup by GNU Guix"
> +                             "-pk" pubkey-file)))
> +                 (lambda ()
> +                   (primitive-exit 1)))
> +               (waitpid pid)))

This works (with the (ice-9 match) module added):

         (match (primitive-fork)
           (0
            ;; Exit with a non-zero status code if an exception is thrown.
            (dynamic-wind
              (const #t)
              (lambda ()
                (setenv "HOME" (passwd:dir user-info))
                (setenv "USER" #$user)
                (setgid (passwd:gid user-info))
                (setuid (passwd:uid user-info))
                (primitive-exit
                 (system* #$(file-append package "/bin/gitolite")
                          "setup"
                          "-m" "gitolite setup by GNU Guix"
                          "-pk" pubkey-file)))
              (lambda ()
                (primitive-exit 1))))
           (pid (waitpid pid)))

Other than that, it looks good to me!

Thanks again,
Clément

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
                   ` (5 preceding siblings ...)
  2018-07-29 20:18 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-31 21:39 ` Christopher Baines
  2018-07-31 21:39   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
  2018-09-22 15:14 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
  7 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-07-31 21:39 UTC (permalink / raw)
  To: 30809

Previously the gitolite package worked, but there were problems using it for
the service where you might have a minimal PATH. This commit patches the
source and scripts where possible to use store paths, and also wraps the
gitolite script to handle the harder dependencies.

* gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
the patch-scripts phase, and add two new phases (patch-source and
wrap-scripts).
[inputs]: Add coreutils, findutils and inetutils.
---
 gnu/packages/version-control.scm | 53 +++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 3db5796b4..70fd40d87 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -1026,12 +1026,48 @@ also walk each side of a merge and test those changes individually.")
                           ((" perl -")
                            (string-append " " perl " -")))
 
+                        (substitute* (find-files "src/triggers" ".*")
+                          ((" sed ")
+                           (string-append " " (which "sed") " ")))
+
+                        (substitute*
+                            '("src/triggers/post-compile/update-gitweb-access-list"
+                              "src/triggers/post-compile/ssh-authkeys-split"
+                              "src/triggers/upstream")
+                          ((" grep ")
+                           (string-append " " (which "grep") " ")))
+
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
                         (substitute* "src/triggers/post-compile/ssh-authkeys"
                           (("\\$glshell \\$user")
                            "gitolite-shell $user"))
                         #t)))
+                  (add-before 'install 'patch-source
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      ;; Gitolite uses cat to test the readability of the
+                      ;; pubkey
+                      (substitute* "src/lib/Gitolite/Setup.pm"
+                        (("\"cat ")
+                         (string-append "\"" (which "cat") " "))
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen"))))
+
+                      (substitute* '("src/lib/Gitolite/Hooks/PostUpdate.pm"
+                                     "src/lib/Gitolite/Hooks/Update.pm")
+                        (("/usr/bin/perl")
+                         (string-append (assoc-ref inputs "perl")
+                                        "/bin/perl")))
+
+                      (substitute* "src/lib/Gitolite/Common.pm"
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen")))
+                        (("\"logger\"")
+                         (string-append "\""
+                                        (assoc-ref inputs "inetutils")
+                                        "/bin/logger\"")))
+
+                      #t))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
@@ -1045,9 +1081,24 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let ((out (assoc-ref outputs "out"))
+                            (coreutils (assoc-ref inputs "coreutils"))
+                            (findutils (assoc-ref inputs "findutils"))
+                            (git (assoc-ref inputs "git")))
+                        (wrap-program (string-append out "/bin/gitolite")
+                          `("PATH" ":" prefix
+                            ,(map (lambda (dir)
+                                    (string-append dir "/bin"))
+                                  (list out coreutils findutils git))))
                         #t))))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-31 21:39 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-07-31 21:39   ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-31 21:39 UTC (permalink / raw)
  To: 30809

* gnu/services/version-control.scm (<gitolite-configuration>,
<gitolite-rc-file>): New record types.
(gitolite-accounts, gitolite-activation): New procedures.
(gitolite-service-type): New variables.
* gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
%test-gitolite): New variables.
(run-gitolite-test): New procedure.
* doc/guix.texi (Version Control): Document the gitolite service.
---
 doc/guix.texi                    |  94 ++++++++++++++++++
 gnu/services/version-control.scm | 165 ++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 114 ++++++++++++++++++++-
 3 files changed, 371 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 080b091b3..e59d7bacd 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -20246,6 +20246,100 @@ could instantiate a cgit service like this:
           (cgitrc "")))
 @end example
 
+@subsubheading Gitolite Service
+
+@cindex Gitolite service
+@cindex Git, hosting
+@uref{http://gitolite.com/gitolite/, Gitolite} is a tool for hosting Git
+repositories on a central server.
+
+Gitolite can handle multiple repositories and users, and supports flexible
+configuration of the permissions for the users on the repositories.
+
+The following example will configure Gitolite using the default @code{git}
+user, and the provided SSH public key.
+
+@example
+(service gitolite-service-type
+         (gitolite-configuration
+           (admin-pubkey (plain-file
+                           "yourname.pub"
+                           "ssh-rsa AAAA... guix@@example.com"))))
+@end example
+
+Gitolite is configured through a special admin repository which you can clone,
+for example, if you setup Gitolite on @code{example.com}, you would run the
+following command to clone the admin repository.
+
+@example
+git clone git@@example.com:gitolite-admin
+@end example
+
+When the Gitolite service is activated, the provided @code{admin-pubkey} will
+be inserted in to the @file{keydir} directory in the gitolite-admin
+repository.  If this results in a change in the repository, it will be
+committed using the message ``gitolite setup by GNU Guix''.
+
+@deftp {Data Type} gitolite-configuration
+Data type representing the configuration for @code{gitolite-service-type}.
+
+@table @asis
+@item @code{package} (default: @var{gitolite})
+Gitolite package to use.
+
+@item @code{user} (default: @code{"git"})
+User to use for Gitolite.  This will be user that you use when accessing
+Gitolite over SSH.
+
+@item @code{group} (default: @code{"git"})
+Group to use for Gitolite.
+
+@item @code{home-directory} (default: @code{"/var/lib/gitolite"})
+Directory in which to store the Gitolite configuration and repositories.
+
+@item @code{rc-file} (default: @code{(gitolite-rc-file)})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
+representing the configuration for Gitolite.
+
+@item @code{admin-pubkey}
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
+setup Gitolite.  This will be inserted in to the @file{keydir} directory
+within the gitolite-admin repository.
+
+To specify the SSH key as a string, use the @code{plain-file} function.
+
+@example
+(plain-file "yourname.pub" "ssh-rsa AAAA... guix@@example.com")
+@end example
+
+@end table
+@end deftp
+
+@deftp {Data Type} gitolite-rc-file
+Data type representing the Gitolite RC file.
+
+@table @asis
+@item @code{umask} (default: @code{#o0077})
+This controls the permissions Gitolite sets on the repositories and their
+contents.
+
+A value like @code{#o0027} will give read access to the group used by Gitolite
+(by default: @code{git}). This is necessary when using Gitolite with software
+like cgit or gitweb.
+
+@item @code{git-config-keys} (default: @code{""})
+Gitolite allows you to set git config values using the "config" keyword. This
+setting allows control over the config keys to accept.
+
+@item @code{roles} (default: @code{'(("READERS" . 1) ("WRITERS" . ))})
+Set the role names allowed to be used by users running the perms command.
+
+@item @code{enable} (default: @code{'("help" "desc" "info" "perms" "writable" "ssh-authkeys" "git-config" "daemon" "gitweb")})
+This setting controls the commands and features to enable within Gitolite.
+
+@end table
+@end deftp
+
 
 @node Game Services
 @subsubsection Game Services
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index 58274c8be..555028d43 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
 ;;; Copyright © 2017 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -40,7 +41,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +214,149 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ""))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package        gitolite-configuration-package
+                  (default gitolite))
+  (user           gitolite-configuration-user
+                  (default "git"))
+  (group          gitolite-configuration-group
+                  (default "git"))
+  (home-directory gitolite-configuration-home-directory
+                  (default "/var/lib/gitolite"))
+  (rc-file        gitolite-configuration-rc-file
+                  (default (gitolite-rc-file)))
+  (admin-pubkey   gitolite-configuration-admin-pubkey))
+
+(define gitolite-accounts
+  (match-lambda
+    (($ <gitolite-configuration> package user group home-directory
+                                 rc-file admin-pubkey)
+     ;; User group and account to run Gitolite.
+     (list (user-group (name user) (system? #t))
+           (user-account
+            (name user)
+            (group group)
+            (system? #t)
+            (comment "Gitolite user")
+            (home-directory home-directory))))))
+
+(define gitolite-activation
+  (match-lambda
+    (($ <gitolite-configuration> package user group home
+                                 rc-file admin-pubkey)
+     #~(let* ((user-info (getpwnam #$user))
+              (admin-pubkey #$admin-pubkey)
+              (pubkey-file (string-append
+                            #$home "/"
+                            (basename
+                             (strip-store-file-name admin-pubkey))))
+              (installed-rc-file
+               #$(string-append home "/.gitolite.rc")))
+         (use-modules (guix build utils))
+
+         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
+         (false-if-exception (delete-file installed-rc-file))
+         (symlink #$rc-file installed-rc-file)
+
+         ;; Set the git configuration, to avoid gitolite trying to use
+         ;; the hostname command, as the network might not be up yet
+         (with-output-to-file #$(string-append home "/.gitconfig")
+           (lambda ()
+             (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+")))
+         ;; Run Gitolite setup, as this updates the hooks and the admin-pubkey
+         (let ((pid (primitive-fork)))
+           (if (eq? pid 0)
+               ;; Exit with a non-zero status code if an exception is thrown.
+               (dynamic-wind
+                 (const #t)
+                 (lambda ()
+                   (setenv "HOME" (passwd:dir user-info))
+                   (setenv "USER" #$user)
+                   (setgid (passwd:gid user-info))
+                   (setuid (passwd:uid user-info))
+                   (primitive-exit
+                    (system* #$(file-append package "/bin/gitolite")
+                             "setup"
+                             "-m" "gitolite setup by GNU Guix"
+                             "-pk" admin-pubkey)))
+                 (lambda ()
+                   (primitive-exit 1)))
+               (waitpid pid)))))))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)
+          (service-extension profile-service-type
+                             ;; The Gitolite package in Guix uses
+                             ;; gitolite-shell in the authorized_keys file, so
+                             ;; gitolite-shell needs to be on the PATH for
+                             ;; gitolite to work.
+                             (lambda (config)
+                               (list
+                                (gitolite-configuration-package config))))))
+   (description
+    "Setup @command{gitolite}, a Git hosting tool providing access over SSH..
+By default, the @code{git} user is used, but this is configurable.
+Additionally, Gitolite can integrate with with tools like gitweb or cgit to
+provide a web interface to view selected repositories.")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 3b935a1b4..4409b8a12 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017, 2018 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -27,14 +28,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -300,3 +304,111 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                           '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/test-admin")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/test-admin.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-assert "service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon))
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair
+                                         "/test-admin")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          (test-assert "cloning the admin repository"
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (test-assert "admin key exists"
+            (file-exists? "/tmp/clone/keydir/test-admin.pub"))
+
+          (with-directory-excursion "/tmp/clone"
+            (invoke #$(file-append git "/bin/git")
+                    "-c" "user.name=Guix" "-c" "user.email=guix"
+                    "commit"
+                    "-m" "Test commit"
+                    "--allow-empty")
+
+            (test-assert "pushing, and the associated hooks"
+              (invoke #$(file-append git "/bin/git") "push")))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Clone the Gitolite admin repository.")
+   (value (run-gitolite-test))))
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-30 23:39     ` Clément Lassieur
@ 2018-07-31 21:40       ` Christopher Baines
  2018-08-12 20:07         ` Clément Lassieur
  2018-09-22 16:03         ` [bug#30809] " Christopher Baines
  0 siblings, 2 replies; 32+ messages in thread
From: Christopher Baines @ 2018-07-31 21:40 UTC (permalink / raw)
  To: Clément Lassieur; +Cc: 30809

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


Clément Lassieur <clement@lassieur.org> writes:

> Hey Christopher!
>
> Thank you for the update.

Thanks for taking another look, I've sent some updated patches again.

> Christopher Baines <mail@cbaines.net> writes:
>
> [...]
>
>> +@example
>> +git clone git@@example.com:gitolite-admin
>> +@end example
>> +
>> +When the Gitolite service is activated, the provided @code{admin-pubkey} will
>> +be inserted in to the @file{keydir} directory in the gitolite-admin
>> +repository.  If this results in a change in the repository, it will be
>> +committed using the message ``gitolite setup by GNU Guix''.
>> +
>> +@deftp {Data Type} gitolite-configuration
>> +Data type representing the configuration for @code{gitolite-service-type}.
>> +
>> +@table @asis
>> +@item @code{package} (default: @var{gitolite})
>> +Gitolite package to use.
>> +
>> +@item @code{user} (default: @var{git})
>                                     ^
> It should be a string ---------------
>
> I don't think you should use @var for default values.  @code would be better.

Ah, ok, I think I've corrected these issues where appropriate.

>> +@item @code{admin-pubkey} (default: @var{#f})
>
> Actually, there is no default :-)

Good spot, I've removed it now.

>> +  (match-lambda
>> +    (($ <gitolite-configuration> package user group home
>> +                                 rc-file admin-pubkey)
>> +     #~(let* ((user-info (getpwnam #$user))
>> +              (admin-pubkey #$admin-pubkey)
>> +              (pubkey-file (string-append
>> +                            #$home "/"
>> +                            (basename
>> +                             (strip-store-file-name admin-pubkey)))))
>> +         (use-modules (guix build utils))
>> +
>> +         (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
>> +         (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
>                  ^
> Maybe a symlink here?

I had some concerns that the store item might be removed, but I guess it
must be safe as it's referenced by the activation script. I've now
changed it to use a symlink.

>> +         ;; The key must be writable, so copy it from the store
>> +         (copy-file admin-pubkey pubkey-file)
>> +
>> +         (chmod pubkey-file #o500)
>
> I don't think it must be writable, because #o500 isn't writable.

I can't quite remember why I added this... I've removed it, and
everything still seems to work.

>> +         ;; Run Gitolite setup, as this updates the hooks and include the
>> +         ;; admin pubkey if specified. The admin pubkey is required for
>> +         ;; initial setup, and will replace the previous key if run after
>> +         ;; initial setup
>> +         (let ((pid (primitive-fork)))
>> +           (if (eq? pid 0)
>> +               ;; Exit with a non-zero status code if an exception is thrown.
>> +               (dynamic-wind
>> +                 (const #t)
>> +                 (lambda ()
>> +                   (setenv "HOME" (passwd:dir user-info))
>> +                   (setenv "USER" #$user)
>> +                   (setgid (passwd:gid user-info))
>> +                   (setuid (passwd:uid user-info))
>> +                   (primitive-exit
>> +                    (system* #$(file-append package "/bin/gitolite")
>> +                             "setup"
>> +                             "-m" "gitolite setup by GNU Guix"
>> +                             "-pk" pubkey-file)))
>> +                 (lambda ()
>> +                   (primitive-exit 1)))
>> +               (waitpid pid)))
>
> This works (with the (ice-9 match) module added):

Unfortunately, when I try, I'm still hitting the same problem. To better
explain, match seems to run the code for the forked process, in both
processes. Adding in some peek statements [1] gives:

  ;;; ("FORK" 273)

  ;;; ("PID SHOULD BE 0")

  ;;; ("FORK" 0)

  ;;; ("PID SHOULD BE 0")

  [    1.817611] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000


This can't be due to a missing import, as removing the import gives a
different error message.

  Unbound variable: match
  [    1.638616] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000


I'm at a loss regarding what is going on here. I've tried testing on top
of 8b8978ade and a previous commit, I've also reproduced this on two
different computers.

I've pushed up a branch here [2] in case you're interested in checking
out the exact code I'm using.


1:
         (match (peek "FORK" (primitive-fork))
           (0
            ;; Exit with a non-zero status code if an exception is thrown.
            (dynamic-wind
              (const #t)
              (lambda ()
                (setenv "HOME" (passwd:dir user-info))
                (setenv "USER" #$user)
                (setgid (passwd:gid user-info))
                (setuid (passwd:uid user-info))
                (peek "PID SHOULD BE 0")
                (primitive-exit
                 (system* #$(file-append package "/bin/gitolite")
                          "setup"
                          "-m" "gitolite setup by GNU Guix"
                          "-pk" pubkey-file)))
              (lambda ()
                (primitive-exit 1))))
           (pid (waitpid (peek "WAITING FOR PID ->" pid))))

2: https://git.cbaines.net/guix/commit/?h=gitolite-service-broken-match&id=b70a26a7875e0d1106290d583ee34db7159bbf60

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

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-31 21:40       ` Christopher Baines
@ 2018-08-12 20:07         ` Clément Lassieur
  2018-08-19 16:12           ` Christopher Baines
  2018-09-22 16:03         ` [bug#30809] " Christopher Baines
  1 sibling, 1 reply; 32+ messages in thread
From: Clément Lassieur @ 2018-08-12 20:07 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809

Hello Christopher,

I often get:

    guix: gitolite: installing /gnu/store/hraw5zr6lp2w4v6czhvf1gp6phzxmzmj-gitolite.rc
    fatal: Unable to create '/var/lib/git/repositories/gitolite-admin.git/./index.lock': File exists.

While upgrading my gitolite service.  Did you encounter it?  Do you know
how to fix it?

Clément

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-08-12 20:07         ` Clément Lassieur
@ 2018-08-19 16:12           ` Christopher Baines
  2018-09-25 18:01             ` Nils Gillmann
  0 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-08-19 16:12 UTC (permalink / raw)
  To: Clément Lassieur; +Cc: 30809

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


Clément Lassieur <clement@lassieur.org> writes:

> Hello Christopher,
>
> I often get:
>
>     guix: gitolite: installing /gnu/store/hraw5zr6lp2w4v6czhvf1gp6phzxmzmj-gitolite.rc
>     fatal: Unable to create '/var/lib/git/repositories/gitolite-admin.git/./index.lock': File exists.
>
> While upgrading my gitolite service.  Did you encounter it?  Do you know
> how to fix it?

I don't think I've seen this. It could be if something has gone wrong
with git, it's left the lockfile around. Perhaps before you next
reconfigure, check if the lockfile exists, and then assuming git isn't
running, delete it.

Do say if it keeps happening though.

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

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

* [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
  2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
                   ` (6 preceding siblings ...)
  2018-07-31 21:39 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-09-22 15:14 ` Christopher Baines
  2018-09-22 15:14   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
  7 siblings, 1 reply; 32+ messages in thread
From: Christopher Baines @ 2018-09-22 15:14 UTC (permalink / raw)
  To: 30809

Previously the gitolite package worked, but there were problems using it for
the service where you might have a minimal PATH. This commit patches the
source and scripts where possible to use store paths, and also wraps the
gitolite script to handle the harder dependencies.

* gnu/packages/version-control.scm (gitolite)[arguments]: Add more patching to
the patch-scripts phase, and add two new phases (patch-source and
wrap-scripts).
[inputs]: Add coreutils, findutils and inetutils.
---
 gnu/packages/version-control.scm | 53 +++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 58c870df5..c45610f2b 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -1031,12 +1031,48 @@ also walk each side of a merge and test those changes individually.")
                           ((" perl -")
                            (string-append " " perl " -")))
 
+                        (substitute* (find-files "src/triggers" ".*")
+                          ((" sed ")
+                           (string-append " " (which "sed") " ")))
+
+                        (substitute*
+                            '("src/triggers/post-compile/update-gitweb-access-list"
+                              "src/triggers/post-compile/ssh-authkeys-split"
+                              "src/triggers/upstream")
+                          ((" grep ")
+                           (string-append " " (which "grep") " ")))
+
                         ;; Avoid references to the store in authorized_keys.
                         ;; This works because gitolite-shell is in the PATH.
                         (substitute* "src/triggers/post-compile/ssh-authkeys"
                           (("\\$glshell \\$user")
                            "gitolite-shell $user"))
                         #t)))
+                  (add-before 'install 'patch-source
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      ;; Gitolite uses cat to test the readability of the
+                      ;; pubkey
+                      (substitute* "src/lib/Gitolite/Setup.pm"
+                        (("\"cat ")
+                         (string-append "\"" (which "cat") " "))
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen"))))
+
+                      (substitute* '("src/lib/Gitolite/Hooks/PostUpdate.pm"
+                                     "src/lib/Gitolite/Hooks/Update.pm")
+                        (("/usr/bin/perl")
+                         (string-append (assoc-ref inputs "perl")
+                                        "/bin/perl")))
+
+                      (substitute* "src/lib/Gitolite/Common.pm"
+                        (("\"ssh-keygen")
+                         (string-append "\"" (which "ssh-keygen")))
+                        (("\"logger\"")
+                         (string-append "\""
+                                        (assoc-ref inputs "inetutils")
+                                        "/bin/logger\"")))
+
+                      #t))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
@@ -1050,9 +1086,24 @@ also walk each side of a merge and test those changes individually.")
                                     (symlink (string-append sharedir "/" script)
                                              (string-append bindir "/" script)))
                                   '("gitolite" "gitolite-shell"))
+                        #t)))
+                  (add-after 'install 'wrap-scripts
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (let ((out (assoc-ref outputs "out"))
+                            (coreutils (assoc-ref inputs "coreutils"))
+                            (findutils (assoc-ref inputs "findutils"))
+                            (git (assoc-ref inputs "git")))
+                        (wrap-program (string-append out "/bin/gitolite")
+                          `("PATH" ":" prefix
+                            ,(map (lambda (dir)
+                                    (string-append dir "/bin"))
+                                  (list out coreutils findutils git))))
                         #t))))))
     (inputs
-     `(("perl" ,perl)))
+     `(("perl" ,perl)
+       ("coreutils" ,coreutils)
+       ("findutils" ,findutils)
+       ("inetutils" ,inetutils)))
     ;; git and openssh are propagated because trying to patch the source via
     ;; regexp matching is too brittle and prone to false positives.
     (propagated-inputs
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-09-22 15:14 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
@ 2018-09-22 15:14   ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-09-22 15:14 UTC (permalink / raw)
  To: 30809

* gnu/services/version-control.scm (<gitolite-configuration>,
<gitolite-rc-file>): New record types.
(gitolite-accounts, gitolite-activation): New procedures.
(gitolite-service-type): New variables.
* gnu/tests/version-control.scm (%gitolite-test-admin-keypair, %gitolite-os,
%test-gitolite): New variables.
(run-gitolite-test): New procedure.
* doc/guix.texi (Version Control): Document the gitolite service.
---
 doc/guix.texi                    |  94 ++++++++++++++++
 gnu/services/version-control.scm | 179 ++++++++++++++++++++++++++++++-
 gnu/tests/version-control.scm    | 114 +++++++++++++++++++-
 3 files changed, 385 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 76ec718b0..4c0b38a00 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -20948,6 +20948,100 @@ could instantiate a cgit service like this:
           (cgitrc "")))
 @end example
 
+@subsubheading Gitolite Service
+
+@cindex Gitolite service
+@cindex Git, hosting
+@uref{http://gitolite.com/gitolite/, Gitolite} is a tool for hosting Git
+repositories on a central server.
+
+Gitolite can handle multiple repositories and users, and supports flexible
+configuration of the permissions for the users on the repositories.
+
+The following example will configure Gitolite using the default @code{git}
+user, and the provided SSH public key.
+
+@example
+(service gitolite-service-type
+         (gitolite-configuration
+           (admin-pubkey (plain-file
+                           "yourname.pub"
+                           "ssh-rsa AAAA... guix@@example.com"))))
+@end example
+
+Gitolite is configured through a special admin repository which you can clone,
+for example, if you setup Gitolite on @code{example.com}, you would run the
+following command to clone the admin repository.
+
+@example
+git clone git@@example.com:gitolite-admin
+@end example
+
+When the Gitolite service is activated, the provided @code{admin-pubkey} will
+be inserted in to the @file{keydir} directory in the gitolite-admin
+repository.  If this results in a change in the repository, it will be
+committed using the message ``gitolite setup by GNU Guix''.
+
+@deftp {Data Type} gitolite-configuration
+Data type representing the configuration for @code{gitolite-service-type}.
+
+@table @asis
+@item @code{package} (default: @var{gitolite})
+Gitolite package to use.
+
+@item @code{user} (default: @var{git})
+User to use for Gitolite.  This will be user that you use when accessing
+Gitolite over SSH.
+
+@item @code{group} (default: @var{git})
+Group to use for Gitolite.
+
+@item @code{home-directory} (default: @var{"/var/lib/gitolite"})
+Directory in which to store the Gitolite configuration and repositories.
+
+@item @code{rc-file} (default: @var{(gitolite-rc-file)})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}),
+representing the configuration for Gitolite.
+
+@item @code{admin-pubkey} (default: @var{#f})
+A ``file-like'' object (@pxref{G-Expressions, file-like objects}) used to
+setup Gitolite.  This will be inserted in to the @file{keydir} directory
+within the gitolite-admin repository.
+
+To specify the SSH key as a string, use the @code{plain-file} function.
+
+@example
+(plain-file "yourname.pub" "ssh-rsa AAAA... guix@@example.com")
+@end example
+
+@end table
+@end deftp
+
+@deftp {Data Type} gitolite-rc-file
+Data type representing the Gitolite RC file.
+
+@table @asis
+@item @code{umask} (default: @code{#o0077})
+This controls the permissions Gitolite sets on the repositories and their
+contents.
+
+A value like @code{#o0027} will give read access to the group used by Gitolite
+(by default: @code{git}). This is necessary when using Gitolite with software
+like cgit or gitweb.
+
+@item @code{git-config-keys} (default: @code{""})
+Gitolite allows you to set git config values using the "config" keyword. This
+setting allows control over the config keys to accept.
+
+@item @code{roles} (default: @code{'(("READERS" . 1) ("WRITERS" . ))})
+Set the role names allowed to be used by users running the perms command.
+
+@item @code{enable} (default: @code{'("help" "desc" "info" "perms" "writable" "ssh-authkeys" "git-config" "daemon" "gitweb")})
+This setting controls the commands and features to enable within Gitolite.
+
+@end table
+@end deftp
+
 
 @node Game Services
 @subsubsection Game Services
diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
index 58274c8be..cc8cd2202 100644
--- a/gnu/services/version-control.scm
+++ b/gnu/services/version-control.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
 ;;; Copyright © 2017 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -40,7 +41,23 @@
 
             git-http-configuration
             git-http-configuration?
-            git-http-nginx-location-configuration))
+            git-http-nginx-location-configuration
+
+            <gitolite-configuration>
+            gitolite-configuration
+            gitolite-configuration-package
+            gitolite-configuration-user
+            gitolite-configuration-rc-file
+            gitolite-configuration-admin-pubkey
+
+            <gitolite-rc-file>
+            gitolite-rc-file
+            gitolite-rc-file-umask
+            gitolite-rc-file-git-config-keys
+            gitolite-rc-file-roles
+            gitolite-rc-file-enable
+
+            gitolite-service-type))
 
 ;;; Commentary:
 ;;;
@@ -197,3 +214,163 @@ access to exported repositories under @file{/srv/git}."
             "")
         (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";")
         "fastcgi_param PATH_INFO $1;"))))))
+
+\f
+;;;
+;;; Gitolite
+;;;
+
+(define-record-type* <gitolite-rc-file>
+  gitolite-rc-file make-gitolite-rc-file
+  gitolite-rc-file?
+  (umask           gitolite-rc-file-umask
+                   (default #o0077))
+  (git-config-keys gitolite-rc-file-git-config-keys
+                   (default ""))
+  (roles           gitolite-rc-file-roles
+                   (default '(("READERS" . 1)
+                              ("WRITERS" . 1))))
+  (enable          gitolite-rc-file-enable
+                   (default '("help"
+                              "desc"
+                              "info"
+                              "perms"
+                              "writable"
+                              "ssh-authkeys"
+                              "git-config"
+                              "daemon"
+                              "gitweb"))))
+
+(define-gexp-compiler (gitolite-rc-file-compiler
+                       (file <gitolite-rc-file>) system target)
+  (match file
+    (($ <gitolite-rc-file> umask git-config-keys roles enable)
+     (apply text-file* "gitolite.rc"
+      `("%RC = (\n"
+        "    UMASK => " ,(format #f "~4,'0o" umask) ",\n"
+        "    GIT_CONFIG_KEYS => '" ,git-config-keys "',\n"
+        "    ROLES => {\n"
+        ,@(map (match-lambda
+                 ((role . value)
+                  (simple-format #f "        ~A => ~A,\n" role value)))
+               roles)
+        "    },\n"
+        "\n"
+        "    ENABLE => [\n"
+        ,@(map (lambda (value)
+                 (simple-format #f "        '~A',\n" value))
+               enable)
+        "    ],\n"
+        ");\n"
+        "\n"
+        "1;\n")))))
+
+(define-record-type* <gitolite-configuration>
+  gitolite-configuration make-gitolite-configuration
+  gitolite-configuration?
+  (package        gitolite-configuration-package
+                  (default gitolite))
+  (user           gitolite-configuration-user
+                  (default "git"))
+  (group          gitolite-configuration-group
+                  (default "git"))
+  (home-directory gitolite-configuration-home-directory
+                  (default "/var/lib/gitolite"))
+  (rc-file        gitolite-configuration-rc-file
+                  (default (gitolite-rc-file)))
+  (admin-pubkey   gitolite-configuration-admin-pubkey))
+
+(define gitolite-accounts
+  (match-lambda
+    (($ <gitolite-configuration> package user group home-directory
+                                 rc-file admin-pubkey)
+     ;; User group and account to run Gitolite.
+     (list (user-group (name user) (system? #t))
+           (user-account
+            (name user)
+            (group group)
+            (system? #t)
+            (comment "Gitolite user")
+            (home-directory home-directory))))))
+
+(define gitolite-activation
+  (match-lambda
+    (($ <gitolite-configuration> package user group home
+                                 rc-file admin-pubkey)
+     #~(begin
+         (use-modules (ice-9 match)
+                      (guix build utils))
+
+         (let* ((user-info (getpwnam #$user))
+                (admin-pubkey #$admin-pubkey)
+                (pubkey-file (string-append
+                              #$home "/"
+                              (basename
+                               (strip-store-file-name admin-pubkey)))))
+
+           (simple-format #t "guix: gitolite: installing ~A\n" #$rc-file)
+           (copy-file #$rc-file #$(string-append home "/.gitolite.rc"))
+
+           ;; The key must be writable, so copy it from the store
+           (copy-file admin-pubkey pubkey-file)
+
+           (chmod pubkey-file #o500)
+           (chown pubkey-file
+                  (passwd:uid user-info)
+                  (passwd:gid user-info))
+
+           ;; Set the git configuration, to avoid gitolite trying to use
+           ;; the hostname command, as the network might not be up yet
+           (with-output-to-file #$(string-append home "/.gitconfig")
+             (lambda ()
+               (display "[user]
+        name = GNU Guix
+        email = guix@localhost
+")))
+           ;; Run Gitolite setup, as this updates the hooks and include the
+           ;; admin pubkey if specified. The admin pubkey is required for
+           ;; initial setup, and will replace the previous key if run after
+           ;; initial setup
+           (match (primitive-fork)
+             (0
+              ;; Exit with a non-zero status code if an exception is thrown.
+              (dynamic-wind
+                (const #t)
+                (lambda ()
+                  (setenv "HOME" (passwd:dir user-info))
+                  (setenv "USER" #$user)
+                  (setgid (passwd:gid user-info))
+                  (setuid (passwd:uid user-info))
+                  (primitive-exit
+                   (system* #$(file-append package "/bin/gitolite")
+                            "setup"
+                            "-m" "gitolite setup by GNU Guix"
+                            "-pk" pubkey-file)))
+                (lambda ()
+                  (primitive-exit 1))))
+             (pid (waitpid pid)))
+
+           (when (file-exists? pubkey-file)
+             (delete-file pubkey-file)))))))
+
+(define gitolite-service-type
+  (service-type
+   (name 'gitolite)
+   (extensions
+    (list (service-extension activation-service-type
+                             gitolite-activation)
+          (service-extension account-service-type
+                             gitolite-accounts)
+          (service-extension profile-service-type
+                             ;; The Gitolite package in Guix uses
+                             ;; gitolite-shell in the authorized_keys file, so
+                             ;; gitolite-shell needs to be on the PATH for
+                             ;; gitolite to work.
+                             (lambda (config)
+                               (list
+                                (gitolite-configuration-package config))))))
+   (description
+    "Setup @command{gitolite}, a Git hosting tool providing access over SSH..
+By default, the @code{git} user is used, but this is configurable.
+Additionally, Gitolite can integrate with with tools like gitweb or cgit to
+provide a web interface to view selected repositories.")))
diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm
index 3b935a1b4..4409b8a12 100644
--- a/gnu/tests/version-control.scm
+++ b/gnu/tests/version-control.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017, 2018 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2017, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
+;;; Copyright © 2018 Christopher Baines <mail@cbaines.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -27,14 +28,17 @@
   #:use-module (gnu services)
   #:use-module (gnu services version-control)
   #:use-module (gnu services cgit)
+  #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:use-module (gnu services networking)
   #:use-module (gnu packages version-control)
+  #:use-module (gnu packages ssh)
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix modules)
   #:export (%test-cgit
-            %test-git-http))
+            %test-git-http
+            %test-gitolite))
 
 (define README-contents
   "Hello!  This is what goes inside the 'README' file.")
@@ -300,3 +304,111 @@ HTTP-PORT."
    (name "git-http")
    (description "Connect to a running Git HTTP server.")
    (value (run-git-http-test))))
+
+\f
+;;;
+;;; Gitolite.
+;;;
+
+(define %gitolite-test-admin-keypair
+  (computed-file
+   "gitolite-test-admin-keypair"
+   (with-imported-modules (source-module-closure
+                           '((guix build utils)))
+     #~(begin
+         (use-modules (ice-9 match) (srfi srfi-26)
+                      (guix build utils))
+
+         (mkdir #$output)
+         (invoke #$(file-append openssh "/bin/ssh-keygen")
+                 "-f" (string-append #$output "/test-admin")
+                 "-t" "rsa"
+                 "-q"
+                 "-N" "")))))
+
+(define %gitolite-os
+  (simple-operating-system
+   (dhcp-client-service)
+   (service openssh-service-type)
+   (service gitolite-service-type
+            (gitolite-configuration
+             (admin-pubkey
+              (file-append %gitolite-test-admin-keypair "/test-admin.pub"))))))
+
+(define (run-gitolite-test)
+  (define os
+    (marionette-operating-system
+     %gitolite-os
+     #:imported-modules '((gnu services herd)
+                          (guix combinators))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings `((2222 . 22)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build utils))
+      #~(begin
+          (use-modules (srfi srfi-64)
+                       (rnrs io ports)
+                       (gnu build marionette)
+                       (guix build utils))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "gitolite")
+
+          ;; Wait for sshd to be up and running.
+          (test-assert "service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'ssh-daemon))
+             marionette))
+
+          (display #$%gitolite-test-admin-keypair)
+
+          (setenv "GIT_SSH_VARIANT" "ssh")
+          (setenv "GIT_SSH_COMMAND"
+                  (string-join
+                   '(#$(file-append openssh "/bin/ssh")
+                     "-i" #$(file-append %gitolite-test-admin-keypair
+                                         "/test-admin")
+                     "-o" "UserKnownHostsFile=/dev/null"
+                     "-o" "StrictHostKeyChecking=no")))
+
+          (test-assert "cloning the admin repository"
+            (invoke #$(file-append git "/bin/git")
+                    "clone" "-v"
+                    "ssh://git@localhost:2222/gitolite-admin"
+                    "/tmp/clone"))
+
+          (test-assert "admin key exists"
+            (file-exists? "/tmp/clone/keydir/test-admin.pub"))
+
+          (with-directory-excursion "/tmp/clone"
+            (invoke #$(file-append git "/bin/git")
+                    "-c" "user.name=Guix" "-c" "user.email=guix"
+                    "commit"
+                    "-m" "Test commit"
+                    "--allow-empty")
+
+            (test-assert "pushing, and the associated hooks"
+              (invoke #$(file-append git "/bin/git") "push")))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "gitolite" test))
+
+(define %test-gitolite
+  (system-test
+   (name "gitolite")
+   (description "Clone the Gitolite admin repository.")
+   (value (run-gitolite-test))))
-- 
2.18.0

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-07-31 21:40       ` Christopher Baines
  2018-08-12 20:07         ` Clément Lassieur
@ 2018-09-22 16:03         ` Christopher Baines
  1 sibling, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-09-22 16:03 UTC (permalink / raw)
  To: 30809; +Cc: Clément Lassieur

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


Christopher Baines <mail@cbaines.net> writes:

> I'm at a loss regarding what is going on here. I've tried testing on top
> of 8b8978ade and a previous commit, I've also reproduced this on two
> different computers.

Right, I think I've found a work around this problem!

Previously the activation gexp was like:

  #~(let* ...
      (use-modules (ice-9 match)
                   (guix build utils))


      ...

      (match ...
        ))

This seems to break, no idea why, but I think it's something to do with
the mystery of macros in Scheme/Guile.

I had a look at how other services were using primitive-fork, and the
PostgreSQL service does. However, it's activation gexp looks more like:

  #~(begin
      (use-modules (ice-9 match)
                   (guix build utils))

      (let ...
        ...

        (match ...
          )))

So, I switched the gitolite activation phase around to use a begin as
the outer expression (rather than the let*), and it seems to work!

I've sent the patches again.

Chris

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

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

* [bug#30809] [PATCH 2/2] services: Add Gitolite.
  2018-08-19 16:12           ` Christopher Baines
@ 2018-09-25 18:01             ` Nils Gillmann
  2018-09-28 20:28               ` bug#30809: " Christopher Baines
  0 siblings, 1 reply; 32+ messages in thread
From: Nils Gillmann @ 2018-09-25 18:01 UTC (permalink / raw)
  To: Christopher Baines; +Cc: 30809, Clément Lassieur

Christopher Baines transcribed 1.8K bytes:
> 
> Clément Lassieur <clement@lassieur.org> writes:
> 
> > Hello Christopher,
> >
> > I often get:
> >
> >     guix: gitolite: installing /gnu/store/hraw5zr6lp2w4v6czhvf1gp6phzxmzmj-gitolite.rc
> >     fatal: Unable to create '/var/lib/git/repositories/gitolite-admin.git/./index.lock': File exists.
> >
> > While upgrading my gitolite service.  Did you encounter it?  Do you know
> > how to fix it?
> 
> I don't think I've seen this. It could be if something has gone wrong
> with git, it's left the lockfile around. Perhaps before you next
> reconfigure, check if the lockfile exists, and then assuming git isn't
> running, delete it.
> 
> Do say if it keeps happening though.


Hi Christopher,

until end of october Taler needs to migrate servers, and I am
responsible to move it to GuixSD. Gitolite is a critical and
essential part of the infrastructure.

Do you think the gitolite service is (mostly) ready to be deployed or
have you encountered any bugs with it?


Thanks for your work on it!

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

* bug#30809: [PATCH 2/2] services: Add Gitolite.
  2018-09-25 18:01             ` Nils Gillmann
@ 2018-09-28 20:28               ` Christopher Baines
  0 siblings, 0 replies; 32+ messages in thread
From: Christopher Baines @ 2018-09-28 20:28 UTC (permalink / raw)
  To: Nils Gillmann; +Cc: 30809-done

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


Nils Gillmann <ng0@n0.is> writes:

> Christopher Baines transcribed 1.8K bytes:
>>
>> Clément Lassieur <clement@lassieur.org> writes:
>>
>> > Hello Christopher,
>> >
>> > I often get:
>> >
>> >     guix: gitolite: installing /gnu/store/hraw5zr6lp2w4v6czhvf1gp6phzxmzmj-gitolite.rc
>> >     fatal: Unable to create '/var/lib/git/repositories/gitolite-admin.git/./index.lock': File exists.
>> >
>> > While upgrading my gitolite service.  Did you encounter it?  Do you know
>> > how to fix it?
>>
>> I don't think I've seen this. It could be if something has gone wrong
>> with git, it's left the lockfile around. Perhaps before you next
>> reconfigure, check if the lockfile exists, and then assuming git isn't
>> running, delete it.
>>
>> Do say if it keeps happening though.
>
>
> Hi Christopher,
>
> until end of october Taler needs to migrate servers, and I am
> responsible to move it to GuixSD. Gitolite is a critical and
> essential part of the infrastructure.
>
> Do you think the gitolite service is (mostly) ready to be deployed or
> have you encountered any bugs with it?

Well, it's in master now (as of a few minutes ago), so I'd suggest
giving it a go.

The Guix service is just a thin wrapper around Gitolite to get it going,
so hopefully not much can go wrong. I'm not sure if necessarily all the
features of Gitolite work in the package (as the service runs in a more
minimal environment that a normal user may have). But, hopefully it will
just work fine :)

1: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=30809#80

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

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

end of thread, other threads:[~2018-09-28 20:29 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-03-13 21:35 [bug#30809] [PATCH] Gitolite service Christopher Baines
2018-03-13 21:39 ` [bug#30809] [PATCH 1/2] services: Add gitolite Christopher Baines
2018-03-13 21:39   ` [bug#30809] [PATCH 2/2] WIP: gitolite package changes to make the service work Christopher Baines
2018-07-13 19:41 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
2018-07-13 19:41   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
2018-07-13 23:15     ` Oleg Pykhalov
2018-07-14  6:31       ` Christopher Baines
2018-07-13 20:01 ` [bug#30809] Fwd: " Christopher Baines
2018-07-14  6:28 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
2018-07-14  6:28   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
2018-07-22 22:30     ` Clément Lassieur
2018-07-23 22:06       ` Christopher Baines
2018-07-22 22:26   ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Clément Lassieur
2018-07-23 22:10     ` Christopher Baines
2018-07-23 21:43 ` Christopher Baines
2018-07-23 21:43   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
2018-07-24  9:23     ` Clément Lassieur
2018-07-29 20:45       ` Christopher Baines
2018-07-30 18:26         ` Clément Lassieur
2018-07-29 20:18 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
2018-07-29 20:18   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
2018-07-30 23:39     ` Clément Lassieur
2018-07-31 21:40       ` Christopher Baines
2018-08-12 20:07         ` Clément Lassieur
2018-08-19 16:12           ` Christopher Baines
2018-09-25 18:01             ` Nils Gillmann
2018-09-28 20:28               ` bug#30809: " Christopher Baines
2018-09-22 16:03         ` [bug#30809] " Christopher Baines
2018-07-31 21:39 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
2018-07-31 21:39   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines
2018-09-22 15:14 ` [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service Christopher Baines
2018-09-22 15:14   ` [bug#30809] [PATCH 2/2] services: Add Gitolite Christopher Baines

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).