Cannot resolve caller infix:<->(Instant, Mu); none of these signatures match: ($x = 0) (\a, \b) (Real \a, Real \b) (Int:D \a, Int:D \b --> Int:D) (int $a, int $b --> int) (Num:D \a, Num:D \b) (num $a, num $b --> num) (Range:D \a, Real:D \b) (Rational \a, Rational \b) (Rational \a, Int \b) (Int \a, Rational \b) (Complex:D \a, Complex:D \b --> Complex:D) (Complex:D \a, Real \b --> Complex:D) (Real \a, Complex:D \b --> Complex:D) (Instant:D $a, Instant:D $b) (Instant:D $a, Real:D $b) (Duration:D $a, Real $b) (Duration:D $a, Duration:D $b) (DateTime:D \a, DateTime:D \b) (DateTime:D \a, Duration:D \b) (Date:D $d, Int:D $x) (Date:D $a, Date:D $b) (Telemetry:U \a, Telemetry:U \b) (Telemetry:D \a, Telemetry:U \b --> Telemetry::Period:D) (Telemetry:U \a, Telemetry:D \b --> Telemetry::Period:D) (Telemetry:D \a, Telemetry:D \b --> Telemetry::Period) in method irc-to-me at /home/bisectable/git/whateverable/lib/Whateverable.pm6 line 161 (⚠ uncommitted) in sub at /home/bisectable/git/whateverable/lib/Whateverable.pm6 line 64 (⚠ uncommitted) in block at /home/bisectable/.rakudobrew/moar-master/install/share/perl6/site/sources/91300E2449A727CEFB2F4BC51BC01429C567F65B (IRC::Client) line 290 in method handle-event at /home/bisectable/.rakudobrew/moar-master/install/share/perl6/site/sources/91300E2449A727CEFB2F4BC51BC01429C567F65B (IRC::Client) line 285 in block at /home/bisectable/.rakudobrew/moar-master/install/share/perl6/site/sources/91300E2449A727CEFB2F4BC51BC01429C567F65B (IRC::Client) line 109 in block at /home/bisectable/.rakudobrew/moar-master/install/share/perl6/site/sources/91300E2449A727CEFB2F4BC51BC01429C567F65B (IRC::Client) line 106
Created
January 25, 2018 23:28
-
-
Save Whateverable/bcf71ec09b0573235215e221ec05bb51 to your computer and use it in GitHub Desktop.
bisectable6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uptime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright © 2016-2017 | |
# Aleks-Daniel Jakimenko-Aleksejev <alex.jakimenko@gmail.com> | |
# Copyright © 2016 | |
# Daniel Green <ddgreen@gmail.com> | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU Affero General Public License as published by | |
# the Free Software Foundation, either version 3 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 Affero General Public License for more details. | |
# | |
# You should have received a copy of the GNU Affero General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
use File::Directory::Tree; | |
use File::Temp; | |
use HTTP::UserAgent; | |
use IRC::Client::Message; | |
use IRC::Client; | |
use IRC::TextColor; | |
use JSON::Fast; | |
use Number::Denominate; | |
use Pastebin::Gist; | |
use Terminal::ANSIColor; | |
use Text::Diff::Sift4; | |
use Misc; | |
our $RAKUDO = (%*ENV<TESTABLE> // ‘’).contains(‘rakudo-mock’) | |
?? ‘./t/data/rakudo’.IO.absolute | |
!! ‘./data/rakudo-moar’.IO.absolute; | |
constant MOARVM = ‘./data/moarvm’.IO.absolute; | |
constant SOURCE = ‘https://github.com/perl6/whateverable’; | |
constant WIKI = ‘https://github.com/perl6/whateverable/wiki/’; | |
constant WORKING-DIRECTORY = ‘.’.IO.absolute; # TODO not supported yet | |
constant ARCHIVES-LOCATION = “{WORKING-DIRECTORY}/data/builds”.IO.absolute; | |
constant BUILDS-LOCATION = ‘/tmp/whateverable/’.IO.absolute; | |
constant MESSAGE-LIMIT is export = 260; | |
constant COMMITS-LIMIT = 500; | |
our $GIST-LIMIT = 10_000; | |
constant $CAVE = ‘#whateverable’; | |
constant $PARENTS = ‘AlexDaniel’, ‘MasterDuke’; | |
our $RAKUDO-REPO = ‘https://github.com/rakudo/rakudo’; | |
our $CONFIG = from-json slurp; | |
constant Message = IRC::Client::Message; | |
unit role Whateverable[:$default-timeout = 10] does IRC::Client::Plugin does Helpful; | |
my $default-stdin = slurp ‘stdin’; | |
has $!bad-releases = set ‘2016.01’, ‘2016.01.1’; | |
method TWEAK { | |
# wrap around everything to catch exceptions | |
once { # per class | |
self.^lookup(‘irc-to-me’).wrap: sub ($self, $msg) { | |
LEAVE sleep 0.02; # https://github.com/perl6/whateverable/issues/163 | |
try { with (callsame) { return $_ but Reply($msg) } else { return } } | |
$self.handle-exception: $!, $msg | |
}; | |
self.^lookup(‘filter’).wrap: sub ($self, $response) { | |
my &filter = nextcallee; | |
try { return filter $self, $response } | |
try { return filter $self, $self.handle-exception($!, $response.?msg) } | |
‘Sorry kid, that's not my department.’ | |
}; | |
} | |
# TODO roles should not have TWEAK method | |
} | |
method handle-exception($exception, $msg?) { | |
CATCH { # exception handling is too fat, so let's do this also… | |
.note; | |
return ‘Exception was thrown while I was trying to handle another exception…’ | |
~ ‘ What are they gonna do to me, Sarge? What are they gonna do⁈’ | |
} | |
if $exception ~~ Whateverable::X::HandleableAdHoc { # oh, it's OK! | |
return $exception.message but Reply($_) with $msg; | |
return $exception.message | |
} | |
note $exception; | |
with $msg { | |
if .channel ne $CAVE { | |
.irc.send-cmd: ‘PRIVMSG’, $CAVE, “I'm acting stupid on {.channel}. Help me.”, | |
:server(.server), :prefix($PARENTS.join(‘, ’) ~ ‘: ’) | |
} | |
} | |
my ($text, @files) = flat self.awesomify-exception: $exception; | |
@files .= map({ ‘uncommitted-’ ~ .split(‘/’).tail => .IO.slurp }); | |
@files.push: ‘|git-diff-HEAD.patch’ => run(:out, ‘git’, ‘diff’, ‘HEAD’).out.slurp-rest if @files; | |
@files.push: ‘result.md’ => $text; | |
my $return = (‘’ but FileStore(%@files)) | |
but PrettyLink({“No! It wasn't me! It was the one-armed man! Backtrace: $_”}); | |
# https://youtu.be/MC6bzR9qmxM?t=97 | |
$return = $return but Reply($_) with $msg; | |
$return | |
} | |
method awesomify-exception($exception) { | |
my @local-files; | |
my $sha = run(:out, ‘git’, ‘rev-parse’, ‘--verify’, ‘HEAD’).out.slurp-rest; | |
‘<pre>’ ~ | |
$exception.gist.lines.map({ | |
# TODO Proper way to get data out of exceptions? | |
# For example, right now it is broken for paths with spaces | |
when /:s ^([\s**2|\s**6]in \w+ \S* at “{WORKING-DIRECTORY}/”?)$<path>=[\S+]( | |
[<.ws>‘(’<-[)]>+‘)’]? line )$<line>=[\d+]$/ { | |
my $status = run :out, ‘git’, ‘status’, ‘--porcelain’, ‘--untracked-files=no’, | |
‘--’, ~$<path>; | |
proceed if !$status && !%*ENV<DEBUGGABLE>; # not a repo file and not in the debug mode | |
my $private-debugging = !$status; | |
$status = $status.out.slurp-rest; | |
my $uncommitted = $status && !$status.starts-with: ‘ ’; # not committed yet | |
@local-files.push: ~$<path> if $uncommitted || $private-debugging; | |
my $href = $uncommitted || $private-debugging | |
?? “#file-uncommitted-{$<path>.split(‘/’).tail.lc.trans(‘.’ => ‘-’)}-” # TODO not perfect but good enough | |
!! “{SOURCE}/blob/$sha/{markdown-escape $<path>}#”; | |
$href ~= “L$<line>”; | |
markdown-escape($0) ~ | |
# let's hope for the best ↓ | |
“<a href="$href">{$<path>}</a>” ~ | |
markdown-escape($1 ~ $<line>) ~ | |
($uncommitted ?? ‘ (⚠ uncommitted)’ !! ‘’) | |
} | |
default { $_ } | |
}).join(“\n”) | |
~ ‘</pre>’, @local-files | |
} | |
multi method irc-to-me(Message $msg where .text ~~ | |
#↓ Matches only one space on purpose (for whitespace-only stdin) | |
/:i^ [stdin] [‘ ’|‘=’] [clear|delete|reset|unset] $/) { | |
$default-stdin = slurp ‘stdin’; | |
‘STDIN is reset to the default value’ | |
} | |
multi method irc-to-me(Message $msg where .text ~~ /:i^ [stdin] [‘ ’|‘=’] $<stdin>=.* $/) { | |
$default-stdin = self.process-code: ~$<stdin>, $msg; | |
“STDIN is set to «{shorten $default-stdin, 200}»” # TODO is 200 a good limit | |
} | |
multi method irc-to-me(Message $ where .text ~~ /:i^ [source|url] ‘?’? $/ --> SOURCE) {} | |
multi method irc-to-me(Message $ where .text ~~ /:i^ wiki ‘?’? $/) { self.get-wiki-link } | |
multi method irc-to-me(Message $msg where .text ~~ /:i^ help ‘?’? $/) { | |
self.help($msg) ~ “ # See wiki for more examples: {self.get-wiki-link}” | |
} | |
multi method irc-to-me(Message $msg where .text ~~ /:i^ uptime $/) { | |
use nqp; | |
use Telemetry; | |
(denominate now - INIT now) ~ ‘, ’ | |
~ T<max-rss>.fmt(‘%.2f’) ÷ 1024 ~ ‘MiB maxrss. ’ | |
~ (with nqp::getcomp("perl6") { | |
“This is {.implementation} version {.config<version>} ” | |
~ “built on {.backend.version_string} ” | |
~ “implementing {.language_name} {.language_version}.” | |
}) | |
} | |
multi method irc-notice-me( $ --> ‘Sorry, it is too private here’) {} # TODO issue #16 | |
multi method irc-privmsg-me($ --> ‘Sorry, it is too private here’) {} # TODO issue #16 | |
multi method irc-to-me($) { | |
‘I cannot recognize this command. See wiki for some examples: ’ ~ self.get-wiki-link | |
} | |
sub I'm-alive is export { | |
use NativeCall; | |
sub sd_notify(int32, str --> int32) is native(‘systemd’) {*}; | |
sd_notify 0, ‘WATCHDOG=1’; # this may be called too often, see TODO below | |
} | |
multi method irc-all($) { | |
# TODO https://github.com/zoffixznet/perl6-IRC-Client/issues/50 | |
#I'm-alive; | |
$.NEXT | |
} | |
method get-wiki-link { WIKI ~ self.^name } | |
method get-short-commit($original-commit) { # TODO not an actual solution tbh | |
$original-commit ~~ /^ <xdigit> ** 7..40 $/ | |
?? $original-commit.substr(0, 7) | |
!! $original-commit | |
} | |
# TODO $default-timeout is VNNull when working in non-OOP style. Rakudobug it? | |
sub get-output(*@run-args, :$timeout = $default-timeout || 10, | |
:$stdin, :$ENV, :$cwd = $*CWD, :$chomp = True) is export { | |
my $proc = Proc::Async.new: |@run-args; | |
my $fh-stdin; | |
LEAVE .close with $fh-stdin; | |
my $temp-file; | |
LEAVE unlink $_ with $temp-file; | |
with $stdin { | |
if $stdin ~~ IO::Path { | |
$fh-stdin = $stdin.open | |
} elsif $stdin ~~ IO::Handle { | |
$fh-stdin = $stdin | |
} else { | |
$temp-file = write-code $stdin; | |
$fh-stdin = $temp-file.IO.open | |
} | |
$proc.bind-stdin: $fh-stdin | |
} | |
my @chunks; | |
my $result; | |
my $s-start = now; | |
my $s-end; | |
react { | |
whenever $proc.stdout { @chunks.push: $_ }; # RT #131763 | |
whenever $proc.stderr { @chunks.push: $_ }; | |
whenever Promise.in($timeout) { | |
$proc.kill; # TODO sends HUP, but should kill the process tree instead | |
@chunks.push: “«timed out after $timeout seconds»” | |
} | |
whenever $proc.start: :$ENV, :$cwd { #: scheduler => BEGIN ThreadPoolScheduler.new { # TODO do we need to set scheduler? | |
$result = $_; | |
$s-end = now; | |
done | |
} | |
} | |
my $output = @chunks.join; | |
%( | |
output => $chomp ?? $output.chomp !! $output, | |
exit-code => $result.exitcode, | |
signal => $result.signal, | |
time => $s-end - $s-start, | |
) | |
} | |
sub perl6-grep($stdin, $regex is copy, :$timeout = 180, :$complex = False, :$hack = 0) is export { | |
my $full-commit = to-full-commit ‘HEAD’ ~ (‘^’ x $hack); | |
die “No build for $full-commit. Oops!” unless build-exists $full-commit; | |
$regex = “m⦑ $regex ⦒”; | |
# TODO can we do something smarter? | |
my $sep = $complex ?? 「“\0\0”」 !! 「“\0”」; | |
my $magic = “INIT \$*ARGFILES.nl-in = $sep; INIT \$*OUT.nl-out = $sep;” | |
~ 「use nqp;」 | |
~ 「 next unless」 | |
~ ($complex ?? 「 nqp::substr($_, 0, nqp::index($_, “\0”)) ~~」 !! ‘’) ~ “\n” | |
~ $regex ~ “;\n” | |
~ 「last if $++ > 」 ~ $GIST-LIMIT; | |
my $filename = write-code $magic; | |
LEAVE unlink $_ with $filename; | |
my $result = run-snippet $full-commit, $filename, :$timeout, :$stdin, args => (‘-np’,); | |
my $output = $result<output>; | |
# numbers less than zero indicate other weird failures ↓ | |
grumble “Something went wrong ($output)” if $result<signal> < 0; | |
$output ~= “ «exit code = $result<exit-code>»” if $result<exit-code> ≠ 0; | |
$output ~= “ «exit signal = {Signal($result<signal>)} ($result<signal>)»” if $result<signal> ≠ 0; | |
grumble $output if $result<exit-code> ≠ 0 or $result<signal> ≠ 0; | |
my @elems = $output.split: ($complex ?? “\0\0” !! “\0”), :skip-empty; | |
if @elems > $GIST-LIMIT { | |
grumble “Cowardly refusing to gist more than $GIST-LIMIT lines” | |
} | |
return ‘Found nothing!’ if @elems == 0; | |
@elems | |
} | |
sub build-exists($full-commit-hash, :$backend=‘rakudo-moar’) is export { | |
“{ARCHIVES-LOCATION}/$backend/$full-commit-hash.zst”.IO ~~ :e | |
or | |
“{ARCHIVES-LOCATION}/$backend/$full-commit-hash”.IO ~~ :e # long-term storage (symlink to a large archive) | |
} | |
method get-similar($tag-or-hash, @other?, :$repo=$RAKUDO) { | |
my @options = @other; | |
my @tags = get-output(cwd => $repo, ‘git’, ‘tag’, | |
‘--format=%(*objectname)/%(objectname)/%(refname:strip=2)’, | |
‘--sort=-taggerdate’)<output>.lines | |
.map(*.split(‘/’)) | |
.grep({ build-exists .[0] || .[1] }) | |
.map(*[2]); | |
my $cutoff = $tag-or-hash.chars max 7; | |
my @commits = get-output(cwd => $repo, ‘git’, ‘rev-list’, | |
‘--all’, ‘--since=2014-01-01’)<output> | |
.lines.map(*.substr: 0, $cutoff); | |
# flat(@options, @tags, @commits).min: { sift4($_, $tag-or-hash, 5, 8) } | |
my $ans = ‘HEAD’; | |
my $ans_min = ∞; | |
for flat @options, @tags, @commits { | |
my $dist = sift4 $_, $tag-or-hash, $cutoff; | |
if $dist < $ans_min { | |
$ans = $_; | |
$ans_min = $dist; | |
} | |
} | |
$ans | |
} | |
sub run-smth($full-commit-hash, $code, :$backend=‘rakudo-moar’) is export { | |
my $build-prepath = “{BUILDS-LOCATION}/$backend”; | |
my $build-path = “$build-prepath/$full-commit-hash”; | |
my $archive-path = “{ARCHIVES-LOCATION}/$backend/$full-commit-hash.zst”; | |
my $archive-link = “{ARCHIVES-LOCATION}/$backend/$full-commit-hash”; | |
mkdir $build-prepath; # create all parent directories just in case | |
# (may be needed for isolated /tmp) | |
# lock on the destination directory to make | |
# sure that other bots will not get in our way. | |
while run(:err(Nil), ‘mkdir’, ‘--’, $build-path).exitcode ≠ 0 { | |
if %*ENV<TESTABLE> { | |
use NativeCall; | |
sub kill(int32, int32) is native {*}; | |
sub getppid(--> int32) is native {*}; | |
kill getppid, 10; # SIGUSR1 | |
} | |
note “$build-path is locked. Waiting…”; | |
sleep 0.5 # should never happen if setup correctly | |
} | |
if $archive-path.IO ~~ :e { | |
my $proc = run :out, :bin, ‘pzstd’, ‘-dqc’, ‘--’, $archive-path; | |
run :in($proc.out), :bin, ‘tar’, ‘x’, ‘--absolute-names’; | |
} else { | |
my $proc = run :out, :bin, ‘lrzip’, ‘-dqo’, ‘-’, ‘--’, $archive-link; | |
run :in($proc.out), :bin, ‘tar’, ‘--extract’, ‘--absolute-names’, ‘--’, $build-path; | |
} | |
my $return = $code($build-path); # basically, we wrap around $code | |
rmtree $build-path; | |
$return | |
} | |
# TODO $default-timeout is VNNull when working in non-OOP style. Rakudobug it? | |
sub run-snippet($full-commit-hash, $file, :$backend=‘rakudo-moar’, :@args=Empty, | |
:$timeout=$default-timeout||10, :$stdin=$default-stdin, :$ENV) is export { | |
run-smth :$backend, $full-commit-hash, -> $path { | |
“$path/bin/perl6”.IO !~~ :e | |
?? %(output => ‘Commit exists, but a perl6 executable could not be built for it’, | |
exit-code => -1, signal => -1, time => -1,) | |
!! get-output “$path/bin/perl6”, |@args, | |
‘--’, $file, :$stdin, :$timeout, :$ENV, :!chomp | |
} | |
} | |
method get-commits($_, :$repo=$RAKUDO) { | |
return .split: /‘,’\s*/ if .contains: ‘,’; | |
if /^ $<start>=\S+ ‘..’ $<end>=\S+ $/ { | |
if run(:out(Nil), :err(Nil), :cwd($repo), | |
‘git’, ‘rev-parse’, ‘--verify’, $<start>).exitcode ≠ 0 { | |
grumble “Bad start, cannot find a commit for “$<start>”” | |
} | |
if run(:out(Nil), :err(Nil), :cwd($repo), | |
‘git’, ‘rev-parse’, ‘--verify’, $<end>).exitcode ≠ 0 { | |
grumble “Bad end, cannot find a commit for “$<end>”” | |
} | |
my $result = get-output :cwd($repo), ‘git’, ‘rev-list’, ‘--reverse’, | |
“$<start>^..$<end>”; # TODO unfiltered input | |
grumble ‘Couldn't find anything in the range’ if $result<exit-code> ≠ 0; | |
my @commits = $result<output>.lines; | |
if @commits.elems > COMMITS-LIMIT { | |
grumble “Too many commits ({@commits.elems}) in range, you're only allowed {COMMITS-LIMIT}” | |
} | |
return @commits | |
} | |
return self.get-tags: ‘2015-12-24’, :$repo if /:i ^ [ releases | v? 6 ‘.’? c ] $/; | |
return self.get-tags: ‘2014-01-01’, :$repo if /:i ^ all $/; | |
return ~$<commit> if /:i ^ compare \s $<commit>=\S+ $/; | |
return $_ | |
} | |
method get-tags($date, :$repo=$RAKUDO) { | |
my @tags = <HEAD>; | |
my %seen; | |
for get-output(cwd => $repo, ‘git’, ‘log’, ‘--pretty="%d"’, | |
‘--tags’, ‘--no-walk’, “--since=$date”)<output>.lines -> $tag { | |
next unless $tag ~~ /:i ‘tag:’ \s* ((\d\d\d\d\.\d\d)[\.\d\d?]?) /; # TODO use tag -l | |
next if $!bad-releases{$0}:exists; | |
next if %seen{$0[0]}++; | |
@tags.push($0) | |
} | |
@tags.reverse | |
} | |
sub to-full-commit($commit, :$short=False, :$repo=$RAKUDO) is export { | |
return if run(:out(Nil), :err(Nil), :cwd($repo), | |
‘git’, ‘rev-parse’, ‘--verify’, $commit).exitcode ≠ 0; # make sure that $commit is valid | |
my $result = get-output cwd => $repo, | |
|(‘git’, ‘rev-list’, ‘-1’, # use rev-list to handle tags | |
($short ?? ‘--abbrev-commit’ !! Empty), $commit); | |
return if $result<exit-code> ≠ 0; | |
return unless $result<output>; | |
$result<output> | |
} | |
sub write-code($code) is export { | |
my ($filename, $filehandle) = tempfile :!unlink; | |
$filehandle.print: $code; | |
$filehandle.close; | |
$filename | |
} | |
sub process-url($url, $msg) is export { | |
my $ua = HTTP::UserAgent.new; | |
my $response; | |
try { | |
$response = $ua.get: $url; | |
CATCH { | |
grumble ‘It looks like a URL, but for some reason I cannot download it’ | |
~ “ ({.message})” | |
} | |
} | |
if not $response.is-success { | |
grumble ‘It looks like a URL, but for some reason I cannot download it’ | |
~ “ (HTTP status line is {$response.status-line}).” | |
} | |
if not $response.content-type.contains: ‘text/plain’ | ‘perl’ { | |
grumble “It looks like a URL, but mime type is ‘{$response.content-type}’” | |
~ ‘ while I was expecting something with ‘text/plain’ or ‘perl’’ | |
~ ‘ in it. I can only understand raw links, sorry.’ | |
} | |
my $body = $response.decoded-content; | |
.reply: ‘Successfully fetched the code from the provided URL.’ with $msg; | |
sleep 0.02; # https://github.com/perl6/whateverable/issues/163 | |
$body | |
} | |
method process-code($code is copy, $msg) { | |
$code ~~ m{^ ( ‘http’ s? ‘://’ \S+ ) } | |
?? process-url(~$0, $msg) | |
!! $code.subst: :g, ‘’, “\n” | |
} | |
multi method filter($response where (.encode.elems > MESSAGE-LIMIT | |
or ?.?additional-files | |
or (!~$_ and $_ ~~ ProperStr))) { | |
# Here $response is a Str with a lot of stuff mixed in (possibly) | |
my $description = ‘Whateverable’; | |
my $text = colorstrip $response.?long-str // ~$response; | |
my %files; | |
%files<result> = $text if $text; | |
%files.push: $_ with $response.?additional-files; | |
if $response ~~ Reply { | |
$description = $response.msg.server.current-nick; | |
%files<query> = $_ with $response.?msg.text; | |
} | |
my $url = self.upload: %files, public => !%*ENV<DEBUGGABLE>, :$description; | |
$url = $response.link-msg()($url) if $response ~~ PrettyLink; | |
$url | |
} | |
multi method filter($text is copy) { | |
ansi-to-irc($text).trans: | |
“\n” => ‘’, | |
3.chr => 3.chr, 0xF.chr => 0xF.chr, # keep these for IRC colors | |
|((^32)».chr Z=> (0x2400..*).map(*.chr)), # convert all unreadable ASCII crap | |
127.chr => ‘␡’, /<:Cc>/ => ‘␦’ | |
} | |
method upload(%files is copy, :$description = ‘’, Bool :$public = True) { | |
if %*ENV<TESTABLE> { | |
my $nick = $.irc.servers.values[0].current-nick; | |
my $gists-path = “{BUILDS-LOCATION}/tist/$nick”; | |
rmtree $gists-path if $gists-path.IO ~~ :d; | |
mkdir $gists-path; | |
spurt “$gists-path/{.key}”, .value for %files; | |
return ‘https://whatever.able/fakeupload’; | |
} | |
%files = %files.pairs.map: { .key => %( ‘content’ => .value ) }; # github format | |
my $gist = Pastebin::Gist.new(token => $CONFIG<github><access_token>); | |
return $gist.paste: %files, desc => $description, public => $public | |
} | |
method selfrun($nick is copy, @alias?) { | |
$nick ~= ‘test’ if %*ENV<DEBUGGABLE>; | |
.run with IRC::Client.new( | |
:$nick | |
:userreal($nick.tc) | |
:username($nick.substr(0, 3) ~ ‘-able’) | |
:password(?%*ENV<TESTABLE> ?? ‘’ !! $CONFIG<irc><login password>.join: ‘:’) | |
:@alias | |
# IPv4 address of chat.freenode.net is hardcoded so that we can double the limit ↓ | |
:host(%*ENV<TESTABLE> ?? ‘127.0.0.1’ !! (‘chat.freenode.net’, ‘185.30.166.38’).pick) | |
:channels(%*ENV<DEBUGGABLE> | |
?? ‘#whateverable’ | |
!! %*ENV<TESTABLE> | |
?? “#whateverable_$nick” | |
!! (|<#perl6 #perl6-dev #zofbot #moarvm>, $CAVE) ) | |
:debug(?%*ENV<DEBUGGABLE>) | |
:plugins(self) | |
:filters( -> |c { self.filter(|c) } ) | |
) | |
} | |
# TODO move somewhere | |
# TODO commit unused | |
sub subprocess-commit($commit, $filename, $full-commit, :%ENV) is export { | |
return ‘No build for this commit’ unless build-exists $full-commit; | |
$_ = run-snippet $full-commit, $filename, :%ENV; # actually run the code | |
# numbers less than zero indicate other weird failures ↓ | |
return “Cannot test this commit ($_<output>)” if .<signal> < 0; | |
my $output = .<output>; | |
$output ~= “ «exit code = $_<exit-code>»” if .<exit-code> ≠ 0; | |
$output ~= “ «exit signal = {Signal($_<signal>)} ($_<signal>)»” if .<signal> ≠ 0; | |
$output | |
} | |
# vim: expandtab shiftwidth=4 ft=perl6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Sakefile b/Sakefile | |
index d40e428..d0f72dc 100644 | |
--- a/Sakefile | |
+++ b/Sakefile | |
@@ -16,7 +16,8 @@ for @bots -> $file { | |
my $bot = to-name $file; | |
task ‘debug:’ ~ ( $bot | $bot.lc ), { | |
note “Starting $bot…”; | |
- run $file, :env(|%*ENV, PERL6LIB => ‘lib’, DEBUGGABLE => 1); | |
+ run $file, :in(‘config.json’.IO.open), | |
+ :env(|%*ENV, PERL6LIB => ‘lib’, DEBUGGABLE => 1); | |
True | |
} | |
task ‘kill:’ ~ ( $bot | $bot.lc ), { | |
diff --git a/bin/Bloatable.p6 b/bin/Bloatable.p6 | |
index 5966f30..7b0498f 100755 | |
--- a/bin/Bloatable.p6 | |
+++ b/bin/Bloatable.p6 | |
@@ -60,7 +60,8 @@ method did-you-mean($out) { | |
return if $out<exit-code> == 0; | |
return unless $out<output> ~~ /(‘no such data source:’ .*)/; | |
$0.tc ~ ‘ (Did you mean one of these: ’ | |
- ~ get-output(‘bloaty’, ‘--list-sources’)<output>.lines.join(‘ ’) | |
+ ~ get-output(‘bloaty’, ‘--list-sources’ | |
+ )<output>.lines.map(*.words[0]).join(‘ ’) | |
~ ‘ ?)’ | |
} | |
diff --git a/bin/Greppable.p6 b/bin/Greppable.p6 | |
index 2b6c4a9..e695c41 100755 | |
--- a/bin/Greppable.p6 | |
+++ b/bin/Greppable.p6 | |
@@ -91,7 +91,7 @@ multi method irc-to-me($msg) { | |
run :out(Nil), :cwd($ECO-PATH), ‘git’, ‘pull’; | |
my $result = get-output :cwd($ECO-PATH), |@cmd; | |
- grumble ‘Sorry, can't do that’ if $result<exit-code> ≠ 0 | 1 or $result<signal> ≠ 0; | |
+ grumble ‘Sorry, can't do that’ if $result<exit-code> != 0 | 1 or $result<signal> != 0; | |
grumble ‘Found nothing!’ unless $result<output>; | |
my %commits = (); | |
diff --git a/bin/Releasable.p6 b/bin/Releasable.p6 | |
index b3ead49..d3a8c09 100755 | |
--- a/bin/Releasable.p6 | |
+++ b/bin/Releasable.p6 | |
@@ -142,7 +142,7 @@ sub blockers() { | |
my %data = from-json $response.decoded-content; | |
return { summary => ‘R6 is weird’ } unless %data<tickets>:exists; | |
my @tickets = %data<tickets>.list; | |
- return { summary => ‘No blockers’ } unless @tickets; | |
+ return { summary => ‘Blockers: https://github.com/rakudo/rakudo/issues?q=is:issue+is:open+label:%22%E2%9A%A0+blocker+%E2%9A%A0%22’ } unless @tickets; | |
my $summary = “{+@tickets} blocker{@tickets ≠ 1 ?? ‘s’ !! ‘’}”; | |
{:$summary, :@tickets} | |
} | |
@@ -164,12 +164,11 @@ multi method irc-to-me($msg where /^ :i \s* | |
return if none %blockers<tickets>, %stats<unlogged>, %stats<warnings>; | |
# ↓ And here just to make a pretty gist ↓ | |
- my &escape-html = { .trans: (‘&’, ‘<’, ‘>’) => (‘&’, ‘<’, ‘>’) }; | |
my %files; | |
my $blockers = join “\n”, (%blockers<tickets> // ()).map: { ‘<a href="’ | |
~ $TICKET-URL ~ .<ticket_id> ~ ‘">RT #’ | |
- ~ .<ticket_id> ~ ‘</a> ’ ~ escape-html .<subject> }; | |
+ ~ .<ticket_id> ~ ‘</a> ’ ~ html-escape .<subject> }; | |
%files<!blockers!.md> = ‘<pre>’ ~ $blockers ~ ‘</pre>’ if %blockers<tickets>; | |
my $warnings = .join(“\n”) with %stats<warnings>; | |
@@ -183,7 +182,7 @@ multi method irc-to-me($msg where /^ :i \s* | |
‘--format=[<a href="’ ~ $RAKUDO-REPO ~ ‘/commit/%H">%h</a>]’, | |
“--abbrev=$SHA-LENGTH”, ‘--quiet’, |%stats<unlogged>; | |
my $unreviewed = join “\n”, ($descs.out.lines Z $links.out.lines).map: | |
- {‘ + ’ ~ escape-html(.[0]) ~ ‘ ’ ~ .[1]}; | |
+ {‘ + ’ ~ html-escape(.[0]) ~ ‘ ’ ~ .[1]}; | |
%files<unreviewed.md> = ‘<pre>’ ~ $unreviewed ~ ‘</pre>’ if $unreviewed; | |
} | |
(‘’ but FileStore(%files)) but PrettyLink({“Details: $_”}) | |
diff --git a/bin/Reportable.p6 b/bin/Reportable.p6 | |
index 44e417c..1e07a93 100755 | |
--- a/bin/Reportable.p6 | |
+++ b/bin/Reportable.p6 | |
@@ -31,11 +31,11 @@ my $next-date = now.DateTime.truncated-to: ‘day’; | |
if !%*ENV<DEBUGGABLE> and !%*ENV<TESTABLE> { | |
start loop { | |
- $next-date .= later(:6hour); | |
+ $next-date .= later: :6hours; | |
next if $next-date < now.DateTime; | |
await Promise.at: $next-date.Instant; | |
$semaphore.acquire; # released in the snapshot sub | |
- snapshot; | |
+ await snapshot | |
} | |
} | |
@@ -51,7 +51,7 @@ multi method irc-to-me($msg where ‘list’) { | |
‘’ but ProperStr(report-dirs.reverse.map(*.basename).join: “\n”) | |
} | |
-multi method irc-to-me($msg where ‘montly’) { | |
+multi method irc-to-me($msg where ‘monthly’) { | |
‘You can implement this feature if you need it :)’ | |
~ ‘ (meanwhile try to be more specific by using 「list」 command)’ | |
} | |
@@ -104,14 +104,16 @@ sub snapshot($msg?) { | |
my $datetime = now.DateTime.truncated-to: ‘minute’; | |
.reply: ‘OK! Working on it. This will take forever, so don't hold your breath.’ with $msg; | |
- # TODO authenticate on github to get rid of unlikely rate limiting | |
- my %config = from-json slurp CONFIG; | |
+ my $env = %*ENV; | |
+ $env<PATH> = ‘/home/bisectable/.rakudobrew/bin/’ ~ ‘:’ ~ $env<PATH>; | |
mkdir “$temp-folder/GH”; | |
- run ‘maintenance/pull-gh’, “$temp-folder/GH”; | |
+ run ‘maintenance/pull-gh’, “$temp-folder/GH”; # TODO authenticate on github to get rid of unlikely rate limiting | |
mkdir “$temp-folder/RT”; | |
- run ‘maintenance/pull-rt’, “$temp-folder/RT”, |%config<reportable><RT><user pass>; | |
+ run ‘maintenance/pull-rt’, “$temp-folder/RT”, |$CONFIG<reportable><RT><user pass>; | |
- rename $temp-folder, $dir.add: $datetime; | |
+ # .move does not work with directories and .rename does not | |
+ # work across devices, so just run ‘mv’ | |
+ run ‘mv’, ‘--’, $temp-folder, $dir.add: $datetime; | |
True | |
} | |
} | |
@@ -191,7 +193,7 @@ sub analyze(IO() $before-dir where .d, IO() $after-dir where .d) { | |
my $subject = $after<title>; | |
$subject .= subst(/^ \s* [‘[’ \w+ ‘]’]* %% \s* /, ‘’); | |
- $subject = “$subject”; # TODO trim long subjects? # TODO escape | |
+ $subject = html-escape $subject; # TODO trim long subjects? | |
my $link = “<a href="{.<html_url>}">{sprintf ‘% 9s’, .<uni-id>}</a>”; | |
my $str = “$link $subject”; | |
if $before<state> ne $after<state> { | |
@@ -244,6 +246,6 @@ sub analyze(IO() $before-dir where .d, IO() $after-dir where .d) { | |
} | |
Reportable.new.selfrun: ‘reportable6’, [ / report6? <before ‘:’> /, | |
- fuzzy-nick(‘reportable6’, 3) ] | |
+ fuzzy-nick(‘reportable6’, 2) ] | |
# vim: expandtab shiftwidth=4 ft=perl6 | |
diff --git a/bin/Squashable.p6 b/bin/Squashable.p6 | |
index f2c89c5..c35ca13 100755 | |
--- a/bin/Squashable.p6 | |
+++ b/bin/Squashable.p6 | |
@@ -137,8 +137,7 @@ multi method irc-to-me($msg where /^ \s* [log|status|info|when|next] | |
use HTTP::Server::Async; | |
use JSON::Fast; | |
-my %config = from-json slurp CONFIG; | |
-my $server = HTTP::Server::Async.new: |(%config<squashable><host port>:p).Capture; | |
+my $server = HTTP::Server::Async.new: |($CONFIG<squashable><host port>:p).Capture; | |
my $channel = Channel.new; | |
my $squashable = Squashable.new; | |
@@ -153,7 +152,7 @@ $server.handler: sub ($request, $response) { | |
use Digest::HMAC; | |
my $body = $request.data; | |
$body .= subbuf: 0..^($body - 1) if $body[*-1] == 0; # TODO trailing null byte. Why is it there? | |
- my $hmac = ‘sha1=’ ~ hmac-hex %config<squashable><secret>, $body, &sha1; | |
+ my $hmac = ‘sha1=’ ~ hmac-hex $CONFIG<squashable><secret>, $body, &sha1; | |
if $hmac ne $request.headers<X-Hub-Signature> { | |
$response.status = 400; $response.close(‘Signatures didn't match’); | |
return | |
diff --git a/bin/build.p6 b/bin/build.p6 | |
index a737ff8..538ff3b 100755 | |
--- a/bin/build.p6 | |
+++ b/bin/build.p6 | |
@@ -37,6 +37,10 @@ my \EVERYTHING-RANGE = ‘2014.01^..HEAD’; # to build everything, but in hist | |
my \WORKING-DIRECTORY = ‘.’; # TODO not supported yet | |
+my \RAKUDO-NQP-ORIGIN = ‘https://github.com/perl6/nqp.git’; | |
+my \RAKUDO-NQP-LATEST = “/tmp/whateverable/rakudo-triple-nqp-repo”; | |
+my \RAKUDO-MOAR-ORIGIN = ‘https://github.com/MoarVM/MoarVM.git’; | |
+my \RAKUDO-MOAR-LATEST = “/tmp/whateverable/rakudo-triple-moar-repo”; | |
my \REPO-ORIGIN = RAKUDOISH | |
?? ‘https://github.com/rakudo/rakudo.git’ | |
!! ‘https://github.com/MoarVM/MoarVM.git’; | |
@@ -60,13 +64,19 @@ exit 0 unless run ‘mkdir’, :err(Nil), ‘--’, BUILD-LOCK; # only one insta | |
my $locked = True; | |
END BUILD-LOCK.IO.rmdir if $locked; | |
-if REPO-LATEST.IO ~~ :d { | |
- my $old-dir = $*CWD; | |
- LEAVE chdir $old-dir; | |
- chdir REPO-LATEST; | |
- run ‘git’, ‘pull’; | |
-} else { | |
- exit unless run ‘git’, ‘clone’, ‘--’, REPO-ORIGIN, REPO-LATEST; | |
+sub pull-or-clone($repo-origin, $repo-path) { | |
+ if $repo-path.IO ~~ :d { | |
+ my $old-dir = $*CWD; | |
+ run :cwd($repo-path), ‘git’, ‘pull’; | |
+ } else { | |
+ exit unless run ‘git’, ‘clone’, ‘--’, $repo-origin, $repo-path; | |
+ } | |
+} | |
+ | |
+pull-or-clone REPO-ORIGIN, REPO-LATEST; | |
+if RAKUDOISH { | |
+ pull-or-clone RAKUDO-NQP-ORIGIN, RAKUDO-NQP-LATEST; | |
+ pull-or-clone RAKUDO-MOAR-ORIGIN, RAKUDO-MOAR-LATEST; | |
} | |
if REPO-CURRENT.IO !~~ :d { | |
@@ -75,21 +85,61 @@ if REPO-CURRENT.IO !~~ :d { | |
my $channel = Channel.new; | |
-my @git-latest = ‘git’, ‘--git-dir’, “{REPO-LATEST}/.git”, ‘--work-tree’, REPO-LATEST; | |
-my @args-tags = |@git-latest, ‘log’, ‘-z’, ‘--pretty=%H’, ‘--tags’, ‘--no-walk’, ‘--since’, TAGS-SINCE; | |
-my @args-latest = |@git-latest, ‘log’, ‘-z’, ‘--pretty=%H’, COMMIT-RANGE; | |
-my @args-recent = |@git-latest, ‘log’, ‘-z’, ‘--pretty=%H’, ‘--all’, ‘--since’, ALL-SINCE; | |
-my @args-old = |@git-latest, ‘log’, ‘-z’, ‘--pretty=%H’, ‘--reverse’, EVERYTHING-RANGE; | |
+my @git-log = ‘git’, ‘log’, ‘-z’, ‘--pretty=%H’; | |
+my @args-tags = |@git-log, ‘--tags’, ‘--no-walk’, ‘--since’, TAGS-SINCE; | |
+my @args-latest = |@git-log, COMMIT-RANGE; | |
+my @args-recent = |@git-log, ‘--all’, ‘--since’, ALL-SINCE; | |
+my @args-old = |@git-log, ‘--reverse’, EVERYTHING-RANGE; | |
my %commits; | |
+ | |
+# Normal Rakudo commits | |
for @args-tags, @args-latest, @args-recent, @args-old -> @_ { | |
- for run(:out, |@_).out.split(0.chr, :skip-empty) { | |
+ for run(:cwd(REPO-LATEST), :out, |@_).out.split(0.chr, :skip-empty) { | |
next if %commits{$_}:exists; | |
%commits{$_}++; | |
$channel.send: $_ | |
} | |
} | |
+sub get-build-revision($repo, $on-commit, $file) { | |
+ run(:cwd($repo), :out, ‘git’, ‘show’, | |
+ “{$on-commit}:tools/build/$file”).out.slurp-rest.trim | |
+} | |
+ | |
+# Rakudo-NQP-Moar triples (for bumps) | |
+#`「「「 | |
+if PROJECT == Rakudo-Moar { | |
+ my @args-bumps = ‘git’, ‘log’, ‘-z’, ‘--pretty=%x00%H’, | |
+ ‘--follow’, ‘--reverse’, | |
+ EVERYTHING-RANGE, ‘tools/build/NQP_REVISION’; | |
+ for run(:cwd(REPO-LATEST), :out, |@args-bumps) | |
+ .out.split(0.chr, :skip-empty).rotor(2) -> ($rakudo-sha, $diff) { | |
+ #my $nqp-old = get-build-revision REPO-LATEST, “$rakudo-sha^”, ‘NQP_REVISION’; | |
+ #my $nqp-new = get-build-revision REPO-LATEST, “$rakudo-sha”, ‘NQP_REVISION’; | |
+ | |
+ #say “$rakudo-sha”; | |
+ for run(:cwd(RAKUDO-NQP-LATEST), :out, |@git-log, “$nqp-old..$nqp-new”) | |
+ .out.split(0.chr, :skip-empty) -> $nqp-sha { | |
+ my $moar-sha = get-build-revision RAKUDO-NQP-LATEST, “$nqp-sha”, ‘MOAR_REVISION’; | |
+ # TODO shas are not shas | |
+ say “|- $nqp-sha - $moar-sha”; | |
+ } | |
+ for run(:cwd(RAKUDO-NQP-LATEST), :out, |@git-log, ‘--follow’, ‘--reverse’, | |
+ “$nqp-old..$nqp-new”, ‘tools/build/MOAR_REVISION’) | |
+ .out.split(0.chr, :skip-empty) -> $nqp-sha { | |
+ my $moar-old = get-build-revision RAKUDO-NQP-LATEST, “$nqp-sha^”, ‘MOAR_REVISION’; | |
+ my $moar-new = get-build-revision RAKUDO-NQP-LATEST, “$nqp-sha”, ‘MOAR_REVISION’; | |
+ for run(:cwd(RAKUDO-MOAR-LATEST), :out, |@git-log, “$moar-old..$moar-new”) | |
+ .out.split(0.chr, :skip-empty) -> $moar-sha { | |
+ say “ |- $moar-sha”; | |
+ } | |
+ } | |
+ } | |
+} | |
+# 」」」 | |
+ | |
+ | |
await (for ^PARALLEL-COUNT { # TODO rewrite when .race starts working in rakudo | |
start loop { | |
my $commit = $channel.poll; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment