From 63c5bca8e1796cea481115c87b023e997a5b7ebd Mon Sep 17 00:00:00 2001 From: Sebastien Binet Date: Mon, 3 Aug 2015 14:24:50 +0200 Subject: [PATCH] gopy: proper handling of lang option This CL introduces a split in handling of {py|py2|py3}{thon,}. It also lifts up the bind.Package creation so the processing is done only once. Change-Id: I946605fb24885df986baa77088f76df90ff4d168 --- cmd_bind.go | 35 ++++++++--------------------- cmd_gen.go | 3 +-- gen.go | 63 ++++++++++++++++++++++++++++++++++++----------------- python.go | 45 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 48 deletions(-) create mode 100644 python.go diff --git a/cmd_bind.go b/cmd_bind.go index 7f0954d..8c975ca 100644 --- a/cmd_bind.go +++ b/cmd_bind.go @@ -6,7 +6,6 @@ package main import ( "fmt" - "go/build" "io/ioutil" "log" "os" @@ -32,6 +31,7 @@ ex: Flag: *flag.NewFlagSet("gopy-bind", flag.ExitOnError), } + cmd.Flag.String("lang", "py2", "python version to use for bindings (python2|py2|python3|py3)") cmd.Flag.String("output", "", "output directory for bindings") return cmd } @@ -47,6 +47,7 @@ func gopyRunCmdBind(cmdr *commander.Command, args []string) error { } odir := cmdr.Flag.Lookup("output").Value.Get().(string) + lang := cmdr.Flag.Lookup("lang").Value.Get().(string) cwd, err := os.Getwd() if err != nil { @@ -69,7 +70,7 @@ func gopyRunCmdBind(cmdr *commander.Command, args []string) error { } path := args[0] - pkg, err := build.Import(path, cwd, 0) + pkg, err := newPackage(path) if err != nil { return fmt.Errorf( "gopy-bind: go/build.Inport failed with path=%q: %v\n", @@ -90,30 +91,12 @@ func gopyRunCmdBind(cmdr *commander.Command, args []string) error { } //defer os.RemoveAll(work) - cmd := exec.Command( - "gopy", "gen", - "-output", work, - "-lang=python", pkg.ImportPath, - ) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - err = cmd.Run() + err = genPkg(work, pkg, lang) if err != nil { return err } - cmd = exec.Command( - "gopy", "gen", - "-output", work, - "-lang=go", pkg.ImportPath, - ) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - err = cmd.Run() + err = genPkg(work, pkg, "go") if err != nil { return err } @@ -129,9 +112,9 @@ func gopyRunCmdBind(cmdr *commander.Command, args []string) error { } defer os.RemoveAll(wbind) - cmd = exec.Command( + cmd := exec.Command( "go", "build", "-v", "-buildmode=c-shared", - "-o", filepath.Join(wbind, pkg.Name)+".so", + "-o", filepath.Join(wbind, pkg.Name())+".so", // pkg.ImportPath, ".", ) @@ -146,8 +129,8 @@ func gopyRunCmdBind(cmdr *commander.Command, args []string) error { cmd = exec.Command( "/bin/cp", - filepath.Join(wbind, pkg.Name)+".so", - filepath.Join(odir, pkg.Name)+".so", + filepath.Join(wbind, pkg.Name())+".so", + filepath.Join(odir, pkg.Name())+".so", ) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout diff --git a/cmd_gen.go b/cmd_gen.go index 4722209..f0e526b 100644 --- a/cmd_gen.go +++ b/cmd_gen.go @@ -6,7 +6,6 @@ package main import ( "fmt" - "go/build" "log" "os" "path/filepath" @@ -73,7 +72,7 @@ func gopyRunCmdGen(cmdr *commander.Command, args []string) error { } path := args[0] - pkg, err := build.Import(path, cwd, 0) + pkg, err := newPackage(path) if err != nil { return fmt.Errorf( "gopy-gen: go/build.Inport failed with path=%q: %v\n", diff --git a/gen.go b/gen.go index 8483609..f850b7e 100644 --- a/gen.go +++ b/gen.go @@ -26,31 +26,22 @@ var ( fset = token.NewFileSet() ) -func genPkg(odir string, pkg *build.Package, lang string) error { +func genPkg(odir string, p *bind.Package, lang string) error { var err error var o *os.File - files, err := parseFiles(pkg.Dir, pkg.GoFiles) - if err != nil { - return err - } - - conf := loader.Config{ - Fset: fset, - } - conf.TypeChecker.Error = func(e error) { - log.Printf("%v\n", e) - err = e - } - - p, err := newPackage(files, &conf, pkg) - if err != nil { - log.Printf("%v\n", err) - return err + switch lang { + case "python", "py": + lang, err = getPythonVersion() + if err != nil { + return err + } + default: + // no-op } switch lang { - case "python", "py": + case "python2", "py2": o, err = os.Create(filepath.Join(odir, p.Name()+".c")) if err != nil { return err @@ -61,6 +52,9 @@ func genPkg(odir string, pkg *build.Package, lang string) error { return err } + case "python3", "py3": + return fmt.Errorf("gopy: python-3 support not yet implemented") + case "go": o, err = os.Create(filepath.Join(odir, p.Name()+".go")) if err != nil { @@ -147,7 +141,36 @@ func parseFiles(dir string, fnames []string) ([]*ast.File, error) { return files, err } -func newPackage(files []*ast.File, conf *loader.Config, pkg *build.Package) (*bind.Package, error) { +func newPackage(path string) (*bind.Package, error) { + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + + pkg, err := build.Import(path, cwd, 0) + files, err := parseFiles(pkg.Dir, pkg.GoFiles) + if err != nil { + return nil, err + } + + conf := loader.Config{ + Fset: fset, + } + conf.TypeChecker.Error = func(e error) { + log.Printf("%v\n", e) + err = e + } + + p, err := newPackageFrom(files, &conf, pkg) + if err != nil { + log.Printf("%v\n", err) + return nil, err + } + + return p, err +} + +func newPackageFrom(files []*ast.File, conf *loader.Config, pkg *build.Package) (*bind.Package, error) { conf.CreateFromFiles(pkg.ImportPath, files...) program, err := conf.Load() diff --git a/python.go b/python.go new file mode 100644 index 0000000..f9eeb6b --- /dev/null +++ b/python.go @@ -0,0 +1,45 @@ +// Copyright 2015 The go-python Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "os/exec" +) + +// getPythonVersion returns the python version available on this machine +func getPythonVersion() (string, error) { + py, err := exec.LookPath("python") + if err != nil { + return "", fmt.Errorf( + "gopy: could not locate 'python' executable (err: %v)", + err, + ) + } + + out, err := exec.Command(py, "--version").Output() + if err != nil { + return "", fmt.Errorf( + "gopy: error retrieving python version (err: %v)", + err, + ) + } + + vers := "" + switch { + case bytes.HasPrefix(out, []byte("Python 2")): + vers = "py2" + case bytes.HasPrefix(out, []byte("Python 3")): + vers = "py3" + default: + return "", fmt.Errorf( + "gopy: invalid python version (%s)", + string(out), + ) + } + + return vers, nil +}