#!/bin/sh
# Merge two app bundle directories into a single universal bundle.

# prevent cd from using $CDPATH and printing directory when it does
unset CDPATH

abort() {
    echo "$@" >&2
    exit 1
}

test $# -eq 3 || abort "usage: $0 src1 src2 dst"

src1="$1"
src2="$2"
dst="$3"

arches="arm64 x86_64"

mkdir -p "$dst"
rm -r "$dst"/*

for f in $(cd "$src1"; find . -name _CodeSignature -prune -o -print); do
    if test -L "$src1/$f"; then
        echo "# copy symlink: $f"
        test -L "$src2/$f" || abort "No match for $f in $src2"
        cp -a "$src1/$f" "$dst/$f" || abort
        continue
    elif test -d "$src1/$f"; then
        echo "# copy directory: $f"
        test -d "$src2/$f" || abort "No match for $f in $src2"
        mkdir -p "$dst/$f" || abort
        continue
    fi

    # normal file
    test -f "$src2/$f" || abort "No match for $f in $src2"
    type=$(file -h "$src1/$f")
    if echo "$type" | egrep -q 'Mach-O .* executable'; then
        echo "# merge executable: $f";
    elif echo "$type" | egrep -q 'Mach-O .* bundle'; then
        echo "# merge bundle: $f";
    elif echo "$type" | egrep -q 'dynamically linked shared library'; then
        echo "# merge shared lib: $f";
    elif echo "$type" | egrep -q 'ASCII text'; then
        echo "# copy text file: $f";
        cp -a "$src1/$f" "$dst/$f.__1" || abort
        cp -a "$src2/$f" "$dst/$f.__2" || abort
        sed -E -e "s;$src1;$dst;g" "$src1/$f" > "$dst/$f.__1" || abort
        sed -E -e "s;$src2;$dst;g" "$src2/$f" > "$dst/$f.__2" || abort
        diff -U3 "$dst/$f.__1" "$dst/$f.__2" || echo "WARNING: $f differs between sources"
        rm "$dst/$f.__2"
        mv "$dst/$f.__1" "$dst/$f"
        continue
    else
        echo "# copy other file: $f";
        cmp "$src1/$f" "$src2/$f" || abort "$f differs between sources"
        cp -a "$src1/$f" "$dst/$f" || abort
        continue
    fi

    # If one of the files is already universal, just copy it
    for file in "$src1/$f" "$src2/$f"; do
        if lipo "$file" -verify_arch $arches; then
            echo "  $file is already universal; copying"
            cp -a "$file" "$dst/$f"
            continue 2
        fi
    done

    # otherwise, merge them
    lipo -create "$src1/$f" "$src2/$f" -output "$dst/$f" || abort
    lipo "$dst/$f" -verify_arch $arches || abort "$dst/$f does not contain all of: $arches"
done
