guile-tools.in 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #!/bin/sh
  2. # -*- scheme -*-
  3. exec guile $GUILE_FLAGS -e '(@@ (guile-tools) main)' -s "$0" "$@"
  4. !#
  5. ;;;; guile-tools --- running scripts bundled with Guile
  6. ;;;; Andy Wingo <wingo@pobox.com> --- April 2009
  7. ;;;;
  8. ;;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
  9. ;;;;
  10. ;;;; This library is free software; you can redistribute it and/or
  11. ;;;; modify it under the terms of the GNU Lesser General Public
  12. ;;;; License as published by the Free Software Foundation; either
  13. ;;;; version 3 of the License, or (at your option) any later version.
  14. ;;;;
  15. ;;;; This library is distributed in the hope that it will be useful,
  16. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. ;;;; Lesser General Public License for more details.
  19. ;;;;
  20. ;;;; You should have received a copy of the GNU Lesser General Public
  21. ;;;; License along with this library; if not, write to the Free
  22. ;;;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  23. ;;;; Boston, MA 02110-1301 USA
  24. (define-module (guile-tools)
  25. #:use-module ((srfi srfi-1) #:select (fold append-map))
  26. #:autoload (ice-9 format) (format))
  27. ;; Hack to provide scripts with the bug-report address.
  28. (module-define! the-scm-module
  29. '%guile-bug-report-address
  30. "@PACKAGE_BUGREPORT@")
  31. (define *option-grammar*
  32. '((help (single-char #\h))
  33. (version (single-char #\v))))
  34. (define (display-help)
  35. (display "\
  36. Usage: guile-tools --version
  37. guile-tools --help
  38. guile-tools PROGRAM [ARGS]
  39. If PROGRAM is \"list\" or omitted, display available scripts, otherwise
  40. PROGRAM is run with ARGS.
  41. "))
  42. (define (display-version)
  43. (format #t "guile-tools (GNU Guile ~A) ~A
  44. Copyright (C) 2010 Free Software Foundation, Inc.
  45. License LGPLv3+: GNU LGPL version 3 or later <http://gnu.org/licenses/lgpl.html>
  46. This is free software: you are free to change and redistribute it.
  47. There is NO WARRANTY, to the extent permitted by law.
  48. " (version) (effective-version)))
  49. (define (directory-files dir)
  50. (if (and (file-exists? dir) (file-is-directory? dir))
  51. (let ((dir-stream (opendir dir)))
  52. (let loop ((new (readdir dir-stream))
  53. (acc '()))
  54. (if (eof-object? new)
  55. (begin
  56. (closedir dir-stream)
  57. acc)
  58. (loop (readdir dir-stream)
  59. (if (or (string=? "." new) ; ignore
  60. (string=? ".." new)) ; ignore
  61. acc
  62. (cons new acc))))))
  63. '()))
  64. (define (strip-extensions path)
  65. (or-map (lambda (ext)
  66. (and
  67. (string-suffix? ext path)
  68. (substring path 0
  69. (- (string-length path) (string-length ext)))))
  70. (append %load-compiled-extensions %load-extensions)))
  71. (define (unique l)
  72. (cond ((null? l) l)
  73. ((null? (cdr l)) l)
  74. ((equal? (car l) (cadr l)) (unique (cdr l)))
  75. (else (cons (car l) (unique (cdr l))))))
  76. (define (find-submodules head)
  77. (let ((shead (map symbol->string head)))
  78. (unique
  79. (sort
  80. (append-map (lambda (path)
  81. (fold (lambda (x rest)
  82. (let ((stripped (strip-extensions x)))
  83. (if stripped (cons stripped rest) rest)))
  84. '()
  85. (directory-files
  86. (fold (lambda (x y) (in-vicinity y x)) path shead))))
  87. %load-path)
  88. string<?))))
  89. (define (list-scripts)
  90. (for-each (lambda (x)
  91. ;; would be nice to show a summary.
  92. (format #t "~A\n" x))
  93. (find-submodules '(scripts))))
  94. (define (find-script s)
  95. (resolve-module (list 'scripts (string->symbol s)) #:ensure #f))
  96. (define (getopt args grammar)
  97. (define (fail)
  98. (format (current-error-port)
  99. "Try `guile-tools --help' for more information.~%")
  100. (exit 1))
  101. (define (unrecognized-arg arg)
  102. (format (current-error-port)
  103. "guile-tools: unrecognized option: `~a'~%" arg)
  104. (fail))
  105. (define (unexpected-value sym val)
  106. (format (current-error-port)
  107. "guile-tools: option `--~a' does not take an argument (given ~s)~%"
  108. sym val)
  109. (fail))
  110. (define (single-char-table grammar)
  111. (cond
  112. ((null? grammar) '())
  113. ((assq 'single-char (cdar grammar))
  114. => (lambda (form)
  115. (acons (cadr form) (car grammar)
  116. (single-char-table (cdr grammar)))))
  117. (else
  118. (single-char-table (cdr grammar)))))
  119. (let ((single (single-char-table grammar)))
  120. (let lp ((args (cdr args)) (options '()))
  121. (cond
  122. ((or (null? args) (equal? (car args) "-"))
  123. (values (reverse options) args))
  124. ((equal? (car args) "--")
  125. (values (reverse options) (cdr args)))
  126. ((string-prefix? "--" (car args))
  127. (let* ((str (car args))
  128. (eq (string-index str #\= 2))
  129. (sym (string->symbol
  130. (substring str 2 (or eq (string-length str)))))
  131. (val (and eq (substring str (1+ eq))))
  132. (spec (assq sym grammar)))
  133. (cond
  134. ((not spec)
  135. (unrecognized-arg (substring str 0 (or eq (string-length str)))))
  136. (val
  137. ;; no values for now
  138. (unexpected-value sym val))
  139. ((assq-ref (cdr spec) 'value)
  140. (error "options with values not supported right now"))
  141. (else
  142. (lp (cdr args) (acons sym #f options))))))
  143. ((string-prefix? "-" (car args))
  144. (let lp* ((chars (cdr (string->list (car args)))) (options options))
  145. (if (null? chars)
  146. (lp (cdr args) options)
  147. (let ((spec (assv-ref single (car chars))))
  148. (cond
  149. ((not spec)
  150. (unrecognized-arg (string #\- (car chars))))
  151. ((assq-ref (cdr spec) 'value)
  152. (error "options with values not supported right now"))
  153. (else
  154. (lp* (cdr chars) (acons (car spec) #f options))))))))
  155. (else (values (reverse options) args))))))
  156. (define (main args)
  157. (if (defined? 'setlocale)
  158. (setlocale LC_ALL ""))
  159. (call-with-values (lambda () (getopt args *option-grammar*))
  160. (lambda (options args)
  161. (cond
  162. ((assq 'help options)
  163. (display-help)
  164. (exit 0))
  165. ((assq 'version options)
  166. (display-version)
  167. (exit 0))
  168. ((or (equal? args '())
  169. (equal? args '("list")))
  170. (list-scripts))
  171. ((find-script (car args))
  172. => (lambda (mod)
  173. (exit (apply (module-ref mod 'main) (cdr args)))))
  174. (else
  175. (format (current-error-port)
  176. "guile-tools: unknown script ~s~%" (car args))
  177. (format (current-error-port)
  178. "Try `guile-tools --help' for more information.~%")
  179. (exit 1))))))