if ! test -e alice.pgp -a -e bob.pgp
then
    echo "You seem to be in the wrong directory! (alice.pgp and bob.pgp not found)"
    exit 1
fi

export GNUPGHOME=$(pwd)/gpg
export SEQUOIA_CERT_STORE=$(pwd)/gpg/pubring.cert.d

if test -d gpg
then
    gpgconf --kill gpg-agent
    rm -rf gpg
    sleep 1
fi
mkdir gpg
chmod 700 gpg
for c in *.pgp
do
    gpg --import $c
done
sleep 1

# Remove old output.
rm -f *[0-9]-*.txt

# Initialize the git repository.
rm -rf frob
mkdir frob
cd frob
git init

# sq --overwrite key generate --name Bob --email bob@example.org --own-key  --without-password --expiration never --output bob.pgp --rev-cert /tmp/alice.rev
# vanity_gpg  -c ed25519 -j8 -u "Alice" -p "^A11CE"

alice_fpr=A11CECD86FB6050466E6259C7993A17BA8537B3D
bob_fpr=B0B50C2B8C3558D225A3310C1A8FAB5E378DD32D
carol_fpr=CA501F894EBD6193655CB77C476D56394D4E67DC

declare -A trust_roots

set -e

context() {
    name="$1"
    case "$name" in
	alice)
	    git config --local user.name "Alice"
	    git config --local user.email "alice@example.org"
	    git config --local gpg.gpgsign true
	    git config --local user.signingKey $alice_fpr
	    ;;
	bob)
	    git config --local user.name "Bob"
	    git config --local user.email "bob@example.org"
	    git config --local gpg.gpgsign true
	    git config --local user.signingKey $bob_fpr
	    ;;
	carol)
	    git config --local user.name "Carol"
	    git config --local user.email "carol@example.org"
	    git config --local gpg.gpgsign true
	    git config --local user.signingKey $carol_fpr
	    ;;
	dave)
	    git config --local user.name "Dave"
	    git config --local user.email "dave@some.org"
	    git config --local gpg.gpgsign false
	    git config --local --unset user.signingKey
	    ;;
	mallory)
	    git config --local user.name "Neal H. Walfield"
	    git config --local user.email "neal@sequoia-pgp.org"
	    if test -z "$neal_fpr"
	    then
		git config --local gpg.gpgsign false
		git config --local --unset user.signingKey || true
	    else
		git config --local gpg.gpgsign true
		git config --local user.signingKey "$neal_fpr"
	    fi
	    ;;
	*)
	    echo "\$1 should be the name"
	    exit 1
    esac

    trust_root=${trust_roots[$name]}
    if test -z "$trust_root"
    then
	git config --local --unset sequoia.trustRoot || true
    else
	git config --local sequoia.trustRoot "$trust_root"
    fi

    PS4="$name\$ "

    rm -f ~/.cache/sq-git.verification.cache
}

# The number of lines to add / delete with each commit.  We rotate
# them to add variety, but to keep the output stable.
declare -a add
declare -a delete
add=( 21 9 32 40 )
delete=( 7 12 6 )

emacs() {
    set +x
    filename="$1"
    if test -z "$filename"
    then
	echo filename not specified
	exit 1
    fi

    touch "$filename"
    if test "${delete[0]}" -gt 0
    then
	sed -i "1,${delete[0]}d" "$filename"
    fi
    { for i in $(seq ${add[0]}); do echo $RANDOM; done } >> "$filename"

    # Rotate
    add=( "${add[@]:1}" "${add[0]}" )
    delete=( "${delete[@]:1}" "${delete[0]}" )
    set -x
}

save() {
    filename="$1"
    # - Remove set +x from output.
    # - Remove stuttering due to PS4.
    # - If the --cert FINGERPRINT argument comes at the end of a line,
    #   wrap it.
    sed -e '/.*$ set +x/d' \
        -e 's/^\(.\)\1\+\(.*$ \)/\1\2/' \
        -e 's/^\(.\{33,\}\)\(--cert [0-9A-F]\{40\}\)/\1\\\n    \2/g' \
	| tee "$filename"
}

context "alice"
{
    set -x
    sq-git policy authorize alice --project-maintainer \
--cert $alice_fpr
    git add openpgp-policy.toml
    git commit -m "Add a signing policy."
} 2>&1 | save ../frob-10-alice-adds-a-signing-policy.txt

context "alice"
{
    set -x
    git config sequoia.trustRoot $(git rev-parse HEAD)
} 2>&1 | save ../frob-20-alice-sets-trust-root.txt

context "alice"
{
    set -x
    sq-git policy authorize bob --release-manager --cert $bob_fpr
    git add openpgp-policy.toml
    git commit -m "Authorize Bob to be a release manager."
} 2>&1 | save ../frob-30-alice-authorizes-bob.txt

context "alice"
{
    set -x
    sq-git log
} 2>&1 | save ../frob-40-alice-runs-git-log.txt

context "bob"
{
    set -x
    emacs main.rs
    git add main.rs
    git commit -m "Add a cool new feature."
    sq-git log --trust-root HEAD^
} 2>&1 | save ../frob-50-bob-adds-a-commit.txt

context "dave"
DAVE_ROOT=$(git rev-parse HEAD)
echo $DAVE_ROOT | save ../frob-55-dave-trust-root.txt
trust_roots["dave"]=$DAVE_ROOT
{
    set -x
    git log -n1
    git config sequoia.trustRoot $DAVE_ROOT
} 2>&1 | save ../frob-60-dave-sets-a-trust-root.txt

