diff options
Diffstat (limited to 'src/tools/vppapigen/generate_go.py')
-rwxr-xr-x | src/tools/vppapigen/generate_go.py | 236 |
1 files changed, 145 insertions, 91 deletions
diff --git a/src/tools/vppapigen/generate_go.py b/src/tools/vppapigen/generate_go.py index 1e072ef1e1c..4ed507b5d73 100755 --- a/src/tools/vppapigen/generate_go.py +++ b/src/tools/vppapigen/generate_go.py @@ -5,6 +5,7 @@ import os import pathlib import subprocess import tarfile +import shutil import requests import sys @@ -13,58 +14,46 @@ import sys # GoVPP API generator generates Go bindings compatible with the local VPP # -parser = argparse.ArgumentParser() -parser.add_argument("-govpp-commit", help="GoVPP commit or branch (defaults to v0.3.5-45-g671f16c)", - default="671f16c", # fixed GoVPP version - type=str) -parser.add_argument("-output-dir", help="output target directory for generated bindings", type=str) -parser.add_argument("-api-files", help="api files to generate (without commas)", nargs="+", type=str) -parser.add_argument("-import-prefix", help="prefix imports in the generated go code", type=str) -parser.add_argument("-no-source-path-info", help="disable source path info in generated files", nargs='?', const=True, - default=False) -args = parser.parse_args() - - -# Check input arguments -def validate_args(vpp_dir, o, f, c, i): - if o is not None: - if not os.path.exists(o) or os.path.isfile(o): - print(o + " is not a valid output path") - sys.exit(1) - else: - o = vpp_dir - if f is None: - f = [] - if c is None: - c = "671f16c" - if i is None: - i = "" - - return str(o), f, c, i +DefaultGoVppCommit = "16a47ef937b3a5ce6acf45885386062b323c8d25" + + +def version_geq(ver_a, ver_b): + major_a, minor_a, patch_a = ver_a.split(".") + major_b, minor_b, patch_b = ver_b.split(".") + if major_a > major_b: + return True + elif major_a == major_b and minor_a > minor_b: + return True + elif major_a == major_b and minor_a == minor_b and patch_a >= patch_b: + return True + return False + + +def execute(cli, cwd=None): + p = subprocess.Popen( + cli.split(), + cwd=cwd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + output, error = p.communicate() + if p.returncode != 0: + print("Command `%s` failed: %d %s" % (cli, p.returncode, error)) + sys.exit(1) + return output, error -# Returns version of the installed Go def get_go_version(go_root): - p = subprocess.Popen(["./go", "version"], - cwd=go_root + "/bin", - stdout=subprocess.PIPE, - universal_newlines=True, ) - output, _ = p.communicate() - output_fmt = output.replace("go version go", "", 1) - - return output_fmt.rstrip("\n") + # Returns version of the installed Go + output, _ = execute("./go version", cwd=go_root + "/bin") + return output.replace("go version go", "", 1).rstrip("\n") # Returns version of the installed binary API generator def get_binapi_gen_version(go_path): - p = subprocess.Popen(["./binapi-generator", "-version"], - cwd=go_path + "/bin", - stdout=subprocess.PIPE, - universal_newlines=True, ) - output, _ = p.communicate() - output_fmt = output.replace("govpp", "", 1) - - return output_fmt.rstrip("\n") + output, _ = execute("./binapi-generator -version", cwd=go_path + "/bin") + return output.replace("govpp", "", 1).rstrip("\n") # Verifies local Go installation and installs the latest @@ -73,20 +62,30 @@ def install_golang(go_root): go_bin = go_root + "/bin/go" if os.path.exists(go_bin) and os.path.isfile(go_bin): - print('Go ' + get_go_version(go_root) + ' is already installed') + print("Go " + get_go_version(go_root) + " is already installed") return + filename = ( + requests.get("https://golang.org/VERSION?m=text").text + ".linux-amd64.tar.gz" + ) + url = "https://dl.google.com/go/" + filename + print("Go binary not found, installing the latest version...") - go_folders = ['src', 'pkg', 'bin'] + print("Download url = %s" % url) + print("Install directory = %s" % go_root) + text = input("[Y/n] ?") + + if text.strip().lower() != "y" and text.strip().lower() != "yes": + print("Aborting...") + exit(1) + + go_folders = ["src", "pkg", "bin"] for f in go_folders: if not os.path.exists(os.path.join(go_root, f)): os.makedirs(os.path.join(go_root, f)) - - filename = requests.get('https://golang.org/VERSION?m=text').text + ".linux-amd64.tar.gz" - url = "https://dl.google.com/go/" + filename r = requests.get(url) - with open("/tmp/" + filename, 'wb') as f: + with open("/tmp/" + filename, "wb") as f: f.write(r.content) go_tf = tarfile.open("/tmp/" + filename) @@ -97,29 +96,29 @@ def install_golang(go_root): go_tf.close() os.remove("/tmp/" + filename) - print('Go ' + get_go_version(go_root) + ' was installed') + print("Go " + get_go_version(go_root) + " was installed") # Installs latest binary API generator def install_binapi_gen(c, go_root, go_path): - os.environ['GO111MODULE'] = "on" - if os.path.exists(go_root + "/bin/go") & os.path.isfile(go_root + "/bin/go"): - p = subprocess.Popen(["./go", "get", "git.fd.io/govpp.git/cmd/binapi-generator@" + c], - cwd=go_root + "/bin", - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, ) - _, error = p.communicate() - if p.returncode != 0: - print("binapi generator installation failed: %d %s" % (p.returncode, error)) - sys.exit(1) + go_version = get_go_version(go_root) + if version_geq(go_version, "1.18.0"): + execute( + "./go install git.fd.io/govpp.git/cmd/binapi-generator@" + c, + cwd=go_root + "/bin", + ) + else: + os.environ["GO111MODULE"] = "on" + execute( + "./go get git.fd.io/govpp.git/cmd/binapi-generator@" + c, + cwd=go_root + "/bin", + ) bg_ver = get_binapi_gen_version(go_path) - print('Installed binary API generator ' + bg_ver) + print("Installed binary API generator " + bg_ver) # Creates generated bindings using GoVPP binapigen to the target folder def generate_api(output_dir, vpp_dir, api_list, import_prefix, no_source, go_path): - output_binapi = output_dir + "binapi" if output_dir[-1] == "/" else output_dir + "/binapi" json_dir = vpp_dir + "/build-root/install-vpp-native/vpp/share/vpp/api" if not os.path.exists(json_dir): @@ -127,25 +126,19 @@ def generate_api(output_dir, vpp_dir, api_list, import_prefix, no_source, go_pat sys.exit(1) print("Generating API") - cmd = ["./binapi-generator", "--output-dir=" + output_binapi, "--input-dir=" + json_dir] + cmd = ["./binapi-generator", "--input-dir=" + json_dir] + if output_dir: + cmd += ["--output-dir=" + output_dir] if len(api_list): print("Following API files were requested by 'GO_API_FILES': " + str(api_list)) print("Note that dependency requirements may generate additional API files") cmd.append(api_list) - if not import_prefix == "": + if import_prefix: cmd.append("-import-prefix=" + import_prefix) if no_source: cmd.append("-no-source-path-info") - p = subprocess.Popen(cmd, cwd=go_path + "/bin", - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, ) - - out = p.communicate()[1] - if p.returncode != 0: - print("go api generate failed: %d %s" % (p.returncode, out)) - sys.exit(1) + _, out = execute(" ".join(cmd), cwd=go_path + "/bin") # Print nice output of the binapi generator for msg in out.split(): if "=" in msg: @@ -153,30 +146,91 @@ def generate_api(output_dir, vpp_dir, api_list, import_prefix, no_source, go_pat print(msg, end=" ") print("\n") - print("Go API bindings were generated to " + output_binapi) + print("Go API bindings were generated to " + output_dir) -def main(): - # project root directory - root = pathlib.Path(os.path.dirname(os.path.abspath(__file__))) - vpp_dir: str = root.parent.parent.parent - - o, f, c, i = validate_args(vpp_dir, args.output_dir, args.api_files, args.govpp_commit, - args.import_prefix) - +def get_go_variables(): # go specific environment variables if "GOROOT" in os.environ: - go_root = os.environ['GOROOT'] + go_root = os.environ["GOROOT"] else: - go_root = os.environ['HOME'] + "/.go" + go_binary = shutil.which("go") + if go_binary != "": + go_binary_dir, _ = os.path.split(go_binary) + go_root = os.path.join(go_binary_dir, "..") + else: + go_root = os.environ["HOME"] + "/.go" if "GOPATH" in os.environ: - go_path = os.environ['GOPATH'] + go_path = os.environ["GOPATH"] else: - go_path = os.environ['HOME'] + "/go" + go_path = os.environ["HOME"] + "/go" + + return go_root, go_path + +def main(): + # project root directory + root = pathlib.Path(os.path.dirname(os.path.abspath(__file__))) + vpp_dir = root.parent.parent.parent + + parser = argparse.ArgumentParser() + parser.add_argument( + "-govpp-commit", + "--govpp-commit", + help="GoVPP commit or branch ", + default=DefaultGoVppCommit, + type=str, + ) + parser.add_argument( + "-output-dir", + "--output-dir", + help="output target directory for generated bindings", + type=str, + default=os.path.join(vpp_dir, "vppbinapi"), + ) + parser.add_argument( + "-api-files", + "--api-files", + help="api files to generate (without commas)", + nargs="+", + type=str, + default=[], + ) + parser.add_argument( + "-import-prefix", + "--import-prefix", + help="prefix imports in the generated go code", + default="", + type=str, + ) + parser.add_argument( + "-no-source-path-info", + "--no-source-path-info", + help="disable source path info in generated files", + nargs="?", + const=True, + default=True, + ) + args = parser.parse_args() + + go_root, go_path = get_go_variables() install_golang(go_root) - install_binapi_gen(c, go_root, go_path) - generate_api(o, str(vpp_dir), f, i, args.no_source_path_info, go_path) + + if not ( + os.path.exists(go_root + "/bin/go") and os.path.isfile(go_root + "/bin/go") + ): + print(go_root + "/bin/go does not exist") + sys.exit(1) + + install_binapi_gen(args.govpp_commit, go_root, go_path) + generate_api( + args.output_dir, + str(vpp_dir), + args.api_files, + args.import_prefix, + args.no_source_path_info, + go_path, + ) if __name__ == "__main__": |