#!/usr/bin/env bash set -u [ -z "$2" ] && { echo "Usage: $0 path/to/xcodeproj target1 target2 ..." echo "The script will verify that all listed targets have the exact same set of files and resources." echo "Tested with Xcode 9.1" } PBXFILE="$1/project.pbxproj" shift hasParameter() { P="$1" shift for i in "$@" ; do if [[ $i == "$P" ]] ; then return 0 fi done return 1 } awk ' /isa = PBXNativeTarget/ { targetName=maybeTargetName; next; } /buildPhases = \(/ { inBuildPhases=1; targetFileGroups=""; next; } inBuildPhases { if ($1 == ");") { inBuildPhases=0; print targetName targetFileGroups; } else { if ($3 == "Sources" || $3 == "Resources") { targetFileGroups = targetFileGroups " " $1; } } } { maybeTargetName=$3; } ' "$PBXFILE" | ( REFERENCE_TARGET= REFERENCE_FILES= FOUND_DIFF=0 while read -r TARGET do TARGET_NAME="${TARGET%% *}" if ! hasParameter "$TARGET_NAME" "$@" then continue fi FILES="$( for HEX in ${TARGET#* } do awk ' /isa = (PBXSourcesBuildPhase|PBXResourcesBuildPhase)/ && maybeHex == "'$HEX'" { found=1; next; } found && /files = \(/ { inFiles=1; next; } inFiles { if ($1 == ");") { found=0; inFiles=0; } else { split($0, parts, "[*]"); print substr(parts[2], 2, length(parts[2])-2); } } { maybeHex=$1; } ' "$PBXFILE" done | sort)" if [ -z "$REFERENCE_FILES" ] then REFERENCE_TARGET="$TARGET_NAME" REFERENCE_FILES="$FILES" else DIFF="$(diff <(echo "$REFERENCE_FILES") <(echo "$FILES"))" if [ -n "$DIFF" ] then if [ "$FOUND_DIFF" = "0" ] then echo >&2 echo "Some files are not added to all of these targets: $@" >&2 echo >&2 fi FOUND_DIFF=1 echo "Diff between the file list of $REFERENCE_TARGET and $TARGET_NAME" >&2 echo "$DIFF" >&2 echo >&2 fi fi done exit $FOUND_DIFF )