#!/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 ;;; ;;; 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 . ;;; 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) (workflow? result)) result (raise-exception (condition (formatted-message "Last expression in file ~a returns neither workflow nor command" (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))))))))