Skip to content

Fix //test/rustfmt/... on Windows#872

Closed
minor-fixes wants to merge 9 commits intobazelbuild:mainfrom
minor-fixes:minor-fixes/619
Closed

Fix //test/rustfmt/... on Windows#872
minor-fixes wants to merge 9 commits intobazelbuild:mainfrom
minor-fixes:minor-fixes/619

Conversation

@minor-fixes
Copy link
Copy Markdown

This change aims to fix //test/rustfmt/... tests under Windows.

The root cause of test failures is, generally speaking, attempting to locate runfiles with logic that assumes directory-based runfiles, which is not available on Windows. This change attempts to find all files through the Runfiles utility object so that it can work cross-platform, adding helper methods where necessary to facilitate higher-level logic.

Fixes: #619

`test_main.rs` was looking for runfiles by getting a path to the
runfiles dir, and then walking the tree looking for files with a
particular extension. This does not work where runfiles are
manifest-based rather than directory-based, as is the case on Windows.

This change fixes the issue by growing a `list_files` method on the
`Runfiles` struct that higher-level code can use to enumerate all
the runfiles, filtering out the files they're looking for.

Since `find_runfiles_dir` was public purely for this one use case, it
can become private; likely higher-level code shouldn't be using this
function directly, but rather interacting with runfiles through a
Runfiles object.

Issues: bazelbuild#619
rustfmt_test should be finding its rustfmt binary and config via
runfiles, but it is finding them by naively joining the supplied path
with its current working directory. This works for directory-based
runfiles, but not manifest-based runfiles.

This change makes the discovery of rustfmt and the associated config
runfiles-aware.
This change passes the files under test to rustfmt with a path decoded
by runfiles, allowing it to work with manifest-based runfiles.
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jul 31, 2021

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@google-cla google-cla Bot added the cla: no label Jul 31, 2021
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jul 31, 2021

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@google-cla google-cla Bot added cla: yes and removed cla: no labels Jul 31, 2021
Comment thread tools/rustfmt/srcs/lib.rs
};
std::fs::metadata(&absolute_path).map(|_| absolute_path)
pub fn current_dir_name() -> PathBuf {
PathBuf::from(std::env::current_dir().unwrap().file_name().unwrap())
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General runfiles question:

Runfiles seem to be passed in/specified as e.g. external/rust_windows_x86_64/bin/rustfmt.exe, but sometimes (concretely, when using manifest-based runfiles) they're expected to be resolved with a workspace name prefix (rules_rust/external/rust_windows_x86_64/bin/rustfmt.exe, in this example, with a rules_rust prefix)

Where is that prefix supposed to come from? Is client code/the runfiles library supposed to assume the workspace name, or divine it somehow? This happens to coincide with the basename of the CWD for both runfiles implementations - hence this sketchy function here - but I'd like to better understand how runfiles are supposed to work r.e. this workspace prefix.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question. I don't think the prefix is expected to be passed anywhere. Bazel uses a launcher to set some environment variables dictating the locations of runfiles related paths. My experience is that bazel suggests paths to be treated as relative paths from the runfiles directory which is also suggested to be a relative path from the binary. I say "suggest" here since Bazel produces outputs this way but it's obviously up to the author to maintain this if the outputs are distributed in some way.

... This very likely doesn't answer your question. Maybe rephrase and I can try to be more direct 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread tools/rustfmt/srcs/lib.rs
Comment on lines +12 to +21
pub fn from_slash(p: PathBuf) -> PathBuf {
let s = p
.to_string_lossy()
.chars()
.map(|c| match c {
'/' => std::path::MAIN_SEPARATOR,
c => c,
})
.collect::<String>();
PathBuf::from(s)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially https://docs.rs/path-slash/0.1.4/src/path_slash/lib.rs.html#302; I would have also not liked to re-implement a directory walking function. Can this repo have third-party dependencies on these crates?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are ways to use 3rd party crates but for this particular tool I'd say it's not desirable since it'd require users to load the dependencies before the target can be used. Maybe there's an easy path forward there that I'm not thinking about but my current thought is that this target should remain free of 3rd party deps 😅

@minor-fixes minor-fixes marked this pull request as ready for review July 31, 2021 20:09
Copy link
Copy Markdown
Collaborator

@UebelAndre UebelAndre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, I like the changes here! 😄

From my end there's just one request for a test and I hope I was able to answer some of your questions.

Comment thread tools/rustfmt/srcs/lib.rs
Comment on lines +12 to +21
pub fn from_slash(p: PathBuf) -> PathBuf {
let s = p
.to_string_lossy()
.chars()
.map(|c| match c {
'/' => std::path::MAIN_SEPARATOR,
c => c,
})
.collect::<String>();
PathBuf::from(s)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are ways to use 3rd party crates but for this particular tool I'd say it's not desirable since it'd require users to load the dependencies before the target can be used. Maybe there's an easy path forward there that I'm not thinking about but my current thought is that this target should remain free of 3rd party deps 😅

Comment thread tools/rustfmt/srcs/lib.rs
};
std::fs::metadata(&absolute_path).map(|_| absolute_path)
pub fn current_dir_name() -> PathBuf {
PathBuf::from(std::env::current_dir().unwrap().file_name().unwrap())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question. I don't think the prefix is expected to be passed anywhere. Bazel uses a launcher to set some environment variables dictating the locations of runfiles related paths. My experience is that bazel suggests paths to be treated as relative paths from the runfiles directory which is also suggested to be a relative path from the binary. I say "suggest" here since Bazel produces outputs this way but it's obviously up to the author to maintain this if the outputs are distributed in some way.

... This very likely doesn't answer your question. Maybe rephrase and I can try to be more direct 😅

/// Does not return directories.
/// The returned path may not be valid. The caller should check the path's
/// validity and that the path exists.
pub fn list_files(&self) -> Vec<PathBuf> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be willing to add a test for this? And perhaps add a few more sample text files to //tools/runfiles/data to make the test a bit more interesting?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I actually would like to see if we could get away with not having this function at all. Other runfiles libraries didn't need it it seems (https://osscs.corp.google.com/bazel/bazel/+/master:tools/cpp/runfiles/runfiles_src.h, https://osscs.corp.google.com/bazel/bazel/+/master:tools/java/runfiles/Runfiles.java, https://osscs.corp.google.com/bazel/bazel/+/master:tools/bash/runfiles/runfiles.bash).

It seems the main motivation is to be able to find rustfmt manifests in the test data. Is there a reason why we cannot hardcode paths to manifests in the test?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless a unique binary is compiled for each use of the rustfmt test binary, there isn't really a way to hard code the values. I think it'd be more desirable to continue to use a shared binary and locate manifests in runfiles than to compile unique binaries but if there's a well defined pattern for runfiles libraries then I'd happily respect that. If there is though, I'd question whether or not the implementations for each language could live all in the same place.

@hlopko hlopko self-requested a review August 3, 2021 07:17
@UebelAndre
Copy link
Copy Markdown
Collaborator

Hey, friendly ping on this PR 😄

Let me know if I can do something to help!

@UebelAndre
Copy link
Copy Markdown
Collaborator

Closing out in favor of #1375

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable //test/rustfmt on the Windows CI

3 participants