diff --git a/backend/resources/templates/debug.tmpl b/backend/resources/templates/debug.tmpl
index 40f2e3c5b..56093e708 100644
--- a/backend/resources/templates/debug.tmpl
+++ b/backend/resources/templates/debug.tmpl
@@ -56,7 +56,12 @@ Debug Main Page
@@ -100,7 +105,7 @@ Debug Main Page
-
+
Do not break on index lookup erros (remap operation).
diff --git a/backend/src/app/http/debug.clj b/backend/src/app/http/debug.clj
index 03c2a090d..4753d0893 100644
--- a/backend/src/app/http/debug.clj
+++ b/backend/src/app/http/debug.clj
@@ -267,7 +267,8 @@
[{:keys [pool] :as cfg} {:keys [params profile-id] :as request}]
(let [file-id (some-> params :file-id parse-uuid)
libs? (contains? params :includelibs)
- clone? (contains? params :clone)]
+ clone? (contains? params :clone)
+ embed? (contains? params :embedassets)]
(when-not file-id
(ex/raise :type :validation
@@ -275,6 +276,7 @@
(let [path (-> cfg
(assoc ::binf/file-id file-id)
+ (assoc ::binf/embed-assets? embed?)
(assoc ::binf/include-libraries? libs?)
(binf/export!))]
(if clone?
@@ -283,6 +285,7 @@
(assoc cfg
::binf/input path
::binf/overwrite? false
+ ::binf/ignore-index-errors? true
::binf/profile-id profile-id
::binf/project-id project-id))
diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj
index dc46177e3..621b8fae7 100644
--- a/backend/src/app/rpc/commands/binfile.clj
+++ b/backend/src/app/rpc/commands/binfile.clj
@@ -330,6 +330,58 @@
(with-open [^AutoCloseable conn (db/open pool)]
(db/exec! conn [sql:file-library-rels (db/create-array conn "uuid" ids)])))
+(defn- embed-file-assets
+ [pool {:keys [id] :as file}]
+ (letfn [(walk-map-form [state form]
+ (cond
+ (uuid? (:fill-color-ref-file form))
+ (do
+ (vswap! state conj [(:fill-color-ref-file form) :colors (:fill-color-ref-id form)])
+ (assoc form :fill-color-ref-file id))
+
+ (uuid? (:stroke-color-ref-file form))
+ (do
+ (vswap! state conj [(:stroke-color-ref-file form) :colors (:stroke-color-ref-id form)])
+ (assoc form :stroke-color-ref-file id))
+
+ (uuid? (:typography-ref-file form))
+ (do
+ (vswap! state conj [(:typography-ref-file form) :typographies (:typography-ref-id form)])
+ (assoc form :typography-ref-file id))
+
+ (uuid? (:component-file form))
+ (do
+ (vswap! state conj [(:component-file form) :components (:component-id form)])
+ (assoc form :component-file id))
+
+ :else
+ form))
+
+ (process-group-of-assets [data [lib-id items]]
+ ;; NOTE: there are a posibility that shape refers to a not
+ ;; existing file because the file was removed. In this
+ ;; case we just ignore the asset.
+ (if-let [lib (retrieve-file pool lib-id)]
+ (reduce #(process-asset %1 lib %2) data items)
+ data))
+
+ (process-asset [data lib [bucket asset-id]]
+ (let [asset (get-in lib [:data bucket asset-id])
+ ;; Add a special case for colors that need to have
+ ;; correctly set the :file-id prop (pending of the
+ ;; refactor that will remove it).
+ asset (cond-> asset
+ (= bucket :colors) (assoc :file-id id))]
+ (update data bucket assoc asset-id asset)))]
+
+ (update file :data (fn [data]
+ (let [assets (volatile! [])]
+ (walk/postwalk #(cond->> % (map? %) (walk-map-form assets)) data)
+ (->> (deref assets)
+ (filter #(as-> (first %) $ (and (uuid? $) (not= $ id))))
+ (d/group-by first rest)
+ (reduce process-group-of-assets data)))))))
+
(defn write-export!
"Do the exportation of a speficied file in custom penpot binary
format. There are some options available for customize the output:
@@ -337,20 +389,28 @@
`::include-libraries?`: additionaly to the specified file, all the
linked libraries also will be included (including transitive
dependencies).
+
+ `::embed-assets?`: instead of including the libraryes, embedd in the
+ same file library all assets used from external libraries.
"
- [{:keys [pool storage ::output ::file-id ::include-libraries?]}]
- (let [libs (when include-libraries?
- (retrieve-libraries pool file-id))
- rels (when include-libraries?
- (retrieve-library-relations pool (cons file-id libs)))
+ [{:keys [pool storage ::output ::file-id ::include-libraries? ::embed-assets?]}]
+
+ (when (and include-libraries? embed-assets?)
+ (ex/raise :type :restriction
+ :code :mutual-exclusive-options-provided
+ :hint "the `include-libraries?` option is mutually exclusive with `embed-assets?`"))
+
+ (let [libs (when include-libraries? (retrieve-libraries pool file-id))
+ rels (when include-libraries? (retrieve-library-relations pool (cons file-id libs)))
files (into [file-id] libs)
- sids (atom #{})]
+ sids (volatile! #{})]
;; Write header with metadata
(l/debug :hint "exportation summary"
:files (count files)
:rels (count rels)
+ :embed-assets? embed-assets?
:include-libs? include-libraries?
::l/async false)
@@ -363,12 +423,13 @@
(l/debug :hint "write section" :section :v1/files :total (count files) ::l/async false)
(write-label! output :v1/files)
(doseq [file-id files]
- (let [file (retrieve-file pool file-id)
+ (let [file (cond->> (retrieve-file pool file-id)
+ embed-assets? (embed-file-assets pool))
media (retrieve-file-media pool file)]
;; Collect all storage ids for later write them all under
;; specific storage objects section.
- (swap! sids into (sequence storage-object-id-xf media))
+ (vswap! sids into (sequence storage-object-id-xf media))
(l/trace :hint "write penpot file"
:id file-id