├── .gitignore ├── README.mkd ├── project.clj ├── src └── clj_file_utils │ └── core.clj └── test └── clj_file_utils ├── core_test.clj └── core_test.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /autodoc 2 | /classes 3 | /lib 4 | /tmp 5 | /*.jar 6 | pom.xml 7 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | # clj-file-utils 2 | 3 | Unix-like filesystem manipulation utilities for Clojure, wrapping Apache 4 | Commons IO. 5 | 6 | Includes a `pchmod` function which changes file permissions in a portable 7 | way. 8 | 9 | ## Implemented Functions 10 | 11 | cp 12 | cp-r 13 | directory? 14 | exists? 15 | file 16 | file? 17 | ls 18 | mv 19 | rm 20 | rm-f 21 | rm-r 22 | rm-rf 23 | size 24 | touch 25 | mkdir-p 26 | chmod 27 | 28 | ## Usage 29 | 30 | user=> (use 'clj-file-utils.core) 31 | nil 32 | user=> (exists? "foo.txt") 33 | false 34 | user=> (touch "foo.txt") 35 | nil 36 | user=> (exists? "foo.txt") 37 | true 38 | user=> (rm "foo.txt") 39 | nil 40 | user=> (.getParent (file "/path/to/foo.txt")) 41 | "/path/to" 42 | 43 | ## Authors 44 | 45 | Extracted from by Mark McGranaghan 46 | 47 | Updates by Nate Murray , Min Huang 48 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject clj-file-utils "0.2.3-SNAPSHOT" 2 | :warn-on-reflection true 3 | :dependencies 4 | [[commons-io/commons-io "2.0"]] 5 | :dev-dependencies 6 | [[org.clojure/clojure "1.2.0"] 7 | [org.clojure/clojure-contrib "1.2.0"] 8 | [autodoc "0.7.1"] 9 | [swank-clojure "1.2.1"]] 10 | :namespaces [clj-file-utils.core] 11 | :repositories 12 | {"ibiblio" "http://mirrors.ibiblio.org/pub/mirrors/maven2"}) 13 | -------------------------------------------------------------------------------- /src/clj_file_utils/core.clj: -------------------------------------------------------------------------------- 1 | (ns clj-file-utils.core 2 | (:require [clojure.contrib.duck-streams :as streams]) 3 | (:require [clojure.contrib.io :as io]) 4 | (:use [clojure.contrib.shell-out :only (sh)]) 5 | (:import [java.io File]) 6 | (:import [org.apache.commons.io FileUtils]) 7 | (:gen-class)) 8 | 9 | (def 10 | ^{:doc "DEPRECATED. Prefer io/file." 11 | :deprecated "0.2.1"} 12 | file io/file) 13 | 14 | (def 15 | ^{:doc "DEPRECATED. Prefer io/pwd" 16 | :deprecated "0.2.1"} 17 | pwd io/pwd) 18 | 19 | (def 20 | ^{:doc "DEPRECATED. Prefer io/pwd" 21 | :deprecated "0.2.1"} 22 | cwd io/pwd) 23 | 24 | (defmacro defun [name docstring args & body] 25 | `(do 26 | (defmulti ~name ~docstring class) 27 | (defmethod ~name File ~args ~@body) 28 | (defmethod ~name String ~args (~name (io/file ~@args))) 29 | (defmethod ~name :default ~args false))) 30 | 31 | (defun file? 32 | "Returns true if the path is a file; false otherwise." 33 | [path] 34 | (.isFile ^File path)) 35 | 36 | (defun directory? 37 | "Returns true if the path is a directory; false otherwise." 38 | [path] 39 | (.isDirectory ^File path)) 40 | 41 | (defun exists? 42 | "Returns true if path exists; false otherwise." 43 | [path] 44 | (.exists ^File path)) 45 | 46 | (defn ls 47 | "List files in a directory." 48 | [dir] 49 | (seq (.listFiles (io/file dir)))) 50 | 51 | (defn touch 52 | "Create a file or update the last modified time." 53 | [path] 54 | (let [file (io/file path)] 55 | (do 56 | (.createNewFile file) 57 | (.setLastModified file (System/currentTimeMillis))))) 58 | 59 | (defn mkdir 60 | "Create a directory." 61 | [dir] 62 | (.mkdir (io/file dir))) 63 | 64 | (defn mkdir-p 65 | "Create a directory and all parent directories if they do not exist." 66 | [dir] 67 | (.mkdirs (io/file dir))) 68 | 69 | (defn canonical-path 70 | "Returns the canonical path of the file or directory." 71 | [path] 72 | (.getCanonicalPath (io/file path))) 73 | 74 | (defn size 75 | "Returns the size in bytes of a file." 76 | [file] 77 | (.length (io/file file))) 78 | 79 | (defn rm 80 | "Remove a file. Will throw an exception if the file cannot be deleted." 81 | [file] 82 | (io/delete-file file)) 83 | 84 | (defn rm-f 85 | "Remove a file, ignoring any errors." 86 | [file] 87 | (io/delete-file file true)) 88 | 89 | (defn rm-r 90 | "Remove a directory. The directory must be empty; will throw an exception 91 | if it is not or if the file cannot be deleted." 92 | [path] 93 | (io/delete-file-recursively path)) 94 | 95 | (defn rm-rf 96 | "Remove a directory, ignoring any errors." 97 | [path] 98 | (io/delete-file-recursively path true)) 99 | 100 | (defn cp 101 | "Copy a file, preserving last modified time by default." 102 | [from to & {:keys [preserve] :or {preserve true}}] 103 | (let [from-file (io/file from) 104 | to-file (io/file to)] 105 | (FileUtils/copyFile from-file to-file preserve))) 106 | 107 | (defn cp-r 108 | "Copy a directory, preserving last modified times by default." 109 | [from to & {:keys [preserve] :or {preserve true}}] 110 | (let [from-file (io/file from) 111 | to-file (io/file to)] 112 | (cond 113 | (and (file? from-file) (file? to-file)) 114 | (FileUtils/copyFile from-file to-file preserve) 115 | (and (file? from-file) (directory? to-file)) 116 | (FileUtils/copyFileToDirectory from-file to-file preserve) 117 | :default 118 | (FileUtils/copyDirectory from-file to-file (boolean preserve))))) 119 | 120 | (defn mv 121 | "Try to rename a file, or copy and delete if on another filesystem." 122 | [from to] 123 | (let [from-file (io/file from) 124 | to-file (io/file to)] 125 | (cond 126 | (and (file? from-file) 127 | (or (file? to-file) (not (exists? to-file)))) 128 | (FileUtils/moveFile from-file to-file) 129 | :default 130 | (FileUtils/moveToDirectory from-file to-file true)))) 131 | 132 | (defn mv-dir 133 | "DEPRECATED. Prefer mv. 134 | Moves a directory" 135 | ^{:deprecated "0.2.0"} 136 | [from to] 137 | (mv from to)) 138 | 139 | (defn mv-dir-to-dir 140 | "DEPRECATED. Prefer mv. 141 | Moves a directory to another directory." 142 | ^{:deprecated "0.2.0"} 143 | [from to] 144 | (mv from to)) 145 | 146 | (defn chmod 147 | "Changes file permissions (UNIX only); for portability, consider pchmod." 148 | [args path] 149 | (sh "chmod" args (.getAbsolutePath (io/file path)))) 150 | 151 | (defn pchmod 152 | "Change file permissions in a portable way." 153 | [path & {:keys [r w x]}] 154 | (let [file (io/file path)] 155 | (do 156 | (if-not (nil? r) (.setReadable file r)) 157 | (if-not (nil? w) (.setWritable file w)) 158 | (if-not (nil? x) (.setExecutable file x))))) 159 | -------------------------------------------------------------------------------- /test/clj_file_utils/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns clj-file-utils.core-test 2 | (:use [clj-file-utils.core] :reload) 3 | (:use [clojure.test]) 4 | (:require [clojure.contrib.io :as io]) 5 | (:import java.io.File)) 6 | 7 | (def test-file (io/file "test" "clj_file_utils" "core_test.txt")) 8 | 9 | (def tmp-dir (io/file "tmp")) 10 | 11 | (defn tmp-dir-fixture [f] 12 | (do 13 | (io/delete-file-recursively tmp-dir true) 14 | (.mkdirs tmp-dir) 15 | (f))) 16 | 17 | (deftest test-core 18 | (is (directory? "src")) 19 | (is (directory? (io/file "src"))) 20 | (is (not (directory? nil))) 21 | (is (file? test-file)) 22 | (is (file? (canonical-path test-file))) 23 | (is (exists? test-file)) 24 | (is (not (exists? nil)))) 25 | 26 | (deftest test-size 27 | (is (= 11 (size test-file))) 28 | (is (= 11 (size (canonical-path test-file))))) 29 | 30 | (deftest test-cp 31 | (let [to-file (io/file tmp-dir "test-cp")] 32 | (do 33 | (cp test-file to-file) 34 | (is (exists? to-file)) 35 | (is (file? to-file)) 36 | (is (= (.lastModified test-file) 37 | (.lastModified to-file)))))) 38 | 39 | (deftest test-mv-file-to-file 40 | (let [from-file (io/file tmp-dir "from-file") 41 | to-file (io/file tmp-dir "to-file")] 42 | (do 43 | (cp test-file from-file) 44 | (is (exists? from-file)) 45 | (mv from-file to-file) 46 | (is (not (exists? from-file))) 47 | (is (exists? to-file)) 48 | (is (file? to-file))))) 49 | 50 | (deftest test-mv-file-to-dir 51 | (let [from-file (io/file tmp-dir "from-file") 52 | to-dir (io/file tmp-dir "to-dir")] 53 | (do 54 | (cp test-file from-file) 55 | (is (exists? from-file)) 56 | (mkdir to-dir) 57 | (mv from-file to-dir) 58 | (is (not (exists? from-file))) 59 | (is (file? (file to-dir (.getName from-file))))))) 60 | 61 | (deftest test-mv-dir-to-dir 62 | (let [from-dir (io/file tmp-dir "from-dir") 63 | to-dir (io/file tmp-dir "to-dir")] 64 | (do 65 | (mkdir from-dir) 66 | (mv from-dir to-dir) 67 | (is (not (exists? from-dir))) 68 | (is (exists? to-dir)) 69 | (is (directory? to-dir))))) 70 | 71 | (deftest test-touch 72 | (let [file (io/file tmp-dir "test-touch")] 73 | (do 74 | (is (not (exists? file))) 75 | (touch file) 76 | (is (exists? file))))) 77 | 78 | (use-fixtures :each tmp-dir-fixture) 79 | -------------------------------------------------------------------------------- /test/clj_file_utils/core_test.txt: -------------------------------------------------------------------------------- 1 | Test file. 2 | --------------------------------------------------------------------------------