-
Notifications
You must be signed in to change notification settings - Fork 908
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
Attempt at checking for license (#209) #2456
Conversation
Thank you for your PR! I think we can have two config options for like we do in |
Great, thanks for the tips! I'll see what I can do and report back :) And I'll also change the license template parsing code so that it can handle nested |
Done, but the approach is slightly different from the case of |
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 a really great PR, thank you! I think the way of handling the options for paths/templates works pretty well. I did have a few other comments in the code, but mostly looks good.
rustfmt-config/src/config_type.rs
Outdated
}; | ||
let mut license_template_str = String::new(); | ||
match license_template_file.read_to_string(&mut license_template_str) { | ||
Ok(_) => (), |
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.
you could use if let Err(e) = ...
rather than match
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.
Thanks, of course, done :)
rustfmt-config/src/config_type.rs
Outdated
@@ -365,12 +373,50 @@ macro_rules! create_config { | |||
self.set().width_heuristics(WidthHeuristics::null()); | |||
} | |||
} | |||
|
|||
fn set_license_template(&mut self) { | |||
let license_template_path = self.license_template_path(); |
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.
Are you accounting for a possibly empty license_template_path somewhere?
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.
No, well-spotted! I didn't realize calling rustfmt with no config file is not quite the same as calling with a config file which doesn't specify the license_template_path
, so it didn't bite me when trying to run 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.
done
rustfmt-config/src/config_type.rs
Outdated
return; | ||
} | ||
} | ||
} |
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 function would look nicer if you create a LicenseError enum with a display method for the messages and use the ?
operator.
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 it's ugly, I just thought I'd do the error handling here and avoid clutter at the call sites :) If I use ?
, how far up should I let the errors bubble? set_license_template()
is called by functions which return unit, I suppose I should just pattern match there and let potential errors print?
rustfmt-config/src/lib.rs
Outdated
/// " | ||
/// ); | ||
/// ``` | ||
pub fn parse_license_template(template: &str) -> Result<String, 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.
this function should be in a submodule
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.
done
rustfmt-config/src/lib.rs
Outdated
let mut parsed = String::from("^"); | ||
let mut buffer = String::new(); | ||
let mut state = State::Lit; | ||
let mut linum = 1; |
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 kind of code usually works better if you factor the fields into a struct and make each state a method on the struct.
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've been trying to figure out how to split that slab of code into smaller pieces, that giant match expression looks daunting. My initial thought was that there must be a way to impl
enum variants, so that state transitions can be neatly divided by state of origin, but it turns out there isn't :) Then I read this, which was very informative but felt slightly overkill. Maybe not after all, I'll see what I can do.
@nrc Thank you very much for the feedback! I'll take a look at the issues and try to resolve them :) |
@nrc OK, I think I've at least attempted to address all the issues you've raised :)
Let me know if that works, or if you have different ideas about some / all of it! |
I ended up getting rid of the closure in |
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.
Looks great, thanks, r+ However, it needs another rebase, sorry. I hope it is just renaming some files since we had to revert the workspaces changes.
I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see rust-lang/rust#44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
This allows occurrences of `{` and `}` within `{}` placeholders in the template, and also for having literal `{` and `}` in the template by means of escaping (`\{`). Unbalanced, unescaped `}` at the toplevel is a syntax error which currently triggers a panic; I'll add proper error handling as I move the license template parsing code into the config parsing phase.
Don't attempt to load license_template if the path wasn't specified.
This also splits the giant state machine match expression into separate methods.
Get rid of the unncessary closure.
2d7dbc1
to
01f6527
Compare
Rebased :) Although maybe I should just remove the doctest for |
Thanks! I merged so you don't have to rebase again, but I think it is worth trying to get the doc test running - does something bad happen if we enable doctest in Cargo.toml? If not, we should just do that. |
Sorry, I had a busy two days :) The doctests fail with the following output:
I'll see if I can figure out how to fix it. |
Doctests were disabled globally because up until rust-lang#2456, they were just formatting examples which were not supposed to compile. Now that there is one runnable doctest, I disabled the other ones individually (by adding the ignore directive). I also added some empty lines around the code blocks to avoid the following warning and instead ignore the code blocks cleanly: WARNING: ... Code block is not currently run as a test, but will in future versions of rustdoc. Please ensure this code block is a runnable test, or use the `ignore` directive. See rust-lang/rust#28712 for further details.
Turns out it was trivial (#2529) :) |
I'm not quite sure how best to handle loading the license template from
a path -- I mean obviously I know how to do it, but I'm not sure where
to fit it in the codebase :) So this first attempt puts the license
template directly into the config file.
These are my misgivings about the license template config option as a
path to a file (I'd love feedback if some of these are wrong or can be
easily circumvented!):
I thought the obvious choice for the type of
license_template
increate_config!
should bePathBuf
, butPathBuf
doesn't implementFromStr
(yet? see Path & PathBuf missing FromStr trait rust#44431), soit would have to be wrapped in a tuple struct, and I went down that road
for a little while but then it seemed like too much ceremony for too
little gain.
So a plain
String
then (which, mind you, also means the samedoc_hint()
, i.e.<string>
, not<path>
or something like that). Thefact that it's a valid path will be checked once we try to read the
file.
But where in the code should the license template be read? The
obvious choice for me would be somewhere in
Config::from_toml()
, butsince
Config
is defined via thecreate_config!
macro, that wouldmean tight coupling between the macro invocation (which defines the
configuration option
license_template
) and its definition (which wouldrely on the existence of that option to run the template loading code).
license_template
could also be made a special option which ishardwired into the macro. This gets rid of the tight coupling, but
special-casing one of the config options would make the code harder to
navigate.
Instead, the macro could maybe be rewritten to allow for config
options that load additional resources from files when the config is
being parsed, but that's beyond my skill level I'm afraid (and probably
overengineering the problem if it's only ever going to be used for this
one option).
Finally, the file can be loaded at some later point in time, e.g. in
format_lines()
, right beforecheck_license()
is called. But toface a potential IO error at so late a stage, when the source files
have already been parsed... I don't know, it doesn't feel right.
BTW I don't like that I'm actually parsing the license template as late
as inside
check_license()
either, but for much the same reasons, Idon't know where else to put it. If the
Config
were hand-rolledinstead of a macro, I'd just define a custom
license_template
optionand load and parse the template in the
Config
's init. But the waythings are, I'm a bit at a loss.
However, if someone more familiar with the project would kindly provide
a few hints as to how the path approach can be done in a way that is as
clean as possible in the context of the codebase, I'll be more than
happy to implement it! :)