github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/os/macports/macports.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package macports extracts package information from OSX macports Portfile files. 16 package macports 17 18 import ( 19 "context" 20 "path/filepath" 21 "regexp" 22 "strings" 23 24 "github.com/google/osv-scalibr/extractor" 25 "github.com/google/osv-scalibr/extractor/filesystem" 26 macportsmeta "github.com/google/osv-scalibr/extractor/filesystem/os/macports/metadata" 27 "github.com/google/osv-scalibr/inventory" 28 "github.com/google/osv-scalibr/plugin" 29 "github.com/google/osv-scalibr/purl" 30 ) 31 32 const ( 33 // Name is the unique name of this extractor. 34 Name = "os/macports" 35 ) 36 37 // Extractor extracts macports apps. 38 type Extractor struct{} 39 40 // New returns a new instance of the extractor. 41 func New() filesystem.Extractor { return &Extractor{} } 42 43 // Name of the extractor. 44 func (e Extractor) Name() string { return Name } 45 46 // Version of the extractor. 47 func (e Extractor) Version() int { return 0 } 48 49 // Requirements of the extractor. 50 func (e Extractor) Requirements() *plugin.Capabilities { 51 return &plugin.Capabilities{} 52 } 53 54 // the Portfile file is found in /opt/local/var/macports/registry/portfiles/<packagename>-<version>_<revision>/<SHA256 hash of Portfile>-<index>/Portfile 55 var filePathRegex = regexp.MustCompile(`macports/registry/portfiles/([^-]+(?:-[^-]+)*)-([0-9][^_]*)_([0-9]+)/[a-f0-9]{64}-\d+/Portfile$`) 56 57 // This regex is used for extracting package name, version and revision from the directory name. Example directory name: autoconf-2.72_0 58 var portfileParsingRegex = regexp.MustCompile(`^(.+)-([0-9][^_]*)_(\d+)$`) 59 60 // FileRequired returns true if the specified file matches Portfile file pattern. 61 func (e Extractor) FileRequired(api filesystem.FileAPI) bool { 62 filePath := api.Path() 63 if !strings.HasSuffix(filePath, "Portfile") { 64 return false 65 } 66 if match := filePathRegex.FindString(filePath); match == "" { 67 return false 68 } 69 return true 70 } 71 72 // Extract extracts Port info from Portfile file passed through the scan input. 73 func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) (inventory.Inventory, error) { 74 pkgs := e.extractFromPath(input.Path) 75 return inventory.Inventory{Packages: pkgs}, nil 76 } 77 78 func (e Extractor) extractFromPath(path string) []*extractor.Package { 79 // Get the first folder after "portfiles/" 80 dir := filepath.Base(filepath.Dir(filepath.Dir(path))) 81 dir = strings.ToLower(dir) 82 // Apply regex 83 m := portfileParsingRegex.FindStringSubmatch(dir) 84 85 if len(m) >= 4 { 86 pkg := &extractor.Package{ 87 Name: m[1], 88 Version: m[2], 89 PURLType: purl.TypeMacports, 90 Locations: []string{path}, 91 Metadata: &macportsmeta.Metadata{ 92 PackageName: m[1], 93 PackageVersion: m[2], 94 PackageRevision: m[3], 95 }, 96 } 97 return []*extractor.Package{pkg} 98 } 99 return nil 100 }