summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/debputy/analysis/debian_dir.py1
-rw-r--r--src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py11
-rw-r--r--src/debputy/linting/lint_report_junit.py8
-rw-r--r--src/debputy/lsp/debputy_ls.py6
-rw-r--r--src/debputy/lsp/lsp_debian_control.py39
-rw-r--r--src/debputy/packager_provided_files.py63
6 files changed, 89 insertions, 39 deletions
diff --git a/src/debputy/analysis/debian_dir.py b/src/debputy/analysis/debian_dir.py
index 7e5b37a..68a5c1b 100644
--- a/src/debputy/analysis/debian_dir.py
+++ b/src/debputy/analysis/debian_dir.py
@@ -152,6 +152,7 @@ def scan_debian_dir(
)
details: PackagingFileInfo = {
"path": key,
+ "binary-package": ppf.package_name,
"pkgfile-stem": ppf.definition.stem,
"pkgfile-explicit-package-name": ppf.uses_explicit_package_name,
"pkgfile-is-active-in-build": ppf.definition.has_active_command,
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 d715e5a..e8e380e 100644
--- a/src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py
+++ b/src/debputy/commands/debputy_cmd/lint_and_lsp_cmds.py
@@ -1,3 +1,4 @@
+import random
import textwrap
from argparse import BooleanOptionalAction
@@ -219,9 +220,17 @@ def lsp_editor_glue(context: CommandContext) -> None:
alias_of = f" (short for: {payload})"
content.append((editor_name, alias_of))
max_name = max(len(c[0]) for c in content)
- print("This version of debputy has editor snippets for the following editors: ")
+ print(
+ "This version of debputy has instructions or editor config snippets for the following editors: "
+ )
+ print()
for editor_name, alias_of in content:
print(f" * {editor_name:<{max_name}}{alias_of}")
+ print()
+ choice = random.Random().choice(list(_EDITOR_SNIPPETS))
+ print(
+ f"Use `debputy editor-config {choice}` (as an example) to see the instructions for a concrete editor."
+ )
return
result = _EDITOR_SNIPPETS[editor_name]
while result in _EDITOR_SNIPPETS:
diff --git a/src/debputy/linting/lint_report_junit.py b/src/debputy/linting/lint_report_junit.py
index 8b1d635..2ad993a 100644
--- a/src/debputy/linting/lint_report_junit.py
+++ b/src/debputy/linting/lint_report_junit.py
@@ -51,6 +51,8 @@ class JunitLintReport(LintReport):
diagnostic_results: Iterable[LintDiagnosticResult],
duration: float,
) -> "TestCase":
+ if not duration:
+ duration = 0.000001
case = TestCase(
filename,
# The JUnit schema has `classname` as mandatory
@@ -63,9 +65,13 @@ class JunitLintReport(LintReport):
continue
diagnostic = diagnostic_result.diagnostic
severity = debputy_severity(diagnostic)
+ if diagnostic_result.is_file_level_diagnostic:
+ range_desc = "entire file"
+ else:
+ range_desc = str(diagnostic.range)
output = textwrap.dedent(
f"""\
- {filename} [{severity}] ({diagnostic.range}): {diagnostic.message}
+ {filename} [{severity}] ({range_desc}): {diagnostic.message}
"""
)
case.add_failure_info(
diff --git a/src/debputy/lsp/debputy_ls.py b/src/debputy/lsp/debputy_ls.py
index e195208..ed076cd 100644
--- a/src/debputy/lsp/debputy_ls.py
+++ b/src/debputy/lsp/debputy_ls.py
@@ -447,6 +447,10 @@ class DebputyLanguageServer(LanguageServer):
cleaned_filename = path[last_idx:]
if self.trust_language_ids and lang_id and not lang_id.isspace():
- return "editor-provided", lang_id, cleaned_filename
+ if lang_id not in ("fundamental",):
+ return "editor-provided", lang_id, cleaned_filename
+ _info(
+ f"Ignoring editor provided language ID: {lang_id} (reverting to filename based detection instead)"
+ )
return "filename", cleaned_filename, cleaned_filename
diff --git a/src/debputy/lsp/lsp_debian_control.py b/src/debputy/lsp/lsp_debian_control.py
index 370a14f..e91a43e 100644
--- a/src/debputy/lsp/lsp_debian_control.py
+++ b/src/debputy/lsp/lsp_debian_control.py
@@ -959,7 +959,7 @@ def _lint_debian_control(
def _package_range_of_stanza(
lint_state: LintState,
binary_stanzas: List[Tuple[Deb822ParagraphElement, TEPosition]],
-) -> Iterable[Tuple[str, Range]]:
+) -> Iterable[Tuple[str, Optional[str], Range]]:
for stanza, stanza_position in binary_stanzas:
kvpair = stanza.get_kvpair_element("Package")
if kvpair is None:
@@ -971,7 +971,7 @@ def _package_range_of_stanza(
lint_state.lines,
te_range_to_lsp(representation_field_range),
)
- yield stanza["Package"], representation_field_range
+ yield stanza["Package"], stanza.get("Architecture"), representation_field_range
def _detect_misspelled_packaging_files(
@@ -989,7 +989,8 @@ def _detect_misspelled_packaging_files(
debian_dir,
)
stanza_ranges = {
- p: r for p, r in _package_range_of_stanza(lint_state, binary_stanzas_w_pos)
+ p: (a, r)
+ for p, a, r in _package_range_of_stanza(lint_state, binary_stanzas_w_pos)
}
for pkg_file_data in all_pkg_file_data:
@@ -999,13 +1000,15 @@ def _detect_misspelled_packaging_files(
stem = pkg_file_data.get("pkgfile-stem")
if binary_package is None or stem is None:
continue
- diag_range = stanza_ranges.get(binary_package)
+ declared_arch, diag_range = stanza_ranges.get(binary_package)
if diag_range is None:
continue
-
path = pkg_file_data["path"]
likely_typo_of = pkg_file_data.get("likely-typo-of")
+ arch_restriction = pkg_file_data.get("pkgfile-architecture-restriction")
if likely_typo_of is not None:
+ # Handles arch_restriction == 'all' at the same time due to how
+ # the `likely-typo-of` is created
diagnostics.append(
Diagnostic(
diag_range,
@@ -1018,6 +1021,31 @@ def _detect_misspelled_packaging_files(
)
)
continue
+ if declared_arch == "all" and arch_restriction is not None:
+ diagnostics.append(
+ Diagnostic(
+ diag_range,
+ f'The file "{path}" has an architecture restriction but is for an `arch:all` package, so'
+ f" the restriction does not make sense.",
+ severity=DiagnosticSeverity.Warning,
+ source="debputy",
+ data=DiagnosticData(
+ report_for_related_file=path,
+ ),
+ )
+ )
+ elif arch_restriction == "all":
+ diagnostics.append(
+ Diagnostic(
+ diag_range,
+ f'The file "{path}" has an architecture restriction of `all` rather than a real architecture',
+ severity=DiagnosticSeverity.Warning,
+ source="debputy",
+ data=DiagnosticData(
+ report_for_related_file=path,
+ ),
+ )
+ )
if not pkg_file_data.get("pkgfile-is-active-in-build", True):
diagnostics.append(
@@ -1037,7 +1065,6 @@ def _detect_misspelled_packaging_files(
if not explicit_package and name_segment is not None:
basename = os.path.basename(path)
alt_name = f"{binary_package}.{stem}"
- arch_restriction = pkg_file_data.get("pkgfile-architecture-restriction")
if arch_restriction is not None:
alt_name = f"{alt_name}.{arch_restriction}"
diagnostics.append(
diff --git a/src/debputy/packager_provided_files.py b/src/debputy/packager_provided_files.py
index 85fff11..8e0e0af 100644
--- a/src/debputy/packager_provided_files.py
+++ b/src/debputy/packager_provided_files.py
@@ -86,42 +86,42 @@ def _find_package_name_prefix(
yield main_binary_package, path.name, False, False
+def _iterate_stem_splits(basename: str) -> Tuple[str, str, int]:
+ stem = basename
+ period_count = stem.count(".")
+ yield stem, None, period_count
+ install_as_name = ""
+ while period_count > 0:
+ period_count -= 1
+ install_as_name_part, stem = stem.split(".", 1)
+ install_as_name = (
+ install_as_name + "." + install_as_name_part
+ if install_as_name != ""
+ else install_as_name_part
+ )
+ yield stem, install_as_name, period_count
+
+
def _find_definition(
packager_provided_files: Mapping[str, PackagerProvidedFileClassSpec],
basename: str,
*,
period2stems: Optional[Mapping[int, Sequence[str]]] = None,
) -> Tuple[Optional[str], Optional[PackagerProvidedFileClassSpec], Optional[str]]:
- definition = packager_provided_files.get(basename)
- if definition is not None:
- return None, definition, None
- if period2stems and "." not in basename:
- stems = period2stems.get(0)
- matches = detect_possible_typo(basename, stems) if stems else None
- if matches and len(matches) == 1:
- definition = packager_provided_files[matches[0]]
- return None, definition, basename
- install_as_name = basename
- file_class = ""
- period_count = -1
- while "." in install_as_name:
- period_count += 1
- install_as_name, file_class_part = install_as_name.rsplit(".", 1)
- file_class = (
- file_class_part + "." + file_class if file_class != "" else file_class_part
- )
- definition = packager_provided_files.get(file_class)
+ for stem, install_as_name, period_count in _iterate_stem_splits(basename):
+ definition = packager_provided_files.get(stem)
if definition is not None:
return install_as_name, definition, None
if not period2stems:
continue
stems = period2stems.get(period_count)
+
if not stems:
continue
- matches = detect_possible_typo(file_class, stems)
- if matches and len(matches) == 1:
+ matches = detect_possible_typo(stem, stems)
+ if matches is not None and len(matches) == 1:
definition = packager_provided_files[matches[0]]
- return install_as_name, definition, file_class
+ return install_as_name, definition, stem
return None, None, None
@@ -260,13 +260,16 @@ def _split_path(
if bug_950723 and not definition.bug_950723:
continue
- _check_mismatches(
- path,
- definition,
- owning_package,
- install_as_name,
- arch_restriction is not None,
- )
+ if not allow_fuzzy_matches:
+ # LSP/Lint checks here but should not use `_check_mismatches` as
+ # the hard error disrupts them.
+ _check_mismatches(
+ path,
+ definition,
+ owning_package,
+ install_as_name,
+ arch_restriction is not None,
+ )
expected_path: Optional[str] = None
if (
@@ -321,7 +324,7 @@ def _split_path(
basename = f"{install_as_name}.{basename}"
if explicit_package:
basename = f"{package_prefix}.{basename}"
- if arch_restriction is not None:
+ if arch_restriction is not None and arch_restriction != "all":
basename = f"{basename}.{arch_restriction}"
expected_path = f"{parent_path}{basename}"
if fuzzy_match and path.name.endswith(".in"):