github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/lua/parse_rockspec.go (about)

     1  package lua
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/anchore/syft/internal/log"
     9  	"github.com/anchore/syft/syft/artifact"
    10  	"github.com/anchore/syft/syft/file"
    11  	"github.com/anchore/syft/syft/pkg"
    12  	"github.com/anchore/syft/syft/pkg/cataloger/generic"
    13  )
    14  
    15  type luaRocksPackage struct {
    16  	Name         string
    17  	Version      string
    18  	License      string
    19  	Homepage     string
    20  	Description  string
    21  	Dependencies map[string]string
    22  	Repository   repository
    23  }
    24  
    25  type repository struct {
    26  	URL string
    27  }
    28  
    29  // parseRockspec parses a package.rockspec and returns the discovered Lua packages.
    30  func parseRockspec(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    31  	doc, err := parseRockspecData(reader)
    32  	if err != nil {
    33  		log.WithFields("error", err).Trace("unable to parse Rockspec app")
    34  		return nil, nil, fmt.Errorf("unable to parse Rockspec app: %w", err)
    35  	}
    36  
    37  	var name, version, license, homepage, description, url string
    38  	var dependencies map[string]string
    39  
    40  	for _, node := range doc.value {
    41  		switch node.key {
    42  		case "package":
    43  			name = node.String()
    44  		case "version":
    45  			version = node.String()
    46  		case "source":
    47  			for _, child := range node.Slice() {
    48  				if child.key == "url" {
    49  					url = child.String()
    50  					break
    51  				}
    52  			}
    53  		case "description":
    54  			for _, child := range node.Slice() {
    55  				switch child.key {
    56  				case "summary":
    57  					description = child.String()
    58  				case "homepage":
    59  					homepage = child.String()
    60  				case "license":
    61  					license = strings.ReplaceAll(child.String(), " ", "-")
    62  				}
    63  			}
    64  		case "dependencies":
    65  			if dependencies == nil {
    66  				dependencies = make(map[string]string)
    67  			}
    68  			for _, child := range node.Slice() {
    69  				depName, depVersion := parseDependency(child.String())
    70  				if depName != "" {
    71  					dependencies[depName] = depVersion
    72  				}
    73  			}
    74  		}
    75  	}
    76  
    77  	p := newLuaRocksPackage(
    78  		ctx,
    79  		resolver,
    80  		luaRocksPackage{
    81  			Name:    name,
    82  			Version: version,
    83  			License: license,
    84  			Repository: repository{
    85  				URL: url,
    86  			},
    87  			Homepage:     homepage,
    88  			Description:  description,
    89  			Dependencies: dependencies,
    90  		},
    91  		reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
    92  	)
    93  
    94  	return []pkg.Package{p}, nil, nil
    95  }
    96  
    97  // parseDependency extracts the package name and version constraint from a dependency string.
    98  // Examples:
    99  //   - "lua >= 5.1" -> ("lua", ">= 5.1")
   100  //   - "lpeg" -> ("lpeg", "")
   101  //   - "lualogging >= 1.4.0, < 2.0.0" -> ("lualogging", ">= 1.4.0, < 2.0.0")
   102  func parseDependency(dep string) (name string, version string) {
   103  	dep = strings.TrimSpace(dep)
   104  	if dep == "" {
   105  		return "", ""
   106  	}
   107  
   108  	// Find the first space which separates package name from version constraint
   109  	parts := strings.SplitN(dep, " ", 2)
   110  	name = strings.TrimSpace(parts[0])
   111  
   112  	if len(parts) == 2 {
   113  		version = strings.TrimSpace(parts[1])
   114  	}
   115  
   116  	return name, version
   117  }