Skip to content

Extend config option similar to package.json prettier field #5313

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

Open
ZelCloud opened this issue Apr 16, 2022 · 7 comments
Open

Extend config option similar to package.json prettier field #5313

ZelCloud opened this issue Apr 16, 2022 · 7 comments

Comments

@ZelCloud
Copy link

Request

Could we get a field to specify a rustfmt.toml configuration either within cargo.toml or rustfmt.toml

example:

#cargo.toml

rustfmt-extends = { git = "https://github.com/some-global-rustfmt-config", branch = "main" }

Rational

I'm working on multiple backend micro-services in rust. In every single repo I'd like to have the exact same styling / formatting. Currently I'm copying over the rustfmt.toml file to each repo and if there's a configuration change I or someone else on my team makes we end up copying over the new file to all the repos. Ideally it would be nice if we could just point to a github repo and a rustfmt.toml and have cargo pull it down and rustfmt use it.

This is similar to what formatters like prettier allow for frontend repos. (ex. npm i some-prettier-config)

@calebcartwright
Copy link
Member

Thanks for reaching out, though to be honest there's far too much going on in the issue description to really be able to have any focused discussions.

If I understand you correctly, your desired outcome is the ability to have some kind of shared or centralized configuration specification. What becomes increasingly unclear though is whether the approaches you enumerated are proposed solutions for that outcome or whether those are additional specific features/behaviors you'd like.

I'll go ahead and state up front that I'm not willing to incorporate features into rustfmt that will have it try to fetch some static file over http on every run as part of resolving some remote configuration. I've used shared config modules for prettier in JS/TS land, but to the best of my knowledge it strictly operates via importing local modules that happen to have been resolved by npm. I've never seen prettier itself support dynamically fetching configs from somewhere else.

Although outside the realm of rustfmt, I suppose it would technically be possible for you to create and package a crate that's configured to include a rustfmt config file that you'd publish to crates.io and then consume as a dependency (or more likely dev dependency) of your applications in order to retrieve/propagate the file onto the file systems of your respective developers. However, I still think there would be real challenges deriving a way rustfmt could deterministically locate that local file.

rustfmt is quite deliberately not cargo aware and must be able to run independently of any cargo context. That means that in order for anything to be feasible, rustfmt would need to be able to look at some rustfmt.toml config file and be able to use the information in that file to locate the "shared" file locally on any user's machine.

I'm open to considering a solution to this if someone can come up with one, but this isn't something the rustfmt team will have bandwidth to pursue ourselves.

In the interim, since it sounds like you've also gone with the poly-repo approach for your microservices, you could consider defining your rustfmt config file in its own repo, and then add that repo as a submodule (or subtree if you prefer) in all of your other repos. Then you'd be able to have your config encapsulated in one place, and only need to change your invocations (task runners, ide configs, etc.) to include the --config-path rustfmt cli option and have it point to whatever the corresponding path would be for your submodule that contains the shared config file

@ZelCloud
Copy link
Author

Thanks for reaching out, though to be honest there's far too much going on in the issue description to really be able to have any focused discussions.

I'm sorry if this seemed to broad, I'll try to narrow it down into more specifics in the following paragraphs.

If I understand you correctly, your desired outcome is the ability to have some kind of shared or centralized configuration specification. What becomes increasingly unclear though is whether the approaches you enumerated are proposed solutions for that outcome or whether those are additional specific features/behaviors you'd like.

Those were just general proposed suggestions for an outcome. I'll explain the feature request in the next block.

I'll go ahead and state up front that I'm not willing to incorporate features into rustfmt that will have it try to fetch some static file over http on every run as part of resolving some remote configuration. I've used shared config modules for prettier in JS/TS land, but to the best of my knowledge it strictly operates via importing local modules that happen to have been resolved by npm. I've never seen prettier itself support dynamically fetching configs from somewhere else.

That's fine I don't think its needed for rustfmt itself to fetch any files, For my needs just having a field like:

# rustfmt.toml

# made up field name 
uses-config-at-location = "{{project-crates}}/my-config/rustfmt.toml"

Although outside the realm of rustfmt, I suppose it would technically be possible for you to create and package a crate that's configured to include a rustfmt config file that you'd publish to crates.io and then consume as a dependency (or more likely dev dependency) of your applications in order to retrieve/propagate the file onto the file systems of your respective developers. However, I still think there would be real challenges deriving a way rustfmt could deterministically locate that local file.

