local-deploy.bzl (3369B)
1 """ 2 Rule for local *nix deployment of a binary build artifact. 3 4 This is useful for local development but is not intended for production deployments. 5 """ 6 7 def _local_deploy_impl(ctx): 8 target = ctx.attr.target 9 copy_runfiles = ctx.attr.copy_runfiles 10 11 # We use a set to avoid duplicates if multiple targets provide the same file 12 files_map = {} 13 transitive_runfiles = [] 14 15 for t in ctx.attr.srcs: 16 if DefaultInfo in t: 17 info = t[DefaultInfo] 18 transitive_runfiles.append(info.default_runfiles) 19 20 # If it's an executable, we prefer that. 21 if info.files_to_run.executable: 22 exe = info.files_to_run.executable 23 files_map[exe.short_path] = exe 24 else: 25 # Otherwise take all files 26 for f in info.files.to_list(): 27 files_map[f.short_path] = f 28 29 # Sort for determinism 30 sorted_paths = sorted(files_map.keys()) 31 32 final_files = [] 33 34 script_content = [ 35 "#!/bin/bash", 36 "set -e", 37 "TARGET_DIR=%s" % target, 38 "sudo mkdir -p \"$TARGET_DIR\"", 39 "", 40 "# Locate the runfiles directory of this deploy script", 41 "if [ -n \"$RUNFILES_DIR\" ]; then", 42 " RUNFILES_SOURCE=\"$RUNFILES_DIR\"", 43 "elif [ -d \"${0}.runfiles\" ]; then", 44 " RUNFILES_SOURCE=\"${0}.runfiles\"", 45 "else", 46 " RUNFILES_SOURCE=\"\"", 47 "fi", 48 "" 49 ] 50 51 for path in sorted_paths: 52 # If "foo.sh" and "foo" exist, skip "foo.sh". 53 is_shadowed = False 54 for ext in [".sh", ".py"]: 55 if path.endswith(ext): 56 wrapper = path[:-len(ext)] 57 if wrapper in files_map: 58 is_shadowed = True 59 break 60 61 if is_shadowed: 62 continue 63 64 f = files_map[path] 65 final_files.append(f) 66 67 # Add copy command 68 script_content.extend([ 69 "SRC=\"%s\"" % f.short_path, 70 "REAL=$(readlink -f \"$SRC\")", 71 "echo \"Copying $SRC to $TARGET_DIR\"", 72 "sudo cp \"$REAL\" \"$TARGET_DIR/$(basename \"$SRC\")\"", 73 ]) 74 75 # Copy runfiles if enabled 76 if copy_runfiles: 77 script_content.extend([ 78 "if [ -n \"$RUNFILES_SOURCE\" ]; then", 79 " DEST_RUNFILES=\"$TARGET_DIR/$(basename \"$SRC\").runfiles\"", 80 " echo \"Copying runfiles to $DEST_RUNFILES\"", 81 " sudo rm -rf \"$DEST_RUNFILES\"", 82 " sudo cp -r \"$RUNFILES_SOURCE\" \"$DEST_RUNFILES\"", 83 "fi", 84 "", 85 ]) 86 87 ctx.actions.write( 88 output = ctx.outputs.executable, 89 is_executable = True, 90 content = "\n".join(script_content) 91 ) 92 93 runfiles = ctx.runfiles(files = final_files) 94 for r in transitive_runfiles: 95 runfiles = runfiles.merge(r) 96 97 return DefaultInfo( 98 executable = ctx.outputs.executable, 99 runfiles = runfiles, 100 ) 101 102 local_deploy = rule( 103 executable = True, 104 implementation = _local_deploy_impl, 105 attrs = { 106 "srcs": attr.label_list(allow_files = True), 107 "target": attr.string(default = "~/.local/share/tools"), 108 "copy_runfiles": attr.bool(default = False), 109 }, 110 )