Skip to content

Commit

Permalink
Use LC_ALL=C for all commands
Browse files Browse the repository at this point in the history
This means every byte is a valid character and so the "invalid byte squence"
won't occur where a character is not a valid character in the system locale.
  • Loading branch information
Andrei authored and wulfgarpro committed Sep 16, 2023
1 parent 611988b commit 4d4a8b9
Showing 1 changed file with 22 additions and 14 deletions.
36 changes: 22 additions & 14 deletions history-sync.plugin.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ ZSH_HISTORY_FILE_DECRYPT_NAME="${ZSH_HISTORY_FILE_DECRYPT_NAME:-zsh_history_decr
ZSH_HISTORY_FILE_MERGED_NAME="${ZSH_HISTORY_FILE_MERGED_NAME:-zsh_history_merged}"
ZSH_HISTORY_COMMIT_MSG="${ZSH_HISTORY_COMMIT_MSG:-latest $(date)}"

function SED() {LC_ALL=C sed "$@";}
function AWK() {LC_ALL=C awk "$@";}
function GREP() {LC_ALL=C grep "$@";}
function SORT() {LC_ALL=C sort "$@";}
function TR() {LC_ALL=C tr "$@";}

function _print_git_error_msg() {
echo "$bold_color${fg[red]}There's a problem with git repository: ${ZSH_HISTORY_PROJ}.$reset_color"
return
Expand Down Expand Up @@ -66,55 +72,55 @@ function _squash_multiline_commands_in_files() {
# Generate random character sequences to replace \n and anchor the first
# line of a command (use global variable for new-line-replacement to use it
# in the restore-multi-line commands function)
NL_REPLACEMENT=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom |
NL_REPLACEMENT=$(TR -dc 'a-zA-Z0-9' < /dev/urandom |
fold -w 32 | head -n 1)
local FIRST_LINE_ANCHOR=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom |
local FIRST_LINE_ANCHOR=$(TR -dc 'a-zA-Z0-9' < /dev/urandom |
fold -w 32 | head -n 1)

for i in "$ZSH_HISTORY_FILE" "$ZSH_HISTORY_FILE_DECRYPT_NAME"; do
# Filter out multi-line commands and save them to a separate file
grep -v -B 1 '^: [0-9]\{1,10\}:[0-9]\+;' "${i}" |
grep -v -e '^--$' > "${TMP_FILE_1}"
GREP -v -B 1 '^: [0-9]\{1,10\}:[0-9]\+;' "${i}" |
GREP -v -e '^--$' > "${TMP_FILE_1}"

# Filter out multi-line commands and remove them from the original file
grep -v -x -F -f "${TMP_FILE_1}" "${i}" > "${TMP_FILE_2}" \
GREP -v -x -F -f "${TMP_FILE_1}" "${i}" > "${TMP_FILE_2}" \
&& mv "${TMP_FILE_2}" "${i}"

# Add anchor before the first line of each command
sed "s/\(^: [0-9]\{1,10\}:[0-9]\+;\)/${FIRST_LINE_ANCHOR} \1/" \
SED "s/\(^: [0-9]\{1,10\}:[0-9]\+;\)/${FIRST_LINE_ANCHOR} \1/" \
"${TMP_FILE_1}" > "${TMP_FILE_2}" \
&& mv "${TMP_FILE_2}" "${TMP_FILE_1}"

# Replace all \n with a sequence of symbols
sed ':a;N;$!ba;s/\n/'" ${NL_REPLACEMENT} "'/g' \
SED ':a;N;$!ba;s/\n/'" ${NL_REPLACEMENT} "'/g' \
"${TMP_FILE_1}" > "${TMP_FILE_2}" \
&& mv "${TMP_FILE_2}" "${TMP_FILE_1}"

# Replace first line anchor by \n
sed "s/${FIRST_LINE_ANCHOR} \(: [0-9]\{1,10\}:[0-9]\+;\)/\n\1/g" \
SED "s/${FIRST_LINE_ANCHOR} \(: [0-9]\{1,10\}:[0-9]\+;\)/\n\1/g" \
"${TMP_FILE_1}" > "${TMP_FILE_2}" \
&& mv "${TMP_FILE_2}" "${TMP_FILE_1}"

# Merge squashed multiline commands to the history file
cat "${TMP_FILE_1}" >> "${i}"

# Sort history file
LC_ALL=C sort -n < "${i}" > "${TMP_FILE_1}" && mv "${TMP_FILE_1}" "${i}"
SORT -n < "${i}" > "${TMP_FILE_1}" && mv "${TMP_FILE_1}" "${i}"
done
}

# Restore multi-line commands in the history file
function _restore_multiline_commands_in_file() {
# Filter unnecessary lines from the history file (Binary file ... matches)
# and save them in a separate file
grep -v '^: [0-9]\{1,10\}:[0-9]\+;' "$ZSH_HISTORY_FILE" > "${TMP_FILE_1}"
GREP -v '^: [0-9]\{1,10\}:[0-9]\+;' "$ZSH_HISTORY_FILE" > "${TMP_FILE_1}"

# Filter out unnecessary lines and remove them from the original file
grep -v -x -F -f "${TMP_FILE_1}" "$ZSH_HISTORY_FILE" > "${TMP_FILE_2}" && \
GREP -v -x -F -f "${TMP_FILE_1}" "$ZSH_HISTORY_FILE" > "${TMP_FILE_2}" && \
mv "${TMP_FILE_2}" "$ZSH_HISTORY_FILE"

# Replace the sequence of symbols by \n to restore multi-line commands
sed "s/ ${NL_REPLACEMENT} /\n/g" "$ZSH_HISTORY_FILE" > "${TMP_FILE_1}" \
SED "s/ ${NL_REPLACEMENT} /\n/g" "$ZSH_HISTORY_FILE" > "${TMP_FILE_1}" \
&& mv "${TMP_FILE_1}" "$ZSH_HISTORY_FILE"

# Unset global variables
Expand Down Expand Up @@ -160,15 +166,17 @@ function history_sync_pull() {
[[ -o extendedhistory ]] && _squash_multiline_commands_in_files

# Merge
cat "$ZSH_HISTORY_FILE" "$ZSH_HISTORY_FILE_DECRYPT_NAME" | awk '/:[0-9]/ { if(s) { print s } s=$0 } !/:[0-9]/ { s=s"\n"$0 } END { print s }' | LC_ALL=C sort -u > "$ZSH_HISTORY_FILE_MERGED_NAME"
cat "$ZSH_HISTORY_FILE" "$ZSH_HISTORY_FILE_DECRYPT_NAME" | \
AWK '/:[0-9]/ { if(s) { print s } s=$0 } !/:[0-9]/ { s=s"\n"$0 } END { print s }' \
| SORT -u > "$ZSH_HISTORY_FILE_MERGED_NAME"
mv "$ZSH_HISTORY_FILE_MERGED_NAME" "$ZSH_HISTORY_FILE"
rm "$ZSH_HISTORY_FILE_DECRYPT_NAME"
cd "$DIR"

# Check if EXTENDED_HISTORY is enabled, and if so, restore multi-line
# commands in the local history file
[[ -o extendedhistory ]] && _restore_multiline_commands_in_file
sed -i '/^$/d' "$ZSH_HISTORY_FILE"
SED -i '/^$/d' "$ZSH_HISTORY_FILE"
}

# Encrypt and push current history to master
Expand Down

0 comments on commit 4d4a8b9

Please sign in to comment.