| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- # Copied from google/nomulus project as we don't want to import the whole repository.
- ZIPPER = "@bazel_tools//tools/zip:zipper"
- def long_path(ctx, file_):
- """Constructs canonical runfile path relative to TEST_SRCDIR.
- Args:
- ctx: A Skylark rule context.
- file_: A File object that should appear in the runfiles for the test.
- Returns:
- A string path relative to TEST_SRCDIR suitable for use in tests and
- testing infrastructure.
- """
- if file_.short_path.startswith("../"):
- return file_.short_path[3:]
- if file_.owner and file_.owner.workspace_root:
- return file_.owner.workspace_root + "/" + file_.short_path
- return ctx.workspace_name + "/" + file_.short_path
- def collect_runfiles(targets):
- """Aggregates runfiles from targets.
- Args:
- targets: A list of Bazel targets.
- Returns:
- A list of Bazel files.
- """
- data = depset()
- for target in targets:
- if hasattr(target, "runfiles"):
- data += target.runfiles.files
- continue
- if hasattr(target, "data_runfiles"):
- data += target.data_runfiles.files
- if hasattr(target, "default_runfiles"):
- data += target.default_runfiles.files
- return data
- def _get_runfiles(target, attribute):
- runfiles = getattr(target, attribute, None)
- if runfiles:
- return runfiles.files
- return []
- def _zip_file(ctx):
- """Implementation of zip_file() rule."""
- for s, d in ctx.attr.mappings.items():
- if (s.startswith("/") or s.endswith("/") or
- d.startswith("/") or d.endswith("/")):
- fail("mappings should not begin or end with slash")
- srcs = depset(transitive = [depset(ctx.files.srcs),depset(ctx.files.data),depset(collect_runfiles(ctx.attr.data))])
- mapped = _map_sources(ctx, srcs, ctx.attr.mappings)
- cmd = [
- "#!/bin/sh",
- "set -e",
- 'repo="$(pwd)"',
- 'zipper="${repo}/%s"' % ctx.file._zipper.path,
- 'archive="${repo}/%s"' % ctx.outputs.out.path,
- 'tmp="$(mktemp -d "${TMPDIR:-/tmp}/zip_file.XXXXXXXXXX")"',
- 'cd "${tmp}"',
- ]
- cmd += [
- '"${zipper}" x "${repo}/%s"' % dep.zip_file.path
- for dep in ctx.attr.deps
- ]
- cmd += ["rm %s" % filename for filename in ctx.attr.exclude]
- cmd += [
- 'mkdir -p "${tmp}/%s"' % zip_path
- for zip_path in depset(
- [
- zip_path[:zip_path.rindex("/")]
- for _, zip_path in mapped
- if "/" in zip_path
- ],
- ).to_list()
- ]
- cmd += [
- 'ln -sf "${repo}/%s" "${tmp}/%s"' % (path, zip_path)
- for path, zip_path in mapped
- ]
- cmd += [
- ("find . | sed 1d | cut -c 3- | LC_ALL=C sort" +
- ' | xargs "${zipper}" cC "${archive}"'),
- 'cd "${repo}"',
- 'rm -rf "${tmp}"',
- ]
- script = ctx.actions.declare_file("%s/%s.sh" % (ctx.bin_dir, ctx.label.name))
- ctx.actions.write(output = script, content = "\n".join(cmd), is_executable = True)
- inputs = [ctx.file._zipper]
- inputs += [dep.zip_file for dep in ctx.attr.deps]
- inputs += list(srcs.to_list())
- ctx.actions.run(
- inputs = inputs,
- outputs = [ctx.outputs.out],
- executable = script,
- mnemonic = "zip",
- progress_message = "Creating zip with %d inputs %s" % (
- len(inputs),
- ctx.label,
- ),
- )
- return struct(files = depset([ctx.outputs.out]), zip_file = ctx.outputs.out)
- def _map_sources(ctx, srcs, mappings):
- """Calculates paths in zip file for srcs."""
- # order mappings with more path components first
- mappings = sorted([
- (-len(source.split("/")), source, dest)
- for source, dest in mappings.items()
- ])
- # get rid of the integer part of tuple used for sorting
- mappings = [(source, dest) for _, source, dest in mappings]
- mappings_indexes = range(len(mappings))
- used = {i: False for i in mappings_indexes}
- mapped = []
- for file_ in srcs.to_list():
- run_path = long_path(ctx, file_)
- zip_path = None
- for i in mappings_indexes:
- source = mappings[i][0]
- dest = mappings[i][1]
- if not source:
- if dest:
- zip_path = dest + "/" + run_path
- else:
- zip_path = run_path
- elif source == run_path:
- if dest:
- zip_path = dest
- else:
- zip_path = run_path
- elif run_path.startswith(source + "/"):
- if dest:
- zip_path = dest + run_path[len(source):]
- else:
- zip_path = run_path[len(source) + 1:]
- else:
- continue
- used[i] = True
- break
- if not zip_path:
- fail("no mapping matched: " + run_path)
- mapped += [(file_.path, zip_path)]
- for i in mappings_indexes:
- if not used[i]:
- fail('superfluous mapping: "%s" -> "%s"' % mappings[i])
- return mapped
- pkg_zip = rule(
- implementation = _zip_file,
- attrs = {
- "out": attr.output(mandatory = True),
- "srcs": attr.label_list(allow_files = True),
- "data": attr.label_list(allow_files = True),
- "deps": attr.label_list(providers = ["zip_file"]),
- "exclude": attr.string_list(),
- "mappings": attr.string_dict(),
- "_zipper": attr.label(default = Label(ZIPPER), allow_single_file = True),
- },
- )
|