Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linters: allow "categories" for subfiltering #4077

Merged
merged 2 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion snapcraft/extensions/ros2_humble.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 37 additions & 6 deletions snapcraft/linters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
tigarmo marked this conversation as resolved.
Show resolved Hide resolved

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 []
48 changes: 28 additions & 20 deletions snapcraft/linters/library_linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Library linter implementation."""

from pathlib import Path
from typing import List, Set

Expand All @@ -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):
Expand All @@ -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,
Expand All @@ -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))

Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions snapcraft/linters/linters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Running linters...
Running linter: classic
Running linter: library
Creating snap package...
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "caca.h"

int main()
{
caca_create_canvas(80, 24);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}
13 changes: 13 additions & 0 deletions tests/spread/core22/linters/library-ignored-mixed/task.yaml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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...
Original file line number Diff line number Diff line change
@@ -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*
13 changes: 13 additions & 0 deletions tests/spread/core22/linters/linter-ros2-humble-mixed/task.yaml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Running linters...
Running linter: classic
Running linter: library
Creating snap package...
18 changes: 18 additions & 0 deletions tests/spread/core22/linters/linter-ros2-humble/snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -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]
13 changes: 13 additions & 0 deletions tests/spread/core22/linters/linter-ros2-humble/task.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading