Last active
October 13, 2015 03:58
-
-
Save ichramm/4136319 to your computer and use it in GitHub Desktop.
longclaw: dependency-based personal builder (runs a DFS in the dependency-tree)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Smart builder for inConcert... ... ... ... | |
# | |
set -e | |
function info() | |
{ | |
[[ -n "$TERM" && "$TERM" != "dumb" ]] && echo -e "$(tput setaf 2)$@$(tput sgr0)" || echo -e "$@"; | |
} | |
function warn() | |
{ | |
[[ -n "$TERM" && "$TERM" != "dumb" ]] && echo -e "$(tput bold)$(tput setaf 3)$@$(tput sgr0)" || echo -e "WARN: $@"; | |
} | |
function error() | |
{ | |
[[ -n "$TERM" && "$TERM" != "dumb" ]] && echo -e "$(tput bold)$(tput setaf 1)$@$(tput sgr0)" || echo -e "ERROR: $@"; | |
} | |
# maps a project with its root directory | |
# base hash for iteration | |
declare -A map_projects | |
#map of dependencies by project name | |
declare -A map_dependencies | |
declare -A map_descriptions | |
declare -A map_makedirs | |
declare -A map_maketargets | |
declare -A map_cmdbefore | |
declare -A map_cmdafter | |
# marks projects as visited (like a DFS) | |
declare -A map_visited | |
this_dir=$(dirname `readlink -f $0`); | |
config_dir=$this_dir/config; | |
# check if INCONCERT_DEVEL is set | |
if [ -z "$INCONCERT_DEVEL" ]; | |
then | |
warn "Environment variable INCONCERT_DEVEL is not set"; | |
TEMP=$(readlink -f "$this_dir/../../"); | |
warn "Setting INCONCERT_DEVEL to '$TEMP'"; | |
export INCONCERT_DEVEL=$TEMP; | |
fi | |
# enable parallel compiling | |
if [[ -z "$MAKEOPTS" || "$MAKEOPTS" != *-j* ]]; | |
then | |
cpu_cores=$(cat /proc/cpuinfo | grep "cpu cores" | head -1 | cut --delimiter=':' -f2); | |
if [ -n "$cpu_cores" -a "$cpu_cores" -eq "$cpu_cores" 2> /dev/null ]; then | |
((cpu_cores=cpu_cores+1)); | |
else | |
cpu_cores=$(cat /proc/cpuinfo | grep processor | wc -l); | |
fi | |
MAKEOPTS="$MAKEOPTS -j$cpu_cores"; | |
warn "Updating variable MAKEOPTS to: [$MAKEOPTS]"; | |
fi | |
export INCONCERT_SOURCES="$INCONCERT_DEVEL/sources" | |
export MAKEGTARGET="$MAKE_TARGET" | |
info "Reading directory $config_dir..."; | |
for file in $config_dir/*.cfg; | |
do | |
# cleanup the environment first | |
unset PROJECT_NAME; | |
unset PROJECT_DESC; | |
unset USES; | |
unset ROOT_DIR; | |
unset MAKE_DIRS; | |
unset MAKE_TARGET | |
unset BEFORE_BUILD; | |
unset AFTER_BUILD; | |
info " - Loading build file $file"; | |
file_name=$(basename $file .cfg); | |
source $file; | |
# read project name or fallback to filename (without extension) | |
[[ -z "$PROJECT_NAME" ]] && warn "PROJECT_NAME is not set, falling back to $file_name" && PROJECT_NAME=$file_name; | |
# read project description (or fallback to project name when compiling) | |
[[ -z "$PROJECT_DESC" ]] && warn "PROJECT_DESC is not set, will fall back to $PROJECT_NAME" || map_descriptions[$PROJECT_NAME]="$PROJECT_DESC"; | |
# read root directory or fallback to project name, will setup the key on the main map (the one used for transversing) | |
[[ -z "$ROOT_DIR" ]] && warn "ROOT_DIR is not set, falling back to $PROJECT_NAME" && ROOT_DIR=$PROJECT_NAME; | |
map_projects[$PROJECT_NAME]="$ROOT_DIR"; | |
# setup make directories, if empty will fallback to '.' | |
[[ -n "$MAKE_DIRS" ]] && map_makedirs[$PROJECT_NAME]="$MAKE_DIRS"; | |
[[ -n "$MAKE_TARGET" ]] && map_maketargets[$PROJECT_NAME]="$MAKE_TARGET"; | |
# read and set dependencies | |
if [ -n "$USES" ]; then | |
info " -- Dependencies for $PROJECT_NAME: $USES"; | |
map_dependencies[$PROJECT_NAME]="$USES"; | |
else | |
info " -- $PROJECT_NAME has no dependencies"; | |
fi | |
# read and set before build commands | |
[[ -n "$BEFORE_BUILD" ]] && map_cmdbefore[$PROJECT_NAME]="$BEFORE_BUILD"; | |
#read and set after build commands | |
[[ -n "$AFTER_BUILD" ]] && map_cmdafter[$PROJECT_NAME]="$AFTER_BUILD"; | |
done | |
function build_project_impl() | |
{ | |
local project_name=$1; | |
local root_dir=$2 | |
local current_target=""; | |
current_dir=`pwd`; | |
cd "$INCONCERT_SOURCES/$root_dir"; | |
info " Working on directory: `pwd`"; | |
if [ "$LONGCLAW_RUN_COMMANDS" != "no" -a -n "${map_cmdbefore["$project_name"]}" ]; then | |
CMDLINE="${map_cmdbefore["$project_name"]}"; | |
warn " Running before-build commands: $CMDLINE"; | |
# run bash -c to avoid problems | |
bash -c "$CMDLINE"; | |
fi; | |
[[ -n "${map_makedirs["$project_name"]}" ]] && makedirs=${map_makedirs["$project_name"]} || makedirs="."; | |
for make_dir in $makedirs; | |
do | |
if [ -n "$MAKEGTARGET" ]; then | |
set +e | |
current_target=$(make -C $make_dir -pn | grep "$MAKEGTARGET:"); | |
set -e | |
if [ -z "$current_target" ]; then | |
warn "Makefile '$root_dir/$make_dir' does not have target $MAKEGTARGET"; | |
else | |
current_target="$MAKEGTARGET"; | |
fi | |
fi | |
if [ -z "$current_target" ]; then | |
current_target="${map_maketargets["$project_name"]}"; | |
fi | |
if [ -n "$CONFIGURATION" ]; then | |
export Target=$CONFIGURATION; | |
else | |
export Target=Debug; | |
info " Running make Debug on directory $make_dir"; | |
make $MAKEOPTS -C $make_dir $current_target; | |
export Target=Release; | |
fi | |
info " Running make $Target on directory $make_dir"; | |
make $MAKEOPTS -C $make_dir $current_target; | |
done | |
if [ "$LONGCLAW_RUN_COMMANDS" != "no" -a -n "${map_cmdafter["$project_name"]}" ]; then | |
CMDLINE="${map_cmdafter["$project_name"]}"; | |
warn " Running post-build commands: $CMDLINE"; | |
# run bash -c to avoid problems | |
bash -c "$CMDLINE"; | |
fi; | |
unset Target; | |
cd $current_dir; | |
} | |
function build_project() | |
{ | |
local project_name=$1; | |
local root_dir="${map_projects["$project_name"]}" | |
local project_desc; | |
[[ -n "${map_descriptions["$project_name"]}" ]] && project_desc=${map_descriptions["$project_name"]} || project_desc=$project_name; | |
info "Building project '$project_desc'"; | |
# mark this project as visited | |
map_visited[$project_name]="1"; | |
if [ -n "${map_dependencies["$project_name"]}" ]; then | |
for depend in ${map_dependencies["$project_name"]}; do | |
if [ -z "${map_visited["$depend"]}" ]; then | |
build_project $depend; | |
fi | |
done | |
fi; | |
info "Really building project '$project_desc'"; | |
build_project_impl "$project_name" "$root_dir" | |
} | |
info "Starting build process..."; | |
if [ -n "$1" ]; then | |
[[ -z "${map_projects["$1"]}" ]] && error "Project $1 not found" && exit 1; | |
build_project $1; | |
else | |
for project in ${!map_projects[@]}; do | |
if [ -z "${map_visited["$project"]}" ]; then | |
build_project $project; | |
fi | |
done | |
fi | |
info "\nDone!"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment