summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitattributes1
-rw-r--r--.gitignore19
-rw-r--r--pyproject.toml1
-rw-r--r--src/debputy/analysis/debian_dir.py54
-rw-r--r--src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py10
-rw-r--r--src/debputy/lsp/lsp_debian_control_reference_data.py42
-rw-r--r--src/debputy/lsp/lsp_features.py23
7 files changed, 106 insertions, 44 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..d9bd16b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.py text eol=lf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..34b57ec
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+__pycache__
+.pytest_cache
+.coverage
+htmlcov
+*.pyc
+*.pyo
+*~
+
+local
+local-test
+
+*.deb
+
+debian/dh-rootless
+debian/.debhelper
+debian/debhelper-build-stamp
+debian/*.substvars
+debian/files
+debian/*.debhelper.log
diff --git a/pyproject.toml b/pyproject.toml
index f0e8427..1fcca4f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,6 +2,7 @@
branch = true
source = ["."]
omit = [
+ "*/debputy/lsp/vendoring/*",
"*/lib/python*/*",
"*/dist-packages/*",
"*/tests/*",
diff --git a/src/debputy/analysis/debian_dir.py b/src/debputy/analysis/debian_dir.py
index 68a5c1b..d63b0c9 100644
--- a/src/debputy/analysis/debian_dir.py
+++ b/src/debputy/analysis/debian_dir.py
@@ -15,6 +15,7 @@ from typing import (
Iterator,
TypedDict,
NotRequired,
+ FrozenSet,
)
from debputy.analysis import REFERENCE_DATA_TABLE
@@ -277,12 +278,49 @@ def _kpf_install_pattern(
return ppkpf.info.get("install_pattern")
+def _parse_dh_cmd_list(
+ cmd_list: Optional[List[Union[Mapping[str, Any], object]]]
+) -> Iterable[str]:
+ if not isinstance(cmd_list, list):
+ return
+
+ for command in cmd_list:
+ if not isinstance(command, dict):
+ continue
+ command_name = command.get("command")
+ if isinstance(command_name, str):
+ yield command_name
+
+
+def _resolve_active_and_inactive_dh_commands(
+ dh_rules_addons: Iterable[str],
+) -> Tuple[FrozenSet[str], FrozenSet[str]]:
+ cmd = ["dh_assistant", "list-commands", "--output-format=json"]
+ if dh_rules_addons:
+ addons = ",".join(dh_rules_addons)
+ cmd.append(f"--with={addons}")
+ try:
+ output = subprocess.check_output(
+ cmd,
+ stderr=subprocess.DEVNULL,
+ )
+ except (subprocess.CalledProcessError, FileNotFoundError):
+ return frozenset(), frozenset()
+ else:
+ result = json.loads(output)
+ active_commands = frozenset(_parse_dh_cmd_list(result.get("commands")))
+ disabled_commands = frozenset(
+ _parse_dh_cmd_list(result.get("disabled-commands"))
+ )
+ return active_commands, disabled_commands
+
+
def _resolve_debhelper_config_files(
debian_dir: VirtualPath,
binary_packages: Mapping[str, BinaryPackage],
debputy_plugin_metadata: DebputyPluginMetadata,
dh_ppf_docs: Dict[str, PluginProvidedKnownPackagingFile],
- dh_rules_addons: Iterable[str],
+ dh_rules_addons: Sequence[str],
dh_compat_level: int,
saw_dh: bool,
) -> Tuple[List[PackagerProvidedFile], Optional[object], int]:
@@ -311,6 +349,7 @@ def _resolve_debhelper_config_files(
"config-files", []
)
issues = result.get("issues")
+ active_commands, _ = _resolve_active_and_inactive_dh_commands(dh_rules_addons)
for config_file in config_files:
if not isinstance(config_file, dict):
continue
@@ -369,6 +408,8 @@ def _resolve_debhelper_config_files(
else:
continue
is_active = command.get("is-active", True)
+ if is_active is None and command_name in active_commands:
+ is_active = True
if not isinstance(is_active, bool):
continue
if is_active:
@@ -396,6 +437,13 @@ def _resolve_debhelper_config_files(
"packageless_is_fallback_for_all_packages",
False,
)
+ has_active_command = (
+ ppkpf.info.get("has_active_command", False) if saw_dh else False
+ )
+ if not has_active_command:
+ dh_cmds = ppkpf.info.get("debhelper_commands")
+ if dh_cmds:
+ has_active_command = any(c in active_commands for c in dh_cmds)
dh_ppfs[stem] = _fake_PPFClassSpec(
debputy_plugin_metadata,
stem,
@@ -404,9 +452,7 @@ def _resolve_debhelper_config_files(
default_priority=default_priority,
post_formatting_rewrite=post_formatting_rewrite,
packageless_is_fallback_for_all_packages=packageless_is_fallback_for_all_packages,
- has_active_command=(
- ppkpf.info.get("has_active_command", False) if saw_dh else False
- ),
+ has_active_command=has_active_command,
)
all_dh_ppfs = list(
flatten_ppfs(
diff --git a/src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py b/src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py
index e8e380e..46b536b 100644
--- a/src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py
+++ b/src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py
@@ -246,9 +246,13 @@ def lsp_describe_features(context: CommandContext) -> None:
from debputy.lsp.lsp_self_check import assert_can_start_lsp
- assert_can_start_lsp()
-
- from debputy.lsp.lsp_features import describe_lsp_features
+ try:
+ from debputy.lsp.lsp_features import describe_lsp_features
+ except ImportError:
+ assert_can_start_lsp()
+ raise AssertionError(
+ "Cannot load the language server features but `assert_can_start_lsp` did not fail"
+ )
describe_lsp_features(context)
diff --git a/src/debputy/lsp/lsp_debian_control_reference_data.py b/src/debputy/lsp/lsp_debian_control_reference_data.py
index 9a589bf..1e32d3c 100644
--- a/src/debputy/lsp/lsp_debian_control_reference_data.py
+++ b/src/debputy/lsp/lsp_debian_control_reference_data.py
@@ -2874,12 +2874,13 @@ BINARY_FIELDS = _fields(
Conflicts: bar
```
- Please check the description of the **Breaks** field for when you would use **Breaks** vs.
- **Conflicts**.
+ Please see https://wiki.debian.org/PackageTransition for when to uses **Breaks**, **Conflicts**,
+ or/and **Replaces**.
Note if a package conflicts with itself (indirectly or via **Provides**), then it is using a
special rule for **Conflicts**. See section
- 7.6.2 "[Replacing whole packages, forcing their removal]" in the Debian Policy Manual.
+ 7.6.2 "[Replacing whole packages, forcing their removal]" in the Debian Policy Manual for the
+ details.
[Replacing whole packages, forcing their removal]: https://www.debian.org/doc/debian-policy/ch-relationships.html#replacing-whole-packages-forcing-their-removal
"""
@@ -2902,31 +2903,12 @@ BINARY_FIELDS = _fields(
Breaks: bar (<= 1.0~)
````
- **Breaks vs. Conflicts**:
+ Please see https://wiki.debian.org/PackageTransition for when to uses **Breaks**, **Conflicts**, or/and
+ **Replaces**.
- * I moved files from **foo** to **bar** in version X, what should I do?
-
- Add `Breaks: foo (<< X~)` + `Replaces: foo (<< X~)` to **bar**
-
- * Upgrading **bar** while **foo** is version X or less causes **foo** or **bar** to break.
- How do I solve this?
-
- Add `Breaks: foo (<< X~)` to **bar**
-
- * The **foo** and **bar** packages provide the same functionality (interface) but different
- implementations and there can be at most one of them. What should I do?
-
- See section 7.6.2 [Replacing whole packages, forcing their removal] in the Debian Policy Manual.
-
- * How to handle when **foo** and **bar** packages are unrelated but happen to provide the same binary?
-
- Attempt to resolve the name conflict by renaming the clashing files in question on either (or both) sides.
-
- Note the use of *~* in version numbers in the answers are generally used to ensure this works correctly in
+ Note the use of *~* in version numbers in the example is used to ensure this works correctly in
case of a backports (in the Debian archive), where the package is rebuilt with the "~bpo" suffix in its
version.
-
- [Replacing whole packages, forcing their removal]: https://www.debian.org/doc/debian-policy/ch-relationships.html#replacing-whole-packages-forcing-their-removal
"""
),
),
@@ -2939,7 +2921,7 @@ BINARY_FIELDS = _fields(
This package either replaces another package or overwrites files that used to be provided by
another package.
- **Attention**: The `Replaces` field is **always** used with either `Breaks` or `Conflicts` field.
+ **Attention**: The `Replaces` field should **always** used with either `Breaks` or `Conflicts` field.
**Example**:
```
@@ -2952,8 +2934,12 @@ BINARY_FIELDS = _fields(
Breaks: foo (<< 1.2-3~)
```
- Please check the description of the `Breaks` field for when you would use `Breaks` vs. `Conflicts`.
- It also covers common uses of `Replaces`.
+ Please see https://wiki.debian.org/PackageTransition for when to uses **Breaks**, **Conflicts**,
+ or/and **Replaces**.
+
+ Note the use of *~* in version numbers in the example is used to ensure this works correctly in
+ case of a backports (in the Debian archive), where the package is rebuilt with the "~bpo" suffix in its
+ version.
"""
),
),
diff --git a/src/debputy/lsp/lsp_features.py b/src/debputy/lsp/lsp_features.py
index 800f738..c513523 100644
--- a/src/debputy/lsp/lsp_features.py
+++ b/src/debputy/lsp/lsp_features.py
@@ -320,18 +320,23 @@ def describe_lsp_features(context: CommandContext) -> None:
print("General features:")
for self_check in LSP_CHECKS:
is_ok = self_check.test()
- assert not self_check.is_mandatory or is_ok
- if self_check.is_mandatory:
- continue
if is_ok:
print(f" * {self_check.feature}: {fo.colored('enabled', fg='green')}")
else:
- disabled = fo.colored(
- "disabled",
- fg="yellow",
- bg="black",
- style="bold",
- )
+ if self_check.is_mandatory:
+ disabled = fo.colored(
+ "missing",
+ fg="red",
+ bg="black",
+ style="bold",
+ )
+ else:
+ disabled = fo.colored(
+ "disabled",
+ fg="yellow",
+ bg="black",
+ style="bold",
+ )
if self_check.how_to_fix:
print(f" * {self_check.feature}: {disabled}")