|
| 1 | +""" |
| 2 | +Wrappers and helpers around `rules_pkg` to build codeql packs. |
| 3 | +""" |
| 4 | + |
| 5 | +load("@rules_pkg//pkg:install.bzl", "pkg_install") |
| 6 | +load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", _strip_prefix = "strip_prefix") |
| 7 | +load("@rules_pkg//pkg:pkg.bzl", "pkg_zip") |
| 8 | +load("@rules_python//python:defs.bzl", "py_binary") |
| 9 | +load("//:defs.bzl", "codeql_platform") |
| 10 | + |
| 11 | +def _make_internal(name): |
| 12 | + def internal(suffix): |
| 13 | + return "%s-%s" % (name, suffix) |
| 14 | + |
| 15 | + return internal |
| 16 | + |
| 17 | +def _get_subrule(label, suffix): |
| 18 | + if ":" in label or "/" not in label: |
| 19 | + return "%s-%s" % (label, suffix) |
| 20 | + path, _, pkg = label.rpartition("/") |
| 21 | + return "%s/%s:%s-%s" % (path, pkg, pkg, suffix) |
| 22 | + |
| 23 | +def codeql_pkg_files( |
| 24 | + *, |
| 25 | + name, |
| 26 | + arch_specific = False, |
| 27 | + srcs = None, |
| 28 | + exes = None, |
| 29 | + renames = None, |
| 30 | + prefix = None, |
| 31 | + visibility = None, |
| 32 | + **kwargs): |
| 33 | + """ |
| 34 | + Wrapper around `pkg_files`. Added functionality: |
| 35 | + * `exes` get their file attributes set to be executable. This is important only for POSIX files, there's no need |
| 36 | + to mark windows executables as such |
| 37 | + * `arch_specific` auto-adds the codeql platform specific directory (linux64, osx64 or windows64), and will be |
| 38 | + consumed by a downstream `codeql_pack` to create the arch specific zip. |
| 39 | + This should be consumed by `codeql_pkg_filegroup` and `codeql_pack` only. |
| 40 | + """ |
| 41 | + internal = _make_internal(name) |
| 42 | + main_rule = internal("generic") |
| 43 | + empty_rule = internal("arch") |
| 44 | + if arch_specific: |
| 45 | + main_rule, empty_rule = empty_rule, main_rule |
| 46 | + prefix = (prefix + "/" if prefix else "") + codeql_platform |
| 47 | + pkg_files( |
| 48 | + name = empty_rule, |
| 49 | + srcs = [], |
| 50 | + visibility = visibility, |
| 51 | + ) |
| 52 | + if not srcs and not exes: |
| 53 | + fail("either srcs or exes should be specified for %s" % name) |
| 54 | + if srcs and exes: |
| 55 | + if renames: |
| 56 | + src_renames = {k: v for k, v in renames.items() if k in srcs} |
| 57 | + exe_renames = {k: v for k, v in renames.items() if k in exes} |
| 58 | + else: |
| 59 | + src_renames = None |
| 60 | + exe_renames = None |
| 61 | + pkg_files( |
| 62 | + name = internal("srcs"), |
| 63 | + srcs = srcs, |
| 64 | + renames = src_renames, |
| 65 | + prefix = prefix, |
| 66 | + visibility = ["//visibility:private"], |
| 67 | + **kwargs |
| 68 | + ) |
| 69 | + pkg_files( |
| 70 | + name = internal("exes"), |
| 71 | + srcs = exes, |
| 72 | + renames = exe_renames, |
| 73 | + prefix = prefix, |
| 74 | + visibility = ["//visibility:private"], |
| 75 | + attributes = pkg_attributes(mode = "0755"), |
| 76 | + **kwargs |
| 77 | + ) |
| 78 | + pkg_filegroup( |
| 79 | + name = main_rule, |
| 80 | + srcs = [internal("srcs"), internal("exes")], |
| 81 | + visibility = visibility, |
| 82 | + ) |
| 83 | + else: |
| 84 | + pkg_files( |
| 85 | + name = main_rule, |
| 86 | + srcs = srcs or exes, |
| 87 | + attributes = pkg_attributes(mode = "0755") if exes else None, |
| 88 | + prefix = prefix, |
| 89 | + visibility = visibility, |
| 90 | + **kwargs |
| 91 | + ) |
| 92 | + native.filegroup( |
| 93 | + name = name, |
| 94 | + srcs = [main_rule], |
| 95 | + visibility = visibility, |
| 96 | + ) |
| 97 | + |
| 98 | +def codeql_pkg_wrap(*, name, srcs, arch_specific = False, prefix = None, visibility = None, **kwargs): |
| 99 | + """ |
| 100 | + Wrap a native `rules_pkg` rule, providing the `arch_specific` functionality and making it consumable by |
| 101 | + `codeql_pkg_filegroup` and `codeql_pack`. |
| 102 | + """ |
| 103 | + internal = _make_internal(name) |
| 104 | + main_rule = internal("generic") |
| 105 | + empty_rule = internal("arch") |
| 106 | + if arch_specific: |
| 107 | + main_rule, empty_rule = empty_rule, main_rule |
| 108 | + prefix = (prefix + "/" if prefix else "") + codeql_platform |
| 109 | + pkg_filegroup( |
| 110 | + name = main_rule, |
| 111 | + srcs = srcs, |
| 112 | + prefix = prefix, |
| 113 | + visibility = visibility, |
| 114 | + **kwargs |
| 115 | + ) |
| 116 | + pkg_files( |
| 117 | + name = empty_rule, |
| 118 | + srcs = [], |
| 119 | + visibility = visibility, |
| 120 | + ) |
| 121 | + native.filegroup( |
| 122 | + name = name, |
| 123 | + srcs = [main_rule], |
| 124 | + visibility = visibility, |
| 125 | + ) |
| 126 | + |
| 127 | +def codeql_pkg_filegroup( |
| 128 | + *, |
| 129 | + name, |
| 130 | + srcs, |
| 131 | + srcs_select = None, |
| 132 | + visibility = None, |
| 133 | + **kwargs): |
| 134 | + """ |
| 135 | + Combine `codeql_pkg_files` and other `codeql_pkg_filegroup` rules, similar to what `pkg_filegroup` does. |
| 136 | + `srcs` is not selectable, but `srcs_select` accepts the same dictionary that a select would accept. |
| 137 | + """ |
| 138 | + internal = _make_internal(name) |
| 139 | + |
| 140 | + def transform(srcs, suffix): |
| 141 | + return [_get_subrule(src, suffix) for src in srcs] |
| 142 | + |
| 143 | + pkg_filegroup( |
| 144 | + name = internal("generic"), |
| 145 | + srcs = transform(srcs, "generic") + (select( |
| 146 | + {k: transform(v, "generic") for k, v in srcs_select.items()}, |
| 147 | + ) if srcs_select else []), |
| 148 | + visibility = visibility, |
| 149 | + **kwargs |
| 150 | + ) |
| 151 | + pkg_filegroup( |
| 152 | + name = internal("arch"), |
| 153 | + srcs = transform(srcs, "arch") + (select( |
| 154 | + {k: transform(v, "arch") for k, v in srcs_select.items()}, |
| 155 | + ) if srcs_select else []), |
| 156 | + visibility = visibility, |
| 157 | + **kwargs |
| 158 | + ) |
| 159 | + native.filegroup( |
| 160 | + name = name, |
| 161 | + srcs = [internal("generic"), internal("arch")], |
| 162 | + visibility = visibility, |
| 163 | + ) |
| 164 | + |
| 165 | +def codeql_pack(*, name, srcs, zip_prefix = None, zip_filename = "extractor", visibility = visibility, install_dest = "extractor-pack", **kwargs): |
| 166 | + """ |
| 167 | + Define a codeql pack. This accepts the same arguments as `codeql_pkg_filegroup`, and additionally: |
| 168 | + * defines a `<name>-generic-zip` target creating a `<zip_filename>-generic.zip` archive with the generic bits, |
| 169 | + prefixed with `zip_prefix` (`name` by default) |
| 170 | + * defines a `<name>-arch-zip` target creating a `<zip_filename>-<codeql_platform>.zip` archive with the |
| 171 | + arch-specific bits, prefixed with `zip_prefix` (`name` by default) |
| 172 | + * defines a runnable `<name>-installer` target that will install the pack in `install_dest`, relative to where the |
| 173 | + rule is used. The install destination can be overridden appending `-- --destdir=...` to the `bazel run` |
| 174 | + invocation. This installation does not use the `zip_prefix`. |
| 175 | + """ |
| 176 | + internal = _make_internal(name) |
| 177 | + zip_prefix = zip_prefix or name |
| 178 | + zip_filename = zip_filename or name |
| 179 | + codeql_pkg_filegroup( |
| 180 | + name = name, |
| 181 | + srcs = srcs, |
| 182 | + visibility = visibility, |
| 183 | + **kwargs |
| 184 | + ) |
| 185 | + codeql_pkg_filegroup( |
| 186 | + name = internal("zip-contents"), |
| 187 | + srcs = [name], |
| 188 | + prefix = zip_prefix, |
| 189 | + visibility = ["//visibility:private"], |
| 190 | + ) |
| 191 | + pkg_zip( |
| 192 | + name = internal("generic-zip"), |
| 193 | + srcs = [internal("zip-contents-generic")], |
| 194 | + package_file_name = zip_filename + "-generic.zip", |
| 195 | + visibility = visibility, |
| 196 | + ) |
| 197 | + pkg_zip( |
| 198 | + name = internal("arch-zip"), |
| 199 | + srcs = [internal("zip-contents-arch")], |
| 200 | + package_file_name = zip_filename + "-" + codeql_platform + ".zip", |
| 201 | + visibility = visibility, |
| 202 | + ) |
| 203 | + pkg_install( |
| 204 | + name = internal("script"), |
| 205 | + srcs = [internal("generic"), internal("arch")], |
| 206 | + visibility = ["//visibility:private"], |
| 207 | + ) |
| 208 | + native.filegroup( |
| 209 | + # used to locate current source directory |
| 210 | + name = internal("build-file"), |
| 211 | + srcs = ["BUILD.bazel"], |
| 212 | + visibility = ["//visibility:private"], |
| 213 | + ) |
| 214 | + py_binary( |
| 215 | + name = internal("installer"), |
| 216 | + srcs = ["//misc/bazel/internal:install.py"], |
| 217 | + main = "//misc/bazel/internal:install.py", |
| 218 | + data = [internal("build-file"), internal("script")], |
| 219 | + deps = ["@rules_python//python/runfiles"], |
| 220 | + args = [ |
| 221 | + "--build-file=$(rlocationpath %s)" % internal("build-file"), |
| 222 | + "--script=$(rlocationpath %s)" % internal("script"), |
| 223 | + "--destdir", |
| 224 | + install_dest, |
| 225 | + ], |
| 226 | + visibility = visibility, |
| 227 | + ) |
| 228 | + |
| 229 | +strip_prefix = _strip_prefix |
| 230 | + |
| 231 | +def _runfiles_group_impl(ctx): |
| 232 | + files = [] |
| 233 | + for src in ctx.attr.srcs: |
| 234 | + rf = src[DefaultInfo].default_runfiles |
| 235 | + if rf != None: |
| 236 | + files.append(rf.files) |
| 237 | + return [ |
| 238 | + DefaultInfo( |
| 239 | + files = depset(transitive = files), |
| 240 | + ), |
| 241 | + ] |
| 242 | + |
| 243 | +_runfiles_group = rule( |
| 244 | + implementation = _runfiles_group_impl, |
| 245 | + attrs = { |
| 246 | + "srcs": attr.label_list(), |
| 247 | + }, |
| 248 | +) |
| 249 | + |
| 250 | +def codeql_pkg_runfiles(*, name, exes, **kwargs): |
| 251 | + """ |
| 252 | + Create a `codeql_pkg_files` with all runfiles from files in `exes`, flattened together. |
| 253 | + """ |
| 254 | + internal = _make_internal(name) |
| 255 | + _runfiles_group( |
| 256 | + name = internal("runfiles"), |
| 257 | + srcs = exes, |
| 258 | + visibility = ["//visibility:private"], |
| 259 | + ) |
| 260 | + codeql_pkg_files( |
| 261 | + name = name, |
| 262 | + exes = [internal("runfiles")], |
| 263 | + **kwargs |
| 264 | + ) |
0 commit comments