Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import argparse |
| 4 | import os |
| 5 | import pathlib |
| 6 | import subprocess |
| 7 | import tarfile |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 8 | import shutil |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 9 | |
| 10 | import requests |
| 11 | import sys |
| 12 | |
| 13 | # |
| 14 | # GoVPP API generator generates Go bindings compatible with the local VPP |
| 15 | # |
| 16 | |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 17 | DefaultGoVppCommit = "16a47ef937b3a5ce6acf45885386062b323c8d25" |
| 18 | |
| 19 | |
| 20 | def version_geq(ver_a, ver_b): |
| 21 | major_a, minor_a, patch_a = ver_a.split(".") |
| 22 | major_b, minor_b, patch_b = ver_b.split(".") |
| 23 | if major_a > major_b: |
| 24 | return True |
| 25 | elif major_a == major_b and minor_a > minor_b: |
| 26 | return True |
| 27 | elif major_a == major_b and minor_a == minor_b and patch_a >= patch_b: |
| 28 | return True |
| 29 | return False |
| 30 | |
| 31 | |
| 32 | def execute(cli, cwd=None): |
| 33 | p = subprocess.Popen( |
| 34 | cli.split(), |
| 35 | cwd=cwd, |
| 36 | stdout=subprocess.PIPE, |
| 37 | stderr=subprocess.PIPE, |
| 38 | universal_newlines=True, |
| 39 | ) |
| 40 | output, error = p.communicate() |
| 41 | if p.returncode != 0: |
| 42 | print("Command `%s` failed: %d %s" % (cli, p.returncode, error)) |
| 43 | sys.exit(1) |
| 44 | return output, error |
| 45 | |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 46 | |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 47 | def get_go_version(go_root): |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 48 | # Returns version of the installed Go |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 49 | output, _ = execute("./go version", cwd=go_root + "/bin") |
| 50 | return output.replace("go version go", "", 1).rstrip("\n") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 51 | |
| 52 | |
| 53 | # Returns version of the installed binary API generator |
| 54 | def get_binapi_gen_version(go_path): |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 55 | output, _ = execute("./binapi-generator -version", cwd=go_path + "/bin") |
| 56 | return output.replace("govpp", "", 1).rstrip("\n") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 57 | |
| 58 | |
| 59 | # Verifies local Go installation and installs the latest |
| 60 | # one if missing |
| 61 | def install_golang(go_root): |
| 62 | go_bin = go_root + "/bin/go" |
| 63 | |
| 64 | if os.path.exists(go_bin) and os.path.isfile(go_bin): |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 65 | print("Go " + get_go_version(go_root) + " is already installed") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 66 | return |
| 67 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 68 | filename = ( |
| 69 | requests.get("https://golang.org/VERSION?m=text").text + ".linux-amd64.tar.gz" |
| 70 | ) |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 71 | url = "https://dl.google.com/go/" + filename |
| 72 | |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 73 | print("Go binary not found, installing the latest version...") |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 74 | print("Download url = %s" % url) |
| 75 | print("Install directory = %s" % go_root) |
| 76 | text = input("[Y/n] ?") |
| 77 | |
| 78 | if text.strip().lower() != "y" and text.strip().lower() != "yes": |
| 79 | print("Aborting...") |
| 80 | exit(1) |
| 81 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 82 | go_folders = ["src", "pkg", "bin"] |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 83 | |
| 84 | for f in go_folders: |
| 85 | if not os.path.exists(os.path.join(go_root, f)): |
| 86 | os.makedirs(os.path.join(go_root, f)) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 87 | r = requests.get(url) |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 88 | with open("/tmp/" + filename, "wb") as f: |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 89 | f.write(r.content) |
| 90 | |
| 91 | go_tf = tarfile.open("/tmp/" + filename) |
| 92 | # Strip /go dir from the go_root path as it will |
| 93 | # be created while extracting the tar file |
| 94 | go_root_head, _ = os.path.split(go_root) |
| 95 | go_tf.extractall(path=go_root_head) |
| 96 | go_tf.close() |
| 97 | os.remove("/tmp/" + filename) |
| 98 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 99 | print("Go " + get_go_version(go_root) + " was installed") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 100 | |
| 101 | |
| 102 | # Installs latest binary API generator |
| 103 | def install_binapi_gen(c, go_root, go_path): |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 104 | go_version = get_go_version(go_root) |
| 105 | if version_geq(go_version, "1.18.0"): |
| 106 | execute( |
| 107 | "./go install git.fd.io/govpp.git/cmd/binapi-generator@" + c, |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 108 | cwd=go_root + "/bin", |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 109 | ) |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 110 | else: |
| 111 | os.environ["GO111MODULE"] = "on" |
| 112 | execute( |
| 113 | "./go get git.fd.io/govpp.git/cmd/binapi-generator@" + c, |
| 114 | cwd=go_root + "/bin", |
| 115 | ) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 116 | bg_ver = get_binapi_gen_version(go_path) |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 117 | print("Installed binary API generator " + bg_ver) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 118 | |
| 119 | |
| 120 | # Creates generated bindings using GoVPP binapigen to the target folder |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 121 | def generate_api(output_dir, vpp_dir, api_list, import_prefix, no_source, go_path): |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 122 | json_dir = vpp_dir + "/build-root/install-vpp-native/vpp/share/vpp/api" |
| 123 | |
| 124 | if not os.path.exists(json_dir): |
| 125 | print("Missing JSON api definitions") |
| 126 | sys.exit(1) |
| 127 | |
| 128 | print("Generating API") |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 129 | cmd = ["./binapi-generator", "--input-dir=" + json_dir] |
| 130 | if output_dir: |
| 131 | cmd += ["--output-dir=" + output_dir] |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 132 | if len(api_list): |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 133 | print("Following API files were requested by 'GO_API_FILES': " + str(api_list)) |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 134 | print("Note that dependency requirements may generate additional API files") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 135 | cmd.append(api_list) |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 136 | if import_prefix: |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 137 | cmd.append("-import-prefix=" + import_prefix) |
| 138 | if no_source: |
| 139 | cmd.append("-no-source-path-info") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 140 | |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 141 | _, out = execute(" ".join(cmd), cwd=go_path + "/bin") |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 142 | # Print nice output of the binapi generator |
| 143 | for msg in out.split(): |
| 144 | if "=" in msg: |
| 145 | print() |
| 146 | print(msg, end=" ") |
| 147 | |
| 148 | print("\n") |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 149 | print("Go API bindings were generated to " + output_dir) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 150 | |
| 151 | |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 152 | def get_go_variables(): |
| 153 | # go specific environment variables |
| 154 | if "GOROOT" in os.environ: |
| 155 | go_root = os.environ["GOROOT"] |
| 156 | else: |
| 157 | go_binary = shutil.which("go") |
| 158 | if go_binary != "": |
| 159 | go_binary_dir, _ = os.path.split(go_binary) |
| 160 | go_root = os.path.join(go_binary_dir, "..") |
| 161 | else: |
| 162 | go_root = os.environ["HOME"] + "/.go" |
| 163 | if "GOPATH" in os.environ: |
| 164 | go_path = os.environ["GOPATH"] |
| 165 | else: |
| 166 | go_path = os.environ["HOME"] + "/go" |
| 167 | |
| 168 | return go_root, go_path |
| 169 | |
| 170 | |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 171 | def main(): |
| 172 | # project root directory |
| 173 | root = pathlib.Path(os.path.dirname(os.path.abspath(__file__))) |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 174 | vpp_dir = root.parent.parent.parent |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 175 | |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 176 | parser = argparse.ArgumentParser() |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 177 | parser.add_argument( |
| 178 | "-govpp-commit", |
| 179 | "--govpp-commit", |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 180 | help="GoVPP commit or branch ", |
| 181 | default=DefaultGoVppCommit, |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 182 | type=str, |
| 183 | ) |
| 184 | parser.add_argument( |
| 185 | "-output-dir", |
| 186 | "--output-dir", |
| 187 | help="output target directory for generated bindings", |
| 188 | type=str, |
| 189 | default=os.path.join(vpp_dir, "vppbinapi"), |
| 190 | ) |
| 191 | parser.add_argument( |
| 192 | "-api-files", |
| 193 | "--api-files", |
| 194 | help="api files to generate (without commas)", |
| 195 | nargs="+", |
| 196 | type=str, |
| 197 | default=[], |
| 198 | ) |
| 199 | parser.add_argument( |
| 200 | "-import-prefix", |
| 201 | "--import-prefix", |
| 202 | help="prefix imports in the generated go code", |
| 203 | default="", |
| 204 | type=str, |
| 205 | ) |
| 206 | parser.add_argument( |
| 207 | "-no-source-path-info", |
| 208 | "--no-source-path-info", |
| 209 | help="disable source path info in generated files", |
| 210 | nargs="?", |
| 211 | const=True, |
| 212 | default=True, |
| 213 | ) |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 214 | args = parser.parse_args() |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 215 | |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 216 | go_root, go_path = get_go_variables() |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 217 | install_golang(go_root) |
Nathan Skrzypczak | 78d24f3 | 2022-05-18 13:46:24 +0200 | [diff] [blame] | 218 | |
| 219 | if not ( |
| 220 | os.path.exists(go_root + "/bin/go") and os.path.isfile(go_root + "/bin/go") |
| 221 | ): |
| 222 | print(go_root + "/bin/go does not exist") |
| 223 | sys.exit(1) |
| 224 | |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 225 | install_binapi_gen(args.govpp_commit, go_root, go_path) |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 226 | generate_api( |
| 227 | args.output_dir, |
| 228 | str(vpp_dir), |
| 229 | args.api_files, |
| 230 | args.import_prefix, |
| 231 | args.no_source_path_info, |
| 232 | go_path, |
| 233 | ) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 234 | |
| 235 | |
| 236 | if __name__ == "__main__": |
| 237 | main() |