install_filegroups.bzl 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. # Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. # Exceptions. See /LICENSE for license information.
  3. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. """Rules for constructing install information."""
  5. load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", "pkg_mklink", "strip_prefix")
  6. load("symlink_helpers.bzl", "symlink_file", "symlink_filegroup")
  7. def install_filegroup(name, filegroup_target, remove_prefix = "", label = None):
  8. """Adds a filegroup for install.
  9. Used in the `install_dirs` dict.
  10. Args:
  11. name: The base directory for the filegroup.
  12. filegroup_target: The bazel filegroup target to install.
  13. remove_prefix: A prefix to remove from the name of each source file when
  14. determining the name of the corresponding installed file.
  15. label: A custom label to assign to the filegroup containing the
  16. installed files.
  17. """
  18. return {
  19. "filegroup": filegroup_target,
  20. "is_digest": False,
  21. "is_driver": False,
  22. "label": label,
  23. "name": name,
  24. "remove_prefix": remove_prefix,
  25. }
  26. def install_symlink(name, symlink_to, is_driver = False):
  27. """Adds a symlink for install.
  28. Used in the `install_dirs` dict.
  29. Args:
  30. name: The filename to use.
  31. symlink_to: A relative path for the symlink.
  32. is_driver: False if it should be included in the `no_driver_name`
  33. filegroup.
  34. """
  35. return {
  36. "is_digest": False,
  37. "is_driver": is_driver,
  38. "name": name,
  39. "symlink": symlink_to,
  40. }
  41. def install_target(name, target, executable = False, is_driver = False, is_digest = False):
  42. """Adds a target for install.
  43. Used in the `install_dirs` dict.
  44. Args:
  45. name: The filename to use.
  46. target: The bazel target being installed.
  47. executable: True if executable.
  48. is_driver: False if it should be included in the `no_driver_name`
  49. filegroup.
  50. is_digest: False if it should be included in the `no_digest_name`
  51. filegroup.
  52. """
  53. return {
  54. "executable": executable,
  55. "is_digest": is_digest,
  56. "is_driver": is_driver,
  57. "name": name,
  58. "target": target,
  59. }
  60. def make_install_filegroups(name, no_digest_name, no_driver_name, pkg_name, install_dirs, prefix):
  61. """Makes filegroups of install data.
  62. Args:
  63. name: The name of the main filegroup, that contains all install_data.
  64. no_digest_name: The name of a filegroup which excludes the digest. This is
  65. used to compute the digest itself.
  66. no_driver_name: The name of a filegroup which excludes the driver. This is
  67. for the driver to depend on and get other files, without a circular
  68. dependency.
  69. pkg_name: The name of a pkg_filegroup for tar.
  70. install_dirs: A dict of {directory: [install_* rules]}. This is used to
  71. structure files to be installed.
  72. prefix: A prefix for files in the native (non-pkg) filegroups.
  73. """
  74. all_srcs = []
  75. no_driver_srcs = []
  76. no_digest_srcs = []
  77. pkg_srcs = []
  78. for dir, entries in install_dirs.items():
  79. for entry in entries:
  80. path = "{0}/{1}".format(dir, entry["name"])
  81. prefixed_path = "{0}/{1}".format(prefix, path)
  82. all_srcs.append(prefixed_path)
  83. if not entry["is_driver"]:
  84. no_driver_srcs.append(prefixed_path)
  85. if not entry["is_digest"]:
  86. no_digest_srcs.append(prefixed_path)
  87. pkg_label = entry.get("label") or path + ".pkg"
  88. pkg_srcs.append(pkg_label)
  89. if "target" in entry:
  90. if entry["executable"]:
  91. symlink_file(
  92. name = prefixed_path,
  93. symlink_binary = entry["target"],
  94. )
  95. mode = "0755"
  96. else:
  97. symlink_file(
  98. name = prefixed_path,
  99. symlink_label = entry["target"],
  100. )
  101. mode = "0644"
  102. pkg_files(
  103. name = pkg_label,
  104. srcs = [entry["target"]],
  105. attributes = pkg_attributes(mode = mode),
  106. renames = {entry["target"]: path},
  107. )
  108. elif "filegroup" in entry:
  109. symlink_filegroup(
  110. name = prefixed_path,
  111. out_prefix = prefixed_path,
  112. srcs = [entry["filegroup"]],
  113. remove_prefix = entry["remove_prefix"],
  114. )
  115. pkg_files(
  116. name = pkg_label,
  117. srcs = [prefixed_path],
  118. strip_prefix = strip_prefix.from_pkg(prefix),
  119. )
  120. elif "symlink" in entry:
  121. symlink_to = "{0}/{1}/{2}".format(prefix, dir, entry["symlink"])
  122. # For bazel, we need to resolve relative symlinks.
  123. if "../" in symlink_to:
  124. parts = symlink_to.split("/")
  125. result = []
  126. for part in parts:
  127. if part == "..":
  128. result = result[:-1]
  129. else:
  130. result.append(part)
  131. symlink_to = "/".join(result)
  132. symlink_file(
  133. name = prefixed_path,
  134. symlink_binary = symlink_to,
  135. )
  136. # For the distributed package, we retain relative symlinks.
  137. pkg_mklink(
  138. name = pkg_label,
  139. link_name = path,
  140. target = entry["symlink"],
  141. )
  142. else:
  143. fail("Unrecognized structure: {0}".format(entry))
  144. native.filegroup(name = name, srcs = all_srcs)
  145. native.filegroup(name = no_driver_name, srcs = no_driver_srcs)
  146. native.filegroup(name = no_digest_name, srcs = no_digest_srcs)
  147. pkg_filegroup(name = pkg_name, srcs = pkg_srcs)