diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..914e21d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + perl-job: + runs-on: [self-hosted, "${{ matrix.architecture }}" ] + container: + image: perl:${{ matrix.perl-version }} + strategy: + fail-fast: false + matrix: + architecture: + - X64 + - ARM + perl-version: + - '5.32' + - 'latest' + name: Perl ${{ matrix.perl-version }}:${{ matrix.architecture }} + steps: + - uses: actions/checkout@v2 + - name: Install libraries and cpm + run: | + apt update && apt -y install libprotobuf-dev libprotoc-dev + cpanm local::lib + eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)" + cpanm --mirror http://cpanproxy/ --mirror-only --notest App::cpm + - name: Install depedencies + run: | + eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)" + cpm install -g -v --no-test --resolver 02packages,http://cpanproxy/ --configure-timeout 180 --build-timeout 600 --cpanfile=./cpanfile + - name: Run tests + run: | + eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)" + prove diff --git a/README.pod b/README.pod index 7a2b2e4..84fc767 100644 --- a/README.pod +++ b/README.pod @@ -2,6 +2,12 @@ =head1 ABOUT +=begin html + + + +=end html + This is the source code for perlbot, the resident infobot on Freenode’s #perl channel. See: @@ -24,6 +30,6 @@ This is a semi-complicated situation as while the code is obstensibly open sourc buu has agreed to put his code under the GPL version 3 ( L ) or at your option any later version. -Shlomi Fish licences his changes under any and all of the Expat license, the +Shlomi Fish licenses his changes under any and all of the Expat license, the CC0, the same terms as perl 5, and the Artistic 2.0 license. =cut diff --git a/bin/run-tests b/bin/run-tests new file mode 100755 index 0000000..40e9e3e --- /dev/null +++ b/bin/run-tests @@ -0,0 +1,45 @@ +#! /usr/bin/env perl +# +# Author Shlomi Fish +# Version 0.0.1 +# +use strict; +use warnings; +use autodie; + +# We'd rather avoid exec() here because from our experience, it sometimes +# does not work too reliably on MSWin32. +exit( ( system( "prove", glob("t/*.t") ) == 0 ) ? 0 : 1 ); + +__END__ + +=head1 COPYRIGHT & LICENSE + +Copyright 2019 by Shlomi Fish + +This program is distributed under the MIT / Expat License: +L + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +=cut + diff --git a/cpanfile b/cpanfile index 3b5388f..fc23cae 100644 --- a/cpanfile +++ b/cpanfile @@ -1,165 +1,82 @@ -requires 'Sys::Linux::Namespace' => 'v0.13.0'; -requires 'POE'; -requires 'Parse::RecDescent'; -requires 'Config::General'; -requires 'Cache::FastMmap'; -requires 'POE::Component::IRC::Common'; -requires 'POE::Component::IRC'; -requires 'Text::Handlebars'; - -requires 'Geo::IP'; -requires 'XML::RSS::Parser'; -requires 'WWW::Shorten'; -requires 'WWW::Mechanize'; -requires 'URI::Encode'; -requires 'Text::Glob'; - -requires 'DBD::SQLite'; -requires 'DBI'; -requires 'Net::DNS'; -requires 'HTML::TreeBuilder'; -requires 'Net::INET6Glue::INET_is_INET6'; - -requires 'Net::Dict'; -requires 'HTML::TreeBuilder::XPath'; - -requires 'Data::Dumper'; -requires 'Scalar::Util'; #Required by Data::Dumper -requires 'BSD::Resource'; -requires 'File::Glob'; -requires 'POSIX'; -requires 'POSIX::strptime'; - -requires 'List::Util'; -requires 'List::MoreUtils'; -requires 'List::UtilsBy'; -requires 'Data::Munge'; -requires 'Scalar::MoreUtils'; -requires 'Regexp::Common'; -requires 'Encode'; -requires 'Digest::MD5'; -requires 'Digest::SHA'; -requires 'DateTime'; -requires 'DateTimeX::Easy'; -requires 'Date::Parse'; - -requires 'Moose'; -requires 'MooseX::Declare'; - -requires 'Function::Parameters'; - -requires 'Rand::MersenneTwister'; -# requires 'arybase'; # removed in 5.29 -requires 'Errno'; -requires 'JSON'; -requires 'JSON::PP'; -requires 'JSON::XS'; -requires 'JSON::MaybeXS'; -requires 'Cpanel::JSON::XS'; - -requires 'LWP::Protocol::https'; -requires 'Mojo::DOM'; -requires 'Mojo::DOM::CSS'; -requires 'Mojo::Collection'; -requires 'YAPE::Regex::Explain'; -requires 'bigint'; -requires 'Math::BigInt'; -requires 'Math::BigFloat'; -requires 'Math::BigRat'; -requires 'indirect'; -requires 'Moo'; -requires 'autovivification'; - -requires 'Linux::Seccomp'; -requires 'Cwd'; -# requires 'Algorithm::Permute'; -requires 'File::Slurper'; -requires 'Path::Tiny'; -requires 'Time::Moment'; -requires 'Switch::Plain'; -requires 'Quote::Code'; -# requires 'JSON::Tiny'; # broken in the canary - -requires 'List::SomeUtils'; -requires 'IO::Async'; -requires 'Future'; -requires 'Class::Tiny'; -requires 'Capture::Tiny'; - -requires 'Return::MultiLevel'; -requires 'Try::Tiny::ByClass'; -requires 'IPC::Run'; -requires 'Text::Metaphone'; - -requires 'DBD::SQLite::BundledExtensions'; -requires 'Text::Levenshtein'; -requires 'Text::Metaphone'; -requires 'Math::Round'; -requires 'Twitter::API'; -requires 'Types::Standard'; -requires 'Perl::Tidy'; -requires 'File::Temp'; -requires 'Permute::Named::Iter'; -requires 'Marpa::R2'; -requires 'Syntax::Keyword::Try'; -requires 'File::Open'; -requires 'App::EvalServerAdvanced'; -requires 'Dir::ls'; -requires 'Object::Tap'; -requires 'XML::LibXML'; -# requires 'Sereal'; # comment out temporarily - -requires 'Email::Sender::Transport::Test'; -requires 'Task::Kensho::Async'; -requires 'Task::Kensho::Config'; -#requires 'Task::Kensho::Date'; -#requires 'Task::Kensho::DBDev'; -requires 'Task::Kensho::Email'; -requires 'Task::Kensho::Logging'; -requires 'Task::Kensho::ModuleDev'; -requires 'Task::Kensho::OOP'; -#requires 'Task::Kensho::Testing'; -#requires 'Task::Kensho::XML'; -requires 'Text::Unidecode'; -requires 'experimental'; - -requires 'Math::Calc::Parser'; - -requires 'ReadonlyX'; -requires 'Const::Fast'; -requires 'DateTime::Event::Holiday::US'; -requires 'App::EvalServerAdvanced::ConstantCalc'; - -requires 'Crypt::OpenSSL::X509'; - -requires 'Math::Random::Secure'; # undeclared dep of Data::Random::Flexible -requires 'Data::Random::Flexible'; -requires 'Acme::AsciiEmoji'; -requires 'PadWalker'; -requires 'Encode::Simple'; -requires 'PPR'; -requires 'Keyword::Simple'; -requires 'Unicode::UTF8'; -requires 'List::Gather'; -requires 'Lingua::EN::Inflexion'; -requires 'local::lib'; -requires 'Array::Utils'; -requires 'DBD::SQLite'; -requires 'Mojo::SQLite'; -requires 'FFI::Platypus'; -requires 'Perl6::Take'; -requires 'List::AllUtils'; -requires 'IRC::FromANSI::Tiny'; -requires 'Unicode::GCString'; -requires 'Unicode::Util'; -requires 'Unicode::Collate'; -requires 'more'; -requires 'Data::Dumper::Compact'; -requires 'Carp::Always'; -requires 'V'; -requires 'Path::Tiny'; -requires 'CryptX'; -requires 'MIME::Base64'; -requires 'DateTime::Event::Cron'; -requires 'Regexp::Assemble'; -requires 'Regexp::Optimizer'; +requires "App::EvalServerAdvanced::Protocol"; +requires "autodie"; +requires "CGI"; +requires "Config::General"; +requires "Crypt::Mode::CBC"; +requires "CryptX"; +requires "Data::Dumper"; +requires "DateTime::Event::Cron"; +requires "DateTime::Event::Holiday::US"; +requires "DBD::SQLite"; +requires "DBI"; +requires "Encode"; +requires "Encode"; +requires "Encode"; +requires "Encode"; +requires "experimental"; +requires "Exporter"; +requires "feature"; +requires "FindBin"; +requires "GeoIP2::Database::Reader"; +requires "HTML::Entities"; +requires "HTML::TreeBuilder"; +requires "HTML::TreeBuilder::XPath"; +requires "HTTP::Status"; +requires "IO::Socket::INET"; +requires "IRC::FromANSI::Tiny"; +requires "IRC::Utils"; +requires "JSON"; +requires "JSON::MaybeXS"; +requires "JSON::MaybeXS"; +requires "JSON::MaybeXS"; +requires "JSON::MaybeXS"; +requires "lib"; +requires "lib::relative"; +requires "List::Util"; +requires "List::Util"; +requires "LWP::Simple"; +requires "LWP::UserAgent"; +requires "Memoize"; +requires "Memoize"; +requires "MIME::Base64"; +requires "Module::ScanDeps"; +requires "Net::CIDR"; +requires "Net::Dict"; +requires "Net::DNS"; +requires "Net::INET6Glue::INET_is_INET6"; +requires "Parse::RecDescent"; +requires "Path::Tiny"; +requires "POE"; +requires "POE::Component::IRC"; +requires "POE::Component::IRC::Common"; +requires "POE::Component::IRC::Common"; +requires "POE::Component::IRC::Plugin::AutoJoin"; +requires "POE::Component::IRC::Plugin::Connector"; +requires "POE::Component::IRC::Plugin::NickReclaim"; +requires "POE::Component::IRC::State"; +requires "POE::Component::Server::SimpleHTTP"; +requires "POE::Component::Server::TCP"; +requires "POE::Filter::Reference"; +requires "POE::Session"; +requires "POE::Wheel::ReadWrite"; +requires "POE::Wheel::Run"; +requires "POE::Wheel::SocketFactory"; +requires "PPI"; +requires "Regexp::Assemble"; +requires "Regexp::Optimizer"; +requires "Socket"; +requires "strict"; +requires "Term::ANSIColor"; +requires "Text::Glob"; +requires "Text::Metaphone"; +requires "Twitter::API"; +requires "Unicode::UCD"; +requires "URI::Encode"; +requires "URI::Escape"; +requires "utf8"; +requires "warnings"; +requires "WWW::Mechanize"; +requires "WWW::Shorten"; +requires "WWW::Shorten::TinyURL"; +requires "XML::RSS::Parser"; +requires "Test::Differences"; diff --git a/cpanfile2 b/cpanfile2 deleted file mode 100644 index 5b1864f..0000000 --- a/cpanfile2 +++ /dev/null @@ -1,7 +0,0 @@ -Usage: - % scan-prereqs-cpanfile - - --diff=META.json # Generate diff from META.json - --diff=cpanfile # Generate diff from cpanfile - --ignore=extlib/ - diff --git a/cpanfile_diffed b/cpanfile_diffed deleted file mode 100644 index ab50b1e..0000000 --- a/cpanfile_diffed +++ /dev/null @@ -1,164 +0,0 @@ ---- cpanfile_scanned 2017-06-21 17:40:10.000000000 -0400 -+++ cpanfile_sorted 2017-06-21 17:41:53.000000000 -0400 -@@ -1,80 +1,91 @@ - -requires 'autodie'; -requires 'Cache::FastMmap'; -requires 'Cache::File'; -requires 'Cache::Mmap'; -requires 'Config::General'; -requires 'Cpanel::JSON::XS'; -requires 'Data::Dumper'; -requires 'DBD::SQLite'; -requires 'DBI'; -requires 'Encode'; -requires 'HTTP::Status'; -requires 'IO::String'; -requires 'JSON::MaybeXS'; -requires 'perl', '5.24'; -requires 'POE'; -requires 'POE::Component::IRC'; -requires 'POE::Component::IRC::Common'; -requires 'POE::Component::IRC::Plugin::AutoJoin'; -requires 'POE::Component::IRC::Plugin::Connector'; -requires 'POE::Component::IRC::Plugin::NickReclaim'; -requires 'POE::Component::IRC::State'; -requires 'POE::Component::Server::SimpleHTTP'; -requires 'POE::Component::Server::TCP'; -requires 'POE::Filter::Line'; -requires 'POE::Filter::Reference'; -requires 'POE::Filter::Stream'; -requires 'POE::Session'; -requires 'POE::Wheel::ReadWrite'; -requires 'POE::Wheel::Run'; -requires 'POE::Wheel::SocketFactory'; -requires 'Scalar::Util'; -requires 'Socket'; -requires 'Sys::Linux::Mount'; -requires 'Sys::Linux::Namespace'; -requires 'Template'; -requires 'Term::ANSIColor'; -requires 'Text::ParseWords'; -requires 'Tie::Hash::NamedCapture'; -requires 'Data::Dumper'; - requires 'BSD::Resource'; - requires 'Cache::FastMmap'; - requires 'Parse::RecDescent'; - - requires 'Text::Glob'; - --requires 'Memoize'; - -feature 'perlbot_plugins' => sub { - requires 'App::EvalServerAdvanced::Protocol'; - requires 'Text::Metaphone'; - requires 'Geo::IP'; - requires 'WWW::Mechanize'; - requires 'WWW::Shorten'; --requires 'WWW::Shorten::TinyURL'; - requires 'DBD::SQLite::BundledExtensions'; -}; - -feature 'eval_needed' => { --requires 'Linux::Clone'; - requires 'Moo'; - requires 'Linux::Seccomp'; -+requires 'Mojo::Collection'; -+requires 'Mojo::DOM'; -+requires 'Mojo::DOM::CSS'; - requires 'Moo'; -+requires 'Marpa::R2'; - requires 'JSON'; -+requires 'JSON::PP'; -+requires 'JSON::Tiny'; -+requires 'JSON::XS'; -+requires 'arybase'; -+requires 'autovivification'; -+requires 'bigint'; -+requires 'Capture::Tiny'; -+requires 'Class::Tiny'; - requires 'BSD::Resource'; -+requires 'Syntax::Keyword::Try'; -+requires 'Capture::Tiny'; -+requires 'Class::Tiny'; -+requires 'Cpanel::JSON::XS'; -+requires 'Cwd'; -+requires 'Data::Munge'; -+requires 'Date::Parse'; -+requires 'DateTime'; -+requires 'DateTimeX::Easy'; -+requires 'Digest::MD5'; -+requires 'Digest::SHA'; -+requires 'Errno'; -+requires 'File::Glob'; -+requires 'File::Open'; - requires 'File::Slurper'; - requires 'File::Temp'; -} - -feature 'eval_optional' => { -} - ---- cpanfile_scanned 2017-06-21 18:24:13.000000000 -0400 -+++ cpanfile_sorted 2017-06-21 17:41:53.000000000 -0400 -@@ -1,50 +1,91 @@ - requires 'Encode'; -+requires 'Function::Parameters'; -+requires 'Future'; -+requires 'Geo::IP'; -+requires 'HTML::TreeBuilder'; -+requires 'HTML::TreeBuilder::XPath'; -+requires 'indirect'; -+requires 'IO::Async'; -+requires 'IPC::Run'; -+requires 'JSON'; - requires 'JSON::MaybeXS'; -+requires 'JSON::PP'; -+requires 'JSON::Tiny'; -+requires 'JSON::XS'; --requires 'Linux::Clone'; - requires 'Linux::Seccomp'; -+requires 'List::MoreUtils'; -+requires 'List::SomeUtils'; - requires 'List::Util'; -+requires 'List::UtilsBy'; -+requires 'LWP::Protocol::https'; -+requires 'Marpa::R2'; -+requires 'Math::BigFloat'; -+requires 'Math::BigInt'; -+requires 'Math::BigRat'; -+requires 'Math::Round'; -+requires 'Mojo::Collection'; -+requires 'Mojo::DOM'; -+requires 'Mojo::DOM::CSS'; -+requires 'Moose'; -+requires 'MooseX::Declare'; -+requires 'Net::Dict'; -+requires 'Net::DNS'; -+requires 'Net::INET6Glue::INET_is_INET6'; -+requires 'Path::Tiny'; - requires 'Perl::Tidy'; - requires 'Permute::Named::Iter'; -+requires 'POE'; -+requires 'POE::Component::IRC'; -+requires 'POE::Component::IRC::Common'; -+requires 'POSIX'; -+requires 'Quote::Code'; -+requires 'Rand::MersenneTwister'; -+requires 'Regexp::Common'; -+requires 'Return::MultiLevel'; -+requires 'Scalar::MoreUtils'; -+requires 'Scalar::Util'; #Required by Data::Dumper -+requires 'Switch::Plain'; -+requires 'Syntax::Keyword::Try'; -+requires 'Sys::Linux::Namespace'.013; -+requires 'Text::Levenshtein'; -+requires 'Text::Metaphone'; -+requires 'Time::Moment'; -+requires 'Try::Tiny::ByClass'; -+requires 'Types::Standard'; -+requires 'URI::Encode'; -+requires 'WWW::Mechanize'; -+requires 'WWW::Shorten'; -+requires 'XML::RSS::Parser'; -+requires 'YAPE::Regex::Explain'; diff --git a/cpanfile_scanned b/cpanfile_scanned deleted file mode 100644 index fe2d6bb..0000000 --- a/cpanfile_scanned +++ /dev/null @@ -1,50 +0,0 @@ -requires 'BSD::Resource'; -requires 'Cache::FastMmap'; -requires 'Cache::File'; -requires 'Cache::Mmap'; -requires 'Config::General'; -requires 'DBD::SQLite'; -requires 'DBI'; -requires 'Encode'; -requires 'File::Slurper'; -requires 'File::Temp'; -requires 'HTTP::Status'; -requires 'IO::String'; -requires 'JSON::MaybeXS'; -requires 'Linux::Clone'; -requires 'Linux::Seccomp'; -requires 'List::Util'; -requires 'Memoize'; -requires 'Moo'; -requires 'POE'; -requires 'POE::Component::IRC'; -requires 'POE::Component::IRC::Common'; -requires 'POE::Component::IRC::Plugin::AutoJoin'; -requires 'POE::Component::IRC::Plugin::Connector'; -requires 'POE::Component::IRC::Plugin::NickReclaim'; -requires 'POE::Component::IRC::State'; -requires 'POE::Component::Server::SimpleHTTP'; -requires 'POE::Component::Server::TCP'; -requires 'POE::Filter::Line'; -requires 'POE::Filter::Reference'; -requires 'POE::Filter::Stream'; -requires 'POE::Session'; -requires 'POE::Wheel::ReadWrite'; -requires 'POE::Wheel::Run'; -requires 'POE::Wheel::SocketFactory'; -requires 'Parse::RecDescent'; -requires 'Perl::Tidy'; -requires 'Permute::Named::Iter'; -requires 'Scalar::Util'; -requires 'Socket'; -requires 'Sys::Linux::Mount'; -requires 'Sys::Linux::Namespace'; -requires 'Template'; -requires 'Term::ANSIColor'; -requires 'Text::Glob'; -requires 'Text::Handlebars'; -requires 'Text::Metaphone'; -requires 'Text::ParseWords'; -requires 'Tie::Hash::NamedCapture'; -requires 'autodie'; -requires 'perl', '5.24'; diff --git a/cpanfiletest.pl b/cpanfiletest.pl deleted file mode 100644 index 9c694ed..0000000 --- a/cpanfiletest.pl +++ /dev/null @@ -1,23 +0,0 @@ -use strict; -use warnings; - -use Module::CPANfile; -use Data::Dumper; - -my $file = Module::CPANfile->load("/home/ryan/bots/perlbuut/cpanfile"); - -my $prereqs = $file->prereqs; - -my @phases = $prereqs->phases; -my @prereqs; - -for my $phase (@phases) { - # TODO try/catch and check other types - for my $type (qw/requires recommends/) { - push @prereqs, $prereqs->requirements_for($phase, $type)->required_modules; - } -} - -# TODO uniq - -print Dumper(\@prereqs); diff --git a/cpanfile_sorted b/evalserver_cpanfile similarity index 55% rename from cpanfile_sorted rename to evalserver_cpanfile index f544932..3b5388f 100644 --- a/cpanfile_sorted +++ b/evalserver_cpanfile @@ -1,91 +1,165 @@ -requires 'App::EvalServerAdvanced'; -requires 'arybase'; -requires 'autovivification'; -requires 'bigint'; -requires 'BSD::Resource'; -requires 'Cache::FastMmap'; -requires 'Capture::Tiny'; -requires 'Class::Tiny'; +requires 'Sys::Linux::Namespace' => 'v0.13.0'; +requires 'POE'; +requires 'Parse::RecDescent'; requires 'Config::General'; -requires 'Cpanel::JSON::XS'; -requires 'Cwd'; -requires 'Data::Dumper'; -requires 'Data::Munge'; -requires 'Date::Parse'; -requires 'DateTime'; -requires 'DateTimeX::Easy'; +requires 'Cache::FastMmap'; +requires 'POE::Component::IRC::Common'; +requires 'POE::Component::IRC'; +requires 'Text::Handlebars'; + +requires 'Geo::IP'; +requires 'XML::RSS::Parser'; +requires 'WWW::Shorten'; +requires 'WWW::Mechanize'; +requires 'URI::Encode'; +requires 'Text::Glob'; + requires 'DBD::SQLite'; -requires 'DBD::SQLite::BundledExtensions'; requires 'DBI'; +requires 'Net::DNS'; +requires 'HTML::TreeBuilder'; +requires 'Net::INET6Glue::INET_is_INET6'; + +requires 'Net::Dict'; +requires 'HTML::TreeBuilder::XPath'; + +requires 'Data::Dumper'; +requires 'Scalar::Util'; #Required by Data::Dumper +requires 'BSD::Resource'; +requires 'File::Glob'; +requires 'POSIX'; +requires 'POSIX::strptime'; + +requires 'List::Util'; +requires 'List::MoreUtils'; +requires 'List::UtilsBy'; +requires 'Data::Munge'; +requires 'Scalar::MoreUtils'; +requires 'Regexp::Common'; +requires 'Encode'; requires 'Digest::MD5'; requires 'Digest::SHA'; -requires 'Encode'; -requires 'Errno'; -requires 'File::Glob'; -requires 'File::Open'; -requires 'File::Slurper'; -requires 'File::Temp'; -requires 'Function::Parameters'; -requires 'Future'; -requires 'Geo::IP'; -requires 'HTML::TreeBuilder'; -requires 'HTML::TreeBuilder::XPath'; -requires 'indirect'; -requires 'IO::Async'; -requires 'IPC::Run'; -requires 'JSON'; -requires 'JSON::MaybeXS'; -requires 'JSON::PP'; -requires 'JSON::Tiny'; -requires 'JSON::XS'; -requires 'Linux::Seccomp'; -requires 'List::MoreUtils'; -requires 'List::SomeUtils'; -requires 'List::Util'; -requires 'List::UtilsBy'; -requires 'LWP::Protocol::https'; -requires 'Marpa::R2'; -requires 'Math::BigFloat'; -requires 'Math::BigInt'; -requires 'Math::BigRat'; -requires 'Math::Round'; -requires 'Mojo::Collection'; -requires 'Mojo::DOM'; -requires 'Mojo::DOM::CSS'; -requires 'Moo'; +requires 'DateTime'; +requires 'DateTimeX::Easy'; +requires 'Date::Parse'; + requires 'Moose'; requires 'MooseX::Declare'; -requires 'Net::Dict'; -requires 'Net::DNS'; -requires 'Net::INET6Glue::INET_is_INET6'; -requires 'Parse::RecDescent'; -requires 'Path::Tiny'; -requires 'Perl::Tidy'; -requires 'Permute::Named::Iter'; -requires 'POE'; -requires 'POE::Component::IRC'; -requires 'POE::Component::IRC::Common'; -requires 'POSIX'; -requires 'Quote::Code'; + +requires 'Function::Parameters'; + requires 'Rand::MersenneTwister'; -requires 'Regexp::Common'; -requires 'Return::MultiLevel'; -requires 'Scalar::MoreUtils'; -requires 'Scalar::Util'; #Required by Data::Dumper +# requires 'arybase'; # removed in 5.29 +requires 'Errno'; +requires 'JSON'; +requires 'JSON::PP'; +requires 'JSON::XS'; +requires 'JSON::MaybeXS'; +requires 'Cpanel::JSON::XS'; + +requires 'LWP::Protocol::https'; +requires 'Mojo::DOM'; +requires 'Mojo::DOM::CSS'; +requires 'Mojo::Collection'; +requires 'YAPE::Regex::Explain'; +requires 'bigint'; +requires 'Math::BigInt'; +requires 'Math::BigFloat'; +requires 'Math::BigRat'; +requires 'indirect'; +requires 'Moo'; +requires 'autovivification'; + +requires 'Linux::Seccomp'; +requires 'Cwd'; +# requires 'Algorithm::Permute'; +requires 'File::Slurper'; +requires 'Path::Tiny'; +requires 'Time::Moment'; requires 'Switch::Plain'; -requires 'Syntax::Keyword::Try'; -requires 'Sys::Linux::Namespace'.013; -requires 'Text::Glob'; -requires 'Text::Handlebars'; +requires 'Quote::Code'; +# requires 'JSON::Tiny'; # broken in the canary + +requires 'List::SomeUtils'; +requires 'IO::Async'; +requires 'Future'; +requires 'Class::Tiny'; +requires 'Capture::Tiny'; + +requires 'Return::MultiLevel'; +requires 'Try::Tiny::ByClass'; +requires 'IPC::Run'; +requires 'Text::Metaphone'; + +requires 'DBD::SQLite::BundledExtensions'; requires 'Text::Levenshtein'; requires 'Text::Metaphone'; -requires 'Text::Metaphone'; -requires 'Time::Moment'; -requires 'Try::Tiny::ByClass'; +requires 'Math::Round'; requires 'Twitter::API'; requires 'Types::Standard'; -requires 'URI::Encode'; -requires 'WWW::Mechanize'; -requires 'WWW::Shorten'; -requires 'XML::RSS::Parser'; -requires 'YAPE::Regex::Explain'; +requires 'Perl::Tidy'; +requires 'File::Temp'; +requires 'Permute::Named::Iter'; +requires 'Marpa::R2'; +requires 'Syntax::Keyword::Try'; +requires 'File::Open'; +requires 'App::EvalServerAdvanced'; +requires 'Dir::ls'; +requires 'Object::Tap'; +requires 'XML::LibXML'; +# requires 'Sereal'; # comment out temporarily + +requires 'Email::Sender::Transport::Test'; +requires 'Task::Kensho::Async'; +requires 'Task::Kensho::Config'; +#requires 'Task::Kensho::Date'; +#requires 'Task::Kensho::DBDev'; +requires 'Task::Kensho::Email'; +requires 'Task::Kensho::Logging'; +requires 'Task::Kensho::ModuleDev'; +requires 'Task::Kensho::OOP'; +#requires 'Task::Kensho::Testing'; +#requires 'Task::Kensho::XML'; +requires 'Text::Unidecode'; +requires 'experimental'; + +requires 'Math::Calc::Parser'; + +requires 'ReadonlyX'; +requires 'Const::Fast'; +requires 'DateTime::Event::Holiday::US'; +requires 'App::EvalServerAdvanced::ConstantCalc'; + +requires 'Crypt::OpenSSL::X509'; + +requires 'Math::Random::Secure'; # undeclared dep of Data::Random::Flexible +requires 'Data::Random::Flexible'; +requires 'Acme::AsciiEmoji'; +requires 'PadWalker'; +requires 'Encode::Simple'; +requires 'PPR'; +requires 'Keyword::Simple'; +requires 'Unicode::UTF8'; +requires 'List::Gather'; +requires 'Lingua::EN::Inflexion'; +requires 'local::lib'; +requires 'Array::Utils'; +requires 'DBD::SQLite'; +requires 'Mojo::SQLite'; +requires 'FFI::Platypus'; +requires 'Perl6::Take'; +requires 'List::AllUtils'; +requires 'IRC::FromANSI::Tiny'; +requires 'Unicode::GCString'; +requires 'Unicode::Util'; +requires 'Unicode::Collate'; +requires 'more'; +requires 'Data::Dumper::Compact'; +requires 'Carp::Always'; +requires 'V'; +requires 'Path::Tiny'; +requires 'CryptX'; +requires 'MIME::Base64'; +requires 'DateTime::Event::Cron'; +requires 'Regexp::Assemble'; +requires 'Regexp::Optimizer'; diff --git a/myscandeps.pl b/myscandeps.pl new file mode 100644 index 0000000..7ded9a5 --- /dev/null +++ b/myscandeps.pl @@ -0,0 +1,22 @@ +use Module::ScanDeps; +use Data::Dumper; + +my @files = ('./bin/cpan_fetch.pl', './bin/generate_metaphones.pl', './bin/test_eval.pl', './asndb/mkasn.pl', './plugins/head.pm', './plugins/echo.pm', './plugins/packages.pm', './plugins/translate.pm', './plugins/save_config.pm', './plugins/nick_lookup.pm', './plugins/tell.pm', './plugins/conf.pm', './plugins/oeis.pm', './plugins/reload_plugins.pm', './plugins/seen.pm', './plugins/part.pm', './plugins/utf8.pm', './plugins/cache_check.pm', './plugins/title.pm', './plugins/geoip.pm', './plugins/twitter.pm', './plugins/8ball.pm', './plugins/conf_dump.pm', './plugins/unicode.pm', './plugins/shorten.pm', './plugins/karma.pm', './plugins/join.pm', './plugins/perldoc.pm', './plugins/allowpaste.pm', './plugins/help.pm', './plugins/rss_title.pm', './plugins/get.pm', './plugins/plugins.pm', './plugins/define.pm', './plugins/default.pm', './plugins/host.pm', './plugins/arg.pm', './plugins/quote.pm', './plugins/pastebinadmin.pm', './plugins/null.pm', './plugins/host_lookup.pm', './plugins/zippit.pm', './plugins/talktome.pm', './plugins/factoids.pm', './plugins/karma_modify.pm', './plugins/google.pm', './plugins/compose.pm', './plugins/more.pm', './plugins/core.pm', './plugins/chatbot.pm', './plugins/rss.pm', './plugins/supereval.pm', './plugins/restart.pm', './plugins/karmatop.pm', './package_lists/generate_list_debian.pl', './lib/Bot/BB3.pm', './lib/Bot/BB3/Logger.pm', './lib/Bot/BB3/PluginManager.pm', './lib/Bot/BB3/ConfigParser.pm', './lib/Bot/BB3/DebugCrypt.pm', './lib/Bot/BB3/MacroQuote.pm', './lib/Bot/BB3/Roles/Console.pm', './lib/Bot/BB3/Roles/RestAPI.pm', './lib/Bot/BB3/Roles/Evalpastebin.pm', './lib/Bot/BB3/Roles/SocketMessageIRC.pm', './lib/Bot/BB3/Roles/IRC.pm', './lib/Bot/BB3/Roles/PasteBot.pm', './lib/Bot/BB3/PluginConfigParser.pm', './lib/Bot/BB3/PluginWrapper.pm'); + +my $hash_ref = scan_deps( + # files => \@files, + files => ["plugins/geoip.pm"], + recurse => 0, +); + +my @keys = keys %$hash_ref; + +my @used = sort {$a cmp $b} grep {!m|Bot/BB3|} grep {exists $hash_ref->{$_}{used_by} } @keys; + +my @mods = map {s|/|::|g; s|.pm$||r} @used; + +#print Dumper(\@mods); + +for my $mod (@mods) { + printf "requires '%s';\n", $mod; +} diff --git a/plugins/core.pm b/plugins/core.pm index b425fb6..d6f63f0 100644 --- a/plugins/core.pm +++ b/plugins/core.pm @@ -29,10 +29,12 @@ sub { if ( Module::CoreList->can('deprecated_in') ) { my $dep = Module::CoreList->deprecated_in($module); print " and deprecated in $dep" if $dep; + return 'handled'; } if ( Module::CoreList->can('removed_from') ) { my $rem = Module::CoreList->removed_from($module); print " and removed from $rem" if $rem; + return 'handled'; } } else { @@ -42,10 +44,12 @@ sub { print 'Found', scalar @modules, ':', join ',', map { $_ . ' in ' . Module::CoreList->first_release($_) } @modules; + return 'handled'; } else { print "Module $module does not appear to be in core. Perhaps capitalization matters or try using the 'cpan' command to search for it."; + return 'handled'; } } } diff --git a/plugins/factoids.pm b/plugins/factoids.pm index 65a1e09..db51c3c 100644 --- a/plugins/factoids.pm +++ b/plugins/factoids.pm @@ -10,6 +10,8 @@ use Text::Metaphone; use strict; use Encode qw/decode/; use JSON::MaybeXS qw/encode_json/; +use PPI; +use PPI::Dumper; use Data::Dumper; use List::Util qw/min max/; @@ -553,13 +555,20 @@ sub get_fact_substitute ($self, $subject, $name, $said) { my ($aliasserver, $aliasnamespace) = $self->get_alias_namespace($said); my ($server, $namespace) = $self->get_namespace($said); - if ( ($said->{body} =~ m{^(?:\s*substitute)?\s*(.*?)\s*=~\s*s /([^/]+ ) /([^/]* )/([gi]*)\s*$}ix) - || ($said->{body} =~ m{^(?:\s*substitute)?\s*(.*?)\s*=~\s*s\|([^|]+ ) \|([^|]* )\|([gi]*)\s*$}ix) - || ($said->{body} =~ m{^(?:\s*substitute)?\s*(.*?)\s*=~\s*s\{([^\}]+)\}\{([^\}]*?)\}([gi]*)\s*$}ix) - || ($said->{body} =~ m{^(?:\s*substitute)?\s*(.*?)\s*=~\s*s\(([^)]+ )\)\(([^)]*? )\)([gi]*)\s*$}ix) - || ($said->{body} =~ m{^(?:\s*substitute)?\s*(.*?)\s*=~\s*s <([^>]+ ) > <([^>]*? ) >([gi]*)\s*$}ix)) + if ($said->{body} =~ m{^(?:\s*substitute)?\s*(.*?)\s*=~\s*s(.*)$}ix) { - my ($subject, $match, $subst, $flags) = ($1, $2, $3, $4); + my ($subject, $regex) = ($1, $2); + my $pdoc = PPI::Document->new(\$regex); + return "Failed to parse $regex" unless $pdoc; + + # TODO handle tr|y/// + my $token = $pdoc->find(sub {$_[1]->isa('PPI::Token::Regexp::Substitute')})->[0]; + + return "Couldn't find s/// in $regex" unless $token; + + my $match = $token->get_match_string; + my $subst = $token->get_substitute_string; + my $flags = join '', keys +{$token->get_modifiers()}->%*; # TODO does this need to be done via the ->get_fact() instead now? my $fact = $self->_db_get_fact(_clean_subject($subject), 0, $server, $namespace); @@ -572,11 +581,6 @@ sub get_fact_substitute ($self, $subject, $name, $said) { #moving this to its own function for cleanliness $result = $self->_fact_substitute($pred, $match, $subst, $flags); - # my( $self, $body, $name, $said ) = @_; - - # $body =~ s/^\s*learn\s+//; - # my( $subject, $predicate ) = split /\s+as\s+/, $body, 2; - # TODO why is this calling there? # let this fail for now my $ret = $self->get_fact_learn("learn $subject as $result", $name, $said, $subject, $result); diff --git a/plugins/oeis.pm b/plugins/oeis.pm index 67d753c..dedf201 100644 --- a/plugins/oeis.pm +++ b/plugins/oeis.pm @@ -6,15 +6,13 @@ use CGI; use LWP::Simple; use WWW::Shorten 'TinyURL'; -sub { - my($said) = @_; - my $q = $said->{"body"}; +sub query_oeis { + my ($q)=@_; warn 1; if( $q =~ /^\s*(?:(?:help|wtf|\?|\:)\s*)?$/i ) { - print "see http://oeis.org/"; - return; + return([], ["see http://oeis.org/"]); } warn 2; my $uri = "http://oeis.org/search?q=" . CGI::escape($q)."&fmt=text"; @@ -24,8 +22,7 @@ sub { my $nrfound = $1; unless( /^%N (\S+) (.*)/m ) { - print "Reply from OEIS in unknown format 2"; - return; + return([ "Reply from OEIS in unknown format 2"],[]); } warn 3; my($anum, $title) = ($1, $2); @@ -35,21 +32,28 @@ sub { warn 3.5; if (1 == $nrfound) { my $outuri = sprintf "http://oeis.org/%s", $anum; - print sprintf "%s %.256s: %.512s", $outuri, $title, $elts; + return ([],[sprintf( "%s %.256s: %.512s", $outuri, $title, $elts)]); } else { my $outuri1 = "http://oeis.org/searchs?q=" . CGI::escape($q); warn 3.6; # my $outuri = makeashorterlink($outuri1) || $outuri1; - print sprintf "%s %.10s(1/%d) %.256s: %.512s", $outuri1, $anum, $nrfound, $title, $elts; + return([], [sprintf( "%s %.10s(1/%d) %.256s: %.512s", $outuri1, $anum, $nrfound, $title, $elts)]); } } elsif (/^no matches/mi) { - print "No matches found"; + return([], ["No matches found"]); warn 4 } else { warn 5; - print "Reply from OEIS in unknown format: $_"; + return([ "Reply from OEIS in unknown format: $_"], []); } } +sub { + my($said) = @_; + my $q = $said->{"body"}; + my ($err, $out) = query_oeis($q); + print "Error: @$err\n" if @$err; + print "@$out\n"; +} __DATA__ Search for a sequence in the On-Line Encyclopedia of Integer Sequences (http://tinyurl.com/2blo2w) Syntax, oeis 1,1,2,3,5 diff --git a/t/arg-plugin.t b/t/arg-plugin.t new file mode 100644 index 0000000..2344c7b --- /dev/null +++ b/t/arg-plugin.t @@ -0,0 +1,23 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; +use Test::More; +use lib::relative './lib', '../lib', '..'; +use t::simple_plugin; +use Encode qw/encode/; + +load_plugin("arg"); + +check("&n", "perlbot", ['FOO'], "empty but valid"); + +check("&a", "", ['FOO'], "macro args"); # this one is difficult to test for, it really gets the arguments to the parent macro +check("", "", ['FOO'], "empty arguments, needs better check"); + +check("&h", "irc.client.example.com", ['FOO'], "host"); +check("&c", "##NULL", ['FOO'], "channel"); +check("&o", 0, ['FOO'], "is op?"); +check("&s", "irc.server.example.com", ['FOO'], "server"); + +done_testing(); diff --git a/t/core-plugin.t b/t/core-plugin.t new file mode 100644 index 0000000..e69efa2 --- /dev/null +++ b/t/core-plugin.t @@ -0,0 +1,15 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; +use Test::More; +use lib::relative './lib', '../lib', '..'; +use t::simple_plugin; + +load_plugin("core"); + +check("", "usage: core Module::Here", ["handled"], "usage help"); +check("CGI", "CGI Added to perl core as of 5.004 and deprecated in 5.019007", ["handled"], "deprecated"); +check("Data::Dumper", "Data::Dumper Added to perl core as of 5.005", ["handled"], "never gonna give it up"); +done_testing(); diff --git a/t/echo-plugin.t b/t/echo-plugin.t new file mode 100644 index 0000000..fabc036 --- /dev/null +++ b/t/echo-plugin.t @@ -0,0 +1,16 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; +use Test::More; +use lib::relative './lib', '../lib', '..'; +use t::simple_plugin; +use Encode qw/encode/; + +load_plugin("echo"); + +check("", "", [1], "empty but valid"); +check("Hello World", "Hello World", [1], "HW"); +check("\N{SNOWMAN}", encode("utf8", "\N{SNOWMAN}"), [1], "Encoding correctly"); +done_testing(); diff --git a/t/lib/t/common.pm b/t/lib/t/common.pm new file mode 100644 index 0000000..9663356 --- /dev/null +++ b/t/lib/t/common.pm @@ -0,0 +1,48 @@ +package t::common; + +use strict; +use warnings; +use utf8; +use parent 'Exporter'; + +our @EXPORT=qw/load_plugin make_said/; + +# This doesn't let us test multiple plugins at a time, which might be needed for the compose plugin +# This can be fixed later +our $plugin; + +sub load_plugin { + my $name = shift; + + my $fullname = "plugins/$name.pm"; + + $plugin = require $fullname; +} + +sub make_said +{ + my ($body, $who, $server, $channel) = @_; + + # TODO make this fill out a lot more of the said object + + $who //= "perlbot"; + + my @args = split /\s+/, $body; + my $said = { + body => $body, + recommended_args => \@args, + macro_args => $body, + name => $who, + ircname => $who."irc", + host => "irc.client.example.com", + sender_raw => "", # this never gets filled out + channel => $channel // "##NULL", + server => $server // "irc.server.example.com", + by_chan_op => 0, + captured => "", + }; + + return $said; +} + +1; diff --git a/t/lib/t/simple_plugin.pm b/t/lib/t/simple_plugin.pm new file mode 100644 index 0000000..f9f0368 --- /dev/null +++ b/t/lib/t/simple_plugin.pm @@ -0,0 +1,29 @@ +package t::simple_plugin; + +use strict; +use warnings; +use utf8; +use parent 'Exporter'; +use t::common; + +our @EXPORT=qw/load_plugin make_said check/; + +use Test::Differences qw/ eq_or_diff /; +use Capture::Tiny qw/capture/; + +sub check +{ + local $Test::Builder::Level = $Test::Builder::Level + 1; + my ( $body, $want, $res, $blurb ) = @_; + + my $said = make_said($body); + my ($out, $err, @result) = capture { + $t::common::plugin->( $said ); + }; + + return eq_or_diff( $err, "", "no errors" ) + && eq_or_diff(\@result, $res, "Result is correct") + && eq_or_diff( $out, $want, $blurb ); +} + +1; diff --git a/t/oeis-plugin.t b/t/oeis-plugin.t new file mode 100644 index 0000000..bcb17da --- /dev/null +++ b/t/oeis-plugin.t @@ -0,0 +1,15 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; +use Test::More tests => 1; +use lib '.'; +use plugins::oeis; + +# TEST +like( + (query_oeis("1,2,6,24"))[1][0], + qr#https?://oeis\.org/.*?Factorial numbers: n!#ms, + "factorials", +); diff --git a/t/quote-plugin.t b/t/quote-plugin.t new file mode 100644 index 0000000..788c9cc --- /dev/null +++ b/t/quote-plugin.t @@ -0,0 +1,20 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; +use Test::More; +use lib::relative './lib', '../lib', '..'; +use t::simple_plugin; + +load_plugin("quote"); + +check("", "", [], "do nothing"); +check('d TESTING HERE', q{"TESTING HERE"}, [1], 'quote d simple'); +check('c TESTING HERE', q{TESTING HERE}, [1], 'quote d simple'); +check(qq{d "TESTING \nHERE"}, q{"\\x22TESTING \\x0aHERE\\x22"}, [1], 'quote d complex'); +check(qq{c "TESTING \nHERE"}, q{\\x22TESTING \\x0aHERE\\x22}, [1], 'quote c complex'); +check(qq{e "TESTING \nHERE"}, q{\\x22TESTING\\x20\\x0aHERE\\x22}, [1], 'quote e complex'); +check(qq{f "TESTING \nHERE"}, q{"\\x22TESTING\\x20\\x0aHERE\\x22"}, [1], 'quote f complex'); +check('h TESTING HERE', q{54455354494e472048455245}, [1], 'quote h'); +done_testing(); diff --git a/t/unicode-plugin.t b/t/unicode-plugin.t new file mode 100644 index 0000000..290678b --- /dev/null +++ b/t/unicode-plugin.t @@ -0,0 +1,31 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; +use Test::More; +use lib::relative './lib', '../lib', '..'; +use t::simple_plugin; +use Encode qw/encode/; + +load_plugin("unicode"); + +# TEST*2 +check( + "perl", + "U+0070 (70): LATIN SMALL LETTER P [p] ". + "U+0065 (65): LATIN SMALL LETTER E [e] ". + "U+0072 (72): LATIN SMALL LETTER R [r] ". + "U+006C (6c): LATIN SMALL LETTER L [l]\n", + [1], + "ascii" +); + +# TEST*2 +check( + "💟", + encode("utf8", "U+1F49F (f0 9f 92 9f): HEART DECORATION [💟]\n"), + [1], + "emoji" ); + +done_testing();