This actually seems fine to me, and I don't think rustfmt needs to automatically locate the shared configuration toml or anything. Like I wrote in the block above I'm fine with pulling the crate (with a rustfmt.toml) and explicitly putting the path in the main rustfmt.toml in the root of the project.

rustfmt is quite deliberately not cargo aware and must be able to run independently of any cargo context. That means that in order for anything to be feasible, rustfmt would need to be able to look at some rustfmt.toml config file and be able to use the information in that file to locate the "shared" file locally on any user's machine.

This is completely fine with me.

In the interim, since it sounds like you've also gone with the poly-repo approach for your microservices, you could consider defining your rustfmt config file in its own repo, and then add that repo as a submodule (or subtree if you prefer) in all of your other repos. Then you'd be able to have your config encapsulated in one place, and only need to change your invocations (task runners, ide configs, etc.) to include the --config-path rustfmt cli option and have it point to whatever the corresponding path would be for your submodule that contains the shared config file

We have considered doing the submodule approach, and we decided against it. Too much hassle and possible issues.

So to summarize everything. All I'd like for the rustfmt.toml is to have a way to specify the location of another locally existing config. I'm fine with the approach of creating an empty crate and pulling it with cargo. Would this be reasonable?

@calebcartwright
Copy link
Member

So to summarize everything. All I'd like for the rustfmt.toml is to have a way to specify the location of another locally existing config. I'm fine with the approach of creating an empty crate and pulling it with cargo. Would this be reasonable?

Thanks for confirming, but what I said previously still holds and remains unanswered 👇

That means that in order for anything to be feasible, rustfmt would need to be able to look at some rustfmt.toml config file and be able to use the information in that file to locate the "shared" file locally on any user's machine.

And that ☝️ can't just be solved with an abstract "{{project-crates}}" token.

There's a lot of differences in the way cargo and npm manage dependencies, and the crate-based proposal is a hack in the sense that's just being used as a piggyback way to get the file onto the system as part of the crate sources. There is no project-local node_modules directory equivalent, nor a singular system/user global directory that could be easily checked either. As such I don't see a straightforward way for rustfmt to know cargo-specific things, like whether the crate was a registry or git reference, what version to use, whether the dep was patched, etc. All of those data points would be required elements necessary to be able to locate the associated sources, and thus the config file, on a given file system.

@ZelCloud
Copy link
Author

ZelCloud commented Apr 16, 2022

I didn't mean for the {{project-crates}} to be a token for rustfmt to use, I was using it as a placeholder for the example project and the path to where the crates are located.

example structure

directory structure

myprojet (project root)
-rustfmt.toml -- 1
- target
- - debug
- - - deps
- - - - my-config
- - - - - rustfmt.toml -- 2
# rustfmt.toml -- 1

uses-config-at-location = "./target/debug/deps/my-config/rustfmt.toml" # 2

# using the actual explicit path from the project root to where ever the additional toml file is located 
# rustfmt doesn't need to figure out the path we'll explicitly provide it

No token substitution or rustfmt trying to figure out anything on its own. We explicitly put the path from root to the toml file where ever it ends up being located in.

@calebcartwright
Copy link
Member

Please feel free to correct me, but I'm pretty sure that sources for external crates don't get copied into the project target directories. I.e. your target/deps/my-config/... isn't going to exist. Your target directory will contain compilation output, not source input.

I'd like to avoid repeating things already said above for the sake of not making this thread any longer, but this remains the crux of the problem with the proposed hack.

@ZelCloud
Copy link
Author

I was mistaken then, feel free to close the issue.

@calebcartwright
Copy link
Member

calebcartwright commented Apr 17, 2022

No worries! I'll leave it open for a bit on the off chance someone can come up with something, as it would be a nifty feature.

For anyone looking to dig into this, the bundled toml config file with the crate would typically (though certainly not always) be somewhere like ~/.cargo/registry/src/github.com-gobeltygook/your-crate-name-majorversion-minorversion-patchversion/shared-rustfmt-config.toml

but with plenty of opportunities for variance (users can change their cargo home directory, dependencies that are git based would be under the git directory tree instead of registry, there can be multiple source directories that start with github.com-, there can be other source providers, etc.)

The only thing I could envisage would require users to essentially duplicate what's specified in their cargo manifest, but even then rustfmt would still likely need to do some scanning and probing. I probably wouldn't be too keen on going down that path, both because of the poor user ergonomics and because it seems like it'd start to get messy from an implementation perspective as well

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

No branches or pull requests

3 participants