debputy.dh_migration.dh_related_migrations

src/debputy/dh_migration/dh_related_migrations.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import os.path
import subprocess
from typing import Optional

from debian.debian_support import Version

from debputy.analysis.debian_dir import resolve_debhelper_config_files
from debputy.dh.debhelper_emulation import dhe_pkgfile
from debputy.dh.dh_assistant import read_dh_addon_sequences, extract_dh_compat_level
from debputy.dh_migration.models import AcceptableMigrationIssues, FeatureMigration
from debputy.highlevel_manifest import HighLevelManifest
from debputy.plugin.api import VirtualPath
from debputy.plugin.api.impl import plugin_metadata_for_debputys_own_plugin
from debputy.plugin.api.spec import DebputyIntegrationMode


def _installed_debhelper_version_is_at_least(desired_version: str) -> bool:
    try:
        output = subprocess.check_output(
            [
                "dpkg-query",
                "-W",
                "--showformat=${Version} ${db:Status-Status}\n",
                "debhelper",
            ]
        ).decode("utf-8")
    except (FileNotFoundError, subprocess.CalledProcessError):
        return False
    else:
        parts = output.split()
        if len(parts) != 2:
            return False
        if parts[1] != "installed":
            return False
        return Version(parts[0]) >= Version(desired_version)


def dh_mbm_migrate_package_files(
    debian_dir: VirtualPath,
    manifest: HighLevelManifest,
    _acceptable_migration_issues: AcceptableMigrationIssues,
    feature_migration: FeatureMigration,
    _migration_target: DebputyIntegrationMode | None,
) -> None:
    feature_migration.tagline = "Add explicit package name to debhelper config files"
    debputy_plugin_metadata = plugin_metadata_for_debputys_own_plugin()
    dh_compat_level, _ = extract_dh_compat_level()
    r = read_dh_addon_sequences(debian_dir)
    if r is not None:
        bd_sequences, dr_sequences, uses_dh_sequencer = r
        dh_sequences = bd_sequences | dr_sequences
        uses_dh_sequencer = True
    else:
        dh_sequences = set()
        uses_dh_sequencer = False

    (
        all_dh_ppfs,
        missing_introspection,
        _,
        _,
    ) = resolve_debhelper_config_files(
        debian_dir,
        {p.name: p for p in manifest.all_packages},
        debputy_plugin_metadata,
        manifest.plugin_provided_feature_set,
        dh_sequences,
        dh_compat_level,
        uses_dh_sequencer,
    )
    for ppf in all_dh_ppfs:
        if (
            ppf.uses_explicit_package_name
            or ppf.definition.packageless_is_fallback_for_all_packages
        ):
            continue
        basename = ppf.path.name
        new_basename = f"{ppf.package_name}.{basename}"
        ppf_parent = ppf.path.parent_dir
        assert ppf_parent is not None
        parent_path = ppf_parent.path
        new_path = os.path.join(parent_path, new_basename)
        feature_migration.rename_on_success(ppf.path.path, new_path)

    if not missing_introspection and not _installed_debhelper_version_is_at_least(
        "13.26~"
    ):
        feature_migration.warn(
            "Please upgrade to `debhelper/13.26` to ensure reliability. Some files might be silently missed."
        )

    for command in missing_introspection:
        feature_migration.warn(
            f"The command `{command}` is used but `dh_assistant` was not aware of whether it had configuration files."
        )

    if missing_introspection:
        feature_migration.warn(
            "Please file a bug against the provider of the commands asking them to supply the relevant hints (see doc/PROGRAMMING.md in debhelper/13.26+) with the debhelper maintainers in CC."
        )

    feature_migration.warn(
        "Any architecture restricted file (such `debian/install.amd64`) and templating based files (such as debian/install.tmpl) may be missed. Please validate these manually."
    )


def dh_mbm_migrate_manual_warnings(
    debian_dir: VirtualPath,
    manifest: HighLevelManifest,
    _acceptable_migration_issues: AcceptableMigrationIssues,
    feature_migration: FeatureMigration,
    _migration_target: DebputyIntegrationMode | None,
) -> None:
    feature_migration.tagline = "Manual parts"
    r = read_dh_addon_sequences(debian_dir)
    if r is not None:
        bd_sequences, dr_sequences, uses_dh_sequencer = r
        dh_sequences = bd_sequences | dr_sequences
        uses_dh_sequencer = True
    else:
        dh_sequences = set()
        uses_dh_sequencer = False
    drules = debian_dir.get("rules")
    if drules and drules.is_file:
        with drules.open() as fd:
            migrated_auto_install = 0
            for line in fd:
                line = line.lstrip()
                if not line or line.startswith("#"):
                    continue
                if line.startswith("\t") and "dh_auto_install" in line:
                    migrated_auto_install += 1 if "--destdir" in line else 0
    used_dh_install_files = 0
    for dctrl_bin in manifest.all_packages:
        dh_config_file = dhe_pkgfile(debian_dir, dctrl_bin, "install")
        if dh_config_file is not None:
            used_dh_install_files += 1
    main_pkg = [p for p in manifest.all_packages if p.is_main_package][0]
    if not migrated_auto_install and not used_dh_install_files:
        feature_migration.warn(
            f"Ensure `dh_auto_install --destdir debian/{main_pkg.name}` or `dh_install` is used. Remember Replaces/Breaks if files are moved"
        )
    if uses_dh_sequencer and "single-binary" in dh_sequences:
        feature_migration.warn("Remove `single-binary` add-on")