Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mac compatibility: Avoid PCRE grep in recon-surf, stat formatting and mapfile #672

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion brun_fastsurfer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ function warn_old()
echo " use --parallel <n>, --parallel_seg <n>, or --parallel_surf <n>!"
}

function fail_bash_version_lt4()
{
if [[ ! "$(bash --version | head -n 1)" =~ [vV]ersion[[:space:]][4-9] ]]
then
echo "ERROR: The brun_fastsurfer script requires at minimum bash version 4 for the options --subject_list and"
echo " subjects via stdin. Specifying a specific number of concurrent processes (--parallel <num>,"
echo " --parallel_seg <num>, --parallel_surf <num>; num is a positive integer) also requires bash 4+."
exit 1
fi
}

# PARSE Command line
inputargs=("$@")
POSITIONAL=()
Expand All @@ -144,6 +155,7 @@ case $key in
# parse/get the subjects to iterate over
#===================================================
--subject_list|--subjects_list)
fail_bash_version_lt4
if [[ ! -f "$1" ]]
then
echo "ERROR: Could not find the subject list $1!"
Expand Down Expand Up @@ -273,6 +285,7 @@ else
fi
if [[ "$subjects_stdin" == "true" ]]
then
fail_bash_version_lt4
if [[ -t 0 ]] || [[ "$debug" == "true" ]]; then
echo "Reading subjects from stdin, press Ctrl-D to end input (one subject per line)"
fi
Expand Down Expand Up @@ -546,6 +559,7 @@ function process_by_token()
# check job count
if [[ "$max_processes" == "max" ]] ; then spawn_task=1
else
fail_bash_version_lt4
mapfile -t running_jobs < <(jobs -pr)
if [[ "${#running_jobs[@]}" -lt "$max_processes" ]] ; then spawn_task=1
elif [[ "$read_in" == 0 ]] ; then wait "${running_jobs[@]}" # wait for any task to finish (std is already closed)
Expand Down Expand Up @@ -611,7 +625,9 @@ function process_by_token()
fi
fi
done
mapfile -t running_jobs < <(jobs -pr)
if [[ "$(bash --version | head -n 1)" =~ [vV]ersion[[:space:]][4-9] ]] ; then mapfile -t running_jobs < <(jobs -pr)
else running_jobs=()
fi
# wait for jobs to finish
if [[ "$debug" == "true" ]]
then
Expand Down Expand Up @@ -642,11 +658,13 @@ if [[ "$parallel_pipelines" == 1 ]] ; then
if [[ "$seg_only" == "true" ]] ; then mode=seg
elif [[ "$surf_only" == "true" ]] ; then mode=surf
fi
if [[ "$num_parallel_seg" != "max" ]] ; then fail_bash_version_lt4 ; fi
iterate_subjects_with_token "${iterate_subjects_with_token_args[@]}" | \
process_by_token "$mode" "${process_by_token_args[@]}" | \
filter_token
else
# multiple pipelines
if [[ "$num_parallel_seg" != "max" ]] || [[ "$num_parallel_surf" != "max" ]] ; then fail_bash_version_lt4 ; fi
iterate_subjects_with_token "${iterate_subjects_with_token_args[@]}" | \
process_by_token "seg" "${process_by_token_args[@]}" | \
process_by_token "surf" "${process_by_token_args[@]}" | \
Expand Down
15 changes: 1 addition & 14 deletions long_fastsurfer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -223,20 +223,7 @@ if [ "${#tpids[@]}" -ne "${#t1s[@]}" ]
fi

# check that SUBJECTS_DIR exists
if [[ -z "${sd}" ]]
then
echo "ERROR: No subject directory defined via --sd. This is required!"
exit 1
elif [[ ! -d "${sd}" ]]
then
echo "INFO: The subject directory did not exist, creating it now."
if ! mkdir -p "$sd" ; then echo "ERROR: directory creation failed" ; exit 1; fi
elif [[ "$(stat -c "%u:%g" "$sd")" == "0:0" ]] && [[ "$(id -u)" != "0" ]] && [[ "$(stat -c "%a" "$sd" | tail -c 2)" -lt 6 ]]
then
echo "ERROR: The subject directory ($sd) is owned by root and is not writable. FastSurfer cannot write results! "
echo " This can happen if the directory is created by docker. Make sure to create the directory before invoking docker!"
exit 1
fi
check_create_subjects_dir_properties "$sd"

if [[ -z "$LF" ]] ; then LF="$sd/$tid/scripts/long_fastsurfer.log" ; fi
# make sure the directory for the logfile exists, create automatically if the directory is not in $sd
Expand Down
47 changes: 36 additions & 11 deletions recon_surf/functions.sh
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@

# set the binpath variable
if [ -z "$FASTSURFER_HOME" ]
then
binpath="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )/"
else
binpath="$FASTSURFER_HOME/recon_surf/"
if [[ -z "$FASTSURFER_HOME" ]] ; then binpath="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )/"
else binpath="$FASTSURFER_HOME/recon_surf/"
fi
export binpath

# fs_time command from fs60, fs72 fails in parallel mode, use local one
# also check for failure (e.g. on mac it fails)
timecmd="${binpath}fs_time"
$timecmd echo testing &> /dev/null
if [ "${PIPESTATUS[0]}" -ne 0 ] ; then
echo "time command failing, not using time..."
timecmd=""
# also check for failure (e.g. on mac it fails, so we cannot use it there)
if FSTIME_LOAD=0 "${binpath}fs_time" echo testing &> /dev/null ; then timecmd="${binpath}fs_time"
else timecmd="" ; echo "INFO: Testing fs_time was not successful, not reporting per-command runtimes."
fi
export timecmd
export LC_NUMERIC="en_US.UTF-8"

function check_create_subjects_dir_properties()
{
# 1: subjects_dir
if [[ -z "$1" ]]
then
echo "ERROR: No subject directory defined via --sd. This is required!"
exit 1
elif [[ ! -d "$1" ]]
then
echo "INFO: The subject directory did not exist, creating it now."
if [[ "$(id -u)" == 0 ]] ; then echo "WARNING: Creating as root!" ; fi
if ! mkdir -p "$1" ; then echo "ERROR: directory creation failed" ; exit 1; fi
else
if stat --version > /dev/null 2> /dev/null ; then # linux (GNU version of stat, supports --version)
user_group=$(stat -c "%u:%g" "$1")
world_access=$(stat -c "%a" "$1" | tail -c 2)
else # macOS (BSD version of stat)
user_group=$(stat -f "%u:%g" "$1")
world_access=$(stat -f "%p" "$1" | tail -c 2)
fi
if [[ "$user_group" == "0:0" ]] && [[ "$(id -u)" != "0" ]] && [[ "$world_access" -lt 6 ]]
then
echo "ERROR: The subject directory ($1) is owned by root and is not writable."
echo " FastSurfer cannot write results! This can happen if the directory is created"
echo " by docker. Make sure to create the directory before invoking docker!"
exit 1
fi
fi
}

function RunIt()
{
Expand Down
20 changes: 1 addition & 19 deletions recon_surf/long_prepare_template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -220,25 +220,7 @@ then
fi

# check that SUBJECTS_DIR exists
if [[ -z "$SUBJECTS_DIR" ]]
then
echo "ERROR: No subject directory defined via --sd. This is required!"
exit 1;
fi
if [[ ! -d "${sd}" ]]
then
echo "INFO: The subject directory did not exist, creating it now."
if ! mkdir -p "$SUBJECTS_DIR" ; then echo "ERROR: directory creation failed" ; exit 1; fi
fi
if [[ "$(stat -c "%u:%g" "$SUBJECTS_DIR")" == "0:0" ]] && [[ "$(id -u)" != "0" ]] && \
[[ "$(stat -c "%a" "$SUBJECTS_DIR" | tail -c 2)" -lt 6 ]]
then
echo "ERROR: The subject directory ($SUBJECTS_DIR) is owned by root and is not writable."
echo " FastSurfer cannot write results! This can happen if the directory is created by"
echo " docker. Make sure to create the directory before invoking docker!"
exit 1;
fi

check_create_subjects_dir_properties "$SUBJECTS_DIR"

################################## SETUP and LOGFILE ##############################

Expand Down
6 changes: 4 additions & 2 deletions recon_surf/recon-surf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,9 @@ cmd="$python $FASTSURFER_HOME/FastSurferCNN/data_loader/conform.py -i $t1 --chec
RunIt "$cmd" "$LF"

# look into the CONFORM_LF to find the voxel sizes, the second conform.py call will check the legality of vox_size
vox_size=$(grep -oP '(?<= - Voxel Size )[0-9\.]+' "$CONFORM_LF")
vox_size_prefix=" - Voxel Size"
vox_size=$(grep -oE "${vox_size_prefix} [0-9.]+" "$CONFORM_LF")
vox_size="${vox_size:${#vox_size_prefix}}"
# remove the temporary conform_log (all info is also in the recon-surf logfile)
if [ -f "$CONFORM_LF" ]; then rm -f "$CONFORM_LF" ; fi

Expand Down Expand Up @@ -1400,7 +1402,7 @@ fi # not base run
# Collect info
EndTime=$(date)
tSecEnd=$(date '+%s')
tRunHours=$(printf %6.3f "$(bc <<< "($tSecEnd - $tSecStart) / 3600")")
tRunHours=$(LC_NUMERIC="en_US.UTF-8" printf %6.3f "$(bc -l <<< "($tSecEnd - $tSecStart) / 3600")")

{
echo ""
Expand Down
63 changes: 25 additions & 38 deletions run_fastsurfer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -563,24 +563,7 @@ if [[ "$legacy_parallel_hemi" == 1 ]] ; then
fi
fi

if [[ -z "${sd}" ]]
then
echo "ERROR: No subject directory defined via --sd. This is required!"
exit 1
fi
if [[ ! -d "${sd}" ]]
then
echo "INFO: The subject directory did not exist, creating it now." | tee -a "$tmpLF"
if ! mkdir -p "$sd" ; then echo "ERROR: Subject directory creation failed" ; exit 1 ; fi
fi
if [[ "$(stat -c "%u:%g" "$sd")" == "0:0" ]] && [[ "$(id -u)" != "0" ]] && \
[[ "$(stat -c "%a" "$sd" | tail -c 2)" -lt 6 ]]
then
echo "ERROR: The subject directory ($sd) is owned by root and is not writable."
echo " FastSurfer cannot write results! This can happen if the directory is created"
echo " by docker. Make sure to create the directory before invoking docker!"
exit 1
fi
check_create_subjects_dir_properties "$sd"

if [[ -z "$subject" ]]
then
Expand Down Expand Up @@ -828,26 +811,30 @@ then
} | tee -a "$seg_log"
fi

pushd "${sd}/${subject}" > /dev/null || { echo "Could not access ${sd}/${subject}!" ; exit 1 ; }
function filter_log_build()
{
# filter expected files $LF and scripts/BUILD.log
IFS=""
while read -r file ; do
if [[ "${sd}/${subject}/${file:2}" != "$seg_log" ]] && [[ "$file" != "./scripts/BUILD.log" ]] ; then echo "$file" ; fi
done
}

mapfile -t content_of_subject_dir < <(find "." -type f | filter_log_build)
popd > /dev/null || exit 1
if [[ "${#content_of_subject_dir[@]}" -gt 1 ]] ; then
if [[ "$edits" == "true" ]] ; then LABEL="INFO" ; else LABEL="WARNING" ; fi
{
echo "$LABEL: Found ${#content_of_subject_dir[@]} files in subject directory \$SUBJECTS_DIR/$subject:"
files=("${content_of_subject_dir[@]:0:6}")
if [[ "${#content_of_subject_dir[@]}" -gt 6 ]] ; then files+=("...") ; fi
echo " Potentially Overwriting: ${files[*]}"
} | tee -a "$seg_log"
# mapfile builtin requires bash 4 (BASH_VERSINFO is available in bash 3)
if [[ "${BASH_VERSINFO[0]}" -gt 3 ]]
then
pushd "${sd}/${subject}" > /dev/null || { echo "Could not access ${sd}/${subject}!" ; exit 1 ; }
function filter_log_build()
{
# filter expected files $LF and scripts/BUILD.log
IFS=""
while read -r file ; do
if [[ "${sd}/${subject}/${file:2}" != "$seg_log" ]] && [[ "$file" != "./scripts/BUILD.log" ]] ; then echo "$file" ; fi
done
}

mapfile -t content_of_subject_dir < <(find "." -type f | filter_log_build)
popd > /dev/null || exit 1
if [[ "${#content_of_subject_dir[@]}" -gt 1 ]] ; then
if [[ "$edits" == "true" ]] ; then LABEL="INFO" ; else LABEL="WARNING" ; fi
{
echo "$LABEL: Found ${#content_of_subject_dir[@]} files in subject directory \$SUBJECTS_DIR/$subject:"
files=("${content_of_subject_dir[@]:0:6}")
if [[ "${#content_of_subject_dir[@]}" -gt 6 ]] ; then files+=("...") ; fi
echo " Potentially Overwriting: ${files[*]}"
} | tee -a "$seg_log"
fi
fi

asegdkt_segfile_manedit=$(add_file_suffix "$asegdkt_segfile" "manedit")
Expand Down
1 change: 1 addition & 0 deletions srun_fastsurfer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ do
fi
done
debugf "$newline\n"
# the following stat command is not compatible with macOS, but srun_fastsurfer is not expected to be
shell=$(stat -c %N "/proc/$$/exe" | cut -d">" -f2 | tail -c +3 | head -c -2)
debug "Running in shell $shell: $($shell --version 2>/dev/null | head -n 1)"
debug ""
Expand Down