aboutsummaryrefslogtreecommitdiff
path: root/scripts/ccwl
blob: 984d22aca19cb870cea0ee9afc9113e442eadf70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env sh
# -*- mode: scheme; -*-
exec guile --no-auto-compile -e main -s "$0" "$@"
!#
;;; ccwl --- Concise Common Workflow Language
;;; Copyright © 2021–2024 Arun Isaac <arunisaac@systemreboot.net>
;;;
;;; This file is part of ccwl.
;;;
;;; ccwl is free software: you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; ccwl is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with ccwl.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; This script is the command-line interface to ccwl.

;;; Code:

(use-modules (rnrs conditions)
             (rnrs exceptions)
             (srfi srfi-28)
             (srfi srfi-37)
             (ice-9 match)
             (ice-9 exceptions)
             (ccwl ccwl)
             (ccwl conditions)
             (ccwl cwl)
             (ccwl graphviz)
             (ccwl ui))

(define (invalid-option opt name arg result)
  (error "Invalid option" name))

(define (invalid-operand arg result)
  (error "Invalid argument" arg))

(define %help-option
  (option (list "help") #f #t
          (lambda (opt name arg result)
            (acons 'help #t result))))

(define (main args)
  (with-exception-handler
      (lambda (condition)
        ;; Catch uncaught exceptions, print their backtrace and
        ;; request the user report an issue. Pass quit exceptions
        ;; through since those may be raised by exceptions that have
        ;; been handled.
        (cond
         ((formatted-message? condition)
          (report-formatted-message condition))
         ((not (quit-exception? condition))
          (display-backtrace (make-stack #t) (current-error-port))
          (newline (current-error-port))
          (write condition (current-error-port))
          (newline (current-error-port))
          (display "
You have discovered a bug! ccwl crashed! :-(
Please report this to https://github.com/arunisaac/ccwl/issues
Thank you!
"
                   (current-error-port))))
        (exit #f))
    (lambda ()
      (match args
        ((program "compile" args ...)
         (let* ((args (args-fold args
                                 (list (option (list #\t "to") #t #f
                                               (lambda (opt name arg result)
                                                 (let ((supported (list "cwl" "dot")))
                                                   (unless (member arg supported)
                                                     (scm-error 'misc-error
                                                                #f
                                                                "Invalid target ~A argument ~S. Supported targets are ~A."
                                                                (list (if (char? name)
                                                                          (string #\- name)
                                                                          (string-append "--" name))
                                                                      arg
                                                                      (string-join supported ", "))
                                                                #f)))
                                                 (acons 'to arg result)))
                                       %help-option)
                                 invalid-option
                                 (lambda (arg result)
                                   (acons 'source-file arg result))
                                 '((to . "cwl")))))
           (when (or (assq 'help args)
                     (not (assq-ref args 'source-file)))
             (display (format "Usage: ~a compile [OPTIONS] SOURCE-FILE
Compile SOURCE-FILE.

  -t, --to=TARGET    compile SOURCE-FILE to TARGET language;
                     Supported targets are cwl (default) and dot.

"
                              program)
                      (current-error-port))
             (exit (assq 'help args)))
           ;; We don't need to compile ccwl files. Loading is sufficient
           ;; for our purposes. Besides, compiling would fail since the
           ;; workflow macro cannot access command definitions.
           (set! %load-should-auto-compile #f)
           (let ((to (assq-ref args 'to)))
             ((cond
               ((string=? to "cwl") function->cwl)
               ((string=? to "dot") function->dot))
              (guard (exception
                      ;; Handle syntax violation exceptions by reporting
                      ;; them and exiting.
                      ((ccwl-violation? exception)
                       (report-ccwl-violation exception)
                       (exit #f)))
                (let ((result (load (canonicalize-path (assq-ref args 'source-file))
                                      read-syntax)))
                  (if (or (command? result)
                          (js-expression? result)
                          (workflow? result))
                      result
                      (raise-exception
                       (condition (formatted-message "Last expression in file ~a returns none of workflow, command or js-expression"
                                                     (assq-ref args 'source-file)))))))
              (current-output-port)))))
        ((program args ...)
         (let ((args (args-fold args
                                (list %help-option)
                                (lambda (opt name arg result)
                                  result)
                                (lambda (arg result)
                                  result)
                                '())))
           (display (format "Usage: ~a COMMAND [OPTIONS] [ARGS]

COMMAND must be one of the sub-commands listed below:

  compile   compile a workflow

To get usage information for one of these sub-commands, run
  ~a COMMAND --help

"
                            program program)
                    (current-error-port))
           (exit (assq 'help args))))))))