"""Rules for Wails binding generation.""" load(":private/common.bzl", "bash_launcher", "write_manifest") def _normalize_relative_path(path): if not path or path == ".": return "" return path.strip("/") def _join_relative_path(base, child): normalized_base = _normalize_relative_path(base) normalized_child = _normalize_relative_path(child) if normalized_base and normalized_child: return normalized_base + "/" + normalized_child if normalized_base: return normalized_base return normalized_child def _package_glob_patterns(package_dir, out_dir): normalized = package_dir.strip("./") generated_dir = _join_relative_path(normalized, out_dir) exclude_patterns = ["**/node_modules/**", "**/dist/**"] if generated_dir: exclude_patterns.append(generated_dir + "/**") if not normalized: return ("**", exclude_patterns) return ( normalized + "/**", exclude_patterns + [ normalized + "/node_modules/**", normalized + "/dist/**", ], ) def _workspace_package_dir(label_package, package_dir): if label_package and package_dir and package_dir != ".": return label_package + "/" + package_dir if label_package: return label_package return package_dir def _wails_generate_bindings_impl(ctx): toolchain = ctx.toolchains["//wails:toolchain_type"].wails out_tree = ctx.actions.declare_directory(ctx.label.name + "_out") workspace_package_dir = _workspace_package_dir(ctx.label.package, ctx.attr.package_dir or ".") manifest = write_manifest( ctx, ctx.label.name + ".manifest", ctx.files.srcs, workspace_package_dir, ) build_args = ctx.actions.args() build_args.add("--clean=%s" % ("true" if ctx.attr.clean else "false")) build_args.add("--manifest", manifest.path) build_args.add("--mode", "action") build_args.add("--out", out_tree.path) build_args.add("--out-dir", ctx.attr.out_dir) build_args.add("--ts=%s" % ("true" if ctx.attr.ts else "false")) build_args.add("--wails", toolchain.executable.path) for extra_arg in ctx.attr.extra_args: build_args.add("--extra-arg", extra_arg) ctx.actions.run( executable = ctx.executable._tool, arguments = [build_args], inputs = depset(ctx.files.srcs + [manifest, toolchain.go_executable]), outputs = [out_tree], tools = [ ctx.executable._tool, toolchain.files_to_run, ], env = { "GO_BIN": toolchain.go_executable.path, }, mnemonic = "WailsGenerateBindings", progress_message = "Generating Wails bindings for %s" % ctx.label, ) launcher = ctx.actions.declare_file(ctx.label.name) resolve_lines = """ tool="$(resolve_runfile "{tool_short_path}")" wails="$(resolve_runfile "{wails_short_path}")" go_bin="$(resolve_runfile "{go_short_path}")" workspace_root="${{BUILD_WORKSPACE_DIRECTORY:-}}" if [[ -z "$workspace_root" ]]; then echo "BUILD_WORKSPACE_DIRECTORY is required for bazel run bindings generation" >&2 exit 1 fi workspace_package_dir="{workspace_package_dir}" if [[ -n "$workspace_package_dir" && "$workspace_package_dir" != "." ]]; then workspace_package_dir="${{workspace_root}}/${{workspace_package_dir}}" else workspace_package_dir="${{workspace_root}}" fi """.format( tool_short_path = ctx.executable._tool.short_path, wails_short_path = toolchain.executable.short_path, go_short_path = toolchain.go_executable.short_path, workspace_package_dir = workspace_package_dir or ".", ) extra_args_lines = "\n".join([ 'cmd+=(--extra-arg %s)' % _shell_quote(arg) for arg in ctx.attr.extra_args ]) command_lines = """ cmd=( "$tool" --clean={clean} --mode workspace --out-dir {out_dir} --package-dir "$workspace_package_dir" --ts={ts} --wails "$wails" ) {extra_args_lines} export GO_BIN="$go_bin" exec "${{cmd[@]}}" """.format( clean = "true" if ctx.attr.clean else "false", out_dir = _shell_quote(ctx.attr.out_dir), ts = "true" if ctx.attr.ts else "false", extra_args_lines = extra_args_lines, ) ctx.actions.write( output = launcher, is_executable = True, content = bash_launcher(resolve_lines, command_lines), ) runfiles = ctx.runfiles( files = [ ctx.executable._tool, toolchain.executable, toolchain.go_executable, ], transitive_files = depset(transitive = [ ctx.attr._tool[DefaultInfo].default_runfiles.files, toolchain.default_runfiles.files, toolchain.go_default_runfiles.files, ]), ) return [ DefaultInfo( executable = launcher, files = depset([out_tree]), runfiles = runfiles, ), ] def _shell_quote(value): return "'" + value.replace("'", "'\"'\"'") + "'" _wails_generate_bindings_rule = rule( implementation = _wails_generate_bindings_impl, attrs = { "clean": attr.bool(default = True), "extra_args": attr.string_list(), "out_dir": attr.string(mandatory = True), "package_dir": attr.string(default = "."), "srcs": attr.label_list( allow_files = True, mandatory = True, ), "ts": attr.bool(default = True), "_tool": attr.label( default = "//wails/tools:generate_bindings_action", cfg = "exec", executable = True, ), }, executable = True, toolchains = ["//wails:toolchain_type"], ) def wails_generate_bindings( name, out_dir, package_dir = ".", clean = True, ts = True, extra_args = None, tags = None, visibility = None): include_pattern, exclude_patterns = _package_glob_patterns(package_dir, out_dir) _wails_generate_bindings_rule( name = name, clean = clean, extra_args = extra_args or [], out_dir = out_dir, package_dir = package_dir, srcs = native.glob([include_pattern], exclude = exclude_patterns), tags = tags, visibility = visibility, ts = ts, )