Skip to content

Instantly share code, notes, and snippets.

@ittaiz
Last active May 3, 2018 18:51
Show Gist options
  • Save ittaiz/3e700cfc3ee7a7e135a57144a47e47a8 to your computer and use it in GitHub Desktop.
Save ittaiz/3e700cfc3ee7a7e135a57144a47e47a8 to your computer and use it in GitHub Desktop.
Bazel Skylark rule and aspect to collect all config files (erbs) transitively
ConfigFiles = provider(
fields = {
'transitive_config_files' : 'number of files'
}
)
_erb_filetype = FileType([".erb"])
_attrs = ['tars','deps','runtime_deps','exports'] #data?
def _accumulate_transitive_config_files(accumulated, deps):
return depset(
transitive = [dep[ConfigFiles].transitive_config_files for dep in deps] + [accumulated])
def _collect_current_config_files(srcs):
current_config_files = []
for src in srcs:
erb_srcs = _erb_filetype.filter(src.files)
for file in erb_srcs:
current_config_files.append(file)
return current_config_files
def _collect_config_files_aspect_impl(target, ctx):
if hasattr(ctx.rule.attr, 'srcs'):
current_config_files = _collect_current_config_files(ctx.rule.attr.srcs)
else:
current_config_files = []
accumulated_config_files = depset(current_config_files)
for attr in _attrs:
if hasattr(ctx.rule.attr, attr):
accumulated_config_files = _accumulate_transitive_config_files(accumulated_config_files, getattr(ctx.rule.attr, attr))
return [ConfigFiles(transitive_config_files=accumulated_config_files)]
def _paths(config_files):
return [f.path for f in config_files]
def _zip(ctx, config_files):
zipper_args = "\n".join(_paths(config_files)) + "\n"
if len(config_files) > 0:
zipper_arg_path = ctx.actions.declare_file("%s_zipper_args" % ctx.outputs.config_archive.path)
ctx.actions.write(zipper_arg_path, zipper_args)
# We move the files and touch them so that the output file is a purely deterministic
# product of the _content_ of the inputs
cmd = """
rm -f {out}
{zipper} c {out} @{path}
"""
cmd = cmd.format(out=ctx.outputs.config_archive.path,
path=zipper_arg_path.path,
zipper=ctx.executable._zipper.path)
ctx.actions.run_shell(
inputs = config_files + [ctx.executable._zipper, zipper_arg_path],
outputs = [ctx.outputs.config_archive],
command = cmd,
progress_message = "making config archive %s (%s files)" % (ctx.label, len(config_files)),
)
else:
# we still have to create the output we declared
ctx.actions.run_shell(
inputs = [ctx.executable._zipper],
outputs = [ctx.outputs.config_archive],
command = """
echo "empty" > {out}.contents
rm -f {out}
{zipper} c {out} {out}.contents
rm {out}.contents
""".format(out=ctx.outputs.config_archive.path,
zipper=ctx.executable._zipper.path),
progress_message = "making empty config archive %s" % ctx.label,
)
def _collect_config_files_rule_impl(ctx):
_zip(ctx, ctx.attr.artifact[ConfigFiles].transitive_config_files.to_list())
collect_config_files_aspect = aspect(implementation = _collect_config_files_aspect_impl,
attr_aspects = _attrs,
)
config_files = rule(
implementation = _collect_config_files_rule_impl,
attrs = {
'artifact' : attr.label(aspects = [collect_config_files_aspect]),
"_zipper": attr.label(executable=True, cfg="host", default=Label("@bazel_tools//tools/zip:zipper"), allow_files=True)
},
outputs={"config_archive": "%{name}-config.zip"},
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment