# Functions for parsing changelogs # # Copyright (C) 2012, 2018, 2019 Patrick McDermott # # This file is part of opkbuild. # # opkbuild 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 3 of the License, or # (at your option) any later version. # # opkbuild 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 opkbuild. If not, see . _ob_parse_changelog_error() { local file="${1}" local line_nr="${2}" local msg_id="${3}" shift 3 || _ob_abort local file_info= file_info="$(printf '%s(l%d)' "${file}" "${line_nr}")" _ob_warn_msg "${msg_id}" "${file_info}" "${@}" return 0 } _ob_get_changelog_expect_str() { local msg_id="${1}" shift 1 || _ob_abort _ob_get_msg "changelog_expect_${msg_id}" return 0 } ## @brief Parse a changelog file ## @details \fBob_parse_changelog\fP() parses a \fIchangelog\fP file, formatted ## as specified at ## . For ## each version entry, \fBob_parse_changelog\fP calls \fIentry_cb\fP ## with the source package name, the source package version, the list ## of distributions into which the package should be installed, the ## formatted heading (source package name, source package version, and ## distributions list) and change details, the name and e-mail address ## of the package maintainer, and the date of packaging as arguments. ## \fBob_parse_changelog\fP stops parsing either at the end of the ## \fIchangelog\fP file or when \fIentry_cb\fP returns non-zero. ## @operand file req The file to parse, or "-" for standard input. ## @operand entry_cb req Callback to run for each entry. ## @return Returns 0 after parsing. ## @stderr Prints error messages on parse errors. ## @pure maybe This function has no side effects. Whether this function is ## subshell-safe in practice depends on whether \fIentry_cb\fP is ## subshell-safe. ob_parse_changelog() { local file="${1}" local entry_cb="${2}" shift 2 || _ob_abort local line_nr= local line= local line_= local expect= local changes= local blank_lines= local source= local distribution= local version= local maintainer= local date= # Parsing logic based on that of dpkg. line_nr=0 expect='first_heading' while IFS='' read line; do line_nr=$((${line_nr} + 1)) case "${line}" in '') if [ x"${expect}" = x'start_changes' ]; then changes="${changes}${OB_LF}${line}" elif [ x"${expect}" = x'next_or_eof' ]; then : elif [ x"${expect}" != x'changes_or_trailer' ] then _ob_parse_changelog_error "${file}" \ "${line_nr}" \ 'changelog_found_blank_line' \ "$(_ob_get_changelog_expect_str\ "${expect}")" else blank_lines="${blank_lines}${OB_LF}" blank_lines="${blank_lines}${line}" fi ;; [!\ ]*) if [ x"${expect}" != x'first_heading' ] && \ [ x"${expect}" != \ x'next_or_eof' ]; then _ob_parse_changelog_error "${file}" \ "${line_nr}" \ 'changelog_found_heading' \ "$(_ob_get_changelog_expect_str\ "${expect}")" fi source="${line%% (*}" line_="${line#* (}" distribution="${line_##*) }" line_="${line_%) *}" version="${line_}" if [ -z "${source}" ] || \ [ -z "${distribution}" ] || \ [ -z "${version}" ] || \ [ x"${version% *}" != \ x"${version}" ]; then _ob_parse_changelog_error "${file}" \ "${line_nr}" \ 'changelog_bad_heading' source='' version='' distribution='' changes='' else if ! ob_validate_source_name "${source}" then _ob_parse_changelog_error \ "${file}" "${line_nr}" \ 'changelog_bad_source' \ "${source}" fi if ! ob_parse_version -- "${version}" then _ob_parse_changelog_error \ "${file}" "${line_nr}" \ "changelog_bad_sourc$(:\ )e_version" "${version}" fi changes="${line}" fi expect='start_changes' blank_lines='' ;; ' -- '*) if [ x"${expect}" != x'changes_or_trailer' ] then _ob_parse_changelog_error "${file}" \ "${line_nr}" \ 'changelog_found_trailer' \ "$(_ob_get_changelog_expect_str\ "${expect}")" fi line="${line# -- }" maintainer="${line%% *}" date="${line#* }" if [ -z "${maintainer}" ] || [ -z "${date}" ] || [ x"${maintainer}" = \ x"${date}" ]; then _ob_parse_changelog_error "${file}" \ "${line_nr}" \ 'changelog_bad_trailer' maintainer='' date='' elif [ -n "${source}" ]; then "${entry_cb}" "${source}" "${version}" \ "${distribution}" "${changes}" \ "${maintainer}" "${date}" || \ return 0 fi expect='next_or_eof' blank_lines='' ;; ' --'*) _ob_parse_changelog_error "${file}" \ "${line_nr}" 'changelog_bad_trailer' ;; ' '*) if [ x"${expect}" != x'start_changes' ] && \ [ x"${expect}" != \ x'changes_or_trailer' ]; then _ob_parse_changelog_error "${file}" \ "${line_nr}" \ 'changelog_found_change' \ "$(_ob_get_changelog_expect_str\ "${expect}")" fi changes="${changes}${OB_LF}${blank_lines}" changes="${changes}${line}" expect='changes_or_trailer' blank_lines='' ;; *) _ob_parse_changelog_error "${file}" \ "${line_nr}" 'changelog_bad_line' blank_lines='' ;; esac done <<-EOF $(cat -- "${file}") EOF if [ x"${expect}" != x'next_or_eof' ]; then _ob_parse_changelog_error "${file}" "${line_nr}" \ 'changelog_found_eof' \ "$(_ob_get_changelog_expect_str "${expect}")" fi return 0 }