<commit_before>#! /bin/bash
# Starting cwd is base of operations.
# TODO: Check to be sure it seems to contain the package.
Basedir=$PWD
# Make sure we have an unmodified git we can use to clone source repos.
Sys_git=/usr/bin/git
# This will be detected and set in detect_cac_card.
Card_id=
# Facilitate skipping install step when --no-install specified
Make_install="make install"

declare -i Step_idx=0
declare -A Skip_steps=()
# These are tied to the --start-step / --end-step options
Start_step=
End_step=

# TODO: Consider adding defaults for all... For now, missing options assumed to be unset.
declare -A Opts=(
	[ca-bundle-dir]=/usr/ssl/certs
	[ca-bundle-name]=ca-bundle-plus-dod-root
	[openssl-conf]=/usr/ssl/pkcs11-openssl.cnf
)

declare -a Steps=(
	install_cyg_pkg
	download_source
	build_opensc
	create_certs
	build_curl
	configure_openssl_conf
	build_git
	install_env_script
)

on_exit() {
	if (($? == 0)); then
		echo "Success!"
	else
		echo "Setup aborted with error! Check stdout for details."
		echo "After resolving any issues, resume setup by running ./setup -s ${Steps[$Step_idx]}"
	fi
	cd "$Basedir"
}

# Run all steps, starting with the first (or the one specified by --start-step), and ending with the last (or the one
# specified with --end-step), skipping any specified by options such as --skip-step.
run() {
	if [[ -n "$Start_step" ]]; then started=no; else started=yes; fi
	for step in "${Steps[@]}"; do
		if [[ $started == no && $step == $Start_step ]]; then
			started=yes
		fi
		# If we've passed start step (or none given) and we're not skipping...
		if [[ $started == yes && -z ${Skip_steps[$step]} ]]; then
			log "Starting step #$((Step_idx + 1)): $step"
			${Opts[no-execute]:+echo Simulating step} $step
			log "Finished step #$((Step_idx + 1)): $step"
		fi
		if [[ -n $End_step && $step == $End_step ]]; then
			log "Exiting due to --end-step '$End_step'"
			((++Step_idx))
			exit 0
		fi
		((++Step_idx))
	done
}

# TODO: Colorize?
log() {
	echo >&2 "$@" 
}
usage() {
	echo >&2 "Usage: ./setup.sh blah blah"
}
error() {
	usage=no
	if [[ "$1" == "--usage" ]]; then
		usage=yes
		shift
	fi
	echo 2>&1 "$@"
	if [[ $usage == yes ]]; then
		usage
	fi
	# TODO: Consider adding an error code option.
	exit 1
}

process_opt() {
	# TODO: Consider a different way, which would handle defaults.
	# TODO: Perhaps put these in array, at least...
	longs=(
		start-step: end-step: skip-step:
		ca-bundle-dir: ca-bundle-name: openssl-conf:
		skip-cygwin-install no-install no-execute)
	# getopt idiosyncrasy: 1st arg specified to a long opt intended to be used to build an array can lose the 1st arg if
	# there no short opts are specified (e.g., with -o).
	eval set -- $(getopt -os: -l$(IFS=, ; echo "${longs[*]}") -- "$@")
	while (($#)); do
		v=$1
		shift
		case $v in
			-s | --start-step) Start_step=$1; shift;;
			--end-step) End_step=$1; shift;;
			--skip-step)
				# Add to hash of steps to skip.
				# Note: Seems to be some weirdness with getopt handling of multiples when no short opts specified.
				# Workaround: Configure at least on short opt (with -o).
				Skip_steps[$1]=yes
				shift;;
			--ca-bundle-dir) Opts[ca-bundle-dir]=$1; shift;;
			--ca-bundle-name) Opts[ca-bundle-name]=$1; shift;;
			--openssl-conf) Opts[openssl-conf]=$1; shift;;
			# TODO: Perhaps just use the --skip-step mechanism internally.
			--skip-cygwin-install)
				Opts[skip-cygwin-install]=yes
				# This option is really just syntactic sugar.
				Skip_steps[install_cyg_pkg]=yes;;
			--no-install)
				Opts[no-install]=yes
				Make_install="echo Skipping install...";;
			--no-execute)
				Opts[no-execute]=yes;;
		esac
	done
}

