install_filegroups.bzl 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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", "busybox_wrapper", "symlink_file", "symlink_filegroup")
  7. def install_busybox_wrapper(name, busybox, busybox_args = []):
  8. """Adds a busybox wrapper for install.
  9. Used in the `install_dirs` dict.
  10. Args:
  11. name: The filename to use.
  12. busybox: A relative path for the busybox.
  13. busybox_args: Arguments needed to simulate busybox when a symlink isn't
  14. actually used.
  15. """
  16. return {
  17. "busybox": busybox,
  18. "busybox_args": busybox_args,
  19. "is_driver": True,
  20. "name": name,
  21. }
  22. def install_filegroup(name, filegroup_target):
  23. """Adds a filegroup for install.
  24. Used in the `install_dirs` dict.
  25. Args:
  26. name: The base directory for the filegroup.
  27. filegroup_target: The bazel filegroup target to install.
  28. """
  29. return {
  30. "filegroup": filegroup_target,
  31. "is_driver": False,
  32. "name": name,
  33. }
  34. def install_symlink(name, symlink_to):
  35. """Adds a symlink for install.
  36. Used in the `install_dirs` dict.
  37. Args:
  38. name: The filename to use.
  39. symlink_to: A relative path for the symlink.
  40. """
  41. return {
  42. "is_driver": False,
  43. "name": name,
  44. "symlink": symlink_to,
  45. }
  46. def install_target(name, target, executable = False, is_driver = False):
  47. """Adds a target for install.
  48. Used in the `install_dirs` dict.
  49. Args:
  50. name: The filename to use.
  51. target: The bazel target being installed.
  52. executable: True if executable.
  53. is_driver: False if it should be included in the `no_driver_name`
  54. filegroup.
  55. """
  56. return {
  57. "executable": executable,
  58. "is_driver": is_driver,
  59. "name": name,
  60. "target": target,
  61. }
  62. def make_install_filegroups(name, no_driver_name, pkg_name, install_dirs, prefix):
  63. """Makes filegroups of install data.
  64. Args:
  65. name: The name of the main filegroup, that contains all install_data.
  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. pkg_srcs = []
  77. for dir, entries in install_dirs.items():
  78. for entry in entries:
  79. path = "{0}/{1}".format(dir, entry["name"])
  80. prefixed_path = "{0}/{1}".format(prefix, path)
  81. all_srcs.append(prefixed_path)
  82. if not entry["is_driver"]:
  83. no_driver_srcs.append(prefixed_path)
  84. pkg_path = path + ".pkg"
  85. pkg_srcs.append(pkg_path)
  86. if "target" in entry:
  87. if entry["executable"]:
  88. symlink_file(
  89. name = prefixed_path,
  90. symlink_binary = entry["target"],
  91. )
  92. mode = "0755"
  93. else:
  94. symlink_file(
  95. name = prefixed_path,
  96. symlink_label = entry["target"],
  97. )
  98. mode = "0644"
  99. pkg_files(
  100. name = pkg_path,
  101. srcs = [entry["target"]],
  102. attributes = pkg_attributes(mode = mode),
  103. renames = {entry["target"]: path},
  104. )
  105. elif "busybox" in entry:
  106. busybox_wrapper(
  107. name = prefixed_path,
  108. symlink = entry["busybox"],
  109. busybox_args = entry["busybox_args"],
  110. )
  111. # For the distributed package, we retain relative symlinks.
  112. pkg_mklink(
  113. name = pkg_path,
  114. link_name = path,
  115. target = entry["busybox"],
  116. )
  117. elif "filegroup" in entry:
  118. symlink_filegroup(
  119. name = prefixed_path,
  120. out_prefix = prefixed_path,
  121. srcs = [entry["filegroup"]],
  122. )
  123. pkg_files(
  124. name = pkg_path,
  125. srcs = [prefixed_path],
  126. strip_prefix = strip_prefix.from_pkg(prefix),
  127. )
  128. elif "symlink" in entry:
  129. symlink_to = "{0}/{1}/{2}".format(prefix, dir, entry["symlink"])
  130. # For bazel, we need to resolve relative symlinks.
  131. if "../" in symlink_to:
  132. parts = symlink_to.split("/")
  133. result = []
  134. for part in parts:
  135. if part == "..":
  136. result = result[:-1]
  137. else:
  138. result.append(part)
  139. symlink_to = "/".join(result)
  140. symlink_file(
  141. name = prefixed_path,
  142. symlink_binary = symlink_to,
  143. )
  144. # For the distributed package, we retain relative symlinks.
  145. pkg_mklink(
  146. name = pkg_path,
  147. link_name = path,
  148. target = entry["symlink"],
  149. )
  150. else:
  151. fail("Unrecognized structure: {0}".format(entry))
  152. native.filegroup(name = name, srcs = all_srcs)
  153. native.filegroup(name = no_driver_name, srcs = no_driver_srcs)
  154. pkg_filegroup(name = pkg_name, srcs = pkg_srcs)