res.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import json
  2. import os
  3. import six
  4. from _common import rootrel_arc_src, ugly_conftest_exception
  5. import ymake
  6. def remove_prefix(text, prefix):
  7. if text.startswith(prefix):
  8. return text[len(prefix) :]
  9. return text
  10. def onresource_files(unit, *args):
  11. """
  12. @usage: RESOURCE_FILES([DONT_COMPRESS] [PREFIX {prefix}] [STRIP prefix_to_strip] {path})
  13. This macro expands into
  14. RESOURCE(DONT_PARSE {path} resfs/file/{prefix}{path}
  15. - resfs/src/resfs/file/{prefix}{remove_prefix(path, prefix_to_strip)}={rootrel_arc_src(path)}
  16. )
  17. resfs/src/{key} stores a source root (or build root) relative path of the
  18. source of the value of the {key} resource.
  19. resfs/file/{key} stores any value whose source was a file on a filesystem.
  20. resfs/src/resfs/file/{key} must store its path.
  21. DONT_COMPRESS allows optionally disable resource compression on platforms where it is supported
  22. This form is for use from other plugins:
  23. RESOURCE_FILES([DEST {dest}] {path}) expands into RESOURCE({path} resfs/file/{dest})
  24. @see: https://wiki.yandex-team.ru/devtools/commandsandvars/resourcefiles/
  25. """
  26. prefix = ''
  27. prefix_to_strip = None
  28. dest = None
  29. res = []
  30. if args and not unit.enabled('_GO_MODULE'):
  31. # GO_RESOURCE currently doesn't support DONT_PARSE
  32. res.append('DONT_PARSE')
  33. if args and not unit.enabled('_GO_MODULE') and 'DONT_COMPRESS' in args:
  34. res.append('DONT_COMPRESS')
  35. args = iter(args)
  36. for arg in args:
  37. if arg == 'DONT_COMPRESS':
  38. pass
  39. elif arg == 'PREFIX':
  40. prefix, dest = next(args), None
  41. elif arg == 'DEST':
  42. dest, prefix = next(args), None
  43. elif arg == 'STRIP':
  44. prefix_to_strip = next(args)
  45. else:
  46. path = arg
  47. key = 'resfs/file/' + (
  48. dest or (prefix + (path if not prefix_to_strip else remove_prefix(path, prefix_to_strip)))
  49. )
  50. if key in res:
  51. unit.message(
  52. ['warn', "Duplicated resource file {} in RESOURCE_FILES() macro. Skipped it.".format(path)]
  53. )
  54. continue
  55. if not ugly_conftest_exception(path):
  56. src = 'resfs/src/{}=${{rootrel;input;context=TEXT:"{}"}}'.format(key, path)
  57. else:
  58. src = 'resfs/src/{}={}'.format(key, rootrel_arc_src(path, unit))
  59. res += ['-', src, path, key]
  60. if unit.enabled('_GO_MODULE'):
  61. unit.on_go_resource(res)
  62. else:
  63. unit.onresource(res)
  64. def on_all_resource_files(unit, macro, *args):
  65. # This is only validation, actual work is done in ymake.core.conf implementation
  66. for arg in args:
  67. if '*' in arg or '?' in arg:
  68. ymake.report_configure_error('Wildcards in [[imp]]{}[[rst]] are not allowed'.format(macro))
  69. def onall_resource_files(unit, *args):
  70. on_all_resource_files(unit, 'ALL_RESOURCE_FILES', args)
  71. def onall_resource_files_from_dirs(unit, *args):
  72. on_all_resource_files(unit, 'ALL_RESOURCE_FILES_FROM_DIRS', args)
  73. def on_ya_conf_json(unit, conf_file):
  74. conf_abs_path = unit.resolve('$S/' + conf_file)
  75. if not os.path.exists(conf_abs_path):
  76. ymake.report_configure_error('File "{}" not found'.format(conf_abs_path))
  77. return
  78. # conf_file should be passed to the RESOURCE_FILES macro without path.
  79. # To resolve it later by name only we must add it's path to SRCDIR().
  80. conf_dir = os.path.dirname(conf_file)
  81. if conf_dir:
  82. unit.onsrcdir(conf_dir)
  83. unit.onresource_files(os.path.basename(conf_file))
  84. valid_dirs = (
  85. "build",
  86. conf_dir,
  87. )
  88. with open(conf_abs_path) as f:
  89. conf = json.load(f)
  90. formulas = set()
  91. def _iter_bottles(config):
  92. if "simple_tools" in config:
  93. for name, info in config["simple_tools"].items():
  94. yield name, f"build/external_resources/{info.get('resource', name)}/resources.json"
  95. for name, bottle in config["bottles"].items():
  96. yield name, bottle["formula"]
  97. for bottle_name, formula in _iter_bottles(conf):
  98. if isinstance(formula, six.string_types):
  99. if formula.startswith(valid_dirs):
  100. abs_path = unit.resolve('$S/' + formula)
  101. if os.path.exists(abs_path):
  102. formulas.add(formula)
  103. else:
  104. ymake.report_configure_error(
  105. 'File "{}" (referenced from bottle "{}" in "{}") is not found'.format(
  106. abs_path, bottle_name, conf_abs_path
  107. )
  108. )
  109. else:
  110. ymake.report_configure_error(
  111. 'File "{}" (referenced from bottle "{}" in "{}") must be located in "{}" file tree'.format(
  112. formula, bottle_name, conf_file, '" or "'.join(valid_dirs)
  113. )
  114. )
  115. for formula in sorted(formulas):
  116. unit.onresource_files(formula)