aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2026-10-28 02:52:19 -0400
committerB. Watson <urchlay@slackware.uk>2026-10-28 02:52:19 -0400
commit009a486d686d73732da2ce09c9c94fdeb825997e (patch)
tree9ac652738fb2c567d077ff528896c0899da57728
parentb681fb311001d9f11d26e518af0aa8388e23883b (diff)
downloadgreypool-009a486d686d73732da2ce09c9c94fdeb825997e.tar.gz
Add ropeylog (SBo-specific, produces maintainer status report).
-rwxr-xr-xropeylog293
1 files changed, 293 insertions, 0 deletions
diff --git a/ropeylog b/ropeylog
new file mode 100755
index 0000000..b48b7f3
--- /dev/null
+++ b/ropeylog
@@ -0,0 +1,293 @@
+#!/usr/bin/perl -w
+
+use JSON::XS;
+use POSIX 'strftime';
+
+($SELF = $0) =~ s,.*/,,;
+$user_agent = 'Mozilla/5.0 (compatible; ropeylog-repology-bot/1.0; +https://github.com/SlackBuildsOrg/slackbuilds)';
+
+$git_root = $ENV{SBO_GITROOT} || "/slackbuilds/www/slackbuilds/15.0/";
+
+###############
+
+sub make_api_url {
+ my $last = shift;
+ my $url = "https://repology.org/api/v1/projects/";
+ $url .= "$last/" if defined $last;
+ $url .= "?status=outdated&inrepo=slackbuilds";
+}
+
+sub wget {
+ my $url = shift;
+ my $output = shift;
+
+ my $cmd =
+ "wget --compression=gzip --user-agent '$user_agent' -O$output '$url'";
+
+ warn "$cmd\n";
+
+ system($cmd);
+ sleep 1;
+}
+
+sub download {
+ my $firstpkg = $_[0] || "";
+ my $lastpkg = "";
+ my $filename = sprintf("%s/%03d.json", $cache_dir, $_[1]);
+
+ wget(make_api_url($_[0]), $filename);
+
+ my $j = parse_one_file($filename);
+
+ for $proj (keys %{$j}) {
+ $lastpkg = $proj if $proj gt $lastpkg;
+ }
+
+ return (($lastpkg eq $firstpkg) ? undef : $lastpkg);
+}
+
+sub download_files {
+ my $lastpkg;
+ my $count = 1;
+
+ do {
+ $lastpkg = download($lastpkg, $count++);
+ } while defined $lastpkg;
+}
+
+###############
+
+sub read_file {
+ undef local $/;
+ local @ARGV = shift;
+ $_ = <>;
+}
+
+sub parse_one_file {
+ my $file = shift;
+ my $j;
+
+ eval { $j = decode_json(read_file($file)); };
+ die "failed to decode JSON: $@\n" if $@;
+
+ return $j;
+}
+
+sub parse_json_files {
+ die "$SELF: nothing to parse, run '$SELF download' first.\n"
+ unless -e "$cache_dir/001.json";
+
+ for(<$cache_dir/*.json>) {
+ my $j = parse_one_file($_);
+ for my $proj (keys %{$j}) {
+ my $arr = $$j{$proj};
+ for my $hr (@{$arr}) {
+ next unless $hr->{repo} eq 'slackbuilds';
+ my $catbuild = $hr->{visiblename};
+ $outdated{$catbuild}++ if $hr->{status} eq 'outdated';
+ }
+ }
+ }
+}
+
+###############
+
+sub read_info_file {
+ my $file = shift;
+
+ my $maint;
+ my $email;
+
+ open my $f, "<$file" or die $!;
+
+ while(<$f>) {
+ chomp;
+ if(/^MAINTAINER="(.*?)"/) {
+ $maint = $1;
+ } elsif(/^EMAIL="(.*?)"/) {
+ $email = $1;
+ }
+ }
+
+ close $f;
+
+ return ($maint, $email);
+}
+
+sub parse_info_files {
+ chdir($git_root) or die "$!";
+ my $files = `git ls-files '*/*/*.info'`;
+ for my $info (split /\n/, $files) {
+ $total_builds++;
+ my ($maintainer, $email) = read_info_file($info);
+ next if $email eq 'NOEMAIL'; # skip orphans
+ my $catbuild = $info;
+ $catbuild =~ s,/[^/]*$,,;
+ $name2email{$maintainer} = $email;
+ push @{$maintbuilds{$maintainer}}, $catbuild;
+ }
+ @maintainers = keys %name2email;
+}
+
+sub get_git_maintainers {
+ chdir($git_root) or die "$!";
+
+ open my $in, "git log --pretty=format:%h%x09%an%x09%ae%x09%as%x09%s|" or die $!;
+ while(<$in>) {
+ chomp;
+ my ($hash, $name, $email, $date, $catbuild, undef) = split /\t/, $_, 6;
+ $catbuild =~ s/:.*$//;
+
+ if(!defined($lastgitdate{$name})) {
+ $lastgitdate{$name} = $date;
+ $lastgithash{$name} = $hash;
+ }
+ }
+ close $in;
+}
+
+sub url_escape {
+ my $s = shift;
+ $s =~ s{[^-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz]}{sprintf("%%%x", ord($&))}ge;
+ return $s;
+}
+
+sub get_percent {
+ my $a = shift;
+ my $b = shift;
+
+ if(!$b) {
+ print "0";
+ return;
+ }
+
+ return sprintf("%d (%.1f%%)", $a, ($a / $b) * 100);
+}
+
+sub print_report {
+ my $stamp = strftime("%Y-%m-%d %H:%M:%S", gmtime);
+ my $maintcount = @maintainers;
+ print <<EOF;
+<!DOCTYPE html>
+<html>
+<head>
+<title>SBo maintainer status report</title>
+<meta charset="utf-8">
+<style>
+ table {border:1px solid;border-collapse:collapse}
+ th.m, td.m {text-align:left;padding:0.5rem;border:1px solid}
+ th.l, td.l {text-align:center;padding:0.5rem;border:1px solid}
+ th.s, td.s {text-align:center;padding:0.5rem;border:1px solid}
+ th.n, td.n {text-align:right;padding:0.5rem;border:1px solid}
+ th.o, td.o {text-align:right;padding:0.5rem;border:1px solid}
+ a.m {font-size:small}
+</style>
+</head>
+<body>
+<h1>SBo maintainer status report</h1>
+<p>Date: $stamp<br />
+SlackBuilds: $total_builds<br />
+Maintainers: $maintcount<br />
+</p>
+<table>
+<thead>
+<tr><th class="m">Maintainer</th><th class="l">Latest</th><th class="s">SlackBuilds</th><th class="n">Newest</th><th class="o">Out of date</th></tr>
+</thead>
+<tbody>
+EOF
+
+ for my $maintainer (sort { lc($a) cmp lc($b) } @maintainers) {
+ my $count = 0;
+ my $outdated_count = 0;
+ for(@{$maintbuilds{$maintainer}}) {
+ $count++;
+ $outdated_count++ if $outdated{$_};
+ }
+
+ my $newest = get_percent($count - $outdated_count, $count);
+ my $outdated = get_percent($outdated_count, $count);
+ my $maint_email = $name2email{$maintainer};
+
+ my $repology_link = "";
+ my $count_link = $count;
+ if(defined $maint_email) {
+ my $escmail = url_escape($maint_email);
+ my $escmaint = url_escape($maintainer);
+ $count_link = "<a class=\"s\" target=\"_blank\" href=\"https://slackbuilds.org/advsearch.php?stype=maint&q=$escmaint\">$count</a>";
+ if($maint_email =~ /\@/) {
+ $repology_link = "<a class=\"m\" target=\"_blank\" href=\"https://repology.org/projects/?maintainer=$escmail\">$maint_email</a>";
+ }
+ }
+
+ my $git_hash = $lastgithash{$maintainer};
+ my $git_date = $lastgitdate{$maintainer};
+ my $git_link = "";
+ if(defined $git_hash && defined $git_date) {
+ $git_link = "<a class=\"c\" target=\"_blank\" href=\"https://git.slackbuilds.org/slackbuilds/commit/?id=$git_hash\">$git_date</a>";
+ }
+
+ print <<EOF;
+<tr>
+ <td class="m">$maintainer<br />$repology_link</td>
+ <td class="l">$git_link</td>
+ <td class="s">$count_link</td>
+ <td class="n">$newest</td>
+ <td class="o">$outdated</td>
+</tr>
+EOF
+ }
+
+ print <<EOF;
+</tbody>
+</table>
+</body>
+</html>
+EOF
+}
+
+# Report looks like this:
+# https://slackbuilds.org/maintainer_status.html
+
+# SBo maintainer status report
+
+# Date: YYYY-MM-DD HH:MM:SS
+# Slackbuilds: NNNNN
+# Maintainers: NNN
+
+# Rest is a table with 4 columns:
+# Maintainer Latest SlackBuilds Newest Out of date
+
+# The maintainer column has name and email, and the email is a repology link:
+# http://repology.org/projects/?maintainer=<email>
+# IMO, there should be mailto: links here too, maybe use 📬
+
+# Latest is YYYY-MM-DD, and it's a link to:
+# https://git.slackbuilds.org/slackbuilds/commit/?id=<commit>
+
+# SlackBuilds is a count only. This should be a link to an advsearch
+# by maintainer.
+
+# Newest is a count and percentage.
+
+# Out of date is a count and percentage.
+
+#
+# main()
+$cache_dir = "$ENV{HOME}/.$SELF";
+system("mkdir -p $cache_dir");
+
+if(@ARGV) {
+ if($ARGV[0] eq 'download') {
+ for(<$cache_dir/*.json>) {
+ unlink $_;
+ }
+ download_files();
+ exit 0;
+ } else {
+ die "unknown command $ARGV[0]\n";
+ }
+}
+parse_json_files();
+parse_info_files();
+get_git_maintainers();
+print_report();