diff --git a/CHANGES.md b/CHANGES.md index 712c1d8f..994256d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ # Changes +## Master + +##### Task Options +- Added `-m, --mode` option to the `target` task — specifies the file + mode for written files — should only be used when default `rw-------` + is not enough. + ## 2.7.0 #### Improved diff --git a/boot/core/src/boot/core.clj b/boot/core/src/boot/core.clj index ad03e434..6ea3e262 100644 --- a/boot/core/src/boot/core.clj +++ b/boot/core/src/boot/core.clj @@ -1002,10 +1002,10 @@ (let [prev (atom nil) clean! (if clean empty-dir! identity) dirs (delay (mapv #(doto (io/file %) .mkdirs clean!) dirs))] - (fn [fs & {:keys [link]}] + (fn [fs & {:keys [link mode]}] (let [link (when link :tmp) [a b] [@prev (reset! prev (output-fileset fs))]] - (mapv deref (for [d @dirs :let [p! (partial fs/patch! (fs/->path d) a b :link)]] + (mapv deref (for [d @dirs :let [p! (partial fs/patch! (fs/->path d) a b :mode mode :link)]] (future (try (p! link) (catch Throwable t (if-not link (throw t) (p! nil))))))))))) diff --git a/boot/core/src/boot/task/built_in.clj b/boot/core/src/boot/task/built_in.clj index 3a8cce4c..1cc55802 100644 --- a/boot/core/src/boot/task/built_in.clj +++ b/boot/core/src/boot/task/built_in.clj @@ -22,6 +22,7 @@ [boot.pedantic :as pedantic]) (:import [java.io File] + [java.nio.file.attribute PosixFilePermissions] [java.util Arrays] [java.util.concurrent LinkedBlockingQueue TimeUnit] [javax.tools ToolProvider DiagnosticCollector Diagnostic$Kind])) @@ -361,16 +362,26 @@ (core/with-post-wrap [_] @(promise)) (core/with-pass-thru [fs] (Thread/sleep time)))) +(defn- mk-posix-file-permissions [posix-string] + (try + (when posix-string + (if (boot.App/isWindows) + (util/warn "Filemode not supported on Windows\n") + (PosixFilePermissions/fromString posix-string))) + (catch IllegalArgumentException _ + (util/warn "Could not parse mode string, ignoring...\n")))) + (core/deftask target "Writes output files to the given directory on the filesystem." [d dir PATH #{str} "The set of directories to write to (target)." + m mode VAL str "The mode of written files in 'rwxrwxrwx' format" L no-link bool "Don't create hard links." C no-clean bool "Don't clean target before writing project files."] (let [dir (or (seq dir) ["target"]) sync! (#'core/fileset-syncer dir :clean (not no-clean))] (core/with-pass-thru [fs] (util/info "Writing target dir(s)...\n") - (sync! fs :link (not no-link))))) + (sync! fs :link (not no-link) :mode (mk-posix-file-permissions mode))))) (core/deftask watch "Call the next handler when source files change." diff --git a/boot/pod/src/boot/file.clj b/boot/pod/src/boot/file.clj index 64fb8b3c..e4202d38 100644 --- a/boot/pod/src/boot/file.clj +++ b/boot/pod/src/boot/file.clj @@ -21,10 +21,14 @@ (def ^:dynamic *sync-delete* true) (def ^:dynamic *hard-link* true) +(def windows? (boot.App/isWindows)) + (def tmpfile-permissions (into-array FileAttribute - [(PosixFilePermissions/asFileAttribute - (PosixFilePermissions/fromString "rw-------"))])) + (if windows? + [] + [(PosixFilePermissions/asFileAttribute + (PosixFilePermissions/fromString "rw-------"))]))) (defn file? [f] (when (try (.isFile (io/file f)) (catch Throwable _)) f)) (defn dir? [f] (when (try (.isDirectory (io/file f)) (catch Throwable _)) f)) @@ -247,8 +251,7 @@ (defn match-filter? [filters f] - (let [windows? (boot.App/isWindows) - normalize #(if-not windows? % (str/replace % #"\\" "/"))] + (let [normalize #(if-not windows? % (str/replace % #"\\" "/"))] ((apply some-fn (map (partial partial re-find) filters)) (normalize (.getPath ^File f))))) (defn keep-filters? diff --git a/boot/pod/src/boot/filesystem.clj b/boot/pod/src/boot/filesystem.clj index c03bdd06..5f9d989c 100644 --- a/boot/pod/src/boot/filesystem.clj +++ b/boot/pod/src/boot/filesystem.clj @@ -38,6 +38,8 @@ (def read-only (PosixFilePermissions/fromString "r--r--r--")) +(def windows? (boot.App/isWindows)) + (defprotocol IToPath (->path [x] "Returns a java.nio.file.Path for x.")) @@ -155,20 +157,22 @@ (Files/setLastModifiedTime dst (FileTime/fromMillis time)))) (defn copy! - [^Path dest path ^Path src time] + [^Path dest path ^Path src time & {:keys [mode]}] (let [dst (doto (rel dest path) mkparents!)] (util/dbug* "Filesystem: copying %s...\n" (string/join "/" path)) (try (Files/copy ^Path src ^Path dst copy-opts) (Files/setLastModifiedTime dst (FileTime/fromMillis time)) + (when (and mode (not windows?)) (Files/setPosixFilePermissions dst mode)) (catch java.nio.file.NoSuchFileException ex (util/dbug* "Filesystem: %s\n", (str ex)))))) (defn link! - [dest path src] + [dest path src & {:keys [mode]}] (let [dst (rel dest path)] (util/dbug* "Filesystem: linking %s...\n" (string/join "/" path)) (try (Files/deleteIfExists dst) (Files/createLink (doto dst mkparents!) src) + (when (and mode (not windows?)) (Files/setPosixFilePermissions dst mode)) (catch java.nio.file.NoSuchFileException ex (util/dbug* "Filesystem: %s\n" (str ex)))))) @@ -188,11 +192,11 @@ (writer-fn os)))) (defn patch! - [dest before after & {:keys [link]}] + [dest before after & {:keys [link mode]}] (with-let [_ (fsp/patch-result before after)] (doseq [[op path & [arg1 arg2]] (fsp/patch before after link)] (case op :delete (delete! dest path) - :write (copy! dest path arg1 arg2) - :link (link! dest path arg1) + :write (copy! dest path arg1 arg2 :mode mode) + :link (link! dest path arg1 :mode mode) :touch (touch! dest path arg1)))))