diff --git a/README.md b/README.md
index 4e0dcf5c94..f076218b45 100644
--- a/README.md
+++ b/README.md
@@ -1842,6 +1842,8 @@ which will halt execution.
- `path_exists(path)` - Returns `true` if the path points at an existing entity
and `false` otherwise. Traverses symbolic links, and returns `false` if the
path is inaccessible or points to a broken symlink.
+- `read_to_string(path)`master - Returns the content of file at
+ `path` as string.
##### Error Reporting
diff --git a/src/function.rs b/src/function.rs
index abeae94368..d292955af5 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -87,6 +87,7 @@ pub(crate) fn get(name: &str) -> Option {
"path_exists" => Unary(path_exists),
"prepend" => Binary(prepend),
"quote" => Unary(quote),
+ "read_to_string" => Unary(read_to_string),
"replace" => Ternary(replace),
"replace_regex" => Ternary(replace_regex),
"semver_matches" => Binary(semver_matches),
@@ -528,6 +529,11 @@ fn quote(_context: Context, s: &str) -> FunctionResult {
Ok(format!("'{}'", s.replace('\'', "'\\''")))
}
+fn read_to_string(context: Context, filename: &str) -> FunctionResult {
+ fs::read_to_string(context.evaluator.context.working_directory().join(filename))
+ .map_err(|err| format!("I/O error reading `{filename}`: {err}"))
+}
+
fn replace(_context: Context, s: &str, from: &str, to: &str) -> FunctionResult {
Ok(s.replace(from, to))
}
diff --git a/tests/functions.rs b/tests/functions.rs
index d68b3946b0..e29e04112d 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -1258,3 +1258,23 @@ fn style_unknown() {
.status(EXIT_FAILURE)
.run();
}
+
+#[test]
+fn read_to_string() {
+ Test::new()
+ .justfile("foo := read_to_string('bar')")
+ .write("bar", "baz")
+ .args(["--evaluate", "foo"])
+ .stdout("baz")
+ .run();
+}
+
+#[test]
+fn read_to_string_not_found() {
+ Test::new()
+ .justfile("foo := read_to_string('bar')")
+ .args(["--evaluate", "foo"])
+ .stderr_regex(r"error: Call to function `read_to_string` failed: I/O error reading `bar`: .*")
+ .status(EXIT_FAILURE)
+ .run();
+}