|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
| 3 | +using System.IO; |
3 | 4 | using Microsoft.Data.Sqlite; |
4 | 5 | using UnityDataTools.Analyzer.SQLite.Commands.ContentLayout; |
5 | 6 | using UnityDataTools.Models; |
@@ -27,6 +28,9 @@ internal class ContentLayoutSQLWriter : IDisposable |
27 | 28 | private bool m_Initialized; |
28 | 29 | private SqliteConnection m_Database; |
29 | 30 |
|
| 31 | + // The layout files that can have a .cf file on disk, kept for LinkSerializedFiles. |
| 32 | + private List<(int Index, string ContentHash)> m_ImportedFiles = new(); |
| 33 | + |
30 | 34 | public ContentLayoutSQLWriter(SqliteConnection database) |
31 | 35 | { |
32 | 36 | m_Database = database; |
@@ -75,10 +79,16 @@ public void WriteContentLayout(string filename, ContentLayout layout) |
75 | 79 | m_AddSerializedFile.SetValue("is_builtin", file.IsBuiltIn ? 1 : 0); |
76 | 80 | m_AddSerializedFile.SetValue("content_hash", |
77 | 81 | string.IsNullOrEmpty(file.ContentHash) ? null : file.ContentHash); |
78 | | - // Filled in when the analyzed input also contains the build content. |
| 82 | + // Filled in by LinkSerializedFiles when the analyzed input also contains the |
| 83 | + // build content. |
79 | 84 | m_AddSerializedFile.SetValue("serialized_file", null); |
80 | 85 | m_AddSerializedFile.ExecuteNonQuery(); |
81 | 86 |
|
| 87 | + if (!string.IsNullOrEmpty(file.ContentHash)) |
| 88 | + { |
| 89 | + m_ImportedFiles.Add((file.Index, file.ContentHash)); |
| 90 | + } |
| 91 | + |
82 | 92 | // Empty arrays can be omitted from the json, leaving the fields null. |
83 | 93 | foreach (var assetPath in file.SourceAssets ?? []) |
84 | 94 | { |
@@ -166,6 +176,52 @@ public void WriteContentLayout(string filename, ContentLayout layout) |
166 | 176 | ExecuteDDL(Properties.Resources.ContentLayoutIndexes); |
167 | 177 | } |
168 | 178 |
|
| 179 | + // Fills in the serialized_file column, linking each layout entry to the serialized_files |
| 180 | + // row of its analyzed .cf file. Called after all files are processed; entries whose file |
| 181 | + // was not part of the analyzed input (e.g. a layout-only analyze) stay NULL. The match is |
| 182 | + // on the file name (the content hash), ignoring any directory part that the analyze pass |
| 183 | + // recorded in serialized_files.name. |
| 184 | + public void LinkSerializedFiles() |
| 185 | + { |
| 186 | + var fileNameToId = new Dictionary<string, int>(); |
| 187 | + using (var select = m_Database.CreateCommand()) |
| 188 | + { |
| 189 | + select.CommandText = "SELECT id, name FROM serialized_files"; |
| 190 | + using var reader = select.ExecuteReader(); |
| 191 | + while (reader.Read()) |
| 192 | + { |
| 193 | + fileNameToId[Path.GetFileName(reader.GetString(1)).ToLowerInvariant()] = reader.GetInt32(0); |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + using var transaction = m_Database.BeginTransaction(); |
| 198 | + using var update = m_Database.CreateCommand(); |
| 199 | + update.Transaction = transaction; |
| 200 | + update.CommandText = "UPDATE content_layout_serialized_files SET serialized_file = @id WHERE file_index = @file_index"; |
| 201 | + update.Parameters.Add("@id", SqliteType.Integer); |
| 202 | + update.Parameters.Add("@file_index", SqliteType.Integer); |
| 203 | + |
| 204 | + try |
| 205 | + { |
| 206 | + foreach (var file in m_ImportedFiles) |
| 207 | + { |
| 208 | + if (fileNameToId.TryGetValue(file.ContentHash + ".cf", out var id)) |
| 209 | + { |
| 210 | + update.Parameters["@id"].Value = id; |
| 211 | + update.Parameters["@file_index"].Value = file.Index; |
| 212 | + update.ExecuteNonQuery(); |
| 213 | + } |
| 214 | + } |
| 215 | + |
| 216 | + transaction.Commit(); |
| 217 | + } |
| 218 | + catch (Exception) |
| 219 | + { |
| 220 | + transaction.Rollback(); |
| 221 | + throw; |
| 222 | + } |
| 223 | + } |
| 224 | + |
169 | 225 | private void SetTransaction(SqliteTransaction transaction) |
170 | 226 | { |
171 | 227 | m_AddContentLayout.SetTransaction(transaction); |
|
0 commit comments