diff --git a/go.mod b/go.mod index 20ced11..f508506 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/crillab/gophersat v1.4.0 github.com/dsnet/compress v0.0.1 github.com/google/uuid v1.6.0 + github.com/klauspost/compress v1.18.3 github.com/ulikunitz/xz v0.5.15 golang.org/x/crypto v0.47.0 golang.org/x/term v0.39.0 @@ -19,7 +20,6 @@ require ( require ( github.com/coregx/ahocorasick v0.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/klauspost/compress v1.18.3 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -32,3 +32,5 @@ require ( modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) + +replace mvdan.cc/sh/v3 => ../reference/mvdan-sh diff --git a/go.sum b/go.sum index d2c8329..148d374 100644 --- a/go.sum +++ b/go.sum @@ -113,5 +113,3 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI= -mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg= diff --git a/internal/ebuild/executor.go b/internal/ebuild/executor.go index 921aefb..f919d53 100644 --- a/internal/ebuild/executor.go +++ b/internal/ebuild/executor.go @@ -619,8 +619,17 @@ func (e *Executor) ParseEbuild() error { return fmt.Errorf("checking ebuild file: %w", err) } - // Parse the ebuild script - parsed, err := ParseEbuildScript(e.EbuildPath) + // Parse the ebuild script with known variables for conditional evaluation. + // This ensures inherit calls inside "if [[ ${PV} == 9999 ]]" blocks + // are skipped when PV doesn't match (e.g., git-r3 for non-live ebuilds). + ebuildVars := map[string]string{ + "PV": e.Env.PV, + "PVR": e.Env.PVR, + "PN": e.Env.PN, + "P": e.Env.P, + "PF": e.Env.PF, + } + parsed, err := ParseEbuildScript(e.EbuildPath, ebuildVars) if err != nil { return fmt.Errorf("parsing ebuild: %w", err) } diff --git a/internal/ebuild/phase_dispatch_test.go b/internal/ebuild/phase_dispatch_test.go index 9415c6f..b9b48ea 100644 --- a/internal/ebuild/phase_dispatch_test.go +++ b/internal/ebuild/phase_dispatch_test.go @@ -47,7 +47,7 @@ src_configure() { } // Parse ebuild to detect functions - script, err := ParseEbuildScript(ebuildPath) + script, err := ParseEbuildScript(ebuildPath, nil) if err != nil { t.Fatalf("failed to parse ebuild: %v", err) } @@ -98,7 +98,7 @@ SLOT="0" } // Parse ebuild - script, err := ParseEbuildScript(ebuildPath) + script, err := ParseEbuildScript(ebuildPath, nil) if err != nil { t.Fatalf("failed to parse ebuild: %v", err) } @@ -131,7 +131,7 @@ SLOT="0" } // Parse ebuild - script, err := ParseEbuildScript(ebuildPath) + script, err := ParseEbuildScript(ebuildPath, nil) if err != nil { t.Fatalf("failed to parse ebuild: %v", err) } @@ -237,7 +237,7 @@ src_configure() { } // Parse ebuild - script, parseErr := ParseEbuildScript(ebuildPath) + script, parseErr := ParseEbuildScript(ebuildPath, nil) if parseErr != nil { t.Fatalf("failed to parse ebuild: %v", parseErr) } @@ -295,7 +295,7 @@ src_prepare() { } // Parse ebuild - script, parseErr := ParseEbuildScript(ebuildPath) + script, parseErr := ParseEbuildScript(ebuildPath, nil) if parseErr != nil { t.Fatalf("failed to parse ebuild: %v", parseErr) } @@ -370,7 +370,7 @@ pkg_prerm() { :; } pkg_postrm() { :; } ` - script, err := ParseEbuildScriptFromString(content) + script, err := ParseEbuildScriptFromString(content, nil) if err != nil { t.Fatalf("ParseEbuildScriptFromString failed: %v", err) } @@ -407,7 +407,7 @@ src_compile() { emake; } pkg_postinst() { einfo "Done"; } ` - script, err := ParseEbuildScriptFromString(content) + script, err := ParseEbuildScriptFromString(content, nil) if err != nil { t.Fatalf("ParseEbuildScriptFromString failed: %v", err) } @@ -501,7 +501,7 @@ src_configure() { EbuildPath: ebuildPath, } - script, parseErr := ParseEbuildScript(ebuildPath) + script, parseErr := ParseEbuildScript(ebuildPath, nil) if parseErr != nil { t.Fatalf("failed to parse ebuild: %v", parseErr) } @@ -549,7 +549,7 @@ src_install() { b.ResetTimer() for i := 0; i < b.N; i++ { - _, _ = ParseEbuildScriptFromString(content) + _, _ = ParseEbuildScriptFromString(content, nil) } } @@ -561,7 +561,7 @@ src_configure() { econf; } src_compile() { emake; } src_install() { emake install; } ` - script, err := ParseEbuildScriptFromString(content) + script, err := ParseEbuildScriptFromString(content, nil) if err != nil { b.Fatalf("ParseEbuildScriptFromString failed: %v", err) } diff --git a/internal/ebuild/script.go b/internal/ebuild/script.go index c243daa..7e09404 100644 --- a/internal/ebuild/script.go +++ b/internal/ebuild/script.go @@ -8,6 +8,7 @@ import ( "bufio" "fmt" "os" + "path/filepath" "regexp" "strings" @@ -40,8 +41,13 @@ type EbuildScript struct { // This is a lightweight parser that identifies function definitions without // fully executing the ebuild. Used for phase dispatch decisions. // +// The vars parameter provides known variables (PV, PN, P, etc.) for evaluating +// simple conditionals. When a conditional like [[ ${PV} == 9999 ]] can be +// statically evaluated, branches that are definitely false are skipped. +// Pass nil to collect all inherit calls unconditionally (conservative mode). +// // Returns EbuildScript with function information or error. -func ParseEbuildScript(path string) (*EbuildScript, error) { +func ParseEbuildScript(path string, vars map[string]string) (*EbuildScript, error) { file, err := os.Open(path) if err != nil { return nil, fmt.Errorf("opening ebuild %s: %w", path, err) @@ -69,38 +75,19 @@ func ParseEbuildScript(path string) (*EbuildScript, error) { script.AST = ast - // Extract functions and metadata from AST - syntax.Walk(ast, func(node syntax.Node) bool { - switch n := node.(type) { - case *syntax.FuncDecl: - // Found a function declaration - script.DefinedFunctions[n.Name.Value] = true - case *syntax.CallExpr: - // Look for inherit calls and EAPI assignments - if len(n.Args) > 0 { - if lit := getFirstWordLit(n.Args[0]); lit != "" { - if lit == "inherit" && len(n.Args) > 1 { - // Collect inherited eclasses - for _, arg := range n.Args[1:] { - if eclassName := getFirstWordLit(arg); eclassName != "" { - script.InheritedEclasses = append(script.InheritedEclasses, eclassName) - } - } - } - } - } - case *syntax.Assign: - // Look for EAPI assignment - if n.Name != nil && n.Name.Value == "EAPI" { - if n.Value != nil { - if word := getWordValue(n.Value); word != "" { - script.EAPI = strings.Trim(word, "\"'") - } - } - } + // If no vars provided, try to infer PV from filename. + // Ebuild filenames follow the pattern: -.ebuild + if vars == nil { + vars = make(map[string]string) + } + if _, ok := vars["PV"]; !ok { + if pv := pvFromPath(path); pv != "" { + vars["PV"] = pv } - return true - }) + } + + // Extract functions and metadata from AST using condition-aware walker + walkStmts(ast.Stmts, script, vars) return script, nil } @@ -108,7 +95,8 @@ func ParseEbuildScript(path string) (*EbuildScript, error) { // ParseEbuildScriptFromString parses ebuild content from a string. // // Useful for testing and when ebuild content is already in memory. -func ParseEbuildScriptFromString(content string) (*EbuildScript, error) { +// Pass vars to enable conditional evaluation, or nil for conservative mode. +func ParseEbuildScriptFromString(content string, vars map[string]string) (*EbuildScript, error) { script := &EbuildScript{ Path: "(string)", DefinedFunctions: make(map[string]bool), @@ -128,34 +116,12 @@ func ParseEbuildScriptFromString(content string) (*EbuildScript, error) { script.AST = ast - // Extract functions and metadata from AST - syntax.Walk(ast, func(node syntax.Node) bool { - switch n := node.(type) { - case *syntax.FuncDecl: - script.DefinedFunctions[n.Name.Value] = true - case *syntax.CallExpr: - if len(n.Args) > 0 { - if lit := getFirstWordLit(n.Args[0]); lit != "" { - if lit == "inherit" && len(n.Args) > 1 { - for _, arg := range n.Args[1:] { - if eclassName := getFirstWordLit(arg); eclassName != "" { - script.InheritedEclasses = append(script.InheritedEclasses, eclassName) - } - } - } - } - } - case *syntax.Assign: - if n.Name != nil && n.Name.Value == "EAPI" { - if n.Value != nil { - if word := getWordValue(n.Value); word != "" { - script.EAPI = strings.Trim(word, "\"'") - } - } - } - } - return true - }) + if vars == nil { + vars = make(map[string]string) + } + + // Extract functions and metadata from AST using condition-aware walker + walkStmts(ast.Stmts, script, vars) return script, nil } @@ -282,6 +248,278 @@ func (s *EbuildScript) FindDefinedPhases() []Phase { return defined } +// walkStmts walks a list of statements, extracting metadata into script. +// It evaluates simple if-conditions using vars to skip dead branches. +func walkStmts(stmts []*syntax.Stmt, script *EbuildScript, vars map[string]string) { + for _, stmt := range stmts { + walkNode(stmt, script, vars) + } +} + +// walkNode processes a single AST node, recursing into children as needed. +func walkNode(node syntax.Node, script *EbuildScript, vars map[string]string) { + if node == nil { + return + } + switch n := node.(type) { + case *syntax.Stmt: + walkNode(n.Cmd, script, vars) + case *syntax.FuncDecl: + script.DefinedFunctions[n.Name.Value] = true + // Don't recurse into function bodies for inherit extraction. + // Inherit calls inside functions are runtime, not load-time. + case *syntax.CallExpr: + walkCallExpr(n, script) + case *syntax.IfClause: + walkIfClause(n, script, vars) + case *syntax.Block: + walkStmts(n.Stmts, script, vars) + case *syntax.Subshell: + walkStmts(n.Stmts, script, vars) + case *syntax.BinaryCmd: + walkNode(n.X, script, vars) + walkNode(n.Y, script, vars) + case *syntax.WhileClause: + walkStmts(n.Cond, script, vars) + walkStmts(n.Do, script, vars) + case *syntax.ForClause: + walkStmts(n.Do, script, vars) + case *syntax.CaseClause: + for _, ci := range n.Items { + walkStmts(ci.Stmts, script, vars) + } + } +} + +// walkCallExpr extracts metadata from a call expression (command or assignment). +func walkCallExpr(n *syntax.CallExpr, script *EbuildScript) { + // Check assigns (e.g., EAPI=8 as a bare assignment) + for _, a := range n.Assigns { + if a.Name != nil && a.Name.Value == "EAPI" { + if a.Value != nil { + if word := getWordValue(a.Value); word != "" { + script.EAPI = strings.Trim(word, "\"'") + } + } + } + } + // Check command (e.g., inherit cmake) + if len(n.Args) > 0 { + if lit := getFirstWordLit(n.Args[0]); lit == "inherit" && len(n.Args) > 1 { + for _, arg := range n.Args[1:] { + if eclassName := getFirstWordLit(arg); eclassName != "" { + script.InheritedEclasses = append(script.InheritedEclasses, eclassName) + } + } + } + } +} + +// walkIfClause processes an if/elif/else chain with conditional evaluation. +// +// For simple conditions like [[ ${PV} == 9999 ]], if the variable is known +// and doesn't match, the branch body is skipped entirely. This prevents +// loading eclasses that are behind version-specific conditionals. +func walkIfClause(ic *syntax.IfClause, script *EbuildScript, vars map[string]string) { + if ic == nil { + return + } + + // Try to evaluate the condition statically. + result := evalCondition(ic.Cond, vars) + + switch result { + case condTrue: + // Condition is definitely true — walk this branch only. + walkStmts(ic.Then, script, vars) + // Skip else/elif entirely. + case condFalse: + // Condition is definitely false — skip this branch, try else/elif. + if ic.Else != nil { + if ic.Else.Cond != nil { + // This is an "elif" — evaluate its condition. + walkIfClause(ic.Else, script, vars) + } else { + // This is an "else" — walk its body. + walkStmts(ic.Else.Then, script, vars) + } + } + default: + // Can't evaluate — conservatively walk ALL branches. + walkStmts(ic.Then, script, vars) + if ic.Else != nil { + walkIfClause(ic.Else, script, vars) + } + } +} + +// condResult represents the result of static condition evaluation. +type condResult int + +const ( + condUnknown condResult = iota + condTrue + condFalse +) + +// evalCondition tries to statically evaluate an if-clause condition. +// +// Supports: +// - [[ ${VAR} == literal ]] and [[ ${VAR} != literal ]] +// - Glob patterns in the literal (e.g., [[ ${PV} == *_p* ]]) +// - Simple string equality (e.g., [[ ${PV} == 9999 ]]) +func evalCondition(cond []*syntax.Stmt, vars map[string]string) condResult { + if len(vars) == 0 || len(cond) != 1 { + return condUnknown + } + stmt := cond[0] + if stmt.Cmd == nil { + return condUnknown + } + + tc, ok := stmt.Cmd.(*syntax.TestClause) + if !ok { + return condUnknown + } + + bt, ok := tc.X.(*syntax.BinaryTest) + if !ok { + return condUnknown + } + + // Only handle == and != + var negate bool + switch bt.Op { + case syntax.TsMatch, syntax.TsMatchShort: + negate = false + case syntax.TsNoMatch: + negate = true + default: + return condUnknown + } + + // Left side: expect ${VAR} (a Word containing a single ParamExp) + varName := extractSimpleVar(bt.X) + if varName == "" { + return condUnknown + } + val, ok := vars[varName] + if !ok { + return condUnknown + } + + // Right side: expect a literal or simple glob pattern + pat := extractTestLiteral(bt.Y) + if pat == "" { + return condUnknown + } + + // Match: in [[ ]], == does glob matching + matched := matchGlob(pat, val) + + if negate { + matched = !matched + } + + if matched { + return condTrue + } + return condFalse +} + +// extractSimpleVar extracts the variable name from a simple ${VAR} expression. +// Returns "" if the expression is not a simple parameter expansion. +func extractSimpleVar(expr syntax.TestExpr) string { + word, ok := expr.(*syntax.Word) + if !ok || len(word.Parts) != 1 { + return "" + } + pe, ok := word.Parts[0].(*syntax.ParamExp) + if !ok || pe.Param == nil { + return "" + } + // Only simple ${VAR}, not ${VAR:-default} or ${VAR%pattern} etc. + if pe.Exp != nil || pe.Slice != nil || pe.Repl != nil || pe.Excl || pe.Length { + return "" + } + return pe.Param.Value +} + +// extractTestLiteral extracts a literal string from a test expression. +// Handles both unquoted literals and double-quoted strings containing only literals. +func extractTestLiteral(expr syntax.TestExpr) string { + word, ok := expr.(*syntax.Word) + if !ok || len(word.Parts) == 0 { + return "" + } + + var sb strings.Builder + for _, part := range word.Parts { + switch p := part.(type) { + case *syntax.Lit: + sb.WriteString(p.Value) + case *syntax.SglQuoted: + sb.WriteString(p.Value) + case *syntax.DblQuoted: + for _, dp := range p.Parts { + if lit, ok := dp.(*syntax.Lit); ok { + sb.WriteString(lit.Value) + } else { + return "" // contains variable expansion + } + } + default: + return "" // contains non-literal parts + } + } + return sb.String() +} + +// matchGlob performs simple glob matching (supports * and ? wildcards). +func matchGlob(pattern, value string) bool { + // filepath.Match handles *, ?, and [...] patterns + matched, err := filepath.Match(pattern, value) + if err != nil { + return pattern == value // fall back to exact match on invalid pattern + } + return matched +} + +// pvFromPath extracts the package version from an ebuild filename. +// +// Ebuild filenames follow: -.ebuild +// For example: make-4.4.1-r102.ebuild → PV=4.4.1, PVR=4.4.1-r102 +func pvFromPath(path string) string { + base := filepath.Base(path) + base = strings.TrimSuffix(base, ".ebuild") + if base == "" { + return "" + } + // Find the last hyphen followed by a digit — that's where the version starts + for i := len(base) - 1; i > 0; i-- { + if base[i-1] == '-' && i < len(base) && base[i] >= '0' && base[i] <= '9' { + vr := base[i:] + // Strip -rN revision suffix for PV + if idx := strings.LastIndex(vr, "-r"); idx >= 0 { + // Verify it's actually a revision (digits after -r) + rev := vr[idx+2:] + allDigits := true + for _, c := range rev { + if c < '0' || c > '9' { + allDigits = false + break + } + } + if allDigits && len(rev) > 0 { + return vr[:idx] + } + } + return vr + } + } + return "" +} + // QuickParseFunctions does a fast regex-based scan for function definitions. // // This is faster than full AST parsing but less accurate. diff --git a/internal/ebuild/script_test.go b/internal/ebuild/script_test.go index 15f6bc5..1d6be66 100644 --- a/internal/ebuild/script_test.go +++ b/internal/ebuild/script_test.go @@ -112,7 +112,7 @@ function src_compile { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - script, err := ParseEbuildScriptFromString(tt.content) + script, err := ParseEbuildScriptFromString(tt.content, nil) if (err != nil) != tt.wantErr { t.Errorf("ParseEbuildScriptFromString() error = %v, wantErr %v", err, tt.wantErr) return @@ -157,13 +157,139 @@ function src_compile { } } +func TestParseEbuildScript_ConditionalInherit(t *testing.T) { + // Reproduces the make-4.4.1 pattern: inherit git-r3 inside if [[ ${PV} == 9999 ]] + makeEbuild := ` +EAPI=8 +inherit flag-o-matic unpacker verify-sig + +if [[ ${PV} == 9999 ]] ; then + EGIT_REPO_URI="https://git.savannah.gnu.org/git/make.git" + inherit autotools git-r3 +elif [[ $(ver_cut 3) -ge 90 ]] ; then + SRC_URI="https://alpha.gnu.org/gnu/make/${P}.tar.lz" +else + SRC_URI="mirror://gnu/make/${P}.tar.lz" + KEYWORDS="amd64 x86" +fi +` + tests := []struct { + name string + vars map[string]string + wantInherit []string + }{ + { + name: "PV=4.4.1 should skip git-r3", + vars: map[string]string{"PV": "4.4.1"}, + wantInherit: []string{"flag-o-matic", "unpacker", "verify-sig"}, + }, + { + name: "PV=9999 should include git-r3", + vars: map[string]string{"PV": "9999"}, + wantInherit: []string{"flag-o-matic", "unpacker", "verify-sig", "autotools", "git-r3"}, + }, + { + name: "nil vars infers PV from filename (conservative for string parse)", + vars: nil, + // Without vars, condition can't be evaluated → all branches included + wantInherit: []string{"flag-o-matic", "unpacker", "verify-sig", "autotools", "git-r3"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + script, err := ParseEbuildScriptFromString(makeEbuild, tt.vars) + if err != nil { + t.Fatalf("ParseEbuildScriptFromString() error = %v", err) + } + if len(script.InheritedEclasses) != len(tt.wantInherit) { + t.Errorf("InheritedEclasses = %v, want %v", script.InheritedEclasses, tt.wantInherit) + return + } + for i, ec := range tt.wantInherit { + if script.InheritedEclasses[i] != ec { + t.Errorf("InheritedEclasses[%d] = %s, want %s", i, script.InheritedEclasses[i], ec) + } + } + }) + } +} + +func TestParseEbuildScript_ConditionalPatternMatch(t *testing.T) { + // Test glob patterns in conditions + content := ` +EAPI=8 +inherit base-eclass + +if [[ ${PV} == *_p* ]] ; then + inherit snapshot-eclass +fi +` + tests := []struct { + name string + vars map[string]string + wantInherit []string + }{ + { + name: "PV without _p skips snapshot eclass", + vars: map[string]string{"PV": "1.2.3"}, + wantInherit: []string{"base-eclass"}, + }, + { + name: "PV with _p includes snapshot eclass", + vars: map[string]string{"PV": "1.2.3_p20250101"}, + wantInherit: []string{"base-eclass", "snapshot-eclass"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + script, err := ParseEbuildScriptFromString(content, tt.vars) + if err != nil { + t.Fatalf("ParseEbuildScriptFromString() error = %v", err) + } + if len(script.InheritedEclasses) != len(tt.wantInherit) { + t.Errorf("InheritedEclasses = %v, want %v", script.InheritedEclasses, tt.wantInherit) + return + } + for i, ec := range tt.wantInherit { + if script.InheritedEclasses[i] != ec { + t.Errorf("InheritedEclasses[%d] = %s, want %s", i, script.InheritedEclasses[i], ec) + } + } + }) + } +} + +func TestParseEbuildScript_PVFromFilename(t *testing.T) { + tests := []struct { + path string + want string + }{ + {"make-4.4.1-r102.ebuild", "4.4.1"}, + {"make-4.4.1.ebuild", "4.4.1"}, + {"zlib-1.3.1.ebuild", "1.3.1"}, + {"python-3.12.0_beta1.ebuild", "3.12.0_beta1"}, + {"make-9999.ebuild", "9999"}, + {"", ""}, + } + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + got := pvFromPath(tt.path) + if got != tt.want { + t.Errorf("pvFromPath(%q) = %q, want %q", tt.path, got, tt.want) + } + }) + } +} + func TestEbuildScriptHasPhaseFunction(t *testing.T) { content := ` EAPI=8 src_configure() { econf; } src_compile() { emake; } ` - script, err := ParseEbuildScriptFromString(content) + script, err := ParseEbuildScriptFromString(content, nil) if err != nil { t.Fatalf("ParseEbuildScriptFromString() error = %v", err) } @@ -197,7 +323,7 @@ src_configure() { econf; } src_install() { emake install DESTDIR="${D}"; } pkg_postinst() { einfo "Done"; } ` - script, err := ParseEbuildScriptFromString(content) + script, err := ParseEbuildScriptFromString(content, nil) if err != nil { t.Fatalf("ParseEbuildScriptFromString() error = %v", err) } @@ -293,7 +419,7 @@ src_install() { b.ResetTimer() for i := 0; i < b.N; i++ { - _, _ = ParseEbuildScriptFromString(content) + _, _ = ParseEbuildScriptFromString(content, nil) } } @@ -350,7 +476,7 @@ src_prepare() { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := ParseEbuildScriptFromString(tt.content) + _, err := ParseEbuildScriptFromString(tt.content, nil) if (err != nil) != tt.wantErr { t.Errorf("ParseEbuildScriptFromString() error = %v, wantErr %v", err, tt.wantErr) } @@ -383,7 +509,7 @@ func TestParseEbuildScript_UnsupportedSyntax(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := ParseEbuildScriptFromString(tt.content) + _, err := ParseEbuildScriptFromString(tt.content, nil) if (err != nil) != tt.wantErr { t.Errorf("ParseEbuildScriptFromString() error = %v, wantErr %v\nNote: %s", err, tt.wantErr, tt.description) @@ -468,7 +594,7 @@ src_install() { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := ParseEbuildScriptFromString(tt.content) + _, err := ParseEbuildScriptFromString(tt.content, nil) if (err != nil) != tt.wantErr { t.Errorf("ParseEbuildScriptFromString() error = %v, wantErr %v", err, tt.wantErr) } diff --git a/tests/integration/framework.go b/tests/integration/framework.go index 3462da2..e8bceee 100644 --- a/tests/integration/framework.go +++ b/tests/integration/framework.go @@ -464,7 +464,7 @@ func ebuildHasFunction(t *testing.T, atom, function string) bool { ebuildPath := filepath.Join(tc.RepoPath, category, pkgName, fmt.Sprintf("%s-%s.ebuild", pkgName, loadedPkg.Version)) - parsed, err := ebuild.ParseEbuildScript(ebuildPath) + parsed, err := ebuild.ParseEbuildScript(ebuildPath, nil) if err != nil { return false } @@ -495,7 +495,7 @@ func getEbuildInherits(t *testing.T, atom string) []string { ebuildPath := filepath.Join(tc.RepoPath, category, pkgName, fmt.Sprintf("%s-%s.ebuild", pkgName, loadedPkg.Version)) - parsed, err := ebuild.ParseEbuildScript(ebuildPath) + parsed, err := ebuild.ParseEbuildScript(ebuildPath, nil) if err != nil { return nil } @@ -558,7 +558,7 @@ func validatePackageParsing(t *testing.T, atom string) *ParseResult { ebuildPath := filepath.Join(tc.RepoPath, category, pkgName, fmt.Sprintf("%s-%s.ebuild", pkgName, loadedPkg.Version)) - parsed, err := ebuild.ParseEbuildScript(ebuildPath) + parsed, err := ebuild.ParseEbuildScript(ebuildPath, nil) if err != nil { result.Error = fmt.Errorf("parsing ebuild: %w", err) return result