From 61af955c3bb6acaf27d292bf611521b050194caf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 26 Jun 2024 08:32:44 +0200 Subject: Merging upstream version 0.1.38. Signed-off-by: Daniel Baumann --- src/debputy/analysis/debian_dir.py | 1 + .../commands/debputy_cmd/lint_and_lsp_cmds.py | 11 +++- src/debputy/linting/lint_report_junit.py | 8 ++- src/debputy/lsp/debputy_ls.py | 6 ++- src/debputy/lsp/lsp_debian_control.py | 39 +++++++++++--- src/debputy/packager_provided_files.py | 63 +++++++++++----------- 6 files changed, 89 insertions(+), 39 deletions(-) (limited to 'src') 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"): -- cgit v1.2.3