Skip to content
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

Improve deleting a src file UX #24

Merged
merged 19 commits into from
Apr 29, 2022
Merged

Improve deleting a src file UX #24

merged 19 commits into from
Apr 29, 2022

Conversation

googleson78
Copy link
Contributor

Fixes #22


func cleanupHiddenModulesList(r *rule.Rule, ruleNameSet map[string]bool) {
ruleName := r.Name()
// TODO: use something better?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if this isn't already implemented somewhere around here, but I didn't find it.

f.Sync()
}

func cleanupModulesList(r *rule.Rule, ruleNameSet map[string]bool) {
// TODO: use labels instead of manually stripping away the ':' ?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a better way to do this?

@googleson78
Copy link
Contributor Author

googleson78 commented Apr 14, 2022

TODO: add fix invocation to CI

EDIT: done, I think

We need to not crash early on missing files, so that fix can handle them
later.
This has two results
* we don't crash when a src for a haskell_module is missing
* the haskell_module is deleted in Fix, since we no longer get the data
  in ruleInfos
When a module is deleted it's still referenced in the modules attribute
of a rule. Here we manually remove it.
This is to be used for hidden_modules too. Also delete the list if it's
left empty after deletion.
In there, running fix is required to get it to build.

main :: IO ()
main = do
haskellSrcs <- lines <$> getContents
mapM scanImportsFromFile haskellSrcs >>= printImports
-- silently ignore missing files
-- TODO: it would be better to instead report them to the user
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would do this here, but I would need to alter the JSON format with which go and hs communicate, so I'd prefer this to be done in a separate PR.

Copy link
Member

@facundominguez facundominguez left a comment

Choose a reason for hiding this comment

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

Thanks @googleson78!

Very nice breakdown of commits.

I added some comments. The PR is already in pretty good shape though.

gazelle_haskell_modules/rule_generation.go Outdated Show resolved Hide resolved
OriginatingRules: oRules,
ModuleData: modDatas[0],
}
if len(modDatas) == 1 {
Copy link
Member

Choose a reason for hiding this comment

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

The weakest condition to run the then branch is len(modDatas) > 0. Maybe this if statement can be simplified to

    if len(modDatas) > 0 { ... } else { log.Printf(...) }

Copy link
Member

Choose a reason for hiding this comment

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

I implemented this in b2f66f2

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I wonder if we should (in another issue perhaps) change the logic here to error if we receive len(modData) > 1, as an assert, since it shouldn't be possible?

Copy link
Member

Choose a reason for hiding this comment

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

I'd be fine with such a change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll open an issue after we merge this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#28

nonDeletedModules := make([]string, 0, len(modules))
for _, module := range modules {
// TODO: use labels instead of manually stripping away the ':' ?
if ruleNameSet[module[1:]] {
Copy link
Member

@facundominguez facundominguez Apr 28, 2022

Choose a reason for hiding this comment

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

It is a bit dangerous to assume that the first character of the label is a colon. The user might try to add modules manually here, and we can't make assumptions about those. It is best to check explicitly that module[1] == ':' and keep the label if it has a different character.

module[1] != byte(':') || ruleNameSet[module[1:]]

Copy link
Member

Choose a reason for hiding this comment

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

In the latest version of the code perhaps something like this would do:

-       stripColon := func(module string) string { return module[1:] }
+       stripColon := func(module string) string {
+               if strings.HasPrefix(module, ":") {
+                       return module[1:]
+               } else {
+                       return module
+               }
+       }

Copy link
Member

Choose a reason for hiding this comment

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

I tried a fix in 8e5ab77

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I think that right now (and before the patch too), if a user writes a fully qualified bazel target in modules, it will get deleted, regardless of whether the module exists or not, because ruleNameSet won't have the fully qualified module name.

So there probably needs to be something more complex here - either store full target names in ruleNameSet, or do a more complex check here.

I think the fully qualified names might be a better solution, as this string manipulation stuff feels very brittle both here and for hidden_modules :/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

8e5ab77

Seems to have broken CI - need to investigate.

Copy link
Member

Choose a reason for hiding this comment

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

I think the fully qualified names might be a better solution, as this string manipulation stuff feels very brittle both here and for hidden_modules :/

A question that helps determining the severity of issues in general is: what the best workaround is?
In light of this question, you are correct that absolute labels in modules can confuse the fix command, but it is also easy for the user to make the labels relative instead, and relative labels are the most economical to use anyway. So it is unlikely to be a barrier for adoption.

Copy link
Member

Choose a reason for hiding this comment

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

Seems to have broken CI - need to investigate.

Mea culpa 🙈
Fixed in efae1e7

Copy link
Member

@facundominguez facundominguez Apr 29, 2022

Choose a reason for hiding this comment

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

And still I was dropping non-relative labels. I tried another fix in 2614494.

OriginatingRules: oRules,
ModuleData: modDatas[0],
}
if len(modDatas) == 1 {
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps for another PR: if the rule is marked with a # keep comment, probably it shouldn't be discarded here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll open an issue after this PR is merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#29

func fixHiddenModulesList(r *rule.Rule, ruleNameSet map[string]bool) {
ruleName := r.Name()
// TODO: use something better?
addPackageName := func(module string) string { return fmt.Sprintf(":%s.%s", ruleName, module) }
Copy link
Member

Choose a reason for hiding this comment

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

IIUC, you want to drop the colon from the output.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, even fixing the above, this implementation is deleting all modules from hidden_modules which don't have a haskell_module rule in the same BUILD file.

Also, if a haskell_module rule is used in more than one library, this implementation will also delete the hidden module in one of them even if the haskell_rule hasn't been removed.

Perhaps we can improve both things in a later PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean by "output"? I'm adding this here so it matches the format in ruleNameSet. It seems a bit brittle though - is there some way to make it better?

Copy link
Member

Choose a reason for hiding this comment

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

I stripped the colon in 5496a59.

Copy link
Member

@facundominguez facundominguez Apr 29, 2022

Choose a reason for hiding this comment

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

What do you mean by "output"? I'm adding this here so it matches the format in ruleNameSet. It seems a bit brittle though - is there some way to make it better?

Let me know if 5496a59 doesn't clarify these questions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not really sure why it works both with and without the colon (this code is out of cache right now 😅 ) but I trust your judgement :)

Copy link
Member

Choose a reason for hiding this comment

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

A first short answer is that ruleNameSet doesn't include the leading :, so it needs to be removed. Though note that the code has evolved since this conversation. Happy to engage with more details if needed.

gazelle_haskell_modules/lang.go Outdated Show resolved Hide resolved
gazelle_haskell_modules/lang.go Show resolved Hide resolved
example/fix-cleanup-modules/BUILD.bazel Show resolved Hide resolved
@facundominguez
Copy link
Member

@googleson78, are there any other changes that you would like to have related to this PR?

@facundominguez facundominguez merged commit 51bb487 into main Apr 29, 2022
@facundominguez facundominguez deleted the fix-deleted-file branch April 29, 2022 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve the experience of deleting a source file
2 participants