From 92d0540ad05ea5d6bf0869ff74cc1d0c81f6b2da Mon Sep 17 00:00:00 2001 From: Tiago Nobrega Date: Thu, 16 Mar 2023 10:43:46 -0300 Subject: [PATCH 1/2] linters: allow "categories" for subfiltering This commit adds the notion of "categories" for Linter subclasses. For linters that perform multiple different "types" of linting, this lets the author ignore specific paths for specific types of linting issues, with a finer granularity than ignoring the whole linter wholesale. Currently the only Linter type that supports this is the LibraryLinter, which provides the "unused-library" and "missing-library" categories to disable checking for unused or missing libraries. --- snapcraft/linters/base.py | 43 ++++++-- snapcraft/linters/library_linter.py | 48 +++++---- snapcraft/linters/linters.py | 5 + .../expected_linter_output.txt | 4 + .../library-ignored-mixed/snap/snapcraft.yaml | 34 +++++++ .../library-ignored-mixed/src/test_missing.c | 7 ++ .../library-ignored-mixed/src/test_unused.c | 5 + .../linters/library-ignored-mixed/task.yaml | 13 +++ tests/unit/linters/test_library_linter.py | 69 ++++++++++++- tests/unit/linters/test_linters.py | 97 +++++++++++++++---- 10 files changed, 275 insertions(+), 50 deletions(-) create mode 100644 tests/spread/core22/linters/library-ignored-mixed/expected_linter_output.txt create mode 100644 tests/spread/core22/linters/library-ignored-mixed/snap/snapcraft.yaml create mode 100644 tests/spread/core22/linters/library-ignored-mixed/src/test_missing.c create mode 100644 tests/spread/core22/linters/library-ignored-mixed/src/test_unused.c create mode 100644 tests/spread/core22/linters/library-ignored-mixed/task.yaml diff --git a/snapcraft/linters/base.py b/snapcraft/linters/base.py index 3e83d2c2b5..c8a819c5b0 100644 --- a/snapcraft/linters/base.py +++ b/snapcraft/linters/base.py @@ -19,7 +19,8 @@ import abc import enum import fnmatch -from typing import TYPE_CHECKING, List, Literal, Optional +from pathlib import Path +from typing import TYPE_CHECKING, List, Literal, Optional, Union import pydantic from craft_cli import emit @@ -103,14 +104,44 @@ def run(self) -> List[LinterIssue]: :return: A list of linter issues flagged by this linter. """ - def _is_file_ignored(self, elf_file: ElfFile) -> bool: - """Check if the file name matches an ignored file pattern.""" - for pattern in self._lint.ignored_files(self._name): - if fnmatch.fnmatch(str(elf_file.path), pattern): + def _is_file_ignored( + self, filepath: Union[ElfFile, Path], category: str = "" + ) -> bool: + """Check if the file name matches an ignored file pattern. + + :param category: + For linters that implement categories, the specific category that + should be checked for the ignored patterns. `filepath` will be checked + against the linter's "main" patterns (based on the linter's name) *and* + against the category-specific patterns. + """ + ignored_files = self._lint.ignored_files(self._name) + + if category: + # No "extend()" because we don't want to affect the original list. + ignored_files = ignored_files + self._lint.ignored_files(category) + + if isinstance(filepath, ElfFile): + path = filepath.path + else: + path = filepath + + for pattern in ignored_files: + if fnmatch.fnmatch(str(path), pattern): emit.debug( - f"{self._name} linter: skip file {str(elf_file.path)!r} " + f"{self._name} linter: skip file {str(path)!r} " f"(matches {pattern!r})" ) return True return False + + @staticmethod + def get_categories() -> List[str]: + """Get a list of specific subcategories that can be filtered against. + + For Linter subclasses that perform multiple "kinds" of linting, this + must return the list of names that can be used to selectively ignore + parts of the linting behavior for given paths. + """ + return [] diff --git a/snapcraft/linters/library_linter.py b/snapcraft/linters/library_linter.py index 922cccb1e1..a6c5976919 100644 --- a/snapcraft/linters/library_linter.py +++ b/snapcraft/linters/library_linter.py @@ -15,7 +15,6 @@ # along with this program. If not, see . """Library linter implementation.""" - from pathlib import Path from typing import List, Set @@ -31,6 +30,11 @@ class LibraryLinter(Linter): """Linter for dynamic library availability in snap.""" + @staticmethod + def get_categories() -> List[str]: + """Get the specific sub-categories that can be filtered against.""" + return ["unused-library", "missing-library"] + @overrides def run(self) -> List[LinterIssue]: if self._snap_metadata.type not in ("app", None): @@ -49,13 +53,19 @@ def run(self) -> List[LinterIssue]: used_libraries: Set[Path] = set() for elf_file in elf_files: - # Skip linting files listed in the ignore list. + # Skip linting files listed in the ignore list for the main "library" + # filter. if self._is_file_ignored(elf_file): continue arch_triplet = elf_utils.get_arch_triplet() content_dirs = self._snap_metadata.get_provider_content_directories() + # if the elf file is a library, add it to the list of all libraries + if elf_file.soname and self._is_library_path(elf_file.path): + # resolve symlinks to libraries + all_libraries.add(elf_file.path.resolve()) + dependencies = elf_file.load_dependencies( root_path=current_path.absolute(), base_path=installed_base_path, @@ -73,21 +83,19 @@ def run(self) -> List[LinterIssue]: # resolve symlinks to libraries used_libraries.add(dependency.resolve()) - # if the elf file is a library, add it to the list of all libraries - if elf_file.soname and self._is_library_path(elf_file.path): - # resolve symlinks to libraries - all_libraries.add(elf_file.path.resolve()) - - search_paths = [current_path.absolute(), *content_dirs] - if installed_base_path: - search_paths.append(installed_base_path) - - self._check_dependencies_satisfied( - elf_file, - search_paths=search_paths, - dependencies=sorted(dependencies), - issues=issues, - ) + # Check whether all dependencies are satisfied, *if* the missing-library + # category is not filtered out for the elf file's path. + if not self._is_file_ignored(elf_file, "missing-library"): + search_paths = [current_path.absolute(), *content_dirs] + if installed_base_path: + search_paths.append(installed_base_path) + + self._check_dependencies_satisfied( + elf_file, + search_paths=search_paths, + dependencies=sorted(dependencies), + issues=issues, + ) issues.extend(self._get_unused_library_issues(all_libraries, used_libraries)) @@ -159,12 +167,12 @@ def _get_unused_library_issues( emit.debug(f"could not resolve path for library {library_path!r}") continue - library = ElfFile(path=resolved_library_path) - # skip linting files listed in the ignore list - if self._is_file_ignored(library): + if self._is_file_ignored(resolved_library_path, "unused-library"): continue + library = ElfFile(path=resolved_library_path) + issue = LinterIssue( name=self._name, result=LinterResult.WARNING, diff --git a/snapcraft/linters/linters.py b/snapcraft/linters/linters.py index 89be9193ee..ee88fc5ab5 100644 --- a/snapcraft/linters/linters.py +++ b/snapcraft/linters/linters.py @@ -141,6 +141,11 @@ def run_linters(location: Path, *, lint: Optional[projects.Lint]) -> List[Linter if lint and lint.all_ignored(name): continue + categories = linter_class.get_categories() + + if lint and categories and all(lint.all_ignored(c) for c in categories): + continue + linter = linter_class(name=name, lint=lint, snap_metadata=snap_metadata) emit.progress(f"Running linter: {name}") issues = linter.run() diff --git a/tests/spread/core22/linters/library-ignored-mixed/expected_linter_output.txt b/tests/spread/core22/linters/library-ignored-mixed/expected_linter_output.txt new file mode 100644 index 0000000000..e1fabef93a --- /dev/null +++ b/tests/spread/core22/linters/library-ignored-mixed/expected_linter_output.txt @@ -0,0 +1,4 @@ +Running linters... +Running linter: classic +Running linter: library +Creating snap package... diff --git a/tests/spread/core22/linters/library-ignored-mixed/snap/snapcraft.yaml b/tests/spread/core22/linters/library-ignored-mixed/snap/snapcraft.yaml new file mode 100644 index 0000000000..38c8b10f63 --- /dev/null +++ b/tests/spread/core22/linters/library-ignored-mixed/snap/snapcraft.yaml @@ -0,0 +1,34 @@ +name: library-ignore-mixed +base: core22 +version: '0.1' +summary: Ignore a mix of unused and missing library linter issues +description: spread test + +grade: devel +confinement: strict + +lint: + ignore: + - unused-library: + - usr/lib/*/libpng16.so* + - missing-library: + - linter-test-missing + +parts: + unused-part: + plugin: nil + source: src + stage-packages: + - libpng16-16 + override-build: + gcc -o $CRAFT_PART_INSTALL/linter-test-unused test_unused.c + + missing-part: + plugin: nil + source: src + build-packages: + - gcc + - libcaca-dev + override-build: + gcc -o $CRAFT_PART_INSTALL/linter-test-missing test_missing.c -lcaca + diff --git a/tests/spread/core22/linters/library-ignored-mixed/src/test_missing.c b/tests/spread/core22/linters/library-ignored-mixed/src/test_missing.c new file mode 100644 index 0000000000..1b6f17fc0f --- /dev/null +++ b/tests/spread/core22/linters/library-ignored-mixed/src/test_missing.c @@ -0,0 +1,7 @@ +#include "caca.h" + +int main() +{ + caca_create_canvas(80, 24); + return 0; +} diff --git a/tests/spread/core22/linters/library-ignored-mixed/src/test_unused.c b/tests/spread/core22/linters/library-ignored-mixed/src/test_unused.c new file mode 100644 index 0000000000..dcfb86bc74 --- /dev/null +++ b/tests/spread/core22/linters/library-ignored-mixed/src/test_unused.c @@ -0,0 +1,5 @@ +#include +int main() { + printf("Hello, World!"); + return 0; +} diff --git a/tests/spread/core22/linters/library-ignored-mixed/task.yaml b/tests/spread/core22/linters/library-ignored-mixed/task.yaml new file mode 100644 index 0000000000..c80169d420 --- /dev/null +++ b/tests/spread/core22/linters/library-ignored-mixed/task.yaml @@ -0,0 +1,13 @@ +summary: Ignore mixed library linter issues + +restore: | + snapcraft clean + rm -f ./*.snap ./*.txt + +execute: | + snapcraft 2> output.txt + + test -f library-ignore-mixed_0.1_*.snap + + sed -n '/^Running linters/,/^Creating snap/p' < output.txt > linter_output.txt + diff -u linter_output.txt expected_linter_output.txt diff --git a/tests/unit/linters/test_library_linter.py b/tests/unit/linters/test_library_linter.py index d662b8678a..d10515ffd3 100644 --- a/tests/unit/linters/test_library_linter.py +++ b/tests/unit/linters/test_library_linter.py @@ -133,7 +133,11 @@ def test_library_linter_unused_library(mocker, new_dir): ] -def test_library_linter_filter_missing_library(mocker, new_dir): +@pytest.mark.parametrize( + "filter_name", + ("library", "missing-library"), +) +def test_library_linter_filter_missing_library(mocker, new_dir, filter_name): """Verify missing libraries can be filtered out.""" shutil.copy("/bin/true", "elf.bin") @@ -164,12 +168,16 @@ def test_library_linter_filter_missing_library(mocker, new_dir): ) issues = linters.run_linters( - new_dir, lint=projects.Lint(ignore=[{"library": ["elf.*"]}]) + new_dir, lint=projects.Lint(ignore=[{filter_name: ["elf.*"]}]) ) assert issues == [] -def test_library_linter_filter_unused_library(mocker, new_dir): +@pytest.mark.parametrize( + "filter_name", + ("library", "unused-library"), +) +def test_library_linter_filter_unused_library(mocker, new_dir, filter_name): """Verify unused libraries can be filtered out.""" # mock an elf file mock_elf_file = Mock(spec=_elf_file.ElfFile) @@ -210,11 +218,64 @@ def test_library_linter_filter_unused_library(mocker, new_dir): ) issues = linters.run_linters( - new_dir, lint=projects.Lint(ignore=[{"library": ["lib/libfoo.*"]}]) + new_dir, lint=projects.Lint(ignore=[{filter_name: ["lib/libfoo.*"]}]) ) assert issues == [] +def test_library_linter_mixed_filters(mocker, new_dir): + """Check that filtering *missing* libraries does not affect *unused* ones.""" + + # mock a library + mock_library = Mock(spec=_elf_file.ElfFile) + mock_library.soname = "libfoo.so" + mock_library.path = Path("lib/libfoo.so") + mock_library.load_dependencies.return_value = [] + + mocker.patch( + "snapcraft.linters.library_linter.elf_utils.get_elf_files", + return_value=[mock_library], + ) + + mocker.patch("snapcraft.linters.library_linter.ElfFile", return_value=mock_library) + mocker.patch("snapcraft.linters.library_linter.Path.is_file", return_value=True) + mocker.patch("snapcraft.linters.linters.LINTERS", {"library": LibraryLinter}) + + yaml_data = { + "name": "mytest", + "version": "1.29.3", + "base": "core22", + "summary": "Single-line elevator pitch for your amazing snap", + "description": "test-description", + "confinement": "strict", + "parts": {}, + } + + project = projects.Project.unmarshal(yaml_data) + snap_yaml.write( + project, + prime_dir=Path(new_dir), + arch="amd64", + arch_triplet="x86_64-linux-gnu", + ) + + # lib/libfoo.so is an *unused* library, but here we filter out *missing* library + # issues for this path. + issues = linters.run_linters( + new_dir, lint=projects.Lint(ignore=[{"missing-library": ["lib/libfoo.*"]}]) + ) + # The "unused library" issue must be generated. + assert issues == [ + LinterIssue( + name="library", + result=LinterResult.WARNING, + filename="libfoo.so", + text="unused library 'lib/libfoo.so'.", + url="https://snapcraft.io/docs/linters-library", + ), + ] + + @pytest.mark.parametrize( "path, expected_result", [ diff --git a/tests/unit/linters/test_linters.py b/tests/unit/linters/test_linters.py index 8a9489fbc1..ea6c7ae09e 100644 --- a/tests/unit/linters/test_linters.py +++ b/tests/unit/linters/test_linters.py @@ -16,7 +16,7 @@ from pathlib import Path from typing import List -from unittest.mock import call +from unittest.mock import MagicMock, call import pytest from overrides import overrides @@ -128,26 +128,32 @@ def test_linter_status(self, linter_issue, results, expected_status): assert status == expected_status +class _TestLinter(Linter): + @overrides + def run(self) -> List[linters.LinterIssue]: + assert self._snap_metadata.name == "mytest" + return [ + linters.LinterIssue( + name="test", + result=LinterResult.WARNING, + text="Something wrong.", + url="https://some/url", + ) + ] + + @staticmethod + def get_categories() -> List[str]: + return ["test-1", "test-2"] + + def is_file_ignored(self, filepath: Path, category: str = "") -> bool: + return self._is_file_ignored(filepath, category) + + class TestLinterRun: """Check linter execution.""" - class _TestLinter(Linter): - @overrides - def run(self) -> List[linters.LinterIssue]: - assert self._snap_metadata.name == "mytest" - return [ - linters.LinterIssue( - name="test", - result=LinterResult.WARNING, - text="Something wrong.", - url="https://some/url", - ) - ] - def test_run_linters(self, mocker, new_dir, linter_issue): - mocker.patch( - "snapcraft.linters.linters.LINTERS", {"test": TestLinterRun._TestLinter} - ) + mocker.patch("snapcraft.linters.linters.LINTERS", {"test": _TestLinter}) yaml_data = { "name": "mytest", "version": "1.29.3", @@ -177,9 +183,7 @@ def test_run_linters(self, mocker, new_dir, linter_issue): ] def test_run_linters_ignore(self, mocker, new_dir, linter_issue): - mocker.patch( - "snapcraft.linters.linters.LINTERS", {"test": TestLinterRun._TestLinter} - ) + mocker.patch("snapcraft.linters.linters.LINTERS", {"test": _TestLinter}) yaml_data = { "name": "mytest", "version": "1.29.3", @@ -202,6 +206,32 @@ def test_run_linters_ignore(self, mocker, new_dir, linter_issue): issues = linters.run_linters(new_dir, lint=lint) assert issues == [] + def test_run_linters_ignore_all_categories(self, mocker, new_dir, linter_issue): + """Verify that if the spec ignores all categories one-by-one, run_linters() + exits early with no issues.""" + mocker.patch("snapcraft.linters.linters.LINTERS", {"test": _TestLinter}) + yaml_data = { + "name": "mytest", + "version": "1.29.3", + "base": "core22", + "summary": "Single-line elevator pitch for your amazing snap", + "description": "test-description", + "confinement": "strict", + "parts": {}, + } + + project = projects.Project.unmarshal(yaml_data) + snap_yaml.write( + project, + prime_dir=Path(new_dir), + arch="amd64", + arch_triplet="x86_64-linux-gnu", + ) + + lint = projects.Lint(ignore=["test-1", "test-2"]) + issues = linters.run_linters(new_dir, lint=lint) + assert issues == [] + def test_ignore_matching_filenames(self, linter_issue): lint = projects.Lint(ignore=[{"test": ["foo*", "some/dir/*"]}]) issues = [ @@ -218,3 +248,30 @@ def test_ignore_matching_filenames(self, linter_issue): linter_issue(filename="some/dir/baz.txt", result=LinterResult.IGNORED), linter_issue(filename="other/dir/quux.txt", result=LinterResult.ERROR), ] + + +def test_base_linter_is_file_ignored(): + """Test the base Linter class' ignore mechanism with categories.""" + lint = projects.Lint( + ignore=[ + {"test": ["test-path"]}, + {"test-1": ["test-1-path"]}, + {"test-2": ["test-2-path"]}, + ] + ) + linter = _TestLinter(name="test", snap_metadata=MagicMock(), lint=lint) + + # The "test-path" Path must be ignored by the "main" filter and all categories. + assert linter.is_file_ignored(Path("test-path")) + assert linter.is_file_ignored(Path("test-path", category="test-1")) + assert linter.is_file_ignored(Path("test-path", category="test-2")) + + # "test-1-path" is ignored by the "test-1" only + assert not linter.is_file_ignored(Path("test-1-path")) + assert linter.is_file_ignored(Path("test-1-path"), category="test-1") + assert not linter.is_file_ignored(Path("test-1-path"), category="test-2") + + # Likewise for "test-2-path" is ignored by the "test-2" only + assert not linter.is_file_ignored(Path("test-2-path")) + assert not linter.is_file_ignored(Path("test-2-path"), category="test-1") + assert linter.is_file_ignored(Path("test-2-path"), category="test-2") From 4ac70be17314cbdd33793716793e8e7d90b71d1e Mon Sep 17 00:00:00 2001 From: Tiago Nobrega Date: Fri, 17 Mar 2023 17:25:44 -0300 Subject: [PATCH 2/2] ros2_humble: add unused-library lint ignores This lets us ignore the many (40+) "unused library" warnings that the linter emits for the libraries in opt/ros/ and related. --- snapcraft/extensions/ros2_humble.py | 25 +++++++++- .../expected_linter_output.txt | 46 +++++++++++++++++++ .../snap/snapcraft.yaml | 32 +++++++++++++ .../linter-ros2-humble-mixed/task.yaml | 13 ++++++ .../expected_linter_output.txt | 4 ++ .../linter-ros2-humble/snap/snapcraft.yaml | 18 ++++++++ .../linters/linter-ros2-humble/task.yaml | 13 ++++++ .../unit/parts/extensions/test_ros2_humble.py | 25 +++++++++- 8 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 tests/spread/core22/linters/linter-ros2-humble-mixed/expected_linter_output.txt create mode 100644 tests/spread/core22/linters/linter-ros2-humble-mixed/snap/snapcraft.yaml create mode 100644 tests/spread/core22/linters/linter-ros2-humble-mixed/task.yaml create mode 100644 tests/spread/core22/linters/linter-ros2-humble/expected_linter_output.txt create mode 100644 tests/spread/core22/linters/linter-ros2-humble/snap/snapcraft.yaml create mode 100644 tests/spread/core22/linters/linter-ros2-humble/task.yaml diff --git a/snapcraft/extensions/ros2_humble.py b/snapcraft/extensions/ros2_humble.py index 67c3de6d4e..a5a1400f46 100644 --- a/snapcraft/extensions/ros2_humble.py +++ b/snapcraft/extensions/ros2_humble.py @@ -60,7 +60,30 @@ def get_root_snippet(self) -> Dict[str, Any]: "key-server": "keyserver.ubuntu.com", "suites": ["jammy"], } - ] + ], + "lint": { + "ignore": [ + { + "unused-library": [ + "opt/ros/*", + "lib/*/libcrypt.so*", + "lib/*/libexpat.so*", + "lib/*/libtirpc.so*", + "lib/*/libz.so*", + "usr/lib/*libatomic.so*", + "usr/lib/*libconsole_bridge.so*", + "usr/lib/*libfmt.so*", + "usr/lib/*libicui18n.so*", + "usr/lib/*libicuio.so*", + "usr/lib/*libicutest.so*", + "usr/lib/*libicutu.so*", + "usr/lib/*libpython3.10.so*", + "usr/lib/*libspdlog.so*", + "usr/lib/*libtinyxml2.so*", + ] + } + ] + }, } @overrides diff --git a/tests/spread/core22/linters/linter-ros2-humble-mixed/expected_linter_output.txt b/tests/spread/core22/linters/linter-ros2-humble-mixed/expected_linter_output.txt new file mode 100644 index 0000000000..2442be15bb --- /dev/null +++ b/tests/spread/core22/linters/linter-ros2-humble-mixed/expected_linter_output.txt @@ -0,0 +1,46 @@ +Running linters... +Running linter: classic +Running linter: library +Lint warnings: +- library: libcrypt.so.1: unused library 'lib/x86_64-linux-gnu/libcrypt.so.1'. (https://snapcraft.io/docs/linters-library) +- library: libexpat.so.1: unused library 'lib/x86_64-linux-gnu/libexpat.so.1.8.7'. (https://snapcraft.io/docs/linters-library) +- library: libtirpc.so.3: unused library 'lib/x86_64-linux-gnu/libtirpc.so.3.0.0'. (https://snapcraft.io/docs/linters-library) +- library: libz.so.1: unused library 'lib/x86_64-linux-gnu/libz.so.1.2.11'. (https://snapcraft.io/docs/linters-library) +- library: libaction_msgs__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/libaction_msgs__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: libaction_msgs__rosidl_typesupport_cpp.so: unused library 'opt/ros/humble/lib/libaction_msgs__rosidl_typesupport_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: libaction_msgs__rosidl_typesupport_fastrtps_c.so: unused library 'opt/ros/humble/lib/libaction_msgs__rosidl_typesupport_fastrtps_c.so'. (https://snapcraft.io/docs/linters-library) +- library: libaction_msgs__rosidl_typesupport_fastrtps_cpp.so: unused library 'opt/ros/humble/lib/libaction_msgs__rosidl_typesupport_fastrtps_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: libaction_msgs__rosidl_typesupport_introspection_c.so: unused library 'opt/ros/humble/lib/libaction_msgs__rosidl_typesupport_introspection_c.so'. (https://snapcraft.io/docs/linters-library) +- library: libaction_msgs__rosidl_typesupport_introspection_cpp.so: unused library 'opt/ros/humble/lib/libaction_msgs__rosidl_typesupport_introspection_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: libbuiltin_interfaces__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/libbuiltin_interfaces__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: libbuiltin_interfaces__rosidl_typesupport_cpp.so: unused library 'opt/ros/humble/lib/libbuiltin_interfaces__rosidl_typesupport_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: liblifecycle_msgs__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/liblifecycle_msgs__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: liblifecycle_msgs__rosidl_typesupport_cpp.so: unused library 'opt/ros/humble/lib/liblifecycle_msgs__rosidl_typesupport_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: liblifecycle_msgs__rosidl_typesupport_fastrtps_c.so: unused library 'opt/ros/humble/lib/liblifecycle_msgs__rosidl_typesupport_fastrtps_c.so'. (https://snapcraft.io/docs/linters-library) +- library: liblifecycle_msgs__rosidl_typesupport_fastrtps_cpp.so: unused library 'opt/ros/humble/lib/liblifecycle_msgs__rosidl_typesupport_fastrtps_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: liblifecycle_msgs__rosidl_typesupport_introspection_c.so: unused library 'opt/ros/humble/lib/liblifecycle_msgs__rosidl_typesupport_introspection_c.so'. (https://snapcraft.io/docs/linters-library) +- library: liblifecycle_msgs__rosidl_typesupport_introspection_cpp.so: unused library 'opt/ros/humble/lib/liblifecycle_msgs__rosidl_typesupport_introspection_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librcl_interfaces__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/librcl_interfaces__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: librcl_interfaces__rosidl_typesupport_cpp.so: unused library 'opt/ros/humble/lib/librcl_interfaces__rosidl_typesupport_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librcl_interfaces__rosidl_typesupport_fastrtps_c.so: unused library 'opt/ros/humble/lib/librcl_interfaces__rosidl_typesupport_fastrtps_c.so'. (https://snapcraft.io/docs/linters-library) +- library: librcl_interfaces__rosidl_typesupport_fastrtps_cpp.so: unused library 'opt/ros/humble/lib/librcl_interfaces__rosidl_typesupport_fastrtps_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librcl_interfaces__rosidl_typesupport_introspection_c.so: unused library 'opt/ros/humble/lib/librcl_interfaces__rosidl_typesupport_introspection_c.so'. (https://snapcraft.io/docs/linters-library) +- library: librcl_interfaces__rosidl_typesupport_introspection_cpp.so: unused library 'opt/ros/humble/lib/librcl_interfaces__rosidl_typesupport_introspection_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librmw_dds_common__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/librmw_dds_common__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: librmw_dds_common__rosidl_typesupport_fastrtps_c.so: unused library 'opt/ros/humble/lib/librmw_dds_common__rosidl_typesupport_fastrtps_c.so'. (https://snapcraft.io/docs/linters-library) +- library: librmw_dds_common__rosidl_typesupport_fastrtps_cpp.so: unused library 'opt/ros/humble/lib/librmw_dds_common__rosidl_typesupport_fastrtps_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librmw_dds_common__rosidl_typesupport_introspection_c.so: unused library 'opt/ros/humble/lib/librmw_dds_common__rosidl_typesupport_introspection_c.so'. (https://snapcraft.io/docs/linters-library) +- library: librmw_dds_common__rosidl_typesupport_introspection_cpp.so: unused library 'opt/ros/humble/lib/librmw_dds_common__rosidl_typesupport_introspection_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librmw_fastrtps_cpp.so: unused library 'opt/ros/humble/lib/librmw_fastrtps_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librosgraph_msgs__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/librosgraph_msgs__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: librosgraph_msgs__rosidl_typesupport_cpp.so: unused library 'opt/ros/humble/lib/librosgraph_msgs__rosidl_typesupport_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librosgraph_msgs__rosidl_typesupport_fastrtps_c.so: unused library 'opt/ros/humble/lib/librosgraph_msgs__rosidl_typesupport_fastrtps_c.so'. (https://snapcraft.io/docs/linters-library) +- library: librosgraph_msgs__rosidl_typesupport_fastrtps_cpp.so: unused library 'opt/ros/humble/lib/librosgraph_msgs__rosidl_typesupport_fastrtps_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: librosgraph_msgs__rosidl_typesupport_introspection_c.so: unused library 'opt/ros/humble/lib/librosgraph_msgs__rosidl_typesupport_introspection_c.so'. (https://snapcraft.io/docs/linters-library) +- library: librosgraph_msgs__rosidl_typesupport_introspection_cpp.so: unused library 'opt/ros/humble/lib/librosgraph_msgs__rosidl_typesupport_introspection_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: libunique_identifier_msgs__rosidl_generator_py.so: unused library 'opt/ros/humble/lib/libunique_identifier_msgs__rosidl_generator_py.so'. (https://snapcraft.io/docs/linters-library) +- library: libunique_identifier_msgs__rosidl_typesupport_cpp.so: unused library 'opt/ros/humble/lib/libunique_identifier_msgs__rosidl_typesupport_cpp.so'. (https://snapcraft.io/docs/linters-library) +- library: libatomic.so.1: unused library 'usr/lib/x86_64-linux-gnu/libatomic.so.1.2.0'. (https://snapcraft.io/docs/linters-library) +- library: libicuio.so.70: unused library 'usr/lib/x86_64-linux-gnu/libicuio.so.70.1'. (https://snapcraft.io/docs/linters-library) +- library: libicutest.so.70: unused library 'usr/lib/x86_64-linux-gnu/libicutest.so.70.1'. (https://snapcraft.io/docs/linters-library) +Creating snap package... diff --git a/tests/spread/core22/linters/linter-ros2-humble-mixed/snap/snapcraft.yaml b/tests/spread/core22/linters/linter-ros2-humble-mixed/snap/snapcraft.yaml new file mode 100644 index 0000000000..d6c6de42d8 --- /dev/null +++ b/tests/spread/core22/linters/linter-ros2-humble-mixed/snap/snapcraft.yaml @@ -0,0 +1,32 @@ +name: linter-ros2-humble-mixed +version: "1.0" +summary: hello world +description: | + Check linter warnings when using the ros2-humble extension with additional + user-provided lint ignores. + +grade: stable +confinement: strict +base: core22 + +apps: + linter-ros2-humble: + command: usr/bin/hello + extensions: [ros2-humble] + +parts: + hello: + plugin: nil + stage-packages: [ros-humble-ros2run, hello] + + unused-lib: + plugin: nil + stage-packages: [libpng16-16] + +# Currently this declaration overrides the "unused-library" lint ignore provided +# by the ros2-humble extension, so it's expected that many ros-related warnings +# are generated. +lint: + ignore: + - unused-library: + - usr/lib/*/libpng16.so* \ No newline at end of file diff --git a/tests/spread/core22/linters/linter-ros2-humble-mixed/task.yaml b/tests/spread/core22/linters/linter-ros2-humble-mixed/task.yaml new file mode 100644 index 0000000000..9076af8790 --- /dev/null +++ b/tests/spread/core22/linters/linter-ros2-humble-mixed/task.yaml @@ -0,0 +1,13 @@ +summary: Check linter warnings ros2-humble extension plus user ignores. + +restore: | + snapcraft clean + rm -f ./*.snap ./*.txt + +execute: | + snapcraft 2> output.txt + + test -f linter-ros2-humble-mixed_1.0_*.snap + + sed -n '/^Running linters/,/^Creating snap/p' < output.txt > linter_output.txt + diff -u linter_output.txt expected_linter_output.txt diff --git a/tests/spread/core22/linters/linter-ros2-humble/expected_linter_output.txt b/tests/spread/core22/linters/linter-ros2-humble/expected_linter_output.txt new file mode 100644 index 0000000000..e1fabef93a --- /dev/null +++ b/tests/spread/core22/linters/linter-ros2-humble/expected_linter_output.txt @@ -0,0 +1,4 @@ +Running linters... +Running linter: classic +Running linter: library +Creating snap package... diff --git a/tests/spread/core22/linters/linter-ros2-humble/snap/snapcraft.yaml b/tests/spread/core22/linters/linter-ros2-humble/snap/snapcraft.yaml new file mode 100644 index 0000000000..c4dafde176 --- /dev/null +++ b/tests/spread/core22/linters/linter-ros2-humble/snap/snapcraft.yaml @@ -0,0 +1,18 @@ +name: linter-ros2-humble +version: "1.0" +summary: hello world +description: Check linter warnings when using the ros2-humble extension. + +grade: stable +confinement: strict +base: core22 + +apps: + linter-ros2-humble: + command: usr/bin/hello + extensions: [ros2-humble] + +parts: + hello: + plugin: nil + stage-packages: [ros-humble-ros2run, hello] diff --git a/tests/spread/core22/linters/linter-ros2-humble/task.yaml b/tests/spread/core22/linters/linter-ros2-humble/task.yaml new file mode 100644 index 0000000000..5ae1c5de96 --- /dev/null +++ b/tests/spread/core22/linters/linter-ros2-humble/task.yaml @@ -0,0 +1,13 @@ +summary: Ignore unused library linter issues + +restore: | + snapcraft clean + rm -f ./*.snap ./*.txt + +execute: | + snapcraft 2> output.txt + + test -f linter-ros2-humble_1.0_*.snap + + sed -n '/^Running linters/,/^Creating snap/p' < output.txt > linter_output.txt + diff -u linter_output.txt expected_linter_output.txt diff --git a/tests/unit/parts/extensions/test_ros2_humble.py b/tests/unit/parts/extensions/test_ros2_humble.py index 1cb1a4d57c..bf465a45b5 100644 --- a/tests/unit/parts/extensions/test_ros2_humble.py +++ b/tests/unit/parts/extensions/test_ros2_humble.py @@ -77,7 +77,30 @@ def test_get_root_snippet(self, setup_method_fixture): "key-server": "keyserver.ubuntu.com", "suites": ["jammy"], } - ] + ], + "lint": { + "ignore": [ + { + "unused-library": [ + "opt/ros/*", + "lib/*/libcrypt.so*", + "lib/*/libexpat.so*", + "lib/*/libtirpc.so*", + "lib/*/libz.so*", + "usr/lib/*libatomic.so*", + "usr/lib/*libconsole_bridge.so*", + "usr/lib/*libfmt.so*", + "usr/lib/*libicui18n.so*", + "usr/lib/*libicuio.so*", + "usr/lib/*libicutest.so*", + "usr/lib/*libicutu.so*", + "usr/lib/*libpython3.10.so*", + "usr/lib/*libspdlog.so*", + "usr/lib/*libtinyxml2.so*", + ] + } + ] + }, } def test_get_app_snippet(self, setup_method_fixture):