-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rfc: make cargo install extensible #2376
rfc: make cargo install extensible #2376
Conversation
for context i would really like this (if considered to be viable) to be blocked on #2196 because i believe the pattern that this RFC introduces builds the affordances in a way that mitigates much of what i believe could be seen as a downside of this RFC |
I guess I'm one of those who think that clean uninstallation is an important feature. I hope the statement that we are few is wrong. I avoid Currently, Cargo solves this in a beautiful way: it just puts a binary into a directory. It is simple, yes, not very extensible, yes. But it allows for clean and simple uninstallation. Updating is equivalent to "forcing" the installation. With If the RFC is merged in the current form, I'd probably stop using Instead I think we should focus on artifact generation: allowing post-build scripts to create .msi files or .snap files or .deb files and allowing users to install them on their own, or maybe even on the user's behalf. |
Maybe a more general way is |
I'm all for supporting that as well. I'd like to make packaging easier. (That also includes policy-compliant packaging that could go into distributions, not just creating a .deb from thin air without a source package.) What I'm looking for here is a way to let crates provide additional files, not just binaries. Generating manpages, generating completions, and putting them in the appropriate places. We'd be open to talking about how exactly that should work. For instance, we certainly could have Another possibility would be to just install those files into a temporary directory under the output directory, and We'd like to do the simplest thing that could work, here. |
@liigo We talked about having a |
- Making `cargo install` more capable could encourage people to use it as a primary distribution mechanism for a broader class of applications, rather than just for simple command-line tools. On the other hand, this same mechanism can also serve as the basis for distribution packaging, which typically wants to install into a temporary directory and package the result. | ||
- It makes the emergence of conventions significantly more difficult as the option to reuse, share, or automate this task has significantly affordance than integrating it into the familiar `cargo` step. | ||
- Currently, `cargo install` tracks what files it installs, and supports `cargo uninstall`; this extension mechanism does not hook into that. Potentially, `install.rs` could emit a list of installed files and let `cargo install` install them, producing a log of those files for later uninstallation. However, we do not intend for `cargo install` to become a full-featured package management mechanism; rather, we expect `cargo install` to work analogously to `make install`. While the occasional package provides a `make uninstall`, few developers expect such a mechanism. | ||
- Currently, `cargo install` tracks what files it installs, and supports `cargo uninstall`; this extension mechanism does not hook into that. Potentially, `install.rs` could emit a list of installed files and let cargo install install them, producing a log of those files for later uninstallation. However, we do not intend for `cargo install` to become a full-featured package management mechanism; rather, we expect `cargo install` to work analogously to `make install`. While the occasional package provides a `make uninstall`, few developers expect such a mechanism. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicate of previous point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops! excellent call. i'll fix that!
That would work as well. in fact we could have Your proposal (calling it "microcargo") sounds fine @joshtriplett but I'd like to give an alternative "monolithic Cargo" proposal to just be able to compare the two: You could have Cargo would then store that list and So with the "microcargo" approach you have So summarizing, compared to the "shellout" proposal of the current RFC, I think "minicargo" and the monolithic approaches are both better, with me preffering the minicargo approach. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally in favor of a move in this direction, but I have some questions and concerns =)
|
||
## Summary | ||
|
||
The goal of this RFC is to introduce the ability for an end user to be able to extend the `cargo install` command arbitrarily to include instructions that should be executed occur after `cargo install <project>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"to be able" seems redundant here?
I propose the following wording:
This RFC gives end users the ability to extend the
cargo install
command arbitrarily, allowing them to include instructions executed aftercargo install <project>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing. Happy to update.
### New Named Concepts | ||
|
||
- `install.rs`: a file that contains a set of instructions to occur after `cargo install` is run. | ||
- `metainstall`: a key in `Cargo.toml` that specifies crate dependencies in an ordered list. Each crate dependency listed must be a library crate that provides a `metainstall` function. The `metainstall` function accepts no arguments, produces no return value, and should panic on failure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the rationale for a metainstall
function accepting no arguments, .. ?
This should be described precisely in the reference-level explanation. =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
metainstall = ["cli-install"] | ||
|
||
[dependencies] | ||
cli-install = "0.1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a regular dependency and not a build or "meta-install" dependency?
Will the CLI app's code use cli-install
as a library? It feels like there should be a separation...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably best discussed on the metabuild
repo where this syntax is being determined. #2196. Further discussing it here is not relevant, but discussion on that issue would be welcomed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see; missed that =)
|
||
### New Named Concepts | ||
|
||
- `install.rs`: a file that contains a set of instructions to occur after `cargo install` is run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To @est31's point on uninstallation, should uninstall.rs
be required if there is a install.rs
?
Of course, a crate can cheat and have uninstall.rs
which is not the inverse of install.rs
, but it is better than nothing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we discussed this issue at length. We're not sure if requiring the uninstall.rs
is better or worse as I would think, personally, that it gives the appearance of a guarantee that we cannot make, i.e. that it's not the inverse of install.rs
by I'm open to being convinced otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
were any thoughts made for making/mandating that install.rs be reversible/isomorphic by design to allow the undoing automatically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @ashleygwilliams here: mandating (or even supporting) uninstall.rs
is no guarantee for uninstall.rs
actually uninstalling all of the artifacts. We should go either with the minicargo or monolithic approaches IMO. As for isomorphism @fbstj do you have any precedent of an isomorphic scripting language or similar that you can share? Also, we would have to make sure that all of the information that enters the program will stay the same, otherwise even if we have an isomorphic subset of Rust, we won't be able to guarantee equal outcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fbstj Is that actually possible tho? Unless we have some snapshot of how things were before, install.rs
being possibly non-deterministic should not allow you to find an inverse function / program. Of course you could require that the main
of an install.rs
file be a const fn
which would get you determinism, but even then - we'd have to rule out many good programs to make reversibility efficient or decidable, no? And you'd need to extend the type system to rule out such good programs.
@ashleygwilliams Given that install.rs
and indeed build.rs
could do all sorts of things to your computer, including invoking UB, I think that guarantees were never something that we could make on this front, and that it's all inherently trust based. I think that if we clearly communicate that this is all best-effort, then it is better to require uninstall.rs
scripts and build great helper crates around this.
As for isomorphism @fbstj do you have any precedent of an isomorphic scripting language or similar that you can share?
That would be quite the restrictive language, see: https://stackoverflow.com/questions/13404208/in-pure-functional-languages-is-there-an-algorithm-to-get-the-inverse-function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
guarantees were never something that we could make on this front, and that it's all inherently trust based.
Right now we still have the option to sandbox install.rs
and friends to one directory where they can put stuff in, asking cargo to do the actual installation for them so that uninstallation is possible.
But even if we decide to not sandbox, this argument sounds too much like: "you need to already trust them so making it easier for them to not introduce bugs is not important".
|
||
## Reference-level explanation | ||
|
||
This is the technical portion of the RFC. Explain the design in sufficient detail that: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part seems left over from the RFC template?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. Can fix.
### Corner Cases | ||
|
||
- Installing an application should not run the `install.rs` files of any of it’s dependencies, only of the application itself. | ||
- When re-installing a binary package this might run a different `install.rs` than the one that was initially run. This might lead to inconsistent/ undefined behavior. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of the phrase "undefined behavior" should probably be reserved for when referring to UB as in your code not having any semantics. If that is what is intended here, then that is concerning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's what is intended here, I think it was meant more as "potentially unexpected behavior"/"surprising behavior". I'm happy to update the language. Thanks for the catch!
- Tools only support specific popular platforms because being cross-platform is deemed “too difficult”. | ||
- Making `cargo install` more capable could encourage people to use it as a primary distribution mechanism for a broader class of applications, rather than just for simple command-line tools. On the other hand, this same mechanism can also serve as the basis for distribution packaging, which typically wants to install into a temporary directory and package the result. | ||
- It makes the emergence of conventions significantly more difficult as the option to reuse, share, or automate this task has significantly affordance than integrating it into the familiar `cargo` step. | ||
- Currently, `cargo install` tracks what files it installs, and supports `cargo uninstall`; this extension mechanism does not hook into that. Potentially, `install.rs` could emit a list of installed files and let `cargo install` install them, producing a log of those files for later uninstallation. However, we do not intend for `cargo install` to become a full-featured package management mechanism; rather, we expect `cargo install` to work analogously to `make install`. While the occasional package provides a `make uninstall`, few developers expect such a mechanism. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to emulate make install
tho? I've never found make
to be a reliable program.
I also question the assertion on expectations. What is the evidence for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fair. The relation to make
was in a convo with @joshtriplett @alexcrichton and @withoutboats - I also share your concern a bit re this, but I found that the affordances this gives us for both cargo install
distribution AS WELL as platform specific package managers outweighed it in my opinion. I'm not sure if there's any data/anecdata to be found but I would be happy to try to find some!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we did want anecdata, I wonder if cross compilers and distro packagers would be a good source of information on make install
behaviour as they're groups of people likely to spend a high percentage of their time compiling things.
My own experience/expectation from when I was doing a lot of cross-compilation with emscripten is that things supporting make install
a) permit some way to set the installation 'prefix' (be it --prefix
with autotools and autotools-mimicking things like the rust configure script or the cmake variable or something else) and nothing gets installed outside of that prefix (e.g. completions end up in $PREFIX/etc/bash_completion.d)
and b) make uninstall
is a bit flaky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small note: I don't think cross compiler and distro packagers are representative of the set "developers". ;) Even so, any and all anecdata would be nice to have even if unrepresentative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I take your point, perception is important. I was just thinking about the most efficient way to get feedback on large numbers of executed make install
commands.
Something that seems worth mentioning, explicitly: some responses have expressed the sentiment that the right answer is to work towards distribution packaging and similar, rather than making |
So, as was mostly expected, the primary question brought up by the comments so far is the issue of Would that appease any of those who are concerned about uninstall? If not, let's try to aggregate other suggestions about mitigating the uninstall issue and discuss which if any would be reasonable to implement alongside this, with an eye that there is still the goal of not packing cargo with so many features that it begins to resemble a platform-specific package manager. (which i think we all agree is something we DON'T want to happen.) |
I'm not sure I understand your proposal fully. Could you explain it? Suppose I did |
I think she's talking of a general class of solutions (correct me if I'm wrong), but one such proposal would be that (This doesn't cover all cases of uninstall, but as the RFC mentions this isn't intended to be a generalized distribution solution) |
@Manishearth Right, the idea would be that |
@est31 yup, what both @Manishearth and @joshtriplett expansion of what i said is correct. i'm curious if that's enough to address the issue- and if not, i'm curious what strategies would best address the issue without growing cargo into a thing similar to a full fledged platform-specific package manager, which, i believe, we all agree that we don't want. if we can agree on something i am very happy to update the RFC to include this strategy explicitly. |
This strategy seems reasonable, and mostly assuages my concerns. There's of course the issue of Personally I prefer the variant where I think an argument in favor of this RFC is that we can always decide to permit an (optional) |
One of the problems that crops up with other languages' package managers (hi, Python!) is that the tool chooses one particular convention for where to install files and uses it on every platform in the name of consistency. Usually this convention is highly-POSIX-flavoured, making things weird and awkward to use on Windows. I realise that ship has kind of already sailed for Cargo, since it installs binaries into |
@Screwtapello so, i share this concern but i think this RFC alleviates it instead of exacerbating it. we specifically are picking to do a |
I didn't see any mention of passing arguments to |
@aidanhs it was not opinionated! i think that would be fine, and likely uncontroversial? but i'm curious what others think (assuming no one objects i can specifically add that to the RFC) |
Yes, both variants as laid out by @joshtriplett would be enough (see quote above). I'd personally prefer the variant where install.rs is not doing the changes directly and would like install.rs to be sandboxed. It could have unrestricted read access but write access restricted to one directory inside the Especially, it seems to me that the intention is not for |
@Screwtapello This may not be true in the future if something like rust-lang/cargo#5183 is merged. |
Installing to a staging area, and from there copying to either |
I think that I'm against this RFC. Instead of allowing crate authors to put arbitrary steps inside of To make it concrete, I'll use man pages as an example. With this RFC, crate authors would write an An alternate approach would be to allow crate authors to put something like I think that the declarative approach is superior for a number of reasons.
So, to sum up, I think we should extend cargo with the ability to understand and install crate artifacts on a type-by-type basis, so that they can be handled consistently and appropriately across platforms, and not left to individual crate authors. |
@casey I think that's fair for a large number of cases, but what about certain Rust projects like tectonic, for which this RFC would be hugely useful in its present form? |
@alexreg, what kinds of artifacts does tectonic need to install? I'm wondering if there might be a better way to support them. |
I suppose this hasn't been high on people's priority lists lately, given the lack of news. Any chance of reviving things? Some questions I had:
|
I'm struggling to parse this. Can you tell me what you mean?
What's the use case for this? |
One of my use cases of this feature is to enforce all of the collaborators to set up git-hooks scripts to enforce some policy like commit message and others. I usually use husky to enforce all collaborators to follow conventionalcommits |
Looks like this is being revived as part of rust-lang/crates-io-cargo-teams#14. @ashleygwilliams / anyone else, how are we going to proceed here? |
This RFC sounds excellent! In particular, this approach to offering
I was surprised to see that there hasn't been any movement on this in a year and a half. Has it been superseded by more recent initiatives? If so, could someone provide a link? |
This came up in today's @rust-lang/cargo meeting. This hasn't seen activity in a long time, and as a result, we'd like to postpone it. This should not be taken as a lack of interest; we just don't want to leave this open and unresolved indefinitely. If someone would like to pick this up, they should feel free to do so, and post a new RFC. In general, if someone is interested in reviving this, they should specifically write this in terms of being able to stage things in an output directory and letting Cargo install them, rather than installing things directly. We're generally not in favor of a completely general "install things directly onto the filesystem" script. (We're also uncertain about the amount of complexity this might create in Cargo, and we'd want to know this wouldn't impact long-term maintainability.) Hopefully this guidance helps someone looking to work on this in the future. @rfcbot postpone |
Team member @joshtriplett has proposed to postpone this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to postpone, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC is now postponed. |
See also rust-lang/rfcs#2376 for difficulties in packaging data files in cargo.
Rendered
The goal of this RFC is to introduce the ability for an end user to be able to extend the
cargo install
command arbitrarily to include instructions that should be executed occur aftercargo install <project>
.This RFC was a collaborative effort between @joshtriplett @spacekookie and @ashleygwilliams.
A note about
cargo
as a distribution toolWe are in no way suggesting that
cargo install
should be the definitive or exclusive distribution mechanism, or that it should supplant other distribution mechanisms such as platform package management tools; we are only proposing to improve the experience for the class of applications that already depend on cargo as a distribution platform today, notably small CLI applications and development tools for the Rust ecosystem.Additionally, this proposal will make
cargo install
more useful for the larger set of rust applications that leverage the larger, often preferred, platform-specific distribution workflows, which typically want to install into a temporary directory and package the result. This point is discussed further in the “Rationale and Alternatives” section.Fundamentally, the aim of this RFC is aligned directly with Rust’s value of “productivity”. It aims to make both building and using small developer CLI tools simpler and easier which has a direct positive effect on the ability of all to improve their workflow.