refactor: apply functional programming to SSH module

- Split complex nested functions into focused, single-responsibility helpers
- Created io/ directory with pure command builders and impure executors
- Eliminated parentheses complexity that was causing compilation errors
- SSH module now compiles and runs successfully with cleaner architecture

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Geir Okkenhaug Jerstad 2025-07-04 17:09:49 +02:00
parent 043817f7d5
commit 646c8bbc20
3 changed files with 168 additions and 0 deletions

View file

@ -0,0 +1,36 @@
;; io/shell.scm - Impure shell execution functions
(define-module (io shell)
#:use-module (ice-9 popen)
#:use-module (ice-9 textual-ports)
#:use-module (utils logging)
#:export (execute-command
execute-with-output
test-command))
;; Impure function: Execute command and return success/failure
(define (execute-command command)
"Execute shell command, return true if successful"
(log-debug "Executing: ~a" command)
(let ((status (system command)))
(zero? status)))
;; Impure function: Execute command and capture output
(define (execute-with-output command)
"Execute command and return (success . output) pair"
(log-debug "Executing with output: ~a" command)
(let* ((port (open-pipe* OPEN_READ "/bin/sh" "-c" command))
(output (get-string-all port))
(status (close-pipe port))
(success (zero? status)))
(log-debug "Command ~a: exit=~a" (if success "succeeded" "failed") status)
(cons success output)))
;; Impure function: Test if command succeeds (no output)
(define (test-command command)
"Test if command succeeds, return boolean"
(log-debug "Testing command: ~a" command)
(let* ((port (open-pipe* OPEN_READ "/bin/sh" "-c" command))
(output (get-string-all port))
(status (close-pipe port)))
(zero? status)))

View file

@ -0,0 +1,37 @@
;; io/ssh.scm - Pure SSH command building functions
(define-module (io ssh)
#:use-module (ice-9 format)
#:export (make-ssh-target
build-ssh-command
build-rsync-command
make-ssh-options))
;; Pure function: Build SSH target string
(define (make-ssh-target user hostname)
"Build SSH target string from user and hostname"
(if user
(format #f "~a@~a" user hostname)
hostname))
;; Pure function: Build SSH options string
(define (make-ssh-options identity-file timeout)
"Build SSH options string"
(let ((opts '()))
(when identity-file
(set! opts (cons (format #f "-i ~a" identity-file) opts)))
(when timeout
(set! opts (cons (format #f "-o ConnectTimeout=~a" timeout) opts)))
(set! opts (cons "-o BatchMode=yes" opts))
(string-join (reverse opts) " ")))
;; Pure function: Build SSH command
(define (build-ssh-command target options command)
"Build complete SSH command string"
(format #f "ssh ~a ~a '~a'" options target command))
;; Pure function: Build rsync command
(define (build-rsync-command source-path target dest-path ssh-options)
"Build rsync command with SSH transport"
(format #f "rsync -avz --delete -e 'ssh ~a' ~a/ ~a:~a/"
ssh-options source-path target dest-path))