"""This script renames the forthcoming section in changelog files with the upcoming version and the current date"""

from __future__ import print_function

import argparse
import datetime
import docutils.core
import os
import re
import sys

from catkin_pkg.changelog import CHANGELOG_FILENAME, get_changelog_from_path
from catkin_pkg.changelog_generator import FORTHCOMING_LABEL
from catkin_pkg.package_version import bump_version
from catkin_pkg.packages import find_packages, verify_equal_package_versions


def get_forthcoming_label(rst):
    document = docutils.core.publish_doctree(rst)
    forthcoming_label = None
    for child in document.children:
        title = None
        if isinstance(child, docutils.nodes.subtitle):
            title = child
        elif isinstance(child, docutils.nodes.section):
            section = child
            if len(section.children) > 0 and isinstance(section.children[0], docutils.nodes.title):
                title = section.children[0]
        if title and len(title.children) > 0 and isinstance(title.children[0], docutils.nodes.Text):
            title_text = title.children[0].rawsource
            if FORTHCOMING_LABEL.lower() in title_text.lower():
                if forthcoming_label:
                    raise RuntimeError('Found multiple forthcoming sections')
                forthcoming_label = title_text
    return forthcoming_label


def rename_section(data, old_label, new_label):
    valid_section_characters = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

    def replace_section(match):
        section_char = match.group(2)[0]
        return new_label + '\n' + section_char * len(new_label)
    pattern = '^(' + re.escape(old_label) + ')\n([' + re.escape(valid_section_characters) + ']+)$'
    data, count = re.subn(pattern, replace_section, data, flags=re.MULTILINE)
    if count == 0:
        raise RuntimeError('Could not find section')
    if count > 1:
        raise RuntimeError('Found multiple matching sections')
    return data


def main(sysargs=None):
    parser = argparse.ArgumentParser(description='Tag the forthcoming section in the changelog files with an upcoming version number')
    parser.add_argument('--bump', choices=('major', 'minor', 'patch'), default='patch', help='Which part of the version number to bump? (default: %(default)s)')
    args = parser.parse_args(sysargs)

    base_path = '.'

    # find packages
    packages = find_packages(base_path)
    if not packages:
        raise RuntimeError('No packages found')
    print('Found packages: %s' % ', '.join([p.name for p in packages.values()]))

    # fetch current version and verify that all packages have same version number
    old_version = verify_equal_package_versions(packages.values())
    new_version = bump_version(old_version, args.bump)
    print('Tag version %s' % new_version)

    # check for changelog entries
    changelogs = []
    missing_forthcoming = []
    already_tagged = []
    for pkg_path, package in packages.items():
        changelog_path = os.path.join(base_path, pkg_path, CHANGELOG_FILENAME)
        if not os.path.exists(changelog_path):
            missing_forthcoming.append(package.name)
            continue
        changelog = get_changelog_from_path(changelog_path, package.name)
        if not changelog:
            missing_forthcoming.append(package.name)
            continue
        # check that forthcoming section exists
        forthcoming_label = get_forthcoming_label(changelog.rst)
        if not forthcoming_label:
            missing_forthcoming.append(package.name)
            continue
        # check that new_version section does not exist yet
        try:
            changelog.get_content_of_version(new_version)
            already_tagged.append(package.name)
            continue
        except KeyError:
            pass
        changelogs.append((package.name, changelog_path, changelog, forthcoming_label))
    if missing_forthcoming:
        print('The following packages do not have a forthcoming section in their changelog file: %s' % ', '.join(sorted(missing_forthcoming)), file=sys.stderr)
    if already_tagged:
        print("The following packages do already have a section '%s' in their changelog file: %s" % (new_version, ', '.join(sorted(already_tagged))), file=sys.stderr)

    # rename forthcoming sections to new_version including current date
    new_changelog_data = []
    new_label = '%s (%s)' % (new_version, datetime.date.today().isoformat())
    for (pkg_name, changelog_path, changelog, forthcoming_label) in changelogs:
        print("Renaming section '%s' to '%s' in package '%s'..." % (forthcoming_label, new_label, pkg_name))
        data = rename_section(changelog.rst, forthcoming_label, new_label)
        new_changelog_data.append((changelog_path, data))

    print('Writing updated changelog files...')
    for (changelog_path, data) in new_changelog_data:
        with open(changelog_path, 'wb') as f:
            f.write(data.encode('utf-8'))

[((45, 18, 45, 77), 're.subn', 're.subn', (), '', False, 'import re\n'), ((54, 13, 54, 134), 'argparse.ArgumentParser', 'argparse.ArgumentParser', (), '', False, 'import argparse\n'), ((61, 15, 61, 39), 'catkin_pkg.packages.find_packages', 'find_packages', ({(61, 29, 61, 38): 'base_path'}, {}), '(base_path)', False, 'from catkin_pkg.packages import find_packages, verify_equal_package_versions\n'), ((68, 18, 68, 54), 'catkin_pkg.package_version.bump_version', 'bump_version', ({(68, 31, 68, 42): 'old_version', (68, 44, 68, 53): 'args.bump'}, {}), '(old_version, args.bump)', False, 'from catkin_pkg.package_version import bump_version\n'), ((76, 25, 76, 78), 'os.path.join', 'os.path.join', ({(76, 38, 76, 47): 'base_path', (76, 49, 76, 57): 'pkg_path', (76, 59, 76, 77): 'CHANGELOG_FILENAME'}, {}), '(base_path, pkg_path, CHANGELOG_FILENAME)', False, 'import os\n'), ((80, 20, 80, 73), 'catkin_pkg.changelog.get_changelog_from_path', 'get_changelog_from_path', ({(80, 44, 80, 58): 'changelog_path', (80, 60, 80, 72): 'package.name'}, {}), '(changelog_path, package.name)', False, 'from catkin_pkg.changelog import CHANGELOG_FILENAME, get_changelog_from_path\n'), ((44, 54, 44, 89), 're.escape', 're.escape', ({(44, 64, 44, 88): 'valid_section_characters'}, {}), '(valid_section_characters)', False, 'import re\n'), ((77, 15, 77, 45), 'os.path.exists', 'os.path.exists', ({(77, 30, 77, 44): 'changelog_path'}, {}), '(changelog_path)', False, 'import os\n'), ((31, 15, 31, 40), 'catkin_pkg.changelog_generator.FORTHCOMING_LABEL.lower', 'FORTHCOMING_LABEL.lower', ({}, {}), '()', False, 'from catkin_pkg.changelog_generator import FORTHCOMING_LABEL\n'), ((44, 21, 44, 41), 're.escape', 're.escape', ({(44, 31, 44, 40): 'old_label'}, {}), '(old_label)', False, 'import re\n'), ((104, 42, 104, 63), 'datetime.date.today', 'datetime.date.today', ({}, {}), '()', False, 'import datetime\n')]