Skip to content

Commit e88f6e6

Browse files
authored
Merge pull request #29 from Unity-Technologies/add-buildlayout-support
Add Addressables Report support
2 parents 226ea3a + 73dc64c commit e88f6e6

File tree

90 files changed

+3780
-677
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+3780
-677
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ UnityFileSystemTestData/**/*.sln
3535
UnityFileSystemTestData/ProjectSettings/
3636
UnityFileSystemTestData/UserSettings/
3737
UnityFileSystemTestData/Packages/
38+
*.db
39+
*.csv

Analyzer/Analyzer.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net9.0</TargetFramework>
@@ -15,8 +15,13 @@
1515

1616
<ItemGroup>
1717
<PackageReference Include="Microsoft.Data.SQLite" Version="9.0.1" />
18+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
1819
</ItemGroup>
1920

21+
<ItemGroup>
22+
<Using Include="UnityDataTools.Analyzer.Properties" />
23+
</ItemGroup>
24+
2025
<ItemGroup>
2126
<ProjectReference Include="..\UnityFileSystem\UnityFileSystem.csproj" />
2227
</ItemGroup>

Analyzer/AnalyzerTool.cs

Lines changed: 48 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5-
using UnityDataTools.Analyzer.SQLite;
6-
using UnityDataTools.FileSystem;
5+
using UnityDataTools.Analyzer.SQLite.Handlers;
6+
using UnityDataTools.Analyzer.SQLite.Parsers;
7+
using UnityDataTools.Analyzer.SQLite.Parsers.Models;
8+
using UnityDataTools.Analyzer.SQLite.Writers;
79

810
namespace UnityDataTools.Analyzer;
911

