Skip to content

Commit ddd6341

Browse files
committed
Forbid wildcard dependencies on crates.io
1 parent e2c36eb commit ddd6341

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

text/0000-no-wildcard-deps.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
- Feature Name: N/A
2+
- Start Date: 2015-07-23
3+
- RFC PR:
4+
- Rust Issue:
5+
6+
# Summary
7+
8+
A Cargo crate's dependencies are associated with constraints that specify the
9+
set of versions of the dependency with which the crate is compatible. These
10+
constraints range from accepting exactly one version (`=1.2.3`), to
11+
accepting a range of versions (`^1.2.3`, `~1.2.3`, `>= 1.2.3, < 3.0.0`), to
12+
accepting any version at all (`*`). This RFC proposes to update crates.io to
13+
reject publishes of crates that have compile or build dependencies with
14+
version constraints that have no upper bound.
15+
16+
# Motivation
17+
18+
Version constraints are a delicate balancing act between stability and
19+
flexibility. On one extreme, one can lock dependencies to an exact version.
20+
From one perspective, this is great, since the dependencies a user will consume
21+
will be the same that the developers tested against. However, on any nontrival
22+
project, one will inevitably run into conflicts where library A depends on
23+
version `1.2.3` of library B, but library C depends on version `1.2.4`, at
24+
which point, the only option is to force the version of library B to one of
25+
them and hope everything works.
26+
27+
On the other hand, a wildcard (`*`) constraint will never conflict with
28+
anything! There are other things to worry about here, though. A version
29+
constraint is fundamentally an assertion from a library's author to its users
30+
that the library will work with any version of a dependency that matches its
31+
constraint. A wildcard constraint is claiming that the library will work with
32+
any version of the dependency that has ever been released *or will ever be
33+
released, forever*. This is a somewhat absurd guarantee to make - forever is a
34+
long time!
35+
36+
Absurd guarantees on their own are not necessarily sufficient motivation to
37+
make a change like this. The real motivation is the effect that these
38+
guarantees have on consumers of libraries.
39+
40+
As an example, consider the [openssl](https://crates.io/crates/openssl) crate.
41+
It is one of the most popular libraries on crates.io, with several hundred
42+
downloads every day. 50% of the [libraries that depend on it](https://crates.io/crates/openssl/reverse_dependencies)
43+
have a wildcard constraint on the version. Almost all of them them will fail
44+
to compile against version 0.7 of openssl when it is released. When that
45+
happens, users of those libraries will be forced to manually override Cargo's
46+
version selection every time it is recalculated. This is not a fun time.
47+
48+
Bad version restrictions are also "viral". Even if a developer is careful to
49+
pick dependencies that have reasonable version restrictions, there could be a
50+
wildcard constraint hiding five transitive levels down. Manually searching the
51+
entire dependency graph is an exercise in frustration that shouldn't be
52+
necessary.
53+
54+
On the other hand, consider a library that has a version constraint of `^0.6`.
55+
When openssl 0.7 releases, the library will either continue to work against
56+
version 0.7, or it won't. In the first case, the author can simply extend the
57+
constraint to `>= 0.6, < 0.8` and consumers can use it with version 0.6 or 0.7
58+
without any trouble. If it does not work against version 0.7, consumers of the
59+
library are fine! Their code will continue to work without any manual
60+
intervention. The author can update the library to work with version 0.7 and
61+
release a new version with a constraint of `^0.7` to support consumers that
62+
want to use that newer release.
63+
64+
Making crates.io more picky than Cargo itself is not a new concept; it
65+
currently [requires several items](https://github.com/rust-lang/crates.io/blob/8c85874b6b967e1f46ae2113719708dce0c16d32/src/krate.rs#L746-L759) in published crates that Cargo will not:
66+
67+
* A valid license
68+
* A description
69+
* A list of authors
70+
71+
All of these requirements are in place to make it easier for developers to use
72+
the libraries uploaded to crates.io - that's why crates are published, after
73+
all! A restriction on wildcards is another step down that path.
74+
75+
Note that this restriction would only apply to normal compile dependencies and
76+
build dependencies, but not to dev dependencies. Dev dependencies are only used
77+
when testing a crate, so it doesn't matter to downstream consumers if they
78+
break.
79+
80+
# Detailed design
81+
82+
Alter crates.io's pre-publish behavior to check the version constraints of all
83+
compile and build dependencies, and reject those that have no upper bound. For
84+
example, these would be rejected:
85+
86+
* `*`
87+
* `> 0.3`
88+
* `>= 0.3`
89+
90+
While these would not:
91+
92+
* `>= 0.3, < 0.5`
93+
* `^0.3`
94+
* `~0.3`
95+
* `=0.3.1`
96+
97+
# Drawbacks
98+
99+
The barrier to entry when publishing a crate will be mildly higher.
100+
101+
In theory, there could be contexts where an unbounded version constraint is
102+
actually appropriate?
103+
104+
# Alternatives
105+
106+
We could continue allowing these kinds of constraints, but complain in a
107+
"sufficiently annoying" manner during publishes to discourage their use.
108+
109+
# Unresolved questions
110+
111+
Should crates.io also forbid constraints that reference versions of
112+
dependencies that don't yet exist? For example, a constraint of `>= 0.3, < 0.5`
113+
where the dependency has no published versions in the `0.4` range.

0 commit comments

Comments
 (0)