aboutsummaryrefslogtreecommitdiffstats
path: root/build/scripts/go_proto_wrapper.py
blob: 8f2a6130e05e2c5dda57a7adf7d317066b99e582 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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))