Skip to content

Error when upload_dir contains multiple HTML files and no index.html#28

Open
cloud9c wants to merge 3 commits intomainfrom
error-on-multiple-html-files
Open

Error when upload_dir contains multiple HTML files and no index.html#28
cloud9c wants to merge 3 commits intomainfrom
error-on-multiple-html-files

Conversation

@cloud9c
Copy link
Copy Markdown
Contributor

@cloud9c cloud9c commented Apr 21, 2026

Summary

  • locate_html_entrypoint silently picked the first HTML returned by WalkDir when index.html was absent. A user re-exporting a Godot build with a different filename ended up with pong.html + gamedevjsJam.html in build/ and didn't realize the old one was still being used.
  • Now: index.html still wins outright (so you can ship helper HTML alongside the canonical entrypoint); if absent, exactly one other .html is required — otherwise the CLI errors and lists the ambiguous files.

Error output

```
Error: Multiple HTML files found in upload_dir (./.):

  • pong.html
  • gamedevjsJam.html

Name one of them `index.html`, or remove the extras (often stale files from a previous export with a different name).
```

Test plan

  • Compiles clean (`cargo check`, `cargo build --release`)
  • Manual repro: two bare `` files in a dir with `[godot]` engine block → CLI errors as shown above
  • Single non-`index.html` file still works
  • `index.html` alongside other HTMLs still works (index wins)

🤖 Generated with Claude Code

`locate_html_entrypoint` silently picked whichever HTML `WalkDir` yielded
first, which produced confusing builds when users had stale exports alongside
a current one (e.g. `pong.html` + `gamedevjsJam.html` after renaming). `index.html`
still wins outright when present, so this doesn't break setups that intentionally
ship helper HTML alongside the canonical entrypoint.

When no `index.html` exists and multiple HTMLs are found, bail with a list of
the ambiguous files and a message pointing at the two fixes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented Apr 21, 2026

Claude finished @cloud9c's task in 1m 20s —— View job


Code Review

  • Gather context and read changed files
  • Review src/dev/entrypoint.rs
  • Review src/dev/mod.rs
  • Provide final review feedback

Overall this is a clean, well-reasoned fix for a real user-facing footgun. The logic is easy to follow and the error message is actionable. A few observations below.

src/dev/entrypoint.rs

Non-deterministic error output (entrypoint.rs:41-61)

WalkDir does not guarantee traversal order, so the list of ambiguous files in the error message can vary between runs on some filesystems. Sorting names before join would make the output stable and easier to read:

let mut names: Vec<String> = found
    .iter()
    .map(|p| p.strip_prefix(upload_dir).unwrap_or(p).display().to_string())
    .collect();
names.sort();  // deterministic, alphabetical

Fix this →


index.html only checked at upload root (entrypoint.rs:21-24)

The early-return shortcut only looks for upload_dir/index.html at the top level. A nested upload_dir/web/index.html falls through to WalkDir, where it is collected alongside any other HTML files — and if there are multiple, the error fires even though there's a technically-canonical index.html present. This edge case is unlikely for typical Godot/Unity exports (which always place index.html at the root of the export directory), but it's worth being aware of.


Cosmetic: .unwrap() in the 1 arm (entrypoint.rs:43)

1 => Ok(Some(found.into_iter().next().unwrap())),

The unwrap is provably safe here, but found.remove(0) or .next().expect("len == 1") would be marginally clearer to a future reader.


No unit tests

locate_html_entrypoint has four distinct code paths (no HTML, one HTML, multiple HTMLs, index.html present with siblings) and is easy to test with tempfile. Adding a #[cfg(test)] block here would protect against regressions from future changes.


src/dev/mod.rs

The single-line change (? propagation on line 125) is correct and idiomatic — no issues.


Pre-existing note (not introduced by this PR)

filter_map(|e| e.ok()) on line 30 silently drops WalkDir IO errors (permission denied, broken symlinks, etc.). This was already there before, but it means a user with a permission issue in their export directory would get confusing results rather than a clear error.


Summary: The fix is solid and ready to merge. The non-deterministic sort is the only change worth making before landing; the rest are minor observations. No blocking issues.

@cloud9c cloud9c changed the title Error when upload_dir contains multiple HTML files Error when upload_dir contains multiple HTML files and no index.html Apr 21, 2026
Address review on #28: `WalkDir` doesn't guarantee traversal order, so the
list of files in the error message could vary per run on some filesystems.
Also use `remove(0)` instead of `into_iter().next().unwrap()` — identical
behavior, marginally clearer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cloud9c
Copy link
Copy Markdown
Contributor Author

cloud9c commented Apr 21, 2026

Thanks for the review. Applied:

  • Sort ambiguous names — deterministic output across filesystems (7b8ca78)
  • remove(0) instead of .into_iter().next().unwrap() — same behavior, clearer intent

Deferring to a follow-up:

  • Nested index.html — real but edge (Godot/Unity always put index.html at the export root). Can revisit if it comes up.
  • Unit tests for locate_html_entrypoint — worth adding alongside tests for other CLI helpers in a separate PR.
  • Pre-existing filter_map(|e| e.ok()) — unchanged by this PR, worth a separate improvement.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 21, 2026

Claude finished @cloud9c's task in 1m 3s —— View job


Code Review

  • Read changed files
  • Review src/dev/entrypoint.rs
  • Review src/dev/mod.rs
  • Post final review

Both fixes from the first review round are correctly applied. The PR is clean.

src/dev/entrypoint.rs

Sort fix (entrypoint.rs:54) — names.sort() is in place. Output is now deterministic. ✓

remove(0) in the 1 arm (entrypoint.rs:43) — cleaner than the previous .into_iter().next().unwrap(), intent is clearer. ✓

strip_prefix(...).unwrap_or(p) fallback (entrypoint.rs:48-52) — the fallback to the full path is safe given WalkDir is rooted at upload_dir, but can't actually fail in practice. Fine as-is.

No new issues introduced.

src/dev/mod.rs

Single-character change (? on line 125) is correct — the error from locate_html_entrypoint now propagates to the caller and surfaces as a user-facing message. ✓


Summary: All requested changes from the previous review are applied correctly. The three deferred items (nested index.html, unit tests, pre-existing filter_map(|e| e.ok())) are tracked and reasonable to address in follow-up PRs. Ready to merge.

@cloud9c
Copy link
Copy Markdown
Contributor Author

cloud9c commented Apr 21, 2026

example output:

Error: Multiple HTML files found in upload_dir (././build-rename-test):
- extra.html
- gamedevjsJam.html

Name one of them index.html, or remove the extras (often stale files from a previous export with a different name).

Based on /simplify review of #28:

- `max_depth(1)` — only consider HTMLs directly under upload_dir. Avoids
  false "ambiguous" errors on engine-emitted nested HTML (e.g. Unity's
  `TemplateData/` or similar helper shells) and drops the worst-case walk
  cost from "entire asset tree" to "top-level entries".
- Short-circuit once we've collected up to 8 HTMLs — the error message
  doesn't benefit from more, and this caps work for pathological cases
  while still showing every offender in the common small-N case.
- Flatten the triple-nested if/let into a single `is_html` predicate.
- Accept `.htm` alongside `.html` for consistency with `file_staging.rs`,
  which already accepts both for the user's configured entrypoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented Apr 21, 2026

Claude finished @cloud9c's task in 1m 3s —— View job


Code Review

  • Gather context
  • Read changed files
  • Review src/dev/entrypoint.rs
  • Review src/dev/mod.rs
  • Post final review

The third commit (2b7355e) is a clean follow-up that addresses the two main concerns flagged in the first review round. Here's a focused look at what changed.

New in 2b7355e

max_depth(1) — good fix (entrypoint.rs:33)

Capping the walk to the top level directly resolves the earlier note about Unity's TemplateData/ subdirectory (and similar engine-emitted nested HTML). The inline comment explaining why is useful for future readers. ✓

Flattened nested ifs → is_some_and (entrypoint.rs:40-43)

Cleaner and idiomatic Rust. ✓

.htm support (entrypoint.rs:43)

Good catch — old Windows-era exporters still emit .htm. One minor inconsistency worth noting:

The early-return shortcut (entrypoint.rs:21-24) only checks for index.html, not index.htm. If a user has index.htm as their canonical entry alongside a second *.html file, both get collected by WalkDir and the error fires even though there's a plausible canonical choice. This is an edge case (exporters that use .htm as the extension rarely also name it index.htm), but it's a small inconsistency introduced by extending the extension set without extending the shortcut:

// entrypoint.rs:21-24 — could be extended to match:
let default_index_html = upload_dir.join("index.html");
let default_index_htm  = upload_dir.join("index.htm");
if default_index_html.is_file() {
    return Ok(Some(default_index_html));
}
if default_index_htm.is_file() {
    return Ok(Some(default_index_htm));
}

Fix this →

8-item cap with no truncation notice (entrypoint.rs:48-50)

The cap prevents unbounded output, but if there are 9+ HTML files the user has no indication that the list is truncated. Minor UX gap — a trailing " - ... and N more" line in the error message would help, but this is low priority for a realistic scenario.


src/dev/mod.rs

No changes in this commit; the ? propagation from the previous commit is correct. ✓


Summary: The max_depth(1) addition is the right call and closes the lingering edge case. The index.htm shortcut gap is the only new observation worth addressing before merge; everything else is solid. The PR is otherwise ready.

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.

1 participant