#!/bin/bash
#
# Generates compiler id and repo schema symbols in a .cpp file and
# header.  The compiler id cpp files goes on every link line (see
# .fbconfig), but that no build rules have a dependency on it (we're
# ok not relinking it in some cases).
#
# The repo schema goes in a header that is only touched if its
# contents would've changed.
#

unset CDPATH
DIR="$( cd "$( dirname "$0" )" && pwd )"

# OSS version depends on this fallback since it's obviously not using fbmake.
if [ x"$FBMAKE_PRE_COMMAND_OUTDIR" = x"" ]; then
  BUILD_DIR="$DIR/../"
else
  # Should be in /some/path/hphp/util/, so chop off the hphp/util.
  BUILD_DIR="$DIR/../../$FBMAKE_PRE_COMMAND_OUTDIR"
fi

BUILDINFO_FILE="$BUILD_DIR/hphp-build-info.cpp"
REPO_SCHEMA_H="$BUILD_DIR/hphp-repo-schema.h"

if git rev-parse --show-toplevel >& /dev/null; then
    scm=git
    root=$(git rev-parse --show-toplevel)
    compiler="git describe --all --long --abbrev=40 --always"
    find_files="git ls-files -- hphp"
    alias scm_update='git fetch origin && git rebase origin/master'
else
    if hg root >& /dev/null; then
        scm=hg
        root=$(hg root)
        if [ -f "$root/fbcode/.projectid" ]; then
          root="$root/fbcode"
        fi
        compiler="hg log -r . --template '{branch}-0-g{gitnode}' 2> /dev/null"
        compiler="$compiler || hg log -r . --template '{branch}-0-h{node}'"
        find_files="hg files -I hphp/"
        alias scm_update='hg pull && hg rebase -d master'
    else
        scm=""
        root=$DIR/../../
        find_files='find hphp \( -type f -o -type l \) \! -iregex ".*\(~\|#.*\|\.swp\|/tags\|/.bash_history\|/out\)" | sort'
    fi
fi

cd $root

######################################################################

# First check if they configured anything hphp-related.  If not, skip
# this stuff, because these commands take upwards of .5s.
if [ -d $root/.fbbuild ]; then
  if cat $root/.fbbuild/generated/info 2>/dev/null \
    | grep fbconfig_argv \
    | grep -v hphp >/dev/null 2>&1 ; then
    exit 0
  fi
fi


######################################################################

if [ x"$COMPILER_ID" = x"" ]; then
  if [ -n "$scm" ]; then
    COMPILER_ID=$(sh -c "$compiler")
  else
    # Building outside of a git repo, use system time instead.
    # This will make the sha appear to change constantly,
    # but without any insight into file state, it's the safest fallback
    COMPILER_ID=$(date +%s_%N)
  fi
fi

# Compute a hash that can be used as a unique repo schema identifier.  The
# identifier incorporates the current git revision and local modifications to
# managed files, but it intentionally ignores unmanaged files (even though they
# could conceivably contain source code that meaningfully changes the repo
# schema), because for some work flows the added instability of schema IDs is a
# cure worse than the disease.
if [ x"$HHVM_REPO_SCHEMA" = x"" ] ; then
  HHVM_REPO_SCHEMA=$(sh -c "$find_files" | \
      grep -v '^hphp/\(benchmarks\|bin\|hack\|hphp\|neo\|public_tld\|test\|tools\|util\|vixl\|zend\)' | \
      tr '\n' '\0' | xargs -0 cat | sha1sum | cut -b-40)
fi

######################################################################

# Generate header files that contains the repo schema, but only write
# to them if the values have changed. This way, source files can
# depend on the headers and get rebuilt as necessary.
function make_define_header() {
  local t
  t=`mktemp -t hhvm_mk.hXXXXXX || exit 1`
  echo "#define $2 \"$3\"" > $t
  mkdir -p $(dirname $1)
  if test -f "$1" ; then
    diff $t $1 >/dev/null 2>&1 || cp $t $1
  else
    cp $t $1
  fi
  rm -f $t
}

######################################################################

make_define_header $REPO_SCHEMA_H REPO_SCHEMA $HHVM_REPO_SCHEMA

cat > $BUILDINFO_FILE <<EOF
// Generated by fbmake_pre_command for hphp.
namespace HPHP {
extern const char* const kCompilerId = "$COMPILER_ID";
}
EOF
