diff options
Diffstat (limited to 'dist.bzl')
-rw-r--r-- | dist.bzl | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/dist.bzl b/dist.bzl new file mode 100644 index 0000000000..98eed9d1a9 --- /dev/null +++ b/dist.bzl @@ -0,0 +1,199 @@ +load("@bazel-erlang//:erlang_home.bzl", "ErlangHomeProvider") +load("@bazel-erlang//:bazel_erlang_lib.bzl", "ErlangLibInfo", "flat_deps", "path_join") +load("@bazel-erlang//:ct.bzl", "additional_file_dest_relative_path") +load( + ":rabbitmq_home.bzl", + "RABBITMQ_HOME_ATTRS", + "RabbitmqHomeInfo", + "flatten", + "link_escript", + "unique_versions", +) + +def _collect_licenses_impl(ctx): + srcs = ctx.files.srcs + flatten([ + d[ErlangLibInfo].license_files + for d in flat_deps(ctx.attr.deps) + ]) + + outs = {} + for src in srcs: + name = src.basename + if name not in outs: + dest = ctx.actions.declare_file(name) + ctx.actions.run( + inputs = [src], + outputs = [dest], + executable = "cp", + arguments = [ + src.path, + dest.path, + ], + ) + outs[name] = dest + + return [ + DefaultInfo( + files = depset(sorted(outs.values())), + ), + ] + +collect_licenses = rule( + implementation = _collect_licenses_impl, + attrs = { + "srcs": attr.label_list(allow_files = True), + "deps": attr.label_list(providers = [ErlangLibInfo]), + }, +) + +def _copy_script(ctx, script): + dest = ctx.actions.declare_file(path_join(ctx.label.name, "sbin", script.basename)) + ctx.actions.expand_template( + template = script, + output = dest, + substitutions = { + "SYS_PREFIX=": "SYS_PREFIX=${RABBITMQ_HOME}", + }, + ) + return dest + +def _extract_version(p): + return "erl -eval '{ok, [{application, _, AppInfo}]} = file:consult(\"" + p + "\"), Version = proplists:get_value(vsn, AppInfo), io:fwrite(Version), halt().' -noshell" + +def _app_file(plugin_lib_info): + for f in plugin_lib_info.beam: + if f.basename.endswith(".app"): + return f + fail(".app file not found in {}".format(plugin_lib_info)) + +def _plugins_dir(ctx, plugins): + plugins_dir = ctx.actions.declare_directory(path_join(ctx.label.name, "plugins")) + + erlang_home = ctx.attr._erlang_home[ErlangHomeProvider].path + + inputs = [] + + commands = ["set -euo pipefail", ""] + + for plugin in plugins: + lib_info = plugin[ErlangLibInfo] + app_file = _app_file(lib_info) + extract_version = _extract_version(app_file.path) + commands.append("PLUGIN_VERSION=$({erlang_home}/bin/{extract_version})".format(erlang_home = erlang_home, extract_version = extract_version)) + + commands.append( + "echo \"Assembling {lib_name}-$PLUGIN_VERSION...\"".format( + lib_name = lib_info.lib_name, + ), + ) + + commands.append( + "mkdir -p {plugins_dir}/{lib_name}-$PLUGIN_VERSION/include".format( + plugins_dir = plugins_dir.path, + lib_name = lib_info.lib_name, + ), + ) + for f in lib_info.include: + commands.append( + "cp {src} {plugins_dir}/{lib_name}-$PLUGIN_VERSION/include/{dest}".format( + src = f.path, + plugins_dir = plugins_dir.path, + lib_name = lib_info.lib_name, + dest = f.basename, + ), + ) + inputs.extend(lib_info.include) + + commands.append( + "mkdir -p {plugins_dir}/{lib_name}-$PLUGIN_VERSION/ebin".format( + plugins_dir = plugins_dir.path, + lib_name = lib_info.lib_name, + ), + ) + for f in lib_info.beam: + if f.is_directory: + if f.basename != "ebin": + fail("{} contains a directory in 'beam' that is not an ebin dir".format(lib_info.lib_name)) + commands.append( + "cp -R {src} {plugins_dir}/{lib_name}-$PLUGIN_VERSION".format( + src = f.path, + plugins_dir = plugins_dir.path, + lib_name = lib_info.lib_name, + ), + ) + else: + commands.append( + "cp {src} {plugins_dir}/{lib_name}-$PLUGIN_VERSION/ebin/{dest}".format( + src = f.path, + plugins_dir = plugins_dir.path, + lib_name = lib_info.lib_name, + dest = f.basename, + ), + ) + inputs.extend(lib_info.beam) + + for f in lib_info.priv: + p = additional_file_dest_relative_path(plugin.label, f) + commands.append( + "mkdir -p $(dirname {plugins_dir}/{lib_name}-$PLUGIN_VERSION/{dest}) && cp {src} {plugins_dir}/{lib_name}-$PLUGIN_VERSION/{dest}".format( + src = f.path, + plugins_dir = plugins_dir.path, + lib_name = lib_info.lib_name, + dest = p, + ), + ) + inputs.extend(lib_info.priv) + + commands.append("") + + ctx.actions.run_shell( + inputs = inputs, + outputs = [plugins_dir], + command = "\n".join(commands), + ) + + return plugins_dir + +def _versioned_rabbitmq_home_impl(ctx): + plugins = flat_deps(ctx.attr.plugins) + + erlang_versions = unique_versions(plugins) + if len(erlang_versions) > 1: + fail("plugins do not have a unified erlang version", erlang_versions) + + scripts = [_copy_script(ctx, script) for script in ctx.files._scripts] + + rabbitmq_ctl_copies = [ + "rabbitmq-diagnostics", + "rabbitmq-plugins", + "rabbitmq-queues", + "rabbitmq-streams", + "rabbitmq-upgrade", + "rabbitmqctl", + ] + escripts = [link_escript(ctx, escript) for escript in rabbitmq_ctl_copies] + + plugins_dir = _plugins_dir(ctx, plugins) + + rabbitmqctl = None + for script in scripts: + if script.basename == "rabbitmqctl": + rabbitmqctl = script + if rabbitmqctl == None: + fail("could not find rabbitmqct among", scripts) + + return [ + RabbitmqHomeInfo( + rabbitmqctl = rabbitmqctl, + ), + DefaultInfo( + files = depset(scripts + escripts + [plugins_dir]), + ), + ] + +versioned_rabbitmq_home = rule( + implementation = _versioned_rabbitmq_home_impl, + attrs = dict(RABBITMQ_HOME_ATTRS.items() + { + "_erlang_home": attr.label(default = "@bazel-erlang//:erlang_home"), + }.items()), +) |