1# Rule to support Bazel in copying its output files to the dist dir outside of 2# the standard Bazel output user root. 3 4load("@bazel_skylib//rules:copy_file.bzl", "copy_file") 5 6def _label_list_to_manifest(lst): 7 """Convert the outputs of a label list to manifest content.""" 8 all_dist_files = [] 9 for f in lst: 10 all_dist_files += f[DefaultInfo].files.to_list() 11 return all_dist_files, "\n".join([dist_file.short_path for dist_file in all_dist_files]) 12 13def _generate_dist_manifest_impl(ctx): 14 # Create a manifest of dist files to differentiate them from other runfiles. 15 dist_manifest = ctx.actions.declare_file(ctx.attr.name + "_dist_manifest.txt") 16 all_dist_files, dist_manifest_content = _label_list_to_manifest(ctx.attr.data) 17 ctx.actions.write( 18 output = dist_manifest, 19 content = dist_manifest_content, 20 ) 21 22 dist_archives_manifest = ctx.actions.declare_file(ctx.attr.name + "_dist_archives_manifest.txt") 23 all_dist_archives, dist_archives_manifest_content = _label_list_to_manifest(ctx.attr.archives) 24 ctx.actions.write( 25 output = dist_archives_manifest, 26 content = dist_archives_manifest_content, 27 ) 28 29 # Create the runfiles object. 30 runfiles = ctx.runfiles(files = all_dist_files + all_dist_archives + [ 31 dist_manifest, 32 dist_archives_manifest, 33 ]) 34 35 return [DefaultInfo(runfiles = runfiles)] 36 37_generate_dist_manifest = rule( 38 implementation = _generate_dist_manifest_impl, 39 doc = """Generate a manifest of files to be dist to a directory.""", 40 attrs = { 41 "data": attr.label_list( 42 allow_files = True, 43 doc = """Files or targets to copy to the dist dir. 44 45In the case of targets, the rule copies the list of `files` from the target's DefaultInfo provider. 46""", 47 ), 48 "archives": attr.label_list( 49 allow_files = [".tar.gz", ".tar"], 50 doc = """Files or targets to be extracted to the dist dir. 51 52In the case of targets, the rule copies the list of `files` from the target's DefaultInfo provider. 53""", 54 ), 55 }, 56) 57 58def copy_to_dist_dir( 59 name, 60 data = None, 61 archives = None, 62 flat = None, 63 prefix = None, 64 archive_prefix = None, 65 dist_dir = None): 66 """A dist rule to copy files out of Bazel's output directory into a custom location. 67 68 Example: 69 ``` 70 bazel run //path/to/my:dist_target -- --dist_dir=/tmp/dist 71 ``` 72 73 Run `bazel run //path/to/my:dist_target -- --help` for explanations of 74 options. 75 76 Args: 77 name: name of this rule 78 data: A list of labels, whose outputs are copied to `--dist_dir`. 79 archives: A list of labels, whose outputs are treated as tarballs and 80 extracted to `--dist_dir`. 81 flat: If true, `--flat` is provided to the script by default. Flatten the distribution 82 directory. 83 prefix: If specified, `--prefix <prefix>` is provided to the script by default. Path prefix 84 to apply within dist_dir for copied files. 85 archive_prefix: If specified, `--archive_prefix <prefix>` is provided to the script by 86 default. Path prefix to apply within dist_dir for extracted archives. 87 dist_dir: If specified, `--dist_dir <dist_dir>` is provided to the script by default. 88 89 In particular, if this is a relative path, it is interpreted as a relative path 90 under workspace root when the target is executed with `bazel run`. 91 See details by running the target with `--help`. 92 """ 93 94 default_args = [] 95 if flat: 96 default_args.append("--flat") 97 if prefix != None: 98 default_args += ["--prefix", prefix] 99 if archive_prefix != None: 100 default_args += ["--archive_prefix", archive_prefix] 101 if dist_dir != None: 102 default_args += ["--dist_dir", dist_dir] 103 104 _generate_dist_manifest( 105 name = name + "_dist_manifest", 106 data = data, 107 archives = archives, 108 ) 109 110 copy_file( 111 name = name + "_dist_tool", 112 src = "//build/bazel_common_rules/dist:dist.py", 113 out = name + "_dist.py", 114 ) 115 116 # The dist py_binary tool must be colocated in the same package as the 117 # dist_manifest so that the runfiles directory is the same, and that the 118 # dist_manifest is in the data runfiles of the dist tool. 119 native.py_binary( 120 name = name, 121 main = name + "_dist.py", 122 srcs = [name + "_dist.py"], 123 python_version = "PY3", 124 visibility = ["//visibility:public"], 125 data = [name + "_dist_manifest"], 126 args = default_args, 127 ) 128