diff options
Diffstat (limited to 'lib/Lintian/Check/Languages')
38 files changed, 3987 insertions, 0 deletions
diff --git a/lib/Lintian/Check/Languages/Fortran/Gfortran.pm b/lib/Lintian/Check/Languages/Fortran/Gfortran.pm new file mode 100644 index 0000000..6479d8a --- /dev/null +++ b/lib/Lintian/Check/Languages/Fortran/Gfortran.pm @@ -0,0 +1,94 @@ +# languages/fortran/gfortran -- lintian check script -*- perl -*- + +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Fortran::Gfortran; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use Unicode::UTF8 qw(encode_utf8); + +const my $NEWLINE => qq{\n}; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + # file-info would be great, but files are zipped + return + unless $item->name =~ m{\.mod$}; + + return + unless $item->name =~ m{^usr/lib/}; + + # do not look at flang, grub or libreoffice modules + return + if $item->name =~ m{/flang-\d+/} + || $item->name =~ m{^usr/lib/grub} + || $item->name =~ m{^usr/lib/libreoffice}; + + return + unless $item->is_file + && $item->is_open_ok + && $item->file_type =~ /\bgzip compressed\b/; + + my $module_version; + + open(my $fd, '<:gzip', $item->unpacked_path) + or die encode_utf8( + 'Cannot open gz file ' . $item->unpacked_path . $NEWLINE); + + while (my $line = <$fd>) { + next + if $line =~ /^\s*$/; + + ($module_version) = ($line =~ /^GFORTRAN module version '(\d+)'/); + last; + } + + close $fd; + + unless (length $module_version) { + $self->pointed_hint('gfortran-module-does-not-declare-version', + $item->pointer); + return; + } + + my $depends = $self->processable->fields->value('Depends'); + $self->pointed_hint('missing-prerequisite-for-gfortran-module', + $item->pointer) + unless $depends =~ /\bgfortran-mod-$module_version\b/; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Golang/BuiltUsing.pm b/lib/Lintian/Check/Languages/Golang/BuiltUsing.pm new file mode 100644 index 0000000..79095d3 --- /dev/null +++ b/lib/Lintian/Check/Languages/Golang/BuiltUsing.pm @@ -0,0 +1,68 @@ +# languages/golang/built-using -- lintian check script -*- perl -*- +# +# Copyright (C) 2004 Marc Brockschmidt +# Copyright (C) 2020 Chris Lamb <lamby@debian.org> +# Copyright (C) 2020-2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Golang::BuiltUsing; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + return + unless $self->processable->relation('Build-Depends') + ->satisfies('golang-go | golang-any'); + + my $control = $self->processable->debian_control; + + for my $installable ($control->installables) { + my $installable_fields= $control->installable_fields($installable); + + my $control_item= $self->processable->debian_control->item; + my $position = $installable_fields->position('Package'); + + $self->pointed_hint( + 'missing-built-using-field-for-golang-package', + $control_item->pointer($position), + "(in section for $installable)" + ) + if $installable_fields->value('Built-Using') + !~ m{ \$ [{] misc:Built-Using [}] }x + && $installable_fields->value('Architecture') ne 'all'; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Golang/ImportPath.pm b/lib/Lintian/Check/Languages/Golang/ImportPath.pm new file mode 100644 index 0000000..210696b --- /dev/null +++ b/lib/Lintian/Check/Languages/Golang/ImportPath.pm @@ -0,0 +1,56 @@ +# languages/golang/import-path -- lintian check script -*- perl -*- +# +# Copyright (C) 2004 Marc Brockschmidt +# Copyright (C) 2020 Chris Lamb <lamby@debian.org> +# Copyright (C) 2020-2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Golang::ImportPath; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + return + unless $self->processable->relation('Build-Depends') + ->satisfies('golang-go | golang-any'); + + my $control = $self->processable->debian_control; + my $source_fields = $control->source_fields; + + $self->hint('missing-xs-go-import-path-for-golang-package') + unless $source_fields->declares('XS-Go-Import-Path'); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Java.pm b/lib/Lintian/Check/Languages/Java.pm new file mode 100644 index 0000000..4b26512 --- /dev/null +++ b/lib/Lintian/Check/Languages/Java.pm @@ -0,0 +1,315 @@ +# languages/java -- lintian check script -*- perl -*- + +# Copyright (C) 2011 Vincent Fourmond +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Java; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use File::Basename; +use List::SomeUtils qw(any none); + +use Lintian::Util qw(normalize_link_target $PKGNAME_REGEX $PKGVERSION_REGEX); + +const my $EMPTY => q{}; +const my $HYPHEN => q{-}; + +const my $ARROW => q{->}; + +const my $BYTE_CODE_VERSION_OFFSET => 44; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +our $CLASS_REGEX = qr/\.(?:class|cljc?)/; + +sub visit_patched_files { + my ($self, $item) = @_; + + my $java_info = $item->java_info; + return + unless scalar keys %{$java_info}; + + my $files = $java_info->{files}; + + $self->pointed_hint('source-contains-prebuilt-java-object', $item->pointer) + if any { m/$CLASS_REGEX$/i } keys %{$files}; + + return; +} + +sub installable { + my ($self) = @_; + + my $missing_jarwrapper = 0; + my $has_public_jars = 0; + my $jmajlow = $HYPHEN; + + my $depends = $self->processable->relation('strong')->to_string; + + # Remove all libX-java-doc packages to avoid thinking they are java libs + # - note the result may not be a valid dependency listing + $depends =~ s/lib[^\s,]+-java-doc//g; + + my @java_lib_depends = ($depends =~ m/\b(lib[^\s,]+-java)\b/g); + + my $JAVA_BYTECODES= $self->data->load('java/constants', qr/\s*=\s*/); + + # We first loop over jar files to find problems + + for my $item (@{$self->processable->installed->sorted_list}) { + + my $java_info = $item->java_info; + next + unless scalar keys %{$java_info}; + + my $files = $java_info->{files}; + my $manifest = $java_info->{manifest}; + my $jar_dir = dirname($item->name); + my $classes = 0; + my $datafiles = 1; + my $class_path = $EMPTY; + my $bsname = $EMPTY; + + if (exists $java_info->{error}) { + $self->pointed_hint('zip-parse-error', $item->pointer, + $java_info->{error}); + next; + } + + # The Java Policy says very little about requires for (jars in) JVMs + next + if $item->name =~ m{^usr/lib/jvm(?:-exports)?/[^/]+/}; + + # Ignore Mozilla's jar files, see #635495 + next + if $item->name =~ m{^usr/lib/xul(?:-ext|runner[^/]*+)/}; + + if ($item->name =~ m{^usr/share/java/[^/]+\.jar$}) { + $has_public_jars = 1; + + # java policy requires package version too; see Bug#976681 + $self->pointed_hint('bad-jar-name', $item->pointer) + unless basename($item->name) + =~ /^$PKGNAME_REGEX-$PKGVERSION_REGEX\.jar$/; + } + + # check for common code files like .class or .clj (Clojure files) + for my $class (grep { m/$CLASS_REGEX$/i } sort keys %{$files}){ + + my $module_version = $files->{$class}; + (my $src = $class) =~ s/\.[^.]+$/\.java/; + + $self->pointed_hint('jar-contains-source', $item->pointer, $src) + if %{$files}{$src}; + + $classes = 1; + + next + if $class =~ m/\.cljc?$/; + + # .class but no major version? + next + if $module_version eq $HYPHEN; + + if ($module_version + < $JAVA_BYTECODES->value('lowest-known-bytecode-version') + || $module_version + > $JAVA_BYTECODES->value('highest-known-bytecode-version')) { + + # First public major version was 45 (Java1), latest + # version is 55 (Java11). + $self->pointed_hint('unknown-java-class-version', + $item->pointer,$class, $ARROW, $module_version); + + # Skip the rest of this Jar. + last; + } + + # Collect the "lowest" Class version used. We assume that + # mixed class formats implies special compat code for certain + # JVM cases. + if ($jmajlow eq $HYPHEN) { + # first; + $jmajlow = $module_version; + + } else { + $jmajlow = $module_version + if $module_version < $jmajlow; + } + } + + $datafiles = 0 + if none { /\.(?:xml|properties|x?html|xhp)$/i } keys %{$files}; + + if ($item->is_executable) { + + $self->pointed_hint('executable-jar-without-main-class', + $item->pointer) + unless $manifest && $manifest->{'Main-Class'}; + + # Here, we need to check that the package depends on + # jarwrapper. + $missing_jarwrapper = 1 + unless $self->processable->relation('strong') + ->satisfies('jarwrapper'); + + } elsif ($item->name !~ m{^usr/share/}) { + + $self->pointed_hint('jar-not-in-usr-share', $item->pointer); + } + + $class_path = $manifest->{'Class-Path'}//$EMPTY if $manifest; + $bsname = $manifest->{'Bundle-SymbolicName'}//$EMPTY if $manifest; + + if ($manifest) { + if (!$classes) { + + # Eclipse / OSGi bundles are sometimes source bundles + # these do not ship classes but java files and other sources. + # Javadoc jars deployed in the Maven repository also do not ship + # classes but HTML files, images and CSS files + if ( + ( + $bsname !~ m/\.source$/ + && $item->name + !~ m{^usr/share/maven-repo/.*-javadoc\.jar} + && $item->name !~ m{\.doc(?:\.(?:user|isv))?_[^/]+.jar} + && $item->name !~ m{\.source_[^/]+.jar} + ) + || $class_path + ) { + $self->pointed_hint('codeless-jar', $item->pointer); + } + } + + } elsif ($classes) { + $self->pointed_hint('missing-manifest', $item->pointer); + } + + if ($class_path) { + # Only run the tests when a classpath is present + my @relative; + my @paths = split(m/\s++/, $class_path); + for my $p (@paths) { + if ($p) { + # Strip leading ./ + $p =~ s{^\./+}{}g; + if ($p !~ m{^(?:file://)?/} && $p =~ m{/}) { + my $target = normalize_link_target($jar_dir, $p); + my $tinfo; + # Can it be normalized? + next unless defined($target); + # Relative link to usr/share/java ? Works if + # we are depending of a Java library. + next + if $target =~ m{^usr/share/java/[^/]+.jar$} + && @java_lib_depends; + $tinfo= $self->processable->installed->lookup($target); + # Points to file or link in this package, + # which is sometimes easier than + # re-writing the classpath. + next + if defined $tinfo + and ($tinfo->is_symlink or $tinfo->is_file); + # Relative path with subdirectories. + push @relative, $p; + } + # @todo add an info tag for relative paths, to educate + # maintainers ? + } + } + + $self->pointed_hint('classpath-contains-relative-path', + $item->pointer, join(', ', @relative)) + if @relative; + } + + # Trigger a warning when a maven plugin lib is installed in + # /usr/share/java/ + $self->pointed_hint('maven-plugin-in-usr-share-java', $item->pointer) + if $has_public_jars + && $self->processable->name =~ /^lib.*maven.*plugin.*/ + && $item->name !~ m{^usr/share/maven-repo/.*\.jar}; + } + + $self->hint('missing-dep-on-jarwrapper') if $missing_jarwrapper; + + if ($jmajlow ne $HYPHEN) { + # Byte code numbers: + # 45-49 -> Java1 - Java5 (Always ok) + # 50 -> Java6 + # 51 -> Java7 + # 52 -> Java8 + # 53 -> Java9 + # 54 -> Java10 + # 55 -> Java11 + my $bad = 0; + + # If the lowest version used is greater than the requested + # limit, then flag it. + $bad = 1 + if $jmajlow > $JAVA_BYTECODES->value('default-bytecode-version'); + + # Technically we ought to do some checks with Java6 class + # files and dependencies/package types, but for now just skip + # that. (See #673276) + + if ($bad) { + # Map the Class version to a Java version. + my $java_version = $jmajlow - $BYTE_CODE_VERSION_OFFSET; + + $self->hint('incompatible-java-bytecode-format', + "Java$java_version version (Class format: $jmajlow)"); + } + } + + if ( !$has_public_jars + && !$self->processable->is_transitional + && $self->processable->name =~ /^lib[^\s,]+-java$/){ + + # Skip this if it installs a symlink in usr/share/java + my $java_dir + = $self->processable->installed->resolve_path('usr/share/java/'); + + my $has_jars = 0; + $has_jars = 1 + if $java_dir + && (any { $_->name =~ m{^[^/]+\.jar$} } $java_dir->children); + + $self->hint('javalib-but-no-public-jars') + unless $has_jars; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Java/Bytecode.pm b/lib/Lintian/Check/Languages/Java/Bytecode.pm new file mode 100644 index 0000000..14566a9 --- /dev/null +++ b/lib/Lintian/Check/Languages/Java/Bytecode.pm @@ -0,0 +1,58 @@ +# languages/java/bytecode -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Java::Bytecode; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +const my $MAGIC_BYTE_SIZE => 4; + +sub visit_installed_files { + my ($self, $item) = @_; + + # .class (compiled Java files) + if ( $item->name =~ /\.class$/ + && $item->name !~ /(?:WEB-INF|demo|doc|example|sample|test)/) { + + my $magic = $item->magic($MAGIC_BYTE_SIZE); + + $self->pointed_hint('package-installs-java-bytecode', $item->pointer) + if $magic eq "\xCA\xFE\xBA\xBE"; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Javascript/Embedded.pm b/lib/Lintian/Check/Languages/Javascript/Embedded.pm new file mode 100644 index 0000000..9227187 --- /dev/null +++ b/lib/Lintian/Check/Languages/Javascript/Embedded.pm @@ -0,0 +1,149 @@ +# languages/javascript/embedded -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Javascript::Embedded; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +my %JS_MAGIC + = ('libjs-bootstrap' => qr{ var [ ] (?: Carousel | Typeahead ) }x,); + +my $JS_EXT + = qr{(?:(?i)[-._]?(?:compiled|lite|min|pack(?:ed)?|prod|umd|yc)?\.(js|css)(?:\.gz)?)$}; +my %JS_FILES = ( + 'ckeditor' => qr{(?i)/ckeditor} . $JS_EXT, + 'fckeditor' => qr{(?i)/fckeditor} . $JS_EXT, + 'libjs-async' => qr{(?i)/async} . $JS_EXT, + 'libjs-bootstrap' => qr{(?i)/bootstrap(?:-[\d\.]+)?} . $JS_EXT, + 'libjs-chai' => qr{(?i)/chai} . $JS_EXT, + 'libjs-cropper' => qr{(?i)/cropper(?:\.uncompressed)?} . $JS_EXT, + 'libjs-dojo-\w+' => qr{(?i)/(?:dojo|dijit)} . $JS_EXT, + 'libjs-excanvas' => qr{(?i)/excanvas(?:-r[0-9]+)?} . $JS_EXT, + 'libjs-jac' => qr{(?i)/jsjac} . $JS_EXT, + 'libjs-jquery' => qr{(?i)/jquery(?:-[\d\.]+)?} . $JS_EXT, + 'libjs-jquery-cookie' => qr{(?i)/jquery\.cookie} . $JS_EXT, + 'libjs-jquery-easing' => qr{(?i)/jquery\.easing} . $JS_EXT, + 'libjs-jquery-event-drag' => qr{(?i)/jquery\.event\.drap} . $JS_EXT, + 'libjs-jquery-event-drop' => qr{(?i)/jquery\.event\.drop} . $JS_EXT, + 'libjs-jquery-fancybox' => qr{(?i)/jquery\.fancybox} . $JS_EXT, + 'libjs-jquery-form' => qr{(?i)/jquery\.form} . $JS_EXT, + 'libjs-jquery-galleriffic' => qr{(?i)/jquery\.galleriffic} . $JS_EXT, + 'libjs-jquery-history' => qr{(?i)/jquery\.history} . $JS_EXT, + 'libjs-jquery-jfeed' => qr{(?i)/jquery\.jfeed} . $JS_EXT, + 'libjs-jquery-jush' => qr{(?i)/jquery\.jush} . $JS_EXT, + 'libjs-jquery-livequery' => qr{(?i)/jquery\.livequery} . $JS_EXT, + 'libjs-jquery-meiomask' => qr{(?i)/jquery\.meiomask} . $JS_EXT, + 'libjs-jquery-metadata' => qr{(?i)/jquery\.metadata} . $JS_EXT, + 'libjs-jquery-migrate-1' => qr{(?i)/jquery-migrate(?:-1[\d\.]*)} + . $JS_EXT, + 'libjs-jquery-mousewheel' => qr{(?i)/jquery\.mousewheel} . $JS_EXT, + 'libjs-jquery-opacityrollover' => qr{(?i)/jquery\.opacityrollover} + . $JS_EXT, + 'libjs-jquery-tablesorter' => qr{(?i)/jquery\.tablesorter} . $JS_EXT, + 'libjs-jquery-tipsy' => qr{(?i)/jquery\.tipsy} . $JS_EXT, + 'libjs-jquery-treetable' => qr{(?i)/jquery\.treetable} . $JS_EXT, + 'libjs-jquery-ui' => qr{(?i)/jquery[\.-](?:-[\d\.]+)?ui} + . $JS_EXT, + 'libjs-mocha' => qr{(?i)/mocha} . $JS_EXT, + 'libjs-mochikit' => qr{(?i)/mochikit} . $JS_EXT, + 'libjs-mootools' => +qr{(?i)/mootools(?:(?:\.v|-)[\d\.]+)?(?:-(?:(?:core(?:-server)?)|more)(?:-(?:yc|jm|nc))?)?} + . $JS_EXT, + 'libjs-mustache' => qr{(?i)/mustache} . $JS_EXT, +# libjs-normalize is provided by node-normalize.css but this is an implementation detail + 'libjs-normalize' => qr{(?i)/normalize(?:\.min)?\.css}, + 'libjs-prototype' => qr{(?i)/prototype(?:-[\d\.]+)?}. $JS_EXT, + 'libjs-raphael' => qr{(?i)/raphael(?:[\.-]min)?} . $JS_EXT, + 'libjs-scriptaculous' => qr{(?i)/scriptaculous} . $JS_EXT, + 'libjs-strophe' => qr{(?i)/strophe} . $JS_EXT, + 'libjs-underscore' => qr{(?i)/underscore} . $JS_EXT, + 'libjs-yui' => qr{(?i)/(?:yahoo|yui)-(?:dom-event)?} + . $JS_EXT, + # Disabled due to false positives. Needs a content check adding to verify + # that the file being checked is /the/ yahoo.js + # 'libjs-yui' => qr{(?i)/yahoo\.js(\.gz)?} . $JS_EXT, + 'jsmath' => qr{(?i)/jsMath(?:-fallback-\w+)?} + . $JS_EXT, + 'node-html5shiv' => qr{(?i)html5shiv(?:-printshiv)?} + . $JS_EXT, + 'sphinx' => + qr{(?i)/_static/(?:doctools|language_data|searchtools)} . $JS_EXT, + 'tinymce' => qr{(?i)/tiny_mce(?:_(?:popup|src))?} + . $JS_EXT, + 'libjs-lodash' => qr{(?i)lodash} . $JS_EXT, + 'node-pako' => + qr{(?i)pako(?:_(:?de|in)flate(?:.es\d+)?)(?:-[\d\.]+)?}. $JS_EXT, + 'node-jszip-utils' => qr{(?i)jszip-utils(?:-ie)?(?:-[\d\.]+)?} + . $JS_EXT, + 'node-jszip' => qr{(?i)jszip(?:-ie)?(?:-[\d\.]+)?} . $JS_EXT, + 'libjs-codemirror' => qr{(?i)codemirror} . $JS_EXT, + 'libjs-punycode' => qr{(?i)punycode(?:\.es\d+)?} . $JS_EXT, +# not yet available in unstable +# 'xinha' => qr{(?i)/(htmlarea|Xinha(Loader|Core))} . $JS_EXT, +); + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + # ignore embedded jQuery libraries for Doxygen (#736360) + my $doxygen = $self->processable->installed->resolve_path( + $item->dirname . 'doxygen.css'); + return + if $item->basename eq 'jquery.js' + && defined $doxygen; + + # embedded javascript + for my $provider (keys %JS_FILES) { + + next + if $self->processable->name =~ /^$provider$/; + + next + unless $item->name =~ /$JS_FILES{$provider}/; + + next + if length $JS_MAGIC{$provider} + && !length $item->bytes_match($JS_MAGIC{$provider}); + + $self->pointed_hint('embedded-javascript-library', $item->pointer, + 'please use', $provider); + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Javascript/Nodejs.pm b/lib/Lintian/Check/Languages/Javascript/Nodejs.pm new file mode 100644 index 0000000..98a5d76 --- /dev/null +++ b/lib/Lintian/Check/Languages/Javascript/Nodejs.pm @@ -0,0 +1,262 @@ +# languages/javascript/nodejs -- lintian check script -*- perl -*- + +# Copyright (C) 2019-2020, Xavier Guimard <yadd@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Javascript::Nodejs; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use JSON::MaybeXS; +use List::SomeUtils qw(any none first_value); +use Path::Tiny; +use Syntax::Keyword::Try; +use Unicode::UTF8 qw(encode_utf8); + +use Lintian::Relation; + +const my $SLASH => q{/}; +const my $DOT => q{.}; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + my $debian_control = $self->processable->debian_control; + + # debian/control check + my @testsuites + = split(m/\s*,\s*/,$debian_control->source_fields->value('Testsuite')); + + if (any { $_ eq 'autopkgtest-pkg-nodejs' } @testsuites) { + + my $item = $self->processable->patched->resolve_path( + 'debian/tests/pkg-js/test'); + if (defined $item) { + + $self->pointed_hint('pkg-js-autopkgtest-test-is-empty', + $item->pointer) + if none { /^[^#]*\w/m } $item->bytes; + + } else { + $self->hint('pkg-js-autopkgtest-test-is-missing'); + } + + # Ensure all files referenced in debian/tests/pkg-js/files exist + my $files + = $self->processable->patched->resolve_path( + 'debian/tests/pkg-js/files'); + if (defined $files) { + + my @patterns = path($files->unpacked_path)->lines; + + # trim leading and trailing whitespace + s/^\s+|\s+$//g for @patterns; + + my @notfound = grep { !$self->path_exists($_) } @patterns; + + $self->hint('pkg-js-autopkgtest-file-does-not-exist', $_) + for @notfound; + } + } + + # debian/rules check + my $droot = $self->processable->patched->resolve_path('debian/') + or return; + my $drules = $droot->child('rules') + or return; + + return + unless $drules->is_open_ok; + + open(my $rules_fd, '<', $drules->unpacked_path) + or die encode_utf8('Cannot open ' . $drules->unpacked_path); + + my $command_prefix_pattern = qr/\s+[@+-]?(?:\S+=\S+\s+)*/; + my ($seen_nodejs,$override_test,$seen_dh_dynamic); + my $bdepends = $self->processable->relation('Build-Depends-All'); + $seen_nodejs = 1 if $bdepends->satisfies('dh-sequence-nodejs'); + + while (my $line = <$rules_fd>) { + + # reconstitute splitted lines + while ($line =~ s/\\$// && defined(my $cont = <$rules_fd>)) { + $line .= $cont; + } + + # skip comments + next + if $line =~ /^\s*\#/; + + if ($line =~ m{^(?:$command_prefix_pattern)dh\s+}) { + $seen_dh_dynamic = 1 + if $line =~ /\$[({]\w/; + + while ($line =~ /\s--with(?:=|\s+)(['"]?)(\S+)\1/g) { + my @addons = split(m{,}, $2); + $seen_nodejs = 1 + if any { $_ eq 'nodejs' } @addons; + } + + } elsif ($line =~ /^([^:]*override_dh_[^:]*):/) { + $override_test = 1 + if $1 eq 'auto_test'; + } + } + + if( $seen_nodejs + && !$override_test + && !$seen_dh_dynamic) { + + # pkg-js-tools search build test in the following order + my @candidates = qw{debian/nodejs/test debian/tests/pkg-js/test}; + + my $item = first_value { defined } + map { $self->processable->patched->resolve_path($_) } @candidates; + + # Ensure test file contains something + if (defined $item) { + $self->pointed_hint('pkg-js-tools-test-is-empty', $item->pointer) + unless any { /^[^#]*\w/m } $item->bytes; + + } else { + $self->hint('pkg-js-tools-test-is-missing'); + } + } + + return; +} + +sub visit_installed_files { + my ($self, $item) = @_; + + return + if $item->is_dir; + + return + if $self->processable->name =~ /-dbg$/; + + # Warn if a file is installed in old nodejs root dir + $self->pointed_hint('nodejs-module-installed-in-usr-lib', $item->pointer) + if $item->name =~ m{^usr/lib/nodejs/.*}; + + # Warn if package is not installed in a subdirectory of nodejs root + # directories + $self->pointed_hint('node-package-install-in-nodejs-rootdir', + $item->pointer) + if $item->name + =~ m{^usr/(?:share|lib(?:/[^/]+)?)/nodejs/(?:package\.json|[^/]*\.js)$}; + + # Now we have to open package.json + return + unless $item->is_open_ok; + + # Return an error if a package-lock.json or a yanr.lock file is installed + $self->pointed_hint('nodejs-lock-file', $item->pointer) + if $item->name + =~ m{^usr/(?:share|lib(?:/[^/]+)?)/nodejs/([^/]+)(.*/)(package-lock\.json|yarn\.lock)$}; + + # Look only nodejs package.json files + return + unless $item->name + =~ m{^usr/(?:share|lib(?:/[^/]+)?)/nodejs/([^\@/]+|\@[^/]+/[^/]+)(.*/)package\.json$}; + + # First regexp arg: directory in /**/nodejs or @foo/bar when dir starts + # with '@', following npm registry policy + my $dirname = $1; + # Second regex arg: subpath in /**/nodejs/module/ (eg: node_modules/foo) + my $subpath = $2; + + my $declared = $self->processable->name; + my $version = $self->processable->fields->value('Version'); + $declared .= "( = $version)" + if length $version; + $version ||= '0-1'; + + my $provides + = $self->processable->relation('Provides')->logical_and($declared); + + my $content = $item->bytes; + + # Look only valid package.json files + my $pac; + try { + $pac = decode_json($content); + die + unless length $pac->{name}; + } catch { + return; + } + + # Store node module name & version (classification) + $self->pointed_hint('nodejs-module', $item->pointer, $pac->{name}, + $pac->{version} // 'undef'); + + # Warn if version is 0.0.0-development + $self->pointed_hint('nodejs-missing-version-override', + $item->pointer, $pac->{name}, $pac->{version}) + if $pac->{version} and $pac->{version} =~ /^0\.0\.0-dev/; + + # Warn if module name is not equal to nodejs directory + if ($subpath eq $SLASH && $dirname ne $pac->{name}) { + $self->pointed_hint('nodejs-module-installed-in-bad-directory', + $item->pointer, $pac->{name}, $dirname); + + } else { + # Else verify that module is declared at least in Provides: field + my $name = 'node-' . lc($pac->{name}); + # Normalize name following Debian policy + # (replace invalid characters by "-") + $name =~ s{[/_\@]}{-}g; + $name =~ s/-+/-/g; + + $self->pointed_hint('nodejs-module-not-declared', $item->pointer,$name) + if $subpath eq $SLASH + && !$provides->satisfies($name); + } + + return; +} + +sub path_exists { + my ($self, $expression) = @_; + + # replace asterisks with proper regex wildcard + $expression =~ s{ [*] }{[^/]*}gsx; + + return 1 + if any { m{^ $expression /? $}sx } + @{$self->processable->patched->sorted_list}; + + return 0; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/ByteCode/Compiled.pm b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Compiled.pm new file mode 100644 index 0000000..f916d68 --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Compiled.pm @@ -0,0 +1,85 @@ +# languages/ocaml/byte-code/compiled -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::ByteCode::Compiled; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +has provided_o => ( + is => 'rw', + lazy => 1, + default => sub { + my ($self) = @_; + + my %provided_o; + + for my $item (@{$self->processable->installed->sorted_list}) { + + for my $count (keys %{$item->ar_info}) { + + my $member = $item->ar_info->{$count}{name}; + next + unless length $member; + + # dirname ends in a slash + my $virtual_path = $item->dirname . $member; + + # Note: a .o may be legitimately in several different .a + $provided_o{$virtual_path} = $item->name; + } + } + + return \%provided_o; + } +); + +sub visit_installed_files { + my ($self, $item) = @_; + + my $no_extension = $item->basename; + $no_extension =~ s{ [.] [^.]+ $}{}x; + + # The .cmx counterpart: for each .cmx file, there must be a + # matching .o file, which can be there by itself, or embedded in a + # .a file in the same directory + # dirname ends with a slash + $self->pointed_hint('ocaml-dangling-cmx', $item->pointer) + if $item->name =~ m{ [.]cmx $}x + && !$item->parent_dir->child($no_extension . '.o') + && !exists $self->provided_o->{$item->dirname . $no_extension . '.o'}; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/ByteCode/Interface.pm b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Interface.pm new file mode 100644 index 0000000..8edeab1 --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Interface.pm @@ -0,0 +1,63 @@ +# languages/ocaml/byte-code/interface -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::ByteCode::Interface; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +const my $LAST_ITEM => -1; + +sub visit_installed_files { + my ($self, $item) = @_; + + my $no_extension = $item->basename; + $no_extension =~ s{ [.] [^.]+ $}{}x; + + # for dune + my $interface_name = (split(/__/, $no_extension))[$LAST_ITEM]; + + # $somename.cmi should be shipped with $somename.mli or $somename.ml + $self->pointed_hint('ocaml-dangling-cmi', $item->pointer) + if $item->name =~ m{ [.]cmi $}x + && !$item->parent_dir->child($interface_name . '.mli') + && !$item->parent_dir->child(lc($interface_name) . '.mli') + && !$item->parent_dir->child($interface_name . '.ml') + && !$item->parent_dir->child(lc($interface_name) . '.ml'); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/ByteCode/Library.pm b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Library.pm new file mode 100644 index 0000000..965f134 --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Library.pm @@ -0,0 +1,58 @@ +# languages/ocaml/byte-code/library -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::ByteCode::Library; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + my $no_extension = $item->basename; + $no_extension =~ s{ [.] [^.]+ $}{}x; + + # For each .cmxa file, there must be a matching .a file (#528367) + $self->pointed_hint('ocaml-dangling-cmxa', $item->pointer) + if $item->name =~ m{ [.]cmxa $}x + && !$item->parent_dir->child($no_extension . '.a'); + + # $somename.cmo should usually not be shipped with $somename.cma + $self->pointed_hint('ocaml-stray-cmo', $item->pointer) + if $item->name =~ m{ [.]cma $}x + && $item->parent_dir->child($no_extension . '.cmo'); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/ByteCode/Misplaced/Package.pm b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Misplaced/Package.pm new file mode 100644 index 0000000..767f6b0 --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Misplaced/Package.pm @@ -0,0 +1,126 @@ +# languages/ocaml/byte-code/misplaced/package -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::ByteCode::Misplaced::Package; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use List::SomeUtils qw(first_value); + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +const my $EMPTY => q{}; +const my $SLASH => q{/}; + +has development_files => (is => 'rw', default => sub { [] }); + +has is_dev_package => ( + is => 'rw', + lazy => 1, + default => sub { + my ($self) = @_; + + # is it a development package? + return 1 + if ( + $self->processable->name =~ m{ + (?: -dev + |\A camlp[45](?:-extra)? + |\A ocaml (?: + -nox + |-interp + |-compiler-libs + )? + )\Z}xsm + ); + + return 0; + } +); + +sub visit_installed_files { + my ($self, $item) = @_; + + # .cma, .cmo and .cmxs are excluded because they can be plugins + push(@{$self->development_files}, $item->name) + if $item->name =~ m{ [.] cm (?: i | xa? ) $}x; + + return; +} + +sub installable { + my ($self) = @_; + + my $count = scalar @{$self->development_files}; + my $plural = ($count == 1) ? $EMPTY : 's'; + + my $prefix = longest_common_prefix(@{$self->development_files}); + + # strip trailing slash + $prefix =~ s{ / $}{}x + unless $prefix eq $SLASH; + + # non-dev packages should not ship .cmi, .cmx or .cmxa files + $self->hint('ocaml-dev-file-in-nondev-package', + "$count file$plural in $prefix") + if $count > 0 + && !$self->is_dev_package; + + return; +} + +sub longest_common_prefix { + my (@paths) = @_; + + my %prefixes; + + for my $path (@paths) { + + my $truncated = $path; + + # first operation drops the file name + while ($truncated =~ s{ / [^/]* $}{}x) { + ++$prefixes{$truncated}; + } + } + + my @by_descending_length = reverse sort keys %prefixes; + + my $common = first_value { $prefixes{$_} == @paths } @by_descending_length; + + $common ||= $SLASH; + + return $common; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/ByteCode/Misplaced/Path.pm b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Misplaced/Path.pm new file mode 100644 index 0000000..68e4f4f --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Misplaced/Path.pm @@ -0,0 +1,105 @@ +# languages/ocaml/byte-code/misplaced/path -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::ByteCode::Misplaced::Path; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use List::SomeUtils qw(first_value); + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +const my $EMPTY => q{}; +const my $SLASH => q{/}; + +has misplaced_files => (is => 'rw', default => sub { [] }); + +sub visit_installed_files { + my ($self, $item) = @_; + + # development files outside /usr/lib/ocaml (.cmi, .cmx, .cmxa) + return + if $item->name =~ m{^ usr/lib/ocaml/ }x; + + # .cma, .cmo and .cmxs are excluded because they can be plugins + push(@{$self->misplaced_files}, $item->name) + if $item->name =~ m{ [.] cm (?: i | xa? ) $}x; + + return; +} + +sub installable { + my ($self) = @_; + + my $count = scalar @{$self->misplaced_files}; + my $plural = ($count == 1) ? $EMPTY : 's'; + + my $prefix = longest_common_prefix(@{$self->misplaced_files}); + + # strip trailing slash + $prefix =~ s{ / $}{}x + unless $prefix eq $SLASH; + + $self->hint( + 'ocaml-dev-file-not-in-usr-lib-ocaml', + "$count file$plural in $prefix" + )if $count > 0; + + return; +} + +sub longest_common_prefix { + my (@paths) = @_; + + my %prefixes; + + for my $path (@paths) { + + my $truncated = $path; + + # first operation drops the file name + while ($truncated =~ s{ / [^/]* $}{}x) { + ++$prefixes{$truncated}; + } + } + + my @by_descending_length = reverse sort keys %prefixes; + + my $common = first_value { $prefixes{$_} == @paths } @by_descending_length; + + $common ||= $SLASH; + + return $common; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/ByteCode/Plugin.pm b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Plugin.pm new file mode 100644 index 0000000..ae14f6b --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/ByteCode/Plugin.pm @@ -0,0 +1,56 @@ +# languages/ocaml/byte-code/plugin -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::ByteCode::Plugin; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + my $no_extension = $item->basename; + $no_extension =~ s{ [.] [^.]+ $}{}x; + + # For each .cmxs file, there must be a matching .cma or .cmo file + # (at least, in library packages) + $self->pointed_hint('ocaml-dangling-cmxs', $item->pointer) + if $item->name =~ m{ [.]cmxs $}x + && !$item->parent_dir->child($no_extension . '.cma') + && !$item->parent_dir->child($no_extension . '.cmo') + && $self->processable->name =~ /^lib/; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/CustomExecutable.pm b/lib/Lintian/Check/Languages/Ocaml/CustomExecutable.pm new file mode 100644 index 0000000..8ebad48 --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/CustomExecutable.pm @@ -0,0 +1,59 @@ +# languages/ocaml/custom-executable -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 2012 Kees Cook +# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org> +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::CustomExecutable; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + return + unless $item->file_type =~ /^ [^,]* \b ELF \b /x; + + # Check for OCaml custom executables (#498138) + $self->pointed_hint('ocaml-custom-executable', $item->pointer) + if $item->file_type =~ m{ \b not [ ] stripped \b }x + && $item->file_type =~ m{ \b executable \b }x + && $item->strings =~ m{^ Caml1999X0 [0-9] [0-9] $}mx; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ocaml/Meta.pm b/lib/Lintian/Check/Languages/Ocaml/Meta.pm new file mode 100644 index 0000000..0a9976b --- /dev/null +++ b/lib/Lintian/Check/Languages/Ocaml/Meta.pm @@ -0,0 +1,67 @@ +# languages/ocaml/meta -- lintian check script -*- perl -*- +# +# Copyright (C) 2009 Stephane Glondu +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ocaml::Meta; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +has has_meta => (is => 'rw', default => 0); + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->name =~ m{^ usr/lib/ocaml/ }x; + + # does the package provide a META file? + $self->has_meta(1) + if $item->name =~ m{ / META (?: [.] | $ ) }x; + + return; +} + +sub installable { + my ($self) = @_; + + my $prerequisites = $self->processable->relation('all'); + + # If there is a META file, ocaml-findlib should at least be suggested. + $self->hint('ocaml-meta-without-suggesting-findlib') + if $self->has_meta + && !$prerequisites->satisfies('ocaml-findlib:any'); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Perl.pm b/lib/Lintian/Check/Languages/Perl.pm new file mode 100644 index 0000000..c68af47 --- /dev/null +++ b/lib/Lintian/Check/Languages/Perl.pm @@ -0,0 +1,125 @@ +# languages/perl -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Perl; + +use v5.20; +use warnings; +use utf8; + +use Unicode::UTF8 qw(encode_utf8); + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +has perl_sources_in_lib => (is => 'rw', default => sub { [] }); +has has_perl_binaries => (is => 'rw', default => 0); + +sub visit_installed_files { + my ($self, $item) = @_; + + # perllocal.pod + $self->pointed_hint('package-installs-perllocal-pod', $item->pointer) + if $item->name =~ m{^usr/lib/perl.*/perllocal.pod$}; + + # .packlist files + if ($item->name =~ m{^usr/lib/perl.*/.packlist$}) { + $self->pointed_hint('package-installs-packlist', $item->pointer); + + }elsif ($item->name =~ m{^usr/lib/(?:[^/]+/)?perl5/.*\.p[lm]$}) { + push @{$self->perl_sources_in_lib}, $item; + + }elsif ($item->name =~ m{^usr/lib/(?:[^/]+/)?perl5/.*\.(?:bs|so)$}) { + $self->has_perl_binaries(1); + } + + # perl modules + if ($item->name =~ m{^usr/(?:share|lib)/perl/\S}) { + + # check if it's the "perl" package itself + $self->pointed_hint('perl-module-in-core-directory', $item->pointer) + unless $self->processable->source_name eq 'perl'; + } + + # perl modules using old libraries + # we do the same check on perl scripts in checks/scripts + my $dep = $self->processable->relation('strong'); + if ( $item->is_file + && $item->name =~ /\.pm$/ + && !$dep->satisfies('libperl4-corelibs-perl | perl (<< 5.12.3-7)')) { + + open(my $fd, '<', $item->unpacked_path) + or die encode_utf8('Cannot open ' . $item->unpacked_path); + + my $position = 1; + while (my $line = <$fd>) { + if ( + $line =~ m{ (?:do|require)\s+['"] # do/require + + # Huge list of perl4 modules... + (abbrev|assert|bigfloat|bigint|bigrat + |cacheout|complete|ctime|dotsh|exceptions + |fastcwd|find|finddepth|flush|getcwd|getopt + |getopts|hostname|importenv|look|newgetopt + |open2|open3|pwd|shellwords|stat|syslog + |tainted|termcap|timelocal|validate) + # ... so they end with ".pl" rather than ".pm" + \.pl['"] + }xsm + ) { + my $module = $1; + + $self->pointed_hint('perl-module-uses-perl4-libs-without-dep', + $item->pointer($position), "$module.pl"); + } + + } continue { + ++$position; + } + + close $fd; + } + + return; +} + +sub installable { + my ($self) = @_; + + unless ($self->has_perl_binaries) { + + $self->pointed_hint('package-installs-nonbinary-perl-in-usr-lib-perl5', + $_->pointer) + for @{$self->perl_sources_in_lib}; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Perl/Core/Provides.pm b/lib/Lintian/Check/Languages/Perl/Core/Provides.pm new file mode 100644 index 0000000..b0a3923 --- /dev/null +++ b/lib/Lintian/Check/Languages/Perl/Core/Provides.pm @@ -0,0 +1,83 @@ +# languages/perl/core/provides -- lintian check script (rewrite) -*- perl -*- +# +# Copyright (C) 2004 Marc Brockschmidt +# Copyright (C) 2021 Felix Lechner +# +# Parts of the code were taken from the old check script, which +# was Copyright (C) 1998 Richard Braakman (also licensed under the +# GPL 2 or higher) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Perl::Core::Provides; + +use v5.20; +use warnings; +use utf8; + +use Dpkg::Version qw(version_check); + +use Lintian::Relation::Version qw(versions_compare); + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub always { + my ($self) = @_; + + my $fields = $self->processable->fields; + + return + unless $fields->declares('Version'); + + my $version = $fields->unfolded_value('Version'); + + my $dversion = Dpkg::Version->new($version); + return + unless $dversion->is_valid; + + my ($epoch, $upstream, $debian) + = ($dversion->epoch, $dversion->version, $dversion->revision); + + my $PERL_CORE_PROVIDES= $self->data->load('fields/perl-provides', '\s+'); + + my $name = $fields->value('Package'); + + return + unless $PERL_CORE_PROVIDES->recognizes($name); + + my $core_version = $PERL_CORE_PROVIDES->value($name); + + my $no_revision = "$epoch:$upstream"; + return + unless version_check($no_revision); + + $self->hint('package-superseded-by-perl', "with $core_version") + if versions_compare($core_version, '>=', $no_revision); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Perl/Perl4/Prerequisites.pm b/lib/Lintian/Check/Languages/Perl/Perl4/Prerequisites.pm new file mode 100644 index 0000000..fb5e9be --- /dev/null +++ b/lib/Lintian/Check/Languages/Perl/Perl4/Prerequisites.pm @@ -0,0 +1,124 @@ +# languages/perl/perl4/prerequisites -- lintian check script -*- perl -*- +# +# Copyright (C) 1998 Richard Braakman +# Copyright (C) 2002 Josip Rodin +# Copyright (C) 2016-2019 Chris Lamb <lamby@debian.org> +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Perl::Perl4::Prerequisites; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use File::Basename; +use Unicode::UTF8 qw(encode_utf8); + +use Lintian::Relation; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +# check for obsolete perl libraries +const my $PERL4_PREREQUISITES => + 'libperl4-corelibs-perl:any | perl:any (<< 5.12.3-7)'; + +has satisfies_perl4_prerequisites => ( + is => 'rw', + lazy => 1, + default => sub { + my ($self) = @_; + + return $self->processable->relation('strong') + ->satisfies($PERL4_PREREQUISITES); + } +); + +sub visit_installed_files { + my ($self, $item) = @_; + + # Consider /usr/src/ scripts as "documentation" + # - packages containing /usr/src/ tend to be "-source" .debs + # and usually come with overrides + # no checks necessary at all for scripts in /usr/share/doc/ + # unless they are examples + return + if ($item->name =~ m{^usr/share/doc/} || $item->name =~ m{^usr/src/}) + && $item->name !~ m{^usr/share/doc/[^/]+/examples/}; + + return + unless length $item->interpreter; + + my $basename = basename($item->interpreter); + return + unless $basename eq 'perl'; + + return + unless $item->is_open_ok; + + open(my $fd, '<', $item->unpacked_path) + or die encode_utf8('Cannot open ' . $item->unpacked_path); + + my $position = 1; + while (my $line = <$fd>) { + if ( + $line =~m{ (?:do|require)\s+['"] # do/require + + # Huge list of perl4 modules... + (abbrev|assert|bigfloat|bigint|bigrat + |cacheout|complete|ctime|dotsh|exceptions + |fastcwd|find|finddepth|flush|getcwd|getopt + |getopts|hostname|importenv|look|newgetopt + |open2|open3|pwd|shellwords|stat|syslog + |tainted|termcap|timelocal|validate) + # ... so they end with ".pl" rather than ".pm" + \.pl['"] + }xsm + ) { + + my $module = "$1.pl"; + + my $pointer = $item->pointer($position); + + $self->pointed_hint( + 'script-uses-perl4-libs-without-dep',$pointer, + "(does not satisfy $PERL4_PREREQUISITES)",$module + ) unless $self->satisfies_perl4_prerequisites; + + } + + } continue { + ++$position; + } + + close $fd; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Perl/Perl5.pm b/lib/Lintian/Check/Languages/Perl/Perl5.pm new file mode 100644 index 0000000..8b138ab --- /dev/null +++ b/lib/Lintian/Check/Languages/Perl/Perl5.pm @@ -0,0 +1,61 @@ +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 1999 Joey Hess +# Copyright (C) 2000 Sean 'Shaleh' Perry +# Copyright (C) 2002 Josip Rodin +# Copyright (C) 2007 Russ Allbery +# Copyright (C) 2013-2018 Bastien ROUCARIES +# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org> +# Copyright (C) 2020-2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Perl::Perl5; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_patched_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + # Find mentioning of usr/lib/perl5 inside the packaging + $self->pointed_hint('mentions-deprecated-usr-lib-perl5-directory', + $item->pointer) + if $item->basename ne 'changelog' + && $item->name =~ m{^ debian/ }sx + && $item->name !~ m{^ debian/patches/ }sx + && $item->name !~ m{^ debian/ (?:.+\.)? install $}sx + && $item->bytes =~ m{^ [^#]* usr/lib/perl5 }msx; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Perl/Yapp.pm b/lib/Lintian/Check/Languages/Perl/Yapp.pm new file mode 100644 index 0000000..adf3605 --- /dev/null +++ b/lib/Lintian/Check/Languages/Perl/Yapp.pm @@ -0,0 +1,55 @@ +# languages/perl/yapp -- lintian check script -*- perl -*- +# +# Copyright (C) 2019 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Perl::Yapp; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_patched_files { + my ($self, $item) = @_; + + return + unless $item->name =~ /\.pm$/; + + my $bytes = $item->bytes; + return + unless $bytes; + + $self->pointed_hint('source-contains-prebuilt-yapp-parser', $item->pointer) + if $bytes + =~ /^#\s+This file was generated using Parse::Yapp version [\d.]+/m; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Php.pm b/lib/Lintian/Check/Languages/Php.pm new file mode 100644 index 0000000..948a7a3 --- /dev/null +++ b/lib/Lintian/Check/Languages/Php.pm @@ -0,0 +1,53 @@ +# languages/php -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Php; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + # /etc/php/*/mods-available/*.ini + if ( $item->is_file + && $item->name =~ m{^etc/php/.*/mods-available/.+\.ini$}) { + + $self->pointed_hint('obsolete-comments-style-in-php-ini', + $item->pointer) + if $item->decoded_utf8 =~ /^\s*#/m; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Php/Composer.pm b/lib/Lintian/Check/Languages/Php/Composer.pm new file mode 100644 index 0000000..142c1e8 --- /dev/null +++ b/lib/Lintian/Check/Languages/Php/Composer.pm @@ -0,0 +1,93 @@ +# languages/php/composer -- lintian check script -*- perl -*- +# +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Php::Composer; + +use v5.20; +use warnings; +use utf8; + +use Lintian::Relation; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + my $control = $self->processable->debian_control; + my $source_fields = $control->source_fields; + + for my $field ( + qw(Build-Depends Build-Depends-Indep + Build-Conflicts Build-Conflicts-Indep) + ) { + next + unless $source_fields->declares($field); + + my $position = $source_fields->position($field); + my $pointer = $control->item->pointer($position); + + my $raw = $source_fields->value($field); + my $relation = Lintian::Relation->new->load($raw); + + my $condition = 'composer:any'; + + $self->pointed_hint('composer-prerequisite', $pointer, $field, + '(in source paragraph)') + if $relation->satisfies($condition); + } + + for my $installable ($control->installables) { + my $installable_fields = $control->installable_fields($installable); + + for my $field ( + qw(Pre-Depends Depends Recommends Suggests Breaks + Conflicts Provides Replaces Enhances) + ) { + next + unless $installable_fields->declares($field); + + my $position = $installable_fields->position($field); + my $pointer = $control->item->pointer($position); + + my $relation + = $self->processable->binary_relation($installable, $field); + + my $condition = 'composer:any'; + + $self->pointed_hint('composer-prerequisite', $pointer, $field, + "(in section for $installable)") + if $relation->satisfies($condition); + } + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Php/Embedded.pm b/lib/Lintian/Check/Languages/Php/Embedded.pm new file mode 100644 index 0000000..2287f09 --- /dev/null +++ b/lib/Lintian/Check/Languages/Php/Embedded.pm @@ -0,0 +1,92 @@ +# languages/php/embedded -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Php::Embedded; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +my $PHP_EXT = qr{(?i)\.(?:php|inc|dtd)$}; +my %PHP_FILES = ( + 'libphp-adodb' => qr{(?i)/adodb\.inc\.php$}, + 'smarty3?' => qr{(?i)/Smarty(?:_Compiler)?\.class\.php$}, + 'libphp-phpmailer' => qr{(?i)/class\.phpmailer(\.(?:php|inc))+$}, + 'phpsysinfo' => +qr{(?i)/phpsysinfo\.dtd|/class\.(?:Linux|(?:Open|Net|Free|)BSD)\.inc\.php$}, + 'php-openid' => qr{/Auth/(?:OpenID|Yadis/Yadis)\.php$}, + 'libphp-snoopy' => qr{(?i)/Snoopy\.class\.(?:php|inc)$}, + 'php-markdown' => qr{(?i)/markdown\.php$}, + 'php-geshi' => qr{(?i)/geshi\.php$}, + 'libphp-pclzip' =>qr{(?i)/(?:class[.-])?pclzip\.(?:inc|lib)?\.php$}, + 'libphp-phplayersmenu' => qr{(?i)/.*layersmenu.*/(lib/)?PHPLIB\.php$}, + 'libphp-phpsniff' => qr{(?i)/phpSniff\.(?:class|core)\.php$}, + 'libphp-jabber' => qr{(?i)/(?:class\.)?jabber\.php$}, + 'libphp-simplepie' => + qr{(?i)/(?:class[\.-])?simplepie(?:\.(?:php|inc))+$}, + 'libphp-jpgraph' => qr{(?i)/jpgraph\.php$}, + 'php-fpdf' => qr{(?i)/fpdf\.php$}, + 'php-getid3' => qr{(?i)/getid3\.(?:lib\.)?(?:\.(?:php|inc))+$}, + 'php-php-gettext' => qr{(?i)/(?<!pomo/)streams\.php$}, + 'libphp-magpierss' => qr{(?i)/rss_parse\.(?:php|inc)$}, + 'php-simpletest' => qr{(?i)/unit_tester\.php$}, + 'libsparkline-php' => qr{(?i)/Sparkline\.php$}, + 'libnusoap-php' => qr{(?i)/(?:class\.)?nusoap\.(?:php|inc)$}, + 'php-htmlpurifier' => qr{(?i)/HTMLPurifier\.php$}, + # not yet available in unstable:, + # 'libphp-ixr' => qr{(?i)/IXR_Library(?:\.inc|\.php)+$}, + # 'libphp-kses' => qr{(?i)/(?:class\.)?kses\.php$}, +); + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + # embedded PHP + for my $provider (keys %PHP_FILES) { + + next + if $self->processable->name =~ /^$provider$/; + + next + unless $item->name =~ /$PHP_FILES{$provider}/; + + $self->pointed_hint('embedded-php-library', $item->pointer, + 'please use',$provider); + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Php/Pear.pm b/lib/Lintian/Check/Languages/Php/Pear.pm new file mode 100644 index 0000000..b73b268 --- /dev/null +++ b/lib/Lintian/Check/Languages/Php/Pear.pm @@ -0,0 +1,242 @@ +# langauges/php/pear -- lintian check script -*- perl -*- + +# Copyright (C) 2013 Mathieu Parent <math.parent@gmail.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Php::Pear; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use List::SomeUtils qw(none); +use Unicode::UTF8 qw(encode_utf8); + +const my $DOLLAR => q{$}; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + # Don't check package if it doesn't contain a .php file + if (none { $_->basename =~ m/\.php$/i && !$_->is_dir } + @{$self->processable->patched->sorted_list}){ + return; + } + + my $build_depends = $self->processable->relation('Build-Depends'); + my $package_type = 'unknown'; + + # PEAR or PECL package + my $package_xml = $self->processable->patched->lookup('package.xml'); + my $package2_xml = $self->processable->patched->lookup('package2.xml'); + + my $debian_control = $self->processable->debian_control; + + if (defined($package_xml) || defined($package2_xml)) { + # Checking source builddep + if (!$build_depends->satisfies('pkg-php-tools')) { + $self->hint('pear-package-without-pkg-php-tools-builddep'); + + } else { + # Checking first binary relations + my @binaries = $debian_control->installables; + my $binary = $binaries[0]; + + my $depends + = $self->processable->binary_relation($binary, 'Depends'); + my $recommends + = $self->processable->binary_relation($binary, 'Recommends'); + my $breaks= $self->processable->binary_relation($binary, 'Breaks'); + + $self->hint('pear-package-but-missing-dependency', 'Depends') + unless $depends->satisfies($DOLLAR . '{phppear:Debian-Depends}'); + + $self->hint('pear-package-but-missing-dependency','Recommends') + unless $recommends->satisfies( + $DOLLAR . '{phppear:Debian-Recommends}'); + + $self->hint('pear-package-but-missing-dependency', 'Breaks') + unless $breaks->satisfies($DOLLAR . '{phppear:Debian-Breaks}'); + + # checking description + my $description + = $debian_control->installable_fields($binary) + ->untrimmed_value('Description'); + + $self->hint( + 'pear-package-not-using-substvar', + $DOLLAR . '{phppear:summary}' + )if $description !~ /\$\{phppear:summary\}/; + + $self->hint( + 'pear-package-not-using-substvar', + $DOLLAR . '{phppear:description}' + )if $description !~ /\$\{phppear:description\}/; + + if (defined $package_xml && $package_xml->is_regular_file) { + + # Wild guess package type as in + # PEAR_PackageFile_v2::getPackageType() + open(my $package_xml_fd, '<', $package_xml->unpacked_path) + or die encode_utf8( + 'Cannot open ' . $package_xml->unpacked_path); + + while (my $line = <$package_xml_fd>) { + if ( + $line =~ m{\A \s* < + (php|extsrc|extbin|zendextsrc|zendextbin) + release \s* /? > }xsm + ) { + $package_type = $1; + last; + } + if ($line =~ /^\s*<bundle\s*\/?>/){ + $package_type = 'bundle'; + last; + } + } + + close $package_xml_fd; + + if ($package_type eq 'extsrc') { # PECL package + if (!$build_depends->satisfies('php-dev')) { + + $self->pointed_hint( + 'pecl-package-requires-build-dependency', + $package_xml->pointer,'php-dev'); + } + + if (!$build_depends->satisfies('dh-php')) { + $self->pointed_hint( + 'pecl-package-requires-build-dependency', + $package_xml->pointer,'dh-php'); + } + } + } + } + } + + # PEAR channel + my $channel_xml = $self->processable->patched->lookup('channel.xml'); + $self->pointed_hint('pear-channel-without-pkg-php-tools-builddep', + $channel_xml->pointer) + if defined $channel_xml + && !$build_depends->satisfies('pkg-php-tools'); + + # Composer package + my $composer_json = $self->processable->patched->lookup('composer.json'); + $self->pointed_hint('composer-package-without-pkg-php-tools-builddep', + $composer_json->pointer) + if defined $composer_json + && !($build_depends->satisfies('pkg-php-tools') + || $build_depends->satisfies('dh-sequence-phpcomposer')) + && !defined $package_xml + && !defined $package2_xml; + + # Check rules + if ( + $build_depends->satisfies('pkg-php-tools') + && ( defined $package_xml + || defined $package2_xml + || defined $channel_xml + || defined $composer_json) + ) { + my $rules = $self->processable->patched->resolve_path('debian/rules'); + if (defined $rules && $rules->is_open_ok) { + + my $has_buildsystem_phppear = 0; + my $has_addon_phppear = 0; + my $has_addon_phpcomposer= 0; + my $has_addon_php = 0; + + open(my $rules_fd, '<', $rules->unpacked_path) + or die encode_utf8('Cannot open ' . $rules->unpacked_path); + + while (my $line = <$rules_fd>) { + + while ($line =~ s/\\$// && defined(my $cont = <$rules_fd>)) { + $line .= $cont; + } + + next + if $line =~ /^\s*\#/; + + $has_buildsystem_phppear = 1 + if $line + =~ /^\t\s*dh\s.*--buildsystem(?:=|\s+)(?:\S+,)*phppear(?:,\S+)*\s/; + + $has_addon_phppear = 1 + if $line + =~ /^\t\s*dh\s.*--with(?:=|\s+)(?:\S+,)*phppear(?:,\S+)*\s/; + + $has_addon_phpcomposer = 1 + if $line + =~ /^\t\s*dh\s.*--with(?:=|\s+)(?:\S+,)*phpcomposer(?:,\S+)*\s/; + + $has_addon_php = 1 + if $line + =~ /^\t\s*dh\s.*--with(?:=|\s+)(?:\S+,)*php(?:,\S+)*\s/; + } + + close $rules_fd; + + if ( defined $package_xml + || defined $package2_xml + || defined $channel_xml) { + + $self->pointed_hint('missing-pkg-php-tools-buildsystem', + $rules->pointer, 'phppear') + unless $has_buildsystem_phppear; + + $self->pointed_hint('missing-pkg-php-tools-addon', + $rules->pointer, 'phppear') + unless $has_addon_phppear; + + $self->pointed_hint('missing-pkg-php-tools-addon', + $rules->pointer, 'php') + if $package_type eq 'extsrc' + && !$has_addon_php; + } + + if ( !defined $package_xml + && !defined $package2_xml + && defined $composer_json) { + + $self->pointed_hint('missing-pkg-php-tools-addon', + $rules->pointer, 'phpcomposer') + unless $has_addon_phpcomposer; + } + } + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Php/Pear/Embedded.pm b/lib/Lintian/Check/Languages/Php/Pear/Embedded.pm new file mode 100644 index 0000000..dfb1268 --- /dev/null +++ b/lib/Lintian/Check/Languages/Php/Pear/Embedded.pm @@ -0,0 +1,92 @@ +# languages/php/pear/embedded -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Php::Pear::Embedded; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +my $PEAR_MAGIC = qr{pear[/.]}; +my $PEAR_EXT = qr{(?i)\.php$}; +my %PEAR_FILES = ( + 'php-auth' => qr{/Auth} . $PEAR_EXT, + 'php-auth-http' => qr{/Auth/HTTP} . $PEAR_EXT, + 'php-benchmark' => qr{/Benchmark/(?:Timer|Profiler|Iterate)} + . $PEAR_EXT, + 'php-http' => qr{(?<!/Auth)/HTTP} . $PEAR_EXT, + 'php-cache' => qr{/Cache} . $PEAR_EXT, + 'php-cache-lite' => qr{/Cache/Lite} . $PEAR_EXT, + 'php-compat' => qr{/Compat} . $PEAR_EXT, + 'php-config' => qr{/Config} . $PEAR_EXT, + 'php-crypt-cbc' => qr{/CBC} . $PEAR_EXT, + 'php-date' => qr{/Date} . $PEAR_EXT, + 'php-db' => qr{(?<!/Container)/DB} . $PEAR_EXT, + 'php-file' => qr{(?<!/Container)/File} . $PEAR_EXT, + 'php-log' => + qr{(?:/Log/(?:file|error_log|null|syslog|sql\w*)|/Log)} . $PEAR_EXT, + 'php-mail' => qr{/Mail} . $PEAR_EXT, + 'php-mail-mime' => qr{(?i)/mime(Part)?} . $PEAR_EXT, + 'php-mail-mimedecode' => qr{/mimeDecode} . $PEAR_EXT, + 'php-net-ftp' => qr{/FTP} . $PEAR_EXT, + 'php-net-imap' => qr{(?<!/Container)/IMAP} . $PEAR_EXT, + 'php-net-ldap' => qr{(?<!/Container)/LDAP} . $PEAR_EXT, + 'php-net-smtp' => qr{/SMTP} . $PEAR_EXT, + 'php-net-socket' => qr{(?<!/FTP)/Socket} . $PEAR_EXT, +); + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + # embedded PEAR + for my $provider (keys %PEAR_FILES) { + + next + if $self->processable->name =~ /^$provider$/; + + next + unless $item->name =~ /$PEAR_FILES{$provider}/; + + next + unless length $item->bytes_match($PEAR_MAGIC); + + $self->pointed_hint('embedded-pear-module', $item->pointer, + 'please use',$provider); + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python.pm b/lib/Lintian/Check/Languages/Python.pm new file mode 100644 index 0000000..089fce4 --- /dev/null +++ b/lib/Lintian/Check/Languages/Python.pm @@ -0,0 +1,516 @@ +# languages/python -- lintian check script -*- perl -*- +# +# Copyright (C) 2016 Chris Lamb +# Copyright (C) 2020 Louis-Philippe Veronneau <pollo@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use List::SomeUtils qw(any none); +use Unicode::UTF8 qw(encode_utf8); + +use Lintian::Relation; +use Lintian::Relation::Version qw(versions_lte); + +const my $EMPTY => q{}; +const my $ARROW => q{ -> }; +const my $DOLLAR => q{$}; + +const my $PYTHON3_MAJOR => 3; +const my $PYTHON2_MIGRATION_MAJOR => 2; +const my $PYTHON2_MIGRATION_MINOR => 6; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +my @FIELDS = qw(Depends Pre-Depends Recommends Suggests); +my @IGNORE = qw(-dev$ -docs?$ -common$ -tools$); +my @PYTHON2 = qw(python2:any python2.7:any python2-dev:any); +my @PYTHON3 = qw(python3:any python3-dev:any); + +my %DJANGO_PACKAGES = ( + '^python3-django-' => 'python3-django', + '^python2?-django-' => 'python-django', +); + +my %REQUIRED_DEPENDS = ( + 'python2' => 'python2-minimal:any | python2:any', + 'python3' => 'python3-minimal:any | python3:any', +); + +my %MISMATCHED_SUBSTVARS = ( + '^python3-.+' => $DOLLAR . '{python:Depends}', + '^python2?-.+' => $DOLLAR . '{python3:Depends}', +); + +has ALLOWED_PYTHON_FILES => ( + is => 'rw', + lazy => 1, + default => sub { + my ($self) = @_; + + return $self->data->load('files/allowed-python-files'); + } +); +has GENERIC_PYTHON_MODULES => ( + is => 'rw', + lazy => 1, + default => sub { + my ($self) = @_; + + return $self->data->load('files/generic-python-modules'); + } +); + +my @VERSION_FIELDS = qw(X-Python-Version XS-Python-Version X-Python3-Version); + +has correct_location => (is => 'rw', default => sub { {} }); + +sub source { + my ($self) = @_; + + my @installable_names = $self->processable->debian_control->installables; + for my $installable_name (@installable_names) { + # Python 2 modules + if ($installable_name =~ /^python2?-(.*)$/) { + my $suffix = $1; + + next + if any { $installable_name =~ /$_/ } @IGNORE; + + next + if any { $_ eq "python3-${suffix}" } @installable_names; + + # Don't trigger if we ship any Python 3 module + next + if any { + $self->processable->binary_relation($_, 'all') + ->satisfies($DOLLAR . '{python3:Depends}') + }@installable_names; + + $self->hint('python-foo-but-no-python3-foo', $installable_name); + } + } + + my $build_all = $self->processable->relation('Build-Depends-All'); + $self->hint('build-depends-on-python-sphinx-only') + if $build_all->satisfies('python-sphinx') + && !$build_all->satisfies('python3-sphinx'); + + $self->hint( + 'alternatively-build-depends-on-python-sphinx-and-python3-sphinx') + if $self->processable->fields->value('Build-Depends') + =~ /\bpython-sphinx\s+\|\s+python3-sphinx\b/; + + my $debian_control = $self->processable->debian_control; + + # Mismatched substvars + for my $regex (keys %MISMATCHED_SUBSTVARS) { + my $substvar = $MISMATCHED_SUBSTVARS{$regex}; + + for my $installable_name ($debian_control->installables) { + + next + if any { $installable_name =~ /$_/ } @IGNORE; + + next + if $installable_name !~ qr/$regex/; + + $self->hint('mismatched-python-substvar', $installable_name, + $substvar) + if $self->processable->binary_relation($installable_name, 'all') + ->satisfies($substvar); + } + } + + my $VERSIONS = $self->data->load('python/versions', qr/\s*=\s*/); + + for my $field (@VERSION_FIELDS) { + + next + unless $debian_control->source_fields->declares($field); + + my $pyversion= $debian_control->source_fields->value($field); + + my @valid = ( + ['\d+\.\d+', '\d+\.\d+'],['\d+\.\d+'], + ['\>=\s*\d+\.\d+', '\<\<\s*\d+\.\d+'],['\>=\s*\d+\.\d+'], + ['current', '\>=\s*\d+\.\d+'],['current'], + ['all'] + ); + + my @pyversion = split(/\s*,\s*/, $pyversion); + + if ($pyversion =~ m/^current/) { + $self->hint('python-version-current-is-deprecated', $field); + } + + if (@pyversion > 2) { + if (any { !/^\d+\.\d+$/ } @pyversion) { + $self->hint('malformed-python-version', $field, $pyversion); + } + } else { + my $okay = 0; + for my $rule (@valid) { + if ( + $pyversion[0] =~ /^$rule->[0]$/ + && ( + ( + $pyversion[1] + && $rule->[1] + && $pyversion[1] =~ /^$rule->[1]$/ + ) + || (!$pyversion[1] && !$rule->[1]) + ) + ) { + $okay = 1; + last; + } + } + $self->hint('malformed-python-version', $field, $pyversion) + unless $okay; + } + + if ($pyversion =~ /\b(([23])\.\d+)$/) { + my ($v, $major) = ($1, $2); + my $old = $VERSIONS->value("old-python$major"); + my $ancient = $VERSIONS->value("ancient-python$major"); + + if (versions_lte($v, $ancient)) { + $self->hint('ancient-python-version-field', $field, $v); + } elsif (versions_lte($v, $old)) { + $self->hint('old-python-version-field', $field, $v); + } + } + } + + $self->hint('source-package-encodes-python-version') + if $self->processable->name =~ m/^python\d-/ + && $self->processable->name ne 'python3-defaults'; + + my $build_depends = Lintian::Relation->new; + $build_depends->load_norestriction( + $self->processable->fields->value('Build-Depends')); + + my $pyproject= $self->processable->patched->resolve_path('pyproject.toml'); + if (defined $pyproject && $pyproject->is_open_ok) { + + my %PYPROJECT_PREREQUISITES = ( + 'poetry.core.masonry.api' => 'python3-poetry-core:any', + 'flit_core.buildapi' => 'flit:any', + 'setuptools.build_meta' => 'python3-setuptools:any', + 'pdm.pep517.api' => 'python3-pdm-pep517:any', + 'hatchling.build' => 'python3-hatchling:any', + 'mesonpy' => 'python3-mesonpy:any', + 'sipbuild.api' => 'python3-sipbuild:any' + ); + + open(my $fd, '<', $pyproject->unpacked_path) + or die encode_utf8('Cannot open ' . $pyproject->unpacked_path); + + my $position = 1; + while (my $line = <$fd>) { + + my $pointer = $pyproject->pointer($position); + + # In theory, TOML only uses double quotes. In practice, that's not + # true and only matching for double quotes introduce false negatives + if ($line =~ m{^ \s* build-backend \s* = \s* "([^"]+)" }x + || $line =~ m{^ \s* build-backend \s* = \s* '([^"]+)' }x) { + + my $backend = $1; + + $self->pointed_hint('uses-poetry-cli', $pointer) + if $backend eq 'poetry.core.masonry.api' + && $build_depends->satisfies('python3-poetry:any') + && !$build_depends->satisfies('python3-poetry-core:any'); + + $self->pointed_hint('uses-pdm-cli', $pointer) + if $backend eq 'pdm.pep517.api' + && $build_depends->satisfies('python3-pdm:any') + && !$build_depends->satisfies('python3-pdm-pep517:any'); + + if (exists $PYPROJECT_PREREQUISITES{$backend}) { + + my $prerequisites = $PYPROJECT_PREREQUISITES{$backend} + . ', pybuild-plugin-pyproject:any'; + + $self->pointed_hint( + 'missing-prerequisite-for-pyproject-backend', + $pointer, $backend,"(does not satisfy $prerequisites)") + if !$build_all->satisfies($prerequisites); + } + } + + } continue { + ++$position; + } + + close $fd; + } + + return; +} + +sub visit_installed_files { + my ($self, $item) = @_; + + # .pyc/.pyo (compiled Python files) + # skip any file installed inside a __pycache__ directory + # - we have a separate check for that directory. + $self->pointed_hint('package-installs-python-bytecode', $item->pointer) + if $item->name =~ /\.py[co]$/ + && $item->name !~ m{/__pycache__/}; + + # __pycache__ (directory for pyc/pyo files) + $self->pointed_hint('package-installs-python-pycache-dir', $item->pointer) + if $item->is_dir + && $item->name =~ m{/__pycache__/}; + + if ( $item->is_file + && $item->name + =~ m{^usr/lib/debug/usr/lib/pyshared/(python\d?(?:\.\d+))/(.+)$}) { + + my $correct = "usr/lib/debug/usr/lib/pymodules/$1/$2"; + $self->pointed_hint('python-debug-in-wrong-location', + $item->pointer, "better: $correct"); + } + + # .egg (Python egg files) + $self->pointed_hint('package-installs-python-egg', $item->pointer) + if $item->name =~ /\.egg$/ + && ( $item->name =~ m{^usr/lib/python\d+(?:\.\d+/)} + || $item->name =~ m{^usr/lib/pyshared} + || $item->name =~ m{^usr/share/}); + + # /usr/lib/site-python + $self->pointed_hint('file-in-usr-lib-site-python', $item->pointer) + if $item->name =~ m{^usr/lib/site-python/\S}; + + # pythonX.Y extensions + if ( $item->name =~ m{^usr/lib/python\d\.\d/\S} + && $item->name !~ m{^usr/lib/python\d\.\d/(?:site|dist)-packages/}){ + + $self->pointed_hint('third-party-package-in-python-dir',$item->pointer) + unless $self->processable->source_name =~ m/^python(?:\d\.\d)?$/ + || $self->processable->source_name =~ m{\A python\d?- + (?:stdlib-extensions|profiler|old-doctools) \Z}xsm; + } + + # ---------------- Python file locations + # - The Python people kindly provided the following table. + # good: + # /usr/lib/python2.5/site-packages/ + # /usr/lib/python2.6/dist-packages/ + # /usr/lib/python2.7/dist-packages/ + # /usr/lib/python3/dist-packages/ + # + # bad: + # /usr/lib/python2.5/dist-packages/ + # /usr/lib/python2.6/site-packages/ + # /usr/lib/python2.7/site-packages/ + # /usr/lib/python3.*/*-packages/ + if ( + $item->name =~ m{\A + (usr/lib/debug/)? + usr/lib/python(\d+(?:\.\d+)?)/ + ((?:site|dist)-packages)/(.+) + \Z}xsm + ){ + my ($debug, $pyver, $actual_package_dir, $relative) = ($1, $2, $3, $4); + $debug //= $EMPTY; + + my ($pmaj, $pmin) = split(m{\.}, $pyver, 2); + $pmin //= 0; + + next + if $pmaj < $PYTHON2_MIGRATION_MAJOR; + + my ($module_name) = ($relative =~ m{^([^/]+)}); + + my $actual_python_libpath = "usr/lib/python$pyver/"; + my $specified_python_libpath = "usr/lib/python$pmaj/"; + + # for python 2.X, folder was python2.X and not python2 + $specified_python_libpath = $actual_python_libpath + if $pmaj < $PYTHON3_MAJOR; + + my $specified_package_dir = 'dist-packages'; + + # python 2.4 and 2.5 + $specified_package_dir = 'site-packages' + if $pmaj == $PYTHON2_MIGRATION_MAJOR + && $pmin < $PYTHON2_MIGRATION_MINOR; + + my $actual_module_path + = $debug. $actual_python_libpath. "$actual_package_dir/$module_name"; + my $specified_module_path + = $debug + . $specified_python_libpath + . "$specified_package_dir/$module_name"; + + $self->correct_location->{$actual_module_path} = $specified_module_path + unless $actual_module_path eq $specified_module_path; + + for my $regex ($self->GENERIC_PYTHON_MODULES->all) { + $self->pointed_hint('python-module-has-overly-generic-name', + $item->pointer, "($1)") + if $relative =~ m{^($regex)(?:\.py|/__init__\.py)$}i; + } + + $self->pointed_hint('unknown-file-in-python-module-directory', + $item->pointer) + if $item->is_file + && $relative eq $item->basename # "top-level" + &&!$self->ALLOWED_PYTHON_FILES->matches_any($item->basename, 'i'); + } + + return; +} + +sub installable { + my ($self) = @_; + + $self->hint( + 'python-module-in-wrong-location', + $_ . $ARROW . $self->correct_location->{$_} + )for keys %{$self->correct_location}; + + my $deps + = $self->processable->relation('all') + ->logical_and($self->processable->relation('Provides'), + $self->processable->name); + + my @entries + = $self->processable->changelog + ? @{$self->processable->changelog->entries} + : (); + + # Check for missing dependencies + if ($self->processable->name !~ /-dbg$/) { + for my $item (@{$self->processable->installed->sorted_list}) { + + if ( $item->is_file + && $item->name + =~ m{^usr/lib/(?<version>python[23])[\d.]*/(?:site|dist)-packages} + && !$deps->satisfies($REQUIRED_DEPENDS{$+{version}})) { + + $self->hint('python-package-missing-depends-on-python'); + + last; + } + } + } + + # Check for duplicate dependencies + for my $field (@FIELDS) { + my $dep = $self->processable->relation($field); + FIELD: for my $py2 (@PYTHON2) { + for my $py3 (@PYTHON3) { + + if ($dep->satisfies($py2) && $dep->satisfies($py3)) { + $self->hint('depends-on-python2-and-python3', + $field, "(satisfies $py2, $py3)"); + last FIELD; + } + } + } + } + + my $pkg = $self->processable->name; + + # Python 2 modules + $self->hint('new-package-should-not-package-python2-module', + $self->processable->name) + if $self->processable->name =~ / ^ python2? - /msx + && (none { $pkg =~ m{ $_ }x } @IGNORE) + && @entries == 1 + && $entries[0]->Changes + !~ / \b python [ ]? 2 (?:[.]x)? [ ] (?:variant|version) \b /imsx + && $entries[0]->Changes !~ / \Q$pkg\E /msx; + + # Python applications + if ($self->processable->name !~ /^python[23]?-/ + && (none { $_ eq $self->processable->name } @PYTHON2)) { + for my $field (@FIELDS) { + for my $dep (@PYTHON2) { + + $self->hint( + 'dependency-on-python-version-marked-for-end-of-life', + $field, "(satisfies $dep)") + if $self->processable->relation($field)->satisfies($dep); + } + } + } + + # Django modules + for my $regex (keys %DJANGO_PACKAGES) { + my $basepkg = $DJANGO_PACKAGES{$regex}; + + next + if $self->processable->name !~ /$regex/; + + next + if any { $self->processable->name =~ /$_/ } @IGNORE; + + $self->hint('django-package-does-not-depend-on-django', $basepkg) + unless $self->processable->relation('strong')->satisfies($basepkg); + } + + if ( + $self->processable->name =~ /^python([23]?)-/ + && (none { $self->processable->name =~ /$_/ } @IGNORE) + ) { + my $version = $1 || '2'; # Assume python-foo is a Python 2.x package + my @prefixes = ($version eq '2') ? 'python3' : qw(python python2); + + for my $field (@FIELDS) { + for my $prefix (@prefixes) { + + my $visit = sub { + my $rel = $_; + return if any { $rel =~ /$_/ } @IGNORE; + $self->hint( +'python-package-depends-on-package-from-other-python-variant', + "$field: $rel" + ) if /^$prefix-/; + }; + + $self->processable->relation($field) + ->visit($visit, Lintian::Relation::VISIT_PRED_NAME); + } + } + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/BogusPrerequisites.pm b/lib/Lintian/Check/Languages/Python/BogusPrerequisites.pm new file mode 100644 index 0000000..fe2df7f --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/BogusPrerequisites.pm @@ -0,0 +1,88 @@ +# languages/python/bogus-prerequisites -- lintian check script -*- perl -*- +# +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::BogusPrerequisites; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub installable { + my ($self) = @_; + + $self->what_is_python($self->processable->source_name, + qw{Depends Pre-Depends Recommends}); + + return; +} + +sub source { + my ($self) = @_; + + $self->what_is_python($self->processable->name, + qw{Build-Depends Build-Depends-Indep Build-Depends-Arch}); + + return; +} + +sub what_is_python { + my ($self, $source, @fields) = @_; + + # see Bug#973011 + my @WHAT_IS_PYTHON = qw( + python-is-python2:any + python-dev-is-python2:any + python-is-python3:any + python-dev-is-python3:any + ); + + my %BOGUS_PREREQUISITES; + + unless ($source eq 'what-is-python') { + + for my $unwanted (@WHAT_IS_PYTHON) { + + $BOGUS_PREREQUISITES{$unwanted} + = [grep {$self->processable->relation($_)->satisfies($unwanted)} + @fields]; + } + } + + for my $unwanted (keys %BOGUS_PREREQUISITES) { + + $self->hint('bogus-python-prerequisite', $_, "(satisfies $unwanted)") + for @{$BOGUS_PREREQUISITES{$unwanted}}; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/DistOverrides.pm b/lib/Lintian/Check/Languages/Python/DistOverrides.pm new file mode 100644 index 0000000..2dadeb6 --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/DistOverrides.pm @@ -0,0 +1,80 @@ +# languages/python/dist-overrides -- lintian check script -*- perl -*- +# +# Copyright (C) 2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::DistOverrides; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; +use List::SomeUtils qw(uniq); + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +const my $SPACE => q{ }; + +sub source { + my ($self) = @_; + + my $override_file + = $self->processable->patched->resolve_path('debian/py3dist-overrides'); + return + unless defined $override_file; + + my $contents = $override_file->decoded_utf8; + return + unless length $contents; + + # strip comments + $contents =~ s/^\s*\#.*$//mg; + + # strip empty lines + $contents =~ s/^\s*$//mg; + + # trim leading spaces + $contents =~ s/^\s*//mg; + + my @lines = split(/\n/, $contents); + + # get first component from each line + my @identifiers + = grep { defined } map { (split($SPACE, $_, 2))[0] } @lines; + + my %count; + $count{$_}++ for @identifiers; + + my @duplicates = grep { $count{$_} > 1 } uniq @identifiers; + + $self->hint('duplicate-p3dist-override', $_) for @duplicates; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/Distutils.pm b/lib/Lintian/Check/Languages/Python/Distutils.pm new file mode 100644 index 0000000..cbc30ce --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/Distutils.pm @@ -0,0 +1,77 @@ +# languages/python/distutils -- lintian check script -*- perl -*- +# +# Copyright (C) 2022 Louis-Philippe VĂ©ronneau <pollo@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::Distutils; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +my $PYTHON3_DEPEND + = 'python3:any | python3-dev:any | python3-all:any | python3-all-dev:any'; + +sub visit_patched_files { + my ($self, $item) = @_; + + my $build_all = $self->processable->relation('Build-Depends-All'); + + # Skip if the package doesn't depend on python + return + unless $build_all->satisfies($PYTHON3_DEPEND); + + # Skip if it's not a python file + return + unless $item->name =~ /\.py$/; + + # Skip if we can't open the file + return + unless $item->is_open_ok; + + open(my $fd, '<', $item->unpacked_path) + or die encode_utf8('Cannot open ' . $item->unpacked_path); + + my $position = 1; + while (my $line = <$fd>) { + + my $pointer = $item->pointer($position); + + $self->pointed_hint('uses-python-distutils', $pointer) + if $line =~ m{^from distutils} || $line =~ m{^import distutils}; + } continue { + ++$position; + } + + close $fd; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/Feedparser.pm b/lib/Lintian/Check/Languages/Python/Feedparser.pm new file mode 100644 index 0000000..da716e7 --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/Feedparser.pm @@ -0,0 +1,54 @@ +# languages/python/feedparser -- lintian check script -*- perl -*- + +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::Feedparser; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + # embedded Feedparser library + $self->pointed_hint('embedded-feedparser-library', $item->pointer) + if $item->name =~ m{ / feedparser[.]py $}x + && $item->bytes =~ /Universal feed parser/ + && $self->processable->source_name ne 'feedparser'; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/Homepage.pm b/lib/Lintian/Check/Languages/Python/Homepage.pm new file mode 100644 index 0000000..18a0470 --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/Homepage.pm @@ -0,0 +1,59 @@ +# languages/python/homepage -- lintian check script (rewrite) -*- perl -*- +# +# Copyright (C) 2021 Felix Lechner +# +# Parts of the code were taken from the old check script, which +# was Copyright (C) 1998 Richard Braakman (also licensed under the +# GPL 2 or higher) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::Homepage; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + my $fields = $self->processable->fields; + if ($fields->declares('Homepage')) { + + my $homepage = $fields->value('Homepage'); + + # see Bug#981932 + $self->hint('pypi-homepage', $homepage) + if $homepage + =~ m{^http s? :// (?:www [.])? pypi (:?[.] python)? [.] org/}isx; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/Obsolete.pm b/lib/Lintian/Check/Languages/Python/Obsolete.pm new file mode 100644 index 0000000..e810faa --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/Obsolete.pm @@ -0,0 +1,63 @@ +# languages/python/obsolete -- lintian check script -*- perl -*- +# +# Copyright (C) 1999 Joey Hess +# Copyright (C) 2000 Sean 'Shaleh' Perry +# Copyright (C) 2002 Josip Rodin +# Copyright (C) 2007 Russ Allbery +# Copyright (C) 2013-2018 Bastien ROUCARIES +# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org> +# Copyright (C) 2020 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::Obsolete; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + my $pycompat= $self->processable->patched->resolve_path('debian/pycompat'); + + $self->pointed_hint('debian-pycompat-is-obsolete', $pycompat->pointer) + if defined $pycompat + && $pycompat->is_file; + + my $pyversions + = $self->processable->patched->resolve_path('debian/pyversions'); + + $self->pointed_hint('debian-pyversions-is-obsolete', $pyversions->pointer) + if defined $pyversions + && $pyversions->is_file; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Python/Scripts.pm b/lib/Lintian/Check/Languages/Python/Scripts.pm new file mode 100644 index 0000000..988b915 --- /dev/null +++ b/lib/Lintian/Check/Languages/Python/Scripts.pm @@ -0,0 +1,54 @@ +# languages/python/scripts -- lintian check script -*- perl -*- +# +# Copyright (C) 2016 Chris Lamb +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Python::Scripts; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_installed_files { + my ($self, $item) = @_; + + return + unless $item->name =~ m{(?:usr/)?bin/[^/]+}; + + return + unless $item->is_script; + + $self->pointed_hint('script-uses-unversioned-python-in-shebang', + $item->pointer) + if $item->interpreter =~ m{^(?:/usr/bin/)?python$}; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/R.pm b/lib/Lintian/Check/Languages/R.pm new file mode 100644 index 0000000..daa8462 --- /dev/null +++ b/lib/Lintian/Check/Languages/R.pm @@ -0,0 +1,74 @@ +# Copyright (C) 1998 Christian Schwarz and Richard Braakman +# Copyright (C) 1999 Joey Hess +# Copyright (C) 2000 Sean 'Shaleh' Perry +# Copyright (C) 2002 Josip Rodin +# Copyright (C) 2007 Russ Allbery +# Copyright (C) 2013-2018 Bastien ROUCARIES +# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org> +# Copyright (C) 2020-2021 Felix Lechner +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::R; + +use v5.20; +use warnings; +use utf8; + +use Const::Fast; + +const my $RDATA_MAGIC_LENGTH => 4; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub visit_patched_files { + my ($self, $item) = @_; + + return + unless $item->is_file; + + # Ensure we have a README.source for R data files + if ( $item->basename =~ /\.(?:rda|Rda|rdata|Rdata|RData)$/ + && $item->is_open_ok + && $item->file_type =~ /gzip compressed data/ + && !$self->processable->patched->resolve_path('debian/README.source')){ + + open(my $fd, '<:gzip', $item->unpacked_path) + or die encode_utf8('Cannot open ' . $item->unpacked_path); + + read($fd, my $magic, $RDATA_MAGIC_LENGTH) + or die encode_utf8('Cannot read from ' . $item->unpacked_path); + + close($fd); + + $self->pointed_hint('r-data-without-readme-source', $item->pointer) + if $magic eq 'RDX2'; + } + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/R/Architecture.pm b/lib/Lintian/Check/Languages/R/Architecture.pm new file mode 100644 index 0000000..3ee0bd2 --- /dev/null +++ b/lib/Lintian/Check/Languages/R/Architecture.pm @@ -0,0 +1,69 @@ +# languages/r/architecture -- lintian check script (rewrite) -*- perl -*- +# +# Copyright (C) 2004 Marc Brockschmidt +# Copyright (C) 2021 Felix Lechner +# +# Parts of the code were taken from the old check script, which +# was Copyright (C) 1998 Richard Braakman (also licensed under the +# GPL 2 or higher) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::R::Architecture; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +has have_r_files => (is => 'rw', default => 0); + +sub visit_installed_files { + my ($self, $item) = @_; + + return + if $item->is_dir; + + $self->have_r_files(1) + if $item->name =~ m{^usr/lib/R/.*/DESCRIPTION$} + && $item->decoded_utf8 =~ /^NeedsCompilation: no/m; + + return; +} + +sub installable { + my ($self) = @_; + + $self->hint('r-package-not-arch-all') + if $self->processable->name =~ /^r-(?:cran|bioc|other)-/ + && $self->have_r_files + && $self->processable->fields->value('Architecture') ne 'all'; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/R/SiteLibrary.pm b/lib/Lintian/Check/Languages/R/SiteLibrary.pm new file mode 100644 index 0000000..1ac6ac9 --- /dev/null +++ b/lib/Lintian/Check/Languages/R/SiteLibrary.pm @@ -0,0 +1,71 @@ +# languages/r/site-library -- lintian check script -*- perl -*- + +# Copyright (C) 2020 Dylan Aissi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::R::SiteLibrary; + +use v5.20; +use warnings; +use utf8; + +use Lintian::Relation; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +has r_site_libraries => (is => 'rw', default => sub { [] }); + +sub visit_installed_files { + my ($self, $item) = @_; + + # R site libraries + if ($item->name =~ m{^usr/lib/R/site-library/(.*)/DESCRIPTION$}) { + push(@{$self->r_site_libraries}, $1); + } + + return; +} + +sub installable { + my ($self) = @_; + + $self->hint('ships-r-site-library', $_) for @{$self->r_site_libraries}; + + return + unless @{$self->r_site_libraries}; + + my $depends = $self->processable->relation('strong'); + + # no version allowed for virtual package; no alternatives + $self->hint('requires-r-api') + unless $depends->matches(qr/^r-api-[\w\d+-.]+$/, + Lintian::Relation::VISIT_OR_CLAUSE_FULL); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Ruby.pm b/lib/Lintian/Check/Languages/Ruby.pm new file mode 100644 index 0000000..563f740 --- /dev/null +++ b/lib/Lintian/Check/Languages/Ruby.pm @@ -0,0 +1,72 @@ +# languages/ruby -- lintian check script (rewrite) -*- perl -*- +# +# Copyright (C) 2021 Felix Lechner +# +# Parts of the code were taken from the old check script, which +# was Copyright (C) 1998 Richard Braakman (also licensed under the +# GPL 2 or higher) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Ruby; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + my $fields = $self->processable->fields; + if ($fields->declares('Homepage')) { + + my $homepage = $fields->value('Homepage'); + + # rubygems itself is okay; see Bug#981935 + $self->hint('rubygem-homepage', $homepage) + if $homepage + =~ m{^http s? :// (?:www [.])? rubygems [.] org/gems/}isx; + } + + return; +} + +sub binary { + my ($self) = @_; + + my @prerequisites + = $self->processable->fields->trimmed_list('Depends', qr/,/); + + my @ruby_interpreter = grep { / \b ruby-interpreter \b /x } @prerequisites; + + $self->hint('ruby-interpreter-is-deprecated', $_)for @ruby_interpreter; + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et diff --git a/lib/Lintian/Check/Languages/Rust.pm b/lib/Lintian/Check/Languages/Rust.pm new file mode 100644 index 0000000..140134f --- /dev/null +++ b/lib/Lintian/Check/Languages/Rust.pm @@ -0,0 +1,69 @@ +# languages/rust -- lintian check script -*- perl -*- + +# Copyright (C) 2020 Sylvestre Ledru +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::Check::Languages::Rust; + +use v5.20; +use warnings; +use utf8; + +use Moo; +use namespace::clean; + +with 'Lintian::Check'; + +sub source { + my ($self) = @_; + + my $debian_control = $self->processable->debian_control; + for my $installable ($debian_control->installables) { + + my $fields = $debian_control->installable_fields($installable); + my $extended = $fields->text('Description'); + + # drop synopsis + $extended =~ s/^ [^\n]* \n //sx; + + $self->hint('rust-boilerplate', $installable) + if $extended + =~ /^ \QThis package contains the following binaries built from the Rust crate\E /isx; + } + + return; +} + +sub installable { + my ($self) = @_; + + $self->hint('empty-rust-library-declares-provides') + if $self->processable->name =~ /^librust-/ + && $self->processable->not_just_docs + && length $self->processable->fields->value('Provides'); + + return; +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: syntax=perl sw=4 sts=4 sr et |