🐛 Fix migrations throwing exception on corrupted file (#9868)

This commit is contained in:
Belén Albeza 2026-05-26 12:07:22 +02:00 committed by GitHub
parent eb095169b8
commit 34f30e38aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -44,43 +44,55 @@
breaks the subcopy-head? predicate, which expects nil. Remove the explicit false so the
downstream fixers can recognize these shapes as nested copy heads."
[file-data]
(ctf/update-all-shapes
file-data
(fn [shape]
(if (false? (:component-root shape))
(do
(log/warn :msg "Normalizing :component-root false on shape"
:shape-id (:id shape)
:shape-name (:name shape)
:file-id (:id file-data))
{:result :update :updated-shape (dissoc shape :component-root)})
{:result :keep}))))
(try
(ctf/update-all-shapes
file-data
(fn [shape]
(if (false? (:component-root shape))
(do
(log/warn :msg "Normalizing :component-root false on shape"
:shape-id (:id shape)
:shape-name (:name shape)
:file-id (:id file-data))
{:result :update :updated-shape (dissoc shape :component-root)})
{:result :keep})))
(catch #?(:clj Throwable :cljs :default) e
(log/error :msg "Failed to normalize :component-root on shapes"
:file-id (:id file-data)
:cause e)
file-data)))
(defn fix-missing-swap-slots
"Locate shapes that have been swapped (i.e. their shape-ref does not point to the near match) but
they don't have a swap slot. In this case, add one pointing to the near match."
[file-data libraries]
(ctf/update-all-shapes
file-data
(fn [shape]
(if (ctk/subcopy-head? shape)
(let [container (:container (meta shape))
file {:id (:id file-data) :data file-data}
near-match (ctf/find-near-match file container libraries shape :include-deleted? true :with-context? false)]
(if (and (some? near-match)
(not= (:shape-ref shape) (:id near-match))
(nil? (ctk/get-swap-slot shape)))
(let [updated-shape (ctk/set-swap-slot shape (:id near-match))]
(log/warn :msg "Adding missing swap slot to shape"
:shape-id (:id shape)
:shape-name (:name shape)
:swap-slot (:id near-match)
:file-id (:id file)
:container-id (:id container)
:container-type (:type container))
{:result :update :updated-shape updated-shape})
{:result :keep}))
{:result :keep}))))
(try
(ctf/update-all-shapes
file-data
(fn [shape]
(if (ctk/subcopy-head? shape)
(let [container (:container (meta shape))
file {:id (:id file-data) :data file-data}
near-match (ctf/find-near-match file container libraries shape :include-deleted? true :with-context? false)]
(if (and (some? near-match)
(not= (:shape-ref shape) (:id near-match))
(nil? (ctk/get-swap-slot shape)))
(let [updated-shape (ctk/set-swap-slot shape (:id near-match))]
(log/warn :msg "Adding missing swap slot to shape"
:shape-id (:id shape)
:shape-name (:name shape)
:swap-slot (:id near-match)
:file-id (:id file)
:container-id (:id container)
:container-type (:type container))
{:result :update :updated-shape updated-shape})
{:result :keep}))
{:result :keep})))
(catch #?(:clj Throwable :cljs :default) e
(log/error :msg "Failed to fix missing swap slots on shapes"
:file-id (:id file-data)
:cause e)
file-data)))
(defn sync-component-id-with-ref-shape
"Ensure that all copies heads have the same component id and file as the referenced shape.
@ -88,40 +100,46 @@
[file-data libraries]
(letfn [(sync-one-iteration
[file-data libraries]
(ctf/update-all-shapes
file-data
(fn [shape]
(if (and (ctk/subcopy-head? shape) (nil? (ctk/get-swap-slot shape)))
(let [container (:container (meta shape))
file {:id (:id file-data) :data file-data}
ref-shape (ctf/find-ref-shape file container libraries shape {:include-deleted? true :with-context? true})]
(if (and (some? ref-shape)
(or (not= (:component-id shape) (:component-id ref-shape))
(not= (:component-file shape) (:component-file ref-shape))))
(let [shape' (cond-> shape
(some? (:component-id ref-shape))
(assoc :component-id (:component-id ref-shape))
(try
(ctf/update-all-shapes
file-data
(fn [shape]
(if (and (ctk/subcopy-head? shape) (nil? (ctk/get-swap-slot shape)))
(let [container (:container (meta shape))
file {:id (:id file-data) :data file-data}
ref-shape (ctf/find-ref-shape file container libraries shape {:include-deleted? true :with-context? true})]
(if (and (some? ref-shape)
(or (not= (:component-id shape) (:component-id ref-shape))
(not= (:component-file shape) (:component-file ref-shape))))
(let [shape' (cond-> shape
(some? (:component-id ref-shape))
(assoc :component-id (:component-id ref-shape))
(nil? (:component-id ref-shape))
(dissoc :component-id)
(nil? (:component-id ref-shape))
(dissoc :component-id)
(some? (:component-file ref-shape))
(assoc :component-file (:component-file ref-shape))
(some? (:component-file ref-shape))
(assoc :component-file (:component-file ref-shape))
(nil? (:component-file ref-shape))
(dissoc :component-file))]
(log/warn :msg "Syncing component id and file with ref shape"
:shape-id (:id shape)
:shape-name (:name shape)
:component-id (:component-id shape')
:component-file (:component-file shape')
:ref-shape-id (:id ref-shape)
:file-id (:id file)
:container-id (:id container)
:container-type (:type container))
{:result :update :updated-shape shape'})
{:result :keep}))
{:result :keep}))))]
(nil? (:component-file ref-shape))
(dissoc :component-file))]
(log/warn :msg "Syncing component id and file with ref shape"
:shape-id (:id shape)
:shape-name (:name shape)
:component-id (:component-id shape')
:component-file (:component-file shape')
:ref-shape-id (:id ref-shape)
:file-id (:id file)
:container-id (:id container)
:container-type (:type container))
{:result :update :updated-shape shape'})
{:result :keep}))
{:result :keep})))
(catch #?(:clj Throwable :cljs :default) e
(log/error :msg "Failed to sync component id and file with ref shape"
:file-id (:id file-data)
:cause e)
file-data)))]
;; If a copy inside a main is updated, we need to repeat the process for the change to be
;; propagated to all copies.
(loop [current-data file-data