/
base.clj
103 lines (85 loc) · 3.19 KB
/
base.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
(ns tech.io.base
"Basic io that handles most simple cases"
(:require [tech.io.protocols :as io-prot]
[tech.io.url :as url]
[clojure.java.io :as io]
[me.raynes.fs :as fs])
(:import [java.io File InputStream OutputStream]
[java.nio.file Files LinkOption]
[java.util Date]))
(set! *warn-on-reflection* true)
(defn- io-input-stream
[url-parts options]
(io/make-input-stream (url/parts->url url-parts) options))
(defn- io-output-stream
[url-parts options]
(io/make-output-stream (url/parts->url url-parts) options))
(defn- file->last-modify-time
[^File file]
(-> (Files/getLastModifiedTime (.toPath file)
(make-array LinkOption 0))
(.toMillis)
(Date.)))
(defn file->byte-length
^long [^File file]
(-> (.toPath file)
Files/size))
(defn parts->file
[url-parts]
(when-not (= :file (:protocol url-parts))
(throw (ex-info "Not a file" url-parts)))
(io/file (url/parts->file-path url-parts)))
(extend-protocol io-prot/IOProvider
Object
(input-stream [this url-parts options] (io-input-stream url-parts options))
(output-stream! [this url-parts options] (io-output-stream url-parts options))
(exists? [this url-parts options]
(try
(.close ^InputStream (io-prot/input-stream this url-parts options))
true
(catch Throwable e false)))
(ls [this url-parts options]
(throw (ex-info "Unimplemented" url-parts)))
(delete! [this url-parts options]
(throw (ex-info "Unimplemented" url-parts)))
(metadata [provider url-parts options] {})
File
(input-stream [this url-parts options]
(io/make-input-stream (parts->file url-parts) options))
(output-stream! [this url-parts options]
(let [fileme (parts->file url-parts)]
(io/make-parents fileme)
(io/make-output-stream fileme options)))
(exists? [this url-parts options]
(.exists ^File this))
(ls [this url-parts options]
(let [fileme (parts->file url-parts)]
(->> (if (:recursive? options)
(file-seq fileme)
(fs/list-dir fileme))
(map (fn [^File f]
{:url (str "file://" (.toString f))
:directory? (.isDirectory f)})))))
(delete! [this url-parts options]
(fs/delete-dir this))
(metadata [provider url-parts options]
{:modify-date (file->last-modify-time provider)
:byte-length (file->byte-length provider)}))
(extend-protocol io-prot/ICopyObject
Object
(get-object [provider url-parts options]
(io-prot/input-stream provider url-parts options))
(put-object! [provider url-parts value options]
(with-open [^InputStream in-s (io/input-stream value)
^OutputStream out-s (io-prot/output-stream! provider url-parts options)]
(io/copy in-s out-s)))
File
(get-object [provider url-parts options] (parts->file url-parts))
(put-object! [provider url-parts value options]
(let [fileme (parts->file url-parts)]
(io/make-parents fileme)
;;A short bit ot looking around makes it appear that stream copy
;;is fastest for files.
(with-open [in-s (io/input-stream value)
out-s (io/output-stream fileme)]
(io/copy in-s out-s)))))