#    __init__.py -- The plugin for bzr
#    Copyright (C) 2005 Jamie Wilkinson <jaq@debian.org>
#                  2006, 2007 James Westby <jw+debian@jameswestby.net>
#                  2007 Reinhard Tartler <siretart@tauware.de>
#                  2008 Canonical Ltd.
#
#    This file is part of brz-debian.
#
#    brz-debian 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.
#
#    brz-debian 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 brz-debian; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#

"""manage versioned Debian packages."""

import os

import breezy  # noqa: F401
from ...commands import plugin_cmds
from ...hooks import install_lazy_named_hook
from ... import trace

from .info import (  # noqa: F401
    brz_plugin_version as version_info,
)

from ...directory_service import (
    AliasDirectory,
    directories,
)

from ...i18n import load_plugin_translations
from ...tag import tag_sort_methods
from ...revisionspec import revspec_registry

translation = load_plugin_translations("brz-debian")
gettext = translation.gettext


commands = {
    "builddeb_do": ["bd-do"],
    "builddeb": ["bd", "debuild"],
    "get_orig_source": [],
    "dep3_patch": [],
    "import_dsc": [],
    "import_upstream": [],
    "merge_upstream": ["mu"],
    "debrelease": [],
}

for command, aliases in commands.items():
    plugin_cmds.register_lazy("cmd_" + command, aliases, __name__ + ".cmds")


def global_conf():
    from ...bedding import config_dir

    return os.path.join(config_dir(), "builddeb.conf")


default_build_dir = "../build-area"
default_orig_dir = ".."
default_result_dir = ".."


directories.register_lazy(
    "apt:",
    __name__ + ".directory",
    "AptDirectory",
    "Directory that uses Vcs-* control fields in apt to look up branches",
)
directories.register_lazy(
    "dgit:",
    __name__ + ".directory",
    "DgitDirectory",
    "Directory that uses Debian Dgit control fields to look up branches",
)
directories.register_lazy(
    "vcs:",
    __name__ + ".directory",
    "VcsDirectory",
    "Directory that uses local Debian Vcs-* control fields to look up branches",
)

AliasDirectory.branch_aliases.register_lazy(
    "upstream",
    __name__ + ".directory",
    "upstream_branch_alias",
    help="upstream branch (for packaging branches)",
)

tag_sort_methods.register_lazy(
    "debversion", __name__ + ".tagging", "sort_debversion", "Sort like Debian versions."
)

revspec_registry.register_lazy(
    "package:", __name__ + ".revspec", "RevisionSpec_package"
)
revspec_registry.register_lazy(
    "upstream:", __name__ + ".revspec", "RevisionSpec_upstream"
)


def debian_changelog_commit_message(commit, start_message):
    if start_message is not None:
        return start_message
    cl_path = "debian/changelog"
    if not commit.work_tree.has_filename(cl_path):
        return start_message
    if not commit.work_tree.is_versioned(cl_path):
        return start_message
    if cl_path in commit.exclude:
        return start_message
    if commit.specific_files and cl_path not in commit.specific_files:
        return start_message
    from .changelog import changelog_changes

    changes = changelog_changes(
        commit.work_tree, commit.work_tree.basis_tree(), cl_path
    )
    if not changes:
        return start_message

    from .util import strip_changelog_message

    changes = strip_changelog_message(changes)

    return "".join(changes)


def debian_changelog_commit(commit, start_message):
    """hooked into breezy.msgeditor set_commit_message.
    Set the commit message from debian/changelog and set any LP: #1234 to bug
    fixed tags."""
    from .util import find_bugs_fixed

    changes = debian_changelog_commit_message(commit, start_message)
    if changes is None:
        return None

    bugs_fixed = find_bugs_fixed([changes], commit.work_tree.branch)
    commit.builder._revprops["bugs"] = "\n".join(bugs_fixed)

    return changes


def changelog_merge_hook_factory(merger):
    from . import merge_changelog

    return merge_changelog.ChangeLogFileMerge(merger)


def tree_debian_tag_name(tree, branch, subpath="", vendor=None):
    from .config import BUILD_TYPE_MERGE
    from .import_dsc import DistributionBranch, DistributionBranchSet
    from .util import (
        debuild_config,
        find_changelog,
        MissingChangelogError,
        suite_to_distribution,
    )

    config = debuild_config(tree, subpath=subpath)
    try:
        (changelog, top_level) = find_changelog(
            tree, subpath=subpath, merge=(config.build_type == BUILD_TYPE_MERGE)
        )
    except MissingChangelogError:
        # Not a debian package
        return None
    if changelog.distributions == "UNRELEASED":
        # The changelog still targets 'UNRELEASED', so apparently hasn't been
        # uploaded. XXX: Give a warning of some sort here?
        return None
    if vendor is None:
        vendor = suite_to_distribution(changelog.distributions)
        # TODO(jelmer): Default to local vendor?
    db = DistributionBranch(branch, None)
    dbs = DistributionBranchSet()
    dbs.add_branch(db)
    return db.tag_name(changelog.version, vendor)


def debian_tag_name(branch, revid):
    subpath = ""
    t = branch.repository.revision_tree(revid)
    return tree_debian_tag_name(t, branch, subpath, vendor=None)


def pre_merge_fix_ancestry(merger):
    from .config import BUILD_TYPE_NATIVE
    from .util import debuild_config
    from .merge_package import fix_ancestry_as_needed
    from ...workingtree import WorkingTree

    if not isinstance(merger.this_tree, WorkingTree):
        return
    if getattr(merger, "other_branch", None) is None:
        return
    # This only works for packages that live in the root. That seems fine,
    # though?
    if not merger.this_tree.is_versioned(
        "debian/changelog"
    ) or not merger.other_tree.is_versioned("debian/changelog"):
        return
    this_config = debuild_config(merger.this_tree, "")
    other_config = debuild_config(merger.other_tree, "")
    if not (
        this_config.build_type == BUILD_TYPE_NATIVE
        or other_config.build_type == BUILD_TYPE_NATIVE
    ):
        from .upstream import PackageVersionNotPresent

        try:
            fix_ancestry_as_needed(
                merger.this_tree,
                merger.other_branch,
                source_revid=merger.other_tree.get_revision_id(),
            )
        except PackageVersionNotPresent as e:
            trace.warning(
                gettext(
                    "Not attempting to fix packaging branch ancestry, "
                    "missing pristine tar data for version %s."
                ),
                e.version,
            )


install_lazy_named_hook(
    "breezy.msgeditor",
    "hooks",
    "commit_message_template",
    debian_changelog_commit_message,
    "Use changes documented in debian/changelog to suggest the commit message",
)
install_lazy_named_hook(
    "breezy.merge",
    "Merger.hooks",
    "merge_file_content",
    changelog_merge_hook_factory,
    "Debian Changelog file merge",
)
install_lazy_named_hook(
    "breezy.branch",
    "Branch.hooks",
    "automatic_tag_name",
    debian_tag_name,
    "Automatically determine tag names from Debian version",
)
install_lazy_named_hook(
    "breezy.merge",
    "Merger.hooks",
    "pre_merge_fix_ancestry",
    pre_merge_fix_ancestry,
    "Debian ancestry fixing",
)


def load_tests(loader, basic_tests, pattern):
    basic_tests.addTest(loader.loadTestsFromModuleNames([__name__ + ".tests"]))
    return basic_tests
