<< Back to previous view

[CLJS-1298] source-on-disk conditional should include :source-url Created: 05/Jun/15  Updated: 05/Jan/16  Resolved: 05/Jan/16

Status: Resolved
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.145
Fix Version/s: 1.7.228

Type: Defect Priority: Major
Reporter: Bruce Hauman Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None



cljs.closure/source-on-disk is conditional on having the IJavaScript having a :source-url. Currently this conditional is exercised after the call to util/ext. But util/ext has a precondition that will fail on a nil :source-url.

Solution: protect util/ext by checking for :source-url before calling util/ext.

(defn source-on-disk
  "Ensure that the given IJavaScript exists on disk in the output directory.
  Return updated IJavaScript with the new location if necessary."
  [opts js]
  (if (write-js? js)
    (write-javascript opts js)
    ;; always copy original ClojureScript sources to the output directory
    ;; when source maps enabled
    (let [out-file (when-let [ns (and (:source-map opts)
                                      (:source-url js) ;;<--- ADD THIS HERE
                                      (first (:provides js)))]
                     (io/file (io/file (util/output-directory opts))
                       (util/ns->relpath ns (util/ext (:source-url js)))))
          source-url (:source-url js)]
      (when (and out-file source-url
                 (or (not (.exists ^File out-file))
                     (> (.lastModified (io/file source-url))
                        (.lastModified out-file))))
        (spit out-file (slurp source-url)))

Or some refactoring of the above.

Comment by David Nolen [ 05/Jun/15 2:20 PM ]

In what cases will an IJavaScript not have a :source-url? Just trying to get some context.

Comment by Bruce Hauman [ 05/Jun/15 2:42 PM ]

Good question. When the sources are already output javascript and they have an output dir relative :url but not a :source-url, this doesn't seem like it should happen.

I'm getting a situation like this

:url #object[java.net.URL 0x5f921081 "file:/Users/brucehauman/workspace/temp/hello-world/resources/goog/uri/utils.js"]
:source-url nil

Comment by David Nolen [ 05/Jun/15 2:58 PM ]

Ok that seems like the real underlying issue. Do you have a small reproducer by chance?

Comment by Bruce Hauman [ 05/Jun/15 3:08 PM ]

It seems like its when the :asset-path is "". And :output-dir is at the root of a resource path like :output-dir "resources".

Comment by Sebastian Bensusan [ 14/Oct/15 4:14 PM ]

I have been able to reproduce the issue here with the following build script:

(cljs.build.api/build "src"
  {:main 'cljs-1298.core
   :output-to "resources/cljs_1298.js"
   :output-dir "resources"
   :asset-path "resources"  ;; <- Note that is not "" as described earlier
   :verbose true})

As described in the ticket, the error is an AssertionError[1] from a call to (cljs.util/ext nil) during compilation.

[1] AssertionError Assert failed: (or (file? x) (url? x) (string? x)) cljs.util/ext (util.cljc:124)

Comment by David Nolen [ 14/Oct/15 4:34 PM ]

Ok so we have a counter example, but still no clue about how the failure comes to be?

Comment by Sebastian Bensusan [ 15/Oct/15 8:25 AM ]

I think it's a classpath clash of resources. If for some reason a IJavaScript has an :url that is already on the :output-dir then the error happens. This happens when the :output-dir is exactly loaded under resources because (io/resources "goog/base.js") is used.

Longer explanation:

After some investigation, I can reproduce it only when both the source folder and the :output-dir/:asset-path are on the classpath. If "src" is not in the classpath it doesn't happen.

The first file to trigger the error is "goog/base.js" but only in the second run of cljs.closure/build. In the first run, "goog/base.js" has the following IJavaScript value:

#cljs.closure.JavaScriptFile{:foreign nil,
:url #object[java.net.URL 0x212b731a jar:file:/home/carlos/.m2/repository/org/clojure/google-closure-library/0.0-20150805-acd8b553/google-closure-library-0.0-20150805-acd8b553.jar!/goog/base.js],
:source-url nil, 
:provides (goog), :requires (), :lines nil, :source-map nil}

which has :url in a jar and triggers cljs.closure/write-javascript.

In the second run, goog/base.js is searched under resources:

(defn add-dependencies [opts & inputs]
  (javascript-file nil (io/resource "goog/base.js") ["goog"] nil)

and io/resources finds it on the :output-dir which is also in resources, which results in this IJavaScript value:

#cljs.closure.JavaScriptFile{:foreign nil, 
:url #object[java.net.URL 0x7879862 file:/home/carlos/OpenSource/clojurescript/resources/goog/base.js],
:source-url nil,
:provides (goog), :requires (),
:lines nil, :source-map nil}

which results in the error since it doesn't trigger write-js? and then has no :source-map.

Comment by Sebastian Bensusan [ 15/Oct/15 8:29 AM ]

Also, Bruce's proposed fix properly sweeps the issue under the rug.

Comment by David Nolen [ 05/Jan/16 4:30 PM ]

fixed https://github.com/clojure/clojurescript/commit/17e167effe2c62f988e659f812dfecb8b4b8f26f

Generated at Mon Feb 08 04:25:37 CST 2016 using JIRA 4.4#649-r158309.