Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
981ff1d5fc
|
@ -183,6 +183,10 @@
|
||||||
(str
|
(str
|
||||||
(safe-name (-> % :attrs :name) :sql)
|
(safe-name (-> % :attrs :name) :sql)
|
||||||
" = ':" (-> % :attrs :name) "'")
|
" = ':" (-> % :attrs :name) "'")
|
||||||
|
"entity"
|
||||||
|
(str
|
||||||
|
(safe-name (-> % :attrs :name) :sql)
|
||||||
|
"_expanded LIKE '%:" (-> % :attrs :name) "%'")
|
||||||
(str
|
(str
|
||||||
(safe-name (-> % :attrs :name) :sql)
|
(safe-name (-> % :attrs :name) :sql)
|
||||||
" = :"
|
" = :"
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
(ns ^{:doc "Application Description Language: generate RING routes for REST requests."
|
(ns ^{:doc "Application Description Language: generate RING routes for REST requests."
|
||||||
:author "Simon Brooke"}
|
:author "Simon Brooke"}
|
||||||
adl.to-json-routes
|
adl.to-json-routes
|
||||||
(:require [clojure.java.io :refer [file make-parents writer]]
|
(:require [adl-support.utils :refer :all]
|
||||||
[clojure.pprint :refer [pprint]]
|
[adl.to-hugsql-queries :refer [queries]]
|
||||||
[clojure.string :as s]
|
|
||||||
[clojure.xml :as x]
|
|
||||||
[clj-time.core :as t]
|
[clj-time.core :as t]
|
||||||
[clj-time.format :as f]
|
[clj-time.format :as f]
|
||||||
[adl-support.utils :refer :all]
|
[clojure.java.io :refer [file make-parents writer]]
|
||||||
[adl.to-hugsql-queries :refer [queries]]))
|
[clojure.pprint :refer [pprint]]
|
||||||
|
[clojure.string :as s]
|
||||||
|
[clojure.xml :as x]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;
|
;;;;
|
||||||
|
@ -47,8 +47,9 @@
|
||||||
(list
|
(list
|
||||||
:require
|
:require
|
||||||
'[adl-support.core :as support]
|
'[adl-support.core :as support]
|
||||||
'[clojure.java.io :as io]
|
|
||||||
'[clojure.core.memoize :as memo]
|
'[clojure.core.memoize :as memo]
|
||||||
|
'[clojure.java.io :as io]
|
||||||
|
'[clojure.tools.logging :as log]
|
||||||
'[compojure.core :refer [defroutes GET POST]]
|
'[compojure.core :refer [defroutes GET POST]]
|
||||||
'[hugsql.core :as hugsql]
|
'[hugsql.core :as hugsql]
|
||||||
'[noir.response :as nresponse]
|
'[noir.response :as nresponse]
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
:author "Simon Brooke"}
|
:author "Simon Brooke"}
|
||||||
adl.to-selmer-routes
|
adl.to-selmer-routes
|
||||||
(:require [adl-support.utils :refer :all]
|
(:require [adl-support.utils :refer :all]
|
||||||
|
[clj-time.core :as t]
|
||||||
|
[clj-time.format :as f]
|
||||||
[clojure.java.io :refer [file make-parents writer]]
|
[clojure.java.io :refer [file make-parents writer]]
|
||||||
[clojure.pprint :refer [pprint]]
|
[clojure.pprint :refer [pprint]]
|
||||||
[clojure.string :as s]
|
[clojure.string :as s]
|
||||||
[clojure.xml :as x]
|
[clojure.xml :as x]
|
||||||
[clj-time.core :as t]
|
|
||||||
[clj-time.format :as f]
|
|
||||||
))
|
))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -51,6 +51,8 @@
|
||||||
:require
|
:require
|
||||||
'[adl-support.core :as support]
|
'[adl-support.core :as support]
|
||||||
'[clojure.java.io :as io]
|
'[clojure.java.io :as io]
|
||||||
|
'[clojure.set :refer [subset?]]
|
||||||
|
'[clojure.tools.logging :as log]
|
||||||
'[compojure.core :refer [defroutes GET POST]]
|
'[compojure.core :refer [defroutes GET POST]]
|
||||||
'[hugsql.core :as hugsql]
|
'[hugsql.core :as hugsql]
|
||||||
'[noir.response :as nresponse]
|
'[noir.response :as nresponse]
|
||||||
|
@ -60,6 +62,109 @@
|
||||||
(vector (symbol (str (:name (:attrs application)) ".db.core")) :as 'db)
|
(vector (symbol (str (:name (:attrs application)) ".db.core")) :as 'db)
|
||||||
(vector (symbol (str (:name (:attrs application)) ".routes.manual")) :as 'm))))
|
(vector (symbol (str (:name (:attrs application)) ".routes.manual")) :as 'm))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn make-form-handler-content
|
||||||
|
[f e a n]
|
||||||
|
(let [warning (str "Error while fetching " (singularise (:name (:attrs e))) " record")]
|
||||||
|
;; TODO: as yet makes no attempt to save the record
|
||||||
|
(list 'let
|
||||||
|
(vector
|
||||||
|
'record (list
|
||||||
|
'support/do-or-log-error
|
||||||
|
(list 'if (list 'subset? (key-names e) (set (list 'keys 'p)))
|
||||||
|
(list
|
||||||
|
(symbol
|
||||||
|
(str "db/get-" (singularise (:name (:attrs e)))))
|
||||||
|
(symbol "db/*db*")
|
||||||
|
'p))
|
||||||
|
:message warning
|
||||||
|
:error-return {:warnings [warning]}))
|
||||||
|
(reduce
|
||||||
|
merge
|
||||||
|
{:warnings (list :warnings 'record)
|
||||||
|
:record (list 'assoc 'record :warnings nil)}
|
||||||
|
(map
|
||||||
|
(fn [p]
|
||||||
|
(hash-map
|
||||||
|
(keyword (-> p :attrs :entity))
|
||||||
|
(list 'support/do-or-log-error
|
||||||
|
(list (symbol (str "db/list-" (:entity (:attrs p)))) (symbol "db/*db*"))
|
||||||
|
:message (str "Error while fetching "
|
||||||
|
(singularise (:entity (:attrs p)))
|
||||||
|
" record"))))
|
||||||
|
(filter #(#{"entity" "link"} (:type (:attrs %)))
|
||||||
|
(descendants-with-tag e :property)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn make-page-handler-content
|
||||||
|
[f e a n]
|
||||||
|
(let [warning (str "Error while fetching " (singularise (:name (:attrs e))) " record")]
|
||||||
|
(list 'let
|
||||||
|
(vector 'record (list
|
||||||
|
'support/handler-content-log-error
|
||||||
|
(list 'if (list 'subset? (list 'keys 'p) (key-names e)) []
|
||||||
|
(list
|
||||||
|
(symbol
|
||||||
|
(str "db/get-" (singularise (:name (:attrs e)))))
|
||||||
|
(symbol "db/*db*")
|
||||||
|
'p))
|
||||||
|
:message warning
|
||||||
|
:error-return {:warnings [warning]}))
|
||||||
|
{:warnings (list :warnings 'record)
|
||||||
|
:record (list 'assoc 'record :warnings nil)})))
|
||||||
|
|
||||||
|
|
||||||
|
(defn make-list-handler-content
|
||||||
|
[f e a n]
|
||||||
|
(list
|
||||||
|
'let
|
||||||
|
(vector
|
||||||
|
'records
|
||||||
|
(list
|
||||||
|
'if
|
||||||
|
(list
|
||||||
|
'some
|
||||||
|
(set (map #(-> % :attrs :name) (all-properties e)))
|
||||||
|
(list 'keys 'p))
|
||||||
|
(list
|
||||||
|
'support/do-or-log-error
|
||||||
|
(list
|
||||||
|
(symbol
|
||||||
|
(str
|
||||||
|
"db/search-strings-"
|
||||||
|
(singularise (:name (:attrs e)))))
|
||||||
|
(symbol "db/*db*")
|
||||||
|
'p)
|
||||||
|
:message (str
|
||||||
|
"Error while searching "
|
||||||
|
(singularise (:name (:attrs e)))
|
||||||
|
" records")
|
||||||
|
:error-return {:warnings [(str
|
||||||
|
"Error while searching "
|
||||||
|
(singularise (:name (:attrs e)))
|
||||||
|
" records")]})
|
||||||
|
(list
|
||||||
|
'support/do-or-log-error
|
||||||
|
(list
|
||||||
|
(symbol
|
||||||
|
(str
|
||||||
|
"db/list-"
|
||||||
|
(:name (:attrs e))))
|
||||||
|
(symbol "db/*db*") {})
|
||||||
|
:message (str
|
||||||
|
"Error while fetching "
|
||||||
|
(singularise (:name (:attrs e)))
|
||||||
|
" records")
|
||||||
|
:error-return {:warnings [(str
|
||||||
|
"Error while fetching "
|
||||||
|
(singularise (:name (:attrs e)))
|
||||||
|
" records")]})))
|
||||||
|
(list 'if
|
||||||
|
(list :warnings 'records)
|
||||||
|
'records
|
||||||
|
{:records 'records})))
|
||||||
|
|
||||||
|
|
||||||
(defn make-handler
|
(defn make-handler
|
||||||
[f e a]
|
[f e a]
|
||||||
(let [n (path-part f e a)]
|
(let [n (path-part f e a)]
|
||||||
|
@ -122,6 +227,18 @@
|
||||||
(:name (:attrs e))))
|
(:name (:attrs e))))
|
||||||
(symbol "db/*db*") {}))})))))))
|
(symbol "db/*db*") {}))})))))))
|
||||||
|
|
||||||
|
;; (def a (x/parse "../youyesyet/youyesyet.canonical.adl.xml"))
|
||||||
|
;; (def e (child-with-tag a :entity))
|
||||||
|
;; (def f (child-with-tag e :form))
|
||||||
|
;; (def n (path-part f e a))
|
||||||
|
;; (vector
|
||||||
|
;; 'p
|
||||||
|
;; (list 'merge
|
||||||
|
;; {:offset 0 :limit 25}
|
||||||
|
;; (list 'support/massage-params (list :params 'r))))
|
||||||
|
;; (make-handler f e a)
|
||||||
|
|
||||||
|
|
||||||
(defn make-route
|
(defn make-route
|
||||||
"Make a route for method `m` to request the resource with name `n`."
|
"Make a route for method `m` to request the resource with name `n`."
|
||||||
[m n]
|
[m n]
|
||||||
|
@ -184,6 +301,16 @@
|
||||||
(list 'str (:name (:attrs application)) ".routes.auto/" 'n)))))))
|
(list 'str (:name (:attrs application)) ".routes.auto/" 'n)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn make-handlers
|
||||||
|
[e application]
|
||||||
|
(doall
|
||||||
|
(map
|
||||||
|
(fn [c]
|
||||||
|
(pprint (make-handler c e application))
|
||||||
|
(println))
|
||||||
|
(filter (fn [c] (#{:form :list :page} (:tag c))) (children e)))))
|
||||||
|
|
||||||
|
|
||||||
(defn to-selmer-routes
|
(defn to-selmer-routes
|
||||||
[application]
|
[application]
|
||||||
(let [filepath (str *output-path* "src/clj/" (:name (:attrs application)) "/routes/auto.clj")]
|
(let [filepath (str *output-path* "src/clj/" (:name (:attrs application)) "/routes/auto.clj")]
|
||||||
|
@ -203,13 +330,7 @@
|
||||||
(println)
|
(println)
|
||||||
(doall
|
(doall
|
||||||
(map
|
(map
|
||||||
(fn [e]
|
#(make-handlers % application)
|
||||||
(doall
|
|
||||||
(map
|
|
||||||
(fn [c]
|
|
||||||
(pprint (make-handler c e application))
|
|
||||||
(println))
|
|
||||||
(filter (fn [c] (#{:form :list :page} (:tag c))) (children e)))))
|
|
||||||
(sort
|
(sort
|
||||||
#(compare (:name (:attrs %1))(:name (:attrs %2)))
|
#(compare (:name (:attrs %1))(:name (:attrs %2)))
|
||||||
(children-with-tag application :entity))))
|
(children-with-tag application :entity))))
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
{:tag :div
|
{:tag :div
|
||||||
:attrs {:class "big-link-container"}
|
:attrs {:class "big-link-container"}
|
||||||
:content
|
:content
|
||||||
[{:tag :a :attrs {:href url}
|
[{:tag :a :attrs {:href url :class "big-link"}
|
||||||
:content (if
|
:content (if
|
||||||
(vector? content)
|
(vector? content)
|
||||||
content
|
content
|
||||||
|
@ -62,22 +62,24 @@
|
||||||
([filename application k]
|
([filename application k]
|
||||||
(emit-content filename nil nil application k))
|
(emit-content filename nil nil application k))
|
||||||
([filename spec entity application k]
|
([filename spec entity application k]
|
||||||
(let [content (:content
|
(let [content
|
||||||
|
(:content
|
||||||
(first
|
(first
|
||||||
(or (children-with-tag spec k)
|
(or (children-with-tag spec k)
|
||||||
(children-with-tag entity k)
|
(children-with-tag entity k)
|
||||||
(children-with-tag
|
(children-with-tag
|
||||||
(first
|
(child-with-tag application :content)
|
||||||
(children-with-tag application :content))
|
|
||||||
k))))]
|
k))))]
|
||||||
(if
|
(if
|
||||||
content
|
content
|
||||||
|
(flatten
|
||||||
(list
|
(list
|
||||||
(str "{% block " (name k) " %}")
|
(str "{% block " (name k) " %}")
|
||||||
|
(doall
|
||||||
(map
|
(map
|
||||||
#(with-out-str (x/emit-element %))
|
#(with-out-str (x/emit-element %))
|
||||||
content)
|
content))
|
||||||
"{% endblock %}")))))
|
"{% endblock %}"))))))
|
||||||
|
|
||||||
|
|
||||||
(defn file-header
|
(defn file-header
|
||||||
|
@ -484,7 +486,7 @@
|
||||||
:content
|
:content
|
||||||
[{:tag :input
|
[{:tag :input
|
||||||
:attrs {:type "submit"
|
:attrs {:type "submit"
|
||||||
:id "search"
|
:id "search-widget"
|
||||||
:value "Search"}}]})))}]})
|
:value "Search"}}]})))}]})
|
||||||
|
|
||||||
|
|
||||||
|
@ -540,51 +542,77 @@
|
||||||
"{% endfor %}"]})
|
"{% endfor %}"]})
|
||||||
|
|
||||||
|
|
||||||
(defn- list-page-control
|
|
||||||
"What this needs to do is emit an HTML control which, when selected, requests the
|
|
||||||
next or previous page keeping the same search parameters; so it essentially needs
|
|
||||||
to be a submit button, not a link."
|
|
||||||
[forward?]
|
|
||||||
{:tag :div
|
|
||||||
:attrs {:class (if forward? "big-link-container" "back-link-container")}
|
|
||||||
:content
|
|
||||||
[{:tag :input
|
|
||||||
:attrs {:id "page"
|
|
||||||
:name "page"
|
|
||||||
:disabled (if
|
|
||||||
forward?
|
|
||||||
false
|
|
||||||
"{% ifequal offset 0 %} false {% else %} true {% endifequal %}")
|
|
||||||
;; TODO: real thought needs to happen on doing i18n for this!
|
|
||||||
:value (if forward? "Next" "Previous")}}]})
|
|
||||||
|
|
||||||
|
|
||||||
(defn- list-tfoot
|
|
||||||
"Return a table footer element for the list view for this `list-spec` of this `entity` within
|
|
||||||
this `application`."
|
|
||||||
[list-spec entity application]
|
|
||||||
{:tag :tfoot
|
|
||||||
:content
|
|
||||||
[(list-page-control false)
|
|
||||||
(list-page-control true)]})
|
|
||||||
|
|
||||||
|
|
||||||
(defn list-to-template
|
(defn list-to-template
|
||||||
"Generate a template as specified by this `list` element for this `entity`,
|
"Generate a template as specified by this `list` element for this `entity`,
|
||||||
taken from this `application`. If `list` is nill, generate a default list
|
taken from this `application`. If `list` is nill, generate a default list
|
||||||
template for the entity."
|
template for the entity."
|
||||||
[list-spec entity application]
|
[list-spec entity application]
|
||||||
{:content
|
(let [form-name
|
||||||
{:tag :form
|
(str
|
||||||
:attrs {:id "content" :class "list"}
|
"list-"
|
||||||
|
(:name (:attrs entity))
|
||||||
|
"-"
|
||||||
|
(:name (:attrs list-spec)))]
|
||||||
|
{:back-links
|
||||||
|
{:tag :div
|
||||||
:content
|
:content
|
||||||
[(big-link (str "Add a new " (pretty-name entity)) (editor-name entity application))
|
[
|
||||||
|
{:tag :div :attrs {:class "back-link-container"}
|
||||||
|
:content
|
||||||
|
["{% ifequal params.offset \"0\" %}"
|
||||||
|
{:tag :a
|
||||||
|
:attrs {:id "back-link" :class "back-link" :href "{{servlet-context}}/admin"}
|
||||||
|
:content ["Back"]}
|
||||||
|
"{% else %}"
|
||||||
|
{:tag :a :attrs {:id "prev-selector" :class "back-link"}
|
||||||
|
:content ["Previous"]}
|
||||||
|
"{% endifunequal %}"]}
|
||||||
|
]}
|
||||||
|
:big-links
|
||||||
|
{:tag :div
|
||||||
|
:content
|
||||||
|
[{:tag :div :attrs {:class "big-link-container"}
|
||||||
|
:content
|
||||||
|
[{:tag :a :attrs {:id "next-selector" :role "button" :class "big-link"}
|
||||||
|
:content ["Next"]}]}
|
||||||
|
(big-link (str "Add a new " (pretty-name entity)) (editor-name entity application))]}
|
||||||
|
:content
|
||||||
|
{:tag :form
|
||||||
|
:attrs {:id form-name :class "list"
|
||||||
|
:action (str "{{servlet-context}}/" form-name)
|
||||||
|
:method "POST"}
|
||||||
|
:content
|
||||||
|
[(csrf-widget)
|
||||||
|
{:tag :input :attrs {:id "offset" :type "hidden" :value "{{params.offset|default:0}}"}}
|
||||||
|
{:tag :input :attrs {:id "limit" :type "hidden" :value "{{params.limit|default:50}}"}}
|
||||||
{:tag :table
|
{:tag :table
|
||||||
:attrs {:caption (:name (:attrs entity))}
|
:attrs {:caption (:name (:attrs entity))}
|
||||||
:content
|
:content
|
||||||
[(list-thead list-spec entity application)
|
[(list-thead list-spec entity application)
|
||||||
(list-tbody list-spec entity application)
|
(list-tbody list-spec entity application)
|
||||||
(list-tfoot list-spec entity application)]}]}})
|
]}]}
|
||||||
|
:extra-script
|
||||||
|
(str "
|
||||||
|
var form = document.getElementById('" form-name "');
|
||||||
|
var ow = document.getElementById('offset');
|
||||||
|
var lw = document.getElementById('limit');
|
||||||
|
form.addEventListener('submit', function() {
|
||||||
|
ow.value='0';
|
||||||
|
});
|
||||||
|
|
||||||
|
{% ifunequal params.offset \"0\" %}
|
||||||
|
document.getElementById('prev-selector').addEventListener('click', function () {
|
||||||
|
ow.value=(parseInt(ow.value)-parseInt(lw.value));
|
||||||
|
console.log('Updated offset to ' + ow.value);
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
{% endifunequal %}
|
||||||
|
|
||||||
|
document.getElementById('next-selector').addEventListener('click', function () {
|
||||||
|
ow.value=(parseInt(ow.value)+parseInt(lw.value));
|
||||||
|
console.log('Updated offset to ' + ow.value);
|
||||||
|
form.submit();
|
||||||
|
});")}))
|
||||||
|
|
||||||
|
|
||||||
(defn entity-to-templates
|
(defn entity-to-templates
|
||||||
|
@ -633,6 +661,7 @@
|
||||||
#(children-with-tag % :list)
|
#(children-with-tag % :list)
|
||||||
(children-with-tag application :entity)))]
|
(children-with-tag application :entity)))]
|
||||||
{:application-index
|
{:application-index
|
||||||
|
{:content
|
||||||
{:tag :dl
|
{:tag :dl
|
||||||
:attrs {:class "index"}
|
:attrs {:class "index"}
|
||||||
:content
|
:content
|
||||||
|
@ -658,16 +687,16 @@
|
||||||
:tag :p
|
:tag :p
|
||||||
:content (:content d)))
|
:content (:content d)))
|
||||||
(children-with-tag % :documentation))))
|
(children-with-tag % :documentation))))
|
||||||
first-class-entities)))}}))
|
first-class-entities)))}}}))
|
||||||
|
|
||||||
|
|
||||||
(defn write-template-file
|
(defn write-template-file
|
||||||
[filename template application]
|
[filename template application]
|
||||||
(let [filepath (str *output-path* "resources/templates/auto/" filename)]
|
(let [filepath (str *output-path* "resources/templates/auto/" filename)]
|
||||||
(make-parents filepath)
|
|
||||||
(if
|
(if
|
||||||
template
|
template
|
||||||
(try
|
(try
|
||||||
|
(do
|
||||||
(spit
|
(spit
|
||||||
filepath
|
filepath
|
||||||
(s/join
|
(s/join
|
||||||
|
@ -675,33 +704,36 @@
|
||||||
(flatten
|
(flatten
|
||||||
(list
|
(list
|
||||||
(file-header filename application)
|
(file-header filename application)
|
||||||
|
(doall
|
||||||
(map
|
(map
|
||||||
#(cond
|
#(let [content (template %)]
|
||||||
(:tag %)
|
(list
|
||||||
|
(str "{% block " (name %) " %}")
|
||||||
|
(cond (string? content)
|
||||||
|
content
|
||||||
|
(map? content)
|
||||||
(with-out-str
|
(with-out-str
|
||||||
(x/emit-element %))
|
(x/emit-element content))
|
||||||
(string? %)
|
|
||||||
%
|
|
||||||
true
|
true
|
||||||
(str ";; WTF? " %))
|
(str "<!-- don't know what to do with '" content "' -->"))
|
||||||
(:header template))
|
"{% endblock %}"))
|
||||||
"{% block content %}"
|
(keys template)))
|
||||||
(with-out-str
|
|
||||||
(x/emit-element (:content template)))
|
|
||||||
(file-footer filename application)))))
|
(file-footer filename application)))))
|
||||||
(if (> *verbosity* 0) (println "\tGenerated " filepath))
|
(if (> *verbosity* 0) (println "\tGenerated " filepath)))
|
||||||
(catch Exception any
|
(catch Exception any
|
||||||
(let [report (str
|
(let [report (str
|
||||||
"ERROR: Exception "
|
"ERROR: Exception "
|
||||||
(.getName (.getClass any))
|
(.getName (.getClass any))
|
||||||
(.getMessage any)
|
(.getMessage any)
|
||||||
" while printing "
|
" while printing "
|
||||||
filename)]
|
filepath)]
|
||||||
|
(try
|
||||||
(spit
|
(spit
|
||||||
filepath
|
filepath
|
||||||
(with-out-str
|
(with-out-str
|
||||||
(println (str "<!-- " report "-->"))
|
(println (str "<!-- " report "-->"))
|
||||||
(p/pprint template)))
|
(p/pprint template)))
|
||||||
|
(catch Exception _ nil))
|
||||||
(println report)
|
(println report)
|
||||||
(throw any)))))
|
(throw any)))))
|
||||||
(str filepath)))
|
(str filepath)))
|
||||||
|
|
Loading…
Reference in a new issue