Symptom
Whether putup refuses an output under a non-directory depends on rule order. PR #494 refuses sub/x.o when a rule has already named the file sub. Put the output rule first, and the command runs and fails in the shell instead:
: |> echo hi > %o |> sub/x.o
: sub |> cat %f > %o |> a.txt
sub is a regular file in the source tree.
$ putup -B .
/bin/sh: 1: cannot create sub/x.o: Directory nonexistent
[.] Build completed: 1 commands (1 failed) in 1ms
The reverse case has the same cause. A path that already holds a Directory node can be claimed as an output, and the command then fails in the shell:
: |> echo b > %o |> gen/x
: |> echo a > %o |> gen
/bin/sh: 1: cannot create gen: Is a directory
Both were run against build/putup from the #494 branch.
Upstream
tup parse refuses both at parse time:
tup error: Unable to output to a different directory because 'sub' is a normal file
tup error: Failed to find directory ID for dir 'sub/x.o' relative to '.'
tup error: Error parsing Tupfile line 1
tup error: Attempting to insert 'gen' as a generated node when it already exists as a different type (generated directory). ...
tup error: Error parsing Tupfile line 2
The first refusal comes from find_dir_tupid_dt_pg; tup knows sub is a file from its filesystem scan, so rule order does not matter. The second comes from validate_output.
Cause
putup learns a source path's type only when a rule names it:
ensure_file_node (src/graph/dag.cpp) creates each missing intermediate component as NodeType::Directory without consulting the disk. So the output rule mints a Directory node for sub. The later input sub then finds that node through path_to_node and never retypes it.
ensure_file_node(…, NodeType::Generated) promotes an existing Ghost or File node to Generated, but returns an existing Directory node unchanged.
Fix direction
Both cases are type checks at the point where ensure_file_node binds an existing or new node:
- An intermediate component that exists on disk as a non-directory should be refused.
- A Generated request that lands on a Directory node should be refused, following
validate_output.
REQ-OUTPUT-UNDER-DIRECTORY (spec/requirements/output-paths.ears.md, added in #494) records the first half of this gap in its reference.
Symptom
Whether putup refuses an output under a non-directory depends on rule order. PR #494 refuses
sub/x.owhen a rule has already named the filesub. Put the output rule first, and the command runs and fails in the shell instead:subis a regular file in the source tree.The reverse case has the same cause. A path that already holds a Directory node can be claimed as an output, and the command then fails in the shell:
Both were run against
build/putupfrom the #494 branch.Upstream
tup parserefuses both at parse time:The first refusal comes from
find_dir_tupid_dt_pg; tup knowssubis a file from its filesystem scan, so rule order does not matter. The second comes fromvalidate_output.Cause
putup learns a source path's type only when a rule names it:
ensure_file_node(src/graph/dag.cpp) creates each missing intermediate component asNodeType::Directorywithout consulting the disk. So the output rule mints a Directory node forsub. The later inputsubthen finds that node throughpath_to_nodeand never retypes it.ensure_file_node(…, NodeType::Generated)promotes an existing Ghost or File node to Generated, but returns an existing Directory node unchanged.Fix direction
Both cases are type checks at the point where
ensure_file_nodebinds an existing or new node:validate_output.REQ-OUTPUT-UNDER-DIRECTORY(spec/requirements/output-paths.ears.md, added in #494) records the first half of this gap in itsreference.