Skip to content

A file named like a group in the same directory merges with the group, and which one wins depends on rule order #491

Description

@typeless

Symptom

A file whose basename is literally <g> and a group <g> declared in the same directory become one node. Which node survives depends on the order of the rules in the Tupfile, and neither order gives the right graph.

Group rule first — the file is never tracked. Tupfile:

: a.c |> cp %f %o |> a.o <g>
: *g* |> cat '%f' > %o |> out.txt
$ printf 'A\n' > '<g>'; putup -B b          # Build completed: 2 commands
$ printf 'B\n' > '<g>'; putup -B b
[b] Nothing to do (up to date).
$ cat b/out.txt
A

show graph has one <g> node, and it is the group: b/a.o -> <g> -> cat '<g>' > b/out.txt. The rule's input binds to the group, whose only member is a.o, so the command reruns when a.o changes and never when the file it reads changes. The file on disk has no node.

Consumer rule first — the group adopts the file. Swap the two rules and the edit is picked up (out.txt becomes B). But the graph is still wrong. The glob creates <g> as a file node, and the group rule's pre-check (find_by_dir_name on the directory and <g>) returns that node and uses it as the group, which gives b/a.o -> <g>, a group-membership edge into a source file. cat now reruns whenever a.o changes even though it does not read a.o.

Both fixtures were run against build/putup at dddfb5620.

Cause

NodeType::Group is path-addressable (is_path_addressable in include/pup/core/types.hpp), and a group node is named with its brackets and parented to the Tupfile's directory. So it occupies exactly the (directory, name) key that a file named <g> spells, and the second producer finds the first producer's node by name and reuses it.

This is the residual left open by #486. That fix took Variable, Condition and Phi out of the path namespace and left Group in because a group is looked up by path. PR #490 does not close this either: neither order makes a second add_file_node call, because each is a lookup that returns the node already there.

Upstream

tup keeps groups and files in the same (dir, name) key. On a type mismatch, tup_db_create_node_part_display does not refuse. It force-deletes the existing node (tup_del_id_force) and recreates it with the new type. I have read that from the source but not run tup on this fixture, so I don't know what tup's scanner and parser do to each other across builds.

Decision to make

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions