feat: add rule to run tool in BUILD_WORKSPACE_DIRECTORY (#60)

This PR adds a rule which is identical to `cwd`, except that it runs the
tool in `BUILD_WORKSPACE_DIRECTORY` instead of
`BUILD_WORKING_DIRECTORY`. There are some tools which should always be
run from the module/workspace root and I think it would be useful to add
a convenience rule for this.
diff --git a/examples/module/BUILD.bazel b/examples/module/BUILD.bazel
index 9e6b820..e143f37 100644
--- a/examples/module/BUILD.bazel
+++ b/examples/module/BUILD.bazel
@@ -15,3 +15,12 @@
     ],
     data = ["@multitool//tools/target-determinator:cwd"],
 )
+
+sh_test(
+    name = "integration_test_workspace_root",
+    srcs = ["integration_test.sh"],
+    args = [
+        "$(location @multitool//tools/target-determinator:workspace_root)",
+    ],
+    data = ["@multitool//tools/target-determinator:workspace_root"],
+)
diff --git a/examples/workspace/BUILD.bazel b/examples/workspace/BUILD.bazel
index 9e6b820..e143f37 100644
--- a/examples/workspace/BUILD.bazel
+++ b/examples/workspace/BUILD.bazel
@@ -15,3 +15,12 @@
     ],
     data = ["@multitool//tools/target-determinator:cwd"],
 )
+
+sh_test(
+    name = "integration_test_workspace_root",
+    srcs = ["integration_test.sh"],
+    args = [
+        "$(location @multitool//tools/target-determinator:workspace_root)",
+    ],
+    data = ["@multitool//tools/target-determinator:workspace_root"],
+)
diff --git a/multitool/private/BUILD.bazel b/multitool/private/BUILD.bazel
index 0df68e1..2f32f09 100644
--- a/multitool/private/BUILD.bazel
+++ b/multitool/private/BUILD.bazel
@@ -1,8 +1,8 @@
 load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
 
 exports_files([
-    "cwd.template.bat",
-    "cwd.template.sh",
+    "run_in.template.bat",
+    "run_in.template.sh",
 ])
 
 bzl_library(
diff --git a/multitool/private/cwd.bzl b/multitool/private/cwd.bzl
index 3703836..803819c 100644
--- a/multitool/private/cwd.bzl
+++ b/multitool/private/cwd.bzl
@@ -1,30 +1,12 @@
 "cwd: a rule for executing an executable in the BUILD_WORKING_DIRECTORY"
 
+load(":run_in.bzl", "run_in", "run_in_attrs")
+
 def _cwd_impl(ctx):
-    # This algorithm requires --enable_runfiles (enabled by default on non-windows)
-    template = ctx.file._template_sh
-    wrapper_name = ctx.label.name
-    tool_short_path = ctx.file.tool.short_path
-    if ctx.file.tool.extension == "exe":
-        template = ctx.file._template_bat
-        wrapper_name = wrapper_name + ".bat"
-        tool_short_path = tool_short_path.replace("/", "\\")
-    output = ctx.actions.declare_file(wrapper_name)
-    ctx.actions.expand_template(
-        template = template,
-        output = output,
-        substitutions = {
-            "{{tool}}": tool_short_path,
-        },
-    )
-    return [DefaultInfo(executable = output, runfiles = ctx.runfiles(files = [ctx.file.tool]))]
+    return run_in(ctx, "BUILD_WORKING_DIRECTORY")
 
 cwd = rule(
     implementation = _cwd_impl,
-    attrs = {
-        "tool": attr.label(mandatory = True, allow_single_file = True, executable = True, cfg = "exec"),
-        "_template_sh": attr.label(default = "//multitool/private:cwd.template.sh", allow_single_file = True),
-        "_template_bat": attr.label(default = "//multitool/private:cwd.template.bat", allow_single_file = True),
-    },
+    attrs = run_in_attrs,
     executable = True,
 )
diff --git a/multitool/private/cwd.template.bat b/multitool/private/cwd.template.bat
deleted file mode 100644
index fcaf9d4..0000000
--- a/multitool/private/cwd.template.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@set tool=%cd%\{{tool}}
-@cd %BUILD_WORKING_DIRECTORY%
-@%tool% %*
diff --git a/multitool/private/cwd.template.sh b/multitool/private/cwd.template.sh
deleted file mode 100644
index 0f6270f..0000000
--- a/multitool/private/cwd.template.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-
-tool="$PWD/{{tool}}"
-cd "$BUILD_WORKING_DIRECTORY" && exec "$tool" "$@"
diff --git a/multitool/private/hub_repo_tool_template/BUILD.bazel.template b/multitool/private/hub_repo_tool_template/BUILD.bazel.template
index ad27ef2..56e54db 100644
--- a/multitool/private/hub_repo_tool_template/BUILD.bazel.template
+++ b/multitool/private/hub_repo_tool_template/BUILD.bazel.template
@@ -1,6 +1,7 @@
 # generated by multitool
 
 load("@rules_multitool//multitool:cwd.bzl", "cwd")
+load("@rules_multitool//multitool:workspace_root.bzl", "workspace_root")
 load(":tool.bzl", "tool")
 
 toolchain_type(
@@ -18,3 +19,9 @@
     tool = ":{name}",
     visibility = ["//visibility:public"],
 )
+
+workspace_root(
+    name = "workspace_root",
+    tool = ":{name}",
+    visibility = ["//visibility:public"],
+)
diff --git a/multitool/private/run_in.bzl b/multitool/private/run_in.bzl
new file mode 100644
index 0000000..619c523
--- /dev/null
+++ b/multitool/private/run_in.bzl
@@ -0,0 +1,39 @@
+"run_in provides a shared implementation for cwd and workspace_root execution"
+
+run_in_attrs = {
+    "tool": attr.label(mandatory = True, allow_single_file = True, executable = True, cfg = "exec"),
+    "_template_sh": attr.label(default = "//multitool/private:run_in.template.sh", allow_single_file = True),
+    "_template_bat": attr.label(default = "//multitool/private:run_in.template.bat", allow_single_file = True),
+}
+
+def run_in(ctx, env_var):
+    """
+    run_in implements a rule that runs a tool in a directory provided by env_var
+
+    Args:
+        ctx: rule ctx argument
+        env_var: env var string that contains the desired execution directory
+
+    Returns:
+        A list including the DefaultInfo provider for the created wrapper
+        executable
+    """
+
+    # This algorithm requires --enable_runfiles (enabled by default on non-windows)
+    template = ctx.file._template_sh
+    wrapper_name = ctx.label.name
+    tool_short_path = ctx.file.tool.short_path
+    if ctx.file.tool.extension == "exe":
+        template = ctx.file._template_bat
+        wrapper_name = wrapper_name + ".bat"
+        tool_short_path = tool_short_path.replace("/", "\\")
+    output = ctx.actions.declare_file(wrapper_name)
+    ctx.actions.expand_template(
+        template = template,
+        output = output,
+        substitutions = {
+            "{{tool}}": tool_short_path,
+            "{{env_var}}": env_var,
+        },
+    )
+    return [DefaultInfo(executable = output, runfiles = ctx.runfiles(files = [ctx.file.tool]))]
diff --git a/multitool/private/run_in.template.bat b/multitool/private/run_in.template.bat
new file mode 100644
index 0000000..0a2a83a
--- /dev/null
+++ b/multitool/private/run_in.template.bat
@@ -0,0 +1,3 @@
+@set tool=%cd%\{{tool}}
+@cd %{{env_var}}%
+@%tool% %*
diff --git a/multitool/private/run_in.template.sh b/multitool/private/run_in.template.sh
new file mode 100644
index 0000000..480412b
--- /dev/null
+++ b/multitool/private/run_in.template.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+tool="$PWD/{{tool}}"
+cd "${{env_var}}" && exec "$tool" "$@"
diff --git a/multitool/private/workspace_root.bzl b/multitool/private/workspace_root.bzl
new file mode 100644
index 0000000..4aba24b
--- /dev/null
+++ b/multitool/private/workspace_root.bzl
@@ -0,0 +1,12 @@
+"workspace_root: a rule for executing an executable in the BUILD_WORKSPACE_DIRECTORY"
+
+load(":run_in.bzl", "run_in", "run_in_attrs")
+
+def _workspace_root_impl(ctx):
+    return run_in(ctx, "BUILD_WORKSPACE_DIRECTORY")
+
+workspace_root = rule(
+    implementation = _workspace_root_impl,
+    attrs = run_in_attrs,
+    executable = True,
+)
diff --git a/multitool/workspace_root.bzl b/multitool/workspace_root.bzl
new file mode 100644
index 0000000..0c5fb30
--- /dev/null
+++ b/multitool/workspace_root.bzl
@@ -0,0 +1,5 @@
+"multitool workspace_root execution rule"
+
+load("@rules_multitool//multitool/private:workspace_root.bzl", _workspace_root = "workspace_root")
+
+workspace_root = _workspace_root
diff --git a/readme.md b/readme.md
index 7919a13..5ac45b4 100644
--- a/readme.md
+++ b/readme.md
@@ -72,6 +72,8 @@
 
 To run a tool in the current working directory, use the convenience target `@multitool//tools/tool-name:cwd`.
 
+To run a tool in the Bazel module or workspace root, use the convenience target `@multitool/tools/tool-name:workspace_root`.
+
 A common pattern we recommend to further simplify invoking tools for repository users it to:
 
 1.  Create a `tools/` directory