-
Notifications
You must be signed in to change notification settings - Fork 42
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
The need to have the DSL at runtime breaks multi-module repos #253
Comments
Are you using ruleguard binary directly or via the golangci-lint? There is an issue that golagnci-lint makes ruleguard load rule file again and again for every package being checked. This will be fixed in future from the either side, but I'm not 100% sure which side it will be right now. For now, it creates both performance and potential It's hard to have it "linked" into the binary as we use normal There is a WIP to make embedding easier, so we can generate the code from the rule file so we don't have to parse/typecheck it ever again apart from the moment when we generate the code. But that would make it impossible to modify the rules without the binary recompilation. Depending on what you want to accomplish, it may or may not solve your issue.
I don't know how to provide these precompiled binaries for the users though. I can ship a separate binary that can build these analyzers into a binary if it sounds alright. Note that for projects as big as k8s I wouldn't expect a tool to work perfectly well without some amount of hacking. It's interesting to hear about the issues though (like memory consumption, etc). As a last resort, there is always a way to write your own main file that runs ruleguard in a way you would like it to behave. Strictly speaking, it doesn't need the |
tl;dr: there is an option of making a binary that embeds all rules. It will introduce an extra step in the deployment scheme (one needs to build a binary themselves) plus it makes the rules less dynamic (you can't edit them and see the changes right away, but, at the same time, you don't need rules file artifact during the deployment anymore). |
Another way would be a conservative usage where you only run a linter on the parts of the k8s project that are well-suited for it, skipping the harder bits. |
We are using it through gocritic, through golangci-lint (though IMO it
should be a first-order linter in golangci-lint) .
I was thinking about using embedding for the dsl library, too. What I
don't want to do is build custom tools and binaries. We just get stuck
maintaining these forever. Maybe I should up-level and describe the
user-story I think we're missing:
Story 1:
I create a rules.go file. I edit my golangci-lint config to enable
ruleguard. I run golangci-lint and ruleguard runs. I did not have to
depend on or even be aware of the DSL library - that's not my job.
Alternately, I run a ruleguard binary and bypass gocritic and golangci-lint.
Story 2:
I write a rules.go file. I run a docker image (either golangci-lint or a
ruleguard image) and mount my rules.go at a known path, and ruleguard
runs. That's all.
It's my intuition that most users of ruleguard don't need to change the DSL
- we just want a tool that works without jumping through hoops.
…On Sun, Aug 22, 2021 at 3:54 AM Iskander (Alex) Sharipov < ***@***.***> wrote:
Another way would be a conservative usage where you only run a linter on
the parts of the k8s project that are well-suited for it, skipping the
harder bits.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#253 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABKWAVFPBHPD5NKGQ3JEXRLT6DJPPANCNFSM5CSDHVPQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
Or if I am going to use ruleguard directly, maybe a flag that points to the DSL lib (ignoring modules)? |
Coming back to this, I have set up a trivial demonstration of the problem(s): https://github.com/thockin/ruleguard-multi-modules There are errors in both
but
I know this is a problem with Go's own handling of multi-repo. Try the usual workaround:
No output.
It found the config, but not the rules file. But it didn't complain in any way, making me thing it actually passed, when it didn't. If I then hack go-critic to find the file, it STILL fails the same way - iternally go-critic gets (and golangci-lint swallows the logs) |
tl;dr: I don't have a concrete solution for that yet. I see the problem, but it's a combination of both design choices and A side note: golangci-lint upgraded go-critic to DSL package is needed to:
I tried to embed DSL sources in binary but then Go typechecking would fail due to the ways it works. It takes more research to know how we can circumvent that. I tried for a long time, with different approaches. I don't have any more spare mental powers to come back to this in the near future. It's one of the most frustrating things I worked on, this import/dependency thing. For the purposes of go-critic we solved it with precompilation, so I thought that if it's an explicit Go-like artifact, it's OK to have it as a direct Go dependency. So unlike some other tools that are not deeply integrated into Go, we have something that works like a first-class citizen. Rules are (almost) Go code after all. You're using Note that it's not necessary to copy/paste all rules from other sources. It's possible to use rules importing: Lines 1 to 10 in 028d651
|
I sounds like the piece I was missing was that this uses Go's libs internally and the shortcomings in those libs become shortcomings of this tool. Is that right? |
I believe that's the case at least partially, yes. |
I got a new starting point on this, but you might not like it. It seems that ruleguard uses E.g. if I said But first it would have to switch to the new lib. I found it easy to do in one of my own tools, but ruleguard is more complex than mine :) |
I was looking towards using This "foo is not foo" issue forced me to forget about using embedded dsl package sources. (There should be a commit somewhere which removes embedded dsl, with some explanations hopefully.) Maybe there is a way to circumwent that. Or maybe it's also possible to add some I'm afraid that what ruleguard does is too unusual and this is why we're facing some unpleasant limitations and issues. That being said, I'm interested in solving the issue. |
OK. How about a MUCH dirtier trick? I just PoC'ed this with a forced failure, and no dep on the dsl in my codebase.
This makes a temp dir, initializes a dummy module, and deps on the DSL code. It parses my rules file from that dir, which lets go tooling resolve the DSL code. Then it changes back to the original dir to use the now-loaded DSL code on my to-be-checked code. Obviously I did no error checking, but it works - it finds the forced error in my code. I don't know what the best way to inject the DSL files would be. This works but depends on the latest tagged version. Ideally you would do something like:
Maybe move the DSL to a different repo so I could say something like What do you think overall? Should I have my Go license revoked? |
Ahahah. Definitely not.
Ideally, some dsl package would be embedded, as you mentioned, so there is a default version (latest release) available even without I could try creating this embedded dsl experiment branch so it's easier to show and explain. |
You would have to "emit" the embedded files into a form that Go thinks they
are real - either as a vendor'ed module or as "local" code (and replace the
imports on the fly?)
This PoC is dirty but it works because it just tries to meet
Go's expectations. We don't need the rules.go and the code-to-be-checked
in the same parse universe.
|
Ooof. I really hoped that it would be possible to avoid doing some write-like fs operations. |
Some wild ideas inspired by @storozhukBM.
|
This exact issue blocks us from introdusing custom Since this issues is a couple years old now, I wonder if there is already a well-known path overcome the problem? |
When Go libraries like Since DSL is Go and it uses the definitions from some package, that package needs to be available during the analysis. It is possible to avoid typechecking the DSL code at the expense of parsing gibberish and then have no any real error message that would tell you what went wrong. I wanted to make these files a proper Go code where you can't pass string as int and so on. It's not a practical thing for me to re-invent a typechecker just for that in my opinion. This issue is way more complicated than I can swallow with ~zero rewards for this project. I moved forward to some other things that at least give me something back (and I'm not talking about the money). The Go team doesn't care about projects like ruleguard and its nature is quite alien to the way Go packages like I could solve this issue if I has like 1-2 months dedicated to make it work. Unless someone can help me out, I'm afraid this issue can stay there forever. |
In other words, if this issue is just about the users of the tool being confused due to an extra dependency in their So, unless the issue is a blocker for the intended usage of this tool (the things I can actually test for and handle with my own hands), it's a no. |
Maybe https://go.googlesource.com/proposal/+/refs/changes/55/495555/5/design/48429-go-tool-modules.md could make some things easier if we can make dsl to be a part of "tool" dependencies. |
I admit that Kubernetes is not exactly "normal" in its repo setup, but it is VALID.
We have one repo with multiple go modules in various directories, but we treat it as a single codebase for the purpose of things like lint. It seems that github.com/quasilyte/go-ruleguard/dsl has to be a dependency of every module. It would be VASTLY simpler to just have it linked into the binary.
Is there a better answer?
The text was updated successfully, but these errors were encountered: