~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A revision's files download as one tar.gz or zip archive

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/archives

What changes

Archive downloads. /<owner>/<repo>/archive/<rev>.tar.gz and .zip download a repository's files at a branch, tag or commit as one archive. The files sit in a folder <repo>-<rev>, with any / in a branch name made -. git archive writes the archive from the mirror, and it is streamed as it is written. Like the raw route, it reads as the viewer, so a private repository's archive goes to its members only and isn't cached. One at a commit's full hash is immutable, and anything else is no-cache. Another ending, or a revision that names no commit, is 404.

On the pages. The Code menu has "Download zip" and "Download tar.gz" for the revision shown. On the tags page, each tag has zip and tar.gz links beside its commit.

Why

This is the first easy item on Basic forge features missing, from archive downloads to webhooks. Until now there was no way to get a repository's files without git and the knotless helper.

Each archive reads the whole tree and compresses it, so at most four are written at once and the rest wait, as blame already does. Writing into a cache was the other option. I left it out because a commit's archive is immutable, so browsers and any proxy in front can keep it.

How it was checked

  • New assertions in browsing_a_repository (tests/web.rs) cover:
    • tar.gz at main: its headers, and its contents un-gzipped, both the paths and the text.
    • zip at a branch with a /: the file name and folder.
    • the immutable cache at a hash, and an annotated tag.
    • 404 for .rar, no ending, an unknown ref, a tag of a tree, and -x.
  • In tests/gateway.rs, a private repository's archive is checked: for a member it is private, no-store and varies by cookie, and with no cookie it is 404.
  • just look repository with the Code menu open, desktop light and phone dark. just look of the tags page with three tags, one with a long name.
  • I didn't build or run the tests locally; that's left to the check and test checks.

Shortcomings

  • Archives aren't kept: each download runs git archive again, bounded by the four-at-once limit. A popular tag downloaded by many people could keep those four busy.
  • The release pages have their own files and don't offer a source archive.

🤖 Generated with Claude Code

Asked for changes

This adds /<owner>/<repo>/archive/<rev>.tar.gz and .zip, streamed from git archive. It reads as the viewer, so private repositories work, and the Code menu and tags page link to it. The route, auth and caching look right, read::rev leaves the revision unchanged so ending is sliced correctly, and the docs are updated. All checks were still queued when I looked, so I haven't seen any result.

  1. Shots-moved: line missing. The Code menu is inside every code page's HTML, and the tags page now shows zip and tar.gz links. AGENTS.md says the shots check fails a moved page that the body doesn't name on a Shots-moved: line. Once the check reports which pages moved, add that line and rerun shots. The PR also says the menu-open state was drawn with just look, but the pictures aren't attached as --images, which AGENTS.md asks for.
  2. Slow clients hold the permits. The semaphore permit is released only when git exits (archive.rs:69-72). git blocks writing to the pipe until the client reads, so four slow or stalled downloads keep all four permits and every other archive waits behind them. The "Shortcomings" section only covers popular tags, not this. A write timeout or a total time limit on the stream would fix it, or at least wait on a bounded deadline and kill the child.
crates/knotless-serve/src/web/archive.rslines 67 to 72Outdated
// The permit is held until git is done writing; kill_on_drop covers a
// client that hangs up first.
tokio::spawn(async move {
let _ = child.wait().await;
drop(permit);
});
review.knotless.dev

The permit lasts as long as the client takes to read. A client that stalls leaves git blocked on the pipe and keeps its permit, so four of them stop all archives. Add a deadline for the whole stream, killing git when it passes.

Asked for changes

The stalled-client problem is fixed. The permit is now held for at most ten minutes (archive.rs:63-66). When the timeout passes, child drops and kill_on_drop kills git. A client that hangs up closes the pipe, so git exits and the permit is freed sooner. I have nothing more to ask on that.

Still open from round 1: the pull body has no Shots-moved: line and no --image pictures. The body hasn't changed since round 1. The Code menu is in every code page's HTML, and the tags page gained links, so these pages have moved. AGENTS.md says the shots check fails a moved page the body doesn't name. shots was still queued when I looked, and so were check, web, e2e and docs. Once shots reports which pages moved, add the Shots-moved: line to the body, attach the pictures from just look, and rerun shots.

The "Shortcomings" section could also mention the ten-minute cut-off. A slow client on a large archive gets a truncated file with no error.

Merged as 4beff6a