Repository navigation
Description
In Rust ecosystem, one main concern for library developers is to not have semver breaking updates to their package, because of the fear that majority of the dependent packages not getting the routing updates that would follow a breaking update.
There are two general solutions to this problem:
-
The old-school back-porting of updates, so that dependents on any API version would get all the routine updates. This solution can easily become a huge maintenance cost on library developers and is not a common practice in the Rust community at the moment.
-
Help owner of dependent packages to update their dependency versions and apply the changes needed, if any. This solution can be much less time consuming, and distributes the workload throughout the dependency chain. It also means that only the versions being used get the maintenance work needed, but not all theoretically-possible versions. So, in rustacean words: you pay for what you use.
Based on this, I want to propose to add new features to help owners with keeping their dependencies up-to-date. Most of the functionality can be exposed via the cargo update command.
Proposed Features
-
Warn on dependencies stuck in older versions. This would be a plain warning on
cargo update. The feature would be enabled by default, but there will be an option to disable it; and there can be one release version of Cargo as transition period, where the option is disabled by-default, but there's a notice about the upcoming change, if it applies. -
Commands to auto-update some/all dependency versions to latest. This option would update the relevant manifests to use a latest version of a single or multiple packages. This can also be an option to
cargo update, similar to--precise, but instead of updating the lock file, it would also update the manifest with the latest version, or some user-provided version.This is a tool to update Cargo Manifest files. Currently,
cargo updateonly works with the Cargo Lock file, so it may be a good idea to have a separate sub-command for the manifest manipulation features. But since it's a core functionality, it's better have this functionality in Cargo proper. -
Auto-update versions to a successful build. This is something that we can aim for in longer term, to have cargo update dependencies, and in case of failures, bisect and find the most-recent version that does not break the builds and/or tests. Best place for this may be a third-party cargo command and not cargo itself.
What do you think?
Activity
behnam commentedon Jul 20, 2017
I'm sure there are many examples where these can be helpful. Here's one that inspired me to write up this proposal: servo/unicode-bidi#46 (comment)
/cc @alexcrichton, @Manishearth, @anowell
alexcrichton commentedon Jul 20, 2017
I think we'd probably want to canvas what other package managers do here, e.g. do npm, yarn, bundler, rubygems, pip, etc do anything like this? I was personally under the impression that this sort of concerns was typically farmed out to a third-party service.
behnam commentedon Jul 24, 2017
Here’s a summary of similar features in some other package managers.
JS NPM
NPM CLI has built-in
outdatedsubcommand that shows the status of packages that their current, wanted and latest versions do not match.Like
cargo update, thenpm updatedoes update the current version to wanted, if needed and possible.It looks like that
npm updatedoes not have any more functionality in this area. Also, no other subcommand look related.Ref: https://docs.npmjs.com/cli/outdated
Description
(from https://github.com/npm/npm/blob/latest/doc/cli/npm-outdated.md)
This command will check the registry to see if any (or, specific) installed packages are currently outdated.
In the output:
wantedis the maximum version of the package that satisfies the semver range specified inpackage.json. If there's no available semver range (i.e. you're runningnpm outdated --global, or the package isn't included inpackage.json), thenwantedshows the currently-installed version.latestis the version of the package tagged as latest in the registry. Runningnpm publishwith no special configuration will publish the package with a dist-tag oflatest. This may or may not be the maximum version of the package, or the most-recently published version of the package, depending on how the package's developer manages the latest dist-tag(1).locationis where in the dependency tree the package is located. Note thatnpm outdateddefaults to a depth of 0, so unless you override that, you'll always be seeing only top-level dependencies that are outdated.package type(when using--long/-l) tells you whether this package is adependencyor adevDependency. Packages not included inpackage.jsonare always markeddependencies.Example
Edit
package.jsonand add"underscore": "1.7"to dependencies list.JS Yarn
Yarn CLI has built-in
outdatedsubcommand to “checks for outdated package dependencies”.Ref: https://yarnpkg.com/lang/en/docs/cli/outdated/
Description
Lists version information for all package dependencies. This information includes the currently installed version, the desired version based on semver, and the latest available version.
For example, say your package.json has the following dependencies listed:
The command run should look something like this:
yarn outdated Package Current Wanted Latest lodash 4.15.0 4.15.0 4.16.4 underscore 1.6.0 1.6.0 1.8.3 ✨ Done in 0.72s.Ruby Gems
Gems CLI has built-in
outdatedsubcommand to “display all gems that need updates”.Ref: http://guides.rubygems.org/command-reference/#gem-outdated
Description
(From ref.)
The outdated command lists gems you may wish to upgrade to a newer version.
You can check for dependency mismatches using the dependency command and update the gems with the update or install commands.
Ruby Bundler
Bundler CLI has built-in
outdatedsubcommand to “list installed gems with newer versions available”.Ref: https://bundler.io/v1.11/bundle_outdated.html
Description
(From ref.)
Outdated lists the names and versions of gems that have a newer version available in the given source. Calling outdated with
[GEM [GEM]]will only check for newer versions of the given gems. By default, available prerelease gems will be ignored.Python PIP
PIP CLI's
listsubcommand has an--outdatedoption, to "list outdated packages", and an--uptodateoption to "list uptodate packages".Ref: https://pip.pypa.io/en/stable/reference/pip_list/
Examples
List installed packages.
List outdated packages (excluding editables), and the latest version available.
behnam commentedon Jul 24, 2017
In summary:
JS and Ruby package managers have built-in
outdatedsubcommand to list packages "not in good standing", in the meaning that their installed version is not what's asked for, or what's asked for is not the latest upstream version (not necessarily the largest one, but the latest marked as stable release).Python PIP has similar functionality via the built-in
listsubcommand, which makes it more generic, but harder to discover and use for beginner/average users.Looks like all these commands are readonly and have no built-in functionality to update manifest files to the latest version.
I have not seen signs of any warning-like functionality regarding out-of-date packages in other commands.
behnam commentedon Jul 24, 2017
So, IMHO, we can plan to for these functionalities, applicable only to direct dependencies of a package/workspace.
a) A built-in
outdatedcommand to help developers find outdated direct dependencies. This would be the readonly and the human-readable output will be similar to the JS/Ruby package managers.b) Expand (a) to support workspaces.
c) Add options to
outdatedto make it read-write, updating version numbers of one/more/all outdated dependencies. This, I assume, would be the only/first cargo command to write to the manifest, so would need more design and implementation work.d) Expand (c) to also support workspaces.
These two can be enough for shell scripts and third-party cargo commands to easily build automations for stable upgrades, meaning that run the tests with single upgrades and revert if there's compile or test errors.
What do you think?
steveklabnik commentedon Jul 24, 2017
https://crates.io/crates/cargo-outdated works well today
behnam commentedon Jul 24, 2017
Unfortunately,
cargo-outdatedpackage doesn't have any support for workspaces, yet.Also, a question would be about the original proposal to add optional warning (possibly as an opt-in, via env-var and/or cli option) for
cargo updateabout existence of outdated package(s). I'd like to know how everyone feels about that.alexcrichton commentedon Jul 25, 2017
I'd be totally down for adding native
outdatedsupport in Cargo itself, but we'd probably want to work closely with the upstream author ofcargo-outdatedto ensure we coordinate. I know I use it often enough!alexcrichton commentedon Jul 25, 2017
Also thanks so much for doing that investigation @behnam, it's quite helpful!
Keats commentedon Jul 25, 2017
A big +1 for getting
cargo outdatedbuilt-in.I've been using
cargo-outdatedfor ages now but as @behnam says, it doesn't support workspaces yet and I use so much withyarnandpipthat I believe it should be part of Cargo.Just to update the yarn output, it actually looks like the following now:
Having the URL in the output is quite nice to be able to see the changes too. Separating the dev-dependencies, build-dependencies and dependencies more cleanly than yarn does would be nice too but then it might become too complex to display with workspaces.
One change to do compared to
cargo-outdatedthat is already mentioned is that imo, it should only list direct dependencies of the project, not subdependencies. Here's an example on one of my projects:I only care about
hyperin that list.If we want to go c) I would recommend checking the
yarn upgrade-interactivecommand as an example of how to handle it.I'd be interested to do the implementation if that ends up being accepted for cargo!
behnam commentedon Jul 26, 2017
Good ideas, @Keats!
Agreed.
Also, on a similar note, a
--verboseoption that shows you also all in good standing, telling you what's been in the check list.I'm not sure what
build-dependenciesis here. But, aboutdev-dependencies, agreed that sometimes it's not a concern and better be able to leave it out of calculation. So, maybe we need a set of options to disable each group of these dependencies.Actually, I think the readonly functionality won't be that complex for workspaces, since there's expected to be one
Cargo.lockalready.But, it's a good reminder that we also need something like NPM's
location, which shows which local (in the workspace) package is depending on the old version.And as a plus, this would be Cargo's internal tool to warn on a workspace (or even a package) having direct dependencies on multiple versions of a single package.
Exactly. I'm not sure if we want a feature to perform these checks more than one level depth. I think we can start with direct deps and see if there's demand for an option to extend.
Awesome! I won't be able to get to this in the next few weeks, but can help with some tests and reviews, if needed.
behnam commentedon Jul 26, 2017
So, looks like we have general consensus on the core functionality of a built-in
outdatedsubcommand and the rest can be discussed per PR, I assume.Also, let's CC author of
cargo-outdated. @kbknapp, what do you think about these?Keats commentedon Jul 26, 2017
Build dependencies would be
bindgenfor example: https://github.com/compass-rs/sass-rs/blob/master/sass-sys/Cargo.toml#L16Dev dependencies is important to display in JS-land since I have more dev dependencies than actual dependencies but I think it still makes sense to display outdated info for all crates listed in my Cargo.toml by default. We could have a flag to disable build/dev dependencies but I don't think it would be used very often: if you run
cargo outdated, you usually want to see all of the crates.My worry was more on how to display it well in the terminal when you have many workspaces like habitat. I guess scrolling a bit is not a huge issue
behnam commentedon Jul 26, 2017
Agreed, @Keats. :)
Funny thing about
build-dependencies: I could tell what it is, but didn't find it anywhere under the manifest reference: http://doc.crates.io/manifest.html. Turns out, it's only mentioned in this other page: http://doc.crates.io/specifying-dependencies.html#build-dependencies I'll submit a PR to add it to the list in http://doc.crates.io/manifest.html#dependency-sections so it doesn't happen again.[doc/manifest] Add build-dependencies to Dependency sections list
24 remaining items
deg4uss3r commentedon Jul 11, 2020
@svenstaro Yes I have! Progress is moving slowly, but I am working on it :) starting the new job at the same time is tough though
svenstaro commentedon Jul 11, 2020
Ok sweet, thanks for the update!
svenstaro commentedon Oct 5, 2020
@deg4uss3r friendly ping :D
deg4uss3r commentedon Oct 6, 2020
@svenstaro Thank you very much for keeping me honest!
So, I am working on this; however, I have been doing so offline because I see a lot of little things to improve on
cargo-oudatedthat I would like to simplify as a cargo sub-command, but still possibly maintaincargo-outdatedas a heavier project based option. So here's my work out in the open: https://github.com/deg4uss3r/outdated2This will look VERY rough right now, I'm sorry it's been a pretty interesting 2020 so far!
So this simplifies the project way down to only looking at workspace dependencies and requesting the latest from https://crates.io through the API. I think this is the best choice to add to cargo since we want it to always work no more compile issues with conflicting dependencies and it will only check the outdated dependencies of the current project rather than diving into dependencies that the launcher will have no control over.
There's A LOT (as you can tell) that I need to work on the biggest is integrating with
cargodirectly, but I have been paying close attention to the dependencies thatcargouses to make sure I'm reusing what is already imported. So far I see that I need to really flesh out before actually putting into cargo for the MR:I would love some opinions on this scaled down version before I continue further though as, personally I think this is what we want as a
cargosub-command, but I might be totally in the minority there.Edit: I'm sure there's some really simple optimizations I haven't done yet but right now it's pretty fast, it takes about 9 seconds (release build, from rustc stable
1.46) for servo... which isn't bad for something like this!svenstaro commentedon Oct 7, 2020
Great to see some progress!
Since you asked for feedback: Features that I really like in the current version:
--ignore,--depth,--workspace.--exit-codeis interesting for CI.golddranks commentedon Oct 7, 2020
I use
cargo outdated -R/--root-deps-onlyquite often, because the standard output is a bit verbose.dessalines commentedon Oct 10, 2020
I suggest looking at
yarn upgrade-interactive --latestfor a really clean upgrading interface. I often use cargo outdated, but having to change every dep manually is a pain.epage commentedon Apr 28, 2022
btw #10498 exists for moving cargo-edit's cargo-upgrade into cargo.
I wonder if
cargo outdatedcould be a resolved viacargo updateandcargo upgradeviaCould you clarify which "modes" you are talking about that it'd need to support
epage commentedon Jul 27, 2022
cargo upgrade v0.10.3 now provides a table summary of upgrades. This doesn't completely replace
cargo outdatedas this only handles root dependencies. I still hope we could havecargo updatehandle that case.Example for clap:
(actual output is colored to make it easier to scan)
tgross35 commentedon Apr 14, 2023
If this gets picked up, one reasonable change from
cargo-outdatedis that having outdated packages should exist nonzero by default. It is a bit surprising when running in CI that you need to use--exit-code 1to make it failpitaj commentedon May 20, 2023
Just wanted to note here that
cargo upgradesalso exists and seems to be more compatible (works on rust-lang/rust workspace for instance).Auto merge of #13372 - epage:update-report, r=weihanglo
epage commentedon Feb 9, 2024
While its not as fancy as
cargo upgradeorcargo outdated, #13372 added highlighting of non-latest dependencies to cargo.