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

Compile individual less files #11

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
.lein-deps-sum
.lein-failures
.lein-plugins
*~
.lein-repl-history
*~
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: clojure
lein: lein2
jdk:
- openjdk7
- openjdk6
28 changes: 22 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,45 @@
# Introduction

[![Build Status](https://travis-ci.org/mtnygard/lein-lesscss.png)](https://travis-ci.org/mtnygard/lein-lesscss)

This plugin allows the user to compile [Less CSS](http://lesscss.org/) resources
to be used in the application.

## Usage

* Add `[lein-lesscss "1.2"]` to the `:plugins` section in your `project.clj` or `~/.lein/profiles.clj` (the latter is Leiningen 2-specific).
* This is a fork of a fork.
* See the original one at http://github.com/fmancinelli/lein-lesscss
or use at your own risk.
* The original was forked by Sergey Shiskin at
https://github.com/shishkin/lein-lesscss with some nice
features. (Collected config into a single map, allows a single
starting file. Good for Bootstrap!)

* Add `[com.michaelnygard/lein-lesscss "1.5.1"]` to the `:plugins` section in your `project.clj`.

* Use the `lesscss` task to perform the compilation.

You can specify in your `project.clj` the `:lesscss-paths` attribute as a list
of directories where Less CSS files are stored. By default this parameter is set
to `less`. You can also specify the output path using `:lesscss-output-path`.
You can specify in your `project.clj` a `:lesscss` key for the
configuration. The `:paths` key is a list of files or directories
where Less CSS files are stored. By default this parameter is set to
`less`. You can also specify the output path using
`:output-path`. LESS compression can be turned on with `:compress
true`. Compression is off by default.

For example:

...
:lesscss-paths ["less" "path/to/other/location"]
:lesscss-output-path "resource/public/css"
:lesscss {:paths ["less" "path/to/other/location/style.less"]
:output-path "resource/public/css"
:compress true}
...

## Contributors

* Fabio Mancinelli <[email protected]>
* John Szakmeister <[email protected]>
* Sergey Shishkin <[email protected]>
* Michael Nygard <[email protected]>

## License

Expand Down
11 changes: 6 additions & 5 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>

(defproject lein-lesscss "1.3-SNAPSHOT"
(defproject com.michaelnygard/lein-lesscss "1.5.1-SNAPSHOT"
:description "Leiningen plugin for compiling Less CSS files."
:url "https://github.com/mtnygard/lein-lesscss"
:license {:name "LGPLv3"
:url "http://www.gnu.org/licenses/lgpl-3.0.en.html"}
:dependencies [[org.clojure/clojure "1.4.0"]
[org.lesscss/lesscss "1.3.0"]]
:eval-in-leiningen true
)
:scm {:name "git"
:url "https://github.com/mtnygard/lein-lesscss"}
:dependencies [[com.asual.lesscss/lesscss-engine "1.5.0"]]
:eval-in-leiningen true)
82 changes: 50 additions & 32 deletions src/leiningen/file_utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
;;
;; Contributors:
;; John Szakmeister <[email protected]>
;; Sergey Shishkin <[email protected]>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Expand All @@ -17,40 +18,57 @@
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>

(ns leiningen.file-utils)
(ns leiningen.file-utils
(:require [clojure.java.io :as io])
(:import [org.apache.commons.io FilenameUtils]))

;; The default extensions for identifying Less CSS files.
(def less-file-extensions #{"less"})
(defn path
"Returns canonical path of the clojure.java.io/file built with args."
[& args]
(.getCanonicalPath (apply io/file args)))

;; Convert the argument to a java.io.File
(defn to-file [o]
(cond (instance? java.io.File o) o
(instance? java.lang.String o) (new java.io.File o)
:else (new java.io.File (str o))
)
)
(def less-file-extensions
"The default extensions for identifying Less CSS files."
#{"less"})

;; Replace the file extension with another one.
(defn replace-extension [filename new-extension]
(clojure.string/replace filename (re-pattern (str (org.apache.commons.io.FilenameUtils/getExtension filename) "$")) new-extension)
)
(defn replace-extension
"Replace the file extension with another one."
[filename new-extension]
(-> filename
FilenameUtils/removeExtension
(str "." new-extension)
io/file))

;; Check if the file is a Less CSS file by looking at its extension.
(defn is-less-file? [x]
(let [file (to-file x)]
(defn is-less-file?
"Check if the file is a Less CSS file by looking at its extension."
[file]
(let [file (io/file file)]
(and
(.isFile file)
(org.apache.commons.io.FilenameUtils/isExtension (.getName file) less-file-extensions)
)
)
)

;; Recursively inspect the path to discover Less CSS files.
(defn list-less-files [path]
(let [dir (to-file path)
all-files (.listFiles dir)
directories (filter #(.isDirectory %) all-files)
standard-files (filter is-less-file? all-files)
]
(concat standard-files (mapcat list-less-files directories))
))
(.isFile file)
(-> file .getName
(FilenameUtils/isExtension less-file-extensions)))))

(defn list-less-files
"Recursively inspect the path to discover Less CSS files."
[file]
(->> file
io/file
file-seq
(filter is-less-file?)))

(defn canonical-dir-path
"Returns canonical path of file if it is a directory otherwise that of its parent."
[file]
(let [file (io/file file)
file (if (.isFile file) (.getParentFile file) file)]
(path file)))

(defn rebase-path
"Replace base with new-base in path."
[file base new-base]
(let [base (canonical-dir-path base)
new-base (canonical-dir-path new-base)
relative (-> file path
(clojure.string/replace base "."))]
(path new-base relative)))

97 changes: 57 additions & 40 deletions src/leiningen/lesscss.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
;;
;; Contributors:
;; John Szakmeister <[email protected]>
;; Sergey Shishkin <[email protected]>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Expand All @@ -18,50 +19,66 @@
;; along with this program. If not, see <http://www.gnu.org/licenses/>

(ns leiningen.lesscss
(:use [leiningen.file-utils :only [list-less-files to-file replace-extension]]
(:use [leiningen.file-utils]
[clojure.string :only [join]])
(:require [leiningen.core.main :as main]))
(:require [leiningen.core.main :as main]
[clojure.java.io :as io])
(:import [com.asual.lesscss LessEngine]))

;; Create an instance of the Less CSS compiler.
(def lesscss-compiler (delay (new org.lesscss.LessCompiler)))
(def default-settings
{:paths ["resources/less"]
:output-path "resources/public/css"
:compress false})

;; Return a list containing a single path where Less files are stored.
(defn default-lesscss-paths [project]
(cons (org.apache.commons.io.FilenameUtils/normalize (str (:root project) "/less")) nil))
(defn less-settings
"Returns a map of LESS project settings."
[project]
(merge default-settings (:lesscss project)))

;; Get the file where to store the compiled output. Its path will depend on the relative path in the source tree.
;; For example, if the path where less files are stored is '/.../projectdir/less/', the current less file is
;; '/.../projectdir/less/foo/bar.less' and the output path is '/.../projectdir/target/classes' then
;; the output path will be '/.../projectdir/target/classes/foo/bar.less'
(defn get-output-file [base-path file output-path]
(let [relative-path (clojure.string/replace (.getAbsolutePath file) base-path "")]
(to-file
(replace-extension (org.apache.commons.io.FilenameUtils/normalize (str output-path "/" relative-path)) "css")
)))
(defn get-output-file
"Get the file where to store the compiled output. Its path will depend on the
relative path in the source tree. For example, if the path where less files
are stored is '/.../projectdir/less/', the current less file is
'/.../projectdir/less/foo/bar.less' and the output path is
'/.../projectdir/target/classes' then the output path will be
'/.../projectdir/target/classes/foo/bar.less'"
[{file :file
base-path :base-path
output-path :output-path}]
(let [output-file (rebase-path file base-path output-path)]
(replace-extension output-file "css")))

;; Compile the Less CSS file to the specified output file.
(defn lesscss-compile [project prefix less-file output-path]
(let [output-file (get-output-file prefix less-file output-path)]
(try
(when (or (not (.exists output-file))
(> (.lastModified less-file) (.lastModified output-file)))
(.compile @lesscss-compiler less-file output-file))
(catch org.lesscss.LessException e
(str "ERROR: compiling " less-file ": " (.getMessage e))))))
(defn lesscss-compile
"Compile the source file to the output file as specified in task."
[compiler {file :file output-file :output-file compress :compress}]
(let [force-recompile false]
(try (.compile compiler (io/file file) (io/file output-file) force-recompile)
(catch com.asual.lesscss.LessException e
(str "ERROR: compiling " file ": " (.getMessage e))))))

(defn compiler
"Returns the compiler function."
[]
(partial lesscss-compile (LessEngine.)))

;; Leiningen task.
(defn lesscss "Compile Less CSS resources." [project & args]
(let [lesscss-paths (:lesscss-paths project (default-lesscss-paths project))
lesscss-output-path (or (:lesscss-output-path project)
(:compile-path project))
]
;; Iterate over all the Less CSS files and compile them
(doseq [less-path lesscss-paths]
(let [less-files (list-less-files less-path)
errors (doall
(filter identity
(for [less-file less-files]
(lesscss-compile project less-path less-file lesscss-output-path))))]
(if (not-empty errors)
(main/abort (join "\n" errors)))))))
(defn compiler-tasks
"Returns a sequence of maps, each representing single file compilation call."
[{paths :paths :as settings}]
(for [path paths
file (list-less-files path)
:let [task (assoc settings :file file :base-path path)]]
(assoc task :output-file (get-output-file task))))

(defn report-errors
"Aborts leiningen task in case of errors."
[results]
(when-let [errors (seq (filter identity results))]
(main/abort (join "\n" errors))))

(defn lesscss
"Compile Less CSS resources."
[project & args]
(let [settings (less-settings project)
compiler (compiler)
tasks (compiler-tasks settings)]
(report-errors (map compiler tasks))))