guix-commits
[Top][All Lists]
Advanced

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

02/02: potluck: Implement more host-channel functionality


From: Andy Wingo
Subject: 02/02: potluck: Implement more host-channel functionality
Date: Wed, 12 Apr 2017 10:44:24 -0400 (EDT)

wingo pushed a commit to branch wip-potluck
in repository guix.

commit 7449ab4f2be04894671da1872cd36cd85c052cca
Author: Andy Wingo <address@hidden>
Date:   Wed Apr 12 16:42:30 2017 +0200

    potluck: Implement more host-channel functionality
    
    * guix/scripts/potluck.scm: Rework host-channel command to have required
      --scratch, --source, and --target command-line arguments.
    * guix/potluck/host.scm: Implement more functionality.
---
 guix/potluck/host.scm    | 172 ++++++++++++++++++++++++++++++++++++++++++-----
 guix/scripts/potluck.scm |  44 ++++++++++--
 2 files changed, 196 insertions(+), 20 deletions(-)

diff --git a/guix/potluck/host.scm b/guix/potluck/host.scm
index 712d7bd..e4aeb97 100644
--- a/guix/potluck/host.scm
+++ b/guix/potluck/host.scm
@@ -20,6 +20,10 @@
   #:use-module (guix config)
   #:use-module (guix base32)
   #:use-module (guix ui)
+  #:use-module ((guix build utils)
+                #:select (mkdir-p
+                          delete-file-recursively
+                          with-directory-excursion))
   #:use-module (guix utils)
   #:use-module (guix potluck packages)
   #:use-module (guix potluck build-systems)
@@ -27,10 +31,12 @@
   #:use-module (guix scripts)
   #:use-module (guix scripts hash)
   #:use-module (ice-9 format)
+  #:use-module (ice-9 ftw)
   #:use-module (ice-9 match)
   #:use-module (ice-9 popen)
   #:use-module (ice-9 pretty-print)
   #:use-module (ice-9 q)
+  #:use-module (ice-9 rdelim)
   #:use-module (ice-9 textual-ports)
   #:use-module (ice-9 threads)
   #:use-module (json)
@@ -108,6 +114,11 @@
 (define (git . args)
   (git* args))
 
+(define (git-check-ref-format str)
+  (when (string-prefix? "-" str)
+    (error "bad ref" str))
+  (git "check-ref-format" str))
+
 (define (git-rev-parse rev)
   (string-trim-both (git "rev-parse" rev)))
 
@@ -117,6 +128,38 @@
 (define* (git-describe #:optional (ref "HEAD"))
   (string-trim-both (git "describe")))
 
+(define (git-fetch)
+  (git "fetch"))
+
+(define (git-push)
+  (git "push"))
+
+(define (git-clone repo dir)
+  (git "clone" "--" repo dir))
+
+(define (git-clone repo dir)
+  (git "clone" "--" repo dir))
+
+(define* (git-reset #:key (ref "HEAD") (mode 'hard))
+  ;; Can't let the ref be mistaken for a command-line argument.
+  (when (string-prefix? "-" ref)
+    (error "bad ref" ref))
+  (git "reset"
+       (case mode
+         ((hard) "--hard")
+         ((mixed) "--mixed")
+         ((soft) "--soft")
+         (else (error "unknown mode" mode)))
+       ref))
+
+(define (git-add file)
+  (git "add" "--" file))
+
+(define* (git-commit #:key message author-name author-email)
+  (git "commit"
+       (string-append "--message=" message)
+       (string-append "--author=" author-name "<" author-email ">")))
+
 
 ;;;
 ;;; async queues
@@ -160,10 +203,102 @@
 ;;; backend
 ;;;
 
-(define (process-update git-checkout remote-git-url branch)
-  (pk 'hey git-checkout remote-git-url branch))
+(define (bytes-free-on-fs filename)
+  (let* ((p (open-pipe* "r" "df" "--output=avail" filename))
+         (l1 (read-line p))
+         (l2 (read-line p))
+         (l3 (read-line p)))
+    (close-pipe p)
+    (cond
+     ((and (string? l1) (string? l2) (eof-object? l3)
+           (equal? (string-trim-both l1) "Avail"))
+      (string->number l2))
+     (else
+      (error "could not get free space for file system containing" 
filename)))))
 
-(define (service-queue git-checkout queue)
+(define (delete-directory-contents-recursively working-dir)
+  (for-each (lambda (file)
+              (delete-file-recursively (in-vicinity working-dir file)))
+            (scandir working-dir
+                     (lambda (file)
+                       (and (string<> "." file)
+                            (string<> ".." file))))))
+
+;; 1GB minimum free space.
+(define *mininum-free-space* #e1e9)
+
+(define (scm-files-in-dir dir)
+  (map (lambda (file)
+         (in-vicinity dir file))
+       (scandir dir
+                (lambda (file)
+                  (and (not (file-is-directory? file))
+                       (string-suffix? ".scm" file))))))
+
+(define (copy-header-comments port file)
+  #f)
+
+(define (emit-guix-package-module port pkg)
+  #f)
+
+(define (process-update host working-dir source-checkout target-checkout
+                        remote-git-url branch)
+  (when (< (bytes-free-on-fs working-dir) *mininum-free-space*)
+    (delete-directory-contents-recursively working-dir)
+    (when (< (bytes-free-on-fs working-dir) *mininum-free-space*)
+      (error "not enough free space")))
+  (chdir working-dir)
+  (let* ((repo-dir (uri-encode remote-git-url))
+         (repo+branch-dir (in-vicinity repo-dir (uri-encode branch))))
+    (cond
+     ((file-exists? repo-dir)
+      (chdir repo-dir)
+      (git-fetch))
+     (else
+      (git-clone remote-git-url repo-dir)
+      (chdir repo-dir)))
+    (git-reset #:ref branch #:mode 'hard)
+    (unless (file-is-directory? "guix-potluck")
+      (error "repo+branch has no guix-potluck dir" remote-git-url branch))
+    (let* ((files (scm-files-in-dir "guix-potluck"))
+           ;; This step safely loads and validates the potluck package
+           ;; definitions.
+           (packages (map load-potluck-package files))
+           (source-dir (in-vicinity source-checkout repo+branch-dir))
+           (target-dir (in-vicinity target-checkout repo+branch-dir)))
+      ;; Clear source and target repo entries.
+      (define (ensure-empty-dir filename)
+        (when (file-exists? filename)
+          (delete-file-recursively filename))
+        (mkdir-p filename))
+      (define (commit-dir dir)
+        (with-directory-excursion dir
+          (lambda ()
+            (git-add ".")
+            (git-commit #:message
+                        (format #f "Update ~a branch ~a."
+                                remote-git-url branch)
+                        #:author-name "Guix potluck host"
+                        #:author-email (string-append "host@" host))
+            (git-push))))
+      (ensure-empty-dir source-dir)
+      (ensure-empty-dir target-dir)
+      ;; Add potluck files to source repo.
+      (for-each (lambda (file) (copy-file file source-dir)) files)
+      (commit-dir source-dir)
+      ;; Add transformed files to target repo.
+      (for-each (lambda (file package)
+                  (call-with-output-file (in-vicinity target-dir file)
+                    (lambda (port)
+                      ;; Preserve copyright notices if possible.
+                      (copy-header-comments port file)
+                      (emit-guix-package-module port package))))
+                files packages)
+      (commit-dir target-dir)))
+  ;; 8. post success message
+  (pk 'success target-checkout remote-git-url branch))
+
+(define (service-queue host working-dir source-checkout target-checkout queue)
   (let lp ()
     (match (async-queue-pop! queue)
       ((remote-git-url . branch)
@@ -171,7 +306,9 @@
                remote-git-url branch)
        (catch #t
          (lambda ()
-           (process-update git-checkout remote-git-url branch)
+           (process-update host working-dir
+                           source-checkout target-checkout
+                           remote-git-url branch)
            (format (current-error-port) "log: success ~a / ~a\n"
                    remote-git-url branch))
          (lambda (k . args)
@@ -197,16 +334,15 @@
                  (public-host? (uri-host uri)))
       (error "expected a public URI" str))))
 
-(define (validate-non-empty-string str)
-  (unless (and (string? str)
-               (not (string-null? str)))
-    (error "expected a non-empty string" str)))
+(define (validate-branch-name str)
+  (unless (git-check-ref-format str)
+    (error "expected a valid git branch name" str)))
 
 (define (enqueue-update params queue)
   (let ((remote-git-url (hash-ref params "git-url"))
         (branch-name (hash-ref params "branch")))
     (validate-public-uri remote-git-url)
-    (validate-non-empty-string branch-name)
+    (validate-branch-name branch-name)
     (async-queue-push! queue (cons remote-git-url branch-name))))
 
 (define (handler request body queue)
@@ -224,17 +360,21 @@
      (values (build-response #:code 404)
              ""))))
 
-(define (host-potluck host local-port local-git-checkout-dir)
+(define (host-potluck host local-port working-dir source-checkout
+                      target-checkout)
   (let ((worker-thread #f)
         (queue (make-async-queue)))
     (dynamic-wind (lambda ()
                     (set! worker-thread
                       (make-thread
-                       (service-queue local-git-checkout-dir queue))))
-                  (lambda () (run-server
-                              (lambda (request body)
-                                (handler request body queue))
-                              ;; Always listen on localhost.
-                              'http `(#:port ,local-port)))
+                       (service-queue host working-dir
+                                      source-checkout target-checkout
+                                      queue))))
+                  (lambda ()
+                    (run-server
+                     (lambda (request body)
+                       (handler request body queue))
+                     ;; Always listen on localhost.
+                     'http `(#:port ,local-port)))
                   (lambda ()
                     (cancel-thread worker-thread)))))
diff --git a/guix/scripts/potluck.scm b/guix/scripts/potluck.scm
index bc7393a..2c5d123 100644
--- a/guix/scripts/potluck.scm
+++ b/guix/scripts/potluck.scm
@@ -258,7 +258,7 @@ ARGS.\n"))
   (newline)
   (display (_ "The available OPTION flags are:\n"))
   (display (_ "
-      --host=URL         for 'update' and 'host-channel', the name of the
+      --host=HOST        for 'update' and 'host-channel', the name of the
                          channel host
                          (default: guix-potluck.org)"))
   (display (_ "
@@ -266,6 +266,17 @@ ARGS.\n"))
                          listen for HTTP connections
                          (default: 8080)"))
   (display (_ "
+      --scratch=DIR      for 'host-channel', the path to a local directory
+                         that will be used as a scratch space to check out
+                         remote git repositories"))
+  (display (_ "
+      --source=DIR       for 'host-channel', the path to a local checkout
+                         of guix potluck source packages to be managed by
+                         host-channel"))
+  (display (_ "
+      --target=DIR       for 'host-channel', the path to a local checkout
+                         of a guix channel to be managed by host-channel"))
+  (display (_ "
       --build-system=SYS for 'init', specify the build system.  Use
                          --build-system=help for all available options."))
   (display (_ "
@@ -310,6 +321,15 @@ ARGS.\n"))
         (option '("port") #t #f
                 (lambda (opt name arg result)
                   (alist-cons 'port arg result)))
+        (option '("scratch") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'scratch arg result)))
+        (option '("source") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'source arg result)))
+        (option '("target") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'target arg result)))
         (option '("verbosity") #t #f
                 (lambda (opt name arg result)
                   (alist-cons 'verbosity (string->number arg) result)))))
@@ -338,6 +358,13 @@ ARGS.\n"))
      (else
       (leave (_ "invalid port: ~a~%") port-str)))))
 
+(define (parse-absolute-directory-name str)
+  (unless (and (absolute-file-name? str)
+               (file-exists? str)
+               (file-is-directory? str))
+    (leave (_ "invalid absolute directory name: ~a~%") str))
+  str)
+
 (define (parse-build-system sys-str)
   (unless sys-str
     (leave (_ "\
@@ -439,13 +466,22 @@ If your package's license is not in this list, add it to 
Guix first.~%")
              (_ "usage: guix potluck update REMOTE-GIT-URL BRANCH-NAME")))))
         ('host-channel
          (match args
-           ((local-git-checkout)
+           (()
             (host-potluck (parse-host (assoc-ref opts 'host))
                           (parse-port (assoc-ref opts 'port))
-                          local-git-checkout))
+                          (parse-absolute-directory-name
+                           (or (assoc-ref opts 'scratch)
+                               (leave (_ "missing --scratch argument~%"))))
+                          (parse-absolute-directory-name
+                           (or (assoc-ref opts 'source)
+                               (leave (_ "missing --source argument~%"))))
+                          (parse-absolute-directory-name
+                           (or (assoc-ref opts 'target)
+                               (leave (_ "missing --target argument~%"))))))
            (args
             (wrong-number-of-args
-             (_ "usage: guix potluck host-channel CHANNEL-DIRECTORY"))
+             (_ "usage: guix potluck host-channel --scratch=DIR \
+--source=DIR --target=DIR"))
             (exit 1))))
         (action
          (leave (_ "~a: unknown action~%") action))))))



reply via email to

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