Skip to content

Commit

Permalink
Fix #102: add gzip and gunzip functions (#104)
Browse files Browse the repository at this point in the history
Co-authored-by: Lauri Oherd <[email protected]>
Co-authored-by: Lauri Oherd <[email protected]>
  • Loading branch information
3 people authored Jun 4, 2023
1 parent 2c0905e commit b751410
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ For a list of breaking changes, check [here](#breaking-changes).

Babashka [fs](https://github.com/babashka/fs): file system utility library for Clojure

## Unreleased

- [#102](https://github.com/babashka/fs/issues/102): add `gzip` and `gunzip` functions

## v0.4.19 (2023-05-24)

- [#97](https://github.com/babashka/fs/issues/97): add `owner` function to retrieve owner of a file or directory ([@emilaasa](https://github.com/emilaasa))
Expand Down
53 changes: 51 additions & 2 deletions src/babashka/fs.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
FileVisitor]
[java.nio.file.attribute BasicFileAttributes FileAttribute FileTime PosixFilePermissions]
[java.nio.charset Charset]
[java.util.zip ZipInputStream ZipOutputStream ZipEntry]
[java.util.zip GZIPInputStream GZIPOutputStream ZipInputStream ZipOutputStream ZipEntry]
[java.io File BufferedInputStream FileInputStream FileOutputStream]))

(set! *warn-on-reflection* true)
Expand Down Expand Up @@ -415,7 +415,7 @@

(defn create-dirs
"Creates directories using `Files#createDirectories`. Also creates parents if needed.
Doesn't throw an exception if the the dirs exist already. Similar to mkdir -p"
Doesn't throw an exception if the dirs exist already. Similar to `mkdir -p`"
([path] (create-dirs path nil))
([path {:keys [:posix-file-permissions]}]
(Files/createDirectories (as-path path) (posix->attrs posix-file-permissions))))
Expand Down Expand Up @@ -1012,6 +1012,55 @@

;;;; End zip

;;;; GZip

(defn gunzip
"Extracts `gz-file` to `dest` directory (default `\".\"`).
Options:
* `:replace-existing` - `true` / `false`: overwrite existing files"
([gz-file] (gunzip gz-file "."))
([gz-file dest] (gunzip gz-file dest nil))
([gz-file dest {:keys [replace-existing]}]
(let [output-path (as-path dest)
dest-filename (str/replace-first gz-file #"\.gz$" "")
gz-file (as-path gz-file)
_ (create-dirs dest)
cp-opts (->copy-opts replace-existing nil nil nil)
new-path (.resolve output-path dest-filename)]
(with-open
[fis (Files/newInputStream gz-file (into-array java.nio.file.OpenOption []))
gzis (GZIPInputStream. fis)]
(create-dirs (parent new-path))
(Files/copy ^java.io.InputStream gzis
new-path
cp-opts)))))

(defn gzip
"Gzips `source-file` and writes the output to `dir/out-file`.
If `out-file` is not provided, the `source-file` name with `.gz` appended is used.
If `dir` is not provided, the current directory is used.
Returns the created gzip file."
([source-file]
(gzip source-file {:dir "."}))
([source-file {:keys [dir out-file] :or {dir "."}}]
(assert source-file "source-file must be specified")
(assert (-> source-file io/file .exists) "source-file does not exist")
(let [output-path (as-path dir)
^String dest-filename (if (not out-file)
(str source-file ".gz")
(str out-file))
new-path (.resolve output-path dest-filename)]
(create-dirs (parent new-path))
(with-open [source-input-stream (io/input-stream source-file)
gzos (GZIPOutputStream.
(FileOutputStream. (file new-path)))]
(io/copy source-input-stream
gzos))
(str new-path))))

;;;; End gzip

(defmacro with-temp-dir
"Evaluate body with binding-name bound to a temporary directory.
Expand Down
20 changes: 20 additions & 0 deletions test/babashka/fs_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,26 @@
(is (fs/exists? (fs/file td-out "babashka" "fs.cljc")))
(is (not (fs/directory? (fs/file td-out "babashka" "fs.cljc")))))))

(deftest gzip-gunzip-test
(let [td (fs/create-temp-dir)
td-out (fs/path td "out")
gz-file (fs/path td-out "README.md.gz")]
(is (= (str gz-file)
(fs/gzip "README.md" {:dir td-out})))
(is (fs/gunzip gz-file td-out))
(is (fs/exists? (fs/path td-out "README.md")))
(is (= (slurp "README.md") (slurp (fs/file td-out "README.md"))))
(is (thrown? java.nio.file.FileAlreadyExistsException (fs/gunzip gz-file td-out)))
(testing "no exception when replacing existing"
(is (do (fs/gunzip gz-file td-out {:replace-existing true})
true)))
(testing "accepts out-file for specifying a custom gzip filename"
(let [out-file "doc.md.gz"]
(is (= (str (fs/path td-out out-file))
(fs/gzip "README.md" {:dir td-out
:out-file out-file})))
(is (fs/exists? (fs/path td-out out-file)))))))

(deftest with-temp-dir-test
(let [capture-dir (volatile! nil)]
(testing "with-temp-dir"
Expand Down

0 comments on commit b751410

Please sign in to comment.