1012
public class AnalyzerTool
1113
{
1214
bool m_Verbose = false;
1315

16+
public List<ISQLiteFileParser> parsers = new List<ISQLiteFileParser>()
17+
{
18+
new AddressablesBuildLayoutParser(),
19+
new SerializedFileParser(),
20+
};
21+
1422
public int Analyze(
1523
string path,
1624
string databaseName,
@@ -21,11 +29,18 @@ public int Analyze(
2129
{
2230
m_Verbose = verbose;
2331

24-
using SQLiteWriter writer = new (databaseName, skipReferences);
32+
using SQLiteWriter writer = new (databaseName);
2533

2634
try
2735
{
2836
writer.Begin();
37+
foreach (var parser in parsers)
38+
{
39+
parser.Verbose = verbose;
40+
parser.SkipReferences = skipReferences;
41+
parser.Init(writer.Connection);
42+
43+
}
2944
}
3045
catch (Exception e)
3146
{
@@ -47,31 +62,52 @@ public int Analyze(
4762
int i = 1;
4863
foreach (var file in files)
4964
{
50-
if (ShouldIgnoreFile(file))
65+
bool foundParser = false;
66+
foreach(var parser in parsers)
67+
{
68+
if (parser.CanParse(file))
69+
{
70+
foundParser = true;
71+
try
72+
{
73+
parser.Parse(file);
74+
ReportProgress(Path.GetRelativePath(path, file), i, files.Length);
75+
countSuccess++;
76+
}
77+
catch (Exception e)
78+
{
79+
EraseProgressLine();
80+
Console.Error.WriteLine();
81+
Console.Error.WriteLine($"Error processing file: {file}");
82+
Console.WriteLine($"{e.GetType()}: {e.Message}");
83+
if (m_Verbose)
84+
Console.WriteLine(e.StackTrace);
85+
countFailures++;
86+
}
87+
}
88+
}
89+
if (!foundParser)
5190
{
5291
if (m_Verbose)
5392
{
5493
var relativePath = Path.GetRelativePath(path, file);
5594
Console.WriteLine();
5695
Console.WriteLine($"Ignoring {relativePath}");
5796
}
97+
5898
countIgnored++;
5999
}
60-
else if (!ProcessFile(file, path, writer, i, files.Length))
61-
{
62-
countFailures++;
63-
}
64-
else
65-
{
66-
countSuccess++;
67-
}
68100
++i;
69101
}
70102

71103
Console.WriteLine();
72104
Console.WriteLine($"Finalizing database. Successfully processed files: {countSuccess}, Failed files: {countFailures}, Ignored files: {countIgnored}");
73105

74106
writer.End();
107+
foreach (var parser in parsers)
108+
{
109+
parser.Dispose();
110+
}
75111

76112
timer.Stop();
77113
Console.WriteLine();
@@ -80,158 +116,6 @@ public int Analyze(
80116
return 0;
81117
}
82118

83-
bool ShouldIgnoreFile(string file)
84-
{
85-
// Unfortunately there is no standard extension for AssetBundles, and SerializedFiles often have no extension at all.
86-
// Also there is also no distinctive signature at the start of a SerializedFile to immediately recognize it based on its first bytes.
87-
// This makes it difficult to use the "--search-pattern" argument to only pick those files.
88-
89-
// Hence to reduce noise in UnityDataTool output we filter out files that we have a high confidence are
90-
// NOT SerializedFiles or Unity Archives.
91-
92-
string fileName = Path.GetFileName(file);
93-
string extension = Path.GetExtension(file);
94-
95-
return IgnoredFileNames.Contains(fileName) || IgnoredExtensions.Contains(extension);
96-
}
97-
98-
// These lists are based on expected output files in Player, AssetBundle, Addressables and ECS builds.
99-
// However this is by no means exhaustive.
100-
private static readonly HashSet<string> IgnoredFileNames = new()
101-
{
102-
".DS_Store", "boot.config", "archive_dependencies.bin", "scene_info.bin", "app.info", "link.xml",
103-
"catalog.bin", "catalog.hash"
104-
};
105-
106-
private static readonly HashSet<string> IgnoredExtensions = new()
107-
{
108-
".txt", ".resS", ".resource", ".json", ".dll", ".pdb", ".exe", ".manifest", ".entities", ".entityheader",
109-
".ini", ".config"
110-
};
111-
112-
bool ProcessFile(string file, string rootDirectory, SQLiteWriter writer, int fileIndex, int cntFiles)
113-
{
114-
bool successful = true;
115-
try
116-
{
117-
if (IsUnityArchive(file))
118-
{
119-
using (UnityArchive archive = UnityFileSystem.MountArchive(file, "archive:" + Path.DirectorySeparatorChar))
120-
{
121-
if (archive == null)
122-
throw new FileLoadException($"Failed to mount archive: {file}");
123-
124-
try
125-
{
126-
var assetBundleName = Path.GetRelativePath(rootDirectory, file);
127-
128-
writer.BeginAssetBundle(assetBundleName, new FileInfo(file).Length);
129-
ReportProgress(assetBundleName, fileIndex, cntFiles);
130-
131-
foreach (var node in archive.Nodes)
132-
{
133-
if (node.Flags.HasFlag(ArchiveNodeFlags.SerializedFile))
134-
{
135-
try
136-
{
137-
writer.WriteSerializedFile(node.Path, "archive:/" + node.Path, Path.GetDirectoryName(file));
138-
}
139-
catch (Exception e)
140-
{
141-
// the most likely exception here is Microsoft.Data.Sqlite.SqliteException,
142-
// for example 'UNIQUE constraint failed: serialized_files.id'.
143-
// or 'UNIQUE constraint failed: objects.id' which can happen
144-
// if AssetBundles from different builds are being processed by a single call to Analyze
145-
// or if there is a Unity Data Tool bug.
146-
EraseProgressLine();
147-
Console.Error.WriteLine($"Error processing {node.Path} in archive {file}");
148-
Console.Error.WriteLine(e.Message);
149-
Console.WriteLine();
150-
151-
// It is possible some files inside an archive will pass and others will fail, to have a partial analyze.
152-
// Overall that is reported as a failure
153-
successful = false;
154-
}
155-
}
156-
}
157-
}
158-
finally
159-
{
160-
writer.EndAssetBundle();
161-
}
162-
}
163-
}
164-
else
165-
{
166-
// This isn't a Unity Archive file. Try to open it as a SerializedFile.
167-
// Unfortunately there is no standard file extension, or clear signature at the start of the file,
168-
// to test if it truly is a SerializedFile. So this will process files that are clearly not unity build files,
169-
// and there is a chance for crashes and freezes if the parser misinterprets the file content.
170-
var relativePath = Path.GetRelativePath(rootDirectory, file);
171-
writer.WriteSerializedFile(relativePath, file, Path.GetDirectoryName(file));
172-
173-
ReportProgress(relativePath, fileIndex, cntFiles);
174-
}
175-
176-
EraseProgressLine();
177-
}
178-
catch (NotSupportedException)
179-
{
180-
EraseProgressLine();
181-
Console.Error.WriteLine();
182-
//A "failed to load" error will already be logged by the UnityFileSystem library
183-
184-
successful = false;
185-
}
186-
catch (Exception e)
187-
{
188-
EraseProgressLine();
189-
Console.Error.WriteLine();
190-
Console.Error.WriteLine($"Error processing file: {file}");
191-
Console.WriteLine($"{e.GetType()}: {e.Message}");
192-
if (m_Verbose)
193-
Console.WriteLine(e.StackTrace);
194-
195-
successful = false;
196-
}
197-
198-
return successful;
199-
}
200-
201-
private static bool IsUnityArchive(string filePath)
202-
{
203-
// Check whether a file is a Unity Archive (AssetBundle) by looking for known signatures at the start of the file.
204-
// "UnifyFS" is the current signature, but some older formats of the file are still supported
205-
string[] signatures = { "UnityFS", "UnityWeb", "UnityRaw", "UnityArchive" };
206-
int maxLen = 12; // "UnityArchive".Length
207-
byte[] buffer = new byte[maxLen];
208-
209-
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
210-
{
211-
int read = fs.Read(buffer, 0, buffer.Length);
212-
foreach (var sig in signatures)
213-
{
214-
if (read >= sig.Length)
215-
{
216-
bool match = true;
217-
for (int i = 0; i < sig.Length; ++i)
218-
{
219-
if (buffer[i] != sig[i])
220-
{
221-
match = false;
222-
break;
223-
}
224-
}
225-
if (match)
226-
return true;
227-
}
228-
}
229-
return false;
230-
}
231-
}
232-
233-
234-
235119
int m_LastProgressMessageLength = 0;
236120

237121
void ReportProgress(string relativePath, int fileIndex, int cntFiles)

Analyzer/IWriter.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)