unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
From: Tomi Ollila <tomi.ollila@iki.fi>
To: notmuch@notmuchmail.org
Cc: tomi.ollila@iki.fi
Subject: [PATCH 1/1] devel: add post-release tools news2wiki.pl and man-to-mdwn.pl
Date: Fri,  8 Mar 2013 18:32:23 +0200	[thread overview]
Message-ID: <1362760343-32620-1-git-send-email-tomi.ollila@iki.fi> (raw)

After new notmuch release has been published the NEWS and manual
pages have been updated using these 2 programs.

Adding the tools to notmuch repository eases their use, adds more
transparency to the "process" and gives more people chance to
do the updates is one is unavailable to do it at the time being.
---
 devel/man-to-mdwn.pl | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++
 devel/news2wiki.pl   | 102 ++++++++++++++++++++++++++
 2 files changed, 299 insertions(+)
 create mode 100755 devel/man-to-mdwn.pl
 create mode 100755 devel/news2wiki.pl

diff --git a/devel/man-to-mdwn.pl b/devel/man-to-mdwn.pl
new file mode 100755
index 0000000..4b59bd6
--- /dev/null
+++ b/devel/man-to-mdwn.pl
@@ -0,0 +1,197 @@
+#!/usr/bin/perl
+#
+# Author: Tomi Ollila
+# License: same as notmuch
+#
+# This program is used to generate mdwn-formatted notmuch manual pages
+# for notmuch wiki. Example run:
+#
+# $ ./devel/man-to-mdwn.pl man ../notmuch-wiki
+#
+# In case taken into more generic use, modify these comments and examples.
+
+use 5.8.1;
+use strict;
+use warnings;
+
+unless (@ARGV == 2) {
+    warn "\n$0 <source-directory> <destination-directory>\n\n";
+    # Remove/edit this comment if this script is taken into generic use.
+    warn "Example: ./devel/man-to-mdwn.pl man ../notmuch-wiki\n\n";
+    exit 1;
+}
+
+die "'$ARGV[0]': no such source directory\n" unless -d $ARGV[0];
+die "'$ARGV[1]': no such destination directory\n" unless -d $ARGV[1];
+
+#die "'manpages' exists\n" if -e 'manpages';
+#die "'manpages.mdwn' exists\n" if -e 'manpages.mdwn';
+
+die "Expecting '$ARGV[1]/manpages' to exist.\n" .
+  "Please create it first or adjust <destination-directory>.\n"
+  unless -d $ARGV[1] . '/manpages';
+
+my $ev = 0;
+my %fhash;
+
+open P, '-|', 'find', $ARGV[0], qw/-name *.[0-9] -print/;
+while (<P>)
+{
+    chomp;
+    next unless -f $_; # follows symlink.
+    $ev = 1, warn "'$_': no such file\n" unless -f $_;
+    my ($in, $on) = ($_, $_);
+    $on =~ s|.*/||; $on =~ tr/./-/;
+    my $f = $fhash{$on};
+    $ev = 1, warn "'$in' collides with '$f' ($on.mdwn)\n" if defined $f;
+    $fhash{$on} = $in;
+}
+close P;
+
+#undef $ENV{'GROFF_NO_SGR'};
+#delete $ENV{'GROFF_NO_SGR'};
+$ENV{'GROFF_NO_SGR'} = '1';
+$ENV{'TERM'} = 'vt100'; # does this matter ?
+
+my %htmlqh = qw/& &amp;   < &lt;   > &gt;   ' &apos;   " &quot;/;
+# do html quotation to $_[0] (which is an alias to the given arg)
+sub htmlquote($)
+{
+    $_[0] =~ s/([&<>'"])/$htmlqh{$1}/ge;
+}
+
+sub maymakelink($);
+sub mayconvert($$);
+
+#warn keys %fhash, "\n";
+
+while (my ($k, $v) = each %fhash)
+{
+    #next if -l $v; # skip symlinks here. -- not... references there may be.
+
+    my @lines;
+    #open I, '-|', qw/groff -man -T utf8/, $v;
+    open I, '-|', qw/groff -man -T latin1/, $v; # this and GROFF_NO_SGR='1'
+
+    my ($emptyline, $pre, $hl) = (0, 0, 'h1');
+    while (<I>) {
+	if (/^\s*$/) {
+	    $emptyline = 1;
+	    next;
+	}
+	s/(?<=\S)\s{8,}.*//; # $hl = 'h1' if s/(?<=\S)\s{8,}.*//;
+	htmlquote $_;
+	s/[_&]\010&/&/g;
+	s/((?:_\010[^_])+)/<u>$1<\/u>/g;
+	s/_\010(.)/$1/g;
+	s/((?:.\010.)+)/<b>$1<\/b>/g;
+	s/.\010(.)/$1/g;
+
+	if (/^\S/) {
+	    $pre = 0, push @lines, "</pre>\n" if $pre;
+	    s/<\/?b>//g;
+	    chomp;
+	    $_ = "\n<$hl>$_</$hl>\n";
+	    $hl = 'h2';
+	    $emptyline = 0;
+	}
+	elsif (/^\s\s\s\S/) {
+	    $pre = 0, push @lines, "</pre>\n" if $pre;
+	    s/(?:^\s+)?<\/?b>//g;
+	    chomp;
+	    $_ = "\n<h3> &nbsp; $_</h3>\n";
+	    $emptyline = 0;
+	}
+	else {
+	    $pre = 1, push @lines, "<pre>\n" unless $pre;
+	    $emptyline = 0, push @lines, "\n" if $emptyline;
+	}
+	push @lines, $_;
+    }
+    $lines[0] =~ s/^\n//;
+    $k = "$ARGV[1]/manpages/$k.mdwn";
+    open O, '>', $k or die;
+    print STDOUT 'Writing ', "'$k'\n";
+    select O;
+    my $pe = '';
+    foreach (@lines) {
+	if ($pe) {
+	    if (s/^(\s+)<b>([^<]+)<\/b>\((\d+)\)//) {
+		my $link = maymakelink "$pe-$2-$3";
+		$link = maymakelink "$pe$2-$3" unless $link;
+		if ($link) {
+		    print "<a href='$link'>$pe-</a>\n";
+		    print "$1<a href='$link'>$2</a>($3)";
+		}
+		else {
+		    print "<b>$pe-</b>\n";
+		    print "$1<b>$2</b>($3)";
+		}
+	    } else {
+		print "<b>$pe-</b>\n";
+	    }
+	    $pe = '';
+	}
+	s/<b>([^<]+)<\/b>\((\d+)\)/mayconvert($1, $2)/ge;
+	$pe = $1 if s/<b>([^<]+)-<\/b>\s*$//;
+	print $_;
+    }
+}
+
+sub maymakelink($)
+{
+#    warn "$_[0]\n";
+    return "../$_[0]/" if exists $fhash{$_[0]};
+    return '';
+}
+
+sub mayconvert($$)
+{
+    my $f = "$_[0]-$_[1]";
+#    warn "$f\n";
+    return "<a href='../$f/'>$_[0]</a>($_[1])" if exists $fhash{$f};
+    return "<b>$_[0]</b>($_[1])";
+}
+
+# Finally, make manpages.mdwn
+
+open O, '>', $ARGV[1] . '/manpages.mdwn' or die $!;
+print STDOUT "Writing '$ARGV[1]/manpages.mdwn'\n";
+select O;
+print "Manual page index\n";
+print "=================\n\n";
+
+sub srt { my ($x, $y) = ($a, $b); $x =~ tr/./-/; $y =~ tr/./-/; $x cmp $y; }
+
+foreach (sort srt values %fhash)
+{
+    my $in = $_;
+    open I, '<', $in or die $!;
+    my $s;
+    while (<I>) {
+	if (/^\s*[.]TH\s+\S+\s+(\S+)/) {
+	    $s = $1;
+	    last;
+	}
+    }
+    while (<I>) {
+	last if /^\s*[.]SH NAME/
+    }
+    my $line = '';
+    while (<I>) {
+	tr/\\//d;
+	if (/\s*(\S+)\s+(.*)/) {
+	    my $e = $2;
+	    # Ignoring the NAME in file, get from file name instead.
+	    #my $on = (-l $in)? readlink $in: $in;
+	    my $on = $in;
+	    $on =~ tr/./-/; $on =~ s|.*/||;
+	    my $n = $in; $n =~ s|.*/||; $n =~ tr/./-/; $n =~ s/-[^-]+$//;
+	    $line = "<a href='$on/'>$n</a>($s) $e\n";
+	    last;
+	}
+    }
+    die "No NAME in '$in'\n" unless $line;
+    print "* $line";
+    #warn $line;
+}
diff --git a/devel/news2wiki.pl b/devel/news2wiki.pl
new file mode 100755
index 0000000..8066ba7
--- /dev/null
+++ b/devel/news2wiki.pl
@@ -0,0 +1,102 @@
+#!/usr/bin/perl
+#
+# Author: Tomi Ollila
+# License: same as notmuch
+
+# This program is used to split NEWS file to separate (mdwn) files
+# for notmuch wiki. Example run:
+#
+# $ ./devel/news2wiki.pl NEWS ../notmuch-wiki/news
+#
+# In case taken into more generic use, modify these comments and examples.
+
+use strict;
+use warnings;
+
+unless (@ARGV == 2) {
+    warn "\n$0 <source-file> <destination-directory>\n\n";
+    warn "Example: ./devel/news2wiki.pl NEWS ../notmuch-wiki/news\n\n";
+    exit 1;
+}
+
+die "'$ARGV[0]': no such file\n" unless -f $ARGV[0];
+die "'$ARGV[1]': no such directory\n" unless -d $ARGV[1];
+
+open I, '<', $ARGV[0] or die "Cannot open '$ARGV[0]': $!\n";
+
+open O, '>', '/dev/null' or die $!;
+my @emptylines = ();
+my $cln;
+print "\nWriting to $ARGV[1]:\n";
+while (<I>)
+{
+    warn "$ARGV[0]:$.: tab(s) in line!\n" if /\t/;
+    warn "$ARGV[0]:$.: trailing whitespace\n" if /\s\s$/;
+    # The date part in regex recognizes wip version dates like: (201x-xx-xx).
+    if (/^Notmuch\s+(\S+)\s+\((\w\w\w\w-\w\w-\w\w)\)\s*$/) {
+	# open O... autocloses previously opened file.
+	open O, '>', "$ARGV[1]/release-$1.mdwn" or die $!;
+	print "+ release-$1.mdwn...\n";
+	print O "[[!meta date=\"$2\"]]\n\n";
+	@emptylines = ();
+    }
+
+    last if /^<!--\s*$/; # Local variables block at the end (as of now).
+
+    # Buffer "trailing" empty lines -- dropped at end of file.
+    push(@emptylines, $_), next if s/^\s*$/\n/;
+    if (@emptylines) {
+	print O @emptylines;
+	@emptylines = ();
+    }
+
+    # Convert '*' to '`*`' and "*" to "`*`" so that * is not considered
+    # as starting emphasis character there. We're a bit opportunistic
+    # there -- some single * does not cause problems and, on the other
+    # hand, this would not regognize already 'secured' *:s.
+    s/'[*]'/'`*`'/g; s/"[*]"/"`*`"/g;
+
+    # Convert nonindented lines that aren't already headers or
+    # don't contain periods (.) or '!'s to level 4 header.
+    if ( /^[^\s-]/ ) {
+	my $tbc = ! /[.!]\s/;
+	chomp;
+	my @l = $_;
+	$cln = $.;
+	while (<I>) {
+	    last if /^\s*$/;
+	    #$cln = 0 if /^---/ or /^===/; # used for debugging.
+	    $tbc = 0 if /[.!]\s/ or /^---/ or /^===/;
+	    chomp; s/^\s+//;
+	    push @l, $_;
+	}
+	if ($tbc) {
+	    print O "### ", (join ' ', @l), "\n";
+	}
+	else {
+	    #print "$ARGV[0]:$cln: skip level 4 header conversion\n" if $cln;
+	    print O (join "\n", @l), "\n";
+	}
+	@emptylines = ( "\n" );
+	next;
+    }
+
+    # Markdown doc specifies that list item may have paragraphs if those
+    # are indented by 4 spaces (or a tab) from current list item marker
+    # indentation (paragraph meaning there is empty line in between).
+    # If there is empty line and next line is not indented 4 chars then
+    # that should end the above list. This doesn't happen in all markdown
+    # implementations.
+    # In our NEWS case this problem exists in release 0.6 documentation.
+    # It can be avoided by removing 2 leading spaces in lines that are not
+    # list items and requiring all that indents are 0, 2, and 4+ (to make
+    # regexp below work).
+    # Nested lists are supported but one needs to be more careful with
+    # markup there (as the hack below works only on first level).
+
+    s/^[ ][ ]// unless /^[ ][ ](?:[\s*+-]|\d+\.)\s/;
+
+    print O $_;
+}
+print "\ndone.\n";
+close O;
-- 
1.8.0

             reply	other threads:[~2013-03-08 16:32 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-08 16:32 Tomi Ollila [this message]
2013-03-29 14:12 ` [PATCH 1/1] devel: add post-release tools news2wiki.pl and man-to-mdwn.pl David Bremner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://notmuchmail.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1362760343-32620-1-git-send-email-tomi.ollila@iki.fi \
    --to=tomi.ollila@iki.fi \
    --cc=notmuch@notmuchmail.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).