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 | |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 17 | |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 18 | def get_go_version(go_root): |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 19 | # Returns version of the installed Go |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 20 | 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 |
| 31 | def 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 |
| 44 | def 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 Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 51 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 55 | print("Go binary not found, installing the latest version...") |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 56 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 64 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 69 | 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 |
| 85 | def install_binapi_gen(c, go_root, go_path): |
| 86 | os.environ['GO111MODULE'] = "on" |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 87 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 91 | 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 Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 97 | print("binapi generator installation failed: %d %s" % |
| 98 | (p.returncode, error)) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 99 | 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 Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 105 | def generate_api(output_dir, vpp_dir, api_list, import_prefix, |
| 106 | no_source, go_path): |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 107 | 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 Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 114 | cmd = ["./binapi-generator", "--input-dir=" + json_dir] |
| 115 | if output_dir: |
| 116 | cmd += ["--output-dir=" + output_dir] |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 117 | if len(api_list): |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 118 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 122 | cmd.append(api_list) |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 123 | if import_prefix: |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 124 | 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 Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 144 | print("Go API bindings were generated to " + output_dir) |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 145 | |
| 146 | |
| 147 | def main(): |
| 148 | # project root directory |
| 149 | root = pathlib.Path(os.path.dirname(os.path.abspath(__file__))) |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 150 | vpp_dir = root.parent.parent.parent |
Vladimir Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 151 | |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 152 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 177 | |
| 178 | # go specific environment variables |
| 179 | if "GOROOT" in os.environ: |
| 180 | go_root = os.environ['GOROOT'] |
| 181 | else: |
Nathan Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 182 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 188 | 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 Skrzypczak | d591b82 | 2022-03-10 12:38:31 +0100 | [diff] [blame] | 194 | 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 Lavor | 3ff1598 | 2021-04-08 13:08:04 +0200 | [diff] [blame] | 197 | |
| 198 | |
| 199 | if __name__ == "__main__": |
| 200 | main() |