Skip to content

g1t/apps/docs/src/content/docs/guides/cargo.md

189 lines7,313 bytesCodeBlame
1---
2title: Cargo
3description: Publish and add a workspace's Rust crates with Cargo, from a sparse registry of its own on g1t.sh, from your machine and from workflows.
4---
5
6Every workspace has a Cargo registry of its own: a sparse index, with the
7web API that `cargo publish`, `cargo yank` and `cargo search` use. It
8works with Cargo 1.74 or later, private crates included.
9
10```text
11sparse+https://g1t.sh/-/cargo/<workspace>/index/
12```
13
14Crates from crates.io still come from crates.io; only the crates you name
15with the workspace's registry come from g1t.
16
17## Set up `.cargo/config.toml`
18
19Name the registry in the project's `.cargo/config.toml`, or in
20`~/.cargo/config.toml` for every project. The name you give it is the one
21you pass to `--registry`; these pages use the workspace's slug:
22
23```toml
24[registries.acme]
25index = "sparse+https://g1t.sh/-/cargo/acme/index/"
26credential-provider = "cargo:token"
27```
28
29Cargo sends a token to a registry that asks for one only through a
30credential provider named for it. `cargo:token` keeps the token in
31`~/.cargo/credentials.toml`, which stays out of the project. To keep it in
32your system's keychain instead, name `cargo:wincred` (Windows),
33`cargo:macos-keychain` (macOS) or `cargo:libsecret` (Linux).
34
35Then give Cargo an [access token](https://g1t.sh/settings/tokens):
36
37```sh
38cargo login --registry acme
39```
40
41Cargo asks for the token and hands it to the provider. A token with full
42access works; one with scopes needs `packages:read` to add private crates
43and `packages:write` to publish and yank them.
44
45The token can also come from the environment, as
46`CARGO_REGISTRIES_ACME_TOKEN` for a registry named `acme`, which is how
47[workflows](#in-workflows) give it.
48
49## Publish
50
51Say in `Cargo.toml` where the crate is published and which repository it
52comes from:
53
54```toml
55[package]
56name = "http-client"
57version = "0.3.1"
58edition = "2021"
59description = "Our HTTP client"
60license = "MIT"
61readme = "README.md"
62repository = "https://g1t.sh/acme/http-client"
63publish = ["acme"]
64```
65
66```sh
67cargo publish --registry acme
68```
69
70The first publish makes the crate. When its `repository` is a g1t.sh
71repository of the same workspace, or a repository is named like the crate
72(a crate `http_client` is also matched to a repository `http-client`), it
73is linked to that repository and has its visibility and roles: publishing needs Write on it.
74Otherwise it is the workspace's, private, and needs the workspace's Write
75base permission. See
76[who can see and publish a package](/guides/packages/#who-can-see-and-publish-a-package).
77
78`publish = ["acme"]` keeps the crate from being published to crates.io by
79mistake, and lets `cargo publish` leave out `--registry` when it is the
80only registry named.
81
82A crate may depend on crates.io crates and on other crates of the
83workspace's registry. The crate's page on g1t.sh shows the README and
84description of its highest stable version.
85
86## Add a crate
87
88```sh
89cargo add http-client --registry acme
90```
91
92That writes the dependency with its registry into `Cargo.toml`:
93
94```toml
95[dependencies]
96http-client = { version = "0.3.1", registry = "acme" }
97```
98
99`Cargo.lock` records each crate's registry and the SHA-256 of its
100`.crate` file, which g1t computes when the version is published.
101
102`cargo search --registry acme http` lists the workspace's crates you can
103see whose names match.
104
105## Names and versions
106
107A crate's name follows the crates.io rules: ASCII letters, digits, `-` and
108`_`, starting with a letter, at most 64 characters. In a workspace, names
109that differ only in case or in `-` against `_` are one name: once
110`http-client` is published, `HTTP_Client` is refused.
111
112A version is published once. Publishing a version that is already there is
113refused, as is one that differs from it only in build metadata (`1.0.0+a`
114and `1.0.0+b`), so bump `version` first.
115
116## Yank
117
118```sh
119cargo yank --registry acme http-client@0.3.1
120cargo yank --registry acme http-client@0.3.1 --undo
121```
122
123A yanked version stays in the registry: projects whose `Cargo.lock`
124names it still build, but Cargo no longer picks it for new lockfiles or
125`cargo update`. Yanking needs what publishing does. The crate's page marks
126yanked versions, and someone with Admin on the linked repository (an
127owner, for the workspace's own crates) can delete a version there for
128good.
129
130Crate owners are not kept: who may publish a crate is decided by its
131repository's roles, or the workspace's, so `cargo owner` answers with an
132error that says so.
133
134## Private and public crates
135
136A crate linked to a repository has the repository's visibility; one of
137the workspace's own is private until an owner makes it public on its page.
138
139| The workspace's crates | Without a token | With a token |
140| --- | --- | --- |
141| All public | Cargo reads the index and downloads them. | The same; the token is sent to publish and yank. |
142| Some private | The registry answers `401`: Cargo needs a token for every crate in it, public ones too. | Cargo sends the token with every request, and sees the crates the token's owner may see. |
143
144Cargo first asks for the registry's `config.json` without a token. When
145the registry answers `401`, Cargo asks again with its token, and the
146answer says `"auth-required": true`, so Cargo sends the token from then on.
147A private crate you cannot see looks exactly like one that does not exist.
148
149## In workflows
150
151A workflow's `G1T_TOKEN` is the workspace's own token for the run, and can
152add and publish the workspace's crates. Give it to Cargo for the registry:
153
154```yaml
155jobs:
156 publish:
157 runs-on: ubuntu-latest
158 env:
159 CARGO_REGISTRIES_ACME_INDEX: sparse+https://g1t.sh/-/cargo/acme/index/
160 CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER: cargo:token
161 CARGO_REGISTRIES_ACME_TOKEN: ${{ secrets.G1T_TOKEN }}
162 steps:
163 - uses: actions/checkout@v4
164 - run: cargo test
165 - run: cargo publish --registry acme
166```
167
168`CARGO_REGISTRIES_ACME_INDEX` and `CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER`
169are needed only when the project has no `.cargo/config.toml` naming the
170registry.
171
172## Size
173
174A publish is one request with the `.crate` file inside it, and may hold at
175most 100 MB. Without the [g1t plan](/guides/usage-and-billing/#the-g1t-plan),
176a workspace's private packages may hold 500 MB and its public ones 10 GB,
177as for [container images](/guides/containers/#storage-and-pull-limits).
178A `.crate` file is stored once, by its content.
179
180## Errors
181
182| Error | Means |
183| --- | --- |
184| `401` | No token, or a wrong or expired one. Run `cargo login --registry acme` with a g1t access token. |
185| `authenticated registries require a credential-provider to be configured` | The workspace has private crates, and Cargo has no provider for its token. Add `credential-provider = "cargo:token"` to the registry in `.cargo/config.toml`. |
186| `403` | Signed in, but your role or your token's scopes do not allow it, or the workspace is out of free package storage. The message says which. |
187| `404` | No such crate or version, or a private one you cannot see. |
188| `400` | The publish was refused: a name that is not valid or is taken, a version already published, or metadata Cargo did not send in full. The message says which. |
189| `413` | The publish is over 100 MB. Leave large files out with `exclude` or `include` in `Cargo.toml`, and check with `cargo package --list`. |