Skip to content

[#149] Name archives by their path relative to the scanned directory - #150

Merged
SkowronskiAndrew merged 3 commits into
mainfrom
issue149-archive-relative-name
Sep 24, 2026
Merged

SkowronskiAndrew merged 3 commits into
mainfrom
issue149-archive-relative-name

Conversation

@SkowronskiAndrew

@SkowronskiAndrew SkowronskiAndrew commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #149.

Summary - archives.name becomes the relative path of the file (based on the scan root as passed to analyze).
There is no visible change if the assetbundles (or other archives) are located directly in the search path argument. But if they are found in nested folders then that relative path is stored.

The archive name also appears in several views objects_view, assetbundle_asset_view, etc

Details:

analyze recorded archives.name as the bare file name of the bundle, so two bundles with the same file name in different folders collided on the UNIQUE constraint and the second was skipped as a duplicate build. An AssetBundle name can itself be a path, and BuildPipeline.BuildAssetBundles writes such a bundle into a matching folder structure, so a real build using that convention had nearly every bundle rejected.

The archive name is now the path of the bundle relative to the directory that was analyzed (dlc/weapons/main rather than main). That is unique whenever the build itself is, and matches the name Unity gives the bundle in the AssetBundleManifest, which makes joining against manifest and build-report data easier.

Changes

  • AnalyzerTool already tracked the scanned root for each collected file (it was used only for progress messages). ISQLiteFileParser.Parse now takes that root and SerializedFileParser uses it for the archive name, normalized to forward slashes so the value is the same on every platform. A file named directly on the command line still gets its bare file name.
  • serialized_files.name is deliberately unchanged: external references and serialized_files.id are keyed on the bare file name, so a path there would disagree with the id and with the scene-file handling.
  • Nothing joins on archives.name — object_view, assetbundle_asset_view, MonoScript.sql, Shader.sql and find-refs only display it, and PPtr resolution goes through the SerializedFile external reference table. The duplicate-name detection and its message are unchanged for genuine duplicates.
  • PRAGMA user_version 7 → 8, with the corresponding row in the schema version table. Documented in analyzer-schema.md (archives.name) and command-analyze.md (a new "How archives are named" section, and a note in the duplicate-name troubleshooting entry).

Testing

dotnet test — full suite green (830 tests). Two new tests in AnalyzeDuplicateNameTests: two different bundles copied to the same file name in different sub-folders of one scanned directory are both recorded under their relative paths with objects attributed to the right archive and no duplicate message, and a directly-named archive keeps its bare file name. The existing duplicate-archive test passes two build folders as separate input paths, so it still exercises the genuine-duplicate path.

Also verified by hand against a real customer build that uses path-shaped bundle names: a folder containing five bundles all named all previously analyzed one and skipped four, and now records all five as <folder>/all.

Also manual tested several other customer projects and visually confirmed the results.

analyze recorded archives.name as the bare file name, so bundles sharing a file
name in different folders were rejected as duplicates. AssetBundle names are
often paths, and BuildPipeline.BuildAssetBundles writes them into a matching
folder structure, so this skipped nearly every bundle in such a build.

AnalyzerTool already tracked the scanned root per file; it is now passed to
ISQLiteFileParser.Parse and used for the archive name, normalized to forward
slashes. SerializedFile names are unchanged (bare file names), since external
references and serialized_files.id are keyed on them.

@SkowronskiAndrew SkowronskiAndrew left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some code review feedback

Also regarding this claude summary:

LooksLikeAssetBundleVariantPair now sees path-shaped names. It calls Path.GetExtension / Path.ChangeExtension on the archive name. Those are fine with / separators, but a folder name containing a dot (e.g. v1.2/main) would make GetExtension return .2/main and could make the variant heuristic misfire. I judged this too unlikely to complicate the code for; flagging it as a known edge.

That sounds either wrong or lazy. It is not hard to write code that works properly so that extension only finds a "." in the filename. "v1.2/main" is not an edge case and we should never treat that as ".2/main". In my experience "/" is accepted as a path separate pretty easily on Widows when writing C#.

Comment thread Analyzer/SQLite/Parsers/SerializedFileParser.cs Outdated
Comment thread Documentation/command-analyze.md Outdated
Two bundles that share a file name in different sub-folders of the analyzed directory are not
duplicates: archives are named by their relative path, so `dlc/weapons/main` and `dlc/armor/main`
are both analyzed. See [How archives are named](#how-archives-are-named).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good.

I think this example error above should be removed:

Skipping build2\assetbundle: Duplicate archive name 'assetbundle'. Each analyzed archive must have a unique name; only a single build can be analyzed at a time.

And

When analyze encounters a second file or archive with a name it has already processed, it prints one
of the messages above

It seems this section needs more revision to make sure it is accurate (duplicate archives are ok, but serialized files need to be unique. Hence it is still true that we cannot analyze two versions of the same build and AssetBundle variants trigger an error.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AGENT: Reworked the section. Renamed it to "Duplicate SerializedFile name", led with SerializedFile uniqueness as the real constraint, and dropped the claim that archive names must be unique.

I kept the Duplicate archive name example, but moved it into a paragraph that says when it now happens: archive names no longer have to be unique across folders, but two builds analyzed together still collide, and when each build is passed as its own input path the archive names collide too (each path is its own root, so both bundles are still named assetbundle). That case is still reachable and still covered by a test, so removing the message entirely would leave an error text that appears in output but nowhere in the docs. Happy to drop it if you'd rather the section only covered SerializedFiles.

@SkowronskiAndrew

Copy link
Copy Markdown
Collaborator Author

AGENT: You were right to push back — my note was wrong, not a real tradeoff.

Path.GetExtension is path-aware on both platforms: on Windows / is Path.AltDirectorySeparatorChar, so it only looks at the final segment. Verified directly:

name GetExtension ChangeExtension(name, null)
v1.2/main "" v1.2/main
v1.2/ui.hd .hd v1.2/ui
dlc/ui.hd .hd dlc/ui

So v1.2/main yields an empty extension and LooksLikeAssetBundleVariantPair returns false at its first guard — the ".2/main" behaviour I described never happens. No code change was needed, but that was worth proving rather than asserting.

Added Analyze_DottedFolderNames_NotReportedAsVariants, which copies one bundle to v1.2/main and v1.3/main (so they share an inner SerializedFile, the condition under which the variant heuristic runs) and asserts the plain duplicate message is used, not the variant one. Also added a line to the comment on LooksLikeAssetBundleVariantPair recording that the names are paths and the Path methods only consider the last segment.

@SkowronskiAndrew
SkowronskiAndrew merged commit 705832b into main Sep 24, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

analyze: archive name is the bare file name, so same-named bundles in different folders are skipped as duplicates

1 participant