go_proto_wrapper.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. from __future__ import absolute_import, unicode_literals
  2. import argparse
  3. import os
  4. import re
  5. import shutil
  6. import subprocess
  7. import sys
  8. import tempfile
  9. OUT_DIR_FLAG_PATTERN = re.compile(r'^(--go(([-_]\w+))*_out=)')
  10. def parse_args():
  11. parser = argparse.ArgumentParser()
  12. parser.add_argument('--arcadia-prefix', required=True)
  13. parser.add_argument('--check', nargs='?', default=None)
  14. parser.add_argument('--contrib-prefix', required=True)
  15. parser.add_argument('--namespace', required=True)
  16. parser.add_argument('--proto', required=True)
  17. parser.add_argument('args', nargs='+')
  18. return parser.parse_args()
  19. def move_tree(src_root, dst_root):
  20. for root, _, files in os.walk(src_root):
  21. rel_dir = os.path.relpath(root, src_root)
  22. dst_dir = os.path.join(dst_root, rel_dir)
  23. if not os.path.exists(dst_dir):
  24. os.mkdir(dst_dir)
  25. for file in files:
  26. os.rename(os.path.join(root, file), os.path.join(dst_dir, file))
  27. def main(args):
  28. arcadia_prefix = args.arcadia_prefix
  29. contrib_prefix = args.contrib_prefix
  30. proto_namespace = args.namespace
  31. check_output = args.check
  32. proto_file = args.proto
  33. args = list(args.args)
  34. args.append(proto_file)
  35. out_dir_orig = None
  36. out_dir_temp = None
  37. for i in range(len(args)):
  38. m = re.match(OUT_DIR_FLAG_PATTERN, args[i])
  39. if m:
  40. out_dir_flag = m.group(1)
  41. index = len(out_dir_flag)
  42. index = max(index, args[i].find(':', index) + 1)
  43. out_dir = args[i][index:]
  44. if out_dir_orig:
  45. assert out_dir_orig == out_dir, 'Output directories do not match: [{}] and [{}]'.format(
  46. out_dir_orig, out_dir
  47. )
  48. else:
  49. out_dir_orig = out_dir
  50. out_dir_temp = tempfile.mkdtemp(dir=out_dir_orig)
  51. args[i] = (args[i][:index] + out_dir_temp).replace('|', ',')
  52. assert out_dir_temp is not None, 'Output directory is not specified'
  53. try:
  54. subprocess.check_output(args, stdin=None, stderr=subprocess.STDOUT)
  55. except subprocess.CalledProcessError as e:
  56. sys.stderr.write(
  57. '{} returned non-zero exit code {}.\n{}\n'.format(' '.join(e.cmd), e.returncode, e.output.decode('utf-8', errors='ignore'))
  58. )
  59. return e.returncode
  60. # All Arcadia GO projects should have 'a.yandex-team.ru/' namespace prefix.
  61. # If the namespace doesn't start with 'a.yandex-team.ru/' prefix then this
  62. # project is from vendor directory under the root of Arcadia.
  63. out_dir_src = os.path.normpath(os.path.join(out_dir_temp, arcadia_prefix, proto_namespace))
  64. out_dir_dst = out_dir_orig
  65. if not os.path.isdir(out_dir_src):
  66. out_dir_src = out_dir_temp
  67. out_dir_dst = os.path.join(out_dir_orig, contrib_prefix)
  68. move_tree(out_dir_src, out_dir_dst)
  69. if check_output and not os.path.exists(check_output):
  70. package_name = None
  71. option_re = re.compile(r'^\s*option\s+go_package\s*=\s*"([^"]+)"')
  72. with open(proto_file, 'r') as f:
  73. for line in f:
  74. m = re.match(option_re, line)
  75. if m:
  76. package_name = m.group(1).split(';')[-1].split('/')[-1]
  77. break
  78. with open(check_output, 'w') as fout:
  79. fout.write(
  80. '// Code generated by go_proto_wrapper.py script. DO NOT EDIT.\n\npackage {}\n'.format(package_name)
  81. )
  82. shutil.rmtree(out_dir_temp)
  83. return 0
  84. if __name__ == '__main__':
  85. args = parse_args()
  86. sys.exit(main(args))