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

✨ Add preliminary python support #348

Merged
merged 11 commits into from
Oct 10, 2023

Conversation

JonahSussman
Copy link
Contributor

Big PR, hopefully I didn't break anything

- name: run demo image and ensure violations output unchanged
run: |
podman run -v $(pwd)/demo-output.yaml:/analyzer-lsp/output.yaml:Z localhost/testing:latest
git diff --exit-code demo-output.yaml
diff \
<(sort <(sed 's/incidents\.[0-9]\+/incidents\.x/g' <(yq -P 'sort_keys(..)' -o=props <(git show HEAD:demo-output.yaml)))) \
Copy link
Contributor

Choose a reason for hiding this comment

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

what sorcery is this?

Copy link
Contributor Author

@JonahSussman JonahSussman Sep 29, 2023

Choose a reason for hiding this comment

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

Since the incidents in a violation can be returned in any order, git diff kept failing. i.e. git diff would compare

sample-rule:
  incidents:
  - A
  - B
sample-rule:
  incidents:
  - B
  - A

and fail. This is because diff only compares the textual differences between the files. It has no knowledge of the YAML structure. To fix this, I installed yq which allows us to examine the actual structure of the input YAML. My whole goal was to still use diff to compare the two files, but make the position of each incident in the array irrelevant.

Moving from right to left, I first get the different versions of demo-output.yaml. I then pipe that into yq, with the -o=props flag . -P 'sort_keys(..)' is actually unnecessary due to what I do later. If we piped the YAML files I showed into that, it would return:

sample-rule.incidents.0 = A
sample-rule.incidents.1 = B
sample-rule.incidents.0 = B
sample-rule.incidents.1 = A

I then pipe that output into sed, replacing every incidents.<number> with incidents.x to erase which index each element is in. Finally, I sort the result and diff the two streams. Both files would return

sample-rule.incidents.x = A
sample-rule.incidents.x = B

Which is the same thing. No error, ta-da!

There might be a better way than cobbling together some shell commands for this. I wouldn't even be surprised if there was a way you could do all of this in yq! At least one of the advantages of having it installed is that we can investigate the actual structure of the YAML now in our tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

@JonahSussman lovely, I think this is a much better version of what we are doing in Kantra now, would love to copy it there

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 consider it a great honor, copy away! I would remove the -P 'sort_keys(..)' part as I'm almost positive it's redundant.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we sort these in the engine then?

Copy link
Member

@djzager djzager left a comment

Choose a reason for hiding this comment

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

This looks good, a few comments but I don't believe any of them are blockers.

I am curious though, after looking into our fallback symbol searching, if we could accept some funcs for the handling of some of the differences between different language servers. That may enable us to make the generic provider work down to the lowest common denominator and have specific examples for golang/pythong/typescript/etc on how to extend it to handle peculiarities between the different implementations.

client := generic.NewGenericProvider()

golangSC, err := client.Init(ctx, log, provider.InitConfig{
Location: "/home/jonah/Projects/analyzer-lsp/examples/golang",
Copy link
Member

Choose a reason for hiding this comment

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

This path doesn't look like one we'd want to commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, Eiher we remove this, or we make this more generic for testing.

I would think that removing for this PR and then coming back and making it easy to test w/ the generic provider makes sense to me. OR we make this a feature of kantra, and work on it from that the layer?

IDK just don't know if we want to change this particular main file yet but I could be wrong

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops, will fix! Is leaving in the mainDebug() function a problem as well? I just found all the stuff I put in there extremely useful when I was having problems.

func (p *genericServiceClient) GetAllSymbols(ctx context.Context, query string) []protocol.WorkspaceSymbol {
// Returns all symbols for the given query.
// NOTE: Only returns definitions when server does not supoprt workspace/symbol.
// Is is intended behavior?
Copy link
Member

Choose a reason for hiding this comment

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

For the .NET work, what made the most sense while experimenting was to:

  1. find occurrences of pattern
  2. call "textDocument/definition" and see if the response URI includes the referenced namespace (ie. System.Web.Mvc)...if it does then we add it as an incident.

And, iirc @fabianvf had mentioned gopls handling references differently which would mean that this is yet another area where differences in implementation may bite us. Makes me wonder if we want to make it possible to pass a callback of sorts that allows you to specify a function for determining if a found Symbol using the fallback method should be included as an incident.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I'm understanding right, you're saying the .NET work utilizes the fallback method? I added the note as if we use the fallback method, only the definitions will be returned, rather than every symbol like when using workspace/symbol. Honestly, I'm not quite seeing why we should do anything other than the fallback method?

Copy link
Member

Choose a reason for hiding this comment

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

I copy/pasted and then modified the fallback method for what I was doing with the .NET work. See here.

My thought was that it may be possible for us to create an exported method for our fallback that accepts a func for determining if a given symbol is the one the provider is looking for.

Copy link
Member

Choose a reason for hiding this comment

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

Looking more thoroughly at what I did, it may be best for us to have our fallback method as an exported function that simply returns a slice of positions...leaving it up to the caller on how to sort which of those positions are valid symbols or not.

@@ -0,0 +1,151 @@
package protocol
Copy link
Member

Choose a reason for hiding this comment

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

I am hopeful that we can move to https://github.com/go-language-server/protocol but I think that's an important-long-term type issue. Do we agree? I can writeup the issue later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Definitely something I want to investigate. Any way we can make it less brittle is a win in my book

Copy link
Contributor

@shawn-hurley shawn-hurley left a comment

Choose a reason for hiding this comment

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

More of slight clean ups and follow up issues that need to be created.

I do want to understand why we are exposing the ServiceClient. I thought that the interface should fully cover what anything else needed to do with it.

- name: run demo image and ensure violations output unchanged
run: |
podman run -v $(pwd)/demo-output.yaml:/analyzer-lsp/output.yaml:Z localhost/testing:latest
git diff --exit-code demo-output.yaml
diff \
<(sort <(sed 's/incidents\.[0-9]\+/incidents\.x/g' <(yq -P 'sort_keys(..)' -o=props <(git show HEAD:demo-output.yaml)))) \
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we sort these in the engine then?

@@ -21,6 +21,9 @@ FROM jaegertracing/all-in-one:latest AS jaeger-builder
# The unofficial base image w/ jdtls and gopls installed
FROM quay.io/konveyor/jdtls-server-base

RUN python3 -m ensurepip --upgrade
Copy link
Contributor

Choose a reason for hiding this comment

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

Note to selves, we need to eventually find a way to have these broken up and use some shared filesystem while running. Probably something for Kantra to figure out. Do we have an issue for this?

client := generic.NewGenericProvider()

golangSC, err := client.Init(ctx, log, provider.InitConfig{
Location: "/home/jonah/Projects/analyzer-lsp/examples/golang",
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, Eiher we remove this, or we make this more generic for testing.

I would think that removing for this PR and then coming back and making it easy to test w/ the generic provider makes sense to me. OR we make this a feature of kantra, and work on it from that the layer?

IDK just don't know if we want to change this particular main file yet but I could be wrong

rpc *jsonrpc2.Conn
cancelFunc context.CancelFunc
cmd *exec.Cmd
type GenericServiceClient struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why exporting the service client?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Had it for debugging stuff, changing it back


// 2-tiered table for each language and their respective fixes we may need to
// apply
var SubstitutionTable = map[string]map[string]string{
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add to the documentation for the specific python one why we need to substitute what? I can see the diff but am confused about the why.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add to the python-provider.md doc!

@@ -1,5 +1,17 @@
To update the Provider GRPC definition, update `library.proto` and run:
To install protoc, go to https://github.com/protocolbuffers/protobuf/releases
Copy link
Contributor

Choose a reason for hiding this comment

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

This will only work for Linux, I would recommend that we point to the install docs for protoc instead.

@@ -102,12 +102,25 @@ const (
type InitConfig struct {
// This is the location of the code base that the
// Provider will be responisble for parsing
// Deprecated: rootUri, which is what this maps to in the LSP spec, is deprecated.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you create issues in the repo for this and link in the deprecated or a TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done! #365

@JonahSussman
Copy link
Contributor Author

This looks good, a few comments but I don't believe any of them are blockers.

I am curious though, after looking into our fallback symbol searching, if we could accept some funcs for the handling of some of the differences between different language servers. That may enable us to make the generic provider work down to the lowest common denominator and have specific examples for golang/pythong/typescript/etc on how to extend it to handle peculiarities between the different implementations.

@djzager I really want to investigate a good way to do this. The vast majority of the functionality between different providers seems the same. Would love to have a discussion about what that looks like

Copy link
Contributor

@shawn-hurley shawn-hurley left a comment

Choose a reason for hiding this comment

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

nit's but the core is good

cancelFunc: cancelFunc,
cmd: cmd,
config: c,
Rpc: rpc,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: If changing, then it should be RPC

config: c,
Rpc: rpc,
CancelFunc: cancelFunc,
Cmd: cmd,
Copy link
Contributor

Choose a reason for hiding this comment

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

CMD as well

@@ -127,6 +139,9 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
h.Done(ctx, err)
}
}()

// fmt.Printf("Sending: %s\n", string(data))
Copy link
Contributor

Choose a reason for hiding this comment

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

lets remove this instead of commenting IMO

@JonahSussman JonahSussman merged commit b6195b3 into konveyor:main Oct 10, 2023
4 of 5 checks passed
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.

4 participants