#!/opt/homebrew/bin/bash
#------------------------------------------------------------------------------
## Repro for: Stream path isolation inheritance.
set -u
## Usage:
##
## ./repro.sh [-f] 2>&1
##
## Scenario: Streams isolate path inheritance
##
## This repro tests whether this stream path entry:
##
## isolate Version
##
## defined only in //stream/main is inherited by descendant streams created after
## that path entry exists.
##
## The SDP use case is that the file named Version is expected to diverge
## permanently in every stream. It should not be proposed by normal merge/copy
## flows between streams, while ordinary shared files should still participate in
## those flows.
##
## The test uses a disposable P4-native DVCS micro-repo created with:
##
## p4 init -C0 -n
##
## This creates the default stream depot named 'stream' and configures the local
## funky-looking P4PORT value used by P4 personal servers. This script does not
## create a depot manually.
export P4CONFIG=.p4config.local
export P4ENVIRO=/dev/null/.p4enviro
declare ThisScript=${0##*/}
declare Version=1.0.0
declare -i ErrorCount=0
declare AppHome="$PWD"
declare H1="=============================================================================="
declare Log="${ThisScript%.sh}.log"
declare CmdLog=
declare ReproDir=/tmp/repro
## Micro functions.
function msg () { echo -e "${1:-Hi}"; }
function errmsg () { msg "\nError: ${1:-Unknown Error}"; ErrorCount+=1; }
function bail () { errmsg "${1:-Unknown Error}"; exit "$ErrorCount"; }
function cmd () { msg "${2:-Executing command: $1}"; $1; return $?; }
function usage () { grep '^##' "$0" | sed 's/^##//'; exit 1; }
declare -i Force=0
declare -i Scenario=1
declare ScenarioTitle="Streams Isolate Path Inheritance"
#------------------------------------------------------------------------------
## Command Line Args
set +u
while [[ $# -gt 0 ]]; do
case $1 in
(-f) Force=1;;
(-h) usage;;
(-*) bail "Usage error: Unknown option ($1).";;
(*) bail "Usage error: Unknown parameter ($1).";;
esac
shift
done
set -u
if [[ "$Log" != off ]]; then
touch "$Log" || bail "Couldn't touch log file [$Log]."
## Redirect stdout and stderr to a log file.
exec > >(tee "$Log")
exec 2>&1
fi
msg "Started ${0##*/} v$Version at $(date) in $AppHome."
msg "ReproDir=$ReproDir"
[[ -d "$ReproDir" && "$Force" -eq 1 ]] && /bin/rm -rf "$ReproDir"
[[ -d "$ReproDir" ]] && bail "Old repro dir [$ReproDir] exists. Use -f to remove it first."
mkdir "$ReproDir" || bail "Could not do: mkdir $ReproDir"
cd "$ReproDir" || bail "Could not do: cd $ReproDir"
CmdLog="$ReproDir/cmd.log"
msg "$H1\nScenario $Scenario: $ScenarioTitle\n"
msg "\nPreliminary info: Show versions of p4/p4d on the PATH:"
cmd "p4 -V"
cmd "p4d -V"
msg "\nPreliminary setup: Spin up a local repo."
msg "Operating in: $PWD"
cmd "p4 init -C0 -n"
msg "\nAfter 'p4 init -C0 -n', the local repo should already have a stream depot named 'stream' and a mainline stream named //stream/main."
cmd "p4 info"
cmd "p4 streams"
#------------------------------------------------------------------------------
# Scenario setup: Configure //stream/main.
#------------------------------------------------------------------------------
msg "\n$H1\nScenario $Scenario setup: Configure //stream/main with 'isolate Version'.\n"
msg "The mainline stream generated by p4 init starts with ordinary shared stream paths."
msg "This repro edits only //stream/main and adds the SDP-style isolated Version path:"
msg "\n Paths:\n share ...\n isolate Version\n"
p4 stream -t mainline -o //stream/main > main.stream.orig
awk '
BEGIN { inPaths = 0 }
/^Paths:/ {
print "Paths:"
print "\tshare ..."
print "\tisolate Version"
inPaths = 1
next
}
inPaths && /^[A-Z][A-Za-z]*:/ {
inPaths = 0
}
!inPaths { print }
' main.stream.orig > main.stream
msg "Modified //stream/main stream spec:"
grep -v '^#' main.stream
msg "p4 -s stream -i < main.stream"
p4 -s stream -i < main.stream
msg "\n//stream/main after update:"
p4 stream -o //stream/main | grep -v '^#'
#------------------------------------------------------------------------------
# Create streams.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Create descendant streams after main already has 'isolate Version'.\n"
msg "\nCreating //stream/dev as a development child of //stream/main."
p4 --field Type=development --field Parent=//stream/main stream -o //stream/dev > dev.stream
grep -v '^#' dev.stream
msg "p4 -s stream -i < dev.stream"
p4 -s stream -i < dev.stream
msg "\nCreating //stream/dev_rebrand as a development child of //stream/dev."
p4 --field Type=development --field Parent=//stream/dev stream -o //stream/dev_rebrand > dev_rebrand.stream
grep -v '^#' dev_rebrand.stream
msg "p4 -s stream -i < dev_rebrand.stream"
p4 -s stream -i < dev_rebrand.stream
msg "\nCreating //stream/r26.1 as a release child of //stream/main."
msg "This intentionally relies on the server's release-stream defaults rather than manually creating a noinherit stream depot or custom depot spec."
p4 --field Type=release --field Parent=//stream/main stream -o //stream/r26.1 > r26.1.stream
grep -v '^#' r26.1.stream
msg "p4 -s stream -i < r26.1.stream"
p4 -s stream -i < r26.1.stream
msg "\nCurrent streams:"
cmd "p4 streams"
#------------------------------------------------------------------------------
# Show stream specs and generated views.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Capture stream specs and generated views for later inspection.\n"
msg "The generated view output is intentionally verbose. It is often the most useful evidence when discussing stream behavior with someone who knows ViewGen internals."
for s in //stream/main //stream/dev //stream/dev_rebrand //stream/r26.1; do
msg "\nStream spec for $s:"
p4 stream -o "$s" | grep -v '^#'
msg "\nGenerated view for $s:"
p4 stream -v -o "$s" | grep -v '^#'
done
#------------------------------------------------------------------------------
# Create clients for each stream.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Create one workspace per stream.\n"
msg "Using separate workspaces makes the file operations easier to read in the resulting log."
#------------------------------------------------------------------------------
# Populate permanent-divergence Version files.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Add a different Version file in every stream.\n"
msg "The theory is that each Version file lives in its own stream forever and is not subject to normal Merge Down / Copy Up flow."
msg "\nAdding Version in //stream/main."
echo "Rev. SDP/MultiArch/2025.1/main ($(date +%Y/%m/%d))." > Version
cmd "p4 add Version"
cmd "p4 submit -d Add-main-Version"
for stream in dev dev_rebrand r26.1; do
msg "\nAdding Version in stream $stream."
cmd "p4 client -s -S //stream/$stream" # Change stream of current workspace.
cmd "p4 sync" # This will remove the Version file on disk.
echo "Rev. SDP/MultiArch/2026.1/$stream ($(date +%Y/%m/%d))." > Version
cmd "p4 add Version"
cmd "p4 submit -d Add-$stream-Version"
done
#------------------------------------------------------------------------------
# Add ordinary shared files to prove merge previews still work.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Add ordinary shared files that should be proposed by merge previews.\n"
msg "To avoid a false PASS, this repro also creates ordinary shared files. The preview tests should show these ordinary files as candidates while not showing Version."
msg "\nAdding SharedFromMain.txt in //stream/main."
cmd "p4 client -s -S //stream/main" # Change stream of current workspace.
cmd "p4 sync"
echo "This ordinary shared file was added in main." > SharedFromMain.txt
cmd "p4 add SharedFromMain.txt"
cmd "p4 submit -d Add-shared-file-from-main"
msg "\nAdding SharedFromDev.txt in //stream/dev."
cmd "p4 client -s -S //stream/dev" # Change stream of current workspace.
cmd "p4 sync"
echo "This ordinary shared file was added in dev." > SharedFromDev.txt
cmd "p4 add SharedFromDev.txt"
cmd "p4 submit -d Add-shared-file-from-dev"
#------------------------------------------------------------------------------
# Preview merges and interpret output.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Preview merges and look for Version.\n"
msg "A successful result is not merely that merge previews are empty."
msg "A successful result is that ordinary shared files are proposed, while Version is not proposed."
msg "\nPreview merge from parent //stream/main into child //stream/dev."
msg "Expected: SharedFromMain.txt should appear; Version should not appear."
cmd "p4 client -s -S //stream/dev"
cmd "p4 sync"
p4 merge -n > "$CmdLog" 2>&1 || true
cat "$CmdLog"
if grep -q 'Version' "$CmdLog"; then
errmsg "Version unexpectedly appeared in merge preview from main to dev."
fi
if ! grep -q 'SharedFromMain.txt' "$CmdLog"; then
errmsg "SharedFromMain.txt did not appear in merge preview from main to dev; the test may not have exercised normal shared stream behavior."
fi
msg "\nPreview merge from parent //stream/dev into grandchild //stream/dev_rebrand."
msg "Expected: SharedFromDev.txt should appear; Version should not appear."
cmd "p4 client -s -S //stream/dev_rebrand"
cmd "p4 sync"
p4 merge -n > "$CmdLog" 2>&1 || true
cat "$CmdLog"
if grep -q 'Version' "$CmdLog"; then
errmsg "Version unexpectedly appeared in merge preview from dev to dev_rebrand."
fi
if ! grep -q 'SharedFromDev.txt' "$CmdLog"; then
errmsg "SharedFromDev.txt did not appear in merge preview from dev to dev_rebrand; the test may not have exercised normal shared stream behavior."
fi
msg "\nPreview merge from parent //stream/main into release stream //stream/r26.1."
msg "Expected: SharedFromMain.txt should appear; Version should not appear."
cmd "p4 client -s -S //stream/r26.1"
cmd "p4 sync"
p4 copy -n > "$CmdLog" 2>&1 || true
cat "$CmdLog"
if grep -q 'Version' "$CmdLog"; then
errmsg "Version unexpectedly appeared in merge preview from main to r26.1."
fi
if ! grep -q 'SharedFromMain.txt' "$CmdLog"; then
errmsg "SharedFromMain.txt did not appear in merge preview from main to r26.1; the release-stream part of the test may need manual inspection."
fi
#------------------------------------------------------------------------------
# Extra inspection output.
#------------------------------------------------------------------------------
Scenario=$((Scenario+1))
msg "\n$H1\nScenario $Scenario: Additional inspection commands.\n"
msg "These commands are informational. They make the log more useful if this repro is later sent to someone else for review."
cmd "p4 files //stream/..."
cmd "p4 interchanges //stream/main //stream/dev"
cmd "p4 interchanges //stream/dev //stream/dev_rebrand"
cmd "p4 interchanges //stream/main //stream/r26.1"
#------------------------------------------------------------------------------
# Result.
#------------------------------------------------------------------------------
msg "\n$H1\nThe Result:\n"
if [[ "$ErrorCount" -eq 0 ]]; then
rm -f "$CmdLog"
msg "Yay!"
msg "\nThe observed behavior supports the theory being tested:"
msg "\n isolate Version\n"
msg "defined only in //stream/main was sufficient for the descendant streams created after that setting was present."
msg "\nThe merge previews proposed ordinary shared files, proving the merge previews were meaningful, but did not propose Version."
msg "\nThis supports the SDP design assumption that Version can be isolated once in main rather than redundantly isolated in every descendant development stream."
msg "\nFor release streams, this repro also checks the practical behavior of a release stream created after main already had the isolated path. Existing noinherit release streams created before the path change should still be reviewed separately."
else
msg "One or more checks reported errors. Review the log above, especially the merge preview sections."
fi
exit "$ErrorCount"