Skip to content

Commit 938db1c

Browse files
authored
fix: use path instead of filepath
Currently, yaegi uses the `filepath` package to join paths. However, this has issues: YAEGI uses an `fs.FS` internally for source code access, and `fs` specifies that `/` separated paths must be used. On Unix systems, this obviously makes no difference; but on Windows, with a non-default FS, this causes errors (since YAEGI creates `\` separated paths, but the FS expects `/` separated paths). Furthermore, generally speaking, Golang import paths and the like are always `/` separated anyway, regardless of OS. To clear this up, this PR changes path handling to `/` separated paths. This has the advantage of being accepted by all OS (even Windows will accept `/` separated paths). Paths passed by the user to `CompilePath` or similar are changed to `/` separators, if necessary.
1 parent f616581 commit 938db1c

File tree

13 files changed

+88
-69
lines changed

13 files changed

+88
-69
lines changed

_test/issue-1280.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type DB struct {
1616
}
1717

1818
func main() {
19-
f, err := os.Open("/dev/null")
19+
f, err := os.Open(os.DevNull)
2020
if err != nil {
2121
log.Fatal(err)
2222
}

cmd/yaegi/yaegi_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ func applyCIMultiplier(timeout time.Duration) time.Duration {
3737
}
3838

3939
func TestYaegiCmdCancel(t *testing.T) {
40+
if runtime.GOOS == "windows" {
41+
t.Skip("skipping cancel test since windows has no os.Interrupt signal")
42+
}
4043
tmp := t.TempDir()
4144
yaegi := filepath.Join(tmp, "yaegi")
4245

example/pkg/pkg_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func TestPackagesError(t *testing.T) {
164164
{
165165
desc: "different packages in the same directory",
166166
goPath: "./_pkg9/",
167-
expected: `1:21: import "github.com/foo/pkg" error: found packages pkg and pkgfalse in ` + filepath.FromSlash("_pkg9/src/github.com/foo/pkg"),
167+
expected: `1:21: import "github.com/foo/pkg" error: found packages pkg and pkgfalse in _pkg9/src/github.com/foo/pkg`,
168168
},
169169
}
170170

interp/build.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"go/build"
66
"go/parser"
77
"path"
8-
"path/filepath"
98
"strconv"
109
"strings"
1110
)
@@ -135,7 +134,7 @@ func skipFile(ctx *build.Context, p string, skipTest bool) bool {
135134
return true
136135
}
137136
p = strings.TrimSuffix(path.Base(p), ".go")
138-
if pp := filepath.Base(p); strings.HasPrefix(pp, "_") || strings.HasPrefix(pp, ".") {
137+
if pp := path.Base(p); strings.HasPrefix(pp, "_") || strings.HasPrefix(pp, ".") {
139138
return true
140139
}
141140
if skipTest && strings.HasSuffix(p, "_test") {

interp/cfg.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"go/constant"
66
"log"
77
"math"
8-
"path/filepath"
8+
"path"
99
"reflect"
1010
"strings"
1111
"unicode"
@@ -64,7 +64,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
6464
var initNodes []*node
6565
var err error
6666

67-
baseName := filepath.Base(interp.fset.Position(root.pos).Filename)
67+
baseName := path.Base(interp.fset.Position(root.pos).Filename)
6868

6969
root.Walk(func(n *node) bool {
7070
// Pre-order processing
@@ -1643,7 +1643,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
16431643
break
16441644
}
16451645
// retry with the filename, in case ident is a package name.
1646-
sym, level, found = sc.lookup(filepath.Join(n.ident, baseName))
1646+
sym, level, found = sc.lookup(path.Join(n.ident, baseName))
16471647
if !found {
16481648
err = n.cfgErrorf("undefined: %s", n.ident)
16491649
break
@@ -2612,8 +2612,8 @@ func (n *node) isType(sc *scope) bool {
26122612
}
26132613
case selectorExpr:
26142614
pkg, name := n.child[0].ident, n.child[1].ident
2615-
baseName := filepath.Base(n.interp.fset.Position(n.pos).Filename)
2616-
suffixedPkg := filepath.Join(pkg, baseName)
2615+
baseName := path.Base(n.interp.fset.Position(n.pos).Filename)
2616+
suffixedPkg := path.Join(pkg, baseName)
26172617
sym, _, ok := sc.lookup(suffixedPkg)
26182618
if !ok {
26192619
sym, _, ok = sc.lookup(pkg)

interp/gta.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package interp
22

33
import (
44
"path"
5-
"path/filepath"
65
)
76

87
// gta performs a global types analysis on the AST, registering types,
@@ -15,7 +14,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([
1514
var err error
1615
var revisit []*node
1716

18-
baseName := filepath.Base(interp.fset.Position(root.pos).Filename)
17+
baseName := path.Base(interp.fset.Position(root.pos).Filename)
1918

2019
root.Walk(func(n *node) bool {
2120
if err != nil {
@@ -125,7 +124,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([
125124
}
126125
}
127126
for _, c := range n.child[:l] {
128-
asImportName := filepath.Join(c.ident, baseName)
127+
asImportName := path.Join(c.ident, baseName)
129128
sym, exists := sc.sym[asImportName]
130129
if !exists {
131130
sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ, node: n}
@@ -203,7 +202,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([
203202
case ident == "init":
204203
// init functions do not get declared as per the Go spec.
205204
default:
206-
asImportName := filepath.Join(ident, baseName)
205+
asImportName := path.Join(ident, baseName)
207206
if _, exists := sc.sym[asImportName]; exists {
208207
// redeclaration error
209208
err = n.cfgErrorf("%s redeclared in this block", ident)
@@ -257,7 +256,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([
257256
// map them by their names, otherwise we could have collisions from same-name
258257
// imports in different source files of the same package. Therefore, we suffix
259258
// the key with the basename of the source file.
260-
name = filepath.Join(name, baseName)
259+
name = path.Join(name, baseName)
261260
if sym, exists := sc.sym[name]; !exists {
262261
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath, scope: sc}}
263262
break
@@ -284,7 +283,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([
284283
if name == "" {
285284
name = pkgName
286285
}
287-
name = filepath.Join(name, baseName)
286+
name = path.Join(name, baseName)
288287
if sym, exists := sc.sym[name]; !exists {
289288
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath, scope: sc}}
290289
break
@@ -345,7 +344,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([
345344
}
346345
n.typ.str = n.typ.path + "." + n.typ.name
347346

348-
asImportName := filepath.Join(typeName, baseName)
347+
asImportName := path.Join(typeName, baseName)
349348
if _, exists := sc.sym[asImportName]; exists {
350349
// redeclaration error
351350
err = n.cfgErrorf("%s redeclared in this block", typeName)

interp/interp.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ func (interp *Interpreter) Eval(src string) (res reflect.Value, err error) {
500500
// by the interpreter, and a non nil error in case of failure.
501501
// The main function of the main package is executed if present.
502502
func (interp *Interpreter) EvalPath(path string) (res reflect.Value, err error) {
503+
path = filepath.ToSlash(path) // Ensure path is in Unix format. Since we work with fs.FS, we need to use Unix path.
503504
if !isFile(interp.opt.filesystem, path) {
504505
_, err := interp.importSrc(mainID, path, NoTest)
505506
return res, err
@@ -647,7 +648,7 @@ func (interp *Interpreter) ImportUsed() {
647648
}
648649

649650
func key2name(name string) string {
650-
return filepath.Join(name, DefaultSourceName)
651+
return path.Join(name, DefaultSourceName)
651652
}
652653

653654
func fixKey(k string) string {

interp/interp_consistent_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ func TestInterpConsistencyBuild(t *testing.T) {
177177
os.Stdout = backupStdout
178178

179179
bin := filepath.Join(dir, strings.TrimSuffix(file.Name(), ".go"))
180+
if runtime.GOOS == "windows" {
181+
bin += ".exe"
182+
}
180183

181184
cmdBuild := exec.Command("go", "build", "-tags=dummy", "-o", bin, filePath)
182185
outBuild, err := cmdBuild.CombinedOutput()

interp/interp_file_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"go/token"
88
"os"
99
"path/filepath"
10-
"regexp"
1110
"runtime"
1211
"strings"
1312
"testing"
@@ -92,9 +91,10 @@ func runCheck(t *testing.T, p string) {
9291
t.Fatal(err)
9392
}
9493

94+
res := strings.TrimSpace(stdout.String())
9595
// Remove path in output, to have results independent of location.
96-
re := regexp.MustCompile(p + ":")
97-
if res := re.ReplaceAllString(strings.TrimSpace(stdout.String()), ""); res != wanted {
96+
res = strings.ReplaceAll(res, filepath.ToSlash(p)+":", "")
97+
if res != wanted {
9898
t.Errorf("\ngot: %q,\nwant: %q", res, wanted)
9999
}
100100
}

interp/program.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import (
44
"context"
55
"go/ast"
66
"go/token"
7-
"os"
7+
"io/fs"
8+
"path/filepath"
89
"reflect"
910
"runtime"
1011
"runtime/debug"
@@ -35,12 +36,13 @@ func (interp *Interpreter) Compile(src string) (*Program, error) {
3536

3637
// CompilePath parses and compiles a Go code located at the given path.
3738
func (interp *Interpreter) CompilePath(path string) (*Program, error) {
39+
path = filepath.ToSlash(path) // Ensure path is in Unix format. Since we work with fs.FS, we need to use Unix path.
3840
if !isFile(interp.filesystem, path) {
3941
_, err := interp.importSrc(mainID, path, NoTest)
4042
return nil, err
4143
}
4244

43-
b, err := os.ReadFile(path)
45+
b, err := fs.ReadFile(interp.filesystem, path)
4446
if err != nil {
4547
return nil, err
4648
}

0 commit comments

Comments
 (0)