summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbst-marge-bot <marge-bot@buildstream.build>2020-06-24 06:47:06 +0000
committerbst-marge-bot <marge-bot@buildstream.build>2020-06-24 06:47:06 +0000
commit88f280d541e2f7c7b8655bab65bb1eb682872a16 (patch)
treeaeb0a23c5ee8cec0c1ffcf61da1f83453fa63601
parente4e3b4568e6f7e1575fdd90ec2c688ceee97322e (diff)
parent3d5d655e40470a805999834560605d6e54bd7d72 (diff)
downloadbuildstream-88f280d541e2f7c7b8655bab65bb1eb682872a16.tar.gz
Merge branch 'tristan/junction-jungle' into 'master'
Explicit control of junction configuration overrides Closes #1326 See merge request BuildStream/buildstream!1901
-rw-r--r--doc/examples/junction-includes/project.conf2
-rw-r--r--doc/source/format_project.rst98
-rw-r--r--src/buildstream/_loader/loadcontext.py177
-rw-r--r--src/buildstream/_loader/loadelement.pyx4
-rw-r--r--src/buildstream/_loader/loader.py240
-rw-r--r--src/buildstream/_project.py101
-rw-r--r--src/buildstream/exceptions.py3
-rw-r--r--src/buildstream/plugins/elements/junction.py212
-rw-r--r--tests/format/junctions.py802
-rw-r--r--tests/format/junctions/bar/app.bst7
-rw-r--r--tests/format/junctions/bar/bar.txt1
-rw-r--r--tests/format/junctions/bar/target.bst5
-rw-r--r--tests/format/junctions/circular-references/link-subsubsubproject.bst4
-rw-r--r--tests/format/junctions/circular-references/project.conf (renamed from tests/format/junctions/bar/project.conf)2
-rw-r--r--tests/format/junctions/circular-references/subproject-overriden-with-circular-reference-link.bst8
-rw-r--r--tests/format/junctions/circular-references/subproject-overriden-with-circular-reference.bst8
-rw-r--r--tests/format/junctions/circular-references/subproject.bst4
-rw-r--r--tests/format/junctions/circular-references/subproject/project.conf (renamed from tests/format/junctions/conflict/project.conf)2
-rw-r--r--tests/format/junctions/circular-references/subproject/sub.txt1
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/subsubsub.txt1
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/circular-references/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/circular-references/subproject/target.bst (renamed from tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/base.bst)2
-rw-r--r--tests/format/junctions/circular-references/target-overridden-subsubproject-circular-link.bst4
-rw-r--r--tests/format/junctions/circular-references/target-overridden-subsubproject-circular.bst4
-rw-r--r--tests/format/junctions/conflict/target.bst6
-rw-r--r--tests/format/junctions/conflicts/include-conflict-target.bst5
-rw-r--r--tests/format/junctions/conflicts/include-conflict.bst7
-rw-r--r--tests/format/junctions/conflicts/nested-conflict-toplevel.bst4
-rw-r--r--tests/format/junctions/conflicts/override-conflict.bst8
-rw-r--r--tests/format/junctions/conflicts/plugin-conflict.bst4
-rw-r--r--tests/format/junctions/conflicts/project.conf2
-rw-r--r--tests/format/junctions/conflicts/simple-conflict.bst5
-rw-r--r--tests/format/junctions/conflicts/subproject-override-conflicting-path.bst13
-rw-r--r--tests/format/junctions/conflicts/subproject.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/project.conf2
-rw-r--r--tests/format/junctions/conflicts/subproject/sub.txt1
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject-conflict-target.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject-conflict.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject-conflict/deepsurprise.txt1
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject-conflict/project.conf2
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject-conflict/target.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/subsubsub.txt1
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject/target.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject2.bst4
-rw-r--r--tests/format/junctions/conflicts/subproject2/inc.yaml1
-rw-r--r--tests/format/junctions/conflicts/subproject2/plugins/found.py19
-rw-r--r--tests/format/junctions/conflicts/subproject2/project.conf8
-rw-r--r--tests/format/junctions/conflicts/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/conflicts/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/project.conf9
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-full-path/target.bst6
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/project.conf7
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/project.conf7
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-incomplete/target.bst6
-rw-r--r--tests/format/junctions/duplicates-nested-link1/project.conf8
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/project.conf7
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject1-link.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-link1/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link1/target.bst6
-rw-r--r--tests/format/junctions/duplicates-nested-link2/project.conf7
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/project.conf8
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject2-link.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-link2/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-link2/target.bst6
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/project.conf8
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/project.conf7
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject1-link.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested-not-found/target.bst6
-rw-r--r--tests/format/junctions/duplicates-nested/project.conf7
-rw-r--r--tests/format/junctions/duplicates-nested/subproject.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/project.conf8
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-nested/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-nested/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-nested/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-nested/target.bst6
-rw-r--r--tests/format/junctions/duplicates-override-dup/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject.bst8
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/project.conf8
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject3.bst4
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject3/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject3/sub3.txt1
-rw-r--r--tests/format/junctions/duplicates-override-dup/subproject3/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-dup/target.bst5
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/duplicate.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/duplicate/duplicate.txt1
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/duplicate/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/duplicate/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/override.bst (renamed from tests/format/junctions/conflict/foo.bst)2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/override/overridden-again.txt1
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/override/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/override/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/project.conf7
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject.bst8
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/override.bst (renamed from tests/format/junctions/foo/base.bst)2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/override/overridden.txt1
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/override/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/override/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/project.conf7
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject.bst8
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/original.txt1
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/subproject/subsubsubproject-link.bst4
-rw-r--r--tests/format/junctions/duplicates-override-twice-link/target.bst5
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/project.conf7
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-incomplete/target.bst5
-rw-r--r--tests/format/junctions/duplicates-simple-link/project.conf8
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject2-link.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-simple-link/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-link/target.bst5
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/project.conf8
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple-not-found/target.bst5
-rw-r--r--tests/format/junctions/duplicates-simple/project.conf8
-rw-r--r--tests/format/junctions/duplicates-simple/subproject1.bst4
-rw-r--r--tests/format/junctions/duplicates-simple/subproject1/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple/subproject1/sub.txt1
-rw-r--r--tests/format/junctions/duplicates-simple/subproject1/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple/subproject2.bst4
-rw-r--r--tests/format/junctions/duplicates-simple/subproject2/project.conf2
-rw-r--r--tests/format/junctions/duplicates-simple/subproject2/sub2.txt1
-rw-r--r--tests/format/junctions/duplicates-simple/subproject2/target.bst4
-rw-r--r--tests/format/junctions/duplicates-simple/target.bst5
-rw-r--r--tests/format/junctions/foo/app.bst7
-rw-r--r--tests/format/junctions/foo/foo.txt1
-rw-r--r--tests/format/junctions/full-path/element-full-path-notfound.bst3
-rw-r--r--tests/format/junctions/full-path/element-full-path.bst3
-rw-r--r--tests/format/junctions/full-path/junction-full-path-notfound.bst4
-rw-r--r--tests/format/junctions/full-path/junction-full-path.bst4
-rw-r--r--tests/format/junctions/full-path/project.conf2
-rw-r--r--tests/format/junctions/full-path/subproject.bst4
-rw-r--r--tests/format/junctions/full-path/subproject/project.conf2
-rw-r--r--tests/format/junctions/full-path/subproject/sub.txt1
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/subsubsub.txt1
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/full-path/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/full-path/subproject/target.bst4
-rw-r--r--tests/format/junctions/inconsistent-names/elements/junction-A.bst4
-rw-r--r--tests/format/junctions/inconsistent-names/elements/junction-B-diff-name.bst4
-rw-r--r--tests/format/junctions/inconsistent-names/elements/target.bst9
-rw-r--r--tests/format/junctions/inconsistent-names/files/foo0
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/elements/app.bst6
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/elements/junction-B.bst4
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/elements/lib.bst7
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/files/app0
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/files/lib0
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/junctionB/base/baseimg0
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/lib2.bst6
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/junctionB/files/lib20
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/junctionB/project.conf8
-rw-r--r--tests/format/junctions/inconsistent-names/junctionA/project.conf8
-rw-r--r--tests/format/junctions/inconsistent-names/project.conf8
-rw-r--r--tests/format/junctions/internal-and-conflict/project.conf2
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject/project.conf6
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/subproject/subtarget.bst10
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-again.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-again/project.conf2
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-again/subsub-again.txt1
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-again/target.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-conflict.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-conflict/project.conf2
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-conflict/subsub-again.txt1
-rw-r--r--tests/format/junctions/internal-and-conflict/subsubproject-conflict/target.bst4
-rw-r--r--tests/format/junctions/internal-and-conflict/target.bst6
-rw-r--r--tests/format/junctions/internal-double/project.conf2
-rw-r--r--tests/format/junctions/internal-double/subproject1.bst4
-rw-r--r--tests/format/junctions/internal-double/subproject1/project.conf6
-rw-r--r--tests/format/junctions/internal-double/subproject1/subsubproject.bst4
-rw-r--r--tests/format/junctions/internal-double/subproject1/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/internal-double/subproject1/subsubproject/subsub1.txt1
-rw-r--r--tests/format/junctions/internal-double/subproject1/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/internal-double/subproject1/subtarget.bst10
-rw-r--r--tests/format/junctions/internal-double/subproject2.bst4
-rw-r--r--tests/format/junctions/internal-double/subproject2/project.conf6
-rw-r--r--tests/format/junctions/internal-double/subproject2/subsubproject.bst4
-rw-r--r--tests/format/junctions/internal-double/subproject2/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/internal-double/subproject2/subsubproject/subsub2.txt1
-rw-r--r--tests/format/junctions/internal-double/subproject2/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/internal-double/subproject2/subtarget.bst10
-rw-r--r--tests/format/junctions/internal-double/subsubproject-again.bst4
-rw-r--r--tests/format/junctions/internal-double/subsubproject-again/project.conf2
-rw-r--r--tests/format/junctions/internal-double/subsubproject-again/subsub-again.txt1
-rw-r--r--tests/format/junctions/internal-double/subsubproject-again/target.bst4
-rw-r--r--tests/format/junctions/internal-double/target.bst6
-rw-r--r--tests/format/junctions/internal-link/project.conf2
-rw-r--r--tests/format/junctions/internal-link/subproject.bst4
-rw-r--r--tests/format/junctions/internal-link/subproject/project.conf6
-rw-r--r--tests/format/junctions/internal-link/subproject/subsubproject-link.bst4
-rw-r--r--tests/format/junctions/internal-link/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/internal-link/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/internal-link/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/internal-link/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/internal-link/subproject/subtarget.bst10
-rw-r--r--tests/format/junctions/internal-link/subsubproject-again.bst4
-rw-r--r--tests/format/junctions/internal-link/subsubproject-again/project.conf2
-rw-r--r--tests/format/junctions/internal-link/subsubproject-again/subsub-again.txt1
-rw-r--r--tests/format/junctions/internal-link/subsubproject-again/target.bst4
-rw-r--r--tests/format/junctions/internal-link/target.bst5
-rw-r--r--tests/format/junctions/internal-override/project.conf2
-rw-r--r--tests/format/junctions/internal-override/subproject.bst8
-rw-r--r--tests/format/junctions/internal-override/subproject/project.conf6
-rw-r--r--tests/format/junctions/internal-override/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/internal-override/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/internal-override/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/internal-override/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/internal-override/subproject/subtarget.bst10
-rw-r--r--tests/format/junctions/internal-override/subsubproject-again.bst4
-rw-r--r--tests/format/junctions/internal-override/subsubproject-again/project.conf2
-rw-r--r--tests/format/junctions/internal-override/subsubproject-again/subsub-again.txt1
-rw-r--r--tests/format/junctions/internal-override/subsubproject-again/target.bst4
-rw-r--r--tests/format/junctions/internal-override/subsubproject-override.bst4
-rw-r--r--tests/format/junctions/internal-override/subsubproject-override/project.conf2
-rw-r--r--tests/format/junctions/internal-override/subsubproject-override/subsub-override.txt1
-rw-r--r--tests/format/junctions/internal-override/subsubproject-override/target.bst4
-rw-r--r--tests/format/junctions/internal-override/target.bst5
-rw-r--r--tests/format/junctions/internal-simple/project.conf2
-rw-r--r--tests/format/junctions/internal-simple/subproject.bst4
-rw-r--r--tests/format/junctions/internal-simple/subproject/project.conf6
-rw-r--r--tests/format/junctions/internal-simple/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/internal-simple/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/internal-simple/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/internal-simple/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/internal-simple/subproject/subtarget.bst10
-rw-r--r--tests/format/junctions/internal-simple/subsubproject-again.bst4
-rw-r--r--tests/format/junctions/internal-simple/subsubproject-again/project.conf2
-rw-r--r--tests/format/junctions/internal-simple/subsubproject-again/subsub-again.txt1
-rw-r--r--tests/format/junctions/internal-simple/subsubproject-again/target.bst4
-rw-r--r--tests/format/junctions/internal-simple/target.bst5
-rw-r--r--tests/format/junctions/invalid/base/base.txt (renamed from tests/format/junctions/base/base.txt)0
-rw-r--r--tests/format/junctions/invalid/base/project.conf (renamed from tests/format/junctions/base/project.conf)0
-rw-r--r--tests/format/junctions/invalid/base/target.bst (renamed from tests/format/junctions/base/target.bst)0
-rw-r--r--tests/format/junctions/invalid/missing-element.bst9
-rw-r--r--tests/format/junctions/invalid/subproject-self-override.bst16
-rw-r--r--tests/format/junctions/invalid/target-self-override.bst4
-rw-r--r--tests/format/junctions/missing-element/bad-junction.bst (renamed from tests/format/junctions/invalid/missing.bst)0
-rw-r--r--tests/format/junctions/nested/deeptarget.bst6
-rw-r--r--tests/format/junctions/nested/foo.bst4
-rw-r--r--tests/format/junctions/nested/project.conf2
-rw-r--r--tests/format/junctions/nested/subproject.bst4
-rw-r--r--tests/format/junctions/nested/subproject/project.conf2
-rw-r--r--tests/format/junctions/nested/subproject/sub.txt1
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/subsubsub.txt1
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/subtarget.bst4
-rw-r--r--tests/format/junctions/nested/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/nested/subproject/subsubtarget.bst4
-rw-r--r--tests/format/junctions/nested/subproject/subtarget.bst4
-rw-r--r--tests/format/junctions/nested/subproject/target.bst4
-rw-r--r--tests/format/junctions/nested/target.bst5
-rw-r--r--tests/format/junctions/options-default/project.conf2
-rw-r--r--tests/format/junctions/options-inherit/project.conf11
-rw-r--r--tests/format/junctions/options/base-default.bst (renamed from tests/format/junctions/options-default/base.bst)0
-rw-r--r--tests/format/junctions/options/base-explicit.bst (renamed from tests/format/junctions/options/base.bst)0
-rw-r--r--tests/format/junctions/options/base-propagate.bst (renamed from tests/format/junctions/options-inherit/base.bst)0
-rw-r--r--tests/format/junctions/options/options-base/horsy.txt (renamed from tests/format/junctions/options-base/horsy.txt)0
-rw-r--r--tests/format/junctions/options/options-base/pony.txt (renamed from tests/format/junctions/options-base/pony.txt)0
-rw-r--r--tests/format/junctions/options/options-base/project.conf (renamed from tests/format/junctions/options-base/project.conf)0
-rw-r--r--tests/format/junctions/options/options-base/target.bst (renamed from tests/format/junctions/options-base/target.bst)0
-rw-r--r--tests/format/junctions/options/target-default.bst (renamed from tests/format/junctions/options-inherit/target.bst)2
-rw-r--r--tests/format/junctions/options/target-explicit.bst (renamed from tests/format/junctions/options/target.bst)2
-rw-r--r--tests/format/junctions/options/target-propagate.bst (renamed from tests/format/junctions/foo/target.bst)3
-rw-r--r--tests/format/junctions/override-twice/override.bst (renamed from tests/format/junctions/bar/base.bst)2
-rw-r--r--tests/format/junctions/override-twice/override/overridden-again.txt1
-rw-r--r--tests/format/junctions/override-twice/override/project.conf2
-rw-r--r--tests/format/junctions/override-twice/override/target.bst4
-rw-r--r--tests/format/junctions/override-twice/project.conf2
-rw-r--r--tests/format/junctions/override-twice/subproject.bst8
-rw-r--r--tests/format/junctions/override-twice/subproject/override.bst (renamed from tests/format/junctions/conflict/bar.bst)2
-rw-r--r--tests/format/junctions/override-twice/subproject/override/overridden.txt1
-rw-r--r--tests/format/junctions/override-twice/subproject/override/project.conf2
-rw-r--r--tests/format/junctions/override-twice/subproject/override/target.bst4
-rw-r--r--tests/format/junctions/override-twice/subproject/project.conf2
-rw-r--r--tests/format/junctions/override-twice/subproject/subsubproject.bst8
-rw-r--r--tests/format/junctions/override-twice/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/original.txt1
-rw-r--r--tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/override-twice/target.bst4
-rw-r--r--tests/format/junctions/overrides/overridden-subsubproject.bst10
-rw-r--r--tests/format/junctions/overrides/overridden-subsubsubproject.bst10
-rw-r--r--tests/format/junctions/overrides/project.conf2
-rw-r--r--tests/format/junctions/overrides/subproject-overriden-with-deep-subproject.bst8
-rw-r--r--tests/format/junctions/overrides/subproject-with-deep-override.bst8
-rw-r--r--tests/format/junctions/overrides/subproject-with-override.bst8
-rw-r--r--tests/format/junctions/overrides/subproject.bst4
-rw-r--r--tests/format/junctions/overrides/subproject/project.conf2
-rw-r--r--tests/format/junctions/overrides/subproject/sub.txt1
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject.bst4
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/project.conf2
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/subsub.txt1
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject.bst4
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/project.conf2
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/subsubsub.txt1
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/target.bst4
-rw-r--r--tests/format/junctions/overrides/subproject/subsubproject/target.bst4
-rw-r--r--tests/format/junctions/overrides/subproject/target.bst4
-rw-r--r--tests/format/junctions/overrides/surpriseproject.bst4
-rw-r--r--tests/format/junctions/overrides/surpriseproject/deepsurpriseproject.bst4
-rw-r--r--tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/deepsurprise.txt1
-rw-r--r--tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/project.conf2
-rw-r--r--tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/target.bst4
-rw-r--r--tests/format/junctions/overrides/surpriseproject/project.conf2
-rw-r--r--tests/format/junctions/overrides/surpriseproject/surprise.txt1
-rw-r--r--tests/format/junctions/overrides/surpriseproject/target.bst4
-rw-r--r--tests/format/junctions/overrides/target-overridden-subsubproject.bst12
-rw-r--r--tests/format/junctions/overrides/target-overridden-subsubsubproject.bst8
-rw-r--r--tests/format/junctions/overrides/target-overridden-with-deepsubproject.bst4
-rw-r--r--tests/format/junctions/simple/project.conf2
-rw-r--r--tests/format/junctions/simple/subproject.bst4
-rw-r--r--tests/format/junctions/simple/subproject/base.txt1
-rw-r--r--tests/format/junctions/simple/subproject/project.conf2
-rw-r--r--tests/format/junctions/simple/subproject/target.bst4
-rw-r--r--tests/format/junctions/simple/target.bst4
-rw-r--r--tests/format/junctions/toplevel/bar.bst4
-rw-r--r--tests/format/junctions/toplevel/base.bst4
-rw-r--r--tests/format/junctions/toplevel/element-full-path-notfound.bst3
-rw-r--r--tests/format/junctions/toplevel/element-full-path.bst3
-rw-r--r--tests/format/junctions/toplevel/foo.bst4
-rw-r--r--tests/format/junctions/toplevel/junction-full-path-notfound.bst4
-rw-r--r--tests/format/junctions/toplevel/junction-full-path.bst4
-rw-r--r--tests/format/junctions/toplevel/project.conf2
-rw-r--r--tests/format/junctions/toplevel/target.bst6
-rw-r--r--tests/format/junctions/use-repo/baserepo/base.txt1
-rw-r--r--tests/format/junctions/use-repo/baserepo/project.conf2
-rw-r--r--tests/format/junctions/use-repo/baserepo/target.bst4
-rw-r--r--tests/format/junctions/use-repo/project.conf (renamed from tests/format/junctions/foo/project.conf)0
-rw-r--r--tests/format/junctions/use-repo/target.bst (renamed from tests/format/junctions/options-default/target.bst)0
-rw-r--r--tests/frontend/project/files/sub2-project/project.conf2
-rw-r--r--tests/frontend/track-cross-junction/subproject/project.conf2
463 files changed, 2719 insertions, 550 deletions
diff --git a/doc/examples/junction-includes/project.conf b/doc/examples/junction-includes/project.conf
index 9d1e6f1e9..ae53d89bf 100644
--- a/doc/examples/junction-includes/project.conf
+++ b/doc/examples/junction-includes/project.conf
@@ -1,4 +1,4 @@
-name: subproject
+name: project
min-version: 2.0
element-path: elements
diff --git a/doc/source/format_project.rst b/doc/source/format_project.rst
index 69c844692..93b7f7812 100644
--- a/doc/source/format_project.rst
+++ b/doc/source/format_project.rst
@@ -220,6 +220,7 @@ and keys, please see: :ref:`Key pair for the server <server_authentication>`.
new server API. As a result newer buildstream clients won't work with older
servers.
+
.. _project_essentials_split_artifacts:
Split cache servers
@@ -258,6 +259,7 @@ format for that is as such:
# currently, also only supported by bst-artifact-server and BuildGrid
type: both
+
.. _project_source_cache:
Source cache server
@@ -285,6 +287,7 @@ Exactly the same as artifact servers, source cache servers can be specified.
Source caches also support "splitting" like :ref:`artifact servers
<project_essentials_split_artifacts>`.
+
.. _project_remote_execution:
Remote execution
@@ -336,6 +339,7 @@ The Remote Execution API can be found via https://github.com/bazelbuild/remote-a
Remote execution configuration can be also provided in the `user
configuration <user_config_remote_execution>`.
+
.. _project_essentials_mirrors:
Mirrors
@@ -940,6 +944,100 @@ same syntax as other Flag options.
enable-debug: True
+.. _project_junctions:
+
+Junctions
+---------
+In this section of ``project.conf``, we can define the relationship a project
+has with :mod:`junction <elements.junction>` elements in the same project, or
+even in subprojects.
+
+Sometimes when your project has multiple :mod:`junction <elements.junction>` elements,
+a situation can arise where you have multiple instances of the same project loaded
+at the same time. In most cases, you will want to reconcile this conflict by ensuring
+that your projects share the same junction. In order to reconcile conflicts by
+ensuring nested junctions to the same project are shared, please refer to
+:ref:`the documentation on nested junctions <core_junction_nested>`.
+
+In some exceptional cases, it is entirely intentional and appropriate to use
+the same project more than once in the same build pipeline. The attributes
+in the ``junctions`` group here in ``project.conf`` provide some tools you can
+use to explicitly allow the coexistence of the same project multiple times.
+
+
+Duplicate junctions
+~~~~~~~~~~~~~~~~~~~
+In the case that you are faced with an error due to subprojects sharing
+a common sub-subproject, you can use the ``duplicates`` configuration
+in order to allow the said project to be loaded twice.
+
+**Example**:
+
+.. code:: yaml
+
+ junctions:
+
+ duplicates:
+
+ # Here we use the packaging tooling completely separately from
+ # the payload that we are packaging, they are never staged to
+ # the same location in a given sandbox, and as such we would
+ # prefer to allow the 'runtime' project to be loaded separately.
+ #
+ # This statement will ensure that loading the 'runtime' project
+ # from these two locations will not produce any errors.
+ #
+ runtime:
+ - payload.bst:runtime.bst
+ - packaging.bst:runtime.bst
+
+When considering duplicated projects in the same pipeline, all instances
+of the said project need to be marked as ``duplicates`` in order to avoid
+a *conflicting junction error* at load time.
+
+.. tip::
+
+ The declaration of ``duplicates`` is inherited by any dependant projects
+ which may later decide to depend on your project.
+
+ If you depend on a project which itself has ``duplicates``, and you need
+ to duplicate it again, then you only need to declare the new duplicate,
+ you do not need to redeclare duplicates redundantly.
+
+
+Internal junctions
+~~~~~~~~~~~~~~~~~~
+Another way to avoid *conflicting junction errors* when you know that your
+subproject should not conflict with other instances of the same subproject,
+is to declare the said subproject as *internal*.
+
+**Example**:
+
+.. code:: yaml
+
+ junctions:
+
+ # Declare this subproject as "internal" because we know
+ # that we only use it for build dependencies, and as such
+ # we know that it cannot collide with elements in dependant
+ # projects.
+ #
+ internal:
+ - special-compiler.bst
+
+When compared to *duplicates* above, *internal* projects have the advantage
+of never producing any *conflicting junction errors* in dependant projects
+(reverse dependency projects).
+
+This approach is preferrable in cases where you know for sure that dependant
+projects will not be depending directly on elements from your internal
+subproject.
+
+.. attention::
+
+ Declaring a junction as *internal* is a promise that dependant projects
+ will not accrue runtime dependencies on elements in your *internal* subproject.
+
.. _project_defaults:
diff --git a/src/buildstream/_loader/loadcontext.py b/src/buildstream/_loader/loadcontext.py
index 161be913b..6183a192b 100644
--- a/src/buildstream/_loader/loadcontext.py
+++ b/src/buildstream/_loader/loadcontext.py
@@ -17,6 +17,146 @@
# Authors:
# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
+from .._exceptions import LoadError
+from ..exceptions import LoadErrorReason
+
+
+# ProjectLoaders()
+#
+# An object representing all of the loaders for a given project.
+#
+class ProjectLoaders:
+ def __init__(self, project_name):
+
+ # The project name
+ self._name = project_name
+
+ # A list of all loaded loaders for this project
+ self._collect = []
+
+ # register_loader()
+ #
+ # Register a Loader for this project
+ #
+ # Args:
+ # loader (Loader): The loader to register
+ #
+ def register_loader(self, loader):
+ assert loader.project.name == self._name
+
+ self._collect.append(loader)
+
+ # assert_loaders():
+ #
+ # Asserts the validity of loaders for this project
+ #
+ # Raises:
+ # (LoadError): In case there is a CONFLICTING_JUNCTION error
+ #
+ def assert_loaders(self):
+ duplicates = {}
+ internal = {}
+ primary = []
+
+ for loader in self._collect:
+ duplicating, internalizing = self._search_project_relationships(loader)
+ if duplicating:
+ duplicates[loader] = duplicating
+ if internalizing:
+ internal[loader] = internalizing
+
+ if not (duplicating or internalizing):
+ primary.append(loader)
+
+ if len(primary) > 1:
+ self._raise_conflict(duplicates, internal)
+
+ elif primary and duplicates:
+ self._raise_conflict(duplicates, internal)
+
+ # _search_project_relationships()
+ #
+ # Searches this loader's ancestry for projects which mark this
+ # loader as internal or duplicate
+ #
+ # Args:
+ # loader (Loader): The loader to search for duplicate markers of
+ #
+ # Returns:
+ # (list): A list of Loader objects who's project has marked
+ # this junction as a duplicate
+ # (list): A list of Loader objects who's project has marked
+ # this junction as internal
+ #
+ def _search_project_relationships(self, loader):
+ duplicates = []
+ internal = []
+ for parent in loader.ancestors():
+ if parent.project.junction_is_duplicated(self._name, loader):
+ duplicates.append(parent)
+ if parent.project.junction_is_internal(loader):
+ internal.append(parent)
+ return duplicates, internal
+
+ # _raise_conflict()
+ #
+ # Raises the LoadError indicating there was a conflict, this
+ # will list all of the instances in which the project has
+ # been loaded as the LoadError detail string
+ #
+ # Args:
+ # duplicates (dict): A table of duplicating Loaders, indexed
+ # by duplicated Loader
+ # internals (dict): A table of Loaders which mark a loader as internal,
+ # indexed by internal Loader
+ #
+ # Raises:
+ # (LoadError): In case there is a CONFLICTING_JUNCTION error
+ #
+ def _raise_conflict(self, duplicates, internals):
+ explanation = (
+ "Internal projects do not cause any conflicts. Conflicts can also be avoided\n"
+ + "by marking every instance of the project as a duplicate."
+ )
+ lines = [self._loader_description(loader, duplicates, internals) for loader in self._collect]
+ detail = "{}\n{}".format("\n".join(lines), explanation)
+
+ raise LoadError(
+ "Project '{}' was loaded in multiple contexts".format(self._name),
+ LoadErrorReason.CONFLICTING_JUNCTION,
+ detail=detail,
+ )
+
+ # _loader_description()
+ #
+ # Args:
+ # loader (Loader): The loader to describe
+ # duplicates (dict): A table of duplicating Loaders, indexed
+ # by duplicated Loader
+ # internals (dict): A table of Loaders which mark a loader as internal,
+ # indexed by internal Loader
+ #
+ # Returns:
+ # (str): A string representing how this loader was loaded
+ #
+ def _loader_description(self, loader, duplicates, internals):
+
+ line = "{}\n".format(loader)
+
+ # Mention projects which have marked this project as a duplicate
+ duplicating = duplicates.get(loader)
+ if duplicating:
+ for dup in duplicating:
+ line += " Duplicated by: {}\n".format(dup)
+
+ # Mention projects which have marked this project as internal
+ internalizing = internals.get(loader)
+ if internalizing:
+ for internal in internalizing:
+ line += " Internal to: {}\n".format(internal)
+
+ return line
+
# LoaderContext()
#
@@ -34,6 +174,9 @@ class LoadContext:
self.fetch_subprojects = None
self.task = None
+ # A table of all Loaders, indexed by project name
+ self._loaders = {}
+
# set_rewritable()
#
# Sets whether the projects are to be loaded in a rewritable fashion,
@@ -64,3 +207,37 @@ class LoadContext:
#
def set_fetch_subprojects(self, fetch_subprojects):
self.fetch_subprojects = fetch_subprojects
+
+ # assert_loaders()
+ #
+ # Asserts that there are no conflicting projects loaded.
+ #
+ # Raises:
+ # (LoadError): A CONFLICTING_JUNCTION LoadError in the case of a conflict
+ #
+ def assert_loaders(self):
+ for _, loaders in self._loaders.items():
+ loaders.assert_loaders()
+
+ # register_loader()
+ #
+ # Registers a new loader in the load context, possibly
+ # raising an error in the case of a conflict.
+ #
+ # This must be called after a recursive load process has completed,
+ # and after the pipeline is resolved (which is to say that all related
+ # Plugin derived objects have been instantiated).
+ #
+ # Args:
+ # loader (Loader): The Loader object to register into context
+ #
+ def register_loader(self, loader):
+ project = loader.project
+
+ try:
+ project_loaders = self._loaders[project.name]
+ except KeyError:
+ project_loaders = ProjectLoaders(project.name)
+ self._loaders[project.name] = project_loaders
+
+ project_loaders.register_loader(loader)
diff --git a/src/buildstream/_loader/loadelement.pyx b/src/buildstream/_loader/loadelement.pyx
index 784ab8f7b..de2f96b37 100644
--- a/src/buildstream/_loader/loadelement.pyx
+++ b/src/buildstream/_loader/loadelement.pyx
@@ -52,11 +52,13 @@ cdef class Dependency:
cdef readonly LoadElement element
cdef readonly str dep_type
cdef readonly bint strict
+ cdef readonly ProvenanceInformation provenance
- def __cinit__(self, LoadElement element, str dep_type, bint strict):
+ def __cinit__(self, LoadElement element, str dep_type, bint strict, ProvenanceInformation provenance):
self.element = element
self.dep_type = dep_type
self.strict = strict
+ self.provenance = provenance
# LoadElement():
diff --git a/src/buildstream/_loader/loader.py b/src/buildstream/_loader/loader.py
index 13d8f9f21..81e5fb032 100644
--- a/src/buildstream/_loader/loader.py
+++ b/src/buildstream/_loader/loader.py
@@ -18,6 +18,7 @@
# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
import os
+from contextlib import suppress
from .._exceptions import LoadError
from ..exceptions import LoadErrorReason
@@ -46,9 +47,10 @@ from .._message import Message, MessageType
# Args:
# project (Project): The toplevel Project object
# parent (Loader): A parent Loader object, in the case this is a junctioned Loader
+# provenance (ProvenanceInformation): The provenance of the reference to this project's junction
#
class Loader:
- def __init__(self, project, *, parent=None):
+ def __init__(self, project, *, parent=None, provenance=None):
# Ensure we have an absolute path for the base directory
basedir = project.element_path
@@ -60,6 +62,7 @@ class Loader:
#
self.load_context = project.load_context # The LoadContext
self.project = project # The associated Project
+ self.provenance = provenance # The provenance of whence this loader was instantiated
self.loaded = None # The number of loaded Elements
#
@@ -69,13 +72,37 @@ class Loader:
self._basedir = basedir # Base project directory
self._first_pass_options = project.first_pass_config.options # Project options (OptionPool)
self._parent = parent # The parent loader
+ self._alternative_parents = [] # Overridden parent loaders
self._meta_elements = {} # Dict of resolved meta elements by name
self._elements = {} # Dict of elements
self._loaders = {} # Dict of junction loaders
+ self._loader_search_provenances = {} # Dictionary of provenances of ongoing child loader searches
self._includes = Includes(self, copy_tree=True)
+ assert project.name is not None
+
+ self.load_context.register_loader(self)
+
+ # The __str__ of a Loader is used to clearly identify the Loader,
+ # the junction is was loaded as, and the provenance causing the
+ # junction to be loaded.
+ #
+ def __str__(self):
+ project_name = self.project.name
+
+ if self.project.junction:
+ junction_name = self.project.junction._get_full_name()
+ if self.provenance:
+ provenance = "({}): {}".format(junction_name, self.provenance)
+ else:
+ provenance = "({})".format(junction_name)
+ else:
+ provenance = "(toplevel)"
+
+ return "{} {}".format(project_name, provenance)
+
# load():
#
# Loads the project based on the parameters given to the constructor
@@ -120,7 +147,7 @@ class Loader:
dummy_target = LoadElement(Node.from_dict({}), "", self)
# Pylint is not very happy with Cython and can't understand 'dependencies' is a list
dummy_target.dependencies.extend( # pylint: disable=no-member
- Dependency(element, Symbol.RUNTIME, False) for element in target_elements
+ Dependency(element, Symbol.RUNTIME, False, None) for element in target_elements
)
with PROFILER.profile(Topics.CIRCULAR_CHECK, "_".join(targets)):
@@ -156,22 +183,74 @@ class Loader:
#
# Obtains the appropriate loader for the specified junction
#
+ # If `load_subprojects` is enabled, then this function will
+ # either return the desired loader or raise a LoadError. If
+ # `load_subprojects` is disabled, then it can also return None
+ # in the case that a loader could not be found. In either case,
+ # a non-existant file in a loaded project will result in a LoadError.
+ #
# Args:
# name (str): Name of junction, may have multiple `:` in the name
# provenance (ProvenanceInformation): The provenance
+ # load_subprojects (bool): Whether to load subprojects on demand
#
# Returns:
# (Loader): loader for sub-project
#
- def get_loader(self, name, provenance, *, level=0):
+ def get_loader(self, name, provenance, *, load_subprojects=True):
junction_path = name.split(":")
loader = self
+ circular_provenance = self._loader_search_provenances.get(name, None)
+ if circular_provenance:
+
+ assert provenance
+
+ detail = None
+ if circular_provenance is not provenance:
+ detail = "Already searching for '{}' at: {}".format(name, circular_provenance)
+ raise LoadError(
+ "{}: Circular reference while searching for '{}'".format(provenance, name),
+ LoadErrorReason.CIRCULAR_REFERENCE,
+ detail=detail,
+ )
+
+ self._loader_search_provenances[name] = provenance
+
for junction_name in junction_path:
- loader = loader._get_loader(junction_name, provenance, level=level)
+ loader = loader._get_loader(junction_name, provenance, load_subprojects=load_subprojects)
+
+ del self._loader_search_provenances[name]
return loader
+ # ancestors()
+ #
+ # This will traverse all active loaders in the ancestry for which this
+ # project is reachable using a relative path.
+ #
+ # Yields:
+ # (Loader): Each loader in the ancestry
+ #
+ def ancestors(self):
+ traversed = {}
+
+ def foreach_parent(parent):
+ while parent:
+ if parent in traversed:
+ return
+ traversed[parent] = True
+ yield parent
+ parent = parent._parent
+
+ # Yield from the direct/active ancestry
+ yield from foreach_parent(self._parent)
+
+ # Yield from alternative parents which have been replaced by
+ # overrides in the ancestry.
+ for parent in self._alternative_parents:
+ yield from foreach_parent(parent)
+
# collect_element_no_deps()
#
# Collect a single element, without its dependencies, into a meta_element
@@ -338,15 +417,16 @@ class Loader:
#
# Args:
# filename (str): The element-path relative bst file
+ # load_subprojects (bool): Whether to load subprojects
# provenance (Provenance): The location from where the file was referred to, or None
#
# Returns:
# (LoadElement): A loaded LoadElement
#
- def _load_file(self, filename, provenance):
+ def _load_file(self, filename, provenance, *, load_subprojects=True):
# Silently ignore already loaded files
- if filename in self._elements:
+ with suppress(KeyError):
return self._elements[filename]
top_element = self._load_file_no_deps(filename, provenance)
@@ -354,8 +434,12 @@ class Loader:
# If this element is a link then we need to resolve it
# and replace the dependency we've processed with this one
if top_element.link_target is not None:
- _, filename, loader = self._parse_name(top_element.link_target, top_element.link_target_provenance)
- top_element = loader._load_file(filename, top_element.link_target_provenance)
+ _, filename, loader = self._parse_name(
+ top_element.link_target, top_element.link_target_provenance, load_subprojects=load_subprojects
+ )
+ top_element = loader._load_file(
+ filename, top_element.link_target_provenance, load_subprojects=load_subprojects
+ )
dependencies = extract_depends_from_node(top_element.node)
# The loader queue is a stack of tuples
@@ -403,7 +487,7 @@ class Loader:
# All is well, push the dependency onto the LoadElement
# Pylint is not very happy with Cython and can't understand 'dependencies' is a list
current_element[0].dependencies.append( # pylint: disable=no-member
- Dependency(dep_element, dep.dep_type, dep.strict)
+ Dependency(dep_element, dep.dep_type, dep.strict, dep.provenance)
)
else:
# We do not have any more dependencies to load for this
@@ -514,19 +598,78 @@ class Loader:
return self._meta_elements[top_element.name]
+ # _search_for_override():
+ #
+ # Search parent projects for an overridden subproject to replace this junction.
+ #
+ # This function is called once for each direct child while looking up
+ # child loaders, after which point the child loader is cached in the `_loaders`
+ # table. This function also has the side effect of recording alternative parents
+ # of a child loader in the case that the child loader is overridden.
+ #
+ # Args:
+ # filename (str): Junction name
+ #
+ def _search_for_override(self, filename):
+ loader = self
+ override_path = filename
+
+ # Collect any overrides to this junction in the ancestry
+ #
+ overriding_loaders = []
+ while loader._parent:
+ junction = loader.project.junction
+ override_filename, override_provenance = junction.overrides.get(override_path, (None, None))
+ if override_filename:
+ overriding_loaders.append((loader._parent, override_filename, override_provenance))
+
+ override_path = junction.name + ":" + override_path
+ loader = loader._parent
+
+ # If there are any overriding loaders, use the highest one in
+ # the ancestry to lookup the loader for this project.
+ #
+ if overriding_loaders:
+ overriding_loader, override_filename, provenance = overriding_loaders[-1]
+ loader = overriding_loader.get_loader(override_filename, provenance)
+
+ #
+ # Record alternative loaders which were overridden.
+ #
+ # When a junction is overridden by another higher priority junction,
+ # the resulting loader is still reachable with the original element paths,
+ # which will now traverse override redirections.
+ #
+ # In order to iterate over every project/loader in the ancestry which can
+ # reach the actually selected loader, we need to keep track of the parent
+ # loaders of all overridden junctions.
+ #
+ if loader is not self:
+ loader._alternative_parents.append(self)
+
+ del overriding_loaders[-1]
+ loader._alternative_parents.extend(l for l, _, _ in overriding_loaders)
+
+ return loader
+
+ # No overrides were found in the ancestry
+ #
+ return None
+
# _get_loader():
#
# Return loader for specified junction
#
# Args:
# filename (str): Junction name
+ # load_subprojects (bool): Whether to load subprojects
# provenance (Provenance): The location from where the file was referred to, or None
#
# Raises: LoadError
#
# Returns: A Loader or None if specified junction does not exist
#
- def _get_loader(self, filename, provenance, *, level=0):
+ def _get_loader(self, filename, provenance, *, load_subprojects=True):
loader = None
provenance_str = ""
if provenance is not None:
@@ -534,43 +677,21 @@ class Loader:
# return previously determined result
if filename in self._loaders:
- loader = self._loaders[filename]
+ return self._loaders[filename]
- if loader is None:
- # do not allow junctions with the same name in different
- # subprojects
- raise LoadError(
- "{}Conflicting junction {} in subprojects, define junction in {}".format(
- provenance_str, filename, self.project.name
- ),
- LoadErrorReason.CONFLICTING_JUNCTION,
- )
-
- return loader
-
- if self._parent:
- # junctions in the parent take precedence over junctions defined
- # in subprojects
- loader = self._parent._get_loader(filename, level=level + 1, provenance=provenance)
- if loader:
- self._loaders[filename] = loader
- return loader
-
- try:
- self._load_file(filename, provenance=provenance)
- except LoadError as e:
- if e.reason != LoadErrorReason.MISSING_FILE:
- # other load error
- raise
-
- if level == 0:
- # junction element not found in this or ancestor projects
- raise
+ #
+ # Search the ancestry for an overridden loader to use in place
+ # of using the locally defined junction.
+ #
+ override_loader = self._search_for_override(filename)
+ if override_loader:
+ self._loaders[filename] = override_loader
+ return override_loader
- # mark junction as not available to allow detection of
- # conflicting junctions in subprojects
- self._loaders[filename] = None
- return None
+ #
+ # Load the junction file
+ #
+ self._load_file(filename, provenance, load_subprojects=load_subprojects)
# At this point we've loaded the LoadElement
load_element = self._elements[filename]
@@ -579,8 +700,15 @@ class Loader:
# immediately and move on to the target.
#
if load_element.link_target:
- _, filename, loader = self._parse_name(load_element.link_target, load_element.link_target_provenance)
- return loader.get_loader(filename, load_element.link_target_provenance)
+ _, filename, loader = self._parse_name(
+ load_element.link_target, load_element.link_target_provenance, load_subprojects=load_subprojects
+ )
+ return loader.get_loader(filename, load_element.link_target_provenance, load_subprojects=load_subprojects)
+
+ # If we're only performing a lookup, we're done here.
+ #
+ if not load_subprojects:
+ return None
# meta junction element
#
@@ -613,7 +741,11 @@ class Loader:
# would be nice if this could be done for *all* element types,
# but since we haven't loaded those yet that's impossible.
if load_element.dependencies:
- raise LoadError("Dependencies are forbidden for 'junction' elements", LoadErrorReason.INVALID_JUNCTION)
+ # Use the first dependency in the list as provenance
+ p = load_element.dependencies[0].provenance
+ raise LoadError(
+ "{}: Dependencies are forbidden for 'junction' elements".format(p), LoadErrorReason.INVALID_JUNCTION
+ )
element = Element._new_from_meta(meta_element)
element._initialize_state()
@@ -664,7 +796,12 @@ class Loader:
from .._project import Project # pylint: disable=cyclic-import
project = Project(
- project_dir, self.load_context.context, junction=element, parent_loader=self, search_for_project=False,
+ project_dir,
+ self.load_context.context,
+ junction=element,
+ parent_loader=self,
+ search_for_project=False,
+ provenance=provenance,
)
except LoadError as e:
if e.reason == LoadErrorReason.MISSING_PROJECT_CONF:
@@ -691,13 +828,14 @@ class Loader:
# Args:
# name (str): Name of target
# provenance (ProvenanceInformation): The provenance
+ # load_subprojects (bool): Whether to load subprojects
#
# Returns:
# (tuple): - (str): name of the junction element
# - (str): name of the element
# - (Loader): loader for sub-project
#
- def _parse_name(self, name, provenance):
+ def _parse_name(self, name, provenance, *, load_subprojects=True):
# We allow to split only once since deep junctions names are forbidden.
# Users who want to refer to elements in sub-sub-projects are required
# to create junctions on the top level project.
@@ -705,7 +843,7 @@ class Loader:
if len(junction_path) == 1:
return None, junction_path[-1], self
else:
- loader = self.get_loader(junction_path[-2], provenance)
+ loader = self.get_loader(junction_path[-2], provenance, load_subprojects=load_subprojects)
return junction_path[-2], junction_path[-1], loader
# Print a warning message, checks warning_token against project configuration
diff --git a/src/buildstream/_project.py b/src/buildstream/_project.py
index e0ddf3d41..21dc2b9d2 100644
--- a/src/buildstream/_project.py
+++ b/src/buildstream/_project.py
@@ -99,6 +99,7 @@ class Project:
cli_options=None,
default_mirror=None,
parent_loader=None,
+ provenance=None,
search_for_project=True,
):
@@ -157,6 +158,15 @@ class Project:
self._sandbox = None
self._splits = None
+ # This is a lookup table of dictionaries indexed by project,
+ # the child dictionaries are junction names as keys with their
+ # provenances as values
+ self._junction_duplicates = {}
+
+ # A table of project relative junctions to consider as 'internal'. The values
+ # of the table are simply used to store ProvenanceInformation.
+ self._junction_internal = {}
+
self._context.add_project(self)
self._partially_loaded = False
@@ -164,7 +174,7 @@ class Project:
self._project_includes = None
with PROFILER.profile(Topics.LOAD_PROJECT, self.directory.replace(os.sep, "-")):
- self._load(parent_loader=parent_loader)
+ self._load(parent_loader=parent_loader, provenance=provenance)
self._partially_loaded = True
@@ -433,6 +443,12 @@ class Project:
Element._clear_meta_elements_cache()
+ # Assert loaders after resolving everything, this is because plugin
+ # loading (across junction boundaries) can also be the cause of
+ # conflicting projects.
+ #
+ self.load_context.assert_loaders()
+
# Now warn about any redundant source references which may have
# been discovered in the resolve() phase.
redundant_refs = Element._get_redundant_source_refs()
@@ -540,6 +556,65 @@ class Project:
return tuple(default_targets)
+ # junction_is_duplicated()
+ #
+ # Check whether this loader is specified as a duplicate by
+ # this project.
+ #
+ # Args:
+ # project_name: (str): The project name
+ # loader (Loader): The loader to check for
+ #
+ # Returns:
+ # (bool): Whether the loader is specified as duplicate
+ #
+ def junction_is_duplicated(self, project_name, loader):
+
+ junction_dict = self._junction_duplicates.get(project_name, {})
+
+ # Iterate over all paths specified by this project and see
+ # if we find a match for the specified loader.
+ #
+ # Using the regular `Loader.get_loader()` codepath from this
+ # project ensures that we will find the correct loader relative
+ # to this project, regardless of any overrides or link elements
+ # which might have been used in the project.
+ #
+ for dup_path, dup_provenance in junction_dict.items():
+ search = self.loader.get_loader(dup_path, dup_provenance, load_subprojects=False)
+ if loader is search:
+ return True
+
+ return False
+
+ # junction_is_internal()
+ #
+ # Check whether this loader is specified as internal to
+ # this project.
+ #
+ # Args:
+ # loader (Loader): The loader to check for
+ #
+ # Returns:
+ # (bool): Whether the loader is specified as internal
+ #
+ def junction_is_internal(self, loader):
+
+ # Iterate over all paths specified by this project and see
+ # if we find a match for the specified loader.
+ #
+ # Using the regular `Loader.get_loader()` codepath from this
+ # project ensures that we will find the correct loader relative
+ # to this project, regardless of any overrides or link elements
+ # which might have been used in the project.
+ #
+ for internal_path, internal_provenance in self._junction_internal.items():
+ search = self.loader.get_loader(internal_path, internal_provenance, load_subprojects=False)
+ if loader is search:
+ return True
+
+ return False
+
########################################################
# Private Methods #
########################################################
@@ -576,6 +651,7 @@ class Project:
"remote-execution",
"sources",
"source-caches",
+ "junctions",
"(@)",
]
)
@@ -653,7 +729,7 @@ class Project:
#
# Raises: LoadError if there was a problem with the project.conf
#
- def _load(self, *, parent_loader=None):
+ def _load(self, *, parent_loader=None, provenance=None):
# Load builtin default
projectfile = os.path.join(self.directory, _PROJECT_CONF_FILE)
@@ -700,7 +776,26 @@ class Project:
# Fatal warnings
self._fatal_warnings = pre_config_node.get_str_list("fatal-warnings", default=[])
- self.loader = Loader(self, parent=parent_loader)
+ # Junction configuration
+ junctions_node = pre_config_node.get_mapping("junctions", default={})
+ junctions_node.validate_keys(["duplicates", "internal"])
+
+ # Parse duplicates
+ junction_duplicates = junctions_node.get_mapping("duplicates", default={})
+ for project_name, junctions in junction_duplicates.items():
+ # For each junction we preserve the provenance and the junction string,
+ # the provenance is used for lookups later on.
+ #
+ self._junction_duplicates[project_name] = junctions_dict = {}
+ for junction_node in junctions:
+ junctions_dict[junction_node.as_str()] = junction_node.get_provenance()
+
+ # Parse internal
+ junction_internal = junctions_node.get_sequence("internal", default=[])
+ for junction_node in junction_internal:
+ self._junction_internal[junction_node.as_str()] = junction_node.get_provenance()
+
+ self.loader = Loader(self, parent=parent_loader, provenance=provenance)
self._project_includes = Includes(self.loader, copy_tree=False)
diff --git a/src/buildstream/exceptions.py b/src/buildstream/exceptions.py
index 2c455be84..e77d64fe7 100644
--- a/src/buildstream/exceptions.py
+++ b/src/buildstream/exceptions.py
@@ -142,3 +142,6 @@ class LoadErrorReason(Enum):
LINK_FORBIDDEN_DEPENDENCIES = 25
"""A link element declared dependencies"""
+
+ CIRCULAR_REFERENCE = 26
+ """A circular element reference was detected"""
diff --git a/src/buildstream/plugins/elements/junction.py b/src/buildstream/plugins/elements/junction.py
index 3e221cce7..425b917ef 100644
--- a/src/buildstream/plugins/elements/junction.py
+++ b/src/buildstream/plugins/elements/junction.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2017 Codethink Limited
+# Copyright (C) 2020 Codethink Limited
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -20,7 +20,7 @@
"""
junction - Integrate subprojects
================================
-This element is a link to another BuildStream project. It allows integration
+This element acts as a window into another BuildStream project. It allows integration
of multiple projects into a single pipeline.
Overview
@@ -48,6 +48,12 @@ Overview
# Optionally look in a subpath of the source repository for the project
path: projects/hello
+ # Optionally override junction configurations in the subproject
+ # with a junction declaration in this project.
+ #
+ overrides:
+ subproject-junction.bst: local-junction.bst
+
# Optionally declare whether elements within the junction project
# should interact with project remotes (default: False).
cache-junction-elements: False
@@ -57,11 +63,6 @@ Overview
# remote(s) (default: False).
ignore-junction-remotes: False
-.. note::
-
- Junction elements may not specify any dependencies as they are simply
- links to other projects and are not in the dependency graph on their own.
-
With a junction element in place, local elements can depend on elements in
the other BuildStream project using :ref:`element paths <format_element_names>`.
For example, if you have a ``toolchain.bst`` junction element referring to
@@ -73,41 +74,69 @@ dependency to the compiler like this:
build-depends:
- junction: toolchain.bst:gcc.bst
-While junctions are elements, only a limited set of element operations is
-supported. They can be tracked and fetched like other elements.
-However, junction elements do not produce any artifacts, which means that
-they cannot be built or staged. It also means that another element cannot
-depend on a junction element itself.
+.. important::
-.. note::
+ **Limitations**
- Elements within the subproject are not tracked by default when running
- `bst source track`. You must specify `--cross-junctions` to the track
- command to explicitly do it.
+ Junction elements are only connectors which bring multiple projects together,
+ and as such they are not in the element dependency graph. This means that it is
+ illegal to depend on a junction, and it is also illegal for a junction to have
+ dependencies.
+
+ While junctions are elements, a limited set of element operations are
+ supported. Junction elements can be tracked and fetched like other
+ elements but they do not produce any artifacts, which means that they
+ cannot be built or staged.
+
+ Note that when running :ref:`bst source track <invoking_source_track>`
+ on your project, elements found in subprojects are not tracked by default.
+ You may specify ``--cross-junctions`` to the
+ :ref:`bst source track <invoking_source_track>` command to explicitly track
+ elements across junction boundaries.
Sources
-------
-``bst show`` does not implicitly fetch junction sources if they haven't been
-cached yet. However, they can be fetched explicitly:
+The sources of a junction element define how to obtain the BuildStream project
+that the junction connects to.
+
+Most commands, such as :ref:`bst build <invoking_build>`, will automatically
+try to fetch the junction elements required to access any subproject elements which
+are specified as dependencies of the targets provided.
+
+Some commands, such as :ref:`bst show <invoking_show>`, do not do this, and in
+such cases they can be fetched explicitly using
+:ref:`bst source fetch <invoking_source_fetch>`:
.. code::
bst source fetch junction.bst
-Other commands such as ``bst build`` implicitly fetch junction sources.
Options
-------
+Junction elements can configure the :ref:`project options <project_options>`
+in the subproject, using the ``options`` configuration.
+
.. code:: yaml
- options:
- machine_arch: "%{machine_arch}"
- debug: True
+ kind: junction
+
+ ...
+
+ config:
+
+ # Specify the options for this subproject
+ #
+ options:
+ machine_arch: "%{machine_arch}"
+ debug: True
+
+Options are never implicitly propagated across junctions, however
+:ref:`variables <format_variables>` can be used to explicitly assign
+configuration in a subproject which matches the toplevel project's
+configuration.
-Junctions can configure options of the linked project. Options are never
-implicitly inherited across junctions, however, variables can be used to
-explicitly assign the same value to a subproject option.
.. _core_junction_nested:
@@ -116,33 +145,119 @@ Nested Junctions
Junctions can be nested. That is, subprojects are allowed to have junctions on
their own. Nested junctions in different subprojects may point to the same
project, however, in most use cases the same project should be loaded only once.
-BuildStream uses the junction element name as key to determine which junctions
-to merge. It is recommended that the name of a junction is set to the same as
-the name of the linked project.
As the junctions may differ in source version and options, BuildStream cannot
simply use one junction and ignore the others. Due to this, BuildStream requires
-the user to resolve possibly conflicting nested junctions by creating a junction
-with the same name in the top-level project, which then takes precedence.
+the user to resolve conflicting nested junctions, and will provide an error
+message whenever a conflict is detected.
+
+
+Overriding subproject junctions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If your project and a subproject share a subproject in common, then one way
+to resolve the conflict is to override the subproject's junction with a local
+in your project.
+
+You can override junctions in a subproject in the junction declaration
+of that subproject, e.g.:
+
+.. code:: yaml
+
+ kind: junction
+
+ # Here we are junctioning "subproject" which
+ # also junctions "subsubproject", which we also
+ # use directly.
+ #
+ sources:
+ - kind: git
+ url: https://example.com/subproject.git
+
+ config:
+ # Override `subsubproject.bst` in the subproject using
+ # the locally declared `local-subsubproject.bst` junction.
+ #
+ overrides:
+ subsubproject.bst: local-subsubproject.bst
+
+When declaring the ``overrides`` dictionary, the keys (on the left side)
+refer to :ref:`junction paths <format_element_names>` which are relative
+to the subproject you are declaring. The values (on the right side) refer
+to :ref:`junction paths <format_element_names>` which are relative to the
+project in which your junction is declared.
+
+.. warning::
+
+ This approach modifies your subproject, causing its output artifacts
+ to differ from that project's expectations.
+
+ If you rely on validation and guarantees provided by the organization
+ which maintains the subproject, then it is desirable to avoid overriding
+ any details from that upstream project.
+
Linking to other junctions
~~~~~~~~~~~~~~~~~~~~~~~~~~
-When working with nested junctions, you often need to ensure that multiple
-projects are using the same version of a given subproject.
+Another way to resolve the conflict when your project and a subproject both
+junction a common project, is to simply reuse the same junction from the
+subproject in your toplevel project.
+
+This is preferable to *overrides* because you can avoid modifying the
+subproject you would otherwise be changing with an override.
+
+A convenient way to reuse a nested junction in a higher level project
+is to create a :mod:`link <elements.link>` element to that subproject's
+junction. This will help you avoid redundantly typing out longer
+:ref:`element paths <format_element_names>` in your project's
+:ref:`dependency declarations <format_dependencies>`.
-In order to ensure that your project is using a junction to a sub-subproject
-declared by a direct subproject, then you can use a :mod:`link <elements.link>`
-element in place of declaring a junction.
+This way you can simply create the :mod:`link <elements.link>` once
+in your project and use it locally to depend on elements in a nested
+subproject.
-This lets you create a link to a junction in the subproject, which you
-can then treat as a regular junction in your toplevel project.
+**Example:**
.. code:: yaml
+ # Declare the `subsubproject-link.bst` link element, which
+ # is a symbolic link to the junction declared in the subproject
+ #
kind: link
config:
target: subproject.bst:subsubproject.bst
+
+
+.. code:: yaml
+
+ # Depend on elements in the subsubproject using
+ # the subproject's junction directly
+ #
+ kind: autotools
+
+ depends:
+ - subsubproject-link.bst:glibc.bst
+
+
+.. tip::
+
+ When reconciling conflicting junction declarations to the
+ same subproject, it is also possible to use a locally defined
+ :mod:`link <elements.link>` element from one subproject to
+ override another junction to the same project in an adjacent
+ subproject.
+
+
+Multiple project instances
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+By default, loading the same project more than once will result
+in a *conflicting junction error*. There are some use cases which
+demand that you load the same project more than once in the same
+build pipeline.
+
+In order to allow the loading of multiple instances of the same project
+in the same build pipeline, please refer to the
+:ref:`relevant project.conf documentation <project_junctions>`.
"""
from buildstream import Element, ElementError
@@ -161,13 +276,34 @@ class JunctionElement(Element):
def configure(self, node):
- node.validate_keys(["path", "options", "cache-junction-elements", "ignore-junction-remotes"])
+ node.validate_keys(["path", "options", "cache-junction-elements", "ignore-junction-remotes", "overrides"])
self.path = node.get_str("path", default="")
self.options = node.get_mapping("options", default={})
self.cache_junction_elements = node.get_bool("cache-junction-elements", default=False)
self.ignore_junction_remotes = node.get_bool("ignore-junction-remotes", default=False)
+ # The overrides dictionary has the target junction
+ # to override as a key, and a tuple consisting
+ # of the local overriding junction and the provenance
+ # of the override declaration.
+ self.overrides = {}
+ overrides_node = node.get_mapping("overrides", {})
+ for key, value in overrides_node.items():
+ junction_name = value.as_str()
+ provenance = value.get_provenance()
+
+ # Cannot override a subproject with the project itself
+ #
+ if junction_name == self.name:
+ raise ElementError(
+ "{}: Attempt to override subproject junction '{}' with the overriding junction '{}' itself".format(
+ provenance, key, junction_name
+ ),
+ reason="override-junction-with-self",
+ )
+ self.overrides[key] = (junction_name, provenance)
+
def preflight(self):
pass
diff --git a/tests/format/junctions.py b/tests/format/junctions.py
index b60d16816..f5858f7e2 100644
--- a/tests/format/junctions.py
+++ b/tests/format/junctions.py
@@ -2,7 +2,6 @@
# pylint: disable=redefined-outer-name
import os
-import shutil
import pytest
@@ -10,31 +9,35 @@ from buildstream import _yaml
from buildstream.exceptions import ErrorDomain, LoadErrorReason
from buildstream.testing import cli # pylint: disable=unused-import
from buildstream.testing import create_repo
-from buildstream.testing._utils.site import HAVE_GIT
DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "junctions",)
-def copy_subprojects(project, datafiles, subprojects):
- for subproject in subprojects:
- shutil.copytree(os.path.join(str(datafiles), subproject), os.path.join(str(project), subproject))
+def update_project(project_path, updated_configuration):
+ project_conf_path = os.path.join(project_path, "project.conf")
+ project_conf = _yaml.roundtrip_load(project_conf_path)
+ project_conf.update(updated_configuration)
-@pytest.mark.datafiles(DATA_DIR)
-def test_simple_pipeline(cli, datafiles):
- project = os.path.join(str(datafiles), "foo")
- copy_subprojects(project, datafiles, ["base"])
+ _yaml.roundtrip_dump(project_conf, project_conf_path)
- # Check that the pipeline includes the subproject element
- element_list = cli.get_pipeline(project, ["target.bst"])
- assert "base.bst:target.bst" in element_list
+
+#
+# Test behavior of `bst show` on a junction element
+#
+@pytest.mark.datafiles(DATA_DIR)
+def test_simple_show(cli, tmpdir, datafiles):
+ project = os.path.join(str(datafiles), "simple")
+ assert cli.get_element_state(project, "subproject.bst") == "junction"
+#
+# Test that we can build build a pipeline with a junction
+#
@pytest.mark.datafiles(DATA_DIR)
def test_simple_build(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "foo")
- copy_subprojects(project, datafiles, ["base"])
+ project = os.path.join(str(datafiles), "simple")
checkoutdir = os.path.join(str(tmpdir), "checkout")
@@ -44,280 +47,223 @@ def test_simple_build(cli, tmpdir, datafiles):
result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
result.assert_success()
- # Check that the checkout contains the expected files from both projects
+ # Check that the checkout contains the expected file from the subproject
assert os.path.exists(os.path.join(checkoutdir, "base.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "foo.txt"))
+#
+# Test failure when there is a missing project.conf
+#
@pytest.mark.datafiles(DATA_DIR)
def test_junction_missing_project_conf(cli, datafiles):
- project = datafiles / "foo"
- copy_subprojects(project, datafiles, ["base"])
-
- # TODO: see if datafiles can tidy this concat up
-
- os.remove(project / "base" / "project.conf")
-
- # Note that both 'foo' and 'base' projects have a 'target.bst'. The
- # 'app.bst' in 'foo' depends on the 'target.bst' in 'base', i.e.:
- #
- # foo/base/target.bst
- # foo/app.bst -> foo/base/target.bst
- # foo/target.bst -> foo/app.bst, foor/base/target.bst
- #
- # In a previous bug (issue #960) if the 'project.conf' was not found in the
- # junction's dir then we were continuing the search in the parent dirs.
- #
- # This would mean that the dep on 'target.bst' would resolve to
- # 'foo/target.bst' instead of 'foo/base/target.bst'.
- #
- # That would lead to a 'circular dependency error' in this setup, when we
- # expect an 'invalid junction'.
- #
- result = cli.run(project=project, args=["build", "app.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_JUNCTION)
+ project = os.path.join(str(datafiles), "simple")
- # Assert that we have the expected provenance encoded into the error
- assert "app.bst [line 6 column 2]" in result.stderr
+ # Just remove the project.conf from the simple test and assert the error
+ os.remove(os.path.join(project, "subproject", "project.conf"))
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_JUNCTION)
+ assert "target.bst [line 4 column 2]" in result.stderr
+#
+# Test failure when there is a missing project.conf in a workspaced junction
+#
@pytest.mark.datafiles(DATA_DIR)
def test_workspaced_junction_missing_project_conf(cli, datafiles):
- # See test_junction_missing_project_conf for some more background.
+ project = os.path.join(str(datafiles), "simple")
- project = datafiles / "foo"
- workspace_dir = project / "base_workspace"
- copy_subprojects(project, datafiles, ["base"])
+ workspace_dir = os.path.join(project, "workspace")
- result = cli.run(project=project, args=["workspace", "open", "base.bst", "--directory", workspace_dir])
- print(result)
+ result = cli.run(project=project, args=["workspace", "open", "subproject.bst", "--directory", workspace_dir])
result.assert_success()
- os.remove(workspace_dir / "project.conf")
-
- result = cli.run(project=project, args=["build", "app.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_JUNCTION)
-
- # Assert that we have the expected provenance encoded into the error
- assert "app.bst [line 6 column 2]" in result.stderr
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_build_of_same_junction_used_twice(cli, datafiles):
- project = os.path.join(str(datafiles), "inconsistent-names")
+ # Remove the project.conf from the workspace directory
+ os.remove(os.path.join(workspace_dir, "project.conf"))
- # Check we can build a project that contains the same junction
- # that is used twice, but named differently
+ # Assert the same missing project.conf error
result = cli.run(project=project, args=["build", "target.bst"])
- result.assert_success()
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_missing_file_in_subproject(cli, datafiles):
- project = os.path.join(str(datafiles), "missing-element")
- result = cli.run(project=project, args=["show", "target.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
+ result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_JUNCTION)
# Assert that we have the expected provenance encoded into the error
assert "target.bst [line 4 column 2]" in result.stderr
+#
+# Test successful builds of deeply nested targets
+#
@pytest.mark.datafiles(DATA_DIR)
-def test_missing_file_in_subsubproject(cli, datafiles):
- project = os.path.join(str(datafiles), "missing-element")
- result = cli.run(project=project, args=["show", "sub-target.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
-
- # Assert that we have the expected provenance encoded into the error
- assert "junction-A.bst:target.bst [line 4 column 2]" in result.stderr
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_missing_junction_in_subproject(cli, datafiles):
- project = os.path.join(str(datafiles), "missing-element")
- result = cli.run(project=project, args=["show", "sub-target-bad-junction.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
-
- # Assert that we have the expected provenance encoded into the error
- assert "junction-A.bst:bad-junction-target.bst [line 4 column 2]" in result.stderr
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_nested_simple(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "foo")
- copy_subprojects(project, datafiles, ["base"])
-
+@pytest.mark.parametrize(
+ "target,expected",
+ [("target.bst", ["sub.txt", "subsub.txt"]), ("deeptarget.bst", ["sub.txt", "subsub.txt", "subsubsub.txt"]),],
+ ids=["simple", "deep"],
+)
+def test_nested(cli, tmpdir, datafiles, target, expected):
project = os.path.join(str(datafiles), "nested")
- copy_subprojects(project, datafiles, ["foo"])
-
- checkoutdir = os.path.join(str(tmpdir), "checkout")
-
- # Build, checkout
- result = cli.run(project=project, args=["build", "target.bst"])
- result.assert_success()
- result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
- result.assert_success()
-
- # Check that the checkout contains the expected files from all subprojects
- assert os.path.exists(os.path.join(checkoutdir, "base.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "foo.txt"))
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_nested_double(cli, tmpdir, datafiles):
- project_foo = os.path.join(str(datafiles), "foo")
- copy_subprojects(project_foo, datafiles, ["base"])
-
- project_bar = os.path.join(str(datafiles), "bar")
- copy_subprojects(project_bar, datafiles, ["base"])
-
- project = os.path.join(str(datafiles), "toplevel")
- copy_subprojects(project, datafiles, ["base", "foo", "bar"])
-
checkoutdir = os.path.join(str(tmpdir), "checkout")
# Build, checkout
- result = cli.run(project=project, args=["build", "target.bst"])
+ result = cli.run(project=project, args=["build", target])
result.assert_success()
- result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result = cli.run(project=project, args=["artifact", "checkout", target, "--directory", checkoutdir])
result.assert_success()
# Check that the checkout contains the expected files from all subprojects
- assert os.path.exists(os.path.join(checkoutdir, "base.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "foo.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "bar.txt"))
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_nested_conflict(cli, datafiles):
- project_foo = os.path.join(str(datafiles), "foo")
- copy_subprojects(project_foo, datafiles, ["base"])
-
- project_bar = os.path.join(str(datafiles), "bar")
- copy_subprojects(project_bar, datafiles, ["base"])
-
- project = os.path.join(str(datafiles), "conflict")
- copy_subprojects(project, datafiles, ["foo", "bar"])
-
- result = cli.run(project=project, args=["build", "target.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.CONFLICTING_JUNCTION)
-
- assert "bar.bst:target.bst [line 3 column 2]" in result.stderr
-
+ for filename in expected:
+ assert os.path.exists(os.path.join(checkoutdir, filename))
-# Test that we error correctly when the junction element itself is missing
-@pytest.mark.datafiles(DATA_DIR)
-def test_missing_junction(cli, datafiles):
- project = os.path.join(str(datafiles), "invalid")
-
- result = cli.run(project=project, args=["build", "missing.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
-
-# Test that we error correctly when an element is not found in the subproject
+#
+# Test missing elements/junctions in subprojects
+#
@pytest.mark.datafiles(DATA_DIR)
-def test_missing_subproject_element(cli, datafiles):
- project = os.path.join(str(datafiles), "invalid")
- copy_subprojects(project, datafiles, ["base"])
-
- result = cli.run(project=project, args=["build", "missing-element.bst"])
+@pytest.mark.parametrize(
+ "target,provenance",
+ [
+ ("target.bst", "target.bst [line 4 column 2]"),
+ ("sub-target.bst", "junction-A.bst:target.bst [line 4 column 2]"),
+ ("bad-junction.bst", "bad-junction.bst [line 3 column 2]"),
+ ("sub-target-bad-junction.bst", "junction-A.bst:bad-junction-target.bst [line 4 column 2]"),
+ ],
+ ids=["subproject-target", "subsubproject-target", "local-junction", "subproject-junction"],
+)
+def test_missing_files(cli, datafiles, target, provenance):
+ project = os.path.join(str(datafiles), "missing-element")
+ result = cli.run(project=project, args=["show", target])
result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
-
-# Test that we error correctly when a junction itself has dependencies
-@pytest.mark.datafiles(DATA_DIR)
-def test_invalid_with_deps(cli, datafiles):
- project = os.path.join(str(datafiles), "invalid")
- copy_subprojects(project, datafiles, ["base"])
-
- result = cli.run(project=project, args=["build", "junction-with-deps.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_JUNCTION)
-
-
-# Test that we error correctly when a junction is directly depended on
-@pytest.mark.datafiles(DATA_DIR)
-def test_invalid_junction_dep(cli, datafiles):
- project = os.path.join(str(datafiles), "invalid")
- copy_subprojects(project, datafiles, ["base"])
-
- result = cli.run(project=project, args=["build", "junction-dep.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA)
+ # Assert that we have the expected provenance encoded into the error
+ assert provenance in result.stderr
-# Test that we error correctly when we junction-depend on a non-junction
+#
+# Test various invalid junction configuraions
+#
@pytest.mark.datafiles(DATA_DIR)
-def test_invalid_junctiondep_not_a_junction(cli, datafiles):
+@pytest.mark.parametrize(
+ "target,domain,reason,provenance",
+ [
+ # Test a junction which itself has dependencies
+ (
+ "junction-with-deps.bst",
+ ErrorDomain.LOAD,
+ LoadErrorReason.INVALID_JUNCTION,
+ "base-with-deps.bst [line 6 column 2]",
+ ),
+ # Test having a dependency directly on a junction
+ ("junction-dep.bst", ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA, "junction-dep.bst [line 3 column 2]"),
+ # Test that we error correctly when we junction-depend on a non-junction
+ (
+ "junctiondep-not-a-junction.bst",
+ ErrorDomain.LOAD,
+ LoadErrorReason.INVALID_DATA,
+ "junctiondep-not-a-junction.bst [line 3 column 2]",
+ ),
+ # Test that overriding a subproject junction with the junction
+ # declaring the override itself will result in an error
+ (
+ "target-self-override.bst",
+ ErrorDomain.ELEMENT,
+ "override-junction-with-self",
+ "subproject-self-override.bst [line 16 column 20]",
+ ),
+ ],
+ ids=["junction-with-deps", "deps-on-junction", "use-element-as-junction", "override-with-self"],
+)
+def test_invalid(cli, datafiles, target, domain, reason, provenance):
project = os.path.join(str(datafiles), "invalid")
- copy_subprojects(project, datafiles, ["base"])
-
- result = cli.run(project=project, args=["build", "junctiondep-not-a-junction.bst"])
- result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA)
-
- # Assert that we have the expected provenance encoded into the error
- assert "junctiondep-not-a-junction.bst [line 3 column 2]" in result.stderr
+ result = cli.run(project=project, args=["build", target])
+ result.assert_main_error(domain, reason)
+ assert provenance in result.stderr
@pytest.mark.datafiles(DATA_DIR)
-def test_options_default(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "options-default")
- copy_subprojects(project, datafiles, ["options-base"])
-
+@pytest.mark.parametrize(
+ "target,expect_exists,expect_not_exists",
+ [("target-default.bst", "pony.txt", "horsy.txt"), ("target-explicit.bst", "horsy.txt", "pony.txt"),],
+ ids=["check-values", "set-explicit-values"],
+)
+def test_options(cli, tmpdir, datafiles, target, expect_exists, expect_not_exists):
+ project = os.path.join(str(datafiles), "options")
checkoutdir = os.path.join(str(tmpdir), "checkout")
# Build, checkout
- result = cli.run(project=project, args=["build", "target.bst"])
+ result = cli.run(project=project, args=["build", target])
result.assert_success()
- result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result = cli.run(project=project, args=["artifact", "checkout", target, "--directory", checkoutdir])
result.assert_success()
- assert os.path.exists(os.path.join(checkoutdir, "pony.txt"))
- assert not os.path.exists(os.path.join(checkoutdir, "horsy.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, expect_exists))
+ assert not os.path.exists(os.path.join(checkoutdir, expect_not_exists))
+#
+# Test propagation of options through a junction
+#
@pytest.mark.datafiles(DATA_DIR)
-def test_options(cli, tmpdir, datafiles):
+@pytest.mark.parametrize(
+ "animal,expect_exists,expect_not_exists",
+ [("pony", "pony.txt", "horsy.txt"), ("horsy", "horsy.txt", "pony.txt"),],
+ ids=["pony", "horsy"],
+)
+def test_options_propagate(cli, tmpdir, datafiles, animal, expect_exists, expect_not_exists):
project = os.path.join(str(datafiles), "options")
- copy_subprojects(project, datafiles, ["options-base"])
-
checkoutdir = os.path.join(str(tmpdir), "checkout")
- # Build, checkout
- result = cli.run(project=project, args=["build", "target.bst"])
- result.assert_success()
- result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
- result.assert_success()
-
- assert not os.path.exists(os.path.join(checkoutdir, "pony.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "horsy.txt"))
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_options_inherit(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "options-inherit")
- copy_subprojects(project, datafiles, ["options-base"])
-
- checkoutdir = os.path.join(str(tmpdir), "checkout")
+ update_project(
+ project,
+ {
+ "options": {
+ "animal": {
+ "type": "enum",
+ "description": "The kind of animal",
+ "values": ["pony", "horsy"],
+ "default": "pony",
+ "variable": "animal",
+ }
+ }
+ },
+ )
# Build, checkout
- result = cli.run(project=project, args=["build", "target.bst"])
+ result = cli.run(project=project, args=["--option", "animal", animal, "build", "target-propagate.bst"])
result.assert_success()
- result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result = cli.run(
+ project=project,
+ args=[
+ "--option",
+ "animal",
+ animal,
+ "artifact",
+ "checkout",
+ "target-propagate.bst",
+ "--directory",
+ checkoutdir,
+ ],
+ )
result.assert_success()
- assert not os.path.exists(os.path.join(checkoutdir, "pony.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "horsy.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, expect_exists))
+ assert not os.path.exists(os.path.join(checkoutdir, expect_not_exists))
-@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+#
+# A lot of testing is using local sources for the junctions for
+# speed and convenience, however there are some internal optimizations
+# for local sources, so we need to test some things using a real
+# source which involves triggering fetches.
+#
+# We use the tar source for this since it is a core plugin.
+#
@pytest.mark.datafiles(DATA_DIR)
-def test_git_show(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "foo")
+def test_tar_show(cli, tmpdir, datafiles):
+ project = os.path.join(str(datafiles), "use-repo")
- # Create the repo from 'base' subdir
- repo = create_repo("git", str(tmpdir))
- ref = repo.create(os.path.join(str(datafiles), "base"))
+ # Create the repo from 'baserepo' subdir
+ repo = create_repo("tar", str(tmpdir))
+ ref = repo.create(os.path.join(project, "baserepo"))
- # Write out junction element with git source
+ # Write out junction element with tar source
element = {"kind": "junction", "sources": [repo.source_config(ref=ref)]}
_yaml.roundtrip_dump(element, os.path.join(project, "base.bst"))
@@ -327,17 +273,16 @@ def test_git_show(cli, tmpdir, datafiles):
assert "base.bst:target.bst" in element_list
-@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
@pytest.mark.datafiles(DATA_DIR)
-def test_git_build(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "foo")
+def test_tar_build(cli, tmpdir, datafiles):
+ project = os.path.join(str(datafiles), "use-repo")
checkoutdir = os.path.join(str(tmpdir), "checkout")
- # Create the repo from 'base' subdir
- repo = create_repo("git", str(tmpdir))
- ref = repo.create(os.path.join(str(datafiles), "base"))
+ # Create the repo from 'baserepo' subdir
+ repo = create_repo("tar", str(tmpdir))
+ ref = repo.create(os.path.join(project, "baserepo"))
- # Write out junction element with git source
+ # Write out junction element with tar source
element = {"kind": "junction", "sources": [repo.source_config(ref=ref)]}
_yaml.roundtrip_dump(element, os.path.join(project, "base.bst"))
@@ -347,59 +292,45 @@ def test_git_build(cli, tmpdir, datafiles):
result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
result.assert_success()
- # Check that the checkout contains the expected files from both projects
+ # Check that the checkout contains the expected file from the subproject
assert os.path.exists(os.path.join(checkoutdir, "base.txt"))
- assert os.path.exists(os.path.join(checkoutdir, "foo.txt"))
-@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
@pytest.mark.datafiles(DATA_DIR)
-def test_git_missing_project_conf(cli, tmpdir, datafiles):
- project = datafiles / "foo"
+def test_tar_missing_project_conf(cli, tmpdir, datafiles):
+ project = datafiles / "use-repo"
- # See test_junction_missing_project_conf for some more background.
- os.remove(datafiles / "base" / "project.conf")
+ # Remove the project.conf from this repo
+ os.remove(datafiles / "use-repo" / "baserepo" / "project.conf")
# Create the repo from 'base' subdir
- repo = create_repo("git", str(tmpdir))
- ref = repo.create(os.path.join(str(datafiles), "base"))
+ repo = create_repo("tar", str(tmpdir))
+ ref = repo.create(os.path.join(project, "baserepo"))
- # Write out junction element with git source
+ # Write out junction element with tar source
element = {"kind": "junction", "sources": [repo.source_config(ref=ref)]}
_yaml.roundtrip_dump(element, str(project / "base.bst"))
- result = cli.run(project=project, args=["build", "app.bst"])
+ result = cli.run(project=project, args=["build", "target.bst"])
result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_JUNCTION)
# Assert that we have the expected provenance encoded into the error
- assert "app.bst [line 6 column 2]" in result.stderr
-
-
-@pytest.mark.datafiles(DATA_DIR)
-def test_cross_junction_names(cli, datafiles):
- project = os.path.join(str(datafiles), "foo")
- copy_subprojects(project, datafiles, ["base"])
-
- element_list = cli.get_pipeline(project, ["base.bst:target.bst"])
- assert "base.bst:target.bst" in element_list
+ assert "target.bst [line 3 column 2]" in result.stderr
@pytest.mark.datafiles(DATA_DIR)
-def test_build_git_cross_junction_names(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "foo")
+def test_build_tar_cross_junction_names(cli, tmpdir, datafiles):
+ project = os.path.join(str(datafiles), "use-repo")
checkoutdir = os.path.join(str(tmpdir), "checkout")
# Create the repo from 'base' subdir
- repo = create_repo("git", str(tmpdir))
- ref = repo.create(os.path.join(str(datafiles), "base"))
+ repo = create_repo("tar", str(tmpdir))
+ ref = repo.create(os.path.join(project, "baserepo"))
- # Write out junction element with git source
+ # Write out junction element with tar source
element = {"kind": "junction", "sources": [repo.source_config(ref=ref)]}
_yaml.roundtrip_dump(element, os.path.join(project, "base.bst"))
- print(element)
- print(cli.get_pipeline(project, ["base.bst"]))
-
# Build (with implicit fetch of subproject), checkout
result = cli.run(project=project, args=["build", "base.bst:target.bst"])
result.assert_success()
@@ -411,28 +342,19 @@ def test_build_git_cross_junction_names(cli, tmpdir, datafiles):
@pytest.mark.datafiles(DATA_DIR)
-def test_junction_show(cli, tmpdir, datafiles):
- project = os.path.join(str(datafiles), "foo")
- copy_subprojects(project, datafiles, ["base"])
-
- # Show, assert that it says junction
- assert cli.get_element_state(project, "base.bst") == "junction"
-
-
-@pytest.mark.datafiles(DATA_DIR)
-@pytest.mark.parametrize("target", ["junction-full-path.bst", "element-full-path.bst", "foo.bst:base.bst:target.bst"])
+@pytest.mark.parametrize(
+ "target",
+ [
+ "junction-full-path.bst",
+ "element-full-path.bst",
+ "subproject.bst:subsubproject.bst:subsubsubproject.bst:target.bst",
+ ],
+ ids=["junction", "element", "command-line"],
+)
def test_full_path(cli, tmpdir, datafiles, target):
- project_foo = os.path.join(str(datafiles), "foo")
- copy_subprojects(project_foo, datafiles, ["base"])
-
- project = os.path.join(str(datafiles), "toplevel")
- copy_subprojects(project, datafiles, ["base", "foo", "bar"])
-
+ project = os.path.join(str(datafiles), "full-path")
checkoutdir = os.path.join(str(tmpdir), "checkout")
- # FIXME: This file can be removed after removing the junction coalescing feature
- os.remove(os.path.join(project, "base.bst"))
-
# Build, checkout
result = cli.run(project=project, args=["build", target])
result.assert_success()
@@ -440,7 +362,7 @@ def test_full_path(cli, tmpdir, datafiles, target):
result.assert_success()
# Check that the checkout contains the expected file from base
- assert os.path.exists(os.path.join(checkoutdir, "base.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "subsubsub.txt"))
@pytest.mark.datafiles(DATA_DIR)
@@ -449,18 +371,12 @@ def test_full_path(cli, tmpdir, datafiles, target):
[
("junction-full-path-notfound.bst", "junction-full-path-notfound.bst [line 3 column 2]"),
("element-full-path-notfound.bst", "element-full-path-notfound.bst [line 3 column 2]"),
- ("foo.bst:base.bst:pony.bst", None),
+ ("subproject.bst:subsubproject.bst:pony.bst", None),
],
+ ids=["junction", "element", "command-line"],
)
def test_full_path_not_found(cli, tmpdir, datafiles, target, provenance):
- project_foo = os.path.join(str(datafiles), "foo")
- copy_subprojects(project_foo, datafiles, ["base"])
-
- project = os.path.join(str(datafiles), "toplevel")
- copy_subprojects(project, datafiles, ["base", "foo", "bar"])
-
- # FIXME: This file can be removed after removing the junction coalescing feature
- os.remove(os.path.join(project, "base.bst"))
+ project = os.path.join(str(datafiles), "full-path")
# Build
result = cli.run(project=project, args=["build", target])
@@ -469,3 +385,311 @@ def test_full_path_not_found(cli, tmpdir, datafiles, target, provenance):
# Check that provenance was provided if expected
if provenance:
assert provenance in result.stderr
+
+
+#
+# Test the overrides feature.
+#
+# Here we reuse the `nested` project since it already has deep
+# nesting, and add to it a couple of additional junctions to
+# test overriding of junctions at various depts
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize(
+ "target,expected",
+ [
+ # Test that we can override a subproject junction of a subproject
+ ("target-overridden-subsubproject.bst", "subsubsub.txt"),
+ # Test that we can override a subproject junction of a subproject's subproject
+ ("target-overridden-subsubsubproject.bst", "surprise.txt"),
+ # Test that we can override a subproject junction with a deep subproject path
+ ("target-overridden-with-deepsubproject.bst", "deepsurprise.txt"),
+ ],
+ ids=["override-subproject", "override-subsubproject", "override-subproject-with-subsubproject"],
+)
+def test_overrides(cli, tmpdir, datafiles, target, expected):
+ project = os.path.join(str(datafiles), "overrides")
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Build, checkout
+ result = cli.run(project=project, args=["build", target])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", target, "--directory", checkoutdir])
+ result.assert_success()
+
+ # Check that the checkout contains the expected file
+ assert os.path.exists(os.path.join(checkoutdir, expected))
+
+
+# Tests a situation where the same deep subproject is overridden
+# more than once.
+#
+@pytest.mark.datafiles(DATA_DIR)
+def test_override_twice(cli, tmpdir, datafiles):
+ project = os.path.join(str(datafiles), "override-twice")
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Build, checkout
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Check that the checkout contains the expected file
+ assert os.path.exists(os.path.join(checkoutdir, "overridden-again.txt"))
+
+
+#
+# Test conflicting junction scenarios
+#
+# Note here we assert 2 provenances, we want to ensure that both
+# provenances leading up to the use of a project are accounted for
+# in a conflicting junction error.
+#
+# The second provenance can be None, because there will be no
+# provenance for the originally loaded project if it was the toplevel
+# project, or in some cases when a full path to a deep element was
+# specified directly on the command line.
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize(
+ "project_dir,target,provenances",
+ [
+ # Test a stack element which depends directly on the same project twice
+ (
+ "conflicts",
+ "simple-conflict.bst",
+ ["simple-conflict.bst [line 5 column 2]", "simple-conflict.bst [line 4 column 2]"],
+ ),
+ # Test a dependency chain leading deep into a project which conflicts with the toplevel
+ (
+ "conflicts",
+ "nested-conflict-toplevel.bst",
+ ["subproject.bst:subsubproject-conflict-target.bst [line 4 column 2]"],
+ ),
+ # Test an attempt to override a subproject with a subproject of that same subproject through a different junction
+ (
+ "conflicts",
+ "override-conflict.bst",
+ [
+ "subproject-override-conflicting-path.bst [line 13 column 23]",
+ "override-conflict.bst [line 8 column 2]",
+ ],
+ ),
+ # Same test as above, but specifying the target as a full path instead of a stack element
+ (
+ "conflicts",
+ "subproject-override-conflicting-path.bst:subsubproject.bst:target.bst",
+ ["subproject-override-conflicting-path.bst [line 13 column 23]"],
+ ),
+ # Test a dependency on a subproject conflicting with an include of a file from a different
+ # version of the same project
+ (
+ "conflicts",
+ "include-conflict-target.bst",
+ ["include-conflict-target.bst [line 5 column 2]", "include-conflict.bst [line 4 column 7]"],
+ ),
+ # Test an element kind which needs to load it's plugin from a subproject, but
+ # the element has a dependency on an element from a different version of the same project
+ (
+ "conflicts",
+ "plugin-conflict.bst",
+ ["project.conf [line 4 column 2]", "plugin-conflict.bst [line 4 column 2]"],
+ ),
+ # Test a project which subproject's the same project twice, but only lists it
+ # as a duplicate via one of it's junctions.
+ (
+ "duplicates-simple-incomplete",
+ "target.bst",
+ ["target.bst [line 4 column 2]", "target.bst [line 5 column 2]"],
+ ),
+ # Test a project which subproject's the same project twice, but only lists it
+ # as a duplicate via one of it's junctions.
+ (
+ "duplicates-nested-incomplete",
+ "target.bst",
+ ["target.bst [line 6 column 2]", "target.bst [line 4 column 2]", "target.bst [line 5 column 2]"],
+ ),
+ # Test a project which uses an internal subsubproject, but also uses that same subsubproject twice
+ # at the toplevel, this test ensures we also get the provenance of the internal project in the error.
+ (
+ "internal-and-conflict",
+ "target.bst",
+ [
+ "subproject.bst:subtarget.bst [line 10 column 2]",
+ "target.bst [line 5 column 2]",
+ "target.bst [line 6 column 2]",
+ ],
+ ),
+ ],
+ ids=[
+ "simple",
+ "nested",
+ "override",
+ "override-full-path",
+ "include",
+ "plugin",
+ "incomplete-duplicates",
+ "incomplete-nested-duplicates",
+ "internal",
+ ],
+)
+def test_conflict(cli, tmpdir, datafiles, project_dir, target, provenances):
+ project = os.path.join(str(datafiles), project_dir)
+
+ # Special case setup the conflicting project.conf
+ if target == "plugin-conflict.bst":
+ update_project(
+ project, {"plugins": [{"origin": "junction", "junction": "subproject2.bst", "elements": ["found"],}]},
+ )
+
+ result = cli.run(project=project, args=["build", target])
+ result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.CONFLICTING_JUNCTION)
+
+ # Assert expected provenances
+ for provenance in provenances:
+ assert provenance in result.stderr
+
+
+#
+# Test circular references in junction override cycles
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize(
+ "target,provenance1,provenance2",
+ [
+ # Override a subprojects subsubproject, with a subproject of the
+ # subsubproject being overridden.
+ (
+ "target-overridden-subsubproject-circular.bst",
+ "subproject-overriden-with-circular-reference.bst [line 8 column 23]",
+ None,
+ ),
+ (
+ "target-overridden-subsubproject-circular-link.bst",
+ "link-subsubsubproject.bst [line 4 column 10]",
+ "target-overridden-subsubproject-circular-link.bst [line 4 column 2]",
+ ),
+ ],
+ ids=["override-self", "override-self-using-link"],
+)
+def test_circular_reference(cli, tmpdir, datafiles, target, provenance1, provenance2):
+ project = os.path.join(str(datafiles), "circular-references")
+ result = cli.run(project=project, args=["build", target])
+ result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.CIRCULAR_REFERENCE)
+ assert provenance1 in result.stderr
+ if provenance2:
+ assert provenance2 in result.stderr
+
+
+#
+# Test explicitly marked duplicates
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize(
+ "project_dir",
+ [
+ # Test a project with two direct dependencies on the same project
+ ("duplicates-simple"),
+ # Test a project with a dependency on a project with two duplicate subprojects,
+ # while additionally adding a dependency on that duplicated subproject at the toplevel
+ ("duplicates-nested"),
+ # Same as previous test, but duplicate the subprojects only from the toplevel,
+ # ensuring that the pathing and addressing of elements works.
+ ("duplicates-nested-full-path"),
+ # Test a project with two direct dependencies on the same project, one of them
+ # referred to via a link to the junction.
+ ("duplicates-simple-link"),
+ # Test a project where the toplevel duplicates a link in a subproject
+ ("duplicates-nested-link1"),
+ # Test a project where the toplevel duplicates a link to a nested subproject
+ ("duplicates-nested-link2"),
+ # Test a project which overrides the a subsubproject which is marked as a duplicate by the subproject,
+ # ensure that the duplicate relationship for the subproject/subsubproject is preserved.
+ ("duplicates-override-dup"),
+ # Test a project which overrides a deep subproject multiple times in the hierarchy, the intermediate
+ # junction to the deep subproject (which is overridden by the toplevel) marks that deep subproject as
+ # a duplicate using a link element in the project.conf to mark the duplicate, this link is otherwise unused.
+ ("duplicates-override-twice-link"),
+ ],
+ ids=[
+ "simple",
+ "nested",
+ "nested-full-path",
+ "simple-link",
+ "link-in-subproject",
+ "link-to-subproject",
+ "overridden",
+ "overridden-twice-link",
+ ],
+)
+def test_duplicates(cli, tmpdir, datafiles, project_dir):
+ project = os.path.join(str(datafiles), project_dir)
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+
+
+#
+# Test errors which occur when duplicate lists refer to elements which
+# don't exist.
+#
+# While subprojects are not loaded by virtue of searching the duplicate
+# lists, we do attempt to load elements in loaded projects in order to
+# ensure that we properly traverse `link` elements.
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize(
+ "project_dir,provenance",
+ [
+ # Test a not found duplicate at the toplevel
+ ("duplicates-simple-not-found", "project.conf [line 8 column 6]"),
+ # Test a listed duplicate of a broken `link` target in a subproject
+ ("duplicates-nested-not-found", "subproject.bst:subproject1-link.bst [line 4 column 10]"),
+ ],
+ ids=["simple", "broken-nested-link"],
+)
+def test_duplicates_not_found(cli, tmpdir, datafiles, project_dir, provenance):
+ project = os.path.join(str(datafiles), project_dir)
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE)
+
+ # Check that provenance was provided if expected
+ assert provenance in result.stderr
+
+
+#
+# Test internal projects
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize(
+ "project_dir,expected_files",
+ [
+ # Test a project which repeats a subproject which is also
+ # internal to another subproject.
+ ("internal-simple", ["subsub.txt", "subsub-again.txt"]),
+ # Test a project which repeats a subproject which is also
+ # internal to two other subprojects.
+ ("internal-double", ["subsub1.txt", "subsub2.txt", "subsub-again.txt"]),
+ # Test a project which repeats a subproject which is also
+ # internal to another subproject, which marks it internal using a link.
+ ("internal-link", ["subsub.txt", "subsub-again.txt"]),
+ # Test a project which repeats a subproject which is also internal to another
+ # subproject, and also overrides that same internal subproject.
+ ("internal-override", ["subsub-override.txt", "subsub-again.txt"]),
+ ],
+ ids=["simple", "double", "link", "override"],
+)
+def test_internal(cli, tmpdir, datafiles, project_dir, expected_files):
+ project = os.path.join(str(datafiles), project_dir)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Check that the checkout contains the expected file
+ for expected in expected_files:
+ assert os.path.exists(os.path.join(checkoutdir, expected))
diff --git a/tests/format/junctions/bar/app.bst b/tests/format/junctions/bar/app.bst
deleted file mode 100644
index a1a7a0ed9..000000000
--- a/tests/format/junctions/bar/app.bst
+++ /dev/null
@@ -1,7 +0,0 @@
-kind: import
-sources:
-- kind: local
- path: bar.txt
-depends:
-- junction: base.bst
- filename: target.bst
diff --git a/tests/format/junctions/bar/bar.txt b/tests/format/junctions/bar/bar.txt
deleted file mode 100644
index 5716ca598..000000000
--- a/tests/format/junctions/bar/bar.txt
+++ /dev/null
@@ -1 +0,0 @@
-bar
diff --git a/tests/format/junctions/bar/target.bst b/tests/format/junctions/bar/target.bst
deleted file mode 100644
index 70b78a3fc..000000000
--- a/tests/format/junctions/bar/target.bst
+++ /dev/null
@@ -1,5 +0,0 @@
-kind: stack
-depends:
-- junction: base.bst
- filename: target.bst
-- app.bst
diff --git a/tests/format/junctions/circular-references/link-subsubsubproject.bst b/tests/format/junctions/circular-references/link-subsubsubproject.bst
new file mode 100644
index 000000000..b10db7740
--- /dev/null
+++ b/tests/format/junctions/circular-references/link-subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subproject-overriden-with-circular-reference-link.bst:subsubproject.bst:subsubsubproject.bst
diff --git a/tests/format/junctions/bar/project.conf b/tests/format/junctions/circular-references/project.conf
index 42d288416..20636c446 100644
--- a/tests/format/junctions/bar/project.conf
+++ b/tests/format/junctions/circular-references/project.conf
@@ -1,2 +1,2 @@
-name: bar
+name: test
min-version: 2.0
diff --git a/tests/format/junctions/circular-references/subproject-overriden-with-circular-reference-link.bst b/tests/format/junctions/circular-references/subproject-overriden-with-circular-reference-link.bst
new file mode 100644
index 000000000..9d8b34111
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject-overriden-with-circular-reference-link.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst: link-subsubsubproject.bst
diff --git a/tests/format/junctions/circular-references/subproject-overriden-with-circular-reference.bst b/tests/format/junctions/circular-references/subproject-overriden-with-circular-reference.bst
new file mode 100644
index 000000000..1cdbc44a6
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject-overriden-with-circular-reference.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst: subproject-overriden-with-circular-reference.bst:subsubproject.bst:subsubsubproject.bst
diff --git a/tests/format/junctions/circular-references/subproject.bst b/tests/format/junctions/circular-references/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/conflict/project.conf b/tests/format/junctions/circular-references/subproject/project.conf
index 660ab4fa2..39a53e2ab 100644
--- a/tests/format/junctions/conflict/project.conf
+++ b/tests/format/junctions/circular-references/subproject/project.conf
@@ -1,2 +1,2 @@
-name: conflict
+name: subtest
min-version: 2.0
diff --git a/tests/format/junctions/circular-references/subproject/sub.txt b/tests/format/junctions/circular-references/subproject/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject.bst b/tests/format/junctions/circular-references/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/project.conf b/tests/format/junctions/circular-references/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/subsub.txt b/tests/format/junctions/circular-references/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/subsubsub.txt b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/subsubsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/subsubsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..351c9a22d
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsubsub.txt
diff --git a/tests/format/junctions/circular-references/subproject/subsubproject/target.bst b/tests/format/junctions/circular-references/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/circular-references/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/base.bst b/tests/format/junctions/circular-references/subproject/target.bst
index ecdc57c79..e24d9bbb4 100644
--- a/tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/base.bst
+++ b/tests/format/junctions/circular-references/subproject/target.bst
@@ -1,4 +1,4 @@
kind: import
sources:
- kind: local
- path: base
+ path: sub.txt
diff --git a/tests/format/junctions/circular-references/target-overridden-subsubproject-circular-link.bst b/tests/format/junctions/circular-references/target-overridden-subsubproject-circular-link.bst
new file mode 100644
index 000000000..32617f620
--- /dev/null
+++ b/tests/format/junctions/circular-references/target-overridden-subsubproject-circular-link.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject-overriden-with-circular-reference-link.bst:subsubproject.bst:target.bst
diff --git a/tests/format/junctions/circular-references/target-overridden-subsubproject-circular.bst b/tests/format/junctions/circular-references/target-overridden-subsubproject-circular.bst
new file mode 100644
index 000000000..fd4b5a5f7
--- /dev/null
+++ b/tests/format/junctions/circular-references/target-overridden-subsubproject-circular.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject-overriden-with-circular-reference.bst:subsubproject.bst:target.bst
diff --git a/tests/format/junctions/conflict/target.bst b/tests/format/junctions/conflict/target.bst
deleted file mode 100644
index 5e280e542..000000000
--- a/tests/format/junctions/conflict/target.bst
+++ /dev/null
@@ -1,6 +0,0 @@
-kind: stack
-depends:
-- junction: foo.bst
- filename: target.bst
-- junction: bar.bst
- filename: target.bst
diff --git a/tests/format/junctions/conflicts/include-conflict-target.bst b/tests/format/junctions/conflicts/include-conflict-target.bst
new file mode 100644
index 000000000..237989cd7
--- /dev/null
+++ b/tests/format/junctions/conflicts/include-conflict-target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- include-conflict.bst
+- subproject.bst:target.bst
diff --git a/tests/format/junctions/conflicts/include-conflict.bst b/tests/format/junctions/conflicts/include-conflict.bst
new file mode 100644
index 000000000..9c1ecab25
--- /dev/null
+++ b/tests/format/junctions/conflicts/include-conflict.bst
@@ -0,0 +1,7 @@
+kind: manual
+
+variables:
+ (@): subproject2.bst:inc.yaml
+
+depends:
+- subproject2.bst:target.bst
diff --git a/tests/format/junctions/conflicts/nested-conflict-toplevel.bst b/tests/format/junctions/conflicts/nested-conflict-toplevel.bst
new file mode 100644
index 000000000..445ac0799
--- /dev/null
+++ b/tests/format/junctions/conflicts/nested-conflict-toplevel.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject.bst:subsubproject-conflict-target.bst
diff --git a/tests/format/junctions/conflicts/override-conflict.bst b/tests/format/junctions/conflicts/override-conflict.bst
new file mode 100644
index 000000000..3f0728d29
--- /dev/null
+++ b/tests/format/junctions/conflicts/override-conflict.bst
@@ -0,0 +1,8 @@
+kind: stack
+
+#
+# To trigger the conflict, we need to traverse the path of
+# the overridden `subsubproject.bst` junction.
+#
+depends:
+- subproject-override-conflicting-path.bst:subsubproject.bst:target.bst
diff --git a/tests/format/junctions/conflicts/plugin-conflict.bst b/tests/format/junctions/conflicts/plugin-conflict.bst
new file mode 100644
index 000000000..b9061d14b
--- /dev/null
+++ b/tests/format/junctions/conflicts/plugin-conflict.bst
@@ -0,0 +1,4 @@
+kind: found
+
+depends:
+- subproject.bst:target.bst
diff --git a/tests/format/junctions/conflicts/project.conf b/tests/format/junctions/conflicts/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/conflicts/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/conflicts/simple-conflict.bst b/tests/format/junctions/conflicts/simple-conflict.bst
new file mode 100644
index 000000000..5aaf3a8ab
--- /dev/null
+++ b/tests/format/junctions/conflicts/simple-conflict.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject.bst:target.bst
+- subproject2.bst:target.bst
diff --git a/tests/format/junctions/conflicts/subproject-override-conflicting-path.bst b/tests/format/junctions/conflicts/subproject-override-conflicting-path.bst
new file mode 100644
index 000000000..3861d97df
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject-override-conflicting-path.bst
@@ -0,0 +1,13 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+#
+# Here we are declaring a junction to subproject, and trying to override
+# it's subproject with a deep subproject, using a different junction to
+# the same subproject `subproject.bst`
+#
+config:
+ overrides:
+ subsubproject.bst: subproject.bst:subsubproject.bst:subsubsubproject.bst
diff --git a/tests/format/junctions/conflicts/subproject.bst b/tests/format/junctions/conflicts/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/conflicts/subproject/project.conf b/tests/format/junctions/conflicts/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/conflicts/subproject/sub.txt b/tests/format/junctions/conflicts/subproject/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject-conflict-target.bst b/tests/format/junctions/conflicts/subproject/subsubproject-conflict-target.bst
new file mode 100644
index 000000000..e9bf1c57e
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject-conflict-target.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subsubproject-conflict.bst:target.bst
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject-conflict.bst b/tests/format/junctions/conflicts/subproject/subsubproject-conflict.bst
new file mode 100644
index 000000000..e4715ea1d
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject-conflict.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-conflict
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject-conflict/deepsurprise.txt b/tests/format/junctions/conflicts/subproject/subsubproject-conflict/deepsurprise.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject-conflict/deepsurprise.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject-conflict/project.conf b/tests/format/junctions/conflicts/subproject/subsubproject-conflict/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject-conflict/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject-conflict/target.bst b/tests/format/junctions/conflicts/subproject/subsubproject-conflict/target.bst
new file mode 100644
index 000000000..981f29da3
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject-conflict/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: deepsurprise.txt
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject.bst b/tests/format/junctions/conflicts/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/project.conf b/tests/format/junctions/conflicts/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/subsub.txt b/tests/format/junctions/conflicts/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/subsubsub.txt b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/subsubsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/subsubsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..351c9a22d
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsubsub.txt
diff --git a/tests/format/junctions/conflicts/subproject/subsubproject/target.bst b/tests/format/junctions/conflicts/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/conflicts/subproject/target.bst b/tests/format/junctions/conflicts/subproject/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/conflicts/subproject2.bst b/tests/format/junctions/conflicts/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/conflicts/subproject2/inc.yaml b/tests/format/junctions/conflicts/subproject2/inc.yaml
new file mode 100644
index 000000000..bbc78380f
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject2/inc.yaml
@@ -0,0 +1 @@
+test: Pony
diff --git a/tests/format/junctions/conflicts/subproject2/plugins/found.py b/tests/format/junctions/conflicts/subproject2/plugins/found.py
new file mode 100644
index 000000000..34a7e4398
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject2/plugins/found.py
@@ -0,0 +1,19 @@
+from buildstream import Element
+
+
+class Found(Element):
+ BST_MIN_VERSION = "2.0"
+
+ def configure(self, node):
+ pass
+
+ def preflight(self):
+ pass
+
+ def get_unique_key(self):
+ return {}
+
+
+# Plugin entry point
+def setup():
+ return Found
diff --git a/tests/format/junctions/conflicts/subproject2/project.conf b/tests/format/junctions/conflicts/subproject2/project.conf
new file mode 100644
index 000000000..286045aa0
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject2/project.conf
@@ -0,0 +1,8 @@
+name: subtest
+min-version: 2.0
+
+plugins:
+- origin: local
+ path: plugins
+ elements:
+ - found
diff --git a/tests/format/junctions/conflicts/subproject2/sub2.txt b/tests/format/junctions/conflicts/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/conflicts/subproject2/target.bst b/tests/format/junctions/conflicts/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/conflicts/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested-full-path/project.conf b/tests/format/junctions/duplicates-nested-full-path/project.conf
new file mode 100644
index 000000000..ddac93c49
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/project.conf
@@ -0,0 +1,9 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject.bst:subproject1.bst
+ - subproject.bst:subproject2.bst
+ - subproject3.bst
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject.bst b/tests/format/junctions/duplicates-nested-full-path/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/project.conf b/tests/format/junctions/duplicates-nested-full-path/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1.bst b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2.bst b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject3.bst b/tests/format/junctions/duplicates-nested-full-path/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject3/project.conf b/tests/format/junctions/duplicates-nested-full-path/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject3/sub3.txt b/tests/format/junctions/duplicates-nested-full-path/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-full-path/subproject3/target.bst b/tests/format/junctions/duplicates-nested-full-path/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-nested-full-path/target.bst b/tests/format/junctions/duplicates-nested-full-path/target.bst
new file mode 100644
index 000000000..c9199fe0f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-full-path/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:subproject1.bst:target.bst
+- subproject.bst:subproject2.bst:target.bst
+- subproject3.bst:target.bst
diff --git a/tests/format/junctions/duplicates-nested-incomplete/project.conf b/tests/format/junctions/duplicates-nested-incomplete/project.conf
new file mode 100644
index 000000000..2e4aff856
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/project.conf
@@ -0,0 +1,7 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject3.bst
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/project.conf b/tests/format/junctions/duplicates-nested-incomplete/subproject/project.conf
new file mode 100644
index 000000000..b9cc870a8
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/project.conf
@@ -0,0 +1,7 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject1.bst
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject3.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject3/project.conf b/tests/format/junctions/duplicates-nested-incomplete/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject3/sub3.txt b/tests/format/junctions/duplicates-nested-incomplete/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-incomplete/subproject3/target.bst b/tests/format/junctions/duplicates-nested-incomplete/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-nested-incomplete/target.bst b/tests/format/junctions/duplicates-nested-incomplete/target.bst
new file mode 100644
index 000000000..28e981ea3
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-incomplete/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject3.bst:target.bst
+- subproject.bst:subproject1.bst:target.bst
+- subproject.bst:subproject2.bst:target.bst
diff --git a/tests/format/junctions/duplicates-nested-link1/project.conf b/tests/format/junctions/duplicates-nested-link1/project.conf
new file mode 100644
index 000000000..e229b9f1f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/project.conf
@@ -0,0 +1,8 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject3.bst
+ - subproject.bst:subproject1-link.bst
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject.bst b/tests/format/junctions/duplicates-nested-link1/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/project.conf b/tests/format/junctions/duplicates-nested-link1/subproject/project.conf
new file mode 100644
index 000000000..0be41104a
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/project.conf
@@ -0,0 +1,7 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject1-link.bst b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1-link.bst
new file mode 100644
index 000000000..0e6d8a484
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1-link.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subproject1.bst
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject1.bst b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject2.bst b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject3.bst b/tests/format/junctions/duplicates-nested-link1/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject3/project.conf b/tests/format/junctions/duplicates-nested-link1/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject3/sub3.txt b/tests/format/junctions/duplicates-nested-link1/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-link1/subproject3/target.bst b/tests/format/junctions/duplicates-nested-link1/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-nested-link1/target.bst b/tests/format/junctions/duplicates-nested-link1/target.bst
new file mode 100644
index 000000000..c9199fe0f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link1/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:subproject1.bst:target.bst
+- subproject.bst:subproject2.bst:target.bst
+- subproject3.bst:target.bst
diff --git a/tests/format/junctions/duplicates-nested-link2/project.conf b/tests/format/junctions/duplicates-nested-link2/project.conf
new file mode 100644
index 000000000..2e4aff856
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/project.conf
@@ -0,0 +1,7 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject3.bst
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject.bst b/tests/format/junctions/duplicates-nested-link2/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/project.conf b/tests/format/junctions/duplicates-nested-link2/subproject/project.conf
new file mode 100644
index 000000000..99ccfa68c
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/project.conf
@@ -0,0 +1,8 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject1.bst
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject1.bst b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject2.bst b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject2-link.bst b/tests/format/junctions/duplicates-nested-link2/subproject2-link.bst
new file mode 100644
index 000000000..c7803f902
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject2-link.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subproject.bst:subproject2.bst
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject3.bst b/tests/format/junctions/duplicates-nested-link2/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject3/project.conf b/tests/format/junctions/duplicates-nested-link2/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject3/sub3.txt b/tests/format/junctions/duplicates-nested-link2/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-link2/subproject3/target.bst b/tests/format/junctions/duplicates-nested-link2/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-nested-link2/target.bst b/tests/format/junctions/duplicates-nested-link2/target.bst
new file mode 100644
index 000000000..3e3906da0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-link2/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:subproject1.bst:target.bst
+- subproject2-link.bst:target.bst
+- subproject3.bst:target.bst
diff --git a/tests/format/junctions/duplicates-nested-not-found/project.conf b/tests/format/junctions/duplicates-nested-not-found/project.conf
new file mode 100644
index 000000000..e229b9f1f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/project.conf
@@ -0,0 +1,8 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject3.bst
+ - subproject.bst:subproject1-link.bst
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject.bst b/tests/format/junctions/duplicates-nested-not-found/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/project.conf b/tests/format/junctions/duplicates-nested-not-found/subproject/project.conf
new file mode 100644
index 000000000..0be41104a
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/project.conf
@@ -0,0 +1,7 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1-link.bst b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1-link.bst
new file mode 100644
index 000000000..642ab8c42
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1-link.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subproject5.bst
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1.bst b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2.bst b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject3.bst b/tests/format/junctions/duplicates-nested-not-found/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject3/project.conf b/tests/format/junctions/duplicates-nested-not-found/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject3/sub3.txt b/tests/format/junctions/duplicates-nested-not-found/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested-not-found/subproject3/target.bst b/tests/format/junctions/duplicates-nested-not-found/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-nested-not-found/target.bst b/tests/format/junctions/duplicates-nested-not-found/target.bst
new file mode 100644
index 000000000..c9199fe0f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested-not-found/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:subproject1.bst:target.bst
+- subproject.bst:subproject2.bst:target.bst
+- subproject3.bst:target.bst
diff --git a/tests/format/junctions/duplicates-nested/project.conf b/tests/format/junctions/duplicates-nested/project.conf
new file mode 100644
index 000000000..2e4aff856
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/project.conf
@@ -0,0 +1,7 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject3.bst
diff --git a/tests/format/junctions/duplicates-nested/subproject.bst b/tests/format/junctions/duplicates-nested/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/duplicates-nested/subproject/project.conf b/tests/format/junctions/duplicates-nested/subproject/project.conf
new file mode 100644
index 000000000..99ccfa68c
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/project.conf
@@ -0,0 +1,8 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject1.bst
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject1.bst b/tests/format/junctions/duplicates-nested/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-nested/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-nested/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-nested/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject2.bst b/tests/format/junctions/duplicates-nested/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-nested/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-nested/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-nested/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-nested/subproject3.bst b/tests/format/junctions/duplicates-nested/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-nested/subproject3/project.conf b/tests/format/junctions/duplicates-nested/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-nested/subproject3/sub3.txt b/tests/format/junctions/duplicates-nested/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-nested/subproject3/target.bst b/tests/format/junctions/duplicates-nested/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-nested/target.bst b/tests/format/junctions/duplicates-nested/target.bst
new file mode 100644
index 000000000..c9199fe0f
--- /dev/null
+++ b/tests/format/junctions/duplicates-nested/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:subproject1.bst:target.bst
+- subproject.bst:subproject2.bst:target.bst
+- subproject3.bst:target.bst
diff --git a/tests/format/junctions/duplicates-override-dup/project.conf b/tests/format/junctions/duplicates-override-dup/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-dup/subproject.bst b/tests/format/junctions/duplicates-override-dup/subproject.bst
new file mode 100644
index 000000000..376ac11ee
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subproject1.bst: subproject3.bst
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/project.conf b/tests/format/junctions/duplicates-override-dup/subproject/project.conf
new file mode 100644
index 000000000..99ccfa68c
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/project.conf
@@ -0,0 +1,8 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubtest:
+ - subproject1.bst
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject1.bst b/tests/format/junctions/duplicates-override-dup/subproject/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject1/project.conf b/tests/format/junctions/duplicates-override-dup/subproject/subproject1/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject1/sub.txt b/tests/format/junctions/duplicates-override-dup/subproject/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject1/target.bst b/tests/format/junctions/duplicates-override-dup/subproject/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject2.bst b/tests/format/junctions/duplicates-override-dup/subproject/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject2/project.conf b/tests/format/junctions/duplicates-override-dup/subproject/subproject2/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject2/sub2.txt b/tests/format/junctions/duplicates-override-dup/subproject/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-dup/subproject/subproject2/target.bst b/tests/format/junctions/duplicates-override-dup/subproject/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-override-dup/subproject3.bst b/tests/format/junctions/duplicates-override-dup/subproject3.bst
new file mode 100644
index 000000000..e4ee2f1d5
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject3.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject3
diff --git a/tests/format/junctions/duplicates-override-dup/subproject3/project.conf b/tests/format/junctions/duplicates-override-dup/subproject3/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject3/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-dup/subproject3/sub3.txt b/tests/format/junctions/duplicates-override-dup/subproject3/sub3.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject3/sub3.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-dup/subproject3/target.bst b/tests/format/junctions/duplicates-override-dup/subproject3/target.bst
new file mode 100644
index 000000000..cb81ea97f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/subproject3/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub3.txt
diff --git a/tests/format/junctions/duplicates-override-dup/target.bst b/tests/format/junctions/duplicates-override-dup/target.bst
new file mode 100644
index 000000000..6ca140afb
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-dup/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject.bst:subproject1.bst:target.bst
+- subproject.bst:subproject2.bst:target.bst
diff --git a/tests/format/junctions/duplicates-override-twice-link/duplicate.bst b/tests/format/junctions/duplicates-override-twice-link/duplicate.bst
new file mode 100644
index 000000000..4acb6e63b
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/duplicate.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: duplicate
diff --git a/tests/format/junctions/duplicates-override-twice-link/duplicate/duplicate.txt b/tests/format/junctions/duplicates-override-twice-link/duplicate/duplicate.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/duplicate/duplicate.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-twice-link/duplicate/project.conf b/tests/format/junctions/duplicates-override-twice-link/duplicate/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/duplicate/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-twice-link/duplicate/target.bst b/tests/format/junctions/duplicates-override-twice-link/duplicate/target.bst
new file mode 100644
index 000000000..8b350a12f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/duplicate/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: duplicate.txt
diff --git a/tests/format/junctions/conflict/foo.bst b/tests/format/junctions/duplicates-override-twice-link/override.bst
index 1feb4010b..c0564b631 100644
--- a/tests/format/junctions/conflict/foo.bst
+++ b/tests/format/junctions/duplicates-override-twice-link/override.bst
@@ -1,4 +1,4 @@
kind: junction
sources:
- kind: local
- path: foo
+ path: override
diff --git a/tests/format/junctions/duplicates-override-twice-link/override/overridden-again.txt b/tests/format/junctions/duplicates-override-twice-link/override/overridden-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/override/overridden-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-twice-link/override/project.conf b/tests/format/junctions/duplicates-override-twice-link/override/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/override/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-twice-link/override/target.bst b/tests/format/junctions/duplicates-override-twice-link/override/target.bst
new file mode 100644
index 000000000..c05396c42
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/override/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: overridden-again.txt
diff --git a/tests/format/junctions/duplicates-override-twice-link/project.conf b/tests/format/junctions/duplicates-override-twice-link/project.conf
new file mode 100644
index 000000000..3dbb08c35
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/project.conf
@@ -0,0 +1,7 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubsubtest:
+ - duplicate.bst
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject.bst b/tests/format/junctions/duplicates-override-twice-link/subproject.bst
new file mode 100644
index 000000000..297dbe90d
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst:subsubsubproject.bst: override.bst
diff --git a/tests/format/junctions/foo/base.bst b/tests/format/junctions/duplicates-override-twice-link/subproject/override.bst
index 10ce559a9..c0564b631 100644
--- a/tests/format/junctions/foo/base.bst
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/override.bst
@@ -1,4 +1,4 @@
kind: junction
sources:
- kind: local
- path: base
+ path: override
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/override/overridden.txt b/tests/format/junctions/duplicates-override-twice-link/subproject/override/overridden.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/override/overridden.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/override/project.conf b/tests/format/junctions/duplicates-override-twice-link/subproject/override/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/override/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/override/target.bst b/tests/format/junctions/duplicates-override-twice-link/subproject/override/target.bst
new file mode 100644
index 000000000..8a725bab6
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/override/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: overridden.txt
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/project.conf b/tests/format/junctions/duplicates-override-twice-link/subproject/project.conf
new file mode 100644
index 000000000..cf2fbc7f3
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/project.conf
@@ -0,0 +1,7 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subsubsubtest:
+ - subsubsubproject-link.bst
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject.bst b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject.bst
new file mode 100644
index 000000000..fd5101878
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
+
+config:
+ overrides:
+ subsubsubproject.bst: override.bst
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/project.conf b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/original.txt b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/original.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/original.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..61edc6467
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: original.txt
diff --git a/tests/format/junctions/duplicates-override-twice-link/subproject/subsubsubproject-link.bst b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubsubproject-link.bst
new file mode 100644
index 000000000..d397fb794
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/subproject/subsubsubproject-link.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subsubproject.bst:subsubsubproject.bst
diff --git a/tests/format/junctions/duplicates-override-twice-link/target.bst b/tests/format/junctions/duplicates-override-twice-link/target.bst
new file mode 100644
index 000000000..efbe3330b
--- /dev/null
+++ b/tests/format/junctions/duplicates-override-twice-link/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject.bst:subsubproject.bst:subsubsubproject.bst:target.bst
+- duplicate.bst:target.bst
diff --git a/tests/format/junctions/duplicates-simple-incomplete/project.conf b/tests/format/junctions/duplicates-simple-incomplete/project.conf
new file mode 100644
index 000000000..e7e7d8d63
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/project.conf
@@ -0,0 +1,7 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subtest:
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject1.bst b/tests/format/junctions/duplicates-simple-incomplete/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject1/project.conf b/tests/format/junctions/duplicates-simple-incomplete/subproject1/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject1/sub.txt b/tests/format/junctions/duplicates-simple-incomplete/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject1/target.bst b/tests/format/junctions/duplicates-simple-incomplete/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject2.bst b/tests/format/junctions/duplicates-simple-incomplete/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject2/project.conf b/tests/format/junctions/duplicates-simple-incomplete/subproject2/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject2/sub2.txt b/tests/format/junctions/duplicates-simple-incomplete/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple-incomplete/subproject2/target.bst b/tests/format/junctions/duplicates-simple-incomplete/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-simple-incomplete/target.bst b/tests/format/junctions/duplicates-simple-incomplete/target.bst
new file mode 100644
index 000000000..fd4734b99
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-incomplete/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject1.bst:target.bst
+- subproject2.bst:target.bst
diff --git a/tests/format/junctions/duplicates-simple-link/project.conf b/tests/format/junctions/duplicates-simple-link/project.conf
new file mode 100644
index 000000000..1e1ebae69
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/project.conf
@@ -0,0 +1,8 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subtest:
+ - subproject1.bst
+ - subproject2-link.bst
diff --git a/tests/format/junctions/duplicates-simple-link/subproject1.bst b/tests/format/junctions/duplicates-simple-link/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-simple-link/subproject1/project.conf b/tests/format/junctions/duplicates-simple-link/subproject1/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple-link/subproject1/sub.txt b/tests/format/junctions/duplicates-simple-link/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple-link/subproject1/target.bst b/tests/format/junctions/duplicates-simple-link/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-simple-link/subproject2-link.bst b/tests/format/junctions/duplicates-simple-link/subproject2-link.bst
new file mode 100644
index 000000000..a8aebfa2c
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject2-link.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subproject2.bst
diff --git a/tests/format/junctions/duplicates-simple-link/subproject2.bst b/tests/format/junctions/duplicates-simple-link/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-simple-link/subproject2/project.conf b/tests/format/junctions/duplicates-simple-link/subproject2/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple-link/subproject2/sub2.txt b/tests/format/junctions/duplicates-simple-link/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple-link/subproject2/target.bst b/tests/format/junctions/duplicates-simple-link/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-simple-link/target.bst b/tests/format/junctions/duplicates-simple-link/target.bst
new file mode 100644
index 000000000..b674ed66c
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-link/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject1.bst:target.bst
+- subproject2-link.bst:target.bst
diff --git a/tests/format/junctions/duplicates-simple-not-found/project.conf b/tests/format/junctions/duplicates-simple-not-found/project.conf
new file mode 100644
index 000000000..793c6bf9b
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/project.conf
@@ -0,0 +1,8 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subtest:
+ - subproject1.bst
+ - subproject5.bst
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject1.bst b/tests/format/junctions/duplicates-simple-not-found/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject1/project.conf b/tests/format/junctions/duplicates-simple-not-found/subproject1/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject1/sub.txt b/tests/format/junctions/duplicates-simple-not-found/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject1/target.bst b/tests/format/junctions/duplicates-simple-not-found/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject2.bst b/tests/format/junctions/duplicates-simple-not-found/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject2/project.conf b/tests/format/junctions/duplicates-simple-not-found/subproject2/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject2/sub2.txt b/tests/format/junctions/duplicates-simple-not-found/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple-not-found/subproject2/target.bst b/tests/format/junctions/duplicates-simple-not-found/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-simple-not-found/target.bst b/tests/format/junctions/duplicates-simple-not-found/target.bst
new file mode 100644
index 000000000..fd4734b99
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple-not-found/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject1.bst:target.bst
+- subproject2.bst:target.bst
diff --git a/tests/format/junctions/duplicates-simple/project.conf b/tests/format/junctions/duplicates-simple/project.conf
new file mode 100644
index 000000000..3f5ac145d
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/project.conf
@@ -0,0 +1,8 @@
+name: test
+min-version: 2.0
+
+junctions:
+ duplicates:
+ subtest:
+ - subproject1.bst
+ - subproject2.bst
diff --git a/tests/format/junctions/duplicates-simple/subproject1.bst b/tests/format/junctions/duplicates-simple/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/duplicates-simple/subproject1/project.conf b/tests/format/junctions/duplicates-simple/subproject1/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject1/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple/subproject1/sub.txt b/tests/format/junctions/duplicates-simple/subproject1/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject1/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple/subproject1/target.bst b/tests/format/junctions/duplicates-simple/subproject1/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject1/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/duplicates-simple/subproject2.bst b/tests/format/junctions/duplicates-simple/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/duplicates-simple/subproject2/project.conf b/tests/format/junctions/duplicates-simple/subproject2/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject2/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/duplicates-simple/subproject2/sub2.txt b/tests/format/junctions/duplicates-simple/subproject2/sub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject2/sub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/duplicates-simple/subproject2/target.bst b/tests/format/junctions/duplicates-simple/subproject2/target.bst
new file mode 100644
index 000000000..a1d15e942
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/subproject2/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub2.txt
diff --git a/tests/format/junctions/duplicates-simple/target.bst b/tests/format/junctions/duplicates-simple/target.bst
new file mode 100644
index 000000000..fd4734b99
--- /dev/null
+++ b/tests/format/junctions/duplicates-simple/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject1.bst:target.bst
+- subproject2.bst:target.bst
diff --git a/tests/format/junctions/foo/app.bst b/tests/format/junctions/foo/app.bst
deleted file mode 100644
index e658628b0..000000000
--- a/tests/format/junctions/foo/app.bst
+++ /dev/null
@@ -1,7 +0,0 @@
-kind: import
-sources:
-- kind: local
- path: foo.txt
-depends:
-- junction: base.bst
- filename: target.bst
diff --git a/tests/format/junctions/foo/foo.txt b/tests/format/junctions/foo/foo.txt
deleted file mode 100644
index 257cc5642..000000000
--- a/tests/format/junctions/foo/foo.txt
+++ /dev/null
@@ -1 +0,0 @@
-foo
diff --git a/tests/format/junctions/full-path/element-full-path-notfound.bst b/tests/format/junctions/full-path/element-full-path-notfound.bst
new file mode 100644
index 000000000..8797b1d93
--- /dev/null
+++ b/tests/format/junctions/full-path/element-full-path-notfound.bst
@@ -0,0 +1,3 @@
+kind: stack
+depends:
+- subproject.bst:subsubproject.bst:pony.bst
diff --git a/tests/format/junctions/full-path/element-full-path.bst b/tests/format/junctions/full-path/element-full-path.bst
new file mode 100644
index 000000000..b483ef466
--- /dev/null
+++ b/tests/format/junctions/full-path/element-full-path.bst
@@ -0,0 +1,3 @@
+kind: stack
+depends:
+- subproject.bst:subsubproject.bst:subsubsubproject.bst:target.bst
diff --git a/tests/format/junctions/full-path/junction-full-path-notfound.bst b/tests/format/junctions/full-path/junction-full-path-notfound.bst
new file mode 100644
index 000000000..7d2cb8da7
--- /dev/null
+++ b/tests/format/junctions/full-path/junction-full-path-notfound.bst
@@ -0,0 +1,4 @@
+kind: stack
+depends:
+- junction: subproject.bst:subsubproject.bst
+ filename: pony.bst
diff --git a/tests/format/junctions/full-path/junction-full-path.bst b/tests/format/junctions/full-path/junction-full-path.bst
new file mode 100644
index 000000000..dc8aa3af5
--- /dev/null
+++ b/tests/format/junctions/full-path/junction-full-path.bst
@@ -0,0 +1,4 @@
+kind: stack
+depends:
+- junction: subproject.bst:subsubproject.bst:subsubsubproject.bst
+ filename: target.bst
diff --git a/tests/format/junctions/full-path/project.conf b/tests/format/junctions/full-path/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/full-path/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/full-path/subproject.bst b/tests/format/junctions/full-path/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/full-path/subproject/project.conf b/tests/format/junctions/full-path/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/full-path/subproject/sub.txt b/tests/format/junctions/full-path/subproject/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/full-path/subproject/subsubproject.bst b/tests/format/junctions/full-path/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/project.conf b/tests/format/junctions/full-path/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/subsub.txt b/tests/format/junctions/full-path/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/subsubsub.txt b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/subsubsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/subsubsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..351c9a22d
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsubsub.txt
diff --git a/tests/format/junctions/full-path/subproject/subsubproject/target.bst b/tests/format/junctions/full-path/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/full-path/subproject/target.bst b/tests/format/junctions/full-path/subproject/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/full-path/subproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/inconsistent-names/elements/junction-A.bst b/tests/format/junctions/inconsistent-names/elements/junction-A.bst
deleted file mode 100644
index 74079f990..000000000
--- a/tests/format/junctions/inconsistent-names/elements/junction-A.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: junctionA
diff --git a/tests/format/junctions/inconsistent-names/elements/junction-B-diff-name.bst b/tests/format/junctions/inconsistent-names/elements/junction-B-diff-name.bst
deleted file mode 100644
index 3b33406e5..000000000
--- a/tests/format/junctions/inconsistent-names/elements/junction-B-diff-name.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: junctionA/junctionB
diff --git a/tests/format/junctions/inconsistent-names/elements/target.bst b/tests/format/junctions/inconsistent-names/elements/target.bst
deleted file mode 100644
index 7eba141de..000000000
--- a/tests/format/junctions/inconsistent-names/elements/target.bst
+++ /dev/null
@@ -1,9 +0,0 @@
-kind: import
-sources:
-- kind: local
- path: files/foo
-depends:
-- filename: lib2.bst
- junction: junction-B-diff-name.bst
-- filename: lib.bst
- junction: junction-A.bst
diff --git a/tests/format/junctions/inconsistent-names/files/foo b/tests/format/junctions/inconsistent-names/files/foo
deleted file mode 100644
index e69de29bb..000000000
--- a/tests/format/junctions/inconsistent-names/files/foo
+++ /dev/null
diff --git a/tests/format/junctions/inconsistent-names/junctionA/elements/app.bst b/tests/format/junctions/inconsistent-names/junctionA/elements/app.bst
deleted file mode 100644
index 473aaee0b..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/elements/app.bst
+++ /dev/null
@@ -1,6 +0,0 @@
-kind: import
-sources:
-- kind: local
- path: files/app
-depends:
-- lib.bst
diff --git a/tests/format/junctions/inconsistent-names/junctionA/elements/junction-B.bst b/tests/format/junctions/inconsistent-names/junctionA/elements/junction-B.bst
deleted file mode 100644
index bc66d7851..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/elements/junction-B.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: junctionB
diff --git a/tests/format/junctions/inconsistent-names/junctionA/elements/lib.bst b/tests/format/junctions/inconsistent-names/junctionA/elements/lib.bst
deleted file mode 100644
index 684a64315..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/elements/lib.bst
+++ /dev/null
@@ -1,7 +0,0 @@
-kind: import
-sources:
-- kind: local
- path: files/lib
-depends:
-- filename: base.bst
- junction: junction-B.bst
diff --git a/tests/format/junctions/inconsistent-names/junctionA/files/app b/tests/format/junctions/inconsistent-names/junctionA/files/app
deleted file mode 100644
index e69de29bb..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/files/app
+++ /dev/null
diff --git a/tests/format/junctions/inconsistent-names/junctionA/files/lib b/tests/format/junctions/inconsistent-names/junctionA/files/lib
deleted file mode 100644
index e69de29bb..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/files/lib
+++ /dev/null
diff --git a/tests/format/junctions/inconsistent-names/junctionA/junctionB/base/baseimg b/tests/format/junctions/inconsistent-names/junctionA/junctionB/base/baseimg
deleted file mode 100644
index e69de29bb..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/junctionB/base/baseimg
+++ /dev/null
diff --git a/tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/lib2.bst b/tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/lib2.bst
deleted file mode 100644
index 5a7c17b99..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/junctionB/elements/lib2.bst
+++ /dev/null
@@ -1,6 +0,0 @@
-kind: import
-sources:
-- kind: local
- path: files/lib2
-depends:
-- base.bst
diff --git a/tests/format/junctions/inconsistent-names/junctionA/junctionB/files/lib2 b/tests/format/junctions/inconsistent-names/junctionA/junctionB/files/lib2
deleted file mode 100644
index e69de29bb..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/junctionB/files/lib2
+++ /dev/null
diff --git a/tests/format/junctions/inconsistent-names/junctionA/junctionB/project.conf b/tests/format/junctions/inconsistent-names/junctionA/junctionB/project.conf
deleted file mode 100644
index 6bdff02c5..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/junctionB/project.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-# Unique project name
-name: projectB
-
-# Minimum required BuildStream version
-min-version: 2.0
-
-# Subdirectory where elements are stored
-element-path: elements
diff --git a/tests/format/junctions/inconsistent-names/junctionA/project.conf b/tests/format/junctions/inconsistent-names/junctionA/project.conf
deleted file mode 100644
index 8af914819..000000000
--- a/tests/format/junctions/inconsistent-names/junctionA/project.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-# Unique project name
-name: projectA
-
-# Minimum required BuildStream version
-min-version: 2.0
-
-# Subdirectory where elements are stored
-element-path: elements
diff --git a/tests/format/junctions/inconsistent-names/project.conf b/tests/format/junctions/inconsistent-names/project.conf
deleted file mode 100644
index 8eef10e76..000000000
--- a/tests/format/junctions/inconsistent-names/project.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-# Unique project name
-name: inconsistent-names
-
-# Minimum required BuildStream version
-min-version: 2.0
-
-# Subdirectory where elements are stored
-element-path: elements
diff --git a/tests/format/junctions/internal-and-conflict/project.conf b/tests/format/junctions/internal-and-conflict/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/internal-and-conflict/subproject.bst b/tests/format/junctions/internal-and-conflict/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/internal-and-conflict/subproject/project.conf b/tests/format/junctions/internal-and-conflict/subproject/project.conf
new file mode 100644
index 000000000..1d44ec886
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject/project.conf
@@ -0,0 +1,6 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ internal:
+ - subsubproject.bst
diff --git a/tests/format/junctions/internal-and-conflict/subproject/subsubproject.bst b/tests/format/junctions/internal-and-conflict/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/internal-and-conflict/subproject/subsubproject/project.conf b/tests/format/junctions/internal-and-conflict/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-and-conflict/subproject/subsubproject/subsub.txt b/tests/format/junctions/internal-and-conflict/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-and-conflict/subproject/subsubproject/target.bst b/tests/format/junctions/internal-and-conflict/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/internal-and-conflict/subproject/subtarget.bst b/tests/format/junctions/internal-and-conflict/subproject/subtarget.bst
new file mode 100644
index 000000000..5e6a76bac
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subproject/subtarget.bst
@@ -0,0 +1,10 @@
+kind: compose
+
+# Use a build dependency on our internal subsubproject target.
+#
+# There is currently no validation for this but it may be
+# introduced in the future. For correctness of this test,
+# use a build dependency.
+#
+build-depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-again.bst b/tests/format/junctions/internal-and-conflict/subsubproject-again.bst
new file mode 100644
index 000000000..308642704
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-again.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-again
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-again/project.conf b/tests/format/junctions/internal-and-conflict/subsubproject-again/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-again/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-again/subsub-again.txt b/tests/format/junctions/internal-and-conflict/subsubproject-again/subsub-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-again/subsub-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-again/target.bst b/tests/format/junctions/internal-and-conflict/subsubproject-again/target.bst
new file mode 100644
index 000000000..1a90211de
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-again/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-again.txt
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-conflict.bst b/tests/format/junctions/internal-and-conflict/subsubproject-conflict.bst
new file mode 100644
index 000000000..e4715ea1d
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-conflict.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-conflict
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-conflict/project.conf b/tests/format/junctions/internal-and-conflict/subsubproject-conflict/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-conflict/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-conflict/subsub-again.txt b/tests/format/junctions/internal-and-conflict/subsubproject-conflict/subsub-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-conflict/subsub-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-and-conflict/subsubproject-conflict/target.bst b/tests/format/junctions/internal-and-conflict/subsubproject-conflict/target.bst
new file mode 100644
index 000000000..1a90211de
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/subsubproject-conflict/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-again.txt
diff --git a/tests/format/junctions/internal-and-conflict/target.bst b/tests/format/junctions/internal-and-conflict/target.bst
new file mode 100644
index 000000000..5e661e6ba
--- /dev/null
+++ b/tests/format/junctions/internal-and-conflict/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:subtarget.bst
+- subsubproject-again.bst:target.bst
+- subsubproject-conflict.bst:target.bst
diff --git a/tests/format/junctions/internal-double/project.conf b/tests/format/junctions/internal-double/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/internal-double/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/internal-double/subproject1.bst b/tests/format/junctions/internal-double/subproject1.bst
new file mode 100644
index 000000000..bfd692d00
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject1
diff --git a/tests/format/junctions/internal-double/subproject1/project.conf b/tests/format/junctions/internal-double/subproject1/project.conf
new file mode 100644
index 000000000..d82152220
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1/project.conf
@@ -0,0 +1,6 @@
+name: subtest1
+min-version: 2.0
+
+junctions:
+ internal:
+ - subsubproject.bst
diff --git a/tests/format/junctions/internal-double/subproject1/subsubproject.bst b/tests/format/junctions/internal-double/subproject1/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/internal-double/subproject1/subsubproject/project.conf b/tests/format/junctions/internal-double/subproject1/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-double/subproject1/subsubproject/subsub1.txt b/tests/format/junctions/internal-double/subproject1/subsubproject/subsub1.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1/subsubproject/subsub1.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-double/subproject1/subsubproject/target.bst b/tests/format/junctions/internal-double/subproject1/subsubproject/target.bst
new file mode 100644
index 000000000..2d631ebba
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub1.txt
diff --git a/tests/format/junctions/internal-double/subproject1/subtarget.bst b/tests/format/junctions/internal-double/subproject1/subtarget.bst
new file mode 100644
index 000000000..5e6a76bac
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject1/subtarget.bst
@@ -0,0 +1,10 @@
+kind: compose
+
+# Use a build dependency on our internal subsubproject target.
+#
+# There is currently no validation for this but it may be
+# introduced in the future. For correctness of this test,
+# use a build dependency.
+#
+build-depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/internal-double/subproject2.bst b/tests/format/junctions/internal-double/subproject2.bst
new file mode 100644
index 000000000..2343652e1
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject2
diff --git a/tests/format/junctions/internal-double/subproject2/project.conf b/tests/format/junctions/internal-double/subproject2/project.conf
new file mode 100644
index 000000000..8ed6c717a
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2/project.conf
@@ -0,0 +1,6 @@
+name: subtest2
+min-version: 2.0
+
+junctions:
+ internal:
+ - subsubproject.bst
diff --git a/tests/format/junctions/internal-double/subproject2/subsubproject.bst b/tests/format/junctions/internal-double/subproject2/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/internal-double/subproject2/subsubproject/project.conf b/tests/format/junctions/internal-double/subproject2/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-double/subproject2/subsubproject/subsub2.txt b/tests/format/junctions/internal-double/subproject2/subsubproject/subsub2.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2/subsubproject/subsub2.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-double/subproject2/subsubproject/target.bst b/tests/format/junctions/internal-double/subproject2/subsubproject/target.bst
new file mode 100644
index 000000000..5cfa4e453
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub2.txt
diff --git a/tests/format/junctions/internal-double/subproject2/subtarget.bst b/tests/format/junctions/internal-double/subproject2/subtarget.bst
new file mode 100644
index 000000000..5e6a76bac
--- /dev/null
+++ b/tests/format/junctions/internal-double/subproject2/subtarget.bst
@@ -0,0 +1,10 @@
+kind: compose
+
+# Use a build dependency on our internal subsubproject target.
+#
+# There is currently no validation for this but it may be
+# introduced in the future. For correctness of this test,
+# use a build dependency.
+#
+build-depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/internal-double/subsubproject-again.bst b/tests/format/junctions/internal-double/subsubproject-again.bst
new file mode 100644
index 000000000..308642704
--- /dev/null
+++ b/tests/format/junctions/internal-double/subsubproject-again.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-again
diff --git a/tests/format/junctions/internal-double/subsubproject-again/project.conf b/tests/format/junctions/internal-double/subsubproject-again/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-double/subsubproject-again/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-double/subsubproject-again/subsub-again.txt b/tests/format/junctions/internal-double/subsubproject-again/subsub-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-double/subsubproject-again/subsub-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-double/subsubproject-again/target.bst b/tests/format/junctions/internal-double/subsubproject-again/target.bst
new file mode 100644
index 000000000..1a90211de
--- /dev/null
+++ b/tests/format/junctions/internal-double/subsubproject-again/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-again.txt
diff --git a/tests/format/junctions/internal-double/target.bst b/tests/format/junctions/internal-double/target.bst
new file mode 100644
index 000000000..b579466d5
--- /dev/null
+++ b/tests/format/junctions/internal-double/target.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject1.bst:subtarget.bst
+- subproject2.bst:subtarget.bst
+- subsubproject-again.bst:target.bst
diff --git a/tests/format/junctions/internal-link/project.conf b/tests/format/junctions/internal-link/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/internal-link/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/internal-link/subproject.bst b/tests/format/junctions/internal-link/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/internal-link/subproject/project.conf b/tests/format/junctions/internal-link/subproject/project.conf
new file mode 100644
index 000000000..ac5810334
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/project.conf
@@ -0,0 +1,6 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ internal:
+ - subsubproject-link.bst
diff --git a/tests/format/junctions/internal-link/subproject/subsubproject-link.bst b/tests/format/junctions/internal-link/subproject/subsubproject-link.bst
new file mode 100644
index 000000000..246a5e41c
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/subsubproject-link.bst
@@ -0,0 +1,4 @@
+kind: link
+
+config:
+ target: subsubproject.bst
diff --git a/tests/format/junctions/internal-link/subproject/subsubproject.bst b/tests/format/junctions/internal-link/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/internal-link/subproject/subsubproject/project.conf b/tests/format/junctions/internal-link/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-link/subproject/subsubproject/subsub.txt b/tests/format/junctions/internal-link/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-link/subproject/subsubproject/target.bst b/tests/format/junctions/internal-link/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/internal-link/subproject/subtarget.bst b/tests/format/junctions/internal-link/subproject/subtarget.bst
new file mode 100644
index 000000000..5e6a76bac
--- /dev/null
+++ b/tests/format/junctions/internal-link/subproject/subtarget.bst
@@ -0,0 +1,10 @@
+kind: compose
+
+# Use a build dependency on our internal subsubproject target.
+#
+# There is currently no validation for this but it may be
+# introduced in the future. For correctness of this test,
+# use a build dependency.
+#
+build-depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/internal-link/subsubproject-again.bst b/tests/format/junctions/internal-link/subsubproject-again.bst
new file mode 100644
index 000000000..308642704
--- /dev/null
+++ b/tests/format/junctions/internal-link/subsubproject-again.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-again
diff --git a/tests/format/junctions/internal-link/subsubproject-again/project.conf b/tests/format/junctions/internal-link/subsubproject-again/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-link/subsubproject-again/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-link/subsubproject-again/subsub-again.txt b/tests/format/junctions/internal-link/subsubproject-again/subsub-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-link/subsubproject-again/subsub-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-link/subsubproject-again/target.bst b/tests/format/junctions/internal-link/subsubproject-again/target.bst
new file mode 100644
index 000000000..1a90211de
--- /dev/null
+++ b/tests/format/junctions/internal-link/subsubproject-again/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-again.txt
diff --git a/tests/format/junctions/internal-link/target.bst b/tests/format/junctions/internal-link/target.bst
new file mode 100644
index 000000000..bc8944592
--- /dev/null
+++ b/tests/format/junctions/internal-link/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject.bst:subtarget.bst
+- subsubproject-again.bst:target.bst
diff --git a/tests/format/junctions/internal-override/project.conf b/tests/format/junctions/internal-override/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/internal-override/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/internal-override/subproject.bst b/tests/format/junctions/internal-override/subproject.bst
new file mode 100644
index 000000000..db1dd6253
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst: subsubproject-override.bst
diff --git a/tests/format/junctions/internal-override/subproject/project.conf b/tests/format/junctions/internal-override/subproject/project.conf
new file mode 100644
index 000000000..1d44ec886
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject/project.conf
@@ -0,0 +1,6 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ internal:
+ - subsubproject.bst
diff --git a/tests/format/junctions/internal-override/subproject/subsubproject.bst b/tests/format/junctions/internal-override/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/internal-override/subproject/subsubproject/project.conf b/tests/format/junctions/internal-override/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-override/subproject/subsubproject/subsub.txt b/tests/format/junctions/internal-override/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-override/subproject/subsubproject/target.bst b/tests/format/junctions/internal-override/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/internal-override/subproject/subtarget.bst b/tests/format/junctions/internal-override/subproject/subtarget.bst
new file mode 100644
index 000000000..5e6a76bac
--- /dev/null
+++ b/tests/format/junctions/internal-override/subproject/subtarget.bst
@@ -0,0 +1,10 @@
+kind: compose
+
+# Use a build dependency on our internal subsubproject target.
+#
+# There is currently no validation for this but it may be
+# introduced in the future. For correctness of this test,
+# use a build dependency.
+#
+build-depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/internal-override/subsubproject-again.bst b/tests/format/junctions/internal-override/subsubproject-again.bst
new file mode 100644
index 000000000..308642704
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-again.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-again
diff --git a/tests/format/junctions/internal-override/subsubproject-again/project.conf b/tests/format/junctions/internal-override/subsubproject-again/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-again/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-override/subsubproject-again/subsub-again.txt b/tests/format/junctions/internal-override/subsubproject-again/subsub-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-again/subsub-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-override/subsubproject-again/target.bst b/tests/format/junctions/internal-override/subsubproject-again/target.bst
new file mode 100644
index 000000000..1a90211de
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-again/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-again.txt
diff --git a/tests/format/junctions/internal-override/subsubproject-override.bst b/tests/format/junctions/internal-override/subsubproject-override.bst
new file mode 100644
index 000000000..a5e47cdc6
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-override.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-override
diff --git a/tests/format/junctions/internal-override/subsubproject-override/project.conf b/tests/format/junctions/internal-override/subsubproject-override/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-override/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-override/subsubproject-override/subsub-override.txt b/tests/format/junctions/internal-override/subsubproject-override/subsub-override.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-override/subsub-override.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-override/subsubproject-override/target.bst b/tests/format/junctions/internal-override/subsubproject-override/target.bst
new file mode 100644
index 000000000..ae732d025
--- /dev/null
+++ b/tests/format/junctions/internal-override/subsubproject-override/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-override.txt
diff --git a/tests/format/junctions/internal-override/target.bst b/tests/format/junctions/internal-override/target.bst
new file mode 100644
index 000000000..bc8944592
--- /dev/null
+++ b/tests/format/junctions/internal-override/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject.bst:subtarget.bst
+- subsubproject-again.bst:target.bst
diff --git a/tests/format/junctions/internal-simple/project.conf b/tests/format/junctions/internal-simple/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/internal-simple/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/internal-simple/subproject.bst b/tests/format/junctions/internal-simple/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/internal-simple/subproject/project.conf b/tests/format/junctions/internal-simple/subproject/project.conf
new file mode 100644
index 000000000..1d44ec886
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject/project.conf
@@ -0,0 +1,6 @@
+name: subtest
+min-version: 2.0
+
+junctions:
+ internal:
+ - subsubproject.bst
diff --git a/tests/format/junctions/internal-simple/subproject/subsubproject.bst b/tests/format/junctions/internal-simple/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/internal-simple/subproject/subsubproject/project.conf b/tests/format/junctions/internal-simple/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-simple/subproject/subsubproject/subsub.txt b/tests/format/junctions/internal-simple/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-simple/subproject/subsubproject/target.bst b/tests/format/junctions/internal-simple/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/internal-simple/subproject/subtarget.bst b/tests/format/junctions/internal-simple/subproject/subtarget.bst
new file mode 100644
index 000000000..5e6a76bac
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subproject/subtarget.bst
@@ -0,0 +1,10 @@
+kind: compose
+
+# Use a build dependency on our internal subsubproject target.
+#
+# There is currently no validation for this but it may be
+# introduced in the future. For correctness of this test,
+# use a build dependency.
+#
+build-depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/internal-simple/subsubproject-again.bst b/tests/format/junctions/internal-simple/subsubproject-again.bst
new file mode 100644
index 000000000..308642704
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subsubproject-again.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject-again
diff --git a/tests/format/junctions/internal-simple/subsubproject-again/project.conf b/tests/format/junctions/internal-simple/subsubproject-again/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subsubproject-again/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/internal-simple/subsubproject-again/subsub-again.txt b/tests/format/junctions/internal-simple/subsubproject-again/subsub-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subsubproject-again/subsub-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/internal-simple/subsubproject-again/target.bst b/tests/format/junctions/internal-simple/subsubproject-again/target.bst
new file mode 100644
index 000000000..1a90211de
--- /dev/null
+++ b/tests/format/junctions/internal-simple/subsubproject-again/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub-again.txt
diff --git a/tests/format/junctions/internal-simple/target.bst b/tests/format/junctions/internal-simple/target.bst
new file mode 100644
index 000000000..bc8944592
--- /dev/null
+++ b/tests/format/junctions/internal-simple/target.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+depends:
+- subproject.bst:subtarget.bst
+- subsubproject-again.bst:target.bst
diff --git a/tests/format/junctions/base/base.txt b/tests/format/junctions/invalid/base/base.txt
index a496efee8..a496efee8 100644
--- a/tests/format/junctions/base/base.txt
+++ b/tests/format/junctions/invalid/base/base.txt
diff --git a/tests/format/junctions/base/project.conf b/tests/format/junctions/invalid/base/project.conf
index 7e258e29f..7e258e29f 100644
--- a/tests/format/junctions/base/project.conf
+++ b/tests/format/junctions/invalid/base/project.conf
diff --git a/tests/format/junctions/base/target.bst b/tests/format/junctions/invalid/base/target.bst
index 2b61c518b..2b61c518b 100644
--- a/tests/format/junctions/base/target.bst
+++ b/tests/format/junctions/invalid/base/target.bst
diff --git a/tests/format/junctions/invalid/missing-element.bst b/tests/format/junctions/invalid/missing-element.bst
deleted file mode 100644
index 4c29221af..000000000
--- a/tests/format/junctions/invalid/missing-element.bst
+++ /dev/null
@@ -1,9 +0,0 @@
-# This refers to the `foo.bst` element through
-# the `base.bst` junction. The `base.bst` junction
-# exists but the `foo.bst` element does not exist
-# in the subproject.
-#
-kind: stack
-depends:
-- junction: base.bst
- filename: foo.bst
diff --git a/tests/format/junctions/invalid/subproject-self-override.bst b/tests/format/junctions/invalid/subproject-self-override.bst
new file mode 100644
index 000000000..22a8b3db8
--- /dev/null
+++ b/tests/format/junctions/invalid/subproject-self-override.bst
@@ -0,0 +1,16 @@
+kind: junction
+sources:
+- kind: local
+ path: base
+
+#
+# In this case, the "base" subproject does not really
+# have a subproject to override, but we're using this
+# setup to test the error of overriding a subproject
+# with the junction declaring the override, which will
+# happen sooner than noticing there is not a subproject.bst
+# to override.
+#
+config:
+ overrides:
+ subproject.bst: subproject-self-override.bst
diff --git a/tests/format/junctions/invalid/target-self-override.bst b/tests/format/junctions/invalid/target-self-override.bst
new file mode 100644
index 000000000..0f7b65676
--- /dev/null
+++ b/tests/format/junctions/invalid/target-self-override.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject-self-override.bst:target.bst
diff --git a/tests/format/junctions/invalid/missing.bst b/tests/format/junctions/missing-element/bad-junction.bst
index 672e967fe..672e967fe 100644
--- a/tests/format/junctions/invalid/missing.bst
+++ b/tests/format/junctions/missing-element/bad-junction.bst
diff --git a/tests/format/junctions/nested/deeptarget.bst b/tests/format/junctions/nested/deeptarget.bst
new file mode 100644
index 000000000..8d7aae29d
--- /dev/null
+++ b/tests/format/junctions/nested/deeptarget.bst
@@ -0,0 +1,6 @@
+kind: stack
+
+depends:
+- subproject.bst:target.bst
+- subproject.bst:subtarget.bst
+- subproject.bst:subsubtarget.bst
diff --git a/tests/format/junctions/nested/foo.bst b/tests/format/junctions/nested/foo.bst
deleted file mode 100644
index 1feb4010b..000000000
--- a/tests/format/junctions/nested/foo.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: foo
diff --git a/tests/format/junctions/nested/project.conf b/tests/format/junctions/nested/project.conf
index eba806781..20636c446 100644
--- a/tests/format/junctions/nested/project.conf
+++ b/tests/format/junctions/nested/project.conf
@@ -1,2 +1,2 @@
-name: nested
+name: test
min-version: 2.0
diff --git a/tests/format/junctions/nested/subproject.bst b/tests/format/junctions/nested/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/nested/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/nested/subproject/project.conf b/tests/format/junctions/nested/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/nested/subproject/sub.txt b/tests/format/junctions/nested/subproject/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/nested/subproject/subsubproject.bst b/tests/format/junctions/nested/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/nested/subproject/subsubproject/project.conf b/tests/format/junctions/nested/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/nested/subproject/subsubproject/subsub.txt b/tests/format/junctions/nested/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/subsubsub.txt b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/subsubsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/subsubsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..351c9a22d
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsubsub.txt
diff --git a/tests/format/junctions/nested/subproject/subsubproject/subtarget.bst b/tests/format/junctions/nested/subproject/subsubproject/subtarget.bst
new file mode 100644
index 000000000..b6fea5b2a
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/subtarget.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subsubsubproject.bst:target.bst
diff --git a/tests/format/junctions/nested/subproject/subsubproject/target.bst b/tests/format/junctions/nested/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/nested/subproject/subsubtarget.bst b/tests/format/junctions/nested/subproject/subsubtarget.bst
new file mode 100644
index 000000000..050e0118c
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subsubtarget.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subsubproject.bst:subtarget.bst
diff --git a/tests/format/junctions/nested/subproject/subtarget.bst b/tests/format/junctions/nested/subproject/subtarget.bst
new file mode 100644
index 000000000..c4549b373
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/subtarget.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subsubproject.bst:target.bst
diff --git a/tests/format/junctions/nested/subproject/target.bst b/tests/format/junctions/nested/subproject/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/nested/subproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/nested/target.bst b/tests/format/junctions/nested/target.bst
index db59499a7..32bbc75bc 100644
--- a/tests/format/junctions/nested/target.bst
+++ b/tests/format/junctions/nested/target.bst
@@ -1,4 +1,5 @@
kind: stack
+
depends:
-- junction: foo.bst
- filename: target.bst
+- subproject.bst:target.bst
+- subproject.bst:subtarget.bst
diff --git a/tests/format/junctions/options-default/project.conf b/tests/format/junctions/options-default/project.conf
deleted file mode 100644
index c362c12b6..000000000
--- a/tests/format/junctions/options-default/project.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-name: options-default
-min-version: 2.0
diff --git a/tests/format/junctions/options-inherit/project.conf b/tests/format/junctions/options-inherit/project.conf
deleted file mode 100644
index b5680a792..000000000
--- a/tests/format/junctions/options-inherit/project.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-name: options-inherit
-min-version: 2.0
-options:
- animal:
- type: enum
- description: The kind of animal
- values:
- - pony
- - horsy
- default: horsy
- variable: animal
diff --git a/tests/format/junctions/options-default/base.bst b/tests/format/junctions/options/base-default.bst
index 5d42e5c31..5d42e5c31 100644
--- a/tests/format/junctions/options-default/base.bst
+++ b/tests/format/junctions/options/base-default.bst
diff --git a/tests/format/junctions/options/base.bst b/tests/format/junctions/options/base-explicit.bst
index a100e5e1e..a100e5e1e 100644
--- a/tests/format/junctions/options/base.bst
+++ b/tests/format/junctions/options/base-explicit.bst
diff --git a/tests/format/junctions/options-inherit/base.bst b/tests/format/junctions/options/base-propagate.bst
index 8623d0d01..8623d0d01 100644
--- a/tests/format/junctions/options-inherit/base.bst
+++ b/tests/format/junctions/options/base-propagate.bst
diff --git a/tests/format/junctions/options-base/horsy.txt b/tests/format/junctions/options/options-base/horsy.txt
index 063dad656..063dad656 100644
--- a/tests/format/junctions/options-base/horsy.txt
+++ b/tests/format/junctions/options/options-base/horsy.txt
diff --git a/tests/format/junctions/options-base/pony.txt b/tests/format/junctions/options/options-base/pony.txt
index f62144808..f62144808 100644
--- a/tests/format/junctions/options-base/pony.txt
+++ b/tests/format/junctions/options/options-base/pony.txt
diff --git a/tests/format/junctions/options-base/project.conf b/tests/format/junctions/options/options-base/project.conf
index 58bfa55e5..58bfa55e5 100644
--- a/tests/format/junctions/options-base/project.conf
+++ b/tests/format/junctions/options/options-base/project.conf
diff --git a/tests/format/junctions/options-base/target.bst b/tests/format/junctions/options/options-base/target.bst
index cda17af98..cda17af98 100644
--- a/tests/format/junctions/options-base/target.bst
+++ b/tests/format/junctions/options/options-base/target.bst
diff --git a/tests/format/junctions/options-inherit/target.bst b/tests/format/junctions/options/target-default.bst
index 8395c0c77..6de0bb89d 100644
--- a/tests/format/junctions/options-inherit/target.bst
+++ b/tests/format/junctions/options/target-default.bst
@@ -1,4 +1,4 @@
kind: stack
depends:
-- junction: base.bst
+- junction: base-default.bst
filename: target.bst
diff --git a/tests/format/junctions/options/target.bst b/tests/format/junctions/options/target-explicit.bst
index 8395c0c77..25d923b8e 100644
--- a/tests/format/junctions/options/target.bst
+++ b/tests/format/junctions/options/target-explicit.bst
@@ -1,4 +1,4 @@
kind: stack
depends:
-- junction: base.bst
+- junction: base-explicit.bst
filename: target.bst
diff --git a/tests/format/junctions/foo/target.bst b/tests/format/junctions/options/target-propagate.bst
index 70b78a3fc..7f2f4b798 100644
--- a/tests/format/junctions/foo/target.bst
+++ b/tests/format/junctions/options/target-propagate.bst
@@ -1,5 +1,4 @@
kind: stack
depends:
-- junction: base.bst
+- junction: base-propagate.bst
filename: target.bst
-- app.bst
diff --git a/tests/format/junctions/bar/base.bst b/tests/format/junctions/override-twice/override.bst
index 10ce559a9..c0564b631 100644
--- a/tests/format/junctions/bar/base.bst
+++ b/tests/format/junctions/override-twice/override.bst
@@ -1,4 +1,4 @@
kind: junction
sources:
- kind: local
- path: base
+ path: override
diff --git a/tests/format/junctions/override-twice/override/overridden-again.txt b/tests/format/junctions/override-twice/override/overridden-again.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/override-twice/override/overridden-again.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/override-twice/override/project.conf b/tests/format/junctions/override-twice/override/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/override-twice/override/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/override-twice/override/target.bst b/tests/format/junctions/override-twice/override/target.bst
new file mode 100644
index 000000000..c05396c42
--- /dev/null
+++ b/tests/format/junctions/override-twice/override/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: overridden-again.txt
diff --git a/tests/format/junctions/override-twice/project.conf b/tests/format/junctions/override-twice/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/override-twice/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/override-twice/subproject.bst b/tests/format/junctions/override-twice/subproject.bst
new file mode 100644
index 000000000..297dbe90d
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst:subsubsubproject.bst: override.bst
diff --git a/tests/format/junctions/conflict/bar.bst b/tests/format/junctions/override-twice/subproject/override.bst
index 62eee825a..c0564b631 100644
--- a/tests/format/junctions/conflict/bar.bst
+++ b/tests/format/junctions/override-twice/subproject/override.bst
@@ -1,4 +1,4 @@
kind: junction
sources:
- kind: local
- path: bar
+ path: override
diff --git a/tests/format/junctions/override-twice/subproject/override/overridden.txt b/tests/format/junctions/override-twice/subproject/override/overridden.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/override/overridden.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/override-twice/subproject/override/project.conf b/tests/format/junctions/override-twice/subproject/override/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/override/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/override-twice/subproject/override/target.bst b/tests/format/junctions/override-twice/subproject/override/target.bst
new file mode 100644
index 000000000..8a725bab6
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/override/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: overridden.txt
diff --git a/tests/format/junctions/override-twice/subproject/project.conf b/tests/format/junctions/override-twice/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/override-twice/subproject/subsubproject.bst b/tests/format/junctions/override-twice/subproject/subsubproject.bst
new file mode 100644
index 000000000..fd5101878
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/subsubproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
+
+config:
+ overrides:
+ subsubsubproject.bst: override.bst
diff --git a/tests/format/junctions/override-twice/subproject/subsubproject/project.conf b/tests/format/junctions/override-twice/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/original.txt b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/original.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/original.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..61edc6467
--- /dev/null
+++ b/tests/format/junctions/override-twice/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: original.txt
diff --git a/tests/format/junctions/override-twice/target.bst b/tests/format/junctions/override-twice/target.bst
new file mode 100644
index 000000000..a748441bf
--- /dev/null
+++ b/tests/format/junctions/override-twice/target.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject.bst:subsubproject.bst:subsubsubproject.bst:target.bst
diff --git a/tests/format/junctions/overrides/overridden-subsubproject.bst b/tests/format/junctions/overrides/overridden-subsubproject.bst
new file mode 100644
index 000000000..bb089ab48
--- /dev/null
+++ b/tests/format/junctions/overrides/overridden-subsubproject.bst
@@ -0,0 +1,10 @@
+# This junction resides at the toplevel project
+#
+# It is used to override the subrpoject's junction to
+# the subsubproject, and instead point that to the
+# subsubsubproject.
+#
+kind: junction
+sources:
+- kind: local
+ path: subproject/subsubproject/subsubsubproject
diff --git a/tests/format/junctions/overrides/overridden-subsubsubproject.bst b/tests/format/junctions/overrides/overridden-subsubsubproject.bst
new file mode 100644
index 000000000..ba349d958
--- /dev/null
+++ b/tests/format/junctions/overrides/overridden-subsubsubproject.bst
@@ -0,0 +1,10 @@
+# This junction resides at the toplevel project
+#
+# It is used to override the subrpoject's subsubproject's
+# junction to the subsubsubproject, and instead point that to
+# the surpriseproject.
+#
+kind: junction
+sources:
+- kind: local
+ path: surpriseproject
diff --git a/tests/format/junctions/overrides/project.conf b/tests/format/junctions/overrides/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/overrides/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/overrides/subproject-overriden-with-deep-subproject.bst b/tests/format/junctions/overrides/subproject-overriden-with-deep-subproject.bst
new file mode 100644
index 000000000..f1878c07d
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject-overriden-with-deep-subproject.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst: surpriseproject.bst:deepsurpriseproject.bst
diff --git a/tests/format/junctions/overrides/subproject-with-deep-override.bst b/tests/format/junctions/overrides/subproject-with-deep-override.bst
new file mode 100644
index 000000000..1be1955a7
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject-with-deep-override.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst:subsubsubproject.bst: overridden-subsubsubproject.bst
diff --git a/tests/format/junctions/overrides/subproject-with-override.bst b/tests/format/junctions/overrides/subproject-with-override.bst
new file mode 100644
index 000000000..9c3398b2e
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject-with-override.bst
@@ -0,0 +1,8 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
+
+config:
+ overrides:
+ subsubproject.bst: overridden-subsubproject.bst
diff --git a/tests/format/junctions/overrides/subproject.bst b/tests/format/junctions/overrides/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/overrides/subproject/project.conf b/tests/format/junctions/overrides/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/overrides/subproject/sub.txt b/tests/format/junctions/overrides/subproject/sub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/sub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/overrides/subproject/subsubproject.bst b/tests/format/junctions/overrides/subproject/subsubproject.bst
new file mode 100644
index 000000000..f535ab0e0
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubproject
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/project.conf b/tests/format/junctions/overrides/subproject/subsubproject/project.conf
new file mode 100644
index 000000000..d11bcbb30
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/subsub.txt b/tests/format/junctions/overrides/subproject/subsubproject/subsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/subsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject.bst b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject.bst
new file mode 100644
index 000000000..bce64597b
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subsubsubproject
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/project.conf b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/project.conf
new file mode 100644
index 000000000..e508da808
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/project.conf
@@ -0,0 +1,2 @@
+name: subsubsubtest
+min-version: 2.0
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/subsubsub.txt b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/subsubsub.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/subsubsub.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/target.bst b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/target.bst
new file mode 100644
index 000000000..351c9a22d
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/subsubsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsubsub.txt
diff --git a/tests/format/junctions/overrides/subproject/subsubproject/target.bst b/tests/format/junctions/overrides/subproject/subsubproject/target.bst
new file mode 100644
index 000000000..afafac601
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/subsubproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: subsub.txt
diff --git a/tests/format/junctions/overrides/subproject/target.bst b/tests/format/junctions/overrides/subproject/target.bst
new file mode 100644
index 000000000..e24d9bbb4
--- /dev/null
+++ b/tests/format/junctions/overrides/subproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: sub.txt
diff --git a/tests/format/junctions/overrides/surpriseproject.bst b/tests/format/junctions/overrides/surpriseproject.bst
new file mode 100644
index 000000000..427c4ebdf
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: surpriseproject
diff --git a/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject.bst b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject.bst
new file mode 100644
index 000000000..62423a996
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: deepsurpriseproject
diff --git a/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/deepsurprise.txt b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/deepsurprise.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/deepsurprise.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/project.conf b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/project.conf
new file mode 100644
index 000000000..cf657b17e
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/project.conf
@@ -0,0 +1,2 @@
+name: deepsurprise
+min-version: 2.0
diff --git a/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/target.bst b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/target.bst
new file mode 100644
index 000000000..981f29da3
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/deepsurpriseproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: deepsurprise.txt
diff --git a/tests/format/junctions/overrides/surpriseproject/project.conf b/tests/format/junctions/overrides/surpriseproject/project.conf
new file mode 100644
index 000000000..0d812aed4
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/project.conf
@@ -0,0 +1,2 @@
+name: surprise
+min-version: 2.0
diff --git a/tests/format/junctions/overrides/surpriseproject/surprise.txt b/tests/format/junctions/overrides/surpriseproject/surprise.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/surprise.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/overrides/surpriseproject/target.bst b/tests/format/junctions/overrides/surpriseproject/target.bst
new file mode 100644
index 000000000..bc496303e
--- /dev/null
+++ b/tests/format/junctions/overrides/surpriseproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: surprise.txt
diff --git a/tests/format/junctions/overrides/target-overridden-subsubproject.bst b/tests/format/junctions/overrides/target-overridden-subsubproject.bst
new file mode 100644
index 000000000..18610631a
--- /dev/null
+++ b/tests/format/junctions/overrides/target-overridden-subsubproject.bst
@@ -0,0 +1,12 @@
+kind: stack
+
+# Here we depend on the target in subproject's subsubproject,
+# however we've overridden the subproject's subsubproject with
+# our own.
+#
+# We should still be able to address that overridden subproject
+# and access the project we've overridden it with, which will
+# turn out to be the subsubsubproject.
+#
+depends:
+- subproject-with-override.bst:subsubproject.bst:target.bst
diff --git a/tests/format/junctions/overrides/target-overridden-subsubsubproject.bst b/tests/format/junctions/overrides/target-overridden-subsubsubproject.bst
new file mode 100644
index 000000000..5c5437b7a
--- /dev/null
+++ b/tests/format/junctions/overrides/target-overridden-subsubsubproject.bst
@@ -0,0 +1,8 @@
+kind: stack
+
+# Here we depend on the target in subproject's subsubproject's
+# subsubsubproject, however we've overridden the subproject's
+# subsubproject's subsubsubproject with our own surprise project
+#
+depends:
+- subproject-with-deep-override.bst:subsubproject.bst:subsubsubproject.bst:target.bst
diff --git a/tests/format/junctions/overrides/target-overridden-with-deepsubproject.bst b/tests/format/junctions/overrides/target-overridden-with-deepsubproject.bst
new file mode 100644
index 000000000..bf5240906
--- /dev/null
+++ b/tests/format/junctions/overrides/target-overridden-with-deepsubproject.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject-overriden-with-deep-subproject.bst:subsubproject.bst:target.bst
diff --git a/tests/format/junctions/simple/project.conf b/tests/format/junctions/simple/project.conf
new file mode 100644
index 000000000..20636c446
--- /dev/null
+++ b/tests/format/junctions/simple/project.conf
@@ -0,0 +1,2 @@
+name: test
+min-version: 2.0
diff --git a/tests/format/junctions/simple/subproject.bst b/tests/format/junctions/simple/subproject.bst
new file mode 100644
index 000000000..c88189cb0
--- /dev/null
+++ b/tests/format/junctions/simple/subproject.bst
@@ -0,0 +1,4 @@
+kind: junction
+sources:
+- kind: local
+ path: subproject
diff --git a/tests/format/junctions/simple/subproject/base.txt b/tests/format/junctions/simple/subproject/base.txt
new file mode 100644
index 000000000..f73f3093f
--- /dev/null
+++ b/tests/format/junctions/simple/subproject/base.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/format/junctions/simple/subproject/project.conf b/tests/format/junctions/simple/subproject/project.conf
new file mode 100644
index 000000000..39a53e2ab
--- /dev/null
+++ b/tests/format/junctions/simple/subproject/project.conf
@@ -0,0 +1,2 @@
+name: subtest
+min-version: 2.0
diff --git a/tests/format/junctions/simple/subproject/target.bst b/tests/format/junctions/simple/subproject/target.bst
new file mode 100644
index 000000000..2b61c518b
--- /dev/null
+++ b/tests/format/junctions/simple/subproject/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: base.txt
diff --git a/tests/format/junctions/simple/target.bst b/tests/format/junctions/simple/target.bst
new file mode 100644
index 000000000..8ecfd7d56
--- /dev/null
+++ b/tests/format/junctions/simple/target.bst
@@ -0,0 +1,4 @@
+kind: stack
+
+depends:
+- subproject.bst:target.bst
diff --git a/tests/format/junctions/toplevel/bar.bst b/tests/format/junctions/toplevel/bar.bst
deleted file mode 100644
index 62eee825a..000000000
--- a/tests/format/junctions/toplevel/bar.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: bar
diff --git a/tests/format/junctions/toplevel/base.bst b/tests/format/junctions/toplevel/base.bst
deleted file mode 100644
index 10ce559a9..000000000
--- a/tests/format/junctions/toplevel/base.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: base
diff --git a/tests/format/junctions/toplevel/element-full-path-notfound.bst b/tests/format/junctions/toplevel/element-full-path-notfound.bst
deleted file mode 100644
index 55efaca10..000000000
--- a/tests/format/junctions/toplevel/element-full-path-notfound.bst
+++ /dev/null
@@ -1,3 +0,0 @@
-kind: stack
-depends:
-- foo.bst:base.bst:pony.bst
diff --git a/tests/format/junctions/toplevel/element-full-path.bst b/tests/format/junctions/toplevel/element-full-path.bst
deleted file mode 100644
index f58559a76..000000000
--- a/tests/format/junctions/toplevel/element-full-path.bst
+++ /dev/null
@@ -1,3 +0,0 @@
-kind: stack
-depends:
-- foo.bst:base.bst:target.bst
diff --git a/tests/format/junctions/toplevel/foo.bst b/tests/format/junctions/toplevel/foo.bst
deleted file mode 100644
index 1feb4010b..000000000
--- a/tests/format/junctions/toplevel/foo.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: junction
-sources:
-- kind: local
- path: foo
diff --git a/tests/format/junctions/toplevel/junction-full-path-notfound.bst b/tests/format/junctions/toplevel/junction-full-path-notfound.bst
deleted file mode 100644
index a57d6ba76..000000000
--- a/tests/format/junctions/toplevel/junction-full-path-notfound.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: stack
-depends:
-- junction: foo.bst:base.bst
- filename: pony.bst
diff --git a/tests/format/junctions/toplevel/junction-full-path.bst b/tests/format/junctions/toplevel/junction-full-path.bst
deleted file mode 100644
index 4a4f67d19..000000000
--- a/tests/format/junctions/toplevel/junction-full-path.bst
+++ /dev/null
@@ -1,4 +0,0 @@
-kind: stack
-depends:
-- junction: foo.bst:base.bst
- filename: target.bst
diff --git a/tests/format/junctions/toplevel/project.conf b/tests/format/junctions/toplevel/project.conf
deleted file mode 100644
index d35b2b8f8..000000000
--- a/tests/format/junctions/toplevel/project.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-name: toplevel
-min-version: 2.0
diff --git a/tests/format/junctions/toplevel/target.bst b/tests/format/junctions/toplevel/target.bst
deleted file mode 100644
index 5e280e542..000000000
--- a/tests/format/junctions/toplevel/target.bst
+++ /dev/null
@@ -1,6 +0,0 @@
-kind: stack
-depends:
-- junction: foo.bst
- filename: target.bst
-- junction: bar.bst
- filename: target.bst
diff --git a/tests/format/junctions/use-repo/baserepo/base.txt b/tests/format/junctions/use-repo/baserepo/base.txt
new file mode 100644
index 000000000..a496efee8
--- /dev/null
+++ b/tests/format/junctions/use-repo/baserepo/base.txt
@@ -0,0 +1 @@
+This is a text file
diff --git a/tests/format/junctions/use-repo/baserepo/project.conf b/tests/format/junctions/use-repo/baserepo/project.conf
new file mode 100644
index 000000000..7e258e29f
--- /dev/null
+++ b/tests/format/junctions/use-repo/baserepo/project.conf
@@ -0,0 +1,2 @@
+name: base
+min-version: 2.0
diff --git a/tests/format/junctions/use-repo/baserepo/target.bst b/tests/format/junctions/use-repo/baserepo/target.bst
new file mode 100644
index 000000000..2b61c518b
--- /dev/null
+++ b/tests/format/junctions/use-repo/baserepo/target.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: base.txt
diff --git a/tests/format/junctions/foo/project.conf b/tests/format/junctions/use-repo/project.conf
index 43a09bb5e..43a09bb5e 100644
--- a/tests/format/junctions/foo/project.conf
+++ b/tests/format/junctions/use-repo/project.conf
diff --git a/tests/format/junctions/options-default/target.bst b/tests/format/junctions/use-repo/target.bst
index 8395c0c77..8395c0c77 100644
--- a/tests/format/junctions/options-default/target.bst
+++ b/tests/format/junctions/use-repo/target.bst
diff --git a/tests/frontend/project/files/sub2-project/project.conf b/tests/frontend/project/files/sub2-project/project.conf
index 74cfd2583..74f5985a5 100644
--- a/tests/frontend/project/files/sub2-project/project.conf
+++ b/tests/frontend/project/files/sub2-project/project.conf
@@ -1,4 +1,4 @@
# Project config for frontend build test
-name: subtest
+name: sub2test
min-version: 2.0
element-path: elements
diff --git a/tests/frontend/track-cross-junction/subproject/project.conf b/tests/frontend/track-cross-junction/subproject/project.conf
index 20636c446..39a53e2ab 100644
--- a/tests/frontend/track-cross-junction/subproject/project.conf
+++ b/tests/frontend/track-cross-junction/subproject/project.conf
@@ -1,2 +1,2 @@
-name: test
+name: subtest
min-version: 2.0