"""mdBook rules""" MdBookInfo = provider( doc = "Information about a `mdbook` target.", fields = { "config": "File: The `book.toml` file.", "plugins": "Depset[File]: TODO", "srcs": "Depset[File]: TODO", }, ) def _map_inputs(file): return "{}={}".format(file.path, file.short_path) def _mdbook_impl(ctx): output = ctx.actions.declare_directory(ctx.label.name) toolchain = ctx.toolchains["@rules_rust_mdbook//:toolchain_type"] plugin_paths = depset([ "${{pwd}}/{}".format(file.dirname) for file in depset(ctx.files.plugins, transitive = [toolchain.plugins]).to_list() ]) is_windows = toolchain.mdbook.basename.endswith(".exe") path_sep = ";" if is_windows else ":" plugin_path = path_sep.join(plugin_paths.to_list()) inputs = depset([ctx.file.book] + ctx.files.srcs) inputs_map_args = ctx.actions.args() inputs_map_args.use_param_file("%s", use_always = True) inputs_map_args.add_all(inputs, map_each = _map_inputs) args = ctx.actions.args() # This arg is used for `--dest-dir` within the action. args.add(output.path) args.add(toolchain.mdbook) args.add("build") args.add("${{pwd}}/{}".format(ctx.file.book.dirname)) ctx.actions.run( mnemonic = "MdBookBuild", executable = ctx.executable._process_wrapper, tools = depset(ctx.files.plugins, transitive = [toolchain.all_files]), outputs = [output], arguments = [inputs_map_args, args], env = {"MDBOOK_PLUGIN_PATH": plugin_path}, inputs = inputs, toolchain = "@rules_rust_mdbook//:toolchain_type", ) return [ DefaultInfo( files = depset([output]), ), MdBookInfo( srcs = depset(ctx.files.srcs), config = ctx.file.book, plugins = depset(ctx.files.plugins), ), ] mdbook = rule( implementation = _mdbook_impl, doc = "Rules to create book from markdown files using `mdBook`.", attrs = { "book": attr.label( doc = "The `book.toml` file.", allow_single_file = ["book.toml"], mandatory = True, ), "plugins": attr.label_list( doc = ( "Executables to inject into `PATH` for use in " + "[preprocessor commands](https://rust-lang.github.io/mdBook/format/configuration/preprocessors.html#provide-your-own-command)." ), allow_files = True, cfg = "exec", ), "srcs": attr.label_list( doc = "All inputs to the book.", allow_files = True, ), "_process_wrapper": attr.label( cfg = "exec", executable = True, default = Label("//private:process_wrapper"), ), }, toolchains = ["@rules_rust_mdbook//:toolchain_type"], ) def _rlocationpath(file, workspace_name): if file.short_path.startswith("../"): return file.short_path[len("../"):] return "{}/{}".format(workspace_name, file.short_path) def _mdbook_server_impl(ctx): toolchain = ctx.toolchains["@rules_rust_mdbook//:toolchain_type"] book_info = ctx.attr.book[MdBookInfo] args = ctx.actions.args() args.add("--mdbook={}".format(_rlocationpath(toolchain.mdbook, ctx.workspace_name))) args.add("--config={}".format(_rlocationpath(book_info.config, ctx.workspace_name))) args.add("--hostname={}".format(ctx.attr.hostname)) args.add("--port={}".format(ctx.attr.port)) workspace_name = ctx.workspace_name def _runfile_map(file): return "--plugin={}".format(_rlocationpath(file, workspace_name)) args.add_all(depset(transitive = [book_info.plugins, toolchain.plugins]), map_each = _runfile_map, allow_closure = True) args_file = ctx.actions.declare_file("{}.mdbook_serve_args.txt".format(ctx.label.name)) ctx.actions.write( output = args_file, content = args, ) is_windows = toolchain.mdbook.basename.endswith(".exe") executable = ctx.actions.declare_file("{}{}".format( ctx.label.name, ".exe" if is_windows else "", )) ctx.actions.symlink( output = executable, target_file = ctx.executable._server, is_executable = True, ) return [ DefaultInfo( executable = executable, files = depset([executable]), runfiles = ctx.runfiles( files = [ book_info.config, args_file, ctx.executable._server, ], transitive_files = depset(transitive = [ book_info.srcs, book_info.plugins, toolchain.all_files, ]), ), ), RunEnvironmentInfo( environment = { "RULES_MDBOOK_SERVE_ARGS_FILE": _rlocationpath(args_file, ctx.workspace_name), }, ), ] mdbook_server = rule( implementation = _mdbook_server_impl, doc = "Spawn an mdbook server for a given `mdbook` target.", attrs = { "book": attr.label( doc = "The `mdbook` target to serve.", providers = [MdBookInfo], mandatory = True, ), "hostname": attr.string( doc = "The default hostname to use (Can be overridden on the command line).", default = "localhost", ), "port": attr.string( doc = "The default port to use (Can be overridden on the command line).", default = "3000", ), "_server": attr.label( doc = "TODO", cfg = "target", executable = True, default = Label("//private:server"), ), }, toolchains = ["@rules_rust_mdbook//:toolchain_type"], executable = True, )