from __future__ import absolute_import, unicode_literals import argparse import os import re import shutil import subprocess import sys import tempfile OUT_DIR_FLAG_PATTERN = re.compile(r'^(--go(([-_]\w+))*_out=)') def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--arcadia-prefix', required=True) parser.add_argument('--check', nargs='?', default=None) parser.add_argument('--contrib-prefix', required=True) parser.add_argument('--namespace', required=True) parser.add_argument('--proto', required=True) parser.add_argument('args', nargs='+') return parser.parse_args() def move_tree(src_root, dst_root): for root, _, files in os.walk(src_root): rel_dir = os.path.relpath(root, src_root) dst_dir = os.path.join(dst_root, rel_dir) if not os.path.exists(dst_dir): os.mkdir(dst_dir) for file in files: os.rename(os.path.join(root, file), os.path.join(dst_dir, file)) def main(args): arcadia_prefix = args.arcadia_prefix contrib_prefix = args.contrib_prefix proto_namespace = args.namespace check_output = args.check proto_file = args.proto args = list(args.args) args.append(proto_file) out_dir_orig = None out_dir_temp = None for i in range(len(args)): m = re.match(OUT_DIR_FLAG_PATTERN, args[i]) if m: out_dir_flag = m.group(1) index = len(out_dir_flag) index = max(index, args[i].find(':', index) + 1) out_dir = args[i][index:] if out_dir_orig: assert out_dir_orig == out_dir, 'Output directories do not match: [{}] and [{}]'.format( out_dir_orig, out_dir ) else: out_dir_orig = out_dir out_dir_temp = tempfile.mkdtemp(dir=out_dir_orig) args[i] = (args[i][:index] + out_dir_temp).replace('|', ',') assert out_dir_temp is not None, 'Output directory is not specified' try: subprocess.check_output(args, stdin=None, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: sys.stderr.write( '{} returned non-zero exit code {}.\n{}\n'.format(' '.join(e.cmd), e.returncode, e.output.decode('utf-8', errors='ignore')) ) return e.returncode # All Arcadia GO projects should have 'a.yandex-team.ru/' namespace prefix. # If the namespace doesn't start with 'a.yandex-team.ru/' prefix then this # project is from vendor directory under the root of Arcadia. out_dir_src = os.path.normpath(os.path.join(out_dir_temp, arcadia_prefix, proto_namespace)) out_dir_dst = out_dir_orig if not os.path.isdir(out_dir_src): out_dir_src = out_dir_temp out_dir_dst = os.path.join(out_dir_orig, contrib_prefix) move_tree(out_dir_src, out_dir_dst) if check_output and not os.path.exists(check_output): package_name = None option_re = re.compile(r'^\s*option\s+go_package\s*=\s*"([^"]+)"') with open(proto_file, 'r') as f: for line in f: m = re.match(option_re, line) if m: package_name = m.group(1).split(';')[-1].split('/')[-1] break with open(check_output, 'w') as fout: fout.write( '// Code generated by go_proto_wrapper.py script. DO NOT EDIT.\n\npackage {}\n'.format(package_name) ) shutil.rmtree(out_dir_temp) return 0 if __name__ == '__main__': args = parse_args() sys.exit(main(args))