6
6
# Summary
7
7
[ summary ] : #summary
8
8
9
- This RFC proposes the concept of * prepublication dependencies * for Cargo. These
10
- dependencies augment a crate index (like crates.io) with new versions of crates
11
- that have not yet been published to the index. Dependency resolution then works
12
- * as if * those prepublished versions actually existed in the
13
- index. Prepublication dependencies thus act as a kind of "staging index".
14
-
15
- Prepublication makes it possible to perform integration testing within a large
16
- crate graph before publishing anything to crates.io, and without requiring
17
- dependencies to be switched from the crates.io index to git branches. It can, to
18
- a degree, simulate an "atomic" change across a large number of crates and
19
- repositories, which can then actually be landed in a piecemeal, non-atomic
9
+ This RFC proposes the concept of * augmenting sources * for Cargo. Sources can be
10
+ enhanced with new versions of a crate that did not exist or have existing
11
+ versions replaced. Dependency resolution will work * as if * these additional
12
+ crates actually existed in the original source.
13
+
14
+ One primary feature enabled by this is the ability to "prepublish" a crate to
15
+ crates.io. Prepublication makes it possible to perform integration testing
16
+ within a large crate graph before publishing anything to crates.io, and without
17
+ requiring dependencies to be switched from the crates.io index to git branches.
18
+ It can, to a degree, simulate an "atomic" change across a large number of crates
19
+ and repositories, which can then actually be landed in a piecemeal, non-atomic
20
20
fashion.
21
21
22
22
# Motivation
@@ -74,26 +74,34 @@ publication to crates.io.
74
74
[ design ] : #detailed-design
75
75
76
76
The design itself is relatively straightforward. The Cargo.toml file will
77
- support a new section for prepublication :
77
+ support a new section for augmenting a source of crates :
78
78
79
79
``` toml
80
- [prepublish ]
80
+ [augment . crates-io ]
81
81
xml-rs = { path = " path/to/fork" }
82
82
```
83
83
84
- The listed dependencies must be path or git dependencies (though see
85
- [ Unresolved Questions] [ unresolved ] for the multi-index case). Cargo will load
86
- the crates and extract version information, supplementing the ambient index with
87
- the version it finds. If the same version * already* exists in the ambient index,
88
- the prepublication will act just like ` [replace] ` , replacing its source with the
89
- one specified in the ` [prepublish] ` section. However, unlike ` [replace] ` ,
90
- Cargo will issue a warning in this case, since this situation is an indication
91
- that the prepublication is ready to be removed.
92
-
93
- Like ` [replace] ` , the ` [prepublish] ` section is only taken into account for the
94
- root crate; allowing it to accumulate anywhere in the crate dependency graph
95
- creates intractable problems for dependency resolution. Cargo will also refuse
96
- to publish crates containing a ` [prepublish] ` section to crates.io
84
+ The listed dependencies have the same syntax as the normal ` [dependencies] `
85
+ section, but they must all come form a different source than the source being
86
+ augmented. For example you can't augment crates.io with other crates from
87
+ crates.io! Cargo will load the crates and extract the version information for
88
+ each dependency's name, supplementing the source specified with the version it
89
+ finds. If the same name/version pair * already* exists in the source being
90
+ augmented, then this will act just like ` [replace] ` , replacing its source with
91
+ the one specified in the ` [augment] ` section.
92
+
93
+ Like ` [replace] ` , the ` [augment] ` section is only taken into account for the
94
+ root crate (or workspace root); allowing it to accumulate anywhere in the crate
95
+ dependency graph creates intractable problems for dependency resolution.
96
+
97
+ The sub-table of ` [augment] ` (where ` crates-io ` is used above) is used to
98
+ specify the source that's being augmented. Cargo will know ahead of time one
99
+ identifier, literally ` crates-io ` , but otherwise this field will currently be
100
+ interpreted as a URL of a source. The name ` crates-io ` will correspond to the
101
+ crates.io index, and other urls, such as git repositories, may also be specified
102
+ for augmentation. Eventually it's intended we'll grow support for multiple
103
+ registries here with their own identifiers, but for now just literally
104
+ ` crates-io ` and other URLs are allowed.
97
105
98
106
## Examples
99
107
@@ -112,6 +120,30 @@ With this setup, the dependency graph for Servo will contain *two* versions of
112
120
` 0.9.1 ` is considered a minor release against ` 0.9.0 ` , while ` 0.9.0 ` and ` 0.8.0 `
113
121
are incompatible.
114
122
123
+ ### Scenario: augmenting with a bugfix
124
+
125
+ Let's say that while developing ` foo ` we've got a lock file pointing to ` xml-rs `
126
+ ` 0.8.0 ` , and there's an ` 0.8.0 ` branch of ` xml-rs ` that hasn't been touched
127
+ since it was published. We then find a bug in the 0.8.0 publication of ` xml-rs `
128
+ which we'd like to fix.
129
+
130
+ First we'll check out ` foo ` locally and implement what we believe is a fix for
131
+ this bug, and next, we change ` Cargo.toml ` for ` foo ` :
132
+
133
+ ``` toml
134
+ [augment .crates-io ]
135
+ xml-rs = { path = " ../xml-rs" }
136
+ ```
137
+
138
+ When compiling ` foo ` , Cargo will resolve the ` xml-rs ` dependency to ` 0.8.0 ` ,
139
+ as it did before, but that version's been replaced with our local copy. The
140
+ local path dependency, which has version 0.8.0, takes precedence over the
141
+ version found in the registry.
142
+
143
+ Once we've confirmed a fix bug we then continue to run tests in ` xml-rs ` itself,
144
+ and then we'll send a PR to the main ` xml-rs ` repo. This then leads us to the
145
+ next section where a new version of ` xml-rs ` comes into play!
146
+
115
147
### Scenario: prepublishing a new minor version
116
148
117
149
Now, suppose that ` foo ` needs some changes to ` xml-rs ` , but we want to check
@@ -120,7 +152,7 @@ that all of Servo compiles before pushing the changes through.
120
152
First, we change ` Cargo.toml ` for ` foo ` :
121
153
122
154
``` toml
123
- [prepublish ]
155
+ [augment . crates-io ]
124
156
xml-rs = { git = " https://github.com/aturon/xml-rs" , branch = " 0.9.2" }
125
157
126
158
[dependencies ]
@@ -132,7 +164,7 @@ or introduce any `xml-rs` dependencies; it's enough to be using the fork of
132
164
` foo ` , which we would be anyway:
133
165
134
166
``` toml
135
- [prepublish ]
167
+ [augment . crates-io ]
136
168
xml-rs = { git = " https://github.com/aturon/xml-rs" , branch = " 0.9.2" }
137
169
138
170
[dependencies ]
@@ -154,15 +186,15 @@ want to do integration testing for (`servo`); no sibling crates needed to be
154
186
changed.
155
187
156
188
Once ` xml-rs ` version ` 0.9.2 ` is actually published, we can remove the
157
- ` [prepublish ] ` sections, and Cargo will warn us that this needs to be done.
189
+ ` [augment ] ` sections, and Cargo will warn us that this needs to be done.
158
190
159
191
### Scenario: prepublishing a new major version
160
192
161
193
What happens if ` foo ` instead needs to make a breaking change to ` xml-rs ` ? The
162
194
workflow is identical. For ` foo ` :
163
195
164
196
``` toml
165
- [prepublish ]
197
+ [augment . crates-io ]
166
198
xml-rs = { git = " https://github.com/aturon/xml-rs" , branch = " 0.10.0" }
167
199
168
200
[dependencies ]
@@ -172,7 +204,7 @@ xml-rs = "0.10.0"
172
204
For ` servo ` :
173
205
174
206
``` toml
175
- [prepublish ]
207
+ [augment . crates-io ]
176
208
xml-rs = { git = " https://github.com/aturon/xml-rs" , branch = " 0.10.0" }
177
209
178
210
[dependencies ]
@@ -191,31 +223,144 @@ prepublication version of `xml-rs`.
191
223
would help catch this issue at the Cargo level and give a maximally informative
192
224
error message).
193
225
226
+ ## Impact on ` Cargo.lock `
227
+
228
+ Usage of ` [augment] ` will perform backwards-incompatible modifications to
229
+ ` Cargo.lock ` , meaning that usage of ` [augment] ` will prevent previous versions
230
+ of Cargo from interpreting the lock file. Cargo will unconditionally resolve all
231
+ entries in the ` [augment] ` section to precise dependencies, encoding them all in
232
+ the lock file whether they're used or not.
233
+
234
+ Dependencies formed on crates listed in ` [augment] ` will then be listed directly
235
+ in Cargo.lock, eschewing the actual dependency entirely. For example let's say
236
+ we depend on ` env_logger ` but we're using ` [augment] ` to depend on a git version
237
+ of the ` log ` crate, a dependency of ` env_logger ` . First we'll have our
238
+ ` Cargo.toml ` including:
239
+
240
+ ``` toml
241
+ # Cargo.toml
242
+ [dependencies ]
243
+ env_logger = " 0.4"
244
+ ```
245
+
246
+ With that we'll find this in ` Cargo.lock ` , notably everything comes from
247
+ crates.io
248
+
249
+ ``` toml
250
+ # Cargo.lock
251
+ [[package ]]
252
+ name = " env_logger"
253
+ version = " 0.4.2"
254
+ source = " registry+https://github.com/rust-lang/crates.io-index"
255
+ dependencies = [
256
+ " log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" ,
257
+ ]
258
+
259
+ [[package ]]
260
+ name = " log"
261
+ version = " 0.3.7"
262
+ source = " registry+https://github.com/rust-lang/crates.io-index"
263
+ ```
264
+
265
+ Next up we'll add our ` [augment] ` section to crates.io:
266
+
267
+ ``` toml
268
+ # Cargo.toml
269
+ [augment .crates-io ]
270
+ log = { git = ' https://github.com/rust-lang-nursery/log' }
271
+ ```
272
+
273
+ and that will generate a lock file that looks (roughly) like:
274
+
275
+ ``` toml
276
+ # Cargo.lock
277
+ [[package ]]
278
+ name = " env_logger"
279
+ version = " 0.4.2"
280
+ source = " registry+https://github.com/rust-lang/crates.io-index"
281
+ dependencies = [
282
+ " log 0.3.7 (git+https://github.com/rust-lang-nursery/log)" ,
283
+ ]
284
+
285
+ [[package ]]
286
+ name = " log"
287
+ version = " 0.3.7"
288
+ source = " git+https://github.com/rust-lang-nursery/log#cb9fa28812ac27c9cadc4e7b18c221b561277289"
289
+ ```
290
+
291
+ Notably ` log ` from crates.io * is not mentioned at all here* , and crucially so!
292
+ Additionally Cargo has the fully resolved version of the ` log ` augmentation
293
+ available to it, down to the sha of what to check out.
294
+
295
+ When Cargo rebuilds from this ` Cargo.lock ` it will not query the registry for
296
+ versions of ` log ` , instead seeing that there's an exact dependency on the git
297
+ repository (from the ` Cargo.lock ` ) and the repository is listed as an
298
+ augmentation, so it'll follow that pointer.
299
+
300
+ ## Impact on ` [replace] `
301
+
302
+ The ` [augment] ` section in the manifest can in many ways be seen as a "replace
303
+ 2.0". It is, in fact, strictly more expressive than the current ` [replace] `
304
+ section! For example these two sections are equivalent:
305
+
306
+ ``` toml
307
+ [replace ]
308
+ 'log:0.3.7' = { git = ' https://github.com/rust-lang-nursery/log' }
309
+
310
+ # is the same as...
311
+
312
+ [augment .crates-io ]
313
+ log = { git = ' https://github.com/rust-lang-nursery/log' }
314
+ ```
315
+
316
+ This is not accidental! The intial development of the ` [augment] ` feature was
317
+ actually focused on prepublishing dependencies and was called ` [prepublish] ` ,
318
+ but while discussing it a conclusion was reached that ` [prepublish] ` already
319
+ allowed replacing existing versions in a registry, but issued a warning when
320
+ doing so. It turned out that without a warning we ended up having a full-on
321
+ ` [replace] ` replacement!
322
+
323
+ At this time, though, it is not planned to deprecate the ` [replace] ` section,
324
+ nor remove it. After the ` [augment] ` section is implemented, if it ends up
325
+ working out this may change. If after a few cycles on stable the ` [augment] `
326
+ section seems to be working well we can issue an official deprecation for
327
+ ` [replace] ` , printing a warning if it's still used.
328
+
329
+ Documentation, however, will immediately being to recommend ` [augment] ` over
330
+ ` [replace] ` .
331
+
194
332
# How We Teach This
195
333
[ how-we-teach-this ] : #how-we-teach-this
196
334
197
- Prepublication is a feature intended for large-scale projects spanning many
198
- repos and crates, where you want to make something like an atomic change across
199
- the repos. As such, it should likely be explained in a dedicated section for
335
+ Augmentation is a feature intended for large-scale projects spanning many repos
336
+ and crates, where you want to make something like an atomic change across the
337
+ repos. As such, it should likely be explained in a dedicated section for
200
338
large-scale Cargo usage, which would also include build system integration and
201
339
other related topics.
202
340
203
341
The mechanism itself is straightforward enough that a handful of examples (as in
204
342
this RFC) is generally enough to explain it. In the docs, these examples should
205
343
be spelled out in greater detail.
206
344
345
+ Most notably, however, the [ overriding dependenices] [ over ] section of Cargo's
346
+ documentation will be rewritten to primarily mention ` [augment] ` , but
347
+ ` [replace] ` will be mentioned still with a recommendation to use ` [augment] `
348
+ instead if possible.
349
+
350
+ [ over ] : http://doc.crates.io/specifying-dependencies.html#overriding-dependencies
351
+
207
352
# Drawbacks
208
353
[ drawbacks ] : #drawbacks
209
354
210
355
This feature adds yet another knob around where, exactly, Cargo is getting its
211
- source and version information. In particular, its similarity to ` [replace] `
212
- means the two features are likely to be confused. One saving grace is that
213
- ` [replace] ` emphatically does not allow version numbers to be changed; it's very
214
- tailored to surgical patches.
356
+ source and version information. In particular, it's basically deprecating
357
+ ` [replace] ` if it works out, and it's typically a shame to deprecate major
358
+ stable features.
215
359
216
- Fortunately, because both features are rarely used, are only used for very large
217
- projects, and cannot be published to crates.io, the knobs are largely invisible
218
- to the vast majority of Cargo users, who are unaffected by them.
360
+ Fortunately, because these features are intended to be relatively rarely used,
361
+ checked in even more rarely, are only used for very large projects, and cannot
362
+ be published to crates.io, the knobs are largely invisible to the vast majority
363
+ of Cargo users, who are unaffected by them.
219
364
220
365
# Alternatives
221
366
[ alternatives ] : #alternatives
@@ -244,14 +389,7 @@ address the desired workflow, for a few reasons:
244
389
# Unresolved questions
245
390
[ unresolved ] : #unresolved-questions
246
391
247
- There are two unresolved questions, both about possible future extensions.
248
-
249
- First: it would be extremely helpful to provide a first-class workflow for
250
- forking a dependency and making the necessary changes to Cargo.toml for
251
- prepublication, and for fixing things up when publication actually occurs. That
252
- shouldn't be hard to do, but is out of scope for this RFC.
253
-
254
- Second: we may eventually want to use multiple crate indexes within a Cargo.toml
255
- file, and we'll need some way to express * which* we're talking about with
256
- prepublication. However, this will also be the case for standard dependencies,
257
- so this RFC assumes that any solution will cover both cases.
392
+ - It would be extremely helpful to provide a first-class workflow for forking a
393
+ dependency and making the necessary changes to Cargo.toml for prepublication,
394
+ and for fixing things up when publication actually occurs. That shouldn't be
395
+ hard to do, but is out of scope for this RFC.
0 commit comments