|
#!/usr/bin/env bash |
|
|
|
source hhs.bash 0.2.0 |
|
|
|
function strmaxlen () # [<strings> ...] |
|
# Get max length of strings. |
|
{ |
|
local s len=0 |
|
for s; do (( len < ${#s} )) && let len=${#s}; done |
|
echo $len |
|
} |
|
|
|
function escape_sed_regex () # <string> |
|
# Escape special characters of sed regex in a string. |
|
{ |
|
sed -re 's/[][$*+.()\/\\{|}]/\\\0/g' <<< "$1" |
|
} |
|
|
|
function git_preserving_mtime_post_checkout () # [<options>] |
|
# Git hooks for post-checkout. |
|
{ |
|
local log lines stamps stamp mtime fn |
|
|
|
log=( git log -1 --pretty="format:%B" ) |
|
lines=( $("${log[@]}" | grep -nE '```' | grep -EA1 '```timestamp' | sed -re 's/:.*//g') ) |
|
if ! [[ "${lines[0]}" =~ ^[0-9]+$ && "${lines[1]}" =~ ^[0-9]+$ ]]; then |
|
warning "No timestamp found." |
|
exit |
|
fi |
|
readarray -t stamps < <("${log[@]}" | headtail $(( lines[0] + 1 )) $(( lines[1] - 1)) ) |
|
|
|
for stamp in "${stamps[@]}"; do |
|
mtime="${stamp%%$'\t'*}" |
|
fn="$(echo "x${stamp#*$'\t'}x" | xargs echo)" |
|
fn="${fn:1:-1}" |
|
echo "$stamp" |
|
[ -n "$OPT_DRY_RUN" ] && continue |
|
touch -d "$mtime" "$fn" |
|
done |
|
} |
|
|
|
function git_preserving_mtime_prepare_commit_msg () # [<options>] <COMMIT_MSG_FILE> <COMMIT_SOURCE> <SHA1> |
|
# Git hooks for prepare-commit-msg. |
|
{ |
|
local files file tmp |
|
|
|
readarray -t files < <(git ls-files) |
|
|
|
tmp="$(mktemp -p "$(dirname "$1")" "$(basename "$1"),XXXXXXXX")" |
|
cp -a "$1" "$tmp" |
|
|
|
{ |
|
echo |
|
echo '```timestamp' |
|
for file in "${files[@]}"; do |
|
stat -c "%y"$'\t'"%N" "$file" |
|
done |
|
echo '```' |
|
cat "$tmp" |
|
} >"$1" |
|
|
|
rm "$tmp" |
|
} |
|
|
|
function common_init_git_preserving_mtime () # [<options>] [<repos> [<targets> ...]] |
|
# Initialization for git-preserving-mtime |
|
# Parameters: |
|
# <repos> : Directory of git repository |
|
# <targets> : Hook targets for git hooks (ex: .git/hooks/post-checkout). |
|
# If this parameter is given, <repos> will be ignored. |
|
# Returns: |
|
# invoker : Invoke string for git-preserving-mtime. |
|
# invoker_regex : Invoker string which escape special characters of regex. |
|
# repos : Directory of repository (default: ./). |
|
# hookdir : Directory of githooks (default: .git/hooks). |
|
# targets : Target files of githooks (default: .git/hooks/{prepare-commit-msg,post-checkout}). |
|
{ |
|
invoker='git preserving-mtime "${0##*/}" "$@"' |
|
invoker_regex="$(escape_sed_regex "$invoker")" |
|
repos=${1:-.} |
|
hookdir="${repos%/}/.git/hooks" |
|
|
|
(( $# < 2 )) && targets=( "${hookdir%/}/"{prepare-commit-msg,post-checkout} ) || targets=( "${@:2}" ) |
|
w="$(strmaxlen "${targets[@]}")" |
|
} |
|
|
|
function git_preserving_mtime_status () # [<options>] [<repos> [<targets> ...]] |
|
# Show status of preserving-mtime. |
|
# Parameters: |
|
# <repos> : Directory of git repository |
|
# <targets> : Hook targets for git hooks (ex: .git/hooks/post-checkout). |
|
# If this parameter is given, <repos> will be ignored. |
|
{ |
|
local invoker invoker_regex repos hookdir targets w file status |
|
common_init_git_preserving_mtime "$@" |
|
|
|
for file in "${targets[@]}"; do |
|
if [ ! -e "$file" ]; then |
|
status="${SGR_rfg_red}${SGR_bold}File is not found${SGR_reset}" |
|
elif head -n1 "$file" | grep -q bash; then |
|
if status="$(grep -E "^#?${invoker_regex}$" "$file")"; then |
|
[[ "${status:0:1}" != "#" ]] && status="${SGR_fg_green}${SGR_bold}enabled${SGR_reset}" || status="${SGR_fg_blue}${SGR_bold}disabled${SGR_reset}" |
|
else |
|
status="${SGR_fg_yellow}${SGR_bold}Never installed${SGR_reset}" |
|
fi |
|
else |
|
status="${SGR_red}${SGR_bold}Not bash script.${SGR_reset}" |
|
fi |
|
printf "%-${w}s : %b\n" "$file" "$status" >&2 |
|
done |
|
} |
|
|
|
function git_preserving_mtime_install () # [<options>] [<repos> [<targets> ...]] |
|
# Install git hooks for preserving-mtime. |
|
# Parameters: |
|
# <repos> : Directory of git repository |
|
# <targets> : Hook targets for git hooks (ex: .git/hooks/post-checkout). |
|
# If this parameter is given, <repos> will be ignored. |
|
{ |
|
local invoker invoker_regex repos hookdir targets w file status |
|
common_init_git_preserving_mtime "$@" |
|
|
|
for file in "${targets[@]}"; do |
|
if [ ! -e "$file" ]; then |
|
{ |
|
echo "#!/usr/bin/env bash" |
|
echo "$invoker" |
|
} >"$file" |
|
chmod +x "$file" |
|
status="Created file and installed." |
|
elif head -n1 "$file" | grep -q bash; then |
|
if status="$(grep -E "^#?${invoker_regex}$" "$file")"; then |
|
if [[ "${status:0:1}" != "#" ]]; then |
|
sed -r -i -e 's/^#?('"$invoker_regex"')$/\1/g' "$file" |
|
status="Enabled." |
|
else |
|
status="Already enabled." |
|
fi |
|
else |
|
echo "$invoker" >> "$file" |
|
status="Installed." |
|
fi |
|
else |
|
status="${SGR_red}${SGR_bold}Not bash script.${SGR_reset}" |
|
fi |
|
printf "%-${w}s : %b\n" "$file" "$status" >&2 |
|
done |
|
} |
|
|
|
function git_preserving_mtime_enable () # [<options>] [<repos> [<targets> ...]] |
|
# Enable git hooks for preserving-mtime. |
|
# Parameters: |
|
# <repos> : Directory of git repository |
|
# <targets> : Hook targets for git hooks (ex: .git/hooks/post-checkout). |
|
# If this parameter is given, <repos> will be ignored. |
|
{ |
|
local invoker invoker_regex repos hookdir targets w file status |
|
common_init_git_preserving_mtime "$@" |
|
|
|
for file in "${targets[@]}"; do |
|
if [ ! -e "$file" ]; then |
|
{ |
|
echo "#!/usr/bin/env bash" |
|
echo "$invoker" |
|
} >"$file" |
|
chmod +x "$file" |
|
status="Created file and installed." |
|
elif head -n1 "$file" | grep -q bash; then |
|
if status="$(grep -E "^#?${invoker_regex}$" "$file")"; then |
|
if [[ "${status:0:1}" == "#" ]]; then |
|
sed -r -i -e 's/^#?('"$invoker_regex"')$/\1/g' "$file" |
|
status="Enabled." |
|
else |
|
status="Already enabled." |
|
fi |
|
else |
|
echo "$invoker" >> "$file" |
|
status="Installed." |
|
fi |
|
else |
|
status="${SGR_red}${SGR_bold}Not bash script.${SGR_reset}" |
|
fi |
|
printf "%-${w}s : %b\n" "$file" "$status" >&2 |
|
done |
|
} |
|
|
|
function git_preserving_mtime_disable () # [<options>] [<repos> [<targets> ...]] |
|
# Disable git hooks for preserving-mtime. |
|
# Parameters: |
|
# <repos> : Directory of git repository |
|
# <targets> : Hook targets for git hooks (ex: .git/hooks/post-checkout). |
|
# If this parameter is given, <repos> will be ignored. |
|
{ |
|
local invoker invoker_regex repos hookdir targets w file status |
|
common_init_git_preserving_mtime "$@" |
|
|
|
for file in "${targets[@]}"; do |
|
if [ ! -e "$file" ]; then |
|
status="File is not found." |
|
elif head -n1 "$file" | grep -q bash; then |
|
if status="$(grep -E "^#?${invoker_regex}$" "$file")"; then |
|
if [[ "${status:0:1}" != "#" ]]; then |
|
sed -r -i -e 's/^#?('"$invoker_regex"')$/#\1/g' "$file" |
|
status="Disabled." |
|
else |
|
status="Already disabled." |
|
fi |
|
else |
|
status="Never installed." |
|
fi |
|
else |
|
status="${SGR_red}${SGR_bold}Not bash script.${SGR_reset}" |
|
fi |
|
printf "%-${w}s : %b\n" "$file" "$status" >&2 |
|
done |
|
} |
|
|
|
function git_preserving_mtime_uninstall () # [<options>] [<repos> [<targets> ...]] |
|
# Uninstall git hooks for preserving-mtime. |
|
# Parameters: |
|
# <repos> : Directory of git repository |
|
# <targets> : Hook targets for git hooks (ex: .git/hooks/post-checkout). |
|
# If this parameter is given, <repos> will be ignored. |
|
{ |
|
local invoker invoker_regex repos hookdir targets w file status |
|
common_init_git_preserving_mtime "$@" |
|
|
|
for file in "${targets[@]}"; do |
|
if [ ! -e "$file" ]; then |
|
status="File is not found." |
|
elif head -n1 "$file" | grep -q bash; then |
|
if status="$(grep -E "^#?${invoker_regex}$" "$file")"; then |
|
sed -r -i -e '/^#?'"$invoker_regex"'$/d' "$file" |
|
status="Uninstalled." |
|
else |
|
status="Never installed." |
|
fi |
|
else |
|
status="${SGR_red}${SGR_bold}Not bash script.${SGR_reset}" |
|
fi |
|
printf "%-${w}s : %b\n" "$file" "$status" >&2 |
|
done |
|
} |
|
|
|
has_subcommand_git_preserving_mtime=1 |
|
|
|
function optparse_git_preserving_mtime () |
|
{ |
|
case "$1" in |
|
-n|--dry-run) |
|
# Do not change anything. |
|
nparams 0 |
|
optset DRY_RUN "$1" |
|
;; |
|
*) return 1 ;; |
|
esac |
|
} |
|
|
|
function usage_git_preserving_mtime () |
|
{ |
|
echo "Usage: git preserving-mtime [COMMAND]" |
|
echo " Preserving mtime." |
|
usage__commands |
|
usage__options |
|
} |
|
|
|
function git_preserving_mtime () # [<options>] [<command>] |
|
{ |
|
invoke_usage |
|
} |
|
|
|
invoke_command "$@" |