-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Implement Rustdoc versioning checks #8640
Conversation
This intends to be a helper structure similar to `RustTargetData` which includes helper functions which are useful for interacting with the rustdoc fingerprint files among other things.
Sometimes we need to remove the `doc/` directory (if exists) in order to not mix different versions of the js/html/css files that Rustc autogenerates and lack versioning.
Before compiling, we need to make sure that if there were any previous docs already compiled, they were compiled with the same Rustc version that we're currently using. Otherways we must remove the `doc/` folder and compile again. This is important because as stated in rust-lang#8461 the .js/.html&.css files that are generated by Rustc don't have any versioning. Therefore, we can fall in weird bugs and behaviours if we mix different compiler versions of these js/.html&.css files.
(rust_highfive has picked a reviewer for you, use r? to override) |
I think it is fine just to return an error. All other commands that delete or replace files will fail if there is something like a permission error. And if
I would make a rustc wrapper that reports a different version. Here is an example of a test that does exactly that. It sets the "RUSTC" environment variable to a custom executable which intercepts the There are many different approaches how to detect that the directory actually got deleted. I would probably just add a bogus file into the Let me know if you have any other questions. |
Is the user does not have permissions or a folder/file can't be created or deleted, Cargo will fail and return an Error indicating the problem.
Hey @ehuss. I've been working on that for some time and have finished the skeleton for the test of the rustdoc fingerprint. But for some reason, I can't open the fingerprint file inside the tests. Thanks! |
I also notice that the current PR won't work because it attempts to write to the fingerprint directory before it is created. The general implementation of |
Thanks a lot for the suggestions @ehuss. Will take a look to the |
☔ The latest upstream changes (presumably #8954) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
After refactoring what was done on the latest approach this time we included the rustdoc versioning logic inside the `compiler::rustdoc` fn. - Created `RustDocFingerprint` struct so that is easier to manage all of the logic & functions related to rustdoc versioning as well as scaling it in the future if needed.
- Check wether the fingerprint is created with the correct data after a `rustdoc` execution. - Check wether the previous docs are removed if the version used to compile them reported in the fingerprint is different from the actual one being used by the compiler.
Hey @ehuss I think I got it now. Thanks for the ideas on the I belive adding the logic inside the Thanks for your help and sorry for the delay. EDIT:The test failing has nothing to do with the changes added in this PR AFAIK. The tests I did are passing on my machine. |
tests/testsuite/doc.rs
Outdated
"crate-b", | ||
] | ||
"#, | ||
[workspace] |
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.
Seems like a bunch of unnecessary whitespace changes here.
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.
Cargo fmt was probably who made that happen. Apologies.
tests/testsuite/doc.rs
Outdated
r#" | ||
[package] | ||
name = "foo" | ||
version = "1.2.4" | ||
authors = [] | ||
"#, |
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.
r#" | |
[package] | |
name = "foo" | |
version = "1.2.4" | |
authors = [] | |
"#, | |
r#" | |
[package] | |
name = "foo" | |
version = "1.2.4" | |
authors = [] | |
"#, |
tests/testsuite/doc.rs
Outdated
|
||
dummy_project.cargo("doc").run(); | ||
|
||
// As the test shows avobe. Now we have generated the `doc/` folder and inside |
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.
// As the test shows avobe. Now we have generated the `doc/` folder and inside | |
// As the test shows above. Now we have generated the `doc/` folder and inside |
src/cargo/core/compiler/mod.rs
Outdated
@@ -649,7 +662,11 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> { | |||
&mut |line| on_stderr_line(state, line, package_id, &target, &mut output_options), | |||
false, | |||
) | |||
.chain_err(|| format!("could not document `{}`", name))?; | |||
.chain_err(|| format!("Could not document `{}`.", name))?; |
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 seems like an unrelated change (and the cause of the test error).
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.
Weird. I don't remember changing that TBH. But thanks for the catchup!
tests/testsuite/doc.rs
Outdated
|
||
// Edit the fingerprint rustc version. | ||
// Read fingerprint rustc version and return it as String | ||
let get_fingerprint_version = |root_path: std::path::PathBuf| -> String { |
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 this needs to be a closure. Also, it can all be replaced with dummy_project.read_file("target/doc/.rustdoc_fingerprint.json")
.
src/cargo/core/compiler/mod.rs
Outdated
// any versioning (See https://github.com/rust-lang/cargo/issues/8461). | ||
// Therefore, we can end up with weird bugs and behaviours if we mix different | ||
// compiler versions of these files. | ||
let (fingerprint, doc_dir_removed) = RustDocFingerprint::check_rustdoc_fingerprint( |
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 probably isn't a safe place to put this, since we don't want building the Work
closure to actually make any changes until it is executed.
I'm not sure where is a good location. It probably should be done once, before it starts draining the queue. Maybe somewhere like in Context::compile
, just after the call to preprare
? It could check if there are any rustdoc units to build, and if so, check the fingerprint.
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 added it here since there's this comment where the doc folder is created. Therefore I assumed this would be the best place to check wether we want to remove it or not etc..
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.
Also, it's important to highlight that inside of the Worker
we only write the fingerprint in case we erased the previous one. But the directory removal/fingerprint reading is done outside. So I don't really know if it is unsafe (obviously, you're the expert here) but just writing the fingerprint in case it was previously erased inside of the Worker
is unsafe?
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 called for every package that is being documented, so we probably don't want it to be called N times. By lifting it out to an earlier stage, that can help ensure that it only runs once.
/// Structure used to deal with Rustdoc fingerprinting | ||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct RustDocFingerprint { | ||
_rustc_verbose_version: String, |
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 leading _
here seems a little unusual.
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 added it because it's never used per se. But ye, might be better to remove it.
}; | ||
|
||
// Check wether `.rustdoc_fingerprint.json exists | ||
let mut fingerprint = match File::open(RustDocFingerprint::path_to_fingerprint(doc_dir)) { |
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 it's a little more succinct to use std::fs::read_to_string
instead of opening a file object. Also, I don't think this needs the extra complexity like from_file
. If it is only read in one place, it can just be inlined.
_rustc_verbose_version: String, | ||
} | ||
|
||
impl RustDocFingerprint { |
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 not sure it's really necessary to have a struct to wrap these methods. From what I can see, this can all be done in a single free function, and it should be substantially smaller.
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 did it on that way so that if in the future more things need to be added to it, we already have the struct and it's easier to add functionalities.
I can implement everything directly anyway if you prefer it. I was just thinking about the future, and more functionalities added to this fingerprinting feature for rustdoc.
What should I do then?
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 if it grows in complexity in the future, it can be reworked to be more abstract, but for the foreseeable future I wouldn't expect it to change much.
// exists neither, we simply do nothing and continue. | ||
Err(_) => { | ||
// We don't care if this suceeds as explained above. | ||
let _ = std::fs::remove_dir_all(doc_dir); |
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.
Cargo has specific code for removing paths in util::paths::remove_dir_all
.
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.
Thanks!
For the rest, has been addressed. I'm waiting for your inputs on the discussions are still open to modify the code appropriately. |
src/cargo/core/compiler/mod.rs
Outdated
@@ -649,7 +662,11 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> { | |||
&mut |line| on_stderr_line(state, line, package_id, &target, &mut output_options), | |||
false, | |||
) | |||
.chain_err(|| format!("could not document `{}`", name))?; | |||
.chain_err(|| format!("could not document `{}`.", name))?; |
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 still has an unrelated change here, which is causing the test failure.
☔ The latest upstream changes (presumably #8996) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
📌 Commit 61c2332 has been approved by |
☀️ Test successful - checks-actions |
Thanks to you, I wouldn't have been consistent without your help patience and support. I really appreciate the work you're doing guys from the cargo-team to give mentorship and help and also maintain this repo among others. ❤️ |
Update cargo 8 commits in ab64d1393b5b77c66b6534ef5023a1b89ee7bf64..bf5a5d5e5d3ae842a63bfce6d070dfd438cf6070 2021-02-10 00:19:10 +0000 to 2021-02-18 15:49:14 +0000 - Propagate `lto=off` harder (rust-lang/cargo#9182) - refactor: make deref intentions more straightforward (rust-lang/cargo#9183) - Update link for no_std attribute. (rust-lang/cargo#9174) - Remove mention of --message-format taking multiple values (rust-lang/cargo#9173) - Emit warning on env variable case mismatch (rust-lang/cargo#9169) - Implement Rustdoc versioning checks (rust-lang/cargo#8640) - Bump to 0.53.0, update changelog (rust-lang/cargo#9168) - Prevent testsuite from loading config out of sandbox. (rust-lang/cargo#9164)
/// Structure used to deal with Rustdoc fingerprinting | ||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct RustDocFingerprint { | ||
pub rustc_vv: String, |
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.
curious, why are just using the rust version, as opposed to the full fingerprint of the build?
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.
Because the docfiles only depend on the compiler version, if it changes we always rebuild deleting the entire docs folder. Otherways, if the compiler version is the same, we know 100% sure that the docfiles are still valid and will not introduce any errors on the browser console or malfunctions.
We simply don't need anymore data than the version, that's why we don't use the full fingerprint of the build.
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 about if people change the feature they are building with, which causes different items to be built? Also is docs only depending on compiler version and no flags something that we guarantee?
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 you check the issue from which the PR was originated. The goal is to ensure that the html, css and js files are consistent with the compiler version currently used and not mix it up.
Any other thing stills being handled on the same way it was before. This has nothing to do with the content that you're documenting ie. target, features etc. But with the actual js, css and html code in the files of the docs and which version should they be used on.
Hope that makes it a bit more clear.
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.
@guswynn Each crate has a "fingerprint" stored in the .fingerprint
directory. The things it tracks are listed here. The fingerprint will detect if an individual crate needs to be rebuilt, but it doesn't detect when shared files (like the search index) need to be deleted and rebuilt. This adds a "global" fingerprint for building docs to detect when the rust toolchain changes (and may introduce an incompatible search index), and clears out the entire docs directory to deal with those changes. Changes to things like features only trigger the individual crate to be rebuilt, but it retains the shared files (which rustdoc updates incrementally).
1.52 Cargo adds rust-lang/cargo#8640 which means that cargo will try to purge the doc directory caches for us. In theory this may mean that we can jettison the clear_if_dirty for rustdoc versioning entirely, but for now just workaround the effects of this change in a less principled but more local way.
beta: revert #8640 - rustdoc versioning checks #8640 has been causing some problems with rustbuild (see rust-lang/rust#83914 and rust-lang/rust#83530 (comment)). In order to give more time to figure out a solution, this reverts the change on beta. Will need to take some time to figure out what to do on master. Also cherry picked the following to get tests passing: * #9316 — Fix semver docs for 1.51. * #9307 — tests: Tolerate "exit status" in error messages
[beta] Update cargo 2 commits in 90691f2bfe9a50291a98983b1ed2feab51d5ca55..d70308ef052397c7d16f881c2d973a8c5b4c23d9 2021-03-16 21:36:55 +0000 to 2021-04-06 17:32:27 +0000 - beta: revert rust-lang/cargo#8640 - rustdoc versioning checks (rust-lang/cargo#9332) - [beta] Fix publication of packages with metadata and resolver (rust-lang/cargo#9304)
…chton Some changes to rustdoc fingerprint checking. #8640 introduced a check which deletes the `doc` directory if cargo detects it has stale contents from a different toolchain version. Rustdoc has some shared files (js and css for example) that can get corrupted between versions. Unfortunately that caused some problems with rustbuild which does a few unusual things. Rustbuild will: * Create the `doc` directory before running `cargo doc` and places a `.stamp` file inside it. * Creates symlinks of the `doc` directory so that they can be shared across different target directories (in particular, between rustc and rustdoc). In order to address these issues, this PR does several things: * Adds `-Z skip-rustdoc-fingerprint` to disable the `doc` clearing behavior. * Don't delete the `doc` directory if the rustdoc fingerprint is missing. This is intended to help with the scenario where the user creates a `doc` directory ahead of time with pre-existing contents before the first build. The downside is that cargo will not be able to protect against switching from pre-1.53 to post-1.53. * Don't delete the `doc` directory itself (just its contents). This should help if the user created the `doc` directory as a symlink to somewhere else. * Don't delete hidden files in the `doc` directory. This isn't something that rustdoc creates. Only the `-Z` change is needed for rustbuild. The others I figured I'd include just to be on the safe side in case there are other users doing unusual things (and I had already written them thinking they would work for rustbuild). Hopefully the rustbuild `.stamp` mechanism will be enough protection there. Fixes #9336
- Fix clippy warnings - Fix MSRV task to use latest stable to install `cargo-sweep` Before, it would use the lower version to install, which broke when cargo-sweep updated its own MSRV. - Fix tests not to conflict with one another They were using the same target directory, which caused them to fail for some reason. I expect this is related to rust-lang/cargo#8640 somehow but it doesn't seem worth investigating.
- Fix clippy warnings - Fix MSRV task to use latest stable to install `cargo-sweep` Before, it would use the lower version to install, which broke when cargo-sweep updated its own MSRV. - Fix tests not to conflict with one another They were using the same target directory, which caused them to fail for some reason. I expect this is related to rust-lang/cargo#8640 somehow but it doesn't seem worth investigating.
- Fix clippy warnings - Fix MSRV task to use latest stable to install `cargo-sweep` Before, it would use the lower version to install, which broke when cargo-sweep updated its own MSRV. - Fix tests not to conflict with one another They were using the same target directory, which caused them to fail for some reason. I expect this is related to rust-lang/cargo#8640 somehow but it doesn't seem worth investigating.
Before compiling, we need to make sure that if there were any previous docs already compiled, they were compiled with the same Rustc version that we're currently using. Otherways we must remove the
doc/
folder and compile again.This is important because as stated in #8461 the .js/.html&.css files that are generated by Rustc don't have any versioning. Therefore, we can fall in weird bugs and behaviours if we mix different compiler versions of these js/.html&.css files.
Closes #8461