From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id A1DAE1F4BD for ; Sun, 6 Oct 2019 23:31:36 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH] doc: generate NEWS, NEWS.atom, and NEWS.html Date: Sun, 6 Oct 2019 23:31:36 +0000 Message-Id: <20191006233136.3603-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: We'll use our Documentation/RelNotes directory and internal APIs to generate these files for website use (the website should be completely reproducible). --- .gitignore | 3 + Documentation/include.mk | 25 +++++-- Documentation/mknews.perl | 146 ++++++++++++++++++++++++++++++++++++++ MANIFEST | 1 + 4 files changed, 170 insertions(+), 5 deletions(-) create mode 100755 Documentation/mknews.perl diff --git a/.gitignore b/.gitignore index 6a44471f..66f165e2 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ *.8 *.html *.gz +/NEWS.html +/NEWS.atom +/NEWS diff --git a/Documentation/include.mk b/Documentation/include.mk index 55c10b51..65ba4e17 100644 --- a/Documentation/include.mk +++ b/Documentation/include.mk @@ -9,6 +9,7 @@ all:: RSYNC = rsync RSYNC_DEST = public-inbox.org:/srv/public-inbox/ MAN = man +XMLSTARLET = xmlstarlet # same as pod2text COLUMNS = 76 @@ -91,8 +92,9 @@ manuals += $(m8) mantxt = $(addprefix Documentation/, $(addsuffix .txt, $(manuals))) docs += $(mantxt) dtxt += $(mantxt) +docs += NEWS -all :: $(mantxt) +all :: $(docs) Documentation/%.txt : Documentation/%.pod $(podtext) $< $@+ && touch -r $< $@+ && mv $@+ $@ @@ -103,16 +105,29 @@ txt2pre = $(PERL) -I lib ./Documentation/txt2pre <$< >$@+ && \ Documentation/standards.txt : Documentation/standards.perl $(PERL) $< >$@+ && touch -r $< $@+ && mv $@+ $@ +RELEASES = +RELEASES += v1.1.0-pre1 +RELEASES += v1.0.0 + +NEWS NEWS.atom NEWS.html : Documentation/RelNotes + $(PERL) -w Documentation/mknews.perl $@ $(RELEASES) + +# check for internal API changes: +check :: NEWS check-NEWS.atom NEWS.html + +check-NEWS.atom: NEWS.atom + $(XMLSTARLET) val $<; e=$$?; test $$e -eq 0 || test $$e -eq 127 + Documentation/%.html: Documentation/%.txt $(txt2pre) %.html: % $(txt2pre) -docs_html := $(addsuffix .html, $(subst .txt,,$(dtxt)) $(txt)) +docs_html := $(addsuffix .html, $(subst .txt,,$(dtxt)) $(txt)) NEWS.html html: $(docs_html) gz_docs := $(addsuffix .gz, $(docs) $(docs_html)) -rsync_docs := $(gz_docs) $(docs) $(docs_html) +rsync_docs := $(gz_docs) $(docs) $(docs_html) NEWS.atom NEWS.atom.gz # external manpages which we host ourselves, since some packages # (currently just Xapian) doesn't host manpages themselves. @@ -147,7 +162,7 @@ gz-doc: $(gz_docs) gz-xdoc: $(gz_xdocs) -rsync-doc: +rsync-doc: NEWS.atom.gz # /usr/share/doc/rsync/scripts/git-set-file-times{.gz} on Debian systems # It is also at: https://yhbt.net/git-set-file-times -git set-file-times $(docs) $(txt) @@ -156,7 +171,7 @@ rsync-doc: clean-doc: $(RM) $(man1) $(man5) $(man7) $(man8) $(gz_docs) $(docs_html) $(mantxt) - $(RM) $(gz_xdocs) $(xdocs_html) $(xdocs) + $(RM) $(gz_xdocs) $(xdocs_html) $(xdocs) NEWS NEWS.atom NEWS.html clean :: clean-doc diff --git a/Documentation/mknews.perl b/Documentation/mknews.perl new file mode 100755 index 00000000..509da3b1 --- /dev/null +++ b/Documentation/mknews.perl @@ -0,0 +1,146 @@ +#!/usr/bin/perl -w +# Copyright (C) 2019 all contributors +# License: AGPL-3.0+ +# Generates NEWS, NEWS.atom, and NEWS.html files using release emails +# this uses unstable internal APIs of public-inbox, and this script +# needs to be updated if they change. +use strict; +use PublicInbox::MIME; +use PublicInbox::View; +use Plack::Util; +use PublicInbox::MsgTime qw(msg_datestamp); +use PublicInbox::MID qw(mids mid_escape); +my $dst = shift @ARGV or die "Usage: $0 "; + +# newest to oldest +my @releases = @ARGV; +my $dir = 'Documentation/RelNotes'; +my $base_url = 'https://public-inbox.org/meta'; +my $html_url = 'https://public-inbox.org/NEWS.html'; +my $atom_url = 'https://public-inbox.org/NEWS.atom'; +my $addr = 'meta@public-inbox.org'; + +my $latest = shift(@releases) or die 'no releases?'; +my $mime_latest = release2mime($latest); +my $mtime = msg_datestamp($mime_latest->header_obj); +my $tmp = "$dst+"; +my $out; +if ($dst eq 'NEWS') { + open $out, '>', $tmp or die; + mime2txt($out, $mime_latest); + for my $v (@releases) { + print $out "\n" or die; + mime2txt($out, release2mime($v)); + } +} elsif ($dst eq 'NEWS.atom' || $dst eq 'NEWS.html') { + open $out, '>', $tmp or die; + my $ibx = Plack::Util::inline_object( + description => sub { 'public-inbox releases' }, + over => sub { undef }, + search => sub { 1 }, # for WwwStream:_html_top + base_url => sub { "$base_url/" }, + ); + $ibx->{-primary_address} = $addr; + my $ctx = { + -inbox => $ibx, + -upfx => "$base_url/", + -hr => 1, + }; + if ($dst eq 'NEWS.html') { + html_start($out, $ctx); + mime2html($out, $mime_latest, $ctx); + while (defined(my $v = shift(@releases))) { + mime2html($out, release2mime($v), $ctx); + } + html_end($out, $ctx); + } elsif ($dst eq 'NEWS.atom') { + my $astream = atom_start($out, $ctx, $mtime); + for my $v (reverse(@releases)) { + mime2atom($out, $astream, release2mime($v), $ctx); + } + mime2atom($out, $astream, $mime_latest, $ctx); + print $out '' or die; + } else { + die "BUG: Unrecognized $dst\n"; + } +} else { + die "Unrecognized $dst\n"; +} + +close($out) or die; +utime($mtime, $mtime, $tmp) or die; +rename($tmp, $dst) or die; +exit 0; + +sub release2mime { + my $f = "$dir/$_[0].eml"; + open(my $fh, '<', $f) or die "open($f): $!"; + PublicInbox::MIME->new(do { local $/; <$fh> }); +} + +sub mime2txt { + my ($out, $mime) = @_; + my $title = $mime->header_str('Subject'); + $title =~ s/^\s*\[\w+\]\s*//g; # [ANNOUNCE] or [ANN] + my $dtime = msg_datestamp($mime->header_obj); + $title .= ' - ' . PublicInbox::View::fmt_ts($dtime) . ' UTC'; + print $out $title, "\n" or die; + my $uline = '=' x length($title); + print $out $uline, "\n\n" or die; + + my $mid = mids($mime)->[0]; + print $out 'Link: ', $base_url, '/', mid_escape($mid), "/\n\n" or die; + print $out $mime->body_str or die; +} + +sub mime2html { + my ($out, $mime, $ctx) = @_; + my $smsg = bless { mime => $mime }, 'PublicInbox::SearchMsg'; + print $out PublicInbox::View::index_entry($smsg, $ctx, 1) or die; +} + +sub html_start { + my ($out, $ctx) = @_; + require PublicInbox::WwwStream; + $ctx->{www} = Plack::Util::inline_object(style => sub { '' }); + my $www_stream = PublicInbox::WwwStream->new($ctx); + print $out $www_stream->_html_top, '
' or die;
+}
+
+sub html_end {
+	print $out <
+EOF
+}
+
+sub atom_start {
+	my ($out, $ctx, $mtime) = @_;
+	require PublicInbox::WwwAtomStream;
+	# WwwAtomStream stats this dir for mtime
+	my $astream = PublicInbox::WwwAtomStream->new($ctx);
+	delete $ctx->{emit_header};
+	my $ibx = $ctx->{-inbox};
+	my $title = PublicInbox::WwwAtomStream::title_tag($ibx->description);
+	my $updated = PublicInbox::WwwAtomStream::feed_updated(gmtime($mtime));
+	print $out <
+$title$atom_url$updated
+EOF
+	$astream;
+}
+
+sub mime2atom  {
+	my ($out, $astream, $mime, $ctx) = @_;
+	my $smsg = bless { mime => $mime }, 'PublicInbox::SearchMsg';
+	if (defined(my $str = $astream->feed_entry($smsg))) {
+		print $out $str or die;
+	}
+}
diff --git a/MANIFEST b/MANIFEST
index b3046cf6..20dbdc54 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -13,6 +13,7 @@ Documentation/extman.perl
 Documentation/hosted.txt
 Documentation/include.mk
 Documentation/marketing.txt
+Documentation/mknews.perl
 Documentation/public-inbox-compact.pod
 Documentation/public-inbox-config.pod
 Documentation/public-inbox-convert.pod