detect_cac_card() {
	# Note: Extract the desired id using pkcs15-tool
	# Using reader with a card: Broadcom Corp Contacted SmartCard 0
	# X.509 Certificate [Certificate for PIV Authentication]
	# 		Object Flags   : [0x0]
	# 		Authority      : no
	# 		Path           : 
	# 		ID             : 01
	Card_id=$(pkcs15-tool -c |
		sed -n -e '/PIV/,/ID/p' |
		sed -n '$s/[[:space:]]*ID[[:space:]]*:[[:space:]]*\([0-9]\+\)[[:space:]]*/\1/p')

	# TODO: Allow user to insert and retry.
	if [[ -z $Card_id ]]; then
		# TODO: Clean up message.
		error "Error: Cannot detect CAC card. Have you inserted it?"
	fi
}
check_prerequisites() {
	# We really need only wget to boostrap things.
	# Caveat: Name of exe and associated package may differ.
	# TODO: No need for loop mechanism if this ends up being the only one...
	local -A exes=([wget]=wget)
	for exe in ${!exes[@]}; do
		if [[ -z $Opts[skip-cygwin-install] ]] && ! which $exe; then
			error "Prerequisite not met: This script cannot proceed without a working \`$exe' program." \
				"Suggested remedy: Install package \`${exes[$exe]}' using Cygwin installer and rerun this script."
		fi
	done
}
# Pre-requisite: Running cygwin setup program standalone fails if the install-info utility is not in the path. Appears
# to be a cygwin bug/oversight: at any rate, we can get it by having user install just the info pkg up-front.
# Note: Using setup -P for an already-installed package appears to re-install harmlessly.
# TODO: Provide special arg for skipping cygwin install (so user needn't know which step follows).
# Important Note: If unattended setup causes problems on user's machine, he can install the packages himself through the
# gui and re-run with --skip-cygwin-install or --skip-step install_cyg_pkg.
# Input: If -u option is provided, uninstall is performed.
install_cyg_pkg() {
	# TODO: Document purpose of all these...
	local -a pkgs=(
		info git curl wget libnss3 openssl openssl-devel
		chkconfig pkg-config automake libtool cygwin-devel
		dos2unix autoconf libopenssl100 libcurl4 patch
	)
	# Obtain latest copy of setup program.
	url=https://cygwin.com/setup-x86.exe
	opt="-q -N -d -W -B"
	setup=./${url##*/}
	wget $url
	# Cygwin setup tends to generate spurious (but apparently harmless) errors, so temporarily turn off errexit.
	set +e
	if [[ $1 == -u ]]; then
		# Uninstall.
		$setup $opt -x "${pkgs[*]}"
	else
		# Caveat: I've run into issues attempting to install packages when install-info (in info package) didn't already
		# exist.
		$setup $opt -C base
		#($setup $opt -P info)
		echo "!!Installing packages: ${pkgs[*]}"
		$setup $opt -P "${pkgs[*]}"
	fi
	set -e

}
download_source() {
	# TODO: Perhaps separate OpenSC from the others, possibly even having a single build_opensc...
	repos=(
		https://github.com/bagder/curl.git
		https://github.com/git/git.git
		https://github.com/OpenSC/engine_pkcs11
		https://github.com/OpenSC/libp11
		https://github.com/OpenSC/OpenSC
	)
	for repo in "${repos[@]}"; do
		rm -rf "$(basename $repo .git)"
		# Note: Setting core.autocrlf=input obviates need for dos2unix post-processing.
		# TODO: How to ensure we always use unmodified versions of things like git. Make this configurable somehow?
		$Sys_git clone --config core.autocrlf=input $repo
	done<commit_msg>Reworking cygwin setup.<commit_after>#! /bin/bash
# Starting cwd is base of operations.
# TODO: Check to be sure it seems to contain the package.
Basedir=$PWD
# Make sure we have an unmodified git we can use to clone source repos.
Sys_git=/usr/bin/git
# This will be detected and set in detect_cac_card.
Card_id=
# Facilitate skipping install step when --no-install specified
Make_install="make install"

declare -i Step_idx=0
declare -A Skip_steps=()
# These are tied to the --start-step / --end-step options
Start_step=
End_step=

# TODO: Consider adding defaults for all... For now, missing options assumed to be unset.
declare -A Opts=(
	[ca-bundle-dir]=/usr/ssl/certs
	[ca-bundle-name]=ca-bundle-plus-dod-root
	[openssl-conf]=/usr/ssl/pkcs11-openssl.cnf
)

declare -a Steps=(
	install_cyg_pkg
	download_source
	build_opensc
	create_certs
	build_curl
	configure_openssl_conf
	build_git
	install_env_script
)

on_exit() {
	if (($? == 0)); then
		echo "Success!"
	else
		echo "Setup aborted with error! Check stdout for details."
		echo "After resolving any issues, resume setup by running ./setup -s ${Steps[$Step_idx]}"
	fi
	cd "$Basedir"
}

# Run all steps, starting with the first (or the one specified by --start-step), and ending with the last (or the one
# specified with --end-step), skipping any specified by options such as --skip-step.
run() {
	if [[ -n "$Start_step" ]]; then started=no; else started=yes; fi
	for step in "${Steps[@]}"; do
		if [[ $started == no && $step == $Start_step ]]; then
			started=yes
		fi
		# If we've passed start step (or none given) and we're not skipping...
		if [[ $started == yes && -z ${Skip_steps[$step]} ]]; then
			log "Starting step #$((Step_idx + 1)): $step"
			${Opts[no-execute]:+echo Simulating step} $step
			log "Finished step #$((Step_idx + 1)): $step"
		fi
		if [[ -n $End_step && $step == $End_step ]]; then
			log "Exiting due to --end-step '$End_step'"
			((++Step_idx))
			exit 0
		fi
		((++Step_idx))
	done
}

# TODO: Colorize?
log() {
	echo >&2 "$@" 
}
usage() {
	echo >&2 "Usage: ./setup.sh blah blah"
}
error() {
	usage=no
	if [[ "$1" == "--usage" ]]; then
		usage=yes
		shift
	fi
	echo 2>&1 "$@"
	if [[ $usage == yes ]]; then
		usage
	fi
	# TODO: Consider adding an error code option.
	exit 1
}

process_opt() {
	# TODO: Consider a different way, which would handle defaults.
	# TODO: Perhaps put these in array, at least...
	longs=(
		start-step: end-step: skip-step:
		ca-bundle-dir: ca-bundle-name: openssl-conf:
		skip-cygwin-install no-install no-execute)
	# getopt idiosyncrasy: 1st arg specified to a long opt intended to be used to build an array can lose the 1st arg if
	# there no short opts are specified (e.g., with -o).
	eval set -- $(getopt -os: -l$(IFS=, ; echo "${longs[*]}") -- "$@")
	while (($#)); do
		v=$1
		shift
		case $v in
			-s | --start-step) Start_step=$1; shift;;
			--end-step) End_step=$1; shift;;
			--skip-step)
				# Add to hash of steps to skip.
				# Note: Seems to be some weirdness with getopt handling of multiples when no short opts specified.
				# Workaround: Configure at least on short opt (with -o).
				Skip_steps[$1]=yes
				shift;;
			--ca-bundle-dir) Opts[ca-bundle-dir]=$1; shift;;
			--ca-bundle-name) Opts[ca-bundle-name]=$1; shift;;
			--openssl-conf) Opts[openssl-conf]=$1; shift;;
			# TODO: Perhaps just use the --skip-step mechanism internally.
			--skip-cygwin-install)
				Opts[skip-cygwin-install]=yes
				# This option is really just syntactic sugar.
				Skip_steps[install_cyg_pkg]=yes;;
			--no-install)
				Opts[no-install]=yes
				Make_install="echo Skipping install...";;
			--no-execute)
				Opts[no-execute]=yes;;
		esac
	done
}

