(in-package :pkgmgr-util) (define-condition stat-failed-error (extended-error) ()) (define-condition command-failed-error (extended-error) ()) (defun chomp-lf (str) (when str (remove-if #'(lambda (ch) (char= ch #\Linefeed)) str))) (defun chomp-cr (str) (when str (remove-if #'(lambda (ch) (char= ch #\Return)) str))) (defun chomp (str) (when str (chomp-lf (chomp-cr str)))) (defun slurp-stream (stream) (with-output-to-string (out) (loop as line = (read-line stream nil nil) while line do (write-line line out)))) (defun slurp-file (filename) (if (probe-file filename) (with-open-file (f filename) (slurp-stream f)) "")) (defun slurp-input (cmd &rest args) (with-open-stream (in (apply #'pipe-input cmd args)) (slurp-stream in))) (defun slurp-shell-input (cmd) (with-open-stream (in (apply #'pipe-input "/bin/sh" (list "-c" cmd))) (slurp-stream in))) (defun shell-run (cmd &key (failure-allowed nil)) #+ clisp (restart-case (when (and (not (= 0 (run-prog "/bin/sh" :args (list "-c" cmd)))) (not failure-allowed)) (error 'command-failed-error :message cmd)) (ignore-command-failure () nil)) #- clisp (error 'implementation-not-supported-error :message "SHELL-RUN: only CLISP supported for now")) ;; Returns the modification time of the given file, or signals ;; stat-failed on error (defun stat-mtime (filename) #+ clisp (handler-case (slot-value (os:file-stat filename) 'os::mtime) (system::simple-os-error () (error 'stat-failed-error :message (format nil "FILE-STAT failed on ~a" filename)))) #- clisp (error 'implementation-not-supported-error :message "STAT-MTIME: only CLISP supported for now")) (defun regexp-escape (str) (let ((output (make-array 0 :element-type 'character :fill-pointer 0 :adjustable t))) (map nil #'(lambda (ch) (when (not (alphanumericp ch)) (vector-push-extend #\\ output)) (vector-push-extend ch output)) str) output)) (defun split-regexp (str delim) (split (format nil "~a" delim) str)) ;; Returns whether action was confirmed (defun confirm (msg &optional (default t)) (print-interactive "~a (~a/~a)" msg (if default "Y" "y") (if (not default) "N" "n")) (let ((response (chomp (read-line)))) (cond ((string= response "y") t) ((string= response "n") nil) ((string= response "") default) (t (confirm msg default))))) (defun band (&rest fns) (lambda (&rest args) (labels ((rec (fns args) (if (null fns) t (if (not (apply (car fns) args)) nil (rec (cdr fns) args))))) (rec fns args)))) (defun bor (&rest fns) (lambda (&rest args) (labels ((rec (fns args) (if (null fns) nil (if (apply (car fns) args) t (rec (cdr fns) args))))) (rec fns args)))) (defun bnot (fn) (complement fn))