Skip to content

Commit

Permalink
Merge branch 'main' into fix/pip-matching-fingerprint
Browse files Browse the repository at this point in the history
  • Loading branch information
DariusZdroba authored Jan 20, 2025
2 parents ead1bee + 007da85 commit 7ef4967
Show file tree
Hide file tree
Showing 22 changed files with 668 additions and 178 deletions.
43 changes: 32 additions & 11 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,34 @@

package ast

import "fmt"

type Node struct {
Line int
StartChar int
EndChar int
DocOffset int64
Parent *Node
Children []*Node
Name string
Value string
Attributes map[string]string
Line int
StartChar int
EndChar int
DocOffset int64
Parent *Node
Children []*Node
Name string
Value string
Attributes map[string]string
Tree *Tree
LinkedParentDependencyNode *Node
}

type Tree struct {
Root *Node
Document string
ParentTree *Tree
Root *Node
Document string
}

func (t *Tree) String() string {
return fmt.Sprintf("Root=%s, Document=%s, ParentTree=%s", t.Root, t.Document, t.ParentTree)
}

func (t *Tree) DebugString() string {
return t.String()
}

type Parser interface {
Expand All @@ -45,6 +58,14 @@ func (n *Node) Accept(v Visitor) {
v.visit(n)
}

func (n *Node) String() string {
return fmt.Sprintf("Name=%s, Value=%s, Position=%d:%d:%d, Tree=%s, Parent=%s, LinkedParentDependencyNode=%s", n.Name, n.Value, n.Line, n.StartChar, n.EndChar, n.Tree, n.Parent, n.LinkedParentDependencyNode)
}

func (n *Node) DebugString() string {
return fmt.Sprintf("%s, DocOffset: %d, ChildrenCount: %d", n.String(), n.DocOffset, len(n.Children))
}

func (n *Node) Add(child *Node) *Node {
n.Children = append(n.Children, child)
child.Parent = n
Expand Down
101 changes: 80 additions & 21 deletions ast/maven/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,31 @@ import (
"encoding/xml"
"errors"
"io"
"os"
"path/filepath"
"strings"

"github.com/snyk/snyk-ls/application/config"
"github.com/snyk/snyk-ls/ast"
)

type Parser struct {
tree ast.Tree
config *config.Config
}

type dependency struct {
type Parent struct {
Group string `xml:"group"`
ArtifactId string `xml:"artifactId"`
Version string `xml:"version"`
RelativePath string `xml:"relativePath"`
}

type Dependency struct {
Group string `xml:"group"`
ArtifactId string `xml:"artifactId"`
Version string `xml:"version"`
Scope string `xml:"scope"`
Type string `xml:"type"`
}

func New(c *config.Config) Parser {
Expand All @@ -44,10 +53,11 @@ func New(c *config.Config) Parser {
}
}

func (p *Parser) Parse(content string, path string) ast.Tree {
func (p *Parser) Parse(content string, path string) *ast.Tree {
tree := p.initTree(path, content)
d := xml.NewDecoder(strings.NewReader(content))
var offset int64
pomDir := filepath.Dir(path)
for {
token, err := d.Token()
offset = d.InputOffset()
Expand All @@ -61,21 +71,56 @@ func (p *Parser) Parse(content string, path string) ast.Tree {
switch xmlType := token.(type) {
case xml.StartElement:
if xmlType.Name.Local == "dependency" {
var dep dependency
var dep Dependency
if err = d.DecodeElement(&dep, &xmlType); err != nil {
p.config.Logger().Err(err).Msg("Couldn't decode dependency")
p.config.Logger().Err(err).Msg("Couldn't decode Dependency")
continue
}

if strings.ToLower(dep.Type) == "bom" {
addDepsFromBOM(path, tree, dep)
}

offsetAfter := d.InputOffset()
node := p.addNewNodeTo(tree.Root, offset, offsetAfter, dep)
p.config.Logger().Debug().Interface("nodeName", node.Name).Str("path", p.tree.Document).Msg("Added dependency node")
p.config.Logger().Debug().Interface("nodeName", node.Name).Str("path", tree.Document).Msg("Added Dependency node")
}
if xmlType.Name.Local == "parent" {
// parse Parent pom
var parentPOM Parent
if err = d.DecodeElement(&parentPOM, &xmlType); err != nil {
p.config.Logger().Err(err).Msg("Couldn't decode Parent")
continue
}

if parentPOM.RelativePath == "" {
parentPOM.RelativePath = filepath.Join("..", "pom.xml")
}

parentAbsPath, err := filepath.Abs(filepath.Join(pomDir, parentPOM.RelativePath))
if err != nil {
p.config.Logger().Err(err).Msg("Couldn't resolve Parent path")
continue
}
content, err := os.ReadFile(parentAbsPath)
if err != nil {
p.config.Logger().Err(err).Msg("Couldn't read Parent file")
continue
}
parentTree := p.Parse(string(content), parentAbsPath)
tree.ParentTree = parentTree
}
default:
}
}
return tree
}

func (p *Parser) initTree(path string, content string) ast.Tree {
func addDepsFromBOM(path string, tree *ast.Tree, dep Dependency) {
// todo retrieve, potentially from configured repos (not parsed yet)
}

func (p *Parser) initTree(path string, content string) *ast.Tree {
var currentLine = 0
root := ast.Node{
Line: currentLine,
Expand All @@ -87,35 +132,49 @@ func (p *Parser) initTree(path string, content string) ast.Tree {
Name: path,
Value: content,
}
p.tree = ast.Tree{

root.Tree = &ast.Tree{
Root: &root,
Document: path,
}
return p.tree
return root.Tree
}

func (p *Parser) addNewNodeTo(parent *ast.Node, offsetBefore int64, offsetAfter int64, dep dependency) *ast.Node {
content := p.tree.Root.Value
contentInclusive := content[0:offsetAfter]
func (p *Parser) addNewNodeTo(parent *ast.Node, offsetBefore int64, offsetAfter int64, dep Dependency) *ast.Node {
var startChar int
var endChar int
var line int
content := parent.Tree.Root.Value
contentInclusiveDep := content[0:offsetAfter]

startTag := "<version>"
endTag := "</version"
versionStartOffset := strings.LastIndex(contentInclusive, startTag)
contentUntilVersion := content[0:versionStartOffset]
line := strings.Count(contentUntilVersion, "\n")
lineStartOffset := strings.LastIndex(contentUntilVersion, "\n")
versionValueStartOffset := versionStartOffset + len(startTag) - lineStartOffset - 1
versionValueEndOffset := strings.LastIndex(contentInclusive, endTag) - lineStartOffset - 1
endTag := "</version>"

if dep.Version == "" {
// highlight artifact, if version is not there (bom/parent pom)
startTag = "<artifactId>"
endTag = "</artifactId>"
}

startTagOffset := strings.LastIndex(contentInclusiveDep, startTag)
contentToVersionStart := content[0:startTagOffset]
line = strings.Count(contentToVersionStart, "\n")
lineStartOffset := strings.LastIndex(contentToVersionStart, "\n") + 1
startChar = startTagOffset + len(startTag) - lineStartOffset
versionEndOffset := strings.LastIndex(contentInclusiveDep, endTag)
endChar = versionEndOffset - lineStartOffset

node := ast.Node{
Line: line,
StartChar: versionValueStartOffset,
EndChar: versionValueEndOffset,
StartChar: startChar,
EndChar: endChar,
DocOffset: offsetBefore,
Parent: parent,
Children: nil,
Name: dep.ArtifactId,
Value: dep.Version,
Attributes: make(map[string]string),
Tree: parent.Tree,
}
parent.Add(&node)
return &node
Expand Down
12 changes: 12 additions & 0 deletions ast/maven/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,15 @@ func TestCreateDependencyTree(t *testing.T) {
assert.Equal(t, 15, children[1].StartChar)
assert.Equal(t, 21, children[1].EndChar)
}

func TestCreateHierarchicalDependencyTree(t *testing.T) {
c := testutil.UnitTest(t)
var testPath, _ = filepath.Abs("testdata/maven-goof/sub/pom.xml")
var testContent, _ = os.ReadFile(testPath)
parser := Parser{config: c}
tree := parser.Parse(string(testContent), testPath)

assert.NotNilf(t, tree.ParentTree, "Should have returned a Parent tree")

assert.Len(t, tree.ParentTree.Root.Children, 2)
}
37 changes: 37 additions & 0 deletions ast/maven/testdata/maven-goof/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<name>my-app</name>
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
85 changes: 85 additions & 0 deletions ast/maven/testdata/maven-goof/sub/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-child-app</artifactId>
<version>1.0-SNAPSHOT</version>


<name>my-app</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- <relativePath/>-->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
</dependencies>

<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Loading

0 comments on commit 7ef4967

Please sign in to comment.