detect_cac_card() {
	# Note: Extract the desired id using pkcs15-tool
	# Using reader with a card: Broadcom Corp Contacted SmartCard 0
	# X.509 Certificate [Certificate for PIV Authentication]
	# 		Object Flags   : [0x0]
	# 		Authority      : no
	# 		Path           : 
	# 		ID             : 01
	Card_id=$(pkcs15-tool -c |
		sed -n -e '/PIV/,/ID/p' |
		sed -n '$s/[[:space:]]*ID[[:space:]]*:[[:space:]]*\([0-9]\+\)[[:space:]]*/\1/p')

	# TODO: Allow user to insert and retry.
	if [[ -z $Card_id ]]; then
		# TODO: Clean up message.
		error "Error: Cannot detect CAC card. Have you inserted it?"
	fi
}
check_prerequisites() {
	# We really need only wget to boostrap things.
	# Caveat: Name of exe and associated package may differ.
	# TODO: No need for loop mechanism if this ends up being the only one...
	local -A exes=([wget]=wget)
	for exe in ${!exes[@]}; do
		if [[ -z $Opts[skip-cygwin-install] ]] && ! which $exe; then
			error "Prerequisite not met: This script cannot proceed without a working \`$exe' program." \
				"Suggested remedy: Install package \`${exes[$exe]}' using Cygwin installer and rerun this script."
		fi
	done
}
# Pre-requisite: Running cygwin setup program standalone fails if the install-info utility is not in the path. Appears
# to be a cygwin bug/oversight: at any rate, we can get it by having user install just the info pkg up-front.
# Note: Using setup -P for an already-installed package appears to re-install harmlessly.
# TODO: Provide special arg for skipping cygwin install (so user needn't know which step follows).
# Important Note: If unattended setup causes problems on user's machine, he can install the packages himself through the
# gui and re-run with --skip-cygwin-install or --skip-step install_cyg_pkg.
# Input: If -u option is provided, uninstall is performed.
install_cyg_pkg() {
	# TODO: Document purpose of all these...
	# Caveat: Make sure info pkg is installed first.
	# Rationale: I've run into issues attempting to install packages when install-info (in info package) didn't exist.
	local -a pkgs=(
		info git curl wget libnss3 openssl openssl-devel
		chkconfig pkg-config automake libtool cygwin-devel
		dos2unix autoconf libopenssl100 libcurl4 patch
	)
	# Obtain latest copy of setup program.
	url=https://cygwin.com/setup-x86.exe
	opt="-q -N -d -W -B"
	setup=./${url##*/}
	wget $url
	# Cygwin setup tends to generate spurious (but apparently harmless) errors, so temporarily turn off errexit.
	# Install packages one at a time (though -P supports multiple).
	# Rationale: Cygwin setup "quiet" mode doesn't handle dependendcies well.
	set +e
	$setup $opt -C base
	for p in "${pkgs[@]}"; do
		$setup $opt -P "$p"
	done
	set -e
}
download_source() {
	# TODO: Perhaps separate OpenSC from the others, possibly even having a single build_opensc...
	repos=(
		https://github.com/bagder/curl.git
		https://github.com/git/git.git
		https://github.com/OpenSC/engine_pkcs11
		https://github.com/OpenSC/libp11
		https://github.com/OpenSC/OpenSC
	)
	for repo in "${repos[@]}"; do
		rm -rf "$(basename $repo .git)"
		# Note: Setting core.autocrlf=input obviates need for dos2unix post-processing.
		# TODO: How to ensure we always use unmodified versions of things like git. Make this configurable somehow?
		$Sys_git clone --config core.autocrlf=input $repo
	done
{'fraction_non_alphanumeric': 0.13514291885664914, 'fraction_numerical': 0.0072719418244654044, 'mean_word_length': 3.4633676092544987, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1575905', 'n_tokens_mistral': 5156, 'n_tokens_neox': 4733, 'n_words': 1686}