blob: 1fb53c715e2262b9b1eaf63388e06fecd45a1b05 [file] [log] [blame]
Vladimir Lavor3ff15982021-04-08 13:08:04 +02001#!/usr/bin/env python3
2
3import argparse
4import os
5import pathlib
6import subprocess
7import tarfile
Nathan Skrzypczakd591b822022-03-10 12:38:31 +01008import shutil
Vladimir Lavor3ff15982021-04-08 13:08:04 +02009
10import requests
11import sys
12
13#
14# GoVPP API generator generates Go bindings compatible with the local VPP
15#
16
Vladimir Lavor3ff15982021-04-08 13:08:04 +020017
Vladimir Lavor3ff15982021-04-08 13:08:04 +020018def get_go_version(go_root):
Nathan Skrzypczakd591b822022-03-10 12:38:31 +010019 # Returns version of the installed Go
Vladimir Lavor3ff15982021-04-08 13:08:04 +020020 p = subprocess.Popen(["./go", "version"],
21 cwd=go_root + "/bin",
22 stdout=subprocess.PIPE,
23 universal_newlines=True, )
24 output, _ = p.communicate()
25 output_fmt = output.replace("go version go", "", 1)
26
27 return output_fmt.rstrip("\n")
28
29
30# Returns version of the installed binary API generator
31def get_binapi_gen_version(go_path):
32 p = subprocess.Popen(["./binapi-generator", "-version"],
33 cwd=go_path + "/bin",
34 stdout=subprocess.PIPE,
35 universal_newlines=True, )
36 output, _ = p.communicate()
37 output_fmt = output.replace("govpp", "", 1)
38
39 return output_fmt.rstrip("\n")
40
41
42# Verifies local Go installation and installs the latest
43# one if missing
44def install_golang(go_root):
45 go_bin = go_root + "/bin/go"
46
47 if os.path.exists(go_bin) and os.path.isfile(go_bin):
48 print('Go ' + get_go_version(go_root) + ' is already installed')
49 return
50
Nathan Skrzypczakd591b822022-03-10 12:38:31 +010051 filename = requests.get(
52 'https://golang.org/VERSION?m=text').text + ".linux-amd64.tar.gz"
53 url = "https://dl.google.com/go/" + filename
54
Vladimir Lavor3ff15982021-04-08 13:08:04 +020055 print("Go binary not found, installing the latest version...")
Nathan Skrzypczakd591b822022-03-10 12:38:31 +010056 print("Download url = %s" % url)
57 print("Install directory = %s" % go_root)
58 text = input("[Y/n] ?")
59
60 if text.strip().lower() != "y" and text.strip().lower() != "yes":
61 print("Aborting...")
62 exit(1)
63
Vladimir Lavor3ff15982021-04-08 13:08:04 +020064 go_folders = ['src', 'pkg', 'bin']
65
66 for f in go_folders:
67 if not os.path.exists(os.path.join(go_root, f)):
68 os.makedirs(os.path.join(go_root, f))
Vladimir Lavor3ff15982021-04-08 13:08:04 +020069 r = requests.get(url)
70 with open("/tmp/" + filename, 'wb') as f:
71 f.write(r.content)
72
73 go_tf = tarfile.open("/tmp/" + filename)
74 # Strip /go dir from the go_root path as it will
75 # be created while extracting the tar file
76 go_root_head, _ = os.path.split(go_root)
77 go_tf.extractall(path=go_root_head)
78 go_tf.close()
79 os.remove("/tmp/" + filename)
80
81 print('Go ' + get_go_version(go_root) + ' was installed')
82
83
84# Installs latest binary API generator
85def install_binapi_gen(c, go_root, go_path):
86 os.environ['GO111MODULE'] = "on"
Nathan Skrzypczakd591b822022-03-10 12:38:31 +010087 if (os.path.exists(go_root + "/bin/go") and
88 os.path.isfile(go_root + "/bin/go")):
89 p = subprocess.Popen(["./go", "get",
90 "git.fd.io/govpp.git/cmd/binapi-generator@" + c],
Vladimir Lavor3ff15982021-04-08 13:08:04 +020091 cwd=go_root + "/bin",
92 stdout=subprocess.PIPE,
93 stderr=subprocess.PIPE,
94 universal_newlines=True, )
95 _, error = p.communicate()
96 if p.returncode != 0:
Nathan Skrzypczakd591b822022-03-10 12:38:31 +010097 print("binapi generator installation failed: %d %s" %
98 (p.returncode, error))
Vladimir Lavor3ff15982021-04-08 13:08:04 +020099 sys.exit(1)
100 bg_ver = get_binapi_gen_version(go_path)
101 print('Installed binary API generator ' + bg_ver)
102
103
104# Creates generated bindings using GoVPP binapigen to the target folder
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100105def generate_api(output_dir, vpp_dir, api_list, import_prefix,
106 no_source, go_path):
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200107 json_dir = vpp_dir + "/build-root/install-vpp-native/vpp/share/vpp/api"
108
109 if not os.path.exists(json_dir):
110 print("Missing JSON api definitions")
111 sys.exit(1)
112
113 print("Generating API")
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100114 cmd = ["./binapi-generator", "--input-dir=" + json_dir]
115 if output_dir:
116 cmd += ["--output-dir=" + output_dir]
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200117 if len(api_list):
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100118 print("Following API files were requested by 'GO_API_FILES': " +
119 str(api_list))
120 print("Note that dependency requirements may generate "
121 "additional API files")
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200122 cmd.append(api_list)
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100123 if import_prefix:
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200124 cmd.append("-import-prefix=" + import_prefix)
125 if no_source:
126 cmd.append("-no-source-path-info")
127 p = subprocess.Popen(cmd, cwd=go_path + "/bin",
128 stdout=subprocess.PIPE,
129 stderr=subprocess.PIPE,
130 universal_newlines=True, )
131
132 out = p.communicate()[1]
133 if p.returncode != 0:
134 print("go api generate failed: %d %s" % (p.returncode, out))
135 sys.exit(1)
136
137 # Print nice output of the binapi generator
138 for msg in out.split():
139 if "=" in msg:
140 print()
141 print(msg, end=" ")
142
143 print("\n")
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100144 print("Go API bindings were generated to " + output_dir)
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200145
146
147def main():
148 # project root directory
149 root = pathlib.Path(os.path.dirname(os.path.abspath(__file__)))
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100150 vpp_dir = root.parent.parent.parent
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200151
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100152 parser = argparse.ArgumentParser()
153 parser.add_argument("-govpp-commit", "--govpp-commit",
154 help="GoVPP commit or branch "
155 "(defaults to v0.3.5-45-g671f16c)",
156 default="671f16c", # fixed GoVPP version
157 type=str)
158 parser.add_argument("-output-dir", "--output-dir",
159 help="output target directory for generated bindings",
160 type=str,
161 default=os.path.join(vpp_dir, "vppbinapi"))
162 parser.add_argument("-api-files", "--api-files",
163 help="api files to generate (without commas)",
164 nargs="+",
165 type=str,
166 default=[])
167 parser.add_argument("-import-prefix", "--import-prefix",
168 help="prefix imports in the generated go code",
169 default="",
170 type=str)
171 parser.add_argument("-no-source-path-info", "--no-source-path-info",
172 help="disable source path info in generated files",
173 nargs='?',
174 const=True,
175 default=True)
176 args = parser.parse_args()
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200177
178 # go specific environment variables
179 if "GOROOT" in os.environ:
180 go_root = os.environ['GOROOT']
181 else:
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100182 go_binary = shutil.which("go")
183 if go_binary != "":
184 go_binary_dir, _ = os.path.split(go_binary)
185 go_root = os.path.join(go_binary_dir, "..")
186 else:
187 go_root = os.environ['HOME'] + "/.go"
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200188 if "GOPATH" in os.environ:
189 go_path = os.environ['GOPATH']
190 else:
191 go_path = os.environ['HOME'] + "/go"
192
193 install_golang(go_root)
Nathan Skrzypczakd591b822022-03-10 12:38:31 +0100194 install_binapi_gen(args.govpp_commit, go_root, go_path)
195 generate_api(args.output_dir, str(vpp_dir), args.api_files,
196 args.import_prefix, args.no_source_path_info, go_path)
Vladimir Lavor3ff15982021-04-08 13:08:04 +0200197
198
199if __name__ == "__main__":
200 main()