Skip to content

Commit

Permalink
Detect path resolution ambiguity (#45)
Browse files Browse the repository at this point in the history
* Detect path resolution ambiguity

* Fix test
  • Loading branch information
simonask authored Feb 5, 2025
1 parent 2ee6bf1 commit 49cdd92
Show file tree
Hide file tree
Showing 19 changed files with 667 additions and 305 deletions.
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- [Variables](./language/variables.md)
- [Expressions](./language/expressions.md)
- [String Interpolation](./language/strings.md)
- [Path resolution](./language/path_resolution.md)
- [Patterns](./language/patterns.md)
- [Recipe commands](./language/recipe_commands.md)
- [Built-in variables](./language/builtins.md)
Expand Down
41 changes: 41 additions & 0 deletions book/src/language/path_resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Path resolution

Werk supports translating [abstract paths](../paths.md) into native OS paths in
string interpolations, using the special `"<...>"` interpolation syntax.

Normal string interpolations `"{...}"` are always "verbatim" - the interpolation
is performed literally.

However, string interpolation with `<...>` performs extra logic to obtain a
native OS path whenever it occurs, and this logic is sensitive to the
surroundings of the interpolation, as well as the presence of build recipe
rules.

Consider the following Werkfile:

```werk
# c:\workspace
# target\
# dir\
# foo.txt
config out-dir = "target"
let input = "foo.txt"
let output = "bar.txt"
let dir = "dir"
```

- `"<input>"` resolves to `c:\workspace\foo.txt`, because `foo.txt` exists in
the workspace.
- `"<output>"` resolves to `c:\workspace\target\bar.txt`, because `bar.txt`
does not exist in the workspace.
- `"<input:out-dir>"` resolves to `c:\workspace\target\foo.txt`, because it is
explicitly requested.
- `"<output:workspace>"` resolves to `c:\workspace\bar.txt`, because it is
explicitly requested, even though the file does not exist in the workspace.
- `"<dir>"` resolves to `c:\workspace\dir`, even though it is a directory.
- When an `<...>` interpolation would match a file in the workspace, but also
matches a build recipe, `werk` fails with an error describing the ambiguity.
The path can be disambiguated by using `:out-dir` or `:workspace` to
disambiguate path resolution.
6 changes: 6 additions & 0 deletions book/src/language/strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ they are applied in order.
produces the file-without-directory part of the path.
- `{...:ext}`: When the stem refers to an [abstract path](../paths.md), produces
the file extension (without the `.`) of the path.
- `<...:out-dir>`: Disambiguate [native path resolution](./path_resolution.md)
to produce a path in the output directory. Does nothing in `{...}`
interpolations.
- `<...:workspace>`: Disambiguate [native path resolution](./path_resolution.md)
to produce a path in the workspace directory. Does nothing in `{...}`
interpolations.

## String interpolation example

Expand Down
13 changes: 7 additions & 6 deletions book/src/paths.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ syntax](./language/strings.md#string-interpolation) `"<var>"`, the abstract path
stored in `var` will be converted to a native absolute path within the
workspace.

Native path resolution may resolve to either an input file in the workspace or a
generated file in the output directory. This check is based on existence: If the
file is found in the workspace, it resolves to the file inside the workspace.
Otherwise, it is assumed that a build recipe will generate the file in the
output directory, and it resolves to an absolute path inside the output
directory, mirroring the directory structure of the workspace.
[Native path resolution](./language/path_resolution.md) may resolve to either an
input file in the workspace or a generated file in the output directory. This
check is based on existence: If the file is found in the workspace, it resolves
to the file inside the workspace. Otherwise, it is assumed that a build recipe
will generate the file in the output directory, and it resolves to an absolute
path inside the output directory, mirroring the directory structure of the
workspace.

In general, build recipes should take care to not clobber the workspace and only
generate files with paths that coincide with paths in the workspace.
Expand Down
15 changes: 15 additions & 0 deletions examples/issue-41/Werkfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
config out-dir = "../../target/examples/issue-41"
config default = "build"

build "foo" {
info "<out>"
}

build "bar" {
info "<out>"
}

task build {
build "foo"
build "bar"
}
4 changes: 4 additions & 0 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ path = "test_pattern_match.rs"
name = "test_outdatedness"
path = "test_outdatedness.rs"

[[test]]
name = "test_path_resolution"
path = "test_path_resolution.rs"

[[test]]
name = "test_cases"
path = "test_cases.rs"
Expand Down
Loading

0 comments on commit 49cdd92

Please sign in to comment.