(define-module (local-pkgs-gnu packages actual-server-installer) #:use-module (guix packages) #:use-module (guix git-download) #:use-module (guix build-system node) #:use-module (guix utils) #:use-module (guix build-system gnu) #:use-module (guix licenses) #:use-module (gnu packages) #:use-module (gnu packages base) #:use-module (gnu packages bash) #:use-module (gnu packages gawk) #:use-module (gnu packages guile) #:use-module (gnu packages shells) #:use-module (gnu packages compression) #:use-module (gnu packages node) #:use-module (gnu packages package-management) #:use-module (gnu packages gnupg) #:use-module (gnu packages gcc) #:use-module (ice-9 pretty-print) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26)) (define-public actual-server-installer (package (name "actual-server-installer") (version "24.5.0") (source (origin (method git-fetch) (uri (git-reference (url "https://github.com/actualbudget/actual-server") (commit "v24.5.0"))) (file-name (git-file-name name version)) (sha256 (base32 "1d0jvm3jf8v3hcm0ydnf50rc3k9racl4kpsa24iqlsqvnas831hf")) (snippet '(begin ;; Guile code to pretty-print to a file (use-modules (ice-9 pretty-print)) (let ((build-output-file "build.scm") (run-output-file "actual-server-install")) (call-with-output-file run-output-file (lambda (port) (format port "#!/usr/bin/env guile~%!#~%") (pretty-print '(begin (use-modules (ice-9 popen) (ice-9 rdelim) (srfi srfi-1) (rnrs io ports) (rnrs bytevectors) (rnrs files) (guix build utils) (ice-9 pretty-print) (gcrypt hash) (guix base32) (ice-9 ftw)) (define (run-and-display-command command) (let* ((port (open-pipe* OPEN_READ "sh" "-c" command)) (status #f)) (let loop () (let ((line (read-line port 'concat))) (if (eof-object? line) (begin (set! status (close-pipe port)) (if (not (zero? status)) (error "Command failed" command status))) (begin (display line) (force-output) (loop))))))) (define (sha256sum file) (call-with-input-file file (lambda (port) (let ((digest (sha256 (get-bytevector-all port)))) (bytevector->nix-base32-string digest))))) (define (generate-actual-server-scm directory checksum) `( (define-module (actual-server) #:use-module (guix packages) #:use-module (gnu packages bash) #:use-module (gnu packages base) #:use-module (guix build-system gnu) #:use-module (gnu packages gcc) #:use-module (guix licenses) #:use-module (guix download) #:use-module (gnu packages) #:use-module (gnu packages node) #:use-module (gnu packages guile) #:use-module (gnu packages gcc) #:use-module (guix build utils) #:use-module (gnu packages elf) #:use-module (ice-9 pretty-print)) (define-public actual-server (package (name "actual-server") (version "24.5.0") (source (origin (method url-fetch) (uri (string-append "file://" ,directory "/actual-server.tar.gz")) (sha256 (base32 ,checksum)))) (build-system gnu-build-system) (propagated-inputs `(("gcc" ,gcc "lib") ("node" ,node-lts) ("bash" ,bash) ("coreutils" ,coreutils) ("findutils" ,findutils) ("guile" ,guile-3.0))) (native-inputs `(("patchelf" ,patchelf))) (arguments `(#:tests? #f ; Disable tests #:phases (modify-phases %standard-phases (delete 'configure) (delete 'build) (delete 'install) (add-after 'unpack 'copy-files (lambda* (#:key outputs #:allow-other-keys) (let ((out (assoc-ref outputs "out"))) (copy-recursively "." (string-append out "/lib")) (mkdir-p (string-append out "/bin")) #t))) (add-after 'copy-files 'create-guile-script (lambda* (#:key outputs #:allow-other-keys) (use-modules (ice-9 pretty-print)) (let* ((out (assoc-ref outputs "out")) (run-output-file (string-append out "/bin/actual-server"))) (call-with-output-file run-output-file (lambda (port) (format port "#!/usr/bin/env guile~%!#~%") (pretty-print `(begin (use-modules (ice-9 popen) (ice-9 rdelim) (srfi srfi-1) (rnrs io ports) (rnrs bytevectors) (rnrs files) (ice-9 pretty-print) (ice-9 ftw)) (define (run-and-display-command command) (let* ((port (open-pipe* OPEN_READ "sh" "-c" command)) (status #f)) (let loop () (let ((line (read-line port 'concat))) (if (eof-object? line) (begin (set! status (close-pipe port)) (if (not (zero? status)) (error "Command failed" command status))) (begin (display line) (force-output) (loop))))))) (define ld-library-path ,(string-append out "/lib")) (define home-path (getenv "HOME")) (define sym-source (string-append home-path "/.cache/node")) (define sym-target (string-append ld-library-path "/actual-server/node")) (symlink sym-target sym-source) (run-and-display-command (string-append "cd " ld-library-path "/actual-server/proj && corepack enable && yarn start"))) port))) (chmod run-output-file #o755)))) (add-after 'copy-files 'create-guile-script (lambda* (#:key inputs outputs #:allow-other-keys) (let* ((out (assoc-ref outputs "out")) (gcc-lib (string-append (assoc-ref inputs "gcc") "/lib"))) (for-each (lambda (binary) (invoke "patchelf" "--set-rpath" gcc-lib binary)) (find-files (string-append out "/lib") ".*\\.node$")))))))) (home-page "https://github.com/actualbudget/actual-server") (synopsis "Actual server for budget management") (description "Actual is a local-first personal finance tool.") (license expat))))) (define (write-actual-server-scm directory scm-content) (call-with-output-file (string-append directory "/actual-server.scm") (lambda (port) (for-each (lambda (expr) (pretty-print expr port)) scm-content)))) (define (main args) (if (< (length args) 1) (error "Usage: script.scm ")) (let ((directory (car args))) (mkdir-p directory) (run-and-display-command (string-append "guix shell --container --network --pure --no-cwd --emulate-fhs --share=" directory "=/actual-server actual-server-installer -- bash -c 'guile $GUIX_ENVIRONMENT/lib/actual-server-installer/build.scm'")) (let* ((checksum (sha256sum (string-append directory "/actual-server.tar.gz"))) (scm-content (generate-actual-server-scm directory checksum))) (write-actual-server-scm directory scm-content)))) (main (cdr (command-line))) ) port))) (call-with-output-file build-output-file (lambda (port) (pretty-print '(begin (use-modules (ice-9 popen) (ice-9 rdelim) (srfi srfi-1) (rnrs io ports) (rnrs bytevectors) (rnrs files) (guix build utils) (ice-9 pretty-print) (gcrypt hash) (guix base32) (ice-9 ftw)) (define (run-and-display-command command) (let* ((port (open-pipe* OPEN_READ "sh" "-c" command)) (status #f)) (let loop () (let ((line (read-line port 'concat))) (if (eof-object? line) (begin (set! status (close-pipe port)) (if (not (zero? status)) (error "Command failed" command status))) (begin (display line) (force-output) (loop))))))) (define (delete-directory-contents dir) (for-each (lambda (file) (let ((full-path (string-append dir "/" file))) (if (directory-exists? full-path) (delete-file-recursively full-path) (delete-file full-path)))) (filter (lambda (file) (not (member file '("." "..")))) (scandir dir)))) (define (chmod-r path mode) (define (change-permissions file stat flag) (chmod file mode)) (ftw path change-permissions)) (delete-directory-contents "/actual-server") (mkdir-p "/actual-server-build/lib/actual-server") (copy-recursively (string-append (getenv "GUIX_ENVIRONMENT") "/lib/actual-server-installer/repo") "/actual-server-build/lib/actual-server/proj") (chmod-r "/actual-server-build/lib/actual-server/proj" #o755) (chdir "/actual-server-build/lib/actual-server/proj") ;; Enable corepack and install yarn (run-and-display-command "corepack enable") (run-and-display-command "corepack install") (run-and-display-command "yarn install") ;; Create the necessary directory (mkdir-p "/actual-server-build/lib/actual-server/node") (copy-recursively (string-append (getenv "HOME") "/.cache/node") "/actual-server-build/lib/actual-server/node/") ;; Create tar.gz archive (run-and-display-command "tar -czvf /actual-server/actual-server.tar.gz -C /actual-server-build .") ) port)))))))) (build-system gnu-build-system) (propagated-inputs `(("bash" ,bash) ("coreutils" ,coreutils) ("findutils" ,findutils) ("tar" ,tar) ("gzip" ,gzip) ("gawk" ,gawk) ("guix" ,guix) ("guile" ,guile-3.0) ("guile-gcrypt" ,guile-gcrypt) ("node", node-lts) ("gcc" ,gcc "lib"))) (arguments `(#:tests? #f ; Disable tests for simplicity #:phases (modify-phases %standard-phases (delete 'configure) (delete 'build) (delete 'install) (add-after 'unpack 'store-source (lambda* (#:key outputs #:allow-other-keys) (let ((source-dir (assoc-ref outputs "out"))) (copy-recursively "." (string-append source-dir "/lib/actual-server-installer/repo")) (mkdir-p (string-append source-dir "/bin")) (format #t "Checking if build.scm exists: ~a~%" (file-exists? (string-append source-dir "/lib/actual-server-installer/repo/build.scm"))) (format #t "Checking if actual-server-install exists: ~a~%" (file-exists? (string-append source-dir "/lib/actual-server-installer/repo/actual-server-install"))) (rename-file (string-append source-dir "/lib/actual-server-installer/repo/build.scm") (string-append source-dir "/lib/actual-server-installer/build.scm")) (rename-file (string-append source-dir "/lib/actual-server-installer/repo/actual-server-install") (string-append source-dir "/bin/actual-server-install")) (chmod (string-append source-dir "/bin/actual-server-install") #o755) #t)))))) (home-page "https://github.com/actualbudget/actual-server") (synopsis "Actual server for budget management") (description "Actual is a local-first personal finance tool.") (license expat)))