mirror of https://github.com/penpot/penpot.git
108 lines
2.9 KiB
Clojure
108 lines
2.9 KiB
Clojure
;; 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) KALEIDOS INC
|
|
|
|
(ns app.util.shell
|
|
"Shell & FS utilities."
|
|
(:require
|
|
["node:child_process" :as proc]
|
|
["node:fs" :as fs]
|
|
["node:path" :as path]
|
|
[app.common.exceptions :as ex]
|
|
[app.common.logging :as l]
|
|
[app.common.time :as ct]
|
|
[app.common.uuid :as uuid]
|
|
[app.config :as cf]
|
|
[cuerdas.core :as str]
|
|
[promesa.core :as p]))
|
|
|
|
(l/set-level! :trace)
|
|
|
|
(def ^:const default-deletion-delay
|
|
(* 60 60 1)) ;; 1h
|
|
|
|
(def tmpdir
|
|
(let [path (cf/get :tempdir)]
|
|
(l/inf :hint "tmptdir setup" :path path)
|
|
(when-not (fs/existsSync path)
|
|
(fs/mkdirSync path #js {:recursive true}))
|
|
path))
|
|
|
|
(defn schedule-deletion
|
|
([path] (schedule-deletion path default-deletion-delay))
|
|
([path delay]
|
|
(let [remove-path
|
|
(fn []
|
|
(try
|
|
(when (fs/existsSync path)
|
|
(fs/rmSync path #js {:recursive true})
|
|
(l/trc :hint "tempfile permanently deleted" :path path))
|
|
(catch :default cause
|
|
(l/err :hint "error on deleting temporal file"
|
|
:path path
|
|
:cause cause))))
|
|
scheduled-at
|
|
(-> (ct/now) (ct/plus #js {:seconds delay}))]
|
|
|
|
(l/trc :hint "schedule tempfile deletion"
|
|
:path path
|
|
:scheduled-at (ct/format-inst scheduled-at))
|
|
|
|
(js/setTimeout remove-path (* delay 1000))
|
|
path)))
|
|
|
|
(defn tempfile
|
|
[& {:keys [prefix suffix]
|
|
:or {prefix "penpot."
|
|
suffix ".tmp"}}]
|
|
(loop [i 0]
|
|
(if (< i 1000)
|
|
(let [path (path/join tmpdir (str/concat prefix (uuid/next) "-" i suffix))]
|
|
(if (fs/existsSync path)
|
|
(recur (inc i))
|
|
(schedule-deletion path)))
|
|
(ex/raise :type :internal
|
|
:code :unable-to-locate-temporal-file
|
|
:hint "unable to find a tempfile candidate"))))
|
|
|
|
(defn move!
|
|
[origin-path dest-path]
|
|
(.rename fs/promises origin-path dest-path))
|
|
|
|
(defn stat
|
|
[path]
|
|
(->> (.stat fs/promises path)
|
|
(p/fmap (fn [data]
|
|
{:path path
|
|
:created-at (inst-ms (.-ctime ^js data))
|
|
:size (.-size data)}))
|
|
(p/merr (fn [_cause]
|
|
(p/resolved nil)))))
|
|
|
|
(defn rmdir!
|
|
[path]
|
|
(.rm fs/promises path #js {:recursive true}))
|
|
|
|
(defn write-file!
|
|
[fpath content]
|
|
(.writeFile fs/promises fpath content))
|
|
|
|
(defn read-file
|
|
[fpath]
|
|
(.readFile fs/promises fpath))
|
|
|
|
(defn run-cmd!
|
|
[cmd]
|
|
(p/create
|
|
(fn [resolve reject]
|
|
(l/trace :fn :run-cmd :cmd cmd)
|
|
(proc/exec cmd #js {:encoding "buffer"}
|
|
(fn [error stdout _stderr]
|
|
;; (l/trace :fn :run-cmd :stdout stdout)
|
|
(if error
|
|
(reject error)
|
|
(resolve stdout)))))))
|
|
|