context "bob"
{
    set -x
    emacs main.rs
    git add main.rs
    git commit -m "Fix a corner case."
    emacs main.rs
    git add main.rs
    git commit -m "Add support for ACME's frob."
} 2>&1 | save ../frob-70-bob-adds-a-commit.txt

context "dave"
{
    set -x
    sq-git log
} 2>&1 | save ../frob-80-dave-checks.txt

context "carol"
{
    set -x
    git switch -c carol/vroom main
    emacs main.rs
    git add main.rs
    git commit -m "Use an O(log(n)) algorithm instead of one that takes O(n)."
} 2>&1 | save ../frob-90-carol-adds-a-commit.txt
CAROL_COMMIT=$(git rev-parse HEAD)
echo $CAROL_COMMIT | save ../frob-95-carol-commit-cherry-picked.txt

context "dave"
{
    set +e; set -x
    sq-git log
} 2>&1 | save ../frob-100-dave-checks-carols-commit.txt

context "carol"
{
    set -x
    git switch -c carol/make-carol-a-committer main
    sq-git policy authorize carol --committer --cert $carol_fpr
    git add openpgp-policy.toml
    git commit -m "Authorize Carol to be a committer."
    git cherry-pick $CAROL_COMMIT
    sq-git log --trust-root HEAD^
} 2>&1 | save ../frob-110-carol-adds-herself-to-the-policy.txt

context "dave"
{
    set +e; set -x
    sq-git log
} 2>&1 | save ../frob-120-dave-checks-carols-new-commits.txt

git checkout main
context "bob"
{
    set +e; set -x
    git merge --no-ff carol/vroom -m "Merge Carol's change"
} 2>&1 | save ../frob-130-bob-merges-carols-commit.txt

context "bob"
{
    set +e; set -x
    git log --decorate --pretty=short --graph
} 2>&1 | save ../frob-140-git-log.txt

context "dave"
{
    set +e; set -x
    sq-git log
} 2>&1 | save ../frob-150-dave-checks-merge-commit.txt

context "bob"
{
    set +e; set -x
    git reset --hard $CAROL_COMMIT
    git commit --amend --allow-empty --reuse-message=HEAD
} 2>&1 | save ../frob-160-bob-signs-carols-commit.txt

context "dave"
{
    set +e; set -x
    git log -n1
    sq-git log
} 2>&1 | save ../frob-170-dave-checks-resign.txt




# Introduction.

cd ..
rm -rf intro
mkdir intro
cd intro
git init

context "mallory"
{
    set -x
    sq key generate --userid 'Neal H. Walfield <neal@sequoia-pgp.org>' --own-key --without-password
} 2>&1 \
 | awk 'BEGIN { suppress = 0 }
        /^Transferable Secret Key./ { print "..."; suppress = 1; exit }
        { if (suppress == 0) { print } }
        /^[a-z]+$/ { suppress = 0; }' \
 | save ../intro-10-neal-cert.txt
# Truncate sq key generate

neal_fpr=$(sq cert list neal@sequoia-pgp.org | awk -F-\  '/^ - [0-9A-F]{40,}/ { print $2 }')
if test -z "$neal_fpr"
then
    echo Failed to extract fingerprint.
    exit 1
fi

sq key export --cert "$neal_fpr" | gpg --import
sleep 1
sq pki link retract --cert "$neal_fpr" --all

context "mallory"
{
    set -x
    emacs main.rs
    git add main.rs
    git commit -m "Clean up the code."
} 2>&1 | save ../intro-20-neal-commit.txt

context "alice"
{
    set -x
    git log -n1 --pretty=short --show-signature
} 2>&1 | save ../intro-30-git-log.txt

# Stabilize the output.
cd ..

rewrite_commits() {
    prefix=$1
    if test -z "$prefix"
    then
	echo "No prefix"
	exit 1
    fi

    shift
    files=$@
    if test -z "$files"
    then
	echo "No files"
	exit 1
    fi

    got_all=$(sed -n -E '
      # .* matches greedily so we need to be careful.  The following loop
      # surrounds the last commit hash on the current line (before the first
      # \n in the pattern space) with \ns.  If it made a substitution, it
      # loops.
      :split
        s/^([^\n]*)(\b[0-9a-f]{40}\b)/\1\n\2\n/;
        t split;

      # If the pattern space is a commit hash, print it.  Otherwise, remove
      # everything up to and including the first new line character.  If
      # the pattern space is not empty, repeast.
      :print
        /^[0-9a-f]{40}/ P;
        s/^[^\n]*(\n|$)//;
        /./ b print
      ' $files)

    echo $got_all

    # We want to dedup, but if we do sort | uniq, then the order is not
    # preserved.
    declare -a got
    declare -A dedup
    for commit in $got_all
    do
	if ! test -z "${dedup[$commit]}"
	then
	    continue
	fi

	dedup[$commit]=1
	got+=( "$commit" )
    done

    commit_i=1
    subs=""
    for c in ${got[@]}
    do
	commit="$prefix$(printf '%03d%040d' $commit_i 0)";
	let commit_i+=1
	echo "$c -> $commit"
	for i in $(seq 7 40)
	do
	    subs+="s/\b${c:0:$i}\b/${commit:0:$i}/g;"
	done
    done

    sed -E -e "${subs}" -i $files
}

# Use a one letter prefix for each scenario.  Make sure the files are
# listed in order so that the commits are ordered correctly.
rewrite_commits a $(ls -1 intro-??-*.txt | sort)
rewrite_commits b $(ls -1 frob-??-*.txt | sort) $(ls -1 frob-???-*.txt | sort)
