Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

# Rust build artifacts (the builder stage runs its own `cargo build`).
/target
/plugins/*/target
**/*.rs.bk

# Node / pnpm (the web build stage runs `pnpm install` fresh from the lockfile).
Expand Down
12 changes: 6 additions & 6 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
name: Forge

paths-ignore:
# Rust: every crate's integration tests (crates/*/tests, plugins/*/tests,
# xtask/tests), the end-to-end crate with its mock IdPs and upstreams, and
# the test helpers behind the `testing` feature. The unit tests inside the
# source files (`#[cfg(test)] mod tests`) cannot be left out by path: the
# workflow extracts the Rust code with `cfg(test)` off instead, as a release
# build compiles it.
# Rust: every crate's integration tests (crates/*/tests,
# crates/formats/*/tests, xtask/tests), the end-to-end crate with its mock
# IdPs and upstreams, and the test helpers behind the `testing` feature. The
# unit tests inside the source files (`#[cfg(test)] mod tests`) cannot be
# left out by path: the workflow extracts the Rust code with `cfg(test)` off
# instead, as a release build compiles it.
- "**/tests"
- crates/e2e
- crates/plugin/src/testing.rs
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/ci-changes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ declare -A CI_JOB_GROUP=(
# reads.
RUST=(
Cargo.toml Cargo.lock rust-toolchain.toml .cargo ':(exclude).cargo/audit.toml'
crates plugins xtask migrations .sqlx fixtures
crates xtask migrations .sqlx fixtures
web/index.html docker/forge.docker.toml
.github/scripts/test-parallel.sh .github/scripts/test-timings-runner.sh
.github/scripts/test-timings-summary.sh .github/scripts/oci-e2e.sh
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
if touches web ':(glob)**/*.js' ':(glob)**/*.cjs' ':(glob)**/*.mjs' ':(glob)**/*.ts' ':(glob)**/*.tsx'; then
languages+=(javascript-typescript)
fi
if touches Cargo.toml Cargo.lock rust-toolchain.toml .cargo .sqlx crates plugins xtask; then
if touches Cargo.toml Cargo.lock rust-toolchain.toml .cargo .sqlx crates xtask; then
languages+=(rust)
fi

Expand Down
22 changes: 11 additions & 11 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,17 @@ request: administrators run Forge from the browser, and a setting that only
(`/manage/realms`) offers the same. When a feature ships without its screen,
its pull request's description says why.

## Formats: every format plugin lives under plugins/

A package format is a crate in `plugins/<id>/`, the directory named after its
format id, linked into the server like `plugins/nuget` (Forge loads no
WebAssembly plugins). Never add a format as a crate under `crates/` (no
`crates/format-<id>`) or as a module of the server: it implements
`FormatPlugin` with the layout [plugins/README.md](plugins/README.md)
describes. Docker / OCI (`crates/format-oci`) and raw
(`crates/server/src/raw/`) are not there yet and are to move, to
`plugins/docker` and `plugins/raw`, each in a pull request of its own; until
then they are not the model for a new format.
## Formats: every format lives under crates/formats/

A package format is a crate in `crates/formats/<id>/`, the directory named
after its format id, linked into the server like `crates/formats/nuget`
(Forge loads no WebAssembly plugins). Never add a format as a crate elsewhere
under `crates/` (no `crates/format-<id>`) or as a module of the server: it
implements `FormatPlugin` with the layout
[crates/formats/README.md](crates/formats/README.md) describes. Docker / OCI
(`crates/format-oci`) is not there yet and is to move to
`crates/formats/docker`, in a pull request of its own; until then it is not
the model for a new format.

## Changelog: a fragment per change, never CHANGELOG.md

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ members = [
"crates/format-oci",
"crates/server",
"crates/e2e",
"plugins/nuget",
"plugins/raw",
"crates/formats/nuget",
"crates/formats/raw",
"xtask",
]

Expand Down
29 changes: 15 additions & 14 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,25 +241,26 @@ password: `docker login localhost:8421 -u admin@example.com`, then
`docker push localhost:8421/docker-hosted/team/app:1`. See
[docs/docker.md](docs/docker.md).

Raw repositories (`"format":"raw"`, the built-in plugin `plugins/raw`) hold
files under arbitrary paths, served under `/raw/`: `curl -u
Raw repositories (`"format":"raw"`, the built-in plugin `crates/formats/raw`)
hold files under arbitrary paths, served under `/raw/`: `curl -u
admin@example.com:<token> --upload-file x.tgz
localhost:8421/raw/binaries/tools/x.tgz`, a proxy of any HTTP(S) base URL
(`"remote_url":"https://github.com/<owner>/<repo>/releases/download/"`), and
groups. See [docs/raw.md](docs/raw.md).

### Repositories of other formats (format plugins)

Every package format is a format plugin, a crate in [`plugins/`](./plugins)
linked into the server (see [docs/format-plugins.md](./docs/format-plugins.md));
NuGet is the one there is. A new format goes in `plugins/` too, never in a
`crates/format-<id>` crate or the server. Docker / OCI (`crates/format-oci`)
and raw (`crates/server/src/raw/`) are not there yet and are to move to
`plugins/docker` and `plugins/raw`. A repository of a plugin format is created
with `"format": "<id>"` (hosted, proxy or group; a plugin format has proxies
when it implements the upstream side) and served under `/repository/<name>/`
unless the plugin names another mount (NuGet's is `/v3`). Helm charts are
pushed to docker repositories, see [docs/docker.md](docs/docker.md#helm-charts).
Every package format is a format plugin, a crate in
[`crates/formats/`](./crates/formats) linked into the server (see
[docs/format-plugins.md](./docs/format-plugins.md)): NuGet and raw. A new
format goes in `crates/formats/<id>` too, never in a `crates/format-<id>`
crate or the server. Docker / OCI (`crates/format-oci`) is not there yet and
is to move to `crates/formats/docker`. A repository of a plugin format is
created with `"format": "<id>"` (hosted, proxy or group; a plugin format has
proxies when it implements the upstream side) and served under
`/repository/<name>/` unless the plugin names another mount (NuGet's is
`/v3`). Helm charts are pushed to docker repositories, see
[docs/docker.md](docs/docker.md#helm-charts).

## Configuration

Expand Down Expand Up @@ -843,7 +844,7 @@ It sorts the change into groups of paths:

| Group | Paths | Jobs |
|---|---|---|
| Rust | `crates/`, `plugins/`, `xtask/`, `Cargo.toml`, `Cargo.lock`, `rust-toolchain.toml`, `.cargo/` (but `audit.toml`), `migrations/`, `.sqlx/`, `fixtures/`; the files the code or its tests read from outside the crates: `web/index.html`, `docker/forge.docker.toml`; and the scripts the jobs run: `test-parallel.sh`, `test-timings-runner.sh`, `test-timings-summary.sh`, `oci-e2e.sh`, `raw-e2e.sh` | `fmt`, `clippy`, `plugins`, `test`, `oci-e2e`, `raw-e2e`, `e2e`, `web-e2e` |
| Rust | `crates/`, `xtask/`, `Cargo.toml`, `Cargo.lock`, `rust-toolchain.toml`, `.cargo/` (but `audit.toml`), `migrations/`, `.sqlx/`, `fixtures/`; the files the code or its tests read from outside the crates: `web/index.html`, `docker/forge.docker.toml`; and the scripts the jobs run: `test-parallel.sh`, `test-timings-runner.sh`, `test-timings-summary.sh`, `oci-e2e.sh`, `raw-e2e.sh` | `fmt`, `clippy`, `test`, `oci-e2e`, `raw-e2e`, `e2e`, `web-e2e` |
| Changelog | `docs/changes/` | `fmt` |
| Release | what xtask's tests read from outside `xtask/`: the version lines `cargo xtask release` sets (`web/package.json`, `deploy/kubernetes/base/kustomization.yaml`, `deploy/helm/forge/Chart.yaml`) and `release-channels.sh` | `fmt` (which runs xtask's tests) |
| Audit | `Cargo.lock`, `.cargo/audit.toml` | `audit` |
Expand Down Expand Up @@ -995,7 +996,7 @@ only when a change touches its code:

| Language | Paths |
|---|---|
| `rust` | `crates/`, `plugins/`, `xtask/`, `Cargo.toml`, `Cargo.lock`, `rust-toolchain.toml`, `.cargo/`, `.sqlx/` |
| `rust` | `crates/`, `xtask/`, `Cargo.toml`, `Cargo.lock`, `rust-toolchain.toml`, `.cargo/`, `.sqlx/` |
| `javascript-typescript` | `web/`, and every `.js`, `.cjs`, `.mjs`, `.ts` and `.tsx` file |
| `actions` | `.github/workflows/`, and every `action.yml` and `action.yaml` |

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ A Cargo workspace of small crates plus the web SPA:
| `format-oci` | `forge-oci` | Docker / OCI registry: the distribution-spec `/v2` API, manifests, registry tokens, hosted/proxy/group resolution. |
| `plugin-api` | `forge-plugin-api` | The format-plugin contract: the `FormatPlugin` trait and its types. |
| `plugin` | `forge-plugin` | The host side of format plugins: an installed plugin and its adapter to the repository machinery. |
| `formats/<id>` | `forge-format-*` | Format plugins, built into the server: `nuget`, `raw`. |
| `server` | `forge-server` | Axum HTTP server: the format plugins' feeds (NuGet at `/v3`, raw files at `/raw`), the file store of files formats, the Docker registry, `/admin` + `/auth` REST, background workers, static SPA serving. |
| `e2e` | `forge-e2e` | End-to-end suite (testcontainers + mock upstream/IdP). |
| `xtask` | — | The task runner (`cargo xtask …`); replaces Make/Just. |
| `plugins/` | `forge-format-*` | Format plugins, built into the server: `nuget`, `raw`. |
| `web/` | — | TanStack Router SPA (pnpm + Vite), built into `web/dist/`. |

**Every format is a plugin in `plugins/`.** A package format is a crate in
`plugins/<id>/` implementing `FormatPlugin`, linked into the server. Docker /
OCI (`crates/format-oci`) and raw (in `forge-server`) are not there yet and
are to move to `plugins/docker` and `plugins/raw`.
**Every format is a plugin in `crates/formats/`.** A package format is a
crate in `crates/formats/<id>/` implementing `FormatPlugin`, linked into the
server. Docker / OCI (`crates/format-oci`) is not there yet and is to move to
`crates/formats/docker`.

**Single-origin serving.** `forge-server` mounts each format plugin's feed
(NuGet at `/v3`, others at `/repository`), the Docker / OCI registry (`/v2`),
Expand Down
2 changes: 1 addition & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-u
forge-db = { path = "../db" }
# NuGet, the format most integration tests use: the built-in plugin and its
# Format (a dev-only cycle through forge-plugin, which Cargo permits).
forge-format-nuget = { path = "../../plugins/nuget" }
forge-format-nuget = { path = "../formats/nuget" }
forge-plugin = { path = "../plugin" }
argon2 = { workspace = true, features = ["password-hash"] }
serde_json = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! `forge-core`: format-agnostic domain logic for Forge.
//!
//! This crate sits above [`forge_db`] and below the format plugins
//! (`plugins/*`) and the server. It defines:
//! (`crates/formats/*`) and the server. It defines:
//!
//! * [`domain`] — neutral types ([`domain::ParsedUpload`]) produced by parsing
//! an uploaded package, the boundary between a concrete format and the rest
Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/group_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn nuget() -> forge_plugin::PluginFormat {
forge_format_nuget::PLUGIN_TOML,
forge_format_nuget::Nuget::default(),
)
.expect("plugins/nuget/plugin.toml is valid");
.expect("crates/formats/nuget/plugin.toml is valid");
forge_plugin::PluginFormat::new(&plugin)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/hosted_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn nuget() -> forge_plugin::PluginFormat {
forge_format_nuget::PLUGIN_TOML,
forge_format_nuget::Nuget::default(),
)
.expect("plugins/nuget/plugin.toml is valid");
.expect("crates/formats/nuget/plugin.toml is valid");
forge_plugin::PluginFormat::new(&plugin)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/hosted_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn nuget() -> forge_plugin::PluginFormat {
forge_format_nuget::PLUGIN_TOML,
forge_format_nuget::Nuget::default(),
)
.expect("plugins/nuget/plugin.toml is valid");
.expect("crates/formats/nuget/plugin.toml is valid");
forge_plugin::PluginFormat::new(&plugin)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/proxy_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn nuget() -> forge_plugin::PluginFormat {
forge_format_nuget::PLUGIN_TOML,
forge_format_nuget::Nuget::default(),
)
.expect("plugins/nuget/plugin.toml is valid");
.expect("crates/formats/nuget/plugin.toml is valid");
forge_plugin::PluginFormat::new(&plugin)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/retention_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn nuget() -> forge_plugin::PluginFormat {
forge_format_nuget::PLUGIN_TOML,
forge_format_nuget::Nuget::default(),
)
.expect("plugins/nuget/plugin.toml is valid");
.expect("crates/formats/nuget/plugin.toml is valid");
forge_plugin::PluginFormat::new(&plugin)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ forge-db = { path = "../db" }
forge-storage = { path = "../storage" }
forge-cache = { path = "../cache" }
forge-core = { path = "../core" }
forge-format-nuget = { path = "../../plugins/nuget" }
forge-format-nuget = { path = "../formats/nuget" }
forge-server = { path = "../server" }

tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-util", "time"] }
Expand Down
8 changes: 4 additions & 4 deletions plugins/README.md → crates/formats/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Format plugins

Package formats for Forge, one crate per directory. Each implements
`FormatPlugin` from [`forge-plugin-api`](../crates/plugin-api) and is linked
into the server. See [docs/format-plugins.md](../docs/format-plugins.md) for
`FormatPlugin` from [`forge-plugin-api`](../plugin-api) and is linked
into the server. See [docs/format-plugins.md](../../docs/format-plugins.md) for
the design, the contract and how to write one.

| Plugin | Format id | What it serves |
| --- | --- | --- |
| [`nuget`](nuget) | `nuget` | NuGet V3 feeds at `/v3`: push, restore, search, unlist and relist; hosted, proxy and group repositories |
| [`raw`](raw) | `raw` | Raw files at `/raw`: files under paths, uploads with `PUT` or a form, ranges, checksum sidecars, listings; hosted, proxy and group repositories ([docs/raw.md](../docs/raw.md)) |
| [`raw`](raw) | `raw` | Raw files at `/raw`: files under paths, uploads with `PUT` or a form, ranges, checksum sidecars, listings; hosted, proxy and group repositories ([docs/raw.md](../../docs/raw.md)) |

A plugin directory holds:

Expand All @@ -22,5 +22,5 @@ A plugin directory holds:
forge_plugin_api::plugin_toml!();`.

The server installs it in `plugins::builtin()`
([`crates/server/src/plugins.rs`](../crates/server/src/plugins.rs)). The
([`crates/server/src/plugins.rs`](../server/src/plugins.rs)). The
workspace builds, lints and tests the plugins like every other crate.
4 changes: 2 additions & 2 deletions plugins/nuget/Cargo.toml → crates/formats/nuget/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ publish.workspace = true
description = "NuGet V3 feeds for Forge, as a format plugin"

[dependencies]
forge-plugin-api = { path = "../../crates/plugin-api" }
forge-plugin-api = { path = "../../plugin-api" }

thiserror = { workspace = true }
serde = { workspace = true }
Expand All @@ -20,5 +20,5 @@ zip = { version = "9.0", default-features = false, features = ["deflate"] }
quick-xml = { version = "0.42" }

[dev-dependencies]
forge-plugin-api = { path = "../../crates/plugin-api", features = ["testing"] }
forge-plugin-api = { path = "../../plugin-api", features = ["testing"] }
zip = { version = "9.0", default-features = false, features = ["deflate"] }
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# A Forge format plugin: NuGet V3 feeds (see plugins/README.md).
# A Forge format plugin: NuGet V3 feeds (see crates/formats/README.md).
[plugin]
id = "nuget"
name = "NuGet"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use forge_plugin_api::{FormatError, FormatPlugin};

fn fixture(name: &str) -> File {
let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
p.push("../../fixtures/nuget");
p.push("../../../fixtures/nuget");
p.push(name);
File::open(&p).unwrap_or_else(|e| panic!("open fixture {}: {e}", p.display()))
}
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions plugins/raw/Cargo.toml → crates/formats/raw/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ publish.workspace = true
description = "Raw file repositories for Forge, as a format plugin"

[dependencies]
forge-plugin-api = { path = "../../crates/plugin-api" }
forge-plugin-api = { path = "../../plugin-api" }
# The JSON listing.
serde = { workspace = true }
serde_json = { workspace = true }
Expand All @@ -21,4 +21,4 @@ percent-encoding = "2.3"
base64 = { workspace = true }

[dev-dependencies]
forge-plugin-api = { path = "../../crates/plugin-api", features = ["testing"] }
forge-plugin-api = { path = "../../plugin-api", features = ["testing"] }
2 changes: 1 addition & 1 deletion plugins/raw/plugin.toml → crates/formats/raw/plugin.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# A Forge format plugin: raw file repositories (see plugins/README.md).
# A Forge format plugin: raw file repositories (see crates/formats/README.md).
[plugin]
id = "raw"
name = "Raw files"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions crates/plugin-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
//! implements the protocol over the host's file store ([`Query::File`] …
//! [`Query::Remove`], [`Action::ServeFile`]).
//!
//! A plugin is a crate under `plugins/<id>/` implementing [`FormatPlugin`],
//! with a `plugin.toml` naming it, linked into the server and called
//! directly (NuGet, raw).
//! A plugin is a crate under `crates/formats/<id>/` implementing
//! [`FormatPlugin`], with a `plugin.toml` naming it, linked into the server
//! and called directly (NuGet, raw).

pub mod files;
mod types;
Expand Down
10 changes: 5 additions & 5 deletions crates/plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
//! storage, metadata, authentication and authorization, hosted/group
//! semantics, retention, the streaming of package bytes.
//!
//! A [`Plugin`] is one installed plugin: a crate under `plugins/<id>/` linked
//! into the server ([`Plugin::builtin`]) and called directly. The server holds
//! it as an `Arc<dyn FormatPlugin>`; [`PluginFormat`] adapts it to
//! [`forge_core::Format`], so hosted publishing, reads, groups and retention
//! work for it unchanged.
//! A [`Plugin`] is one installed plugin: a crate under `crates/formats/<id>/`
//! linked into the server ([`Plugin::builtin`]) and called directly. The
//! server holds it as an `Arc<dyn FormatPlugin>`; [`PluginFormat`] adapts it
//! to [`forge_core::Format`], so hosted publishing, reads, groups and
//! retention work for it unchanged.

mod format;
pub mod manifest;
Expand Down
2 changes: 1 addition & 1 deletion crates/plugin/src/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! `plugin.toml`: what a plugin declares about itself, next to its crate's
//! `Cargo.toml` (`plugins/<id>/plugin.toml`).
//! `Cargo.toml` (`crates/formats/<id>/plugin.toml`).
//!
//! ```toml
//! [plugin]
Expand Down
9 changes: 5 additions & 4 deletions crates/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ forge-core = { path = "../core" }
forge-crypto = { path = "../crypto" }
forge-plugin = { path = "../plugin" }
forge-oci = { path = "../format-oci" }
# The built-in format plugins (plugins/nuget, plugins/raw), linked in.
forge-format-nuget = { path = "../../plugins/nuget" }
forge-format-raw = { path = "../../plugins/raw" }
# The built-in format plugins (crates/formats/nuget, crates/formats/raw),
# linked in.
forge-format-nuget = { path = "../formats/nuget" }
forge-format-raw = { path = "../formats/raw" }

tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-util", "time", "signal"] }
axum = { workspace = true, features = ["multipart"] }
Expand Down Expand Up @@ -89,7 +90,7 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-u
testcontainers = "0.27"
testcontainers-modules = { version = "0.15", features = ["postgres"] }
reqwest = { workspace = true, features = ["multipart", "query"] }
forge-format-nuget = { path = "../../plugins/nuget" }
forge-format-nuget = { path = "../formats/nuget" }
http-body-util = "0.1"
tower = { version = "0.5", features = ["util"] }
figment = { version = "0.10", features = ["toml", "env", "test"] }
Expand Down
5 changes: 3 additions & 2 deletions crates/server/src/files/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! The file store: the repositories of a format whose `plugin.toml` says
//! `storage = "files"` (raw) hold files under paths, like Nexus' raw-hosted,
//! raw-proxy and raw-group repositories. The format's plugin owns the
//! protocol (`plugins/raw`, served under its mount by [`crate::plugins`]);
//! this module answers the file queries and actions it asks for:
//! protocol (`crates/formats/raw`, served under its mount by
//! [`crate::plugins`]); this module answers the file queries and actions it
//! asks for:
//!
//! * `file` and `fetch-file`: [`Files::locate`] — the stored file; a proxy's
//! copy, re-validated with its upstream once it is due, or fetched from it
Expand Down
Loading
Loading