diff --git a/.editorconfig b/.editorconfig index d30746808b8d..20e19ce61b24 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,11 +12,20 @@ spaces_around_operators = true [*.bat] end_of_line = crlf -[*.{py,rst,sh}] +[*.py] indent_size = 4 -[*.{js}] +[*.rst] +indent_size = 3 + +[*.js] quote_type = double [*.{markdown,md}] trim_trailing_whitespace = false + +[[shell]] +indent_style = space +indent_size = 4 +space_redirects = true +simplify = true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0222219fa883..bf255cbb8187 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,6 +56,10 @@ repos: - mdformat-ruff==0.1.3 - mdformat-shfmt==0.1.0 - mdformat_tables==1.0.0 +- repo: https://github.com/scop/pre-commit-shfmt + rev: v3.9.0-1 + hooks: + - id: shfmt - repo: https://github.com/awebdeveloper/pre-commit-stylelint rev: 0.0.2 hooks: diff --git a/ci/apt-install b/ci/apt-install index 6a637d0734c6..e739efb74f65 100755 --- a/ci/apt-install +++ b/ci/apt-install @@ -53,7 +53,7 @@ apt-get install -y \ apt-get install -y libleptonica-dev libtesseract-dev # Remove MySQL 8.x client, use older MariaDB one to ensure compatibility -if [ "$CI_DATABASE" = "mariadb" ] ; then +if [ "$CI_DATABASE" = "mariadb" ]; then apt-get purge 'mysql-client.*' apt-get install -y mariadb-client fi diff --git a/ci/lib.sh b/ci/lib.sh index afecf8662d44..b9f39e9411eb 100644 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -6,13 +6,13 @@ # shellcheck shell=sh -if [ -z "$TERM" ] ; then +if [ -z "$TERM" ]; then export TERM=xterm-256color fi check() { RET=$? - if [ $RET -ne 0 ] ; then + if [ $RET -ne 0 ]; then exit $RET fi } @@ -24,7 +24,7 @@ run_coverage() { get_mysql_args() { # shellcheck disable=SC2153 args="--host=$CI_DB_HOST --user=root" - if [ -n "$CI_DB_PORT" ] ; then + if [ -n "$CI_DB_PORT" ]; then args="$args --port=$CI_DB_PORT" fi echo "$args" @@ -33,8 +33,8 @@ get_mysql_args() { cleanup_database() { rm -f weblate.db - if [ "$CI_DATABASE" = "mysql" ] || [ "$CI_DATABASE" = 'mariadb' ] ; then - if [ -n "$CI_DB_PASSWORD" ] ; then + if [ "$CI_DATABASE" = "mysql" ] || [ "$CI_DATABASE" = 'mariadb' ]; then + if [ -n "$CI_DB_PASSWORD" ]; then export MYSQL_PWD="$CI_DB_PASSWORD" fi # shellcheck disable=SC2046 @@ -47,11 +47,11 @@ cleanup_database() { mysql $(get_mysql_args) -e 'CREATE DATABASE weblate CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;' fi - if [ "$CI_DATABASE" = "postgresql" ] ; then - if [ -n "$CI_DB_PASSWORD" ] ; then + if [ "$CI_DATABASE" = "postgresql" ]; then + if [ -n "$CI_DB_PASSWORD" ]; then export PGPASSWORD="$CI_DB_PASSWORD" fi - if [ -n "$CI_DB_PORT" ] ; then + if [ -n "$CI_DB_PORT" ]; then export PGPORT="$CI_DB_PORT" fi psql --host="$CI_DB_HOST" -c 'DROP DATABASE IF EXISTS weblate;' -U postgres @@ -66,8 +66,8 @@ print_step() { } print_version() { - for cmd in "$@" ; do - if command -v "$cmd" ; then + for cmd in "$@"; do + if command -v "$cmd"; then $cmd --version return fi diff --git a/ci/pip-install b/ci/pip-install index 7b5fbd68e121..994b02512f45 100755 --- a/ci/pip-install +++ b/ci/pip-install @@ -6,26 +6,26 @@ set -e -x -if [ "${1:-latest}" = migrations ] ; then +if [ "${1:-latest}" = migrations ]; then uv pip install --system -e ".[all,mysql,ci]" else - if [ "${1:-latest}" = minimal ] ; then + if [ "${1:-latest}" = minimal ]; then # Adjust deps to force minimal version sed -i '/^ *"/ s/>=/==/' pyproject.toml fi - if [ "${1:-latest}" = mypy ] ; then - uv pip install --system -e ".[all,mysql,ci,mypy,test]" + if [ "${1:-latest}" = mypy ]; then + uv pip install --system -e ".[all,mysql,ci,mypy,test]" else - # TODO: lxml can use wheels once xmlsec has one - # see https://github.com/xmlsec/python-xmlsec/issues/327 - if python -c 'import sys; sys.exit(0 if sys.version_info >= (3,13) else 1)' ; then - uv pip install --system --no-binary=lxml -e ".[all,mysql,ci,test]" - else - uv pip install --system -e ".[all,mysql,ci,test]" - fi + # TODO: lxml can use wheels once xmlsec has one + # see https://github.com/xmlsec/python-xmlsec/issues/327 + if python -c 'import sys; sys.exit(0 if sys.version_info >= (3,13) else 1)'; then + uv pip install --system --no-binary=lxml -e ".[all,mysql,ci,test]" + else + uv pip install --system -e ".[all,mysql,ci,test]" + fi fi - if [ "${1:-latest}" = edge ] ; then + if [ "${1:-latest}" = edge ]; then uv pip install --system --upgrade -e ".[all,mysql,test,ci]" # Install from git / pre-release uv pip install --system --no-deps --upgrade --force-reinstall \ @@ -37,6 +37,6 @@ else fi # Verify that deps are consistent -if [ "${1:-latest}" != edge ] ; then +if [ "${1:-latest}" != edge ]; then uv pip check fi diff --git a/ci/prepare-database b/ci/prepare-database index 2def92e34a97..6537c6f2d382 100755 --- a/ci/prepare-database +++ b/ci/prepare-database @@ -10,15 +10,15 @@ set -e cleanup_database -if [ "$CI_DATABASE" = "mysql" ] || [ "$CI_DATABASE" = 'mariadb' ] ; then +if [ "$CI_DATABASE" = "mysql" ] || [ "$CI_DATABASE" = 'mariadb' ]; then # shellcheck disable=SC2046 mysql $(get_mysql_args) -e 'SHOW VARIABLES LIKE "%version%";' fi -if [ "$CI_DATABASE" = "postgresql" ] ; then - if [ -n "$CI_DB_PASSWORD" ] ; then +if [ "$CI_DATABASE" = "postgresql" ]; then + if [ -n "$CI_DB_PASSWORD" ]; then export PGPASSWORD="$CI_DB_PASSWORD" fi - if [ -n "$CI_DB_PORT" ] ; then + if [ -n "$CI_DB_PORT" ]; then export PGPORT="$CI_DB_PORT" fi psql --host="$CI_DB_HOST" -c 'SELECT version();' -U postgres diff --git a/ci/run-checkmigrate b/ci/run-checkmigrate index 8f2e8d09cd83..7702f6d9a6bf 100755 --- a/ci/run-checkmigrate +++ b/ci/run-checkmigrate @@ -12,9 +12,9 @@ cleanup_database run_coverage ./manage.py migrate run_coverage ./manage.py makemigrations check -if [ "$(git status -s -- '*/migrations/*' | wc -l)" -gt 0 ] ; then +if [ "$(git status -s -- '*/migrations/*' | wc -l)" -gt 0 ]; then echo 'There are untracked migrations:' - git status -s --porcelain -- '*/migrations/*' | sed -n '/^??/ s/^?? \(.*\)/\1/p' | while read -r migration ; do + git status -s --porcelain -- '*/migrations/*' | sed -n '/^??/ s/^?? \(.*\)/\1/p' | while read -r migration; do echo "$migration" cat "$migration" echo diff --git a/ci/run-docs b/ci/run-docs index 6f1b04de04bd..da3602f0fae1 100755 --- a/ci/run-docs +++ b/ci/run-docs @@ -6,12 +6,10 @@ set -e -if ! command -v dot &> /dev/null -then +if ! command -v dot &> /dev/null; then echo "dot command could not be found, please install graphviz" exit 1 fi - # Build documentation with warnings treated as errors make -C docs "${1:-html}" SPHINXOPTS='-n -W -a --keep-going' diff --git a/ci/run-migrate b/ci/run-migrate index a9732c299fca..cfc72580eb42 100755 --- a/ci/run-migrate +++ b/ci/run-migrate @@ -8,7 +8,7 @@ . ci/lib.sh -if [ -n "$1" ] ; then +if [ -n "$1" ]; then TAG="weblate-$1" else echo "Missing version to migrate from!" @@ -20,7 +20,7 @@ HEAD_COMMIT=$(git rev-parse HEAD) print_step "Testing migration from $TAG on $CI_DATABASE..." cleanup_database check -if ! git fetch --depth 1 origin tag "$TAG" ; then +if ! git fetch --depth 1 origin tag "$TAG"; then git remote add upstream https://github.com/WeblateOrg/weblate.git git fetch --depth 1 upstream tag "$TAG" fi @@ -36,11 +36,11 @@ uv pip install -e ".[all,mysql]" check echo "DATABASES['default']['HOST'] = '$CI_DB_HOST'" >> weblate/settings_test.py check -if [ -n "$CI_DB_PASSWORD" ] ; then +if [ -n "$CI_DB_PASSWORD" ]; then echo "DATABASES['default']['PASSWORD'] = '$CI_DB_PASSWORD'" >> weblate/settings_test.py check fi -if [ -n "$CI_DB_PORT" ] ; then +if [ -n "$CI_DB_PORT" ]; then echo "DATABASES['default']['PORT'] = '$CI_DB_PORT'" >> weblate/settings_test.py check fi @@ -77,7 +77,6 @@ check ./manage.py shell -c 'from weblate.memory.models import Memory; from weblate.lang.models import Language; Memory.objects.create(source_language=Language.objects.get(code="en"), target_language=Language.objects.get(code="cs"), source="source"*1000, target="target"*1000, origin="origin"*1000)' check - git reset --hard check git checkout "$HEAD_COMMIT" diff --git a/ci/services-down b/ci/services-down index 679ff03ea831..7d6a14ad32a2 100755 --- a/ci/services-down +++ b/ci/services-down @@ -6,7 +6,7 @@ set -e -if [ ! -f services-down ] ; then +if [ ! -f services-down ]; then cd ci fi diff --git a/ci/services-up b/ci/services-up index 16b739baa396..7325e064aa21 100755 --- a/ci/services-up +++ b/ci/services-up @@ -6,7 +6,7 @@ set -e -if [ ! -f services-up ] ; then +if [ ! -f services-up ]; then cd ci fi diff --git a/rundev.sh b/rundev.sh index 9ab6c20c6d21..acda619aa40b 100755 --- a/rundev.sh +++ b/rundev.sh @@ -20,7 +20,6 @@ export USER_ID GROUP_ID=$(id -g) export GROUP_ID - cd dev-docker/ build() { @@ -37,45 +36,45 @@ build() { } case $1 in - stop) - docker compose down - ;; - logs) - shift - docker compose logs "$@" - ;; - test) - shift - docker compose exec -T -e WEBLATE_DATA_DIR=/tmp/test-data -e WEBLATE_CELERY_EAGER=1 -e WEBLATE_SITE_TITLE=Weblate -e WEBLATE_ADD_APPS=weblate.billing,weblate.legal -e WEBLATE_VCS_FILE_PROTOCOL=1 -e WEBLATE_VCS_API_DELAY=0 weblate weblate test --noinput "$@" - ;; - check) - shift - docker compose exec -T weblate weblate check "$@" - ;; - build) - build - ;; - wait) - TIMEOUT=0 - while ! docker compose ps | grep healthy ; do - echo "Waiting for the container startup..." - sleep 1 - docker compose ps - TIMEOUT=$((TIMEOUT + 1)) - if [ $TIMEOUT -gt 120 ] ; then - docker compose logs - exit 1 - fi - done - ;; - start|restart|"") - build +stop) + docker compose down + ;; +logs) + shift + docker compose logs "$@" + ;; +test) + shift + docker compose exec -T -e WEBLATE_DATA_DIR=/tmp/test-data -e WEBLATE_CELERY_EAGER=1 -e WEBLATE_SITE_TITLE=Weblate -e WEBLATE_ADD_APPS=weblate.billing,weblate.legal -e WEBLATE_VCS_FILE_PROTOCOL=1 -e WEBLATE_VCS_API_DELAY=0 weblate weblate test --noinput "$@" + ;; +check) + shift + docker compose exec -T weblate weblate check "$@" + ;; +build) + build + ;; +wait) + TIMEOUT=0 + while ! docker compose ps | grep healthy; do + echo "Waiting for the container startup..." + sleep 1 + docker compose ps + TIMEOUT=$((TIMEOUT + 1)) + if [ $TIMEOUT -gt 120 ]; then + docker compose logs + exit 1 + fi + done + ;; +start | restart | "") + build - # Start it up - docker compose up -d --force-recreate - echo -e "\n${GREEN}Running development version of Weblate on http://${WEBLATE_HOST}/${NC}\n" - ;; - *) - docker compose "$@" - ;; + # Start it up + docker compose up -d --force-recreate + echo -e "\n${GREEN}Running development version of Weblate on http://${WEBLATE_HOST}/${NC}\n" + ;; +*) + docker compose "$@" + ;; esac diff --git a/scripts/create-release b/scripts/create-release index 1868a70c27b4..6ad9f244c79d 100755 --- a/scripts/create-release +++ b/scripts/create-release @@ -6,25 +6,24 @@ set -e -if [ "$1" = "--help" ] || [ "$1" = "-h" ] ; then +if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then echo "Usage: ./scripts/create-release [--tag]" exit 1 fi -if ! git diff --exit-code --quiet ; then +if ! git diff --exit-code --quiet; then echo "There are not committed changes!" exit 1 fi DO_TAG=0 -if [ "$1" = "--tag" ] ; then +if [ "$1" = "--tag" ]; then DO_TAG=1 shift fi - # What are we going to build? -if [ "$DO_TAG" -eq 1 ] ; then +if [ "$DO_TAG" -eq 1 ]; then ./scripts/prepare-release # Grab version diff --git a/scripts/optimize-svg b/scripts/optimize-svg index 4de3b5f3cde5..59c2f2abb97d 100755 --- a/scripts/optimize-svg +++ b/scripts/optimize-svg @@ -8,19 +8,19 @@ optimize() { # SVG optimization scour --strip-xml-space --strip-xml-prolog --remove-metadata --no-line-breaks --enable-id-stripping --enable-comment-stripping --indent=none --remove-descriptive-elements "$icon" "$icon.tmp" # Remove possible doctype - sed '/!DOCTYPE/d' < "$icon.tmp" > "$icon" + sed '/!DOCTYPE/d' < "$icon.tmp" > "$icon" # Remove trailing newline (imgbot does this and we want to avoid fighting with it) truncate -s -1 "$icon" rm "$icon.tmp" } -if [ $# -ne 0 ] ; then - for icon in "$@" ; do +if [ $# -ne 0 ]; then + for icon in "$@"; do optimize "$icon" done exit 0 fi -for icon in weblate/static/icons/*.svg weblate/static/auth/*.svg weblate/static/state/*.svg weblate/static/sort/*.svg ; do +for icon in weblate/static/icons/*.svg weblate/static/auth/*.svg weblate/static/state/*.svg weblate/static/sort/*.svg; do optimize "$icon" done diff --git a/scripts/pack-test-data b/scripts/pack-test-data index 746d8e51800d..634773d50c1a 100755 --- a/scripts/pack-test-data +++ b/scripts/pack-test-data @@ -48,7 +48,7 @@ svnadmin create --compatible-version 1.6 test-base-repo.svn # Hardcode UUID to make this reproducible echo "24fccd88-22b4-439e-bb17-3cda778ca655" > test-base-repo.svn/db/uuid # Allow propset to change timestamps -cat > test-base-repo.svn/hooks/pre-revprop-change < test-base-repo.svn/hooks/pre-revprop-change << EOT #!/bin/sh exit 0 EOT @@ -66,9 +66,9 @@ svn propset -rHEAD --revprop svn:date "2019-02-02T00:44:04.921324Z" "file://$WD/ # Pack them reproducible_tar() { tar --sort=name \ - --mtime="2019-01-01" \ - --owner=0 --group=0 --numeric-owner \ - -cf "$@" + --mtime="2019-01-01" \ + --owner=0 --group=0 --numeric-owner \ + -cf "$@" } reproducible_tar "$OUT/test-base-repo.hg.tar" test-base-repo.hg reproducible_tar "$OUT/test-base-repo.git.tar" test-base-repo.git diff --git a/scripts/prepare-release b/scripts/prepare-release index 603268c6715c..918a95927f07 100755 --- a/scripts/prepare-release +++ b/scripts/prepare-release @@ -6,23 +6,22 @@ set -e -if ! git diff --exit-code --quiet ; then +if ! git diff --exit-code --quiet; then echo "There are not committed changes!" exit 1 fi suffix="" -if [ -n "$1" ] ; then +if [ -n "$1" ]; then suffix="$1" shift fi -if [ -n "$1" ] ; then +if [ -n "$1" ]; then datespec="datetime.date.fromisoformat('$1')" shift else datespec="datetime.date.today()" fi - . scripts/test-database.sh version=$(python -c 'import weblate.utils.version; print(weblate.utils.version.VERSION_BASE)') today=$(./manage.py shell -c 'from django.utils.dateformat import format; import datetime; print(format('"$datespec"', "F jS Y"))') @@ -30,10 +29,10 @@ today=$(./manage.py shell -c 'from django.utils.dateformat import format; import sed -i "s/^VERSION =.*/VERSION = \"$version$suffix\"/" weblate/utils/version.py sed -i "s/^Not yet released./Released on $today./" docs/changes.rst -if [ -z "$suffix" ] ; then +if [ -z "$suffix" ]; then ./scripts/list-contributors --update fi -if ! git diff --exit-code --quiet ; then +if ! git diff --exit-code --quiet; then git commit -m "chore: releasing $version$suffix" -- weblate/utils/version.py docs/changes.rst "docs/changes/contributors/$version.rst" fi diff --git a/scripts/update-graphics b/scripts/update-graphics index 36ddf80e8bf5..ed433e3de332 100755 --- a/scripts/update-graphics +++ b/scripts/update-graphics @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -if [ ! -d ../graphics/ ] ; then +if [ ! -d ../graphics/ ]; then echo "Graphics repository missing!" fi @@ -19,10 +19,10 @@ cp ../graphics/logo/weblate.svg ../graphics/logo/weblate-black.svg weblate/stati cp ../graphics/logo/weblate.ico weblate/static/favicon.ico # Scaled logos -for size in 24 32 80 128 150 180 192 512 ; do +for size in 24 32 80 128 150 180 192 512; do cp ../graphics/logo/weblate-background-$size.png weblate/static/weblate-$size.png done -for size in 16 32 128 1024 ; do +for size in 16 32 128 1024; do cp ../graphics/logo/weblate-logo-$size.png weblate/static/logo-$size.png done diff --git a/scripts/update-locales b/scripts/update-locales index f9203e28d99a..d3c3f9e76ac6 100755 --- a/scripts/update-locales +++ b/scripts/update-locales @@ -9,7 +9,6 @@ # Exit on failure set -e - . scripts/test-database.sh version=$(python -c 'import weblate.utils.version; print(weblate.utils.version.VERSION_BASE)') @@ -17,7 +16,7 @@ version=$(python -c 'import weblate.utils.version; print(weblate.utils.version.V COMPONENTS="weblate/application weblate/javascript weblate/documentation" do_wlc() { - for component in $COMPONENTS ; do + for component in $COMPONENTS; do wlc "$1" "$component" done } @@ -43,11 +42,11 @@ find weblate/locale -type d -empty -delete ./manage.py makemessages --keep-pot -a -i 'data/*' -i 'docs/*' -i 'examples/*' -i 'build/*' -d djangojs # Include translations from Django -for locale in weblate/locale/*/LC_MESSAGES/django.po ; do +for locale in weblate/locale/*/LC_MESSAGES/django.po; do code=${locale#weblate/locale/} code=${code%/LC_MESSAGES/django.po} file=~/work/django/django/conf/locale/$code/LC_MESSAGES/django.po - if [ -f "$file" ] ; then + if [ -f "$file" ]; then msgmerge --previous -C "$file" -U "$locale" weblate/locale/django.pot fi done diff --git a/scripts/yarn-update b/scripts/yarn-update index af11ebbefe34..d4cf628e4ce6 100755 --- a/scripts/yarn-update +++ b/scripts/yarn-update @@ -52,21 +52,21 @@ cp node_modules/moment/moment.js ../../weblate/static/vendor/ sed '/font-family/ a font-display: swap;' < node_modules/source-sans/source-sans-3.css > ../../weblate/static/vendor/font-source/source-sans-3.css sed '/font-family/ a font-display: swap;' < node_modules/source-code-pro/source-code-pro.css > ../../weblate/static/vendor/font-source/source-code-pro.css find node_modules/source-sans/WOFF node_modules/source-sans/WOFF2 node_modules/source-sans/TTF node_modules/source-code-pro/ \ - -name 'SourceSans3-ExtraLight.*' \ - -o -name 'SourceSans3-Light.*' \ - -o -name 'SourceSans3-Semibold.*' \ - -o -name 'SourceSans3-Black.*' \ - -o -name 'SourceSans3-Bold.*' \ - -o -name 'SourceSans3-Regular.*' \ - -o -name 'SourceSans3-It.*' \ - -o -name 'SourceSans3-BoldIt.*' \ - -o -name 'SourceCodePro-Medium.*' \ - -o -name 'SourceCodePro-Regular.*' \ - -o -name 'SourceCodePro-Bold.*' \ - -o -name 'SourceCodePro-Semibold.*' | while read -r name ; do + -name 'SourceSans3-ExtraLight.*' \ + -o -name 'SourceSans3-Light.*' \ + -o -name 'SourceSans3-Semibold.*' \ + -o -name 'SourceSans3-Black.*' \ + -o -name 'SourceSans3-Bold.*' \ + -o -name 'SourceSans3-Regular.*' \ + -o -name 'SourceSans3-It.*' \ + -o -name 'SourceSans3-BoldIt.*' \ + -o -name 'SourceCodePro-Medium.*' \ + -o -name 'SourceCodePro-Regular.*' \ + -o -name 'SourceCodePro-Bold.*' \ + -o -name 'SourceCodePro-Semibold.*' | while read -r name; do target=$(echo "$name" | sed 's@node_modules/source-\(sans\|code-pro\)/@../../weblate/static/vendor/font-source/@') dir=$(dirname "$target") - if [ ! -d "$dir" ] ; then + if [ ! -d "$dir" ]; then mkdir -p "$dir" fi cp "$name" "$target" diff --git a/weblate/examples/git-merge-gettext-po b/weblate/examples/git-merge-gettext-po index 052add8204f3..8c33555851d8 100755 --- a/weblate/examples/git-merge-gettext-po +++ b/weblate/examples/git-merge-gettext-po @@ -44,7 +44,6 @@ MSGCAT_FINAL_FLAGS="" # 3: Also show all status messages with timestamps VERBOSITY="${VERBOSITY:=0}" - # Use logical names for arguments: BASE="$1" LOCAL="$2" @@ -57,18 +56,17 @@ OUTPUT="$LOCAL" # smarter merging fails. TEMP_FILE="$(mktemp /tmp/merge-po.XXXXXX)" -if git merge-file --stdout "$LOCAL" "$BASE" "$OTHER" > "$TEMP_FILE" ; then - cat "$TEMP_FILE" > "$OUTPUT" +if git merge-file --stdout "$LOCAL" "$BASE" "$OTHER" > "$TEMP_FILE"; then + cat "$TEMP_FILE" > "$OUTPUT" rm "$TEMP_FILE" exit 0 fi rm "$TEMP_FILE" - ########################################################################## # Fallback when gettext tools are not installed: -if ! type msgmerge >/dev/null 2>&1 ; then +if ! type msgmerge > /dev/null 2>&1; then # With Gettext PO files, you might get bit by conflicts in PO file # headers. To avoid it, you can use the this merge driver. Use it by # putting the following configuration in your .gitconfig: @@ -98,17 +96,15 @@ fi # use names like "local" and "other" instead of e.g. "local.G2wZ.po". TEMP="$(mktemp -d /tmp/merge-po.XXXXXX)" - # abort on any error and report the details if possible set -E set -e # shellcheck disable=SC2317 # shellcheck does not understand trap below -on_error() -{ +on_error() { local parent_lineno="$1" local code="$2" local message="$3" - if [[ -n "$message" ]] ; then + if [[ -n $message ]]; then printf "### $0: error near line %d: status %d: %s\n" "${parent_lineno}" "${code}" "${message}" 1>&2 else printf "### $0: error near line %d: status %d\n" "${parent_lineno}" "${code}" 1>&2 @@ -117,12 +113,9 @@ on_error() } trap 'on_error ${LINENO} $?' ERR - # Maybe print message(s) to stdout with timestamps -function status() -{ - if test "$VERBOSITY" -ge 3 - then +function status() { + if test "$VERBOSITY" -ge 3; then printf "%s %s\n" "$(date '+%Y-%m-%d %H:%M:%S.%3N')" "$@" fi } @@ -130,49 +123,43 @@ function status() # Quietly take translations from $1 and apply those according to template $2 # (and do not use fuzzy-matching, always generate output) # also supports all flags to msgmerge -function apply_po_template() -{ +function apply_po_template() { msgmerge --force-po --quiet --no-fuzzy-matching "$@" } # Take stdin, remove the "graveyard strings" and emit the result to stdout -function strip_graveyard() -{ +function strip_graveyard() { msgattrib --no-obsolete } # Take stdin, keep only conflict lines and emit the result to stdout -function only_conflicts() -{ +function only_conflicts() { msggrep --msgstr -F -e '#-#-#-#-#' - # alternative slightly worse implementation: msgattrib --only-fuzzy } # Take stdin, discard conflict lines and emit the result to stdout -function without_conflicts() -{ +function without_conflicts() { msggrep -v --msgstr -F -e '#-#-#-#-#' - # alternative slightly worse implementation: msgattrib --no-fuzzy } # Select messages from $1 that are also in $2 but whose contents have changed # and emit results to stdout -function extract_changes() -{ +function extract_changes() { # Extract conflicting changes and discard any changes to graveyard area only - msgcat -o - "$1" "$2" \ - | only_conflicts \ - | apply_po_template -o - "$1" - \ - | strip_graveyard + msgcat -o - "$1" "$2" | + only_conflicts | + apply_po_template -o - "$1" - | + strip_graveyard } # Emit only the header of $1, supports flags of msggrep -function extract_header() -{ +function extract_header() { # Unfortunately gettext really doesn't support extracting just header # so we have to get creative: extract only strings that originate # from file called "//" which should result to header only - msggrep --force-po -N // "$@" + msggrep --force-po -N // "$@" # Logically msggrep --force-po -v -K -E -e '.' should return the header # only but msggrep seems be buggy with msgids with line feeds and output @@ -180,15 +167,13 @@ function extract_header() } # Take file in $1 and show conflicts with colors in the file to stdout -function show_conflicts() -{ +function show_conflicts() { filename="$1" shift # Count number of lines to remove from the output and output conflict lines without the header CONFLICT_HEADER_LINES=$(msggrep --force-po --msgstr -F -e '#-#-#-#-#' "$filename" | extract_header - | wc -l) CONFLICTS=$(msggrep --force-po --color --msgstr -F -e '#-#-#-#-#' "$filename" | tail -n "-$CONFLICT_HEADER_LINES") - if test -n "$CONFLICTS" - then + if test -n "$CONFLICTS"; then #echo "----------------------------" #echo "Conflicts after merge:" echo "----------------------------" @@ -202,8 +187,7 @@ test -n "$TEMP" || exit 125 test -d "$TEMP" || exit 126 test -w "$TEMP" || exit 127 -if test "$VERBOSITY" -ge 1 -then +if test "$VERBOSITY" -ge 1; then printf "Using gettext .PO merge driver: %s ...\n" "$FILENAME" fi @@ -213,7 +197,6 @@ extract_header -o "${TEMP}/header" "$LOCAL" ########################################################################## # Following parts can be run partially parallel and "wait" is used to synchronize processing - # Clean input files and use logical filenames for possible conflict markers: status "Canonicalizing input files ..." msguniq --force-po -o "${TEMP}/base" --unique "${BASE}" & @@ -233,7 +216,7 @@ msgcat --force-po -o - "${TEMP}/other-changes" "${TEMP}/local-changes" | only_co # Messages changed on local, not on other; and vice-versa: status "Computing local-only and other-only changes ..." -msgcat --force-po -o "${TEMP}/local-only" --unique "${TEMP}/local-changes" "${TEMP}/conflicts" & +msgcat --force-po -o "${TEMP}/local-only" --unique "${TEMP}/local-changes" "${TEMP}/conflicts" & msgcat --force-po -o "${TEMP}/other-only" --unique "${TEMP}/other-changes" "${TEMP}/conflicts" & wait @@ -264,15 +247,12 @@ rmdir "${TEMP}" status "Checking for conflicts in the result ..." # Check for conflicts in the final merge -if grep -q '#-#-#-#-#' "$OUTPUT" -then - if test "$VERBOSITY" -ge 1 - then +if grep -q '#-#-#-#-#' "$OUTPUT"; then + if test "$VERBOSITY" -ge 1; then printf "### Conflict(s) detected ###\n" fi - if test "$VERBOSITY" -ge 2 - then + if test "$VERBOSITY" -ge 2; then # Verbose diagnostics show_conflicts "$OUTPUT" fi diff --git a/weblate/trans/tests/data/lab b/weblate/trans/tests/data/lab index b29a523f877f..e5e877dfdc11 100755 --- a/weblate/trans/tests/data/lab +++ b/weblate/trans/tests/data/lab @@ -3,8 +3,13 @@ # Fake lab implementation for use in testsuite case "$1" in - mr) exit 0;; - fork) git remote add test "$(git config --get remote.origin.url)"; exit 0;; +mr) + exit 0 + ;; +fork) + git remote add test "$(git config --get remote.origin.url)" + exit 0 + ;; esac git "$@"