Skip to content

Commit

Permalink
New command mycli files end-of-line (#16)
Browse files Browse the repository at this point in the history
* Add command "files end-of-line"

* Fix doc

* Fix typo

* Fix file name
  • Loading branch information
gcbeltramini authored Jan 18, 2025
1 parent 98ede74 commit fffda97
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 7 deletions.
30 changes: 30 additions & 0 deletions commands/files/end-of-line.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail

##? Display files that don't have exactly one empty line at the end.
##?
##? Usage:
##? files end-of-line [<path>]
##?
##? Options:
##? <path> Path to the directory to search for files [default: .]

source "${CLI_DIR}/core/helpers.sh"
parse_help "$@"
declare path

files_to_check=$(find_relevant_files "${path:-.}")

echo "Files without exactly one empty line at the end:"
found=false
while IFS= read -r file; do
if ! has_exactly_one_line_at_the_end "$file"; then
echo "$file"
found=true
fi
done < <(printf '%s\n' "$files_to_check")

if [ "$found" = false ]; then
echo_color "gray" "All files have exactly one empty line at the end."
fi
echo_done
77 changes: 77 additions & 0 deletions core/helpers/files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,80 @@ backup_if_exists() {
echo >&2 "'$name' already exists. Backup created: '$backup_path'"
fi
}

find_relevant_files() {
# List relevant files.
#
# Usage:
# find_relevant_files [<path> <find-args>]
#
# Options:
# <path> Path to the directory to search for files [default: .]
# <find-args> Additional arguments to pass to the find command
local -r path_name=${1:-.}
shift 1 || true
local find_args=("$@")

find "$path_name" \
-type f \
-not -name '.DS_Store' \
-not -name '*.pyc' \
-not -name '*.pyo' \
-not -name '*.egg' \
-not -name '*.egg-info' \
-not -name '*.whl' \
-not -path '*/__pycache__/*' \
-not -path '*/.venv/*' \
-not -path '*/venv/*' \
-not -path '*/.ipynb_checkpoints/*' \
-not -path '*/node_modules/*' \
-not -name '*.tar' \
-not -name '*.zip' \
-not -name '*.tfstate' \
-not -name '*.tfstate.backup' \
-not -name '*.coverage' \
-not -path '*/.git/*' \
-not -path '*/.idea/*' \
-not -path '*/.terraform/*' \
"${find_args[@]}" #\
# Maybe ignore binary files with:
# ! -exec file --mime {} + |
# grep -v ': binary' |
# awk -F: '{print $1}'
}

files_not_ending_with_newline() {
# List files that do not end with a newline.
#
# Usage:
# files_not_ending_with_newline <files>
#
# References:
# - Based on: https://stackoverflow.com/a/25686825/7649076
# - "Why should text files end with a newline?":
# https://stackoverflow.com/questions/729692/why-should-text-files-end-with-a-newline
local -r files=$1
while IFS= read -r file; do
if [[ -n "$(tail -c 1 "$file")" ]]; then
echo "$file"
fi
done < <(printf '%s\n' "$files")
}

has_exactly_one_line_at_the_end() {
# Check if file has exactly one empty line at the end.
#
# Usage:
# has_exactly_one_line_at_the_end <file>
local -r file=$1

if [[ -n "$(tail -c 1 "$file")" ]]; then
# No empty line at the end
return 1
elif tail -n 1 "$file" | grep -q '^ *$'; then
# More than one empty line at the end
return 2
else
return 0
fi
}
3 changes: 2 additions & 1 deletion scripts/tests/run_all_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ while IFS= read -r file; do
invalid_files_lines_at_the_end+="\n$file"
fi
done <<<"$files"
allow_list_regex=".*/tests/resources/commands/problematic file.sh$"
allow_list_regex=".*/tests/resources/commands/problematic file.sh$
.*/tests/resources/commands/no_newline_at_the_end.txt$"
invalid_files_lines_at_the_end=$(remove_from_list "$invalid_files_lines_at_the_end" "$allow_list_regex")
check_if_error "$invalid_files_lines_at_the_end"
echo_done
Expand Down
57 changes: 57 additions & 0 deletions tests/core/helpers/test_files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,63 @@ test_backup_if_exists() {
assertTrue "[ -f ${mock_file}.20*.bkp ]"
}

test_find_relevant_files() {
local result expected

# result=$(find_relevant_files "tests/resources/commands" | xargs -0 -n 1 echo | sort)
result=$(find_relevant_files "tests/resources/commands" | sort)
expected=$(cat <<-EOF
tests/resources/commands/hello-world.sh
tests/resources/commands/no_newline_at_the_end.txt
tests/resources/commands/problematic file.sh
tests/resources/commands/update/.gitkeep
EOF
)
assertEquals "$expected" "$result"

result=$(find_relevant_files "tests/resources/commands" -name '*.sh' | sort)
expected=$(cat <<-EOF
tests/resources/commands/hello-world.sh
tests/resources/commands/problematic file.sh
EOF
)
assertEquals "$expected" "$result"
}

test_files_not_ending_with_newline() {
local result expected

result=$(files_not_ending_with_newline "$(find_relevant_files "tests/resources/commands")" | sort)
expected="tests/resources/commands/no_newline_at_the_end.txt"
assertEquals "$expected" "$result"

files=$(cat <<-EOF
tests/resources/commands/no_newline_at_the_end.txt
tests/resources/commands/problematic file.sh
EOF
)
result=$(files_not_ending_with_newline "$files")
expected="tests/resources/commands/no_newline_at_the_end.txt"
assertEquals "$expected" "$result"
}

test_has_exactly_one_line_at_the_end() {
local result
assertTrue 'has_exactly_one_line_at_the_end "tests/resources/commands/hello-world.sh"'

assertFalse 'has_exactly_one_line_at_the_end "tests/resources/commands/problematic file.sh"'

has_exactly_one_line_at_the_end "tests/resources/commands/problematic file.sh"
result=$?
assertEquals 2 "$result"

assertFalse 'has_exactly_one_line_at_the_end "tests/resources/commands/no_newline_at_the_end.txt"'

has_exactly_one_line_at_the_end "tests/resources/commands/no_newline_at_the_end.txt"
result=$?
assertEquals 1 "$result"
}

oneTimeSetUp() {
mock_file="mock_file.txt"
touch "$mock_file"
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/commands/no_newline_at_the_end.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This file doesn't end in a newline character.
It is used in a unit test.
5 changes: 0 additions & 5 deletions tests/test_unit_test_helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,6 @@ EOF
assertEquals "$expected" "$result"
}

test_has_exactly_one_line_at_the_end() {
assertTrue 'has_exactly_one_line_at_the_end "tests/resources/commands/hello-world.sh"'
assertFalse 'has_exactly_one_line_at_the_end "tests/resources/commands/problematic file.sh"'
}

test_get_variable_def_or_fn_call() {
local result

Expand Down
4 changes: 3 additions & 1 deletion tests/unit_test_helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ find_forbidden_cmd_names() {
}

has_exactly_one_line_at_the_end() {
# COPIED FROM core/helpers/files.sh TO AVOID SOURCING EXTERNAL FILES.
#
# Check if file has exactly one empty line at the end.
#
# Usage:
Expand All @@ -265,7 +267,7 @@ has_exactly_one_line_at_the_end() {
return 1
elif tail -n 1 "$file" | grep -q '^ *$'; then
# More than one empty line at the end
return 1
return 2
else
return 0
fi
Expand Down

0 comments on commit fffda97

Please sign in to comment.