Signed-off-by: Allan McRae <allan@archlinux.org> --- scripts/Makefile.am | 18 ++ scripts/libmakepkg/.gitignore | 2 + scripts/libmakepkg/lint_pkgbuild.sh.in | 46 +++ scripts/libmakepkg/lint_pkgbuild/arch.sh.in | 64 ++++ scripts/libmakepkg/lint_pkgbuild/backup.sh.in | 51 ++++ scripts/libmakepkg/lint_pkgbuild/changelog.sh.in | 45 +++ scripts/libmakepkg/lint_pkgbuild/epoch.sh.in | 37 +++ scripts/libmakepkg/lint_pkgbuild/install.sh.in | 44 +++ scripts/libmakepkg/lint_pkgbuild/optdepends.sh.in | 64 ++++ scripts/libmakepkg/lint_pkgbuild/options.sh.in | 57 ++++ .../lint_pkgbuild/package_function.sh.in | 51 ++++ scripts/libmakepkg/lint_pkgbuild/pkgbase.sh.in | 37 +++ scripts/libmakepkg/lint_pkgbuild/pkglist.sh.in | 44 +++ scripts/libmakepkg/lint_pkgbuild/pkgname.sh.in | 57 ++++ scripts/libmakepkg/lint_pkgbuild/pkgrel.sh.in | 42 +++ scripts/libmakepkg/lint_pkgbuild/pkgver.sh.in | 55 ++++ scripts/libmakepkg/lint_pkgbuild/provides.sh.in | 62 ++++ scripts/libmakepkg/lint_pkgbuild/source.sh.in | 39 +++ scripts/libmakepkg/lint_pkgbuild/util.sh.in | 41 +++ scripts/makepkg.sh.in | 334 +-------------------- scripts/po/POTFILES.in | 17 ++ 21 files changed, 874 insertions(+), 333 deletions(-) create mode 100644 scripts/libmakepkg/lint_pkgbuild.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/arch.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/backup.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/changelog.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/epoch.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/install.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/optdepends.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/options.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/package_function.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/pkgbase.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/pkglist.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/pkgname.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/pkgrel.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/pkgver.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/provides.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/source.sh.in create mode 100644 scripts/libmakepkg/lint_pkgbuild/util.sh.in diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 4a54b8d..fb32f16 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -42,6 +42,7 @@ libmakepkgdir = $(datarootdir)/makepkg LIBMAKEPKGDIRS = \ lint_package \ + lint_pkgbuild \ tidy \ util @@ -55,6 +56,23 @@ LIBMAKEPKG_IN = \ libmakepkg/lint_package.sh \ libmakepkg/lint_package/build_references.sh \ libmakepkg/lint_package/missing_backup.sh \ + libmakepkg/lint_pkgbuild.sh \ + libmakepkg/lint_pkgbuild/arch.sh \ + libmakepkg/lint_pkgbuild/backup.sh \ + libmakepkg/lint_pkgbuild/changelog.sh \ + libmakepkg/lint_pkgbuild/epoch.sh \ + libmakepkg/lint_pkgbuild/install.sh \ + libmakepkg/lint_pkgbuild/optdepends.sh \ + libmakepkg/lint_pkgbuild/options.sh \ + libmakepkg/lint_pkgbuild/package_function.sh \ + libmakepkg/lint_pkgbuild/pkgbase.sh \ + libmakepkg/lint_pkgbuild/pkglist.sh \ + libmakepkg/lint_pkgbuild/pkgname.sh \ + libmakepkg/lint_pkgbuild/pkgrel.sh \ + libmakepkg/lint_pkgbuild/pkgver.sh \ + libmakepkg/lint_pkgbuild/provides.sh \ + libmakepkg/lint_pkgbuild/source.sh \ + libmakepkg/lint_pkgbuild/util.sh \ libmakepkg/tidy.sh \ libmakepkg/tidy/docs.sh \ libmakepkg/tidy/emptydirs.sh \ diff --git a/scripts/libmakepkg/.gitignore b/scripts/libmakepkg/.gitignore index 46d8fc1..e5a6995 100644 --- a/scripts/libmakepkg/.gitignore +++ b/scripts/libmakepkg/.gitignore @@ -1,6 +1,8 @@ lint_package.sh lint_package/build_references.sh lint_package/missing_backup.sh +lint_pkgbuild.sh +lint_pkgbuild/*.sh tidy.sh tidy/docs.sh tidy/emptydirs.sh diff --git a/scripts/libmakepkg/lint_pkgbuild.sh.in b/scripts/libmakepkg/lint_pkgbuild.sh.in new file mode 100644 index 0000000..a792d5b --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild.sh.in @@ -0,0 +1,46 @@ +#!/bin/bash +# +# lint_pkgbuild.sh - functions for detecting PKGBUILD errors +# +# Copyright (c) 2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +declare -a lint_pkgbuild_functions + +for lib in "$LIBRARY/lint_pkgbuild/"*.sh; do + source "$lib" +done + +readonly -a lint_pkgbuild_functions + + +lint_pkgbuild() { + local ret=0 + + for func in ${lint_pkgbuild_functions[@]}; do + $func || ret=1 + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/arch.sh.in b/scripts/libmakepkg/lint_pkgbuild/arch.sh.in new file mode 100644 index 0000000..547d5fc --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/arch.sh.in @@ -0,0 +1,64 @@ +#!/bin/bash +# +# arch.sh - Check the 'arch' array conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_ARCH_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_ARCH_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + + +lint_pkgbuild_functions+=('lint_arch') + + +lint_arch() { + local a name list + + if [[ $arch == 'any' ]]; then + return 0 + fi + + for a in "${arch[@]}"; do + if [[ $a = *[![:alnum:]_]* ]]; then + error "$(gettext "%s contains invalid characters: '%s'")" \ + 'arch' "${a//[[:alnum:]_]}" + ret=1 + fi + done + + if (( ! IGNOREARCH )) && ! in_array "$CARCH" "${arch[@]}"; then + error "$(gettext "%s is not available for the '%s' architecture.")" "$pkgbase" "$CARCH" + plain "$(gettext "Note that many packages may need a line added to their %s")" "$BUILDSCRIPT" + plain "$(gettext "such as %s.")" "arch=('$CARCH')" + return 1 + fi + + for name in "${pkgname[@]}"; do + get_pkgbuild_attribute "$name" 'arch' 1 list + if [[ $list && $list != 'any' ]] && ! in_array $CARCH "${list[@]}"; then + if (( ! IGNOREARCH )); then + error "$(gettext "%s is not available for the '%s' architecture.")" "$name" "$CARCH" + ret=1 + fi + fi + done +} diff --git a/scripts/libmakepkg/lint_pkgbuild/backup.sh.in b/scripts/libmakepkg/lint_pkgbuild/backup.sh.in new file mode 100644 index 0000000..c128d33 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/backup.sh.in @@ -0,0 +1,51 @@ +#!/bin/bash +# +# backup.sh - Check the 'backup' array conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_BACKUP_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_BACKUP_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + + +lint_pkgbuild_functions+=('lint_backup') + + +lint_backup() { + local list name backup_list ret=0 + + backup_list=("${backup[@]}") + for name in "${pkgname[@]}"; do + if extract_function_variable "package_$name" backup 1 list; then + backup_list+=("${list[@]}") + fi + done + + for name in "${backup_list[@]}"; do + if [[ ${name:0:1} = "/" ]]; then + error "$(gettext "%s entry should not contain leading slash : %s")" "backup" "$name" + ret=1 + fi + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/changelog.sh.in b/scripts/libmakepkg/lint_pkgbuild/changelog.sh.in new file mode 100644 index 0000000..2dac5db --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/changelog.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# +# changelog.sh - Check the files in the 'changelog' array exist. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_CHANGELOG_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_CHANGELOG_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" +source "$LIBRARY/lint_pkgbuild/util.sh" + + +lint_pkgbuild_functions+=('lint_changelog') + + +lint_changelog() { + local list name file changelog_list ret=0 + + changelog_list=("${changelog[@]}") + for name in "${pkgname[@]}"; do + if extract_function_variable "package_$name" changelog 0 file; then + changelog_list+=("$file") + fi + done + + check_files_exist 'changelog' "${changelog_list[@]}" +} diff --git a/scripts/libmakepkg/lint_pkgbuild/epoch.sh.in b/scripts/libmakepkg/lint_pkgbuild/epoch.sh.in new file mode 100644 index 0000000..93b51b8 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/epoch.sh.in @@ -0,0 +1,37 @@ +#!/bin/bash +# +# epoch.sh - Check the 'epoch' variable conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_EPOCH_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_EPOCH_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +lint_pkgbuild_functions+=('lint_epoch') + + +lint_epoch() { + if [[ $epoch != *([[:digit:]]) ]]; then + error "$(gettext "%s must be an integer, not %s.")" "epoch" "$epoch" + return 1 + fi +} diff --git a/scripts/libmakepkg/lint_pkgbuild/install.sh.in b/scripts/libmakepkg/lint_pkgbuild/install.sh.in new file mode 100644 index 0000000..21e0bfb --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/install.sh.in @@ -0,0 +1,44 @@ +#!/bin/bash +# +# install.sh - Check the files in the 'install' array exist. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_INSTALL_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_INSTALL_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" +source "$LIBRARY/lint_pkgbuild/util.sh" + + +lint_pkgbuild_functions+=('lint_install') + + +lint_install() { + local list file name install_list ret=0 + + install_list=("${install[@]}") + for name in "${pkgname[@]}"; do + extract_function_variable "package_$name" install 0 file + install_list+=("$file") + done + + check_files_exist 'install' "${install_list[@]}" +} diff --git a/scripts/libmakepkg/lint_pkgbuild/optdepends.sh.in b/scripts/libmakepkg/lint_pkgbuild/optdepends.sh.in new file mode 100644 index 0000000..6e66e0d --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/optdepends.sh.in @@ -0,0 +1,64 @@ +#!/bin/bash +# +# optdepends.sh - Check the 'optdepends' array conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_OPTDEPENDS_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_OPTDEPENDS_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + + +lint_pkgbuild_functions+=('lint_optdepends') + + +lint_optdepends() { + local a list name optdepends_list ret=0 + + optdepends_list=("${optdepends[@]}") + for a in "${arch[@]}"; do + array_build list "optdepends_$a" + optdepends_list+=("${list[@]}") + done + + for name in "${pkgname[@]}"; do + if extract_function_variable "package_$name" optdepends 1 list; then + optdepends_list+=("${list[@]}") + fi + + for a in "${arch[@]}"; do + if extract_function_variable "package_$name" "optdepends_$a" 1 list; then + optdepends_list+=("${list[@]}") + fi + done + done + + for name in "${optdepends_list[@]}"; do + local pkg=${name%%:[[:space:]]*} + # the '-' character _must_ be first or last in the character range + if [[ $pkg != +([-[:alnum:]><=.+_:]) ]]; then + error "$(gettext "Invalid syntax for %s: '%s'")" "optdepend" "$name" + ret=1 + fi + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/options.sh.in b/scripts/libmakepkg/lint_pkgbuild/options.sh.in new file mode 100644 index 0000000..4423d26 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/options.sh.in @@ -0,0 +1,57 @@ +#!/bin/bash +# +# options.sh - Check the 'options' array conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_OPTIONS_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_OPTIONS_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + + +lint_pkgbuild_functions+=('lint_options') + + +lint_options() { + local ret=0 list name kopt options_list + + options_list=("${options[@]}") + for name in "${pkgname[@]}"; do + if extract_function_variable "package_$name" options 1 list; then + options_list+=("${list[@]}") + fi + done + + for i in "${options_list[@]}"; do + # check if option matches a known option or its inverse + for kopt in "${packaging_options[@]}" "${build_options[@]}"; do + if [[ $i = "$kopt" || $i = "!$kopt" ]]; then + # continue to the next $i + continue 2 + fi + done + + error "$(gettext "%s array contains unknown option '%s'")" "options" "$i" + ret=1 + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/package_function.sh.in b/scripts/libmakepkg/lint_pkgbuild/package_function.sh.in new file mode 100644 index 0000000..c2ed837 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/package_function.sh.in @@ -0,0 +1,51 @@ +#!/bin/bash +# +# package_function.sh - Check that required package functions exist. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PACKAGE_FUNCTION_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PACKAGE_FUNCTION_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + + +lint_pkgbuild_functions+=('lint_package_function') + + +lint_package_function() { + local i ret=0 + + if (( ${#pkgname[@]} == 1 )); then + if have_function 'build' && ! { have_function 'package' || have_function "package_$pkgname"; }; then + error "$(gettext "Missing %s function in %s")" "package()" "$BUILDFILE" + ret=1 + fi + else + for i in "${pkgname[@]}"; do + if ! have_function "package_$i"; then + error "$(gettext "Missing %s function for split package '%s'")" "package_$i()" "$i" + ret=1 + fi + done + fi + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/pkgbase.sh.in b/scripts/libmakepkg/lint_pkgbuild/pkgbase.sh.in new file mode 100644 index 0000000..abb40e0 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/pkgbase.sh.in @@ -0,0 +1,37 @@ +#!/bin/bash +# +# pkgbase.sh - Check the 'pkgbase' variable conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PKGBASE_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PKGBASE_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +lint_pkgbuild_functions+=('lint_pkgbase') + + +lint_pkgbase() { + if [[ ${pkgbase:0:1} = "-" ]]; then + error "$(gettext "%s is not allowed to start with a hyphen.")" "pkgname" + return 1 + fi +} diff --git a/scripts/libmakepkg/lint_pkgbuild/pkglist.sh.in b/scripts/libmakepkg/lint_pkgbuild/pkglist.sh.in new file mode 100644 index 0000000..26a8ac0 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/pkglist.sh.in @@ -0,0 +1,44 @@ +#!/bin/bash +# +# pkglist.sh - Check the packages selected to build exist. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PKGLIST_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PKGLIST_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/util.sh" + + +lint_pkgbuild_functions+=('lint_pkglist') + + +lint_pkglist() { + local i ret=0 + + for i in "${PKGLIST[@]}"; do + if ! in_array "$i" "${pkgname[@]}"; then + error "$(gettext "Requested package %s is not provided in %s")" "$i" "$BUILDFILE" + ret=1 + fi + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/pkgname.sh.in b/scripts/libmakepkg/lint_pkgbuild/pkgname.sh.in new file mode 100644 index 0000000..e5e2f26 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/pkgname.sh.in @@ -0,0 +1,57 @@ +#!/bin/bash +# +# pkgname.sh - Check the 'pkgname' variable conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PKGNAME_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PKGNAME_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +lint_pkgbuild_functions+=('lint_pkgname') + + +lint_pkgname() { + local ret=0 i + + for i in "${pkgname[@]}"; do + if [[ -z $i ]]; then + error "$(gettext "%s is not allowed to be empty.")" "pkgname" + ret=1 + continue + fi + if [[ ${i:0:1} = "-" ]]; then + error "$(gettext "%s is not allowed to start with a hyphen.")" "pkgname" + ret=1 + fi + if [[ ${i:0:1} = "." ]]; then + error "$(gettext "%s is not allowed to start with a dot.")" "pkgname" + ret=1 + fi + if [[ $i = *[^[:alnum:]+_.@-]* ]]; then + error "$(gettext "%s contains invalid characters: '%s'")" \ + 'pkgname' "${i//[[:alnum:]+_.@-]}" + ret=1 + fi + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/pkgrel.sh.in b/scripts/libmakepkg/lint_pkgbuild/pkgrel.sh.in new file mode 100644 index 0000000..371e6a1 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/pkgrel.sh.in @@ -0,0 +1,42 @@ +#!/bin/bash +# +# pkgrel.sh - Check the 'pkgrel' variable conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PKGREL_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PKGREL_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +lint_pkgbuild_functions+=('lint_pkgrel') + + +lint_pkgrel() { + if [[ -z $pkgrel ]]; then + error "$(gettext "%s is not allowed to be empty.")" "pkgrel" + return 1 + fi + + if [[ $pkgrel != +([0-9])?(.+([0-9])) ]]; then + error "$(gettext "%s must be a decimal, not %s.")" "pkgrel" "$pkgrel" + return 1 + fi +} diff --git a/scripts/libmakepkg/lint_pkgbuild/pkgver.sh.in b/scripts/libmakepkg/lint_pkgbuild/pkgver.sh.in new file mode 100644 index 0000000..d23f704 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/pkgver.sh.in @@ -0,0 +1,55 @@ +#!/bin/bash +# +# pkgver.sh - Check the 'pkgver' variable conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PKGVER_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PKGVER_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +lint_pkgbuild_functions+=('lint_pkgver') + + +validate_pkgver() { + if [[ $1 = *[[:space:]:-]* ]]; then + error "$(gettext "%s is not allowed to contain colons, hyphens or whitespace.")" "pkgver" + return 1 + fi +} + +check_pkgver() { + if [[ -z ${pkgver} ]]; then + error "$(gettext "%s is not allowed to be empty.")" "pkgver" + return 1 + fi + + validate_pkgver "$pkgver" +} + +lint_pkgver() { + if (( PKGVERFUNC )); then + # defer check to after getting version from pkgver function + return 0 + fi + + check_pkgver +} diff --git a/scripts/libmakepkg/lint_pkgbuild/provides.sh.in b/scripts/libmakepkg/lint_pkgbuild/provides.sh.in new file mode 100644 index 0000000..668cf56 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/provides.sh.in @@ -0,0 +1,62 @@ +#!/bin/bash +# +# provides.sh - Check the 'provides' array conforms to requirements. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PROVIDES_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_PROVIDES_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + + +lint_pkgbuild_functions+=('lint_provides') + + +lint_provides() { + local a list name provides_list ret=0 + + provides_list=("${provides[@]}") + for a in "${arch[@]}"; do + array_build list "provides_$a" + provides_list+=("${list[@]}") + done + + for name in "${pkgname[@]}"; do + if extract_function_variable "package_$name" provides 1 list; then + provides_list+=("${list[@]}") + fi + + for a in "${arch[@]}"; do + if extract_function_variable "package_$name" "provides_$a" 1 list; then + provides_list+=("${list[@]}") + fi + done + done + + for provide in "${provides_list[@]}"; do + if [[ $provide == *['<>']* ]]; then + error "$(gettext "%s array cannot contain comparison (< or >) operators.")" "provides" + ret=1 + fi + done + + return $ret +} diff --git a/scripts/libmakepkg/lint_pkgbuild/source.sh.in b/scripts/libmakepkg/lint_pkgbuild/source.sh.in new file mode 100644 index 0000000..c327299 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/source.sh.in @@ -0,0 +1,39 @@ +#!/bin/bash +# +# source.sh - Check the 'source' array is not sparse. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_SOURCE_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_SOURCE_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +lint_pkgbuild_functions+=('lint_source') + + +lint_source() { + local idx=("${!source[@]}") + + if (( ${#source[*]} > 0 && (idx[-1] + 1) != ${#source[*]} )); then + error "$(gettext "Sparse arrays are not allowed for source")" + return 1 + fi +} diff --git a/scripts/libmakepkg/lint_pkgbuild/util.sh.in b/scripts/libmakepkg/lint_pkgbuild/util.sh.in new file mode 100644 index 0000000..448abc8 --- /dev/null +++ b/scripts/libmakepkg/lint_pkgbuild/util.sh.in @@ -0,0 +1,41 @@ +#!/bin/bash +# +# util.sh - utility functions for pkgbuild linting. +# +# Copyright (c) 2014-2015 Pacman Development Team <pacman-dev@archlinux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_UTIL_SH" ]] && return +LIBMAKEPKG_LINT_PKGBUILD_UTIL_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + + +check_files_exist() { + local kind=$1 files=("${@:2}") file ret + + for file in "${files[@]}"; do + if [[ $file && ! -f $file ]]; then + error "$(gettext "%s file (%s) does not exist or is not a regular file.")" \ + "$kind" "$file" + ret=1 + fi + done + + return $ret +} diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index a00e8a4..4885341 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -2135,338 +2135,6 @@ install_package() { fi } -lint_pkgbase() { - if [[ ${pkgbase:0:1} = "-" ]]; then - error "$(gettext "%s is not allowed to start with a hyphen.")" "pkgname" - return 1 - fi -} - -lint_pkgname() { - local ret=0 i - - for i in "${pkgname[@]}"; do - if [[ -z $i ]]; then - error "$(gettext "%s is not allowed to be empty.")" "pkgname" - ret=1 - continue - fi - if [[ ${i:0:1} = "-" ]]; then - error "$(gettext "%s is not allowed to start with a hyphen.")" "pkgname" - ret=1 - fi - if [[ ${i:0:1} = "." ]]; then - error "$(gettext "%s is not allowed to start with a dot.")" "pkgname" - ret=1 - fi - if [[ $i = *[^[:alnum:]+_.@-]* ]]; then - error "$(gettext "%s contains invalid characters: '%s'")" \ - 'pkgname' "${i//[[:alnum:]+_.@-]}" - ret=1 - fi - done - - return $ret -} - -lint_pkgrel() { - if [[ -z $pkgrel ]]; then - error "$(gettext "%s is not allowed to be empty.")" "pkgrel" - return 1 - fi - - if [[ $pkgrel != +([0-9])?(.+([0-9])) ]]; then - error "$(gettext "%s must be a decimal, not %s.")" "pkgrel" "$pkgrel" - return 1 - fi -} - -lint_pkgver() { - if (( PKGVERFUNC )); then - # defer check to after getting version from pkgver function - return 0 - fi - - check_pkgver -} - -lint_epoch() { - if [[ $epoch != *([[:digit:]]) ]]; then - error "$(gettext "%s must be an integer, not %s.")" "epoch" "$epoch" - return 1 - fi -} - -lint_arch() { - local a name list - - if [[ $arch == 'any' ]]; then - return 0 - fi - - for a in "${arch[@]}"; do - if [[ $a = *[![:alnum:]_]* ]]; then - error "$(gettext "%s contains invalid characters: '%s'")" \ - 'arch' "${a//[[:alnum:]_]}" - ret=1 - fi - done - - if (( ! IGNOREARCH )) && ! in_array "$CARCH" "${arch[@]}"; then - error "$(gettext "%s is not available for the '%s' architecture.")" "$pkgbase" "$CARCH" - plain "$(gettext "Note that many packages may need a line added to their %s")" "$BUILDSCRIPT" - plain "$(gettext "such as %s.")" "arch=('$CARCH')" - return 1 - fi - - for name in "${pkgname[@]}"; do - get_pkgbuild_attribute "$name" 'arch' 1 list - if [[ $list && $list != 'any' ]] && ! in_array $CARCH "${list[@]}"; then - if (( ! IGNOREARCH )); then - error "$(gettext "%s is not available for the '%s' architecture.")" "$name" "$CARCH" - ret=1 - fi - fi - done -} - -lint_provides() { - local a list name provides_list ret=0 - - provides_list=("${provides[@]}") - for a in "${arch[@]}"; do - array_build list "provides_$a" - provides_list+=("${list[@]}") - done - - for name in "${pkgname[@]}"; do - if extract_function_variable "package_$name" provides 1 list; then - provides_list+=("${list[@]}") - fi - - for a in "${arch[@]}"; do - if extract_function_variable "package_$name" "provides_$a" 1 list; then - provides_list+=("${list[@]}") - fi - done - done - - for provide in "${provides_list[@]}"; do - if [[ $provide == *['<>']* ]]; then - error "$(gettext "%s array cannot contain comparison (< or >) operators.")" "provides" - ret=1 - fi - done - - return $ret -} - -lint_backup() { - local list name backup_list ret=0 - - backup_list=("${backup[@]}") - for name in "${pkgname[@]}"; do - if extract_function_variable "package_$name" backup 1 list; then - backup_list+=("${list[@]}") - fi - done - - for name in "${backup_list[@]}"; do - if [[ ${name:0:1} = "/" ]]; then - error "$(gettext "%s entry should not contain leading slash : %s")" "backup" "$name" - ret=1 - fi - done - - return $ret -} - -lint_optdepends() { - local a list name optdepends_list ret=0 - - optdepends_list=("${optdepends[@]}") - for a in "${arch[@]}"; do - array_build list "optdepends_$a" - optdepends_list+=("${list[@]}") - done - - for name in "${pkgname[@]}"; do - if extract_function_variable "package_$name" optdepends 1 list; then - optdepends_list+=("${list[@]}") - fi - - for a in "${arch[@]}"; do - if extract_function_variable "package_$name" "optdepends_$a" 1 list; then - optdepends_list+=("${list[@]}") - fi - done - done - - for name in "${optdepends_list[@]}"; do - local pkg=${name%%:[[:space:]]*} - # the '-' character _must_ be first or last in the character range - if [[ $pkg != +([-[:alnum:]><=.+_:]) ]]; then - error "$(gettext "Invalid syntax for %s: '%s'")" "optdepend" "$name" - ret=1 - fi - done - - return $ret -} - -check_files_exist() { - local kind=$1 files=("${@:2}") file ret - - for file in "${files[@]}"; do - if [[ $file && ! -f $file ]]; then - error "$(gettext "%s file (%s) does not exist or is not a regular file.")" \ - "$kind" "$file" - ret=1 - fi - done - - return $ret -} - -lint_install() { - local list file name install_list ret=0 - - install_list=("${install[@]}") - for name in "${pkgname[@]}"; do - extract_function_variable "package_$name" install 0 file - install_list+=("$file") - done - - check_files_exist 'install' "${install_list[@]}" -} - -lint_changelog() { - local list name file changelog_list ret=0 - - changelog_list=("${changelog[@]}") - for name in "${pkgname[@]}"; do - if extract_function_variable "package_$name" changelog 0 file; then - changelog_list+=("$file") - fi - done - - check_files_exist 'changelog' "${changelog_list[@]}" -} - -lint_options() { - local ret=0 list name kopt options_list - - options_list=("${options[@]}") - for name in "${pkgname[@]}"; do - if extract_function_variable "package_$name" options 1 list; then - options_list+=("${list[@]}") - fi - done - - for i in "${options_list[@]}"; do - # check if option matches a known option or its inverse - for kopt in "${packaging_options[@]}" "${build_options[@]}"; do - if [[ $i = "$kopt" || $i = "!$kopt" ]]; then - # continue to the next $i - continue 2 - fi - done - - error "$(gettext "%s array contains unknown option '%s'")" "options" "$i" - ret=1 - done - - return $ret -} - -lint_source() { - local idx=("${!source[@]}") - - if (( ${#source[*]} > 0 && (idx[-1] + 1) != ${#source[*]} )); then - error "$(gettext "Sparse arrays are not allowed for source")" - return 1 - fi -} - -lint_pkglist() { - local i ret=0 - - for i in "${PKGLIST[@]}"; do - if ! in_array "$i" "${pkgname[@]}"; then - error "$(gettext "Requested package %s is not provided in %s")" "$i" "$BUILDFILE" - ret=1 - fi - done - - return $ret -} - -lint_packagefn() { - local i ret=0 - - if (( ${#pkgname[@]} == 1 )); then - if have_function 'build' && ! { have_function 'package' || have_function "package_$pkgname"; }; then - error "$(gettext "Missing %s function in %s")" "package()" "$BUILDFILE" - ret=1 - fi - else - for i in "${pkgname[@]}"; do - if ! have_function "package_$i"; then - error "$(gettext "Missing %s function for split package '%s'")" "package_$i()" "$i" - ret=1 - fi - done - fi - - return $ret -} - -check_sanity() { - # check for no-no's in the build script - local ret=0 - local lintfn lint_functions - - lint_functions=( - lint_pkgbase - lint_pkgname - lint_pkgver - lint_pkgrel - lint_epoch - lint_arch - lint_provides - lint_backup - lint_optdepends - lint_changelog - lint_install - lint_options - lint_packagefn - lint_pkglist - lint_source - ) - - for lintfn in "${lint_functions[@]}"; do - "$lintfn" || ret=1 - done - - return $ret -} - -validate_pkgver() { - if [[ $1 = *[[:space:]:-]* ]]; then - error "$(gettext "%s is not allowed to contain colons, hyphens or whitespace.")" "pkgver" - return 1 - fi -} - -check_pkgver() { - if [[ -z ${pkgver} ]]; then - error "$(gettext "%s is not allowed to be empty.")" "pkgver" - return 1 - fi - - validate_pkgver "$pkgver" -} - get_vcsclient() { local proto=${1%%+*} @@ -3130,7 +2798,7 @@ if have_function pkgver; then fi # check the PKGBUILD for some basic requirements -check_sanity || exit 1 +lint_pkgbuild || exit 1 # check we have the software required to process the PKGBUILD check_software || exit 1 diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index b25e53b..43916c0 100644 --- a/scripts/po/POTFILES.in +++ b/scripts/po/POTFILES.in @@ -11,6 +11,23 @@ scripts/repo-add.sh.in scripts/libmakepkg/lint_package.sh.in scripts/libmakepkg/lint_package/build_references.sh.in scripts/libmakepkg/lint_package/missing_backup.sh.in +scripts/libmakepkg/lint_pkgbuild.sh.in +scripts/libmakepkg/lint_pkgbuild/arch.sh.in +scripts/libmakepkg/lint_pkgbuild/backup.sh.in +scripts/libmakepkg/lint_pkgbuild/changelog.sh.in +scripts/libmakepkg/lint_pkgbuild/epoch.sh.in +scripts/libmakepkg/lint_pkgbuild/install.sh.in +scripts/libmakepkg/lint_pkgbuild/optdepends.sh.in +scripts/libmakepkg/lint_pkgbuild/options.sh.in +scripts/libmakepkg/lint_pkgbuild/package_function.sh.in +scripts/libmakepkg/lint_pkgbuild/pkgbase.sh.in +scripts/libmakepkg/lint_pkgbuild/pkglist.sh.in +scripts/libmakepkg/lint_pkgbuild/pkgname.sh.in +scripts/libmakepkg/lint_pkgbuild/pkgrel.sh.in +scripts/libmakepkg/lint_pkgbuild/pkgver.sh.in +scripts/libmakepkg/lint_pkgbuild/provides.sh.in +scripts/libmakepkg/lint_pkgbuild/source.sh.in +scripts/libmakepkg/lint_pkgbuild/util.sh.in scripts/libmakepkg/tidy.sh.in scripts/libmakepkg/tidy/docs.sh.in scripts/libmakepkg/tidy/emptydirs.sh.in -- 2.4.0