Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using include - java.io.FileNotFoundException: [projectpath]/src (Is a directory) #79

Open
trevor opened this issue Apr 23, 2015 · 11 comments

Comments

@trevor
Copy link
Contributor

trevor commented Apr 23, 2015

selmer v0.8.2

General project layout:

[projectpath]/project.clj
[projectpath]/src/...
[projectpath]/templates/layouts/main.html
[projectpath]/templates/includes/footer.html

Declared in proect.clj: :resource-paths ["public" "resources" "templates"]

This works:

(selmer.parser/render-file "layouts/main.html")

However when adding {% include "includes/footer.html" %} to main.html, this error is thrown:

java.io.FileNotFoundException: [projectpath]/src (Is a directory)
                   (Unknown Source) java.io.FileInputStream.open0
           FileInputStream.java:195 java.io.FileInputStream.open
           FileInputStream.java:138 java.io.FileInputStream.<init>
                         io.clj:238 clojure.java.io/fn
                          io.clj:69 clojure.java.io/fn[fn]
                         io.clj:165 clojure.java.io/fn
                          io.clj:69 clojure.java.io/fn[fn]
                         io.clj:102 clojure.java.io/reader
                    RestFn.java:410 clojure.lang.RestFn.invoke
                  validator.clj:103 selmer.validator/validate-tags
                  validator.clj:116 selmer.validator/validate
            template_parser.clj:196 selmer.template-parser/read-template
            template_parser.clj:252 selmer.template-parser/preprocess-template
                    RestFn.java:439 clojure.lang.RestFn.invoke
             template_parser.clj:51 selmer.template-parser/insert-includes[fn]
             template_parser.clj:41 selmer.template-parser/insert-includes
            template_parser.clj:252 selmer.template-parser/preprocess-template
                    RestFn.java:410 clojure.lang.RestFn.invoke
                     parser.clj:236 selmer.parser/parse-file
                     parser.clj:262 selmer.parser/parse
                    RestFn.java:442 clojure.lang.RestFn.invoke
                     parser.clj:122 selmer.parser/render-file
@yogthos
Copy link
Owner

yogthos commented Apr 23, 2015

You have to specify the absolute path with a leading / for templates with your directory structure, so {% include "/includes/footer.html" %} should work.

@trevor
Copy link
Contributor Author

trevor commented Apr 23, 2015

{% include "/includes/footer.html" %} gives:

clojure.lang.ExceptionInfo: resource-path for /includes/footer.html returned nil, typically means the file doesn't exist in your classpath.
                      core.clj:4403 clojure.core/ex-info
                   validator.clj:40 selmer.validator/validation-error
                   validator.clj:29 selmer.validator/validation-error
            template_parser.clj:194 selmer.template-parser/read-template
            template_parser.clj:252 selmer.template-parser/preprocess-template
                    RestFn.java:439 clojure.lang.RestFn.invoke
             template_parser.clj:51 selmer.template-parser/insert-includes[fn]
             template_parser.clj:41 selmer.template-parser/insert-includes
            template_parser.clj:252 selmer.template-parser/preprocess-template
                    RestFn.java:410 clojure.lang.RestFn.invoke
                     parser.clj:236 selmer.parser/parse-file
                     parser.clj:262 selmer.parser/parse
                    RestFn.java:442 clojure.lang.RestFn.invoke
                     parser.clj:122 selmer.parser/render-file

However {% include "../templates/includes/footer.html" %} will render the content.

It would be nice if "includes/footer.html" worked similarly to resource path matching:

website=> (clojure.java.io/resource "includes/footer.html")
#<URL file:[projectpath]/templates/includes/footer.html>

website=> (clojure.java.io/resource "/includes/footer.html")
nil

website=> (clojure.java.io/resource "../templates/includes/footer.html")
#<URL file:[projectpath]/templates/includes/footer.html>

@yogthos
Copy link
Owner

yogthos commented Apr 23, 2015

you should just be able to set the resource path as follows: (parser/set-resource-path! (clojure.java.io/resource "templates"))

@yogthos yogthos closed this as completed Apr 24, 2015
@trevor
Copy link
Contributor Author

trevor commented Apr 24, 2015

(clojure.java.io/resource "templates") returns nil however, doesn't appear to work.

@trevor
Copy link
Contributor Author

trevor commented Apr 24, 2015

If parser/set-resource-path! allowed for multiple paths, something like this might work, and may be a good default if it could be constrained to resource-paths:

(import 'java.io.File)
(selmer.parser/set-resource-path!
 (map #(str (File. ^String %))
      (.split (System/getProperty "java.class.path")
              (System/getProperty "path.separator")))

It's a nasty hack, but for illustration this happens to work:

(import 'java.io.File)
(selmer.parser/set-resource-path!
 (first (filter #(re-matches #".*/templates$" %)
                (map #(str (File. ^String %))
                     (.split (System/getProperty "java.class.path")
                             (System/getProperty "path.separator"))))))

@yogthos
Copy link
Owner

yogthos commented Apr 24, 2015

I recommend taking a look at how this is setup in Luminus. If you create a new project using lein new luminus mapp, it will create a templates folder under resources:

[projectpath]/resources/templates/

The myapp.layout namespace will set the resource path to:

(parser/set-resource-path! (clojure.java.io/resource "templates"))

You can now setup the templates using the your directory structure:

[projectpath]/resources/templates/layouts/main.html
[projectpath]/resources/templates/includes/footer.html

and you should be able to include using the /:

{% include "/includes/footer.html" %}

@trevor
Copy link
Contributor Author

trevor commented Apr 24, 2015

I see what you're saying, and that is a way around it, but it seems odd that file locating for include works differently than that for render-file.

For instance this works without any special setup:

(selmer.parser/render-file "includes/footer.html" {})

Why not have this behave in the same manner?

{% include "includes/footer.html" %}

I would expect it to yield the same sort of file locating approach in render-file unless overridden. (Which appears to be:)

(-> (Thread/currentThread)
  (.getContextClassLoader)
  (.getResource "includes/footer.html"))

@yogthos
Copy link
Owner

yogthos commented Apr 24, 2015

Sure, I agree that making that consistent would be an improvement. I won't have time to look at it in the near future though.

@yogthos yogthos reopened this Apr 24, 2015
@yogthos
Copy link
Owner

yogthos commented Apr 24, 2015

Would you be interested in making a pr with a fix?

@trevor
Copy link
Contributor Author

trevor commented Apr 24, 2015

I'm also short on time, but good to have this issue open for later if the opportunity comes up, or if anyone else would like to take a shot.

@yogthos
Copy link
Owner

yogthos commented Apr 24, 2015

sounds good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants