[PATCH] Gitolite service

  • Done
  • quality assurance status badge
Details
4 participants
  • Clément Lassieur
  • Oleg Pykhalov
  • Christopher Baines
  • Nils Gillmann
Owner
unassigned
Submitted by
Christopher Baines
Severity
normal
C
C
Christopher Baines wrote on 13 Mar 2018 22:35
(address . guix-patches@gnu.org)
87woyfzmir.fsf@cbaines.net
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.
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAlqoRDxfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XchzxAAnvJ+nsDRzwk0oHCyemWfu9qLdKWxz9eysu0mh755ChGHCYtk41MbJ+QZ
FLOBjzM7dvJ4Lmv0ctlRpw/7pA5CY10IcvgEzPuDXNhN6UnMAnPBKSxdHnQ2NZI8
fYHCvXiU6wHI4e+v/cuY+v7FMhW8ip9vS9Ie6As1v6fmY19Cf239hB3X4KBw59nO
gIz+urztxCY6EqIKwauqO3dot515xYGxdMVza+gbWKSuFGEEUXAOT68uU9HazCeD
1D8g6ElAJfH+ejcRI2Kl6FbyzmWSGyNH4/ROJVP8YkvuS72oRzntxsZZ1r8MCbxK
JSKjffyK2a/X6ra28XnU5wr7/UdfQ6OAQ9sDq849zyCQLo2xQFau1S3czL6Z9Vhi
/Fxq+Yv9lvOfT1HzzXvQVamhWxyDvI43q+XbEmKooN15sK9h7081NN0OQC+tFGUq
NY/XGLgGtTQMChbB2Q4XA+FxIXuIpH2mcAkC+ZrJY3kp35+qgGGL52TSxTDMKyA+
ob6TVNqbXl4cOPaH+Q7FSGdR2bYpXUDteCh4Nc99/+Bz2ORXSjs6uJoe7qamFJjI
rrUzwioTHR0o052rFUNuvafySdi7AbaFSSUWlvRsAWeWeeBbY8Y0YUIRa/BGyCiE
uh6jmH3GrGk/8wxQNLujzttGhcAl3TY1O4t8d5siFLm4sAFPvas=
=Pqym
-----END PGP SIGNATURE-----

C
C
Christopher Baines wrote on 13 Mar 2018 22:39
[PATCH 2/2] WIP: gitolite package changes to make the service work.
(address . 30809@debbugs.gnu.org)
20180313213933.11268-2-mail@cbaines.net
---
gnu/packages/version-control.scm | 37 ++++++++++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 5 deletions(-)

Toggle diff (58 lines)
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
C
C
Christopher Baines wrote on 13 Mar 2018 22:39
[PATCH 1/2] services: Add gitolite.
(address . 30809@debbugs.gnu.org)
20180313213933.11268-1-mail@cbaines.net
---
gnu/services/version-control.scm | 158 ++++++++++++++++++++++++++++++++++++++-
gnu/tests/version-control.scm | 103 ++++++++++++++++++++++++-
2 files changed, 259 insertions(+), 2 deletions(-)

Toggle diff (300 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 13 Jul 2018 21:41
[PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
20180713194101.14891-2-mail@cbaines.net
* 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(-)

Toggle diff (413 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 13 Jul 2018 21:41
[PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(address . 30809@debbugs.gnu.org)
20180713194101.14891-1-mail@cbaines.net
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(-)

Toggle diff (80 lines)
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
C
C
Christopher Baines wrote on 13 Jul 2018 22:01
Fwd: [bug#30809] [PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
87zhyuewgz.fsf@cbaines.net
Christopher Baines <mail@cbaines.net> writes:

Toggle quote (14 lines)
> * 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.
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAltJBR1fFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XdQ1g//cX/8vFbSlNhf+M/JD3HdAMHf9A5lVz9OOmXHXMNbjFSzfB4gCEkGws/t
B3tV2DcbIysezItqEe9SDyVSa/5DBevJ+uplsbRMSdFto1bOcCijPROjNExHznXl
cGWLX4cvl7ZujmF5UnkZ0QpHTgT3/RmhpCuGdoHsdIRDMWCKo5I/fyKz+UgJxvlK
dIcqIKfctX1sjLQxIfc2ZicpdffhUcAvQJIeqsIL9Q+4BcgEK29d27EDsYKZhS8A
6mKboyFviUloeZZLw98J6hz8rFnfqlnAcm1Ea8/SKMPVUbuBb15L2NYam6LbP3WE
hRuOS5IJucYdFgceBUaRV/VMhGbyVVCaj1AFl9V+qMluLFOY431782aRRiNSLoYp
izQ6hbVZq9iAFCcafLOS8jEkZ7ixb5Jg63Dr64W1LKnEUMolVK0ryTHYHscJjrmO
IbWXWOKqfSGAZKU3p5eYfft0ioSli6HSrzIW/a7i8Tq7Y0Ovk9StewtD63ivGBeW
uuowvL/vgAIwic/nGY0vFySbUy87RixwonVhhJS0y4n8G9aI+HLTzwX4CV0WbpGP
ddiV/LaCKjziXjmxWFaV65a6udx2dgsSNzEmGmxlNhDIn3s6+UOxr+5oBh9fYLgB
BWFiH/a8MHSKfbI2SZ0I8YesMDlyWMmWOPyeBHOC2fz0RWutW/k=
=mJzs
-----END PGP SIGNATURE-----

O
O
Oleg Pykhalov wrote on 14 Jul 2018 01:15
Re: [bug#30809] [PATCH 2/2] services: Add Gitolite.
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87wotyg226.fsf@gmail.com
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:

Toggle quote (14 lines)
> * 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(-)

[…]

Toggle quote (6 lines)
> +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.
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEc+OyAXw1EaDPCmAPckbhHGm3lWkFAltJMpEACgkQckbhHGm3
lWk9OxAAyUre6UB2LbiZ7qZDBeyp3CM2ksu/7S43MELrfEUmyEFN2xNJzzCfdGN0
SSBnjqRZ7BMD6fzLQ3Q5Q7qruLLmoc6B+dbFhOKw2JtndMuwvIJXgRemIBFsL8TR
gM/gn2wdZmScG73Hk7b7MWrtOj6w+b/88AnUz7WxmAGBeKhw+2B6d88z+htp1/6l
i1w9PActkZaJlJSElx7+76kCrfYs7oYImLLSyYMCki8jr/Fz56+Av4vh9kWfDf3d
AjH8BoZXr/5JhyxNAj0KPDBTzqoiWYzhLw6o2CH8/pvJrYzT7X6t0LO89f5q5NLS
w7XOGMAxXHW5HYyNo28oyRZZWkRnBfqwrGF7nGvdsUgeEy3e4DC8ekDMKUHJ+Bw2
XV2AH2pqaGZSqgDhqm1b5XEyaf7YB0k0VBqn8blYwJl3aZE8a0uYuQIvCYpIi/kK
tcoPm0goWG2l1b6K/eHeXWee+zF+dpxYO4gJGddzB1eSx4Y6XDrbTZvTEhPuoDHG
SFt/jkQfp/zJWEahBxXZiX0Lnj9+ShuKlGBFK/NDDNMmHMEIfXfvLR/YqaHBcpGR
Sw/VVC6vMFjuQzFpbuDmBV7x/kCuJgTqgSlOiGU4G9Lg5KH5mFe+DRE05rPiatYX
NgnFhQmjYimJ9SQqlUGenNxHpsVAUAH+rt7/cWhR/GBKkJ7KNmI=
=R9cx
-----END PGP SIGNATURE-----

C
C
Christopher Baines wrote on 14 Jul 2018 08:28
[PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
20180714062855.18705-2-mail@cbaines.net
* 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(-)

Toggle diff (412 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 14 Jul 2018 08:28
[PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(address . 30809@debbugs.gnu.org)
20180714062855.18705-1-mail@cbaines.net
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(-)

Toggle diff (80 lines)
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
C
C
Christopher Baines wrote on 14 Jul 2018 08:31
Re: [bug#30809] [PATCH 2/2] services: Add Gitolite.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 30809@debbugs.gnu.org)
87y3eee3b7.fsf@cbaines.net
Oleg Pykhalov <go.wigust@gmail.com> writes:

Toggle quote (5 lines)
> 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 :)

Toggle quote (14 lines)
> 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
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAltJmLxfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XfIHBAAuUTKvQ+u7huq4jX/5twiSXLK/1a48P3nXO1nzd06YJbeDjphGOG9BjU2
XbKiwcBrZkvXDgjl/3JMM2/ZKWqCbu1wpwyGrYt6j+uYXF7TN4vng3ixmhXujBAR
dmb2KQOUWyWWrRPlVgia5kf6YHNoCS+cHUZr2hjMEzEpArZpW5nRSn5c1x3D0X6J
VYGA4Gz/XWG8+5K3JQaX+OdBT5eCmGbZz51TnMphtl0B9OZ6KJgAtvx23sqwoZua
o1QtSX1PJe0/La7p9qjzSE/WQVDM1O3aYqYIdyu3pfg858zVEHwToo9CkJIMaK2D
DDj4U9jGdcQQ3G76oWb+Wzh8yXSGerfNXJYiiXMw6gkXa2er9GKDHPXkkV8qfC5r
1ML/dkfrAE2znkGn8MOPtjqm+BUxIQh8uQc9OIlI+Z84EySdH4egGthutXNInKby
TKIEAVS5EBz8xLQI0Z8MplFnEM3PmCY8eJL4oYWbGT95ewjW8cdUYPTcZr0UJNNy
JmODYHi2dgYptvuo/U8YOWNn+MIWGOeyRLxyo1kAN0/Wib37DiMZ/GS/jG1VqqYS
NWFvyZiUX7H1DXTqiJmbjLIdy11dNh2pK6p7/eJX17qQipyTCuH5Il7CqnIrj23x
ZOLvoh8/7kSDORNEs9Djh47ax2DRLRu5KS/QCUwbQ4hGLVRxu/E=
=cyFi
-----END PGP SIGNATURE-----

C
C
Clément Lassieur wrote on 23 Jul 2018 00:26
Re: [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87wotmq54x.fsf@lassieur.org
Hi Christopher!

Christopher Baines <mail@cbaines.net> writes:

Toggle quote (13 lines)
> 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(-)

[...]

Toggle quote (24 lines)
> (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)

Toggle quote (12 lines)
> +
> + #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!
C
C
Clément Lassieur wrote on 23 Jul 2018 00:30
Re: [bug#30809] [PATCH 2/2] services: Add Gitolite.
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87va96q4ye.fsf@lassieur.org
Christopher Baines <mail@cbaines.net> writes:

Toggle quote (14 lines)
> * 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 :-)

[...]

Toggle quote (5 lines)
> +@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.

[...]

Toggle quote (20 lines)
> +(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.

Toggle quote (12 lines)
> + (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?

Toggle quote (42 lines)
> + (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")))))))

[...]

Toggle quote (2 lines)
> diff --git a/gnu/tests/version-control.scm b/gnu/tests/version-control.scm

Could you add your copyright header for this file?

Toggle quote (37 lines)
> 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))))
> +
> +
> +;;;
> +;;; 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 ;-)

Toggle quote (11 lines)
> + #~(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" "")))))

[...]

Toggle quote (27 lines)
> + (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.

Toggle quote (29 lines)
> + (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/25957and
https://bugs.gnu.org/30401? Do you know if they are still here?

Thank you very much!
Clément
C
C
Christopher Baines wrote on 23 Jul 2018 23:43
[PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(address . 30809@debbugs.gnu.org)
20180723214328.18740-1-mail@cbaines.net
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(-)

Toggle diff (81 lines)
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
C
C
Christopher Baines wrote on 23 Jul 2018 23:43
[PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
20180723214328.18740-2-mail@cbaines.net
* 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(-)

Toggle diff (451 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 24 Jul 2018 00:06
(name . Clément Lassieur)(address . clement@lassieur.org)(address . 30809@debbugs.gnu.org)
87efftwqrs.fsf@cbaines.net
Clément Lassieur <clement@lassieur.org> writes:

Toggle quote (18 lines)
> 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.

Toggle quote (8 lines)
>> +@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.

Toggle quote (23 lines)
>> +(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.

Toggle quote (19 lines)
>> + (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.

Toggle quote (48 lines)
>> + (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 :)

Toggle quote (40 lines)
>> 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))))
>> +
>> +
>> +;;;
>> +;;; 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.

Toggle quote (17 lines)
>> + ;; 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.

Toggle quote (32 lines)
>> + (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.
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAltWUXdfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XcK9hAAuSreMgaYFT3/ucaBw+dMXq95+bFtXHXmhuYTFQGJgsj3+ifRbANMV4DG
S4WtwBk8+mujSqzapSM2bY1cETg4zVJXZUAtsQSje6Y0yBDMcOsIc0vK6owJVjFb
h+zdC1txJBwF9L7K0IKzlXYLgIWcBcVVLLhaY98w15sqXhjKEGfF7NKcmJjDa2XS
6QXv8bEyMyqlWFqoQrcoQMUDOXDaUKWwAWlWx9QV1MPuhTCVGn5+cKL+0E+znrhc
Tx/+ea3KFjvmX5MJfIO3mmJ4yejxv5hljUQKT8Gw5qzHUDZr+yzia2fomzyYCcT0
dD5j5iroeLFji9vWCsG5Rwwe1UCKR6trkXqI+y0bXngL1hgIbY7r68jx5caBXMnL
D3cbweLZM7xCEqCCfIGGLKRynOe3Fo4jwywMVuch0gvfNPboKHpaygntpyFoIS2n
v/xXt3tWk6pDBAebffCJabpmovksoydL71Sq9gJTJiBzFGhagfmrth7qxpFiJSaT
XIJs69CTh4p4kFrlyzPHzr8Bdj09kUGGxgpBCgcv7Zj7ZDR1MasFTwgM/KvEy+ox
DC7RUdECuyttqRqo9fBIE0uVG7nVjfEhnRqdRn5lR4oF/diS3jrqLhAjNj1EU57N
2m8kMgHfZh1ttujw57na58qkqsAts1qpRHdmJ2k/AK8+8h47Qgs=
=QQDE
-----END PGP SIGNATURE-----

C
C
Christopher Baines wrote on 24 Jul 2018 00:10
Re: [bug#30809] [PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(name . Clément Lassieur)(address . clement@lassieur.org)(address . 30809@debbugs.gnu.org)
87d0vdwqlp.fsf@cbaines.net
Clément Lassieur <clement@lassieur.org> writes:

Toggle quote (37 lines)
>> (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.

Toggle quote (14 lines)
>> +
>> + #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.
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAltWUlJfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XfLBg//csgcqJuSldNfM3FOaD31LW/QoH/vgPllv/R1zEbum5oRVYc1yiQCuzjh
L1ZWoHlURra3vMy6Ceu5w/cldkQy/0ZB45xw4f1IFPI+sTOuKlguXxBTIeLE0YXe
6y3WqFvZLFLqY3fgbRnaCrrwylLiuJLAAUbQ77FKz6Khu0Qj+Ca7nmppp0EImML6
68RtSi7LD35EOVFnxa3HiR29n6b1/nGT7lcxFkFZbwYfpp5xcwOVVy5WkCKwYqyq
5AvDw+pvkm60JxOKvrileP/cTvw/Y/iIwK2r+hECbhCcLIXIvZphhDkDYqTZZ2uH
t3Pk7BPyYTYE2ReBjvTCVkasuFEBgD4KcogvLVYsb2YcpxNYPtDKkDeJHicR1T7X
kDsyDdRuYSRE4dZCtTLwvjK4jtwReFE0au5vz51qeVunuL/A6cd0njLNh+wkT0VD
krcDD7VOr6DdvTBkIaVF05wDoHbq5TrzisTyricsAf0kPv+d8cOB3QK4poZoCIp8
BrC8AexWpSspiU+cTrUTSe3W6kqZmofiHa+IZSj2MfkLdHJyUwHs9cIknMoGHNpx
gJatSNdqrH/6jYiAQidkWVk4HB0nyeda8KRt4dlVyAcKsZorCjm5oYnxCOxHXRwR
xrA15+c4g60OyW+uZeSd+vekwboYmYp+HQ0+sf3eQpgSSNzYMjc=
=Uc6/
-----END PGP SIGNATURE-----

C
C
Clément Lassieur wrote on 24 Jul 2018 11:23
Re: [bug#30809] [PATCH 2/2] services: Add Gitolite.
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87o9ext2b8.fsf@lassieur.org
Hi Christopher, thank you for the update!

Christopher Baines <mail@cbaines.net> writes:

[...]

Toggle quote (12 lines)
> +(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'
:-).

Toggle quote (3 lines)
> + (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.

Toggle quote (23 lines)
> + ;; 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.

Toggle quote (2 lines)
> + (begin

I think that 'begin' is useless.

Toggle quote (28 lines)
> + ;; 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.

[...]

Toggle quote (3 lines)
> + (test-eq "cloning the admin repository"
> + #t

test-assert

Toggle quote (15 lines)
> + (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

Toggle quote (2 lines)
> + (invoke #$(file-append git "/bin/git") "push")))

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

Toggle quote (11 lines)
> + (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
C
C
Christopher Baines wrote on 29 Jul 2018 22:18
[PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(address . 30809@debbugs.gnu.org)
20180729201822.12372-1-mail@cbaines.net
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(-)

Toggle diff (81 lines)
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
C
C
Christopher Baines wrote on 29 Jul 2018 22:18
[PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
20180729201822.12372-2-mail@cbaines.net
* 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(-)

Toggle diff (448 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 29 Jul 2018 22:45
(name . Clément Lassieur)(address . clement@lassieur.org)(address . 30809@debbugs.gnu.org)
87zhy9kbyu.fsf@cbaines.net
Clément Lassieur <clement@lassieur.org> writes:

Toggle quote (2 lines)
> Hi Christopher, thank you for the update!

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

Toggle quote (19 lines)
> 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.

Toggle quote (6 lines)
>> + (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.

Toggle quote (26 lines)
>> + ;; 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.

Toggle quote (4 lines)
>> + (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.

Toggle quote (39 lines)
>> + ;; 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.

Toggle quote (10 lines)
>> + (test-eq "cloning the admin repository"
>> + #t
>
> test-assert
>
>> + (test-eq "pushing, and the associated hooks"
>> + #t
>
> test-assert

I've changed these now :)

Toggle quote (4 lines)
>> + (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.
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAlteJ2lfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XeW3xAAntZSanenOHsLxeMnfXl+IHhS5mzNNDbm3WG0G5J+u8xq2KLJFUKASD1t
I4FYoTCtzAdFZVHKe/dmZCzp3ydFrC38UtHGbx4L4tfEiuX8HHQIUqz/QI3P+/lU
XvsZuFsHWYhapVj278KcJN4O3YLHNt+NstKpTm8h5/upkRM9hB69H3Ku65Z16xLs
VG1rmBn5JAf+nw2JLJXgBNybzwGkIoT5FNlXth4io4rPwItAhTGfK+pfqfI16eUE
ZcI0O99/UH5pQI2f92HkJe/NK9l1RdNYEA+QKViGUHC0hr6lruQon6QLCpCLrVnE
RiBMXC4x94uB6AoPfNfzaSfdzEdffX+crxIPtr67Ehv9989H7PZo+xeWlM6IC+cr
YIIGCBykyAz0AkGBn0EVG9qy0jzOI7VEgJBpMznc4xzK+qPPUgnJK2mp1R5gzLeE
UBp38uyuiHATTmOgrr+S8z//iHugW4atlbsREpKKnkzaHXYIUpVXhJ4d5n5JPoDw
0iwHSun5jIstAndHSF2CnGMfRNiluGlZpfUrBUwnvIuV2G3foQABCXQ1GpmuWK/C
CF958dzzD+rWlX9+6dpp2BMZafnDaU+2LEWUjQIiK8oiiST7/Y+DDCpgaBeer9dS
3D37wIC9+LEnxy3/WcayxwDTO34Tb8RwhhwIKRBFb4prgVb7fzo=
=YoxP
-----END PGP SIGNATURE-----

C
C
Clément Lassieur wrote on 30 Jul 2018 20:26
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87tvog8trt.fsf@lassieur.org
Christopher Baines <mail@cbaines.net> writes:

[...]

Toggle quote (7 lines)
>>> +(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)----^

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

[...]

Toggle quote (8 lines)
>> 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?
C
C
Clément Lassieur wrote on 31 Jul 2018 01:39
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87r2jk8faj.fsf@lassieur.org
Hey Christopher!

Thank you for the update.

Christopher Baines <mail@cbaines.net> writes:

[...]

Toggle quote (17 lines)
> +@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.

Toggle quote (4 lines)
> +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 ---------------

Toggle quote (11 lines)
> +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 :-)

[...]

Toggle quote (13 lines)
> + (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?

Toggle quote (5 lines)
> + ;; 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.

Toggle quote (35 lines)
> + (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
C
C
Christopher Baines wrote on 31 Jul 2018 23:39
[PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(address . 30809@debbugs.gnu.org)
20180731213945.12930-1-mail@cbaines.net
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(-)

Toggle diff (81 lines)
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
C
C
Christopher Baines wrote on 31 Jul 2018 23:39
[PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
20180731213945.12930-2-mail@cbaines.net
* 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(-)

Toggle diff (437 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 31 Jul 2018 23:40
(name . Clément Lassieur)(address . clement@lassieur.org)(address . 30809@debbugs.gnu.org)
87wotbm6db.fsf@cbaines.net
Clément Lassieur <clement@lassieur.org> writes:

Toggle quote (4 lines)
> Hey Christopher!
>
> Thank you for the update.

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

Toggle quote (26 lines)
> 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.

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

Good spot, I've removed it now.

Toggle quote (16 lines)
>> + (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.

Toggle quote (7 lines)
>> + ;; 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.

Toggle quote (25 lines)
>> + ;; 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))))

-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAltg10BfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XfYPA/9FJDeM6CSCqIT2EZZwD0M1nJ0wXbpQfsvEjb3OGlQohM6xooVbIAZFJ0R
KMtpz6YQFNeT9nANCzJW5Zxz7Cf3XqstVEQncSZM6iy+jNKWwIz/beXxE15MG/3k
KraZ4OsiRDFaKXM1/lI3rvqx2raWiBpzCSe/A4f1P+xu/iRfr/9dCsavJl4hXHzv
gcDMLZ9I6pXovvBaibGIDWn3mtlP0txxaJovqc0esb/WZuo4clxRKccreCmX9uTt
mutMl6UUbuOftcR/oxlKbTcdI7brvGiNqS9ETC+80wI+67TFhrpI3CRSepkj0Nwn
ZdQSBz4YOovCiTK3sNyRI2HU5Ub4o0RdxaqfJ6mfMc6NtMcSLksf7g8+0Bx/3+Kp
AngTE3QzLAl6gXkOy5E1b1pZBMVg8rI4UN5A6NnZNz0OQ9fV9Vr7FpGh8UbzEuPf
/4zNx3wq1btrKK5kqjXep0kI5lWMYgIn6EIrZKCBCG8GuWl5Y1/4+nR5rT0IPdWw
bd7m9EepMEn1ZXIxiBdHmp2FZh8FQq6k1e6DMdkI16psk6IS/baIuPfOGeIZtpq+
QsOv8a6dKi6y6f3RgbEDbJz+lAUSN+YjDjcvzOOELHao6ziZbW2PCeTOizpaas3R
2IM5BIqPwErVvP4nagX61DAl1gmuM3qFdyJeqqnzmg1vriRztHg=
=CIcR
-----END PGP SIGNATURE-----

C
C
Clément Lassieur wrote on 12 Aug 2018 22:07
(name . Christopher Baines)(address . mail@cbaines.net)(address . 30809@debbugs.gnu.org)
87a7pr73ho.fsf@lassieur.org
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
C
C
Christopher Baines wrote on 19 Aug 2018 18:12
(name . Clément Lassieur)(address . clement@lassieur.org)(address . 30809@debbugs.gnu.org)
87h8jql4ic.fsf@cbaines.net
Clément Lassieur <clement@lassieur.org> writes:

Toggle quote (10 lines)
> 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.
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAlt5lutfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9Xc1rg/6A1rAsJ8xG62VNrpwsDYed32RD48mNJaP32GXfRBJCfeXd53pHR0bTko3
2RFZTCN1fdOPWKNTWWqp6iUeHwYKgmCcdPynMDScJ2Zi6KLXxv/W2q1BayAD3G+1
acHof4/LYUuoAtkTw+SAjQsBrJg9yMzlf2vfJnCUEWKXG/wnoQFU8/xapJPSdCKW
HBho/tYwKo5a0ql0YQpsgwlWag064J2X2BYOubuftlrv5flXA9ndnrpi/Eibe5uU
jZP4xhMHDjCytihKDhIMu31DDEbrGZjy8WbW0EAtV4aBlTyMwR4lR0bYKuHpa3fj
EiZHzodK+dGfxd8RQVM634CbZMRmqvZi0GR0KSs/zQwazGXz3P4bYBXx5gSQvJqG
IIa0xmEIcf8xkv95raK13kxBC8W97sUYlc4Kv57E7QxxEEoloE4NgCNC/KK/A1o4
TI67TAObLlZhOmFGmfqbWkzPhCx1RLLd5ersaLurxy1tPXBaV5cDDDqMQ82eYfL+
A0jzXGTwmxbByt43obj5oqDvxFcsbUMoWINqeS2qV6oce+vcsUR+8I4LbwiDvlOi
WwhJbnIu370hoaxwmGZ71n4jLUpW/tivL/K05H/BWAUSqeFL3IYFQ8KM70h6HGKS
sEeenJGs7csoHu9DMG6LtsYJ+hvJ3E9yBNZW/LT2eupV0+0RHwM=
=7h1x
-----END PGP SIGNATURE-----

C
C
Christopher Baines wrote on 22 Sep 2018 17:14
[PATCH 1/2] gnu: Modify the gitolite package to support the Guix service.
(address . 30809@debbugs.gnu.org)
20180922151437.20154-1-mail@cbaines.net
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(-)

Toggle diff (81 lines)
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
C
C
Christopher Baines wrote on 22 Sep 2018 17:14
[PATCH 2/2] services: Add Gitolite.
(address . 30809@debbugs.gnu.org)
20180922151437.20154-2-mail@cbaines.net
* 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(-)

Toggle diff (451 lines)
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;"))))))
+
+
+;;;
+;;; 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))))
+
+
+;;;
+;;; 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
C
C
Christopher Baines wrote on 22 Sep 2018 18:03
(address . 30809@debbugs.gnu.org)(name . Clément Lassieur)(address . clement@lassieur.org)
87y3btwmcc.fsf@cbaines.net
Christopher Baines <mail@cbaines.net> writes:

Toggle quote (4 lines)
> 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
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAlumZ+NfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9XdF/BAAtQnwOWNNLUrZXsA47gw7vCiViqZznuGLzgZs8o2bZS4P2ZNwHk0ALJhO
Z8MRKsVLvMF1SbTyz2bluG0EGgROcJYiYUSrOCZOHFk0npcmZJgSWjHVzFqGaa2h
658iielmK4U6ekHQ/4PelXs8YAwxAl+rNT4Qp7+AiJOLmKj0s1LWwweis88lo0wo
HZaQsKk4Wh8NhF6o13dqErGvXhmhzW4J7/5VMpFpTjYrKwLprJEehLz9e5QvTLrK
lfReJsqwJkIBPY1HmoLZnFFxvOS3qV5FEiSLGVEdj+icseJaopOPz/DZnQE/oNkM
p71VTsEODFOZ6LRvZYZEIP+zvqS74m1L1xUtA0BCXWiq36Ooc79QxeWTCBJ91rRL
9afySPmF0qRIkzvz/sTeuXfmRIfRlfMFtTaF79iTpo9LgQJZdEbBLZxxY3iYCPQz
apKLPuB91vE5ZyXSf8m7bfe/b/ZNIc5uyaMsVo/vjPBNtYtR4RpUSPl8ijF8aZqS
g+9+8J8cZKro+sqE/sR7XCjMZO4r1i9jXNKlbZQNR4NlNyAiSt9a9Xm4TJuIHiqc
kaFvjk9WSdIkapTWyl6o5XQn19O8SR/7kQ7VLaaWQHSU+TGkWekcf7H3JxwN9D7E
P6TkzY36PrX6lmVH5HZVb+sItCcocIoWrill9tj3oTkUDf+rY6Y=
=KNwj
-----END PGP SIGNATURE-----

N
N
Nils Gillmann wrote on 25 Sep 2018 20:01
(name . Christopher Baines)(address . mail@cbaines.net)
20180925180146.cwchfgbre5xfnxj7@abyayala
Christopher Baines transcribed 1.8K bytes:
Toggle quote (21 lines)
>
> 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!
C
C
Christopher Baines wrote on 28 Sep 2018 22:28
(name . Nils Gillmann)(address . ng0@n0.is)(address . 30809-done@debbugs.gnu.org)
87h8i9jric.fsf@cbaines.net
Nils Gillmann <ng0@n0.is> writes:

Toggle quote (31 lines)
> 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 :)

-----BEGIN PGP SIGNATURE-----

iQKTBAEBCgB9FiEEPonu50WOcg2XVOCyXiijOwuE9XcFAluujvtfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDNF
ODlFRUU3NDU4RTcyMEQ5NzU0RTBCMjVFMjhBMzNCMEI4NEY1NzcACgkQXiijOwuE
9Xdr5A//Q5YtUagA9WNh5ZeB2lIfaTWQnKF1Czvc+1FofM5XU2PZnUJf+I+UHUSR
UClaBhCrBoFOQ1Y4O3z5tkNqCmnxIUb+vgGnz9qCtCt2aNiMh1mHKI3iLUaZx8L0
2s3c9S+2M4CDUMQvFsrEhhTwu+yZlqe+gJMRDGFv2Z+etIqJNFXKuQhBeBFN53Dh
PUS2YOJxzeH5BocWNCMf1KOBX5MWE/iSqodY78N/OAJjRMlHIXT+sZyF/qPoQxuy
Qcbhy7cWYZo4dQK8fa6+z5o2/JkYJ214c+0wsOSTI7f5d6c0+ub0YUDwNIkAvIJb
3/c7v0q0o1q25kILr/wvdzjVQMC3eYbo2sPETWKieTOez9XFZYN1OKz+BTo9ljHK
m/OGmtdlrpKhMs2lIuYTtbEYnyIw/BdTFcTo+HWitaDyZ9y6KPuhJNjioDq5+JxC
6j9qkzG8wSJQ/tY7GI0So8IVCVZe/vFPDBfk6ASFx0SEOpkY4aJQZ+BhChi7nPc9
PlrP1FQbPqsvfuUy40xTpfxX9xwex0gb+eBLOXf4Dhud8fEfnNFNNsZLzsmRkIvN
T/Jeor5yBOVxdLX73KcOS3HVoj4Zye69NOaXCmusN+4e10aIvXr+p+Zp3nxUWGUX
wAc/YI9SefgzSDYEwz4xWdyFDIZYOfPr5pywMFwHWT2nR5D6jjM=
=+3Wm
-----END PGP SIGNATURE-----

Closed
?