Skip to content

Commit 9a76dcc

Browse files
author
Ilan Piperno
authored
Merge pull request #47 from lumapps/fix_go_lib
fix: fixed a bug making impossible to install the Go lib
2 parents cd4f926 + e76175b commit 9a76dcc

File tree

8 files changed

+98
-87
lines changed

8 files changed

+98
-87
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
name: Check dependencies
3333
command: |
3434
source venv/bin/activate && \
35-
PYTHONPATH=. GOPATH=dep_check/lib python3.7 dep_check/main.py check dep_check
35+
PYTHONPATH=. python3.7 dep_check/main.py check dep_check
3636
3737
# Run the unit tests
3838
tests:

dep_check/infra/go_parser.py

Lines changed: 20 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,33 @@
11
import logging
2-
from ctypes import Structure, c_char_p, c_longlong, cdll
3-
from os import environ
2+
from os import chdir
43
from subprocess import CalledProcessError, run
54

65
from dep_check.dependency_finder import IParser
76
from dep_check.models import Dependencies, Dependency, ModuleWildcard, SourceFile
87

9-
10-
class GoString(Structure): # pylint: disable=too-few-public-methods
11-
_fields_ = [("data", c_char_p), ("n", c_longlong)]
8+
try:
9+
from dep_check.lib import goparse
10+
except ImportError:
11+
chdir("dep_check/lib")
12+
try:
13+
run(["go", "build", "-buildmode=c-shared", "-o", "goparse.so"], check=True)
14+
from dep_check.lib import goparse # pylint: disable=no-name-in-module
15+
except (CalledProcessError, FileNotFoundError):
16+
logging.warning(
17+
"Couldn't load GO library, you won't be able to use dep-check on GO projects."
18+
)
19+
except ImportError:
20+
logging.warning(
21+
"Couldn't importy GO library, you won't be able to use dep-check on GO projects."
22+
)
23+
chdir("../..")
1224

1325

1426
class GoParser(IParser):
1527
"""
1628
Implementation of the interface, to parse go
1729
"""
1830

19-
def __init__(self):
20-
self.lib_path = environ.get("GOLIB", f'{environ["HOME"]}/.dep-check')
21-
22-
try:
23-
self.lib = cdll.LoadLibrary(f"{self.lib_path}/go_parse.so")
24-
except OSError:
25-
logging.info("go_parse.so not found. Building...")
26-
try:
27-
run(
28-
["go", "get", "-d", "github.com/lumapps/dep-check/dep_check/lib"],
29-
check=True,
30-
)
31-
run(
32-
[
33-
"go",
34-
"build",
35-
"-o",
36-
f"{self.lib_path}/go_parse.so",
37-
"-buildmode=c-shared",
38-
"$GOPATH/src/github.com/lumapps/dep-check/dep_check/lib/go_parse.go",
39-
],
40-
check=True,
41-
)
42-
environ["GOLIB"] = self.lib_path
43-
logging.info("GO lib go_parse.so built")
44-
45-
except CalledProcessError:
46-
logging.error(
47-
"Unable to build the GO lib from "
48-
"github.com/lumapps/dep-check/dep_check/lib"
49-
)
50-
raise
51-
52-
try:
53-
self.lib = cdll.LoadLibrary(f"{self.lib_path}/go_parse.so")
54-
# After building the lib, we try to load it again
55-
except OSError:
56-
logging.error("Error while loading the library. Please try again")
57-
raise
58-
59-
self.lib.FindDependencies.argtypes = [GoString]
60-
self.lib.FindDependencies.restype = GoString
61-
6231
def wildcard_to_regex(self, module: ModuleWildcard) -> str:
6332
"""
6433
Return a regex expression for the Module from wildcard
@@ -71,12 +40,10 @@ def wildcard_to_regex(self, module: ModuleWildcard) -> str:
7140
return module_regex
7241

7342
def find_dependencies(self, source_file: SourceFile) -> Dependencies:
74-
if source_file.code == "":
43+
if not source_file.code:
7544
return set()
76-
deps_string = self.lib.FindDependencies(
77-
GoString(source_file.code.encode(), len(source_file.code))
78-
)
79-
deps_list = deps_string.data.decode("utf-8").replace('"', "").split(";")[:-1]
45+
deps_string = goparse.find_dependencies(source_file.code)
46+
deps_list = deps_string.replace('"', "").split(";")[:-1]
8047

8148
dependecies: Dependencies = {Dependency(dep) for dep in deps_list}
8249
return dependecies

dep_check/lib/find_dependencies.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
// #cgo pkg-config: python3
4+
// #define Py_LIMITED_API
5+
// #include <Python.h>
6+
// int PyArg_ParseTuple_str(PyObject *, char **);
7+
// PyObject * Py_BuildValue_str(PyObject * args, char * src);
8+
import "C"
9+
10+
import (
11+
"fmt"
12+
"go/parser"
13+
"go/token"
14+
)
15+
16+
//export find_dependencies
17+
func find_dependencies(self, args *C.PyObject) *C.PyObject {
18+
var src *C.char
19+
if C.PyArg_ParseTuple_str(args, &src) == 0 {
20+
return nil
21+
}
22+
23+
fset := token.NewFileSet() // positions are relative to fset
24+
25+
// Parse src but stop after processing the imports.
26+
f, err := parser.ParseFile(fset, "", C.GoString(src), parser.ImportsOnly)
27+
if err != nil {
28+
fmt.Println(err)
29+
return nil
30+
}
31+
32+
// Print the imports from the file's AST.
33+
dependencies := ""
34+
for _, s := range f.Imports {
35+
dependencies += s.Path.Value + ";"
36+
}
37+
38+
return C.Py_BuildValue_str(self, C.CString(dependencies))
39+
}
40+
41+
func main() {}

dep_check/lib/go_parse.go

Lines changed: 0 additions & 31 deletions
This file was deleted.

dep_check/lib/goparse.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#define Py_LIMITED_API
2+
#include <Python.h>
3+
4+
PyObject * find_dependencies(PyObject *, PyObject *);
5+
6+
// Workaround missing variadic function support
7+
// https://github.com/golang/go/issues/975
8+
int PyArg_ParseTuple_str(PyObject * args, char ** src) {
9+
return PyArg_ParseTuple(args, "s", src);
10+
}
11+
12+
static PyMethodDef GoParseMethods[] = {
13+
{"find_dependencies", find_dependencies, METH_VARARGS, "Parses a file and returns its dependencies."},
14+
{NULL, NULL, 0, NULL}
15+
};
16+
17+
static struct PyModuleDef goparsemodule = {
18+
PyModuleDef_HEAD_INIT, "goparse", NULL, -1, GoParseMethods
19+
};
20+
21+
PyObject * Py_BuildValue_str(PyObject * args, char * src) {
22+
return Py_BuildValue("s", src);
23+
}
24+
25+
PyMODINIT_FUNC
26+
PyInit_goparse(void)
27+
{
28+
return PyModule_Create(&goparsemodule);
29+
}

dep_check/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ def main(self) -> int:
136136
self.create_app_configuration()
137137
try:
138138
use_case = DEP_CHECK_FEATURES[self.feature].use_case_factory(self)
139-
use_case.run()
140-
139+
code = use_case.run()
141140
except KeyError:
142141
raise MissingOptionError()
143142

dependency_config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ dependency_rules:
1414
dep_check.infra.std_lib_filter:
1515
- dep_check.use_cases.interfaces
1616

17+
dep_check.infra.go_parser:
18+
- dep_check.lib.goparse
19+
1720
dep_check.use_cases%:
1821
- dep_check.use_cases.app_configuration
1922
- dep_check.use_cases.interfaces

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,6 @@ known_third_party=flask,google,marshmallow,sqlalchemy,yaml,structlog
5555
line_length=88
5656
multi_line_output=3
5757
use_parentheses=True
58+
59+
[mypy-dep_check.lib]
60+
ignore_missing_imports = True

0 commit comments

Comments
 (0)