diff --git a/backend/src/uxbox/cli/collimp.clj b/backend/src/uxbox/cli/collimp.clj index 8eceacb86..9846af6d9 100644 --- a/backend/src/uxbox/cli/collimp.clj +++ b/backend/src/uxbox/cli/collimp.clj @@ -12,8 +12,8 @@ [mount.core :as mount] [cuerdas.core :as str] [suricatta.core :as sc] - [storages.core :as st] - [storages.fs :as fs] + [datoteka.storages :as st] + [datoteka.core :as fs] [uxbox.config] [uxbox.db :as db] [uxbox.migrations] @@ -68,7 +68,7 @@ {:pre [(fs/path? localpath) (uuid? collid) (uuid? iconid)]} - (let [filename (fs/base-name localpath) + (let [filename (fs/name localpath) extension (second (fs/split-ext filename)) data (svg/parse localpath) params {:name (:name data filename) @@ -85,7 +85,7 @@ (defn- import-icon [conn id fpath] {:pre [(uuid? id) (fs/path? fpath)]} - (let [filename (fs/base-name fpath) + (let [filename (fs/name fpath) iconid (uuid/namespaced +icons-uuid-ns+ (str id filename))] (when-not (retrieve-icon conn iconid) (println "Importing icon:" (str fpath)) @@ -95,8 +95,9 @@ [conn basedir {:keys [path regex] :as entry}] {:pre [(us/valid? ::import-entry entry)]} (let [id (create-icons-collection conn entry) - path (fs/resolve basedir path)] - (doseq [fpath (fs/list-files path)] + path (fs/join basedir path)] + (doseq [fpath (->> (fs/list-dir path) + (filter fs/regular-file?))] (when (re-matches regex (str fpath)) (import-icon conn id fpath))))) @@ -137,7 +138,7 @@ {:pre [(fs/path? localpath) (uuid? collid) (uuid? imageid)]} - (let [filename (fs/base-name localpath) + (let [filename (fs/name localpath) storage media/images-storage [width height] (retrieve-image-size localpath) extension (second (fs/split-ext filename)) @@ -157,7 +158,7 @@ (defn- import-image [conn id fpath] {:pre [(uuid? id) (fs/path? fpath)]} - (let [filename (fs/base-name fpath) + (let [filename (fs/name fpath) imageid (uuid/namespaced +images-uuid-ns+ (str id filename))] (when-not (retrieve-image conn imageid) (println "Importing image:" (str fpath)) @@ -167,8 +168,9 @@ [conn basedir {:keys [path regex] :as entry}] {:pre [(us/valid? ::import-entry entry)]} (let [id (create-images-collection conn entry) - path (fs/resolve basedir path)] - (doseq [fpath (fs/list-files path)] + path (fs/join basedir path)] + (doseq [fpath (->> (fs/list-dir path) + (filter fs/regular-file?))] (when (re-matches regex (str fpath)) (import-image conn id fpath))))) diff --git a/backend/src/uxbox/frontend/icons.clj b/backend/src/uxbox/frontend/icons.clj index c69c41ef4..9d7dc2417 100644 --- a/backend/src/uxbox/frontend/icons.clj +++ b/backend/src/uxbox/frontend/icons.clj @@ -8,7 +8,6 @@ (:require [clojure.spec :as s] [promesa.core :as p] [catacumba.http :as http] - [storages.core :as st] [uxbox.util.spec :as us] [uxbox.services :as sv] [uxbox.util.response :refer (rsp)] diff --git a/backend/src/uxbox/frontend/images.clj b/backend/src/uxbox/frontend/images.clj index a2001faa0..26d573915 100644 --- a/backend/src/uxbox/frontend/images.clj +++ b/backend/src/uxbox/frontend/images.clj @@ -8,8 +8,8 @@ (:require [clojure.spec :as s] [promesa.core :as p] [catacumba.http :as http] - [storages.core :as st] - [storages.fs :as fs] + [datoteka.storages :as st] + [datoteka.core :as fs] [uxbox.media :as media] [uxbox.images :as images] [uxbox.util.spec :as us] @@ -116,7 +116,7 @@ (let [{:keys [file id width height mimetype collection]} (us/conform ::create-image data) id (or id (uuid/random)) - filename (fs/base-name file) + filename (fs/name file) storage media/images-storage] (letfn [(persist-image-entry [path] (sv/novelty {:id id diff --git a/backend/src/uxbox/frontend/users.clj b/backend/src/uxbox/frontend/users.clj index 5e8ffa401..e895f2125 100644 --- a/backend/src/uxbox/frontend/users.clj +++ b/backend/src/uxbox/frontend/users.clj @@ -8,8 +8,8 @@ (:require [clojure.spec :as s] [promesa.core :as p] [catacumba.http :as http] - [storages.core :as st] - [storages.fs :as fs] + [datoteka.storages :as st] + [datoteka.core :as fs] [uxbox.media :as media] [uxbox.images :as images] [uxbox.util.spec :as us] @@ -80,7 +80,7 @@ (defn update-photo [{user :identity data :data}] (letfn [(store-photo [file] - (let [filename (fs/base-name file) + (let [filename (fs/name file) storage media/images-storage] (st/save storage filename file))) (assign-photo [path] diff --git a/backend/src/uxbox/images.clj b/backend/src/uxbox/images.clj index 9faf467b4..f3686b7a4 100644 --- a/backend/src/uxbox/images.clj +++ b/backend/src/uxbox/images.clj @@ -7,8 +7,10 @@ (ns uxbox.images "Image postprocessing." (:require [clojure.spec :as s] - [storages.core :as st] - [storages.fs :as fs] + [clojure.java.io :as io] + [datoteka.storages :as st] + [datoteka.core :as fs] + [datoteka.proto :as pt] [uxbox.util.spec :as us] [uxbox.media :as media] [uxbox.util.images :as images] diff --git a/backend/src/uxbox/media.clj b/backend/src/uxbox/media.clj index b81c5a36c..0d1ebc156 100644 --- a/backend/src/uxbox/media.clj +++ b/backend/src/uxbox/media.clj @@ -6,15 +6,13 @@ (ns uxbox.media "A media storage impl for uxbox." - (:require [mount.core :as mount :refer (defstate)] + (:require [mount.core :refer [defstate]] [clojure.java.io :as io] [cuerdas.core :as str] - [storages.core :as st] - [storages.backend.local :refer (localfs)] - [storages.backend.misc :refer (hashed scoped)] - [uxbox.config :refer (config)])) - -;; FIXME: migrate from storages to datoteka + [datoteka.storages :as st] + [datoteka.storages.local :refer [localfs]] + [datoteka.storages.misc :refer [hashed scoped]] + [uxbox.config :refer [config]])) ;; --- State diff --git a/backend/src/uxbox/portation.clj b/backend/src/uxbox/portation.clj index 85d447e8a..7a13f104c 100644 --- a/backend/src/uxbox/portation.clj +++ b/backend/src/uxbox/portation.clj @@ -9,7 +9,7 @@ (:refer-clojure :exclude [with-open]) (:require [clojure.java.io :as io] [suricatta.core :as sc] - [storages.fs :as fs] + [datoteka.core :as fs] [uxbox.db :as db] [uxbox.sql :as sql] [uxbox.util.uuid :as uuid] diff --git a/backend/src/uxbox/services/images.clj b/backend/src/uxbox/services/images.clj index 24e521f1d..57060a227 100644 --- a/backend/src/uxbox/services/images.clj +++ b/backend/src/uxbox/services/images.clj @@ -9,8 +9,8 @@ (:require [clojure.spec :as s] [promesa.core :as p] [suricatta.core :as sc] - [storages.core :as st] - [storages.fs :as fs] + [datoteka.storages :as st] + [datoteka.core :as fs] [uxbox.config :as ucfg] [uxbox.util.spec :as us] [uxbox.sql :as sql] @@ -184,7 +184,7 @@ (ex/raise :type :validation :code ::image-does-not-exists)) (let [path @(st/lookup storage (:path image)) - filename (fs/base-name path) + filename (fs/name path) path @(st/save storage filename path) image (assoc image :path (str path) diff --git a/backend/test/storages/tests.clj b/backend/test/storages/tests.clj deleted file mode 100644 index a10004b34..000000000 --- a/backend/test/storages/tests.clj +++ /dev/null @@ -1,106 +0,0 @@ -(ns storages.tests - (:require [clojure.test :as t] - [storages.core :as st] - [storages.backend.local :as local] - [storages.backend.misc :as misc]) - (:import java.io.File - org.apache.commons.io.FileUtils)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Test Fixtures -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn- clean-temp-directory - [next] - (next) - (let [directory (File. "/tmp/catacumba/")] - (FileUtils/deleteDirectory directory))) - -(t/use-fixtures :each clean-temp-directory) - -;; --- Tests: FileSystemStorage - -(t/deftest test-localfs-store-and-lookup - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - rpath @(st/save storage "test.txt" "my content") - fpath @(st/lookup storage rpath) - fdata (slurp fpath)] - (t/is (= (str fpath) "/tmp/catacumba/test/test.txt")) - (t/is (= "my content" fdata)))) - -(t/deftest test-localfs-store-and-get-public-url - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - rpath @(st/save storage "test.txt" "my content") - ruri (st/public-url storage rpath)] - (t/is (= (str ruri) "http://localhost:5050/test.txt")))) - -(t/deftest test-localfs-store-and-lookup-with-subdirs - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - rpath @(st/save storage "somepath/test.txt" "my content") - fpath @(st/lookup storage rpath) - fdata (slurp fpath)] - (t/is (= (str fpath) "/tmp/catacumba/test/somepath/test.txt")) - (t/is (= "my content" fdata)))) - -(t/deftest test-localfs-store-and-delete-and-check - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - rpath @(st/save storage "test.txt" "my content")] - (t/is @(st/delete storage rpath)) - (t/is (not @(st/exists? storage rpath))))) - -(t/deftest test-localfs-store-duplicate-file-raises-exception - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"})] - (t/is @(st/save storage "test.txt" "my content")) - (t/is (thrown? java.util.concurrent.ExecutionException - @(st/save storage "test.txt" "my content"))))) - -(t/deftest test-localfs-access-unauthorized-path - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"})] - (t/is (thrown? java.util.concurrent.ExecutionException - @(st/lookup storage "../test.txt"))) - (t/is (thrown? java.util.concurrent.ExecutionException - @(st/lookup storage "/test.txt"))))) - -;; --- Tests: ScopedPathStorage - -(t/deftest test-localfs-scoped-store-and-lookup - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - storage (misc/scoped storage "some/prefix") - rpath @(st/save storage "test.txt" "my content") - fpath @(st/lookup storage rpath) - fdata (slurp fpath)] - (t/is (= (str fpath) "/tmp/catacumba/test/some/prefix/test.txt")) - (t/is (= "my content" fdata)))) - -(t/deftest test-localfs-scoped-store-and-delete-and-check - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - storage (misc/scoped storage "some/prefix") - rpath @(st/save storage "test.txt" "my content")] - (t/is @(st/delete storage rpath)) - (t/is (not @(st/exists? storage rpath))))) - -(t/deftest test-localfs-scoped-store-duplicate-file-raises-exception - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - storage (misc/scoped storage "some/prefix")] - (t/is @(st/save storage "test.txt" "my content")) - (t/is (thrown? java.util.concurrent.ExecutionException - @(st/save storage "test.txt" "my content"))))) - -(t/deftest test-localfs-scoped-access-unauthorized-path - (let [storage (local/localfs {:basedir "/tmp/catacumba/test" - :baseuri "http://localhost:5050/"}) - storage (misc/scoped storage "some/prefix")] - (t/is (thrown? java.util.concurrent.ExecutionException - @(st/lookup storage "../test.txt"))) - (t/is (thrown? java.util.concurrent.ExecutionException - @(st/lookup storage "/test.txt"))))) - diff --git a/backend/test/uxbox/tests/helpers.clj b/backend/test/uxbox/tests/helpers.clj index 57620376d..89997c963 100644 --- a/backend/test/uxbox/tests/helpers.clj +++ b/backend/test/uxbox/tests/helpers.clj @@ -5,7 +5,7 @@ [buddy.core.codecs :as codecs] [catacumba.serializers :as sz] [mount.core :as mount] - [storages.core :as st] + [datoteka.storages :as st] [suricatta.core :as sc] [uxbox.services.auth :as usa] [uxbox.services.users :as usu] diff --git a/backend/test/uxbox/tests/test_images.clj b/backend/test/uxbox/tests/test_images.clj index 385183f61..6f664d363 100644 --- a/backend/test/uxbox/tests/test_images.clj +++ b/backend/test/uxbox/tests/test_images.clj @@ -4,7 +4,7 @@ [suricatta.core :as sc] [clojure.java.io :as io] [catacumba.testing :refer (with-server)] - [storages.core :as st] + [datoteka.storages :as st] [uxbox.db :as db] [uxbox.sql :as sql] [uxbox.media :as media] diff --git a/backend/vendor/storages/backend/local.clj b/backend/vendor/storages/backend/local.clj deleted file mode 100644 index 746612e8d..000000000 --- a/backend/vendor/storages/backend/local.clj +++ /dev/null @@ -1,104 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2016 Andrey Antukh - -(ns storages.backend.local - "A local filesystem storage implementation." - (:require [promesa.core :as p] - [clojure.java.io :as io] - [executors.core :as exec] - [storages.proto :as pt] - [storages.impl :as impl] - [storages.fs :as fs]) - (:import java.io.InputStream - java.io.OutputStream - java.net.URI - java.nio.file.Path - java.nio.file.Files)) - -(defn normalize-path - [^Path base ^Path path] - (if (fs/absolute? path) - (throw (ex-info "Suspicios operation: absolute path not allowed." - {:path (str path)})) - (let [^Path fullpath (.resolve base path) - ^Path fullpath (.normalize fullpath)] - (when-not (.startsWith fullpath base) - (throw (ex-info "Suspicios operation: go to parent dir is not allowed." - {:path (str path)}))) - fullpath))) - -(defn- save - [base path content] - (let [^Path path (pt/-path path) - ^Path fullpath (normalize-path base path)] - (when-not (fs/exists? (.getParent fullpath)) - (fs/create-dir! (.getParent fullpath))) - (with-open [^InputStream source (pt/-input-stream content) - ^OutputStream dest (Files/newOutputStream - fullpath fs/write-open-opts)] - (io/copy source dest) - path))) - -(defn- delete - [base path] - (let [path (->> (pt/-path path) - (normalize-path base))] - (Files/deleteIfExists ^Path path))) - -(defrecord LocalFileSystemBackend [^Path base ^URI baseuri] - pt/IPublicStorage - (-public-uri [_ path] - (.resolve baseuri (str path))) - - pt/IStorage - (-save [_ path content] - (exec/submit (partial save base path content))) - - (-delete [_ path] - (exec/submit (partial delete base path))) - - (-exists? [this path] - (try - (p/resolved - (let [path (->> (pt/-path path) - (normalize-path base))] - (fs/exists? path))) - (catch Exception e - (p/rejected e)))) - - pt/IClearableStorage - (-clear [_] - (fs/delete-dir! base) - (fs/create-dir! base)) - - pt/ILocalStorage - (-lookup [_ path'] - (try - (p/resolved - (->> (pt/-path path') - (normalize-path base))) - (catch Exception e - (p/rejected e))))) - -(defn localfs - "Create an instance of local FileSystem storage providing an - absolute base path. - - If that path does not exists it will be automatically created, - if it exists but is not a directory, an exception will be - raised." - [{:keys [basedir baseuri] :as keys}] - (let [^Path basepath (pt/-path basedir) - ^URI baseuri (pt/-uri baseuri)] - (when (and (fs/exists? basepath) - (not (fs/directory? basepath))) - (throw (ex-info "File already exists." {}))) - - (when-not (fs/exists? basepath) - (fs/create-dir! basepath)) - - (->LocalFileSystemBackend basepath baseuri))) - diff --git a/backend/vendor/storages/backend/misc.clj b/backend/vendor/storages/backend/misc.clj deleted file mode 100644 index 164b0d30d..000000000 --- a/backend/vendor/storages/backend/misc.clj +++ /dev/null @@ -1,111 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2016 Andrey Antukh - -(ns storages.backend.misc - "A local filesystem storage implementation." - (:require [promesa.core :as p] - [cuerdas.core :as str] - [buddy.core.codecs :as codecs] - [buddy.core.codecs.base64 :as b64] - [buddy.core.nonce :as nonce] - [buddy.core.hash :as hash] - [storages.proto :as pt] - [storages.impl :as impl] - [storages.backend.local :as local]) - (:import java.io.InputStream - java.io.OutputStream - java.nio.file.Path - java.nio.file.Files)) - -;; --- Scoped Storage - -(defrecord ScopedBackend [storage ^Path prefix] - pt/IPublicStorage - (-public-uri [_ path] - (let [^Path path (pt/-path [prefix path])] - (pt/-public-uri storage path))) - - pt/IStorage - (-save [_ path content] - (let [^Path path (pt/-path [prefix path])] - (->> (pt/-save storage path content) - (p/map (fn [^Path path] - (.relativize prefix path)))))) - - (-delete [_ path] - (let [^Path path (pt/-path [prefix path])] - (pt/-delete storage path))) - - (-exists? [this path] - (let [^Path path (pt/-path [prefix path])] - (pt/-exists? storage path))) - - pt/ILocalStorage - (-lookup [_ path] - (->> (pt/-lookup storage "") - (p/map (fn [^Path base] - (let [base (pt/-path [base prefix])] - (->> (pt/-path path) - (local/normalize-path base)))))))) - -(defn scoped - "Create a composed storage instance that automatically prefixes - the path when content is saved. For the rest of methods it just - relies to the underlying storage. - - This is usefull for atomatically add sertain prefix to some - uploads." - [storage prefix] - (let [prefix (pt/-path prefix)] - (->ScopedBackend storage prefix))) - -;; --- Hashed Storage - -(defn- generate-path - [^Path path] - (let [name (str (.getFileName path)) - hash (-> (nonce/random-nonce 128) - (hash/blake2b-256) - (b64/encode true) - (codecs/bytes->str)) - tokens (re-seq #"[\w\d\-\_]{3}" hash) - path-tokens (take 6 tokens) - rest-tokens (drop 6 tokens) - path (pt/-path path-tokens) - frest (apply str rest-tokens)] - (pt/-path (list path frest name)))) - -(defrecord HashedBackend [storage] - pt/IPublicStorage - (-public-uri [_ path] - (pt/-public-uri storage path)) - - pt/IStorage - (-save [_ path content] - (let [^Path path (pt/-path path) - ^Path path (generate-path path)] - (pt/-save storage path content))) - - (-delete [_ path] - (pt/-delete storage path)) - - (-exists? [this path] - (pt/-exists? storage path)) - - pt/ILocalStorage - (-lookup [_ path] - (pt/-lookup storage path))) - -(defn hashed - "Create a composed storage instance that uses random - hash based directory tree distribution for the final - file path. - - This is usefull when you want to store files with - not predictable uris." - [storage] - (->HashedBackend storage)) - diff --git a/backend/vendor/storages/core.clj b/backend/vendor/storages/core.clj deleted file mode 100644 index f817801be..000000000 --- a/backend/vendor/storages/core.clj +++ /dev/null @@ -1,52 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2016 Andrey Antukh - -(ns storages.core - "A storages abstraction layer." - (:require [storages.proto :as pt] - [storages.impl])) - -(defn save - "Perists a file or bytes in the storage. This function - returns a relative path where file is saved. - - The final file path can be different to the one provided - to this function and the behavior is totally dependen on - the storage implementation." - [storage path content] - (pt/-save storage path content)) - -(defn lookup - "Resolve provided relative path in the storage and return - the local filesystem absolute path to it. - This method may be not implemented in all storages." - [storage path] - {:pre [(satisfies? pt/ILocalStorage storage)]} - (pt/-lookup storage path)) - -(defn exists? - "Check if a relative `path` exists in the storage." - [storage path] - (pt/-exists? storage path)) - -(defn delete - "Delete a file from the storage." - [storage path] - (pt/-delete storage path)) - -(defn clear! - "Clear all contents of the storage." - [storage] - (pt/-clear storage)) - -(defn public-url - [storage path] - (pt/-public-uri storage path)) - -(defn storage? - "Return `true` if `v` implements IStorage protocol" - [v] - (satisfies? pt/IStorage v)) diff --git a/backend/vendor/storages/fs.clj b/backend/vendor/storages/fs.clj deleted file mode 100644 index 7e47e44d8..000000000 --- a/backend/vendor/storages/fs.clj +++ /dev/null @@ -1,168 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2016 Andrey Antukh - -(ns storages.fs - "File System helpers." - (:refer-clojure :exclude [name resolve]) - (:require [storages.proto :as pt]) - (:import java.nio.file.Path - java.nio.file.Files - java.nio.file.LinkOption - java.nio.file.OpenOption - java.nio.file.CopyOption - java.nio.file.StandardOpenOption - java.nio.file.StandardCopyOption - java.nio.file.SimpleFileVisitor - java.nio.file.FileVisitResult - java.nio.file.attribute.FileAttribute - java.nio.file.attribute.PosixFilePermissions - ratpack.form.UploadedFile)) - -;; --- Constants - -(def write-open-opts - (->> [StandardOpenOption/TRUNCATE_EXISTING - StandardOpenOption/CREATE - StandardOpenOption/WRITE] - (into-array OpenOption))) - -(def read-open-opts - (->> [StandardOpenOption/READ] - (into-array OpenOption))) - -(def move-opts - (->> [StandardCopyOption/ATOMIC_MOVE - StandardCopyOption/REPLACE_EXISTING] - (into-array CopyOption))) - -(def follow-link-opts - (into-array LinkOption [LinkOption/NOFOLLOW_LINKS])) - -;; --- Path Helpers - -(defn path - "Create path from string or more than one string." - ([fst] - (pt/-path fst)) - ([fst & more] - (pt/-path (cons fst more)))) - -(defn make-file-attrs - "Generate a array of `FileAttribute` instances - generated from `rwxr-xr-x` kind of expressions." - [^String expr] - (let [perms (PosixFilePermissions/fromString expr) - attr (PosixFilePermissions/asFileAttribute perms)] - (into-array FileAttribute [attr]))) - -(defn path? - "Return `true` if provided value is an instance of Path." - [v] - (instance? Path v)) - -(defn absolute? - "Return `true` if the provided path is absolute, `else` in case contrary. - The `path` parameter can be anything convertible to path instance." - [path] - (let [^Path path (pt/-path path)] - (.isAbsolute path))) - -(defn exists? - "Return `true` if the provided path exists, `else` in case contrary. - The `path` parameter can be anything convertible to path instance." - [path] - (let [^Path path (pt/-path path)] - (Files/exists path follow-link-opts))) - -(defn directory? - "Return `true` if the provided path is a directory, `else` in case contrary. - The `path` parameter can be anything convertible to path instance." - [path] - (let [^Path path (pt/-path path)] - (Files/isDirectory path follow-link-opts))) - -(defn parent - "Get parent path if it exists." - [path] - (.getParent ^Path (pt/-path path))) - -(defn base-name - "Get the file name." - [path] - (if (instance? UploadedFile path) - (.getFileName ^UploadedFile path) - (str (.getFileName ^Path (pt/-path path))))) - -(defn split-ext - "Returns a vector of `[name extension]`." - [path] - (let [base (base-name path) - i (.lastIndexOf base ".")] - (if (pos? i) - [(subs base 0 i) (subs base i)] - [base nil]))) - -(defn extension - "Return the extension part of a file." - [path] - (last (split-ext path))) - -(defn name - "Return the name part of a file." - [path] - (first (split-ext path))) - -(defn resolve - "Resolve path on top of an other path." - [base path] - (let [^Path base (pt/-path base) - ^Path path (pt/-path path)] - (-> (.resolve base path) - (.normalize)))) - -(defn list-directory - [path] - (let [path (pt/-path path)] - (with-open [stream (Files/newDirectoryStream path)] - (vec stream)))) - -(defn list-files - [path] - (filter (complement directory?) (list-directory path))) - -;; --- Side-Effectfull Operations - -(defn create-dir! - "Create a new directory." - [path] - (let [^Path path (pt/-path path) - attrs (make-file-attrs "rwxr-xr-x")] - (Files/createDirectories path attrs))) - -(defn create-dir! - "Create a new directory." - [path] - (let [^Path path (pt/-path path) - attrs (make-file-attrs "rwxr-xr-x")] - (Files/createDirectories path attrs))) - -(defn delete-dir! - [path] - (let [path (pt/-path path) - visitor (proxy [SimpleFileVisitor] [] - (visitFile [file attrs] - (Files/delete file) - FileVisitResult/CONTINUE) - (postVisitDirectory [dir exc] - (Files/delete dir) - FileVisitResult/CONTINUE))] - (Files/walkFileTree path visitor))) - -(defn create-tempfile - "Create a temporal file." - [& {:keys [suffix prefix]}] - (->> (make-file-attrs "rwxr-xr-x") - (Files/createTempFile prefix suffix))) diff --git a/backend/vendor/storages/impl.clj b/backend/vendor/storages/impl.clj deleted file mode 100644 index cda035e3c..000000000 --- a/backend/vendor/storages/impl.clj +++ /dev/null @@ -1,115 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2016 Andrey Antukh - -(ns storages.impl - "Implementation details and helpers." - (:require [storages.proto :as pt] - [storages.fs :as fs] - [buddy.core.codecs :as codecs] - [clojure.java.io :as io]) - (:import java.io.File - java.io.ByteArrayInputStream - java.io.InputStream - java.net.URL - java.net.URI - java.nio.file.Path - java.nio.file.Paths - java.nio.file.Files)) - -(extend-protocol pt/IContent - String - (-input-stream [v] - (ByteArrayInputStream. (codecs/str->bytes v))) - - Path - (-input-stream [v] - (io/input-stream v)) - - File - (-input-stream [v] - (io/input-stream v)) - - URI - (-input-stream [v] - (io/input-stream v)) - - URL - (-input-stream [v] - (io/input-stream v)) - - InputStream - (-input-stream [v] - v) - - ratpack.http.TypedData - (-input-stream [this] - (.getInputStream this))) - -(extend-protocol pt/IUri - URI - (-uri [v] v) - - String - (-uri [v] (URI. v))) - -(def ^:private empty-string-array - (make-array String 0)) - -(extend-protocol pt/IPath - Path - (-path [v] v) - - URI - (-path [v] (Paths/get v)) - - URL - (-path [v] (Paths/get (.toURI v))) - - String - (-path [v] (Paths/get v empty-string-array)) - - clojure.lang.Sequential - (-path [v] - (reduce #(.resolve %1 %2) - (pt/-path (first v)) - (map pt/-path (rest v))))) - -(defn- path->input-stream - [^Path path] - (Files/newInputStream path fs/read-open-opts)) - -(defn- path->output-stream - [^Path path] - (Files/newOutputStream path fs/write-open-opts)) - -(extend-type Path - io/IOFactory - (make-reader [path opts] - (let [^InputStream is (path->input-stream path)] - (io/make-reader is opts))) - (make-writer [path opts] - (let [^OutputStream os (path->output-stream path)] - (io/make-writer os opts))) - (make-input-stream [path opts] - (let [^InputStream is (path->input-stream path)] - (io/make-input-stream is opts))) - (make-output-stream [path opts] - (let [^OutputStream os (path->output-stream path)] - (io/make-output-stream os opts)))) - -(extend-type ratpack.http.TypedData - io/IOFactory - (make-reader [td opts] - (let [^InputStream is (.getInputStream td)] - (io/make-reader is opts))) - (make-writer [path opts] - (throw (UnsupportedOperationException. "read only object"))) - (make-input-stream [td opts] - (let [^InputStream is (.getInputStream td)] - (io/make-input-stream is opts))) - (make-output-stream [path opts] - (throw (UnsupportedOperationException. "read only object")))) - diff --git a/backend/vendor/storages/proto.clj b/backend/vendor/storages/proto.clj deleted file mode 100644 index c80e6548a..000000000 --- a/backend/vendor/storages/proto.clj +++ /dev/null @@ -1,38 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2016 Andrey Antukh - -(ns storages.proto - "A storage abstraction definition.") - -(defprotocol IUri - (-uri [_] "Coerce to uri.")) - -(defprotocol IPath - (-path [_] "Coerce to path.")) - -(defprotocol IContent - (-input-stream [_] "Coerce to input stream.")) - -(defprotocol IStorage - "A basic abstraction for storage access." - (-save [_ path content] "Persist the content under specified path.") - (-delete [_ path] "Delete the file by its path.") - (-exists? [_ path] "Check if file exists by path.")) - -(defprotocol IClearableStorage - (-clear [_] "clear all contents of the storage")) - -(defprotocol IPublicStorage - (-public-uri [_ path] "Get a public accessible uri for path.")) - -(defprotocol ILocalStorage - (-lookup [_ path] "Resolves the path to the local filesystem.")) - -(defprotocol IStorageIntrospection - (-accessed-time [_ path] "Return the last accessed time of the file.") - (-created-time [_ path] "Return the creation time of the file.") - (-modified-time [_ path] "Return the last modified time of the file.")) -