go_proto_wrapper.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. from __future__ import absolute_import
  2. import os
  3. import re
  4. import shutil
  5. import subprocess
  6. import sys
  7. import tempfile
  8. from six.moves import range
  9. OUT_DIR_FLAG_PATTERN = re.compile(r'^(--go(([-_]\w+))*_out=)')
  10. def move_tree(src_root, dst_root):
  11. for root, _, files in os.walk(src_root):
  12. rel_dir = os.path.relpath(root, src_root)
  13. dst_dir = os.path.join(dst_root, rel_dir)
  14. if not os.path.exists(dst_dir):
  15. os.mkdir(dst_dir)
  16. for file in files:
  17. os.rename(os.path.join(root, file), os.path.join(dst_dir, file))
  18. def main(arcadia_prefix, contrib_prefix, proto_namespace, args):
  19. out_dir_orig = None
  20. out_dir_temp = None
  21. for i in range(len(args)):
  22. m = re.match(OUT_DIR_FLAG_PATTERN, args[i])
  23. if m:
  24. out_dir_flag = m.group(1)
  25. index = max(len(out_dir_flag), args[i].rfind(':')+1)
  26. out_dir = args[i][index:]
  27. if out_dir_orig:
  28. assert out_dir_orig == out_dir, 'Output directories do not match: [{}] and [{}]'.format(out_dir_orig, out_dir)
  29. else:
  30. out_dir_orig = out_dir
  31. out_dir_temp = tempfile.mkdtemp(dir=out_dir_orig)
  32. args[i] = (args[i][:index] + out_dir_temp).replace('|', ',')
  33. assert out_dir_temp is not None, 'Output directory is not specified'
  34. try:
  35. subprocess.check_output(args, stdin=None, stderr=subprocess.STDOUT)
  36. except subprocess.CalledProcessError as e:
  37. sys.stderr.write('{} returned non-zero exit code {}.\n{}\n'.format(' '.join(e.cmd), e.returncode, e.output))
  38. return e.returncode
  39. # All Arcadia GO projects should have 'a.yandex-team.ru/' namespace prefix.
  40. # If the namespace doesn't start with 'a.yandex-team.ru/' prefix then this
  41. # project is from vendor directory under the root of Arcadia.
  42. out_dir_src = os.path.normpath(os.path.join(out_dir_temp, arcadia_prefix, proto_namespace))
  43. out_dir_dst = out_dir_orig
  44. is_from_contrib = False
  45. if not os.path.isdir(out_dir_src):
  46. is_from_contrib = True
  47. out_dir_src = out_dir_temp
  48. out_dir_dst = os.path.join(out_dir_orig, contrib_prefix)
  49. if not os.path.exists(out_dir_src) or is_from_contrib:
  50. protos = [x for x in args if x.endswith('.proto')]
  51. if not is_from_contrib or not all(x.startswith(contrib_prefix) for x in protos):
  52. proto_list = []
  53. option_re = re.compile(r'^\s*option\s+go_package\s*=\s*')
  54. for arg in protos:
  55. with open(arg, 'r') as f:
  56. if not any([re.match(option_re, line) for line in f]):
  57. proto_list.append(arg)
  58. if proto_list:
  59. sys.stderr.write(
  60. '\nError: Option go_package is not specified in the following proto files: {}\n'
  61. '\nNOTE! You can find detailed description of how to properly set go_package '
  62. 'option here https://wiki.yandex-team.ru/devrules/Go/#protobufigrpc'.format(', '.join(proto_list)))
  63. return 1
  64. move_tree(out_dir_src, out_dir_dst)
  65. shutil.rmtree(out_dir_temp)
  66. return 0
  67. if __name__ == '__main__':
  68. sys.exit(main(os.path.normpath(sys.argv[1]), os.path.normpath(sys.argv[2]), os.path.normpath(sys.argv[3]), sys.argv[4:]))