unofficial mirror of meta@public-inbox.org
 help / color / mirror / Atom feed
* RFE: Long .onion URL breaks mobile view
@ 2021-08-16 16:36 Konstantin Ryabitsev
  2021-08-16 22:38 ` Eric Wong
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
  0 siblings, 2 replies; 21+ messages in thread
From: Konstantin Ryabitsev @ 2021-08-16 16:36 UTC (permalink / raw)
  To: meta

Hello:

Passing more observations from people testing out x-lore.kernel.org:

- the long .onion URL at the bottom of each page causes problems on mobile
  devices because it results in a very wide page with blank content on the
  right side.

I suggest that we don't need to provide the "git clone" part, but merely add a
link to the git repository:

<a href="http://7fh....onion/public-inbox.git">AGPL code for this site</a>

This should still serve the same purpose and not result in rendering issues on
mobile devices.

-K

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: RFE: Long .onion URL breaks mobile view
  2021-08-16 16:36 RFE: Long .onion URL breaks mobile view Konstantin Ryabitsev
@ 2021-08-16 22:38 ` Eric Wong
  2021-08-16 22:53   ` Eric Wong
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
  1 sibling, 1 reply; 21+ messages in thread
From: Eric Wong @ 2021-08-16 22:38 UTC (permalink / raw)
  To: Konstantin Ryabitsev; +Cc: meta

Konstantin Ryabitsev <konstantin@linuxfoundation.org> wrote:
> Hello:
> 
> Passing more observations from people testing out x-lore.kernel.org:
> 
> - the long .onion URL at the bottom of each page causes problems on mobile
>   devices because it results in a very wide page with blank content on the
>   right side.

Agreed, this is important feedback.

> I suggest that we don't need to provide the "git clone" part, but merely add a
> link to the git repository:
> 
> <a href="http://7fh....onion/public-inbox.git">AGPL code for this site</a>
> 
> This should still serve the same purpose and not result in rendering issues on
> mobile devices.

I think making it obvious a link goes to an external domain is
important.  How about splitting it on long tokens?  Something
like:

	<a href="...">http://
		7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd
		.onion/public-inbox.git</a>

Is a 56-character token OK for mobile displays?  My own preference is to
wrap at 64-characters despite using 80-column displays.

I wish Tor could've figured out some better way to make .onion v3 URLs
shorter...

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: RFE: Long .onion URL breaks mobile view
  2021-08-16 22:38 ` Eric Wong
@ 2021-08-16 22:53   ` Eric Wong
  0 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-16 22:53 UTC (permalink / raw)
  To: Konstantin Ryabitsev; +Cc: meta

Eric Wong <e@80x24.org> wrote:
> 	<a href="...">http://
> 		7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd
> 		.onion/public-inbox.git</a>

Actually, it's for "git clone" instructions, so something
shell-compatible might be required:

	u=7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd
	torsocks git clone http://$u.onion/public-inbox.git

No good options, really :<

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 0/8] various WWW + extindex stuff
  2021-08-16 16:36 RFE: Long .onion URL breaks mobile view Konstantin Ryabitsev
  2021-08-16 22:38 ` Eric Wong
@ 2021-08-26 12:33 ` Eric Wong
  2021-08-26 12:33   ` [PATCH 1/8] get rid of unnecessary bytes::length usage Eric Wong
                     ` (8 more replies)
  1 sibling, 9 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta; +Cc: Konstantin Ryabitsev

This hopefully makes the long .onion URL more usable on small
displays; but I also got sidetracked into making our "use bytes"
stuff less scary based on the notice in the bytes(3perl)
manpage.

There's a couple of small extindex-related fixes to reconcile
the differences between the two ibxish object types for WWW.

Eric Wong (8):
  get rid of unnecessary bytes::length usage
  ds: use bytes::substr and bytes::length module-wide for now
  www_stream: sh-friendly .onion URLs wrapping
  www: avoid incorrect instructions for extindex
  www_text: fix example config snippet for extindex
  config: do not parse altid for extindex
  www_text: add coderepo config support for extindex
  move ->ids_after from mm to over

 lib/PublicInbox/Config.pm       |   2 +-
 lib/PublicInbox/DS.pm           |  21 +++---
 lib/PublicInbox/ExtSearch.pm    |   4 -
 lib/PublicInbox/HTTP.pm         |  17 ++---
 lib/PublicInbox/ManifestJsGz.pm |   3 +-
 lib/PublicInbox/Mbox.pm         |  10 +--
 lib/PublicInbox/Msgmap.pm       |  11 ---
 lib/PublicInbox/NNTP.pm         |   4 +-
 lib/PublicInbox/Over.pm         |  11 +++
 lib/PublicInbox/View.pm         |   5 +-
 lib/PublicInbox/ViewVCS.pm      |   5 +-
 lib/PublicInbox/WWW.pm          |  10 +--
 lib/PublicInbox/WwwAttach.pm    |   4 +-
 lib/PublicInbox/WwwHighlight.pm |   5 +-
 lib/PublicInbox/WwwListing.pm   |   4 +-
 lib/PublicInbox/WwwStatic.pm    |   4 +-
 lib/PublicInbox/WwwStream.pm    | 126 +++++++++++++++++++-------------
 lib/PublicInbox/WwwText.pm      | 103 ++++++++++++++++----------
 t/extindex-psgi.t               |  15 ++++
 t/psgi_search.t                 |   1 -
 t/search-thr-index.t            |   8 +-
 t/www_listing.t                 |  19 ++++-
 xt/cmp-msgstr.t                 |   2 +-
 23 files changed, 229 insertions(+), 165 deletions(-)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/8] get rid of unnecessary bytes::length usage
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 2/8] ds: use bytes::substr and bytes::length module-wide for now Eric Wong
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

The only place where we could return wide characters with -httpd
was the raw $INBOX_DIR/description text, which is now converted
to octets.

All daemon (HTTP/NNTP/IMAP) sockets are opened in binary mode,
so length() and bytes::length() are equivalent on reads.  For
socket writes, any non-octet data would warn about wide characters
and we are strict in warnings with test_httpd.

All gzipped buffers are also octets, as is PublicInbox::Eml->body,
and anything from PerlIO objects ("git cat-file --batch" output,
filesystems), so bytes::length was unnecessary in all those places.
---
 lib/PublicInbox/HTTP.pm         | 17 ++++++++---------
 lib/PublicInbox/ManifestJsGz.pm |  3 +--
 lib/PublicInbox/NNTP.pm         |  2 +-
 lib/PublicInbox/View.pm         |  5 ++---
 lib/PublicInbox/ViewVCS.pm      |  5 ++---
 lib/PublicInbox/WWW.pm          | 10 ++++------
 lib/PublicInbox/WwwAttach.pm    |  4 ++--
 lib/PublicInbox/WwwHighlight.pm |  5 ++---
 lib/PublicInbox/WwwListing.pm   |  4 ++--
 lib/PublicInbox/WwwStatic.pm    |  4 ++--
 lib/PublicInbox/WwwStream.pm    |  4 ++--
 lib/PublicInbox/WwwText.pm      |  5 ++---
 t/psgi_search.t                 |  1 -
 t/search-thr-index.t            |  8 ++++----
 t/www_listing.t                 | 19 +++++++++++++++----
 xt/cmp-msgstr.t                 |  2 +-
 16 files changed, 50 insertions(+), 48 deletions(-)

diff --git a/lib/PublicInbox/HTTP.pm b/lib/PublicInbox/HTTP.pm
index d0708c5b..b2c74cf3 100644
--- a/lib/PublicInbox/HTTP.pm
+++ b/lib/PublicInbox/HTTP.pm
@@ -21,7 +21,6 @@
 package PublicInbox::HTTP;
 use strict;
 use parent qw(PublicInbox::DS);
-use bytes (); # only for bytes::length
 use Fcntl qw(:seek);
 use Plack::HTTPParser qw(parse_http_request); # XS or pure Perl
 use Plack::Util;
@@ -89,7 +88,7 @@ sub event_step { # called by PublicInbox::DS
 
 	return read_input($self) if ref($self->{env});
 	my $rbuf = $self->{rbuf} // (\(my $x = ''));
-	$self->do_read($rbuf, 8192, bytes::length($$rbuf)) or return;
+	$self->do_read($rbuf, 8192, length($$rbuf)) or return;
 	rbuf_process($self, $rbuf);
 }
 
@@ -104,7 +103,7 @@ sub rbuf_process {
 	# (they are rarely-used and git (as of 2.7.2) does not use them)
 	if ($r == -1 || $env{HTTP_TRAILER} ||
 			# this length-check is necessary for PURE_PERL=1:
-			($r == -2 && bytes::length($$rbuf) > 0x4000)) {
+			($r == -2 && length($$rbuf) > 0x4000)) {
 		return quit($self, 400);
 	}
 	if ($r < 0) { # incomplete
@@ -121,7 +120,7 @@ sub rbuf_process {
 # IO::Handle::write returns boolean, this returns bytes written:
 sub xwrite ($$$) {
 	my ($fh, $rbuf, $max) = @_;
-	my $w = bytes::length($$rbuf);
+	my $w = length($$rbuf);
 	$w = $max if $w > $max;
 	$fh->write($$rbuf, $w) or return;
 	$w;
@@ -236,7 +235,7 @@ sub response_header_write {
 sub chunked_write ($$) {
 	my $self = $_[0];
 	return if $_[1] eq '';
-	msg_more($self, sprintf("%x\r\n", bytes::length($_[1])));
+	msg_more($self, sprintf("%x\r\n", length($_[1])));
 	msg_more($self, $_[1]);
 
 	# use $self->write(\"\n\n") if you care about real-time
@@ -411,12 +410,12 @@ sub read_input_chunked { # unlikely...
 			$$rbuf =~ s/\A\r\n//s and
 				return app_dispatch($self, $input, $rbuf);
 
-			return quit($self, 400) if bytes::length($$rbuf) > 2;
+			return quit($self, 400) if length($$rbuf) > 2;
 		}
 		if ($len == CHUNK_END) {
 			if ($$rbuf =~ s/\A\r\n//s) {
 				$len = CHUNK_START;
-			} elsif (bytes::length($$rbuf) > 2) {
+			} elsif (length($$rbuf) > 2) {
 				return quit($self, 400);
 			}
 		}
@@ -426,14 +425,14 @@ sub read_input_chunked { # unlikely...
 				if (($len + -s $input) > $MAX_REQUEST_BUFFER) {
 					return quit($self, 413);
 				}
-			} elsif (bytes::length($$rbuf) > CHUNK_MAX_HDR) {
+			} elsif (length($$rbuf) > CHUNK_MAX_HDR) {
 				return quit($self, 400);
 			}
 			# will break from loop since $len >= 0
 		}
 
 		if ($len < 0) { # chunk header is trickled, read more
-			$self->do_read($rbuf, 8192, bytes::length($$rbuf)) or
+			$self->do_read($rbuf, 8192, length($$rbuf)) or
 				return recv_err($self, $len);
 			# (implicit) goto chunk_start if $r > 0;
 		}
diff --git a/lib/PublicInbox/ManifestJsGz.pm b/lib/PublicInbox/ManifestJsGz.pm
index 7fee78dd..69d81fa1 100644
--- a/lib/PublicInbox/ManifestJsGz.pm
+++ b/lib/PublicInbox/ManifestJsGz.pm
@@ -6,7 +6,6 @@ package PublicInbox::ManifestJsGz;
 use strict;
 use v5.10.1;
 use parent qw(PublicInbox::WwwListing);
-use bytes (); # length
 use PublicInbox::Config;
 use IO::Compress::Gzip qw(gzip);
 use HTTP::Date qw(time2str);
@@ -108,7 +107,7 @@ sub psgi_triple {
 	gzip(\$manifest => \(my $out));
 	[ 200, [ qw(Content-Type application/gzip),
 		 'Last-Modified', time2str($ctx->{-mtime}),
-		 'Content-Length', bytes::length($out) ], [ $out ] ]
+		 'Content-Length', length($out) ], [ $out ] ]
 }
 
 sub per_inbox {
diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm
index 13a68bb8..aea04c05 100644
--- a/lib/PublicInbox/NNTP.pm
+++ b/lib/PublicInbox/NNTP.pm
@@ -241,7 +241,7 @@ sub parse_time ($$;$) {
 		$gmt = 1;
 	}
 	my ($YYYY, $MM, $DD);
-	if (bytes::length($date) == 8) { # RFC 3977 allows YYYYMMDD
+	if (length($date) == 8) { # RFC 3977 allows YYYYMMDD
 		($YYYY, $MM, $DD) = unpack('A4A2A2', $date);
 	} else { # legacy clients send YYMMDD
 		my $YY;
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index 17d38302..94ea6148 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -5,8 +5,7 @@
 # See Documentation/design_www.txt for this.
 package PublicInbox::View;
 use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
 use List::Util qw(max);
 use PublicInbox::MsgTime qw(msg_datestamp);
 use PublicInbox::Hval qw(ascii_html obfuscate_addrs prurl mid_href
@@ -531,7 +530,7 @@ sub attach_link ($$$$;$) {
 	return unless $part->{bdy};
 
 	my $nl = $idx eq '1' ? '' : "\n"; # like join("\n", ...)
-	my $size = bytes::length($part->body);
+	my $size = length($part->body);
 
 	# hide attributes normally, unless we want to aid users in
 	# spotting MUA problems:
diff --git a/lib/PublicInbox/ViewVCS.pm b/lib/PublicInbox/ViewVCS.pm
index 702a075d..6365f045 100644
--- a/lib/PublicInbox/ViewVCS.pm
+++ b/lib/PublicInbox/ViewVCS.pm
@@ -15,8 +15,7 @@
 
 package PublicInbox::ViewVCS;
 use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
 use PublicInbox::SolverGit;
 use PublicInbox::WwwStream qw(html_oneshot);
 use PublicInbox::Linkify;
@@ -49,7 +48,7 @@ sub stream_blob_parse_hdr { # {parse_hdr} for Qspawn
 	} elsif (index($$bref, "\0") >= 0) {
 		[200, [qw(Content-Type application/octet-stream), @cl] ];
 	} else {
-		my $n = bytes::length($$bref);
+		my $n = length($$bref);
 		if ($n >= $BIN_DETECT || $n == $size) {
 			return [200, [ 'Content-Type',
 				'text/plain; charset=UTF-8', @cl ] ];
diff --git a/lib/PublicInbox/WWW.pm b/lib/PublicInbox/WWW.pm
index 1afdece0..570e690e 100644
--- a/lib/PublicInbox/WWW.pm
+++ b/lib/PublicInbox/WWW.pm
@@ -11,10 +11,8 @@
 # - Must not rely on static content
 # - UTF-8 is only for user-content, 7-bit US-ASCII for us
 package PublicInbox::WWW;
-use 5.010_001;
 use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
 use PublicInbox::Config;
 use PublicInbox::Hval;
 use URI::Escape qw(uri_unescape);
@@ -646,8 +644,7 @@ sub get_css ($$$) {
 		$css = PublicInbox::UserContent::sample($ctx->{ibx}, $env);
 	}
 	defined $css or return r404();
-	my $h = [ 'Content-Length', bytes::length($css),
-		'Content-Type', 'text/css' ];
+	my $h = [ 'Content-Length', length($css), 'Content-Type', 'text/css' ];
 	PublicInbox::GitHTTPBackend::cache_one_year($h);
 	[ 200, $h, [ $css ] ];
 }
@@ -656,7 +653,8 @@ sub get_description {
 	my ($ctx, $inbox) = @_;
 	invalid_inbox($ctx, $inbox) || do {
 		my $d = $ctx->{ibx}->description . "\n";
-		[ 200, [ 'Content-Length', bytes::length($d),
+		utf8::encode($d);
+		[ 200, [ 'Content-Length', length($d),
 			'Content-Type', 'text/plain' ], [ $d ] ];
 	};
 }
diff --git a/lib/PublicInbox/WwwAttach.pm b/lib/PublicInbox/WwwAttach.pm
index a6c68a3f..c17394af 100644
--- a/lib/PublicInbox/WwwAttach.pm
+++ b/lib/PublicInbox/WwwAttach.pm
@@ -4,8 +4,8 @@
 # For retrieving attachments from messages in the WWW interface
 package PublicInbox::WwwAttach; # internal package
 use strict;
+use v5.10.1;
 use parent qw(PublicInbox::GzipFilter);
-use bytes (); # only for bytes::length
 use PublicInbox::Eml;
 
 sub referer_match ($) {
@@ -50,7 +50,7 @@ sub get_attach_i { # ->each_part callback
 			$part = "Deep-linking prevented\n";
 		}
 	}
-	push @{$res->[1]}, 'Content-Length', bytes::length($part);
+	push @{$res->[1]}, 'Content-Length', length($part);
 	$res->[2]->[0] = $part;
 }
 
diff --git a/lib/PublicInbox/WwwHighlight.pm b/lib/PublicInbox/WwwHighlight.pm
index 6fed2fed..3593c2d4 100644
--- a/lib/PublicInbox/WwwHighlight.pm
+++ b/lib/PublicInbox/WwwHighlight.pm
@@ -20,8 +20,7 @@
 
 package PublicInbox::WwwHighlight;
 use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
 use parent qw(PublicInbox::HlMod);
 use PublicInbox::Linkify qw();
 use PublicInbox::Hval qw(ascii_html);
@@ -69,7 +68,7 @@ sub call {
 	$l->linkify_2($$bref);
 
 	my $h = [ 'Content-Type', 'text/html; charset=UTF-8' ];
-	push @$h, 'Content-Length', bytes::length($$bref);
+	push @$h, 'Content-Length', length($$bref);
 
 	[ 200, $h, [ $$bref ] ]
 }
diff --git a/lib/PublicInbox/WwwListing.pm b/lib/PublicInbox/WwwListing.pm
index a31aa4ca..8b54d724 100644
--- a/lib/PublicInbox/WwwListing.pm
+++ b/lib/PublicInbox/WwwListing.pm
@@ -5,12 +5,12 @@
 # Used by PublicInbox::WWW
 package PublicInbox::WwwListing;
 use strict;
+use v5.10.1;
 use PublicInbox::Hval qw(prurl fmt_ts ascii_html);
 use PublicInbox::Linkify;
 use PublicInbox::GzipFilter qw(gzf_maybe);
 use PublicInbox::ConfigIter;
 use PublicInbox::WwwStream;
-use bytes (); # bytes::length
 
 sub ibx_entry {
 	my ($ctx, $ibx, $ce) = @_;
@@ -213,7 +213,7 @@ sub psgi_triple {
 	my $out = $gzf->zflush('</pre><hr><pre>'.
 			PublicInbox::WwwStream::code_footer($ctx->{env}) .
 			'</pre></body></html>');
-	$h->[3] = bytes::length($out);
+	$h->[3] = length($out);
 	[ $code, $h, [ $out ] ];
 }
 
diff --git a/lib/PublicInbox/WwwStatic.pm b/lib/PublicInbox/WwwStatic.pm
index 29e4819d..b3476ab8 100644
--- a/lib/PublicInbox/WwwStatic.pm
+++ b/lib/PublicInbox/WwwStatic.pm
@@ -9,8 +9,8 @@
 # functionality of nginx.
 package PublicInbox::WwwStatic;
 use strict;
+use v5.10.1;
 use parent qw(Exporter);
-use bytes ();
 use Fcntl qw(SEEK_SET O_RDONLY O_NONBLOCK);
 use POSIX qw(strftime);
 use HTTP::Date qw(time2str);
@@ -318,7 +318,7 @@ sub dir_response ($$$) {
 		"</head><body><pre>Index of $path_info_html</pre><hr><pre>\n");
 	$gzf->zmore(join("\n", @entries));
 	my $out = $gzf->zflush("</pre><hr></body></html>\n");
-	$h->[3] = bytes::length($out);
+	$h->[3] = length($out);
 	[ 200, $h, [ $out ] ]
 }
 
diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm
index 2f8212d4..adcb5fe2 100644
--- a/lib/PublicInbox/WwwStream.pm
+++ b/lib/PublicInbox/WwwStream.pm
@@ -7,9 +7,9 @@
 # See PublicInbox::GzipFilter parent class for more info.
 package PublicInbox::WwwStream;
 use strict;
+use v5.10.1;
 use parent qw(Exporter PublicInbox::GzipFilter);
 our @EXPORT_OK = qw(html_oneshot);
-use bytes (); # length
 use PublicInbox::Hval qw(ascii_html prurl ts2str);
 our $TOR_URL = 'https://www.torproject.org/';
 our $CODE_URL = [ qw(http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git
@@ -216,7 +216,7 @@ sub html_oneshot ($$;$) {
 	};
 	$ctx->zmore($$sref) if $sref;
 	my $bdy = $ctx->zflush(_html_end($ctx));
-	$res_hdr->[3] = bytes::length($bdy);
+	$res_hdr->[3] = length($bdy);
 	[ $code, $res_hdr, [ $bdy ] ]
 }
 
diff --git a/lib/PublicInbox/WwwText.pm b/lib/PublicInbox/WwwText.pm
index 76a95a6b..db5060ea 100644
--- a/lib/PublicInbox/WwwText.pm
+++ b/lib/PublicInbox/WwwText.pm
@@ -4,8 +4,7 @@
 # used for displaying help texts and other non-mail content
 package PublicInbox::WwwText;
 use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
 use PublicInbox::Linkify;
 use PublicInbox::WwwStream;
 use PublicInbox::Hval qw(ascii_html);
@@ -43,7 +42,7 @@ sub get_text {
 			$txt = $gzf->translate($txt);
 			$txt .= $gzf->zflush;
 		}
-		$hdr->[3] = bytes::length($txt);
+		$hdr->[3] = length($txt);
 		return [ $code, $hdr, [ $txt ] ]
 	}
 
diff --git a/t/psgi_search.t b/t/psgi_search.t
index 5bdd66ed..3da93eda 100644
--- a/t/psgi_search.t
+++ b/t/psgi_search.t
@@ -8,7 +8,6 @@ use IO::Uncompress::Gunzip qw(gunzip);
 use PublicInbox::Eml;
 use PublicInbox::Config;
 use PublicInbox::Inbox;
-use bytes (); # only for bytes::length
 my @mods = qw(DBD::SQLite Search::Xapian HTTP::Request::Common Plack::Test
 		URI::Escape Plack::Builder);
 require_mods(@mods);
diff --git a/t/search-thr-index.t b/t/search-thr-index.t
index fc1b666a..62745dbc 100644
--- a/t/search-thr-index.t
+++ b/t/search-thr-index.t
@@ -1,8 +1,8 @@
+#!perl -w
 # Copyright (C) 2017-2021 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
 use Test::More;
 use PublicInbox::TestCommon;
 use PublicInbox::MID qw(mids);
@@ -45,7 +45,7 @@ foreach (reverse split(/\n\n/, $data)) {
 	my $mime = PublicInbox::Eml->new(\$_);
 	$mime->header_set('From' => 'bw@g');
 	$mime->header_set('To' => 'git@vger.kernel.org');
-	my $bytes = bytes::length($mime->as_string);
+	my $bytes = length($mime->as_string);
 	my $mid = mids($mime->header_obj)->[0];
 	my $smsg = bless {
 		bytes => $bytes,
@@ -92,7 +92,7 @@ To: git@vger.kernel.org
 	my $tid0 = $dbh->selectrow_array(<<'', undef, $num);
 SELECT tid FROM over WHERE num = ? LIMIT 1
 
-	my $bytes = bytes::length($mime->as_string);
+	my $bytes = length($mime->as_string);
 	my $mid = mids($mime->header_obj)->[0];
 	my $smsg = bless {
 		bytes => $bytes,
diff --git a/t/www_listing.t b/t/www_listing.t
index 6b3b408f..7ea12eea 100644
--- a/t/www_listing.t
+++ b/t/www_listing.t
@@ -55,7 +55,7 @@ sub tiny_test {
 	ok(my $clone = $manifest->{'/alt'}, '/alt in manifest');
 	is($clone->{owner}, "lorelei \x{100}", 'owner set');
 	is($clone->{reference}, '/bare', 'reference detected');
-	is($clone->{description}, "we're all clones", 'description read');
+	is($clone->{description}, "we're \x{100}ll clones", 'description read');
 	ok(my $bare = $manifest->{'/bare'}, '/bare in manifest');
 	is($bare->{description}, 'Unnamed repository',
 		'missing $GIT_DIR/description fallback');
@@ -72,6 +72,10 @@ sub tiny_test {
 	ok(my $v2epoch1 = $manifest->{'/v2/git/1.git'}, 'v2 epoch 1 appeared');
 	like($v2epoch1->{description}, qr/ \[epoch 1\]\z/,
 		'epoch 1 in description');
+
+	$res = $http->get("http://$host:$port/alt/description");
+	is($res->{content}, "we're \xc4\x80ll clones\n", 'UTF-8 description')
+		or diag explain($res);
 }
 
 my $td;
@@ -91,9 +95,9 @@ SKIP: {
 		is(xsys(@clone, $alt, "$v2/git/$i.git"), 0, "clone epoch $i")
 	}
 	ok(open(my $fh, '>', "$v2/inbox.lock"), 'mock a v2 inbox');
-	open $fh, '>', "$alt/description" or die;
-	print $fh "we're all clones\n" or die;
-	close $fh or die;
+	open $fh, '>', "$alt/description" or xbail "open $alt/description $!";
+	print $fh "we're \xc4\x80ll clones\n" or xbail "print $!";
+	close $fh or xbail "write: $alt/description $!";
 	is(xsys('git', "--git-dir=$alt", qw(config gitweb.owner),
 		"lorelei \xc4\x80"), 0,
 		'set gitweb user');
@@ -178,6 +182,13 @@ manifest = \${site}/v2/manifest.js.gz
 	for (qw(v2/git/0.git v2/git/1.git v2/git/2.git)) {
 		ok(-d "$tmpdir/per-inbox/$_", "grok-pull created $_");
 	}
+	$td->kill;
+	$td->join;
+	is($?, 0, 'no error in exited process');
+	open $fh, '<', $err or BAIL_OUT("open $err failed: $!");
+	my $eout = do { local $/; <$fh> };
+	unlike($eout, qr/wide/i, 'no Wide character warnings');
+	unlike($eout, qr/uninitialized/i, 'no uninitialized warnings');
 }
 
 done_testing();
diff --git a/xt/cmp-msgstr.t b/xt/cmp-msgstr.t
index e0e8ed5a..900127c7 100644
--- a/xt/cmp-msgstr.t
+++ b/xt/cmp-msgstr.t
@@ -60,7 +60,7 @@ my $cmp = sub {
 				my $dig = $dig_cls->new;
 				$dig->add($part);
 				push @$cmp_arg, "M: ".$dig->hexdigest;
-				push @$cmp_arg, "B: ".bytes::length($part);
+				push @$cmp_arg, "B: ".length($part);
 			} else {
 				$part =~ s/\s+\z//s;
 				push @$cmp_arg, "X: ".$part;

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 2/8] ds: use bytes::substr and bytes::length module-wide for now
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
  2021-08-26 12:33   ` [PATCH 1/8] get rid of unnecessary bytes::length usage Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 3/8] www_stream: sh-friendly .onion URLs wrapping Eric Wong
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

The use of substr within IO::Handle->write may not be correct if
we have wide characters, so handle it ourselves.

bytes.pm usage is probably better fixed in PublicInbox::NNTP,
but the effort required is higher, so we'll just keep bytes in
DS for now.
---
 lib/PublicInbox/DS.pm | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm
index 7a4dfed0..d804792b 100644
--- a/lib/PublicInbox/DS.pm
+++ b/lib/PublicInbox/DS.pm
@@ -23,7 +23,7 @@ package PublicInbox::DS;
 use strict;
 use v5.10.1;
 use parent qw(Exporter);
-use bytes;
+use bytes qw(length substr); # FIXME(?): needed for PublicInbox::NNTP
 use POSIX qw(WNOHANG sigprocmask SIG_SETMASK);
 use Fcntl qw(SEEK_SET :DEFAULT O_APPEND);
 use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
@@ -499,13 +499,14 @@ sub drop {
 # n.b.: use ->write/->read for this buffer to allow compatibility with
 # PerlIO::mmap or PerlIO::scalar if needed
 sub tmpio ($$$) {
-    my ($self, $bref, $off) = @_;
-    my $fh = tmpfile('wbuf', $self->{sock}, O_APPEND) or
-        return drop($self, "tmpfile $!");
-    $fh->autoflush(1);
-    my $len = bytes::length($$bref) - $off;
-    $fh->write($$bref, $len, $off) or return drop($self, "write ($len): $!");
-    [ $fh, 0 ] # [1] = offset, [2] = length, not set by us
+	my ($self, $bref, $off) = @_;
+	my $fh = tmpfile('wbuf', $self->{sock}, O_APPEND) or
+		return drop($self, "tmpfile $!");
+	$fh->autoflush(1);
+	my $len = length($$bref) - $off;
+	print $fh substr($$bref, $off, $len) or
+		return drop($self, "write ($len): $!");
+	[ $fh, 0 ] # [1] = offset, [2] = length, not set by us
 }
 
 =head2 C<< $obj->write( $data ) >>
@@ -547,7 +548,7 @@ sub write {
         $bref->($self);
         return 1;
     } else {
-        my $to_write = bytes::length($$bref);
+        my $to_write = length($$bref);
         my $written = syswrite($sock, $$bref, $to_write);
 
         if (defined $written) {
@@ -582,7 +583,7 @@ sub msg_more ($$) {
 		!$sock->can('stop_SSL')) {
         my $n = send($sock, $_[1], MSG_MORE);
         if (defined $n) {
-            my $nlen = bytes::length($_[1]) - $n;
+            my $nlen = length($_[1]) - $n;
             return 1 if $nlen == 0; # all done!
             # queue up the unwritten substring:
             my $tmpio = tmpio($self, \($_[1]), $n) or return 0;

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 3/8] www_stream: sh-friendly .onion URLs wrapping
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
  2021-08-26 12:33   ` [PATCH 1/8] get rid of unnecessary bytes::length usage Eric Wong
  2021-08-26 12:33   ` [PATCH 2/8] ds: use bytes::substr and bytes::length module-wide for now Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 4/8] www: avoid incorrect instructions for extindex Eric Wong
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta; +Cc: Konstantin Ryabitsev

The long v3 .onion URL was causing havoc on small mobile
displays, so extract "hostname" into a variable which can
still used as a Bourne shell snippet.

While we're at it, include "torsocks" in the git command used
for .onion URLs since that's the (near)-universal wrapper for
Tor-ifying things (like git) which are dynamically linked to
libc.

Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Link: https://public-inbox.org/meta/20210816163654.c6gfzuezhji4l6s7@nitro.local/
---
 lib/PublicInbox/WwwStream.pm | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm
index adcb5fe2..57c23690 100644
--- a/lib/PublicInbox/WwwStream.pm
+++ b/lib/PublicInbox/WwwStream.pm
@@ -12,8 +12,10 @@ use parent qw(Exporter PublicInbox::GzipFilter);
 our @EXPORT_OK = qw(html_oneshot);
 use PublicInbox::Hval qw(ascii_html prurl ts2str);
 our $TOR_URL = 'https://www.torproject.org/';
-our $CODE_URL = [ qw(http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git
-	https://public-inbox.org/public-inbox.git) ];
+
+our $CODE_URL = [ qw(
+http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git
+https://public-inbox.org/public-inbox.git) ];
 
 sub base_url ($) {
 	my $ctx = shift;
@@ -107,7 +109,13 @@ EOF
 sub code_footer ($) {
 	my ($env) = @_;
 	my $u = prurl($env, $CODE_URL);
-	qq(AGPL code for this site: git clone <a\nhref="$u">$u</a>)
+	my $arg = $u;
+	if ($arg =~ s!\A(https?://)([^/\.]+)\.onion/!$1\$hostname\.onion/!i) {
+		"AGPL code for this site:\n\thostname=$2\n\t" .
+		qq(torsocks git clone <a\nhref="$u">$arg</a>)
+	} else {
+		qq(AGPL code for this site: git clone <a\nhref="$u">$u</a>)
+	}
 }
 
 sub _html_end {
@@ -125,6 +133,9 @@ EOF
 	my $max = $ibx->max_git_epoch;
 	my $dir = (split(m!/!, $http))[-1];
 	my %seen = ($http => 1);
+	# TODO: some of these URLs may be too long and we may need to
+	# do something like code_footer() above, but these are local
+	# admin-defined
 	if (defined($max)) { # v2
 		for my $i (0..$max) {
 			# old epochs my be deleted:

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 4/8] www: avoid incorrect instructions for extindex
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
                     ` (2 preceding siblings ...)
  2021-08-26 12:33   ` [PATCH 3/8] www_stream: sh-friendly .onion URLs wrapping Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 5/8] www_text: fix example config snippet " Eric Wong
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

There's no way to clone an extindex, since there's no git
storage associated with them.  So attempt to link to the
HTML listing of public-inboxes, instead.
---
 lib/PublicInbox/ExtSearch.pm |   4 --
 lib/PublicInbox/WwwStream.pm | 111 +++++++++++++++++++----------------
 2 files changed, 62 insertions(+), 53 deletions(-)

diff --git a/lib/PublicInbox/ExtSearch.pm b/lib/PublicInbox/ExtSearch.pm
index 0b480c7e..bd301158 100644
--- a/lib/PublicInbox/ExtSearch.pm
+++ b/lib/PublicInbox/ExtSearch.pm
@@ -106,10 +106,6 @@ sub description {
 		'$EXTINDEX_DIR/description missing';
 }
 
-sub cloneurl { [] } # TODO
-
-sub nntp_url { [] }
-
 no warnings 'once';
 *base_url = \&PublicInbox::Inbox::base_url;
 *smsg_eml = \&PublicInbox::Inbox::smsg_eml;
diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm
index 57c23690..d8142824 100644
--- a/lib/PublicInbox/WwwStream.pm
+++ b/lib/PublicInbox/WwwStream.pm
@@ -120,52 +120,50 @@ sub code_footer ($) {
 
 sub _html_end {
 	my ($ctx) = @_;
-	my $urls = <<EOF;
-<a
-id=mirror>This inbox may be cloned and mirrored by anyone:</a>
-EOF
-
 	my $ibx = $ctx->{ibx};
 	my $desc = ascii_html($ibx->description);
-
-	my @urls;
+	my $s = "<a\nid=mirror>";
 	my $http = $ctx->{base_url};
-	my $max = $ibx->max_git_epoch;
 	my $dir = (split(m!/!, $http))[-1];
 	my %seen = ($http => 1);
-	# TODO: some of these URLs may be too long and we may need to
-	# do something like code_footer() above, but these are local
-	# admin-defined
-	if (defined($max)) { # v2
-		for my $i (0..$max) {
-			# old epochs my be deleted:
-			-d "$ibx->{inboxdir}/git/$i.git" or next;
-			my $url = "$http/$i";
-			$seen{$url} = 1;
-			push @urls, "$url $dir/git/$i.git";
+	if ($ibx->can('cloneurl')) { # PublicInbox::Inbox
+		$s .= "This inbox may be cloned and mirrored by anyone:</a>\n";
+		my @urls;
+		my $max = $ibx->max_git_epoch;
+		# TODO: some of these URLs may be too long and we may need to
+		# do something like code_footer() above, but these are local
+		# admin-defined
+		if (defined($max)) { # v2
+			for my $i (0..$max) {
+				# old epochs my be deleted:
+				-d "$ibx->{inboxdir}/git/$i.git" or next;
+				my $url = "$http/$i";
+				$seen{$url} = 1;
+				push @urls, "$url $dir/git/$i.git";
+			}
+			my $nr = scalar(@urls);
+			if ($nr > 1) {
+				$s .= "\n\t";
+				$s .= "# this inbox consists of $nr epochs:";
+				$urls[0] .= "\t# oldest";
+				$urls[-1] .= "\t# newest";
+			}
+		} else { # v1
+			push @urls, $http;
 		}
-		my $nr = scalar(@urls);
-		if ($nr > 1) {
-			$urls .= "\n\t# this inbox consists of $nr epochs:";
-			$urls[0] .= "\t# oldest";
-			$urls[-1] .= "\t# newest";
+		# FIXME: epoch splits can be different in other repositories,
+		# use the "cloneurl" file as-is for now:
+		for my $u (@{$ibx->cloneurl}) {
+			next if $seen{$u}++;
+			push @urls, ($u =~ /\Ahttps?:/ ?
+					qq(<a\nhref="$u">$u</a>) : $u);
 		}
-	} else { # v1
-		push @urls, $http;
-	}
-
-	# FIXME: epoch splits can be different in other repositories,
-	# use the "cloneurl" file as-is for now:
-	foreach my $u (@{$ibx->cloneurl}) {
-		next if $seen{$u}++;
-		push @urls, $u =~ /\Ahttps?:/ ? qq(<a\nhref="$u">$u</a>) : $u;
-	}
-
-	$urls .= "\n" . join('', map { "\tgit clone --mirror $_\n" } @urls);
-	if (my $addrs = $ibx->{address}) {
-		$addrs = join(' ', @$addrs) if ref($addrs) eq 'ARRAY';
-		my $v = defined $max ? '-V2' : '-V1';
-		$urls .= <<EOF;
+		$s .= "\n";
+		$s .= join('', map { "\tgit clone --mirror $_\n" } @urls);
+		if (my $addrs = $ibx->{address}) {
+			$addrs = join(' ', @$addrs) if ref($addrs) eq 'ARRAY';
+			my $v = defined $max ? '-V2' : '-V1';
+			$s .= <<EOF;
 
 	# If you have public-inbox 1.1+ installed, you may
 	# initialize and index your mirror using the following commands:
@@ -173,26 +171,41 @@ EOF
 		$addrs
 	public-inbox-index $dir
 EOF
+		}
+	} else { # PublicInbox::ExtSearch
+		$s .= <<EOM;
+This is an extindex which is an amalgamation of several public-inboxes</a>
+EOM
+		my $v = $ctx->{www}->{pi_cfg}->{lc('publicInbox.wwwListing')};
+		if (($v // '') =~ /\A(?:all|match=domain)\z/) {
+			my $upfx = ($ctx->{-upfx} // ''). '../';
+			$s .= <<EOM;
+A list of them is available in the <a\nhref="$upfx">listing</a>
+EOM
+		}
 	}
+
 	my $cfg_link = ($ctx->{-upfx} // '').'_/text/config/raw';
-	$urls .= <<EOF;
+	$s .= <<EOF;
 
 Example <a
 href="$cfg_link">config snippet</a> for mirrors.
 EOF
-	my @nntp = map { qq(<a\nhref="$_">$_</a>) } @{$ibx->nntp_url};
-	if (@nntp) {
-		$urls .= @nntp == 1 ? 'Newsgroup' : 'Newsgroups are';
-		$urls .= ' available over NNTP:';
-		$urls .= "\n\t" . join("\n\t", @nntp) . "\n";
+	if ($ibx->can('nntp_url')) {
+		my @nntp = map { qq(<a\nhref="$_">$_</a>) } @{$ibx->nntp_url};
+		if (@nntp) {
+			$s .= @nntp == 1 ? 'Newsgroup' : 'Newsgroups are';
+			$s .= ' available over NNTP:';
+			$s .= "\n\t" . join("\n\t", @nntp) . "\n";
+		}
 	}
-	if ($urls =~ m!\b[^:]+://\w+\.onion/!) {
-		$urls .= " note: .onion URLs require Tor: ";
-		$urls .= qq[<a\nhref="$TOR_URL">$TOR_URL</a>];
+	if ($s =~ m!\b[^:]+://\w+\.onion/!) {
+		$s .= " note: .onion URLs require Tor: ";
+		$s .= qq[<a\nhref="$TOR_URL">$TOR_URL</a>];
 	}
 	'<hr><pre>'.join("\n\n",
 		$desc,
-		$urls,
+		$s,
 		coderepos($ctx),
 		code_footer($ctx->{env})
 	).'</pre></body></html>';

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 5/8] www_text: fix example config snippet for extindex
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
                     ` (3 preceding siblings ...)
  2021-08-26 12:33   ` [PATCH 4/8] www: avoid incorrect instructions for extindex Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 6/8] config: do not parse altid " Eric Wong
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

extindex doesn't use the same config stuff as normal
"publicinbox" entries, so we'll need a separate function
for them.
---
 lib/PublicInbox/WwwText.pm | 29 ++++++++++++++++++++++++++++-
 t/extindex-psgi.t          | 12 ++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/lib/PublicInbox/WwwText.pm b/lib/PublicInbox/WwwText.pm
index db5060ea..eb5e3ac7 100644
--- a/lib/PublicInbox/WwwText.pm
+++ b/lib/PublicInbox/WwwText.pm
@@ -214,10 +214,37 @@ EOF
 	1;
 }
 
+# n.b. this is a perfect candidate for memoization
+sub extindex_config ($$$) {
+	my ($ctx, $hdr, $txt) = @_;
+	my $ibx = $ctx->{ibx};
+	push @$hdr, 'Content-Disposition', 'inline; filename=extindex.config';
+	my $name = dq_escape($ibx->{name});
+	my $base_url = $ibx->base_url($ctx->{env});
+	$$txt .= <<EOS;
+; Example public-inbox config snippet for the external index (extindex) at:
+; $base_url
+; See public-inbox-config(5)manpage for more details:
+; https://public-inbox.org/public-inbox-config.html
+[extindex "$name"]
+	topdir = /path/to/extindex-topdir
+	url = https://example.com/$name/
+	url = http://example.onion/$name/
+EOS
+	for my $k (qw(infourl)) {
+		defined(my $v = $ibx->{$k}) or next;
+		$$txt .= "\t$k = $v\n";
+	}
+	# TODO: coderepo support for extindex
+	1;
+}
+
 sub _default_text ($$$$) {
 	my ($ctx, $key, $hdr, $txt) = @_;
 	return _colors_help($ctx, $txt) if $key eq 'color';
-	return inbox_config($ctx, $hdr, $txt) if $key eq 'config';
+	$key eq 'config' and return $ctx->{ibx}->can('cloneurl') ?
+			inbox_config($ctx, $hdr, $txt) :
+			extindex_config($ctx, $hdr, $txt);
 	return if $key ne 'help'; # TODO more keys?
 
 	my $ibx = $ctx->{ibx};
diff --git a/t/extindex-psgi.t b/t/extindex-psgi.t
index 6f62b5a0..b9acc979 100644
--- a/t/extindex-psgi.t
+++ b/t/extindex-psgi.t
@@ -40,6 +40,18 @@ my $client = sub {
 		'Host: header respected in Atom feed');
 	unlike($res->content, qr!http://bogus\.example\.com/!s,
 		'default URL ignored with different host header');
+
+	$res = $cb->(GET('/all/_/text/config/'));
+	is($res->code, 200, '/text/config HTML');
+	$res = $cb->(GET('/all/_/text/config/raw'));
+	is($res->code, 200, '/text/config raw');
+	my $f = "$tmpdir/extindex.config";
+	open my $fh, '>', $f or xbail $!;
+	print $fh $res->content or xbail $!;
+	close $fh or xbail $!;
+	my $cfg = PublicInbox::Config->git_config_dump($f);
+	is($?, 0, 'no errors from git-config parsing');
+	ok($cfg->{'extindex.all.topdir'}, 'extindex.topdir defined');
 };
 test_psgi(sub { $www->call(@_) }, $client);
 %$env = (%$env, TMPDIR => $tmpdir, PI_CONFIG => $pi_config);

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 6/8] config: do not parse altid for extindex
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
                     ` (4 preceding siblings ...)
  2021-08-26 12:33   ` [PATCH 5/8] www_text: fix example config snippet " Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 7/8] www_text: add coderepo config support " Eric Wong
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

There's currently no support for altid with extindex, and
there's likely no legacy precedent for using altid like there is
with single public-inboxes.
---
 lib/PublicInbox/Config.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index 7aa1f6c8..b3e00ae0 100644
--- a/lib/PublicInbox/Config.pm
+++ b/lib/PublicInbox/Config.pm
@@ -525,7 +525,7 @@ sub _fill_ei ($$) {
 		my $v = get_1($self, $pfx, $k) // next;
 		$es->{$k} = $v;
 	}
-	for my $k (qw(altid coderepo hide url infourl)) {
+	for my $k (qw(coderepo hide url infourl)) {
 		my $v = $self->{"$pfx.$k"} // next;
 		$es->{$k} = _array($v);
 	}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 7/8] www_text: add coderepo config support for extindex
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
                     ` (5 preceding siblings ...)
  2021-08-26 12:33   ` [PATCH 6/8] config: do not parse altid " Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 12:33   ` [PATCH 8/8] move ->ids_after from mm to over Eric Wong
  2021-08-26 13:27   ` [PATCH 0/8] various WWW + extindex stuff Konstantin Ryabitsev
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

At least manually configured coderepos "just work"
for extindex, though it probably could be automatic
and inherited from the publicinbox configs.
---
 lib/PublicInbox/WwwText.pm | 75 +++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 37 deletions(-)

diff --git a/lib/PublicInbox/WwwText.pm b/lib/PublicInbox/WwwText.pm
index eb5e3ac7..47310258 100644
--- a/lib/PublicInbox/WwwText.pm
+++ b/lib/PublicInbox/WwwText.pm
@@ -129,7 +129,42 @@ sub dq_escape ($) {
 	$name;
 }
 
-sub URI_PATH () { '^A-Za-z0-9\-\._~/' }
+sub _coderepo_config ($$) {
+	my ($ctx, $txt) = @_;
+	my $cr = $ctx->{ibx}->{coderepo} // return;
+	# note: this doesn't preserve cgitrc layout, since we parse cgitrc
+	# and drop the original structure
+	$$txt .= "\tcoderepo = $_\n" for @$cr;
+	$$txt .= <<'EOF';
+
+; `coderepo' entries allows blob reconstruction via patch emails if
+; the inbox is indexed with Xapian.  `@@ <from-range> <to-range> @@'
+; line number ranges in `[PATCH]' emails link to /$INBOX_NAME/$OID/s/,
+; an HTTP endpoint which reconstructs git blobs via git-apply(1).
+EOF
+	my $pi_cfg = $ctx->{www}->{pi_cfg};
+	for my $cr_name (@$cr) {
+		my $urls = $pi_cfg->get_all("coderepo.$cr_name.cgiturl");
+		my $path = "/path/to/$cr_name";
+		$cr_name = dq_escape($cr_name);
+
+		$$txt .= qq([coderepo "$cr_name"]\n);
+		if ($urls && scalar(@$urls)) {
+			$$txt .= "\t; ";
+			$$txt .= join(" ||\n\t;\t", map {;
+				my $dst = $path;
+				if ($path !~ m![a-z0-9_/\.\-]!i) {
+					$dst = '"'.dq_escape($dst).'"';
+				}
+				qq(git clone $_ $dst);
+			} @$urls);
+			$$txt .= "\n";
+		}
+		$$txt .= "\tdir = $path\n";
+		$$txt .= "\tcgiturl = https://example.com/";
+		$$txt .= uri_escape_utf8($cr_name, '^A-Za-z0-9\-\._~/')."\n";
+	}
+}
 
 # n.b. this is a perfect candidate for memoization
 sub inbox_config ($$$) {
@@ -176,41 +211,7 @@ EOF
 		$$txt .= "\t$k = $v\n";
 	}
 	$$txt .= "\tnntpmirror = $_\n" for (@{$ibx->nntp_url});
-
-	# note: this doesn't preserve cgitrc layout, since we parse cgitrc
-	# and drop the original structure
-	if (defined(my $cr = $ibx->{coderepo})) {
-		$$txt .= "\tcoderepo = $_\n" for @$cr;
-		$$txt .= <<'EOF';
-
-; `coderepo' entries allows blob reconstruction via patch emails if
-; the inbox is indexed with Xapian.  `@@ <from-range> <to-range> @@'
-; line number ranges in `[PATCH]' emails link to /$INBOX_NAME/$OID/s/,
-; an HTTP endpoint which reconstructs git blobs via git-apply(1).
-EOF
-		my $pi_cfg = $ctx->{www}->{pi_cfg};
-		for my $cr_name (@$cr) {
-			my $urls = $pi_cfg->get_all("coderepo.$cr_name.cgiturl");
-			my $path = "/path/to/$cr_name";
-			$cr_name = dq_escape($cr_name);
-
-			$$txt .= qq([coderepo "$cr_name"]\n);
-			if ($urls && scalar(@$urls)) {
-				$$txt .= "\t; ";
-				$$txt .= join(" ||\n\t;\t", map {;
-					my $dst = $path;
-					if ($path !~ m![a-z0-9_/\.\-]!i) {
-						$dst = '"'.dq_escape($dst).'"';
-					}
-					qq(git clone $_ $dst);
-				} @$urls);
-				$$txt .= "\n";
-			}
-			$$txt .= "\tdir = $path\n";
-			$$txt .= "\tcgiturl = https://example.com/";
-			$$txt .= uri_escape_utf8($cr_name, URI_PATH)."\n";
-		}
-	}
+	_coderepo_config($ctx, $txt);
 	1;
 }
 
@@ -235,7 +236,7 @@ EOS
 		defined(my $v = $ibx->{$k}) or next;
 		$$txt .= "\t$k = $v\n";
 	}
-	# TODO: coderepo support for extindex
+	_coderepo_config($ctx, $txt);
 	1;
 }
 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 8/8] move ->ids_after from mm to over
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
                     ` (6 preceding siblings ...)
  2021-08-26 12:33   ` [PATCH 7/8] www_text: add coderepo config support " Eric Wong
@ 2021-08-26 12:33   ` Eric Wong
  2021-08-26 13:27   ` [PATCH 0/8] various WWW + extindex stuff Konstantin Ryabitsev
  8 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-26 12:33 UTC (permalink / raw)
  To: meta

Since we favor ->over in WWW and IMAP, move this method to
->over to reduce open files in common cases.

This fixes the /$EXTINDEX_NAME/all.mbox.gz endpoint for extindex
entries (which may get expensive...).
---
 lib/PublicInbox/Mbox.pm   | 10 ++++------
 lib/PublicInbox/Msgmap.pm | 11 -----------
 lib/PublicInbox/NNTP.pm   |  2 +-
 lib/PublicInbox/Over.pm   | 11 +++++++++++
 t/extindex-psgi.t         |  3 +++
 5 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/lib/PublicInbox/Mbox.pm b/lib/PublicInbox/Mbox.pm
index 844099aa..f72af26b 100644
--- a/lib/PublicInbox/Mbox.pm
+++ b/lib/PublicInbox/Mbox.pm
@@ -161,19 +161,17 @@ sub all_ids_cb {
 			my $smsg = $ctx->{over}->get_art($num) or next;
 			return $smsg;
 		}
-		$ctx->{ids} = $ids = $ctx->{mm}->ids_after(\($ctx->{prev}));
+		$ctx->{ids} = $ids = $ctx->{over}->ids_after(\($ctx->{prev}));
 	} while (@$ids);
 }
 
 sub mbox_all_ids {
 	my ($ctx) = @_;
-	my $ibx = $ctx->{ibx};
 	my $prev = 0;
-	my $mm = $ctx->{mm} = $ibx->mm;
-	my $ids = $mm->ids_after(\$prev) or return
-		[404, [qw(Content-Type text/plain)], ["No results found\n"]];
-	$ctx->{over} = $ibx->over or
+	$ctx->{over} = $ctx->{ibx}->over or
 		return PublicInbox::WWW::need($ctx, 'Overview');
+	my $ids = $ctx->{over}->ids_after(\$prev) or return
+		[404, [qw(Content-Type text/plain)], ["No results found\n"]];
 	$ctx->{ids} = $ids;
 	$ctx->{prev} = $prev;
 	require PublicInbox::MboxGz;
diff --git a/lib/PublicInbox/Msgmap.pm b/lib/PublicInbox/Msgmap.pm
index 16a9a476..3887a9e6 100644
--- a/lib/PublicInbox/Msgmap.pm
+++ b/lib/PublicInbox/Msgmap.pm
@@ -189,17 +189,6 @@ CREATE TABLE IF NOT EXISTS meta (
 
 }
 
-# used by NNTP.pm
-sub ids_after {
-	my ($self, $num) = @_;
-	my $ids = $self->{dbh}->selectcol_arrayref(<<'', undef, $$num);
-SELECT num FROM msgmap WHERE num > ?
-ORDER BY num ASC LIMIT 1000
-
-	$$num = $ids->[-1] if @$ids;
-	$ids;
-}
-
 sub msg_range {
 	my ($self, $beg, $end, $cols) = @_;
 	$cols //= 'num,mid';
diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm
index aea04c05..ea9ce183 100644
--- a/lib/PublicInbox/NNTP.pm
+++ b/lib/PublicInbox/NNTP.pm
@@ -210,7 +210,7 @@ sub listgroup_range_i {
 
 sub listgroup_all_i {
 	my ($self, $num) = @_;
-	my $ary = $self->{ibx}->mm(1)->ids_after($num);
+	my $ary = $self->{ibx}->over(1)->ids_after($num);
 	scalar(@$ary) or return;
 	more($self, join("\r\n", @$ary));
 	1;
diff --git a/lib/PublicInbox/Over.pm b/lib/PublicInbox/Over.pm
index 58fdea0e..19da056a 100644
--- a/lib/PublicInbox/Over.pm
+++ b/lib/PublicInbox/Over.pm
@@ -371,4 +371,15 @@ SELECT COUNT(*) FROM xref3 WHERE oidbin = ?
 
 sub blob_exists { oidbin_exists($_[0], pack('H*', $_[1])) }
 
+# used by NNTP.pm
+sub ids_after {
+	my ($self, $num) = @_;
+	my $ids = dbh($self)->selectcol_arrayref(<<'', undef, $$num);
+SELECT num FROM over WHERE num > ?
+ORDER BY num ASC LIMIT 1000
+
+	$$num = $ids->[-1] if @$ids;
+	$ids;
+}
+
 1;
diff --git a/t/extindex-psgi.t b/t/extindex-psgi.t
index b9acc979..d4761641 100644
--- a/t/extindex-psgi.t
+++ b/t/extindex-psgi.t
@@ -52,6 +52,9 @@ my $client = sub {
 	my $cfg = PublicInbox::Config->git_config_dump($f);
 	is($?, 0, 'no errors from git-config parsing');
 	ok($cfg->{'extindex.all.topdir'}, 'extindex.topdir defined');
+
+	$res = $cb->(GET('/all/all.mbox.gz'));
+	is($res->code, 200, 'all.mbox.gz');
 };
 test_psgi(sub { $www->call(@_) }, $client);
 %$env = (%$env, TMPDIR => $tmpdir, PI_CONFIG => $pi_config);

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 0/8] various WWW + extindex stuff
  2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
                     ` (7 preceding siblings ...)
  2021-08-26 12:33   ` [PATCH 8/8] move ->ids_after from mm to over Eric Wong
@ 2021-08-26 13:27   ` Konstantin Ryabitsev
  2021-08-28 11:50     ` [PATCH 0/2] www: split out mirror to /text/ Eric Wong
  8 siblings, 1 reply; 21+ messages in thread
From: Konstantin Ryabitsev @ 2021-08-26 13:27 UTC (permalink / raw)
  To: Eric Wong; +Cc: meta

On Thu, Aug 26, 2021 at 12:33:30PM +0000, Eric Wong wrote:
> This hopefully makes the long .onion URL more usable on small
> displays;

It's still not quite fixing the problem (actually, for some reason it's now
looking worse in the narrow mobile view for me). May I suggest the following:

- The / mirror / link at the top should link to _/text/mirror
- Everything below "This inbox may be clone and mirrored by anyone:" should
  move to that page, including cloning instructions for public-inbox itself
- "AGPL code to this site" will be just a link to _/text/mirror/#clone

I think this solves multiple problems:

1. Removes the long link view from the thread listing, allowing for better
   display on narrow screens; mobile device users are unlikely to be accessing
   the mirroring instructions page, because that requires an actual
   workstation to do.
2. On lists with a lot of epochs, moving mirroring instructions from every
   view shrinks the page basement considerably (e.g. see /lkml/ with 11
   epochs).
3. Allows adding more content to _/text/mirror page without any fear of
   impacting the thread listing.

What do you think?

-K

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 0/2] www: split out mirror to /text/
  2021-08-26 13:27   ` [PATCH 0/8] various WWW + extindex stuff Konstantin Ryabitsev
@ 2021-08-28 11:50     ` Eric Wong
  2021-08-28 11:50       ` [PATCH 1/2] www: move mirror instructions " Eric Wong
                         ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-28 11:50 UTC (permalink / raw)
  To: meta; +Cc: Konstantin Ryabitsev

Maybe this works better?  *shrug*

I was somewhat under the impression every page needed to
link/advertise code under the AGPL, but maybe just one HTML page
is fine...  We can't advertise our AGPL code to NNTP/IMAP users,
nor to people using Atom feed readers.

So maybe just burying the code link in the "mirror" link is
fine.  I could never be comfortable with promoting anything I
do, anyways.

Eric Wong (2):
  www: move mirror instructions to /text/
  www_stream: description header links to top $INBOX_URL

 lib/PublicInbox/WwwListing.pm |   4 +-
 lib/PublicInbox/WwwStream.pm  | 118 +++---------------------------
 lib/PublicInbox/WwwText.pm    | 134 +++++++++++++++++++++++++++++++++-
 t/psgi_mount.t                |  11 +--
 4 files changed, 145 insertions(+), 122 deletions(-)

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/2] www: move mirror instructions to /text/
  2021-08-28 11:50     ` [PATCH 0/2] www: split out mirror to /text/ Eric Wong
@ 2021-08-28 11:50       ` Eric Wong
  2021-08-28 11:50       ` [PATCH 2/2] www_stream: description header links to top $INBOX_URL Eric Wong
  2021-08-28 17:58       ` [PATCH 0/2] www: split out mirror to /text/ Konstantin Ryabitsev
  2 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-28 11:50 UTC (permalink / raw)
  To: meta; +Cc: Konstantin Ryabitsev

This makes the mirroring and code retrieval instructions less
obstructive.  Relying on WwwText means we only use our Linkify
module to make hrefs of full URLs; making relative and shortened
hrefs off-limits; hopefully this isn't too much of a problem.

coderepo information remains duplicated on every page since
(IMHO) coderepos are an important feature; but nobody besides me
has ever bothered to configure coderepos, so I suppose it's
fine...

Suggested-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Link: https://public-inbox.org/meta/20210826132747.6gxuwnhftyf7c6hp@nitro.local/
---
 lib/PublicInbox/WwwListing.pm |   4 +-
 lib/PublicInbox/WwwStream.pm  | 116 +++--------------------------
 lib/PublicInbox/WwwText.pm    | 134 +++++++++++++++++++++++++++++++++-
 t/psgi_mount.t                |  11 +--
 4 files changed, 143 insertions(+), 122 deletions(-)

diff --git a/lib/PublicInbox/WwwListing.pm b/lib/PublicInbox/WwwListing.pm
index ef9048b5..c3779619 100644
--- a/lib/PublicInbox/WwwListing.pm
+++ b/lib/PublicInbox/WwwListing.pm
@@ -226,9 +226,7 @@ sub psgi_triple {
 	} else {
 		$gzf->zmore('<pre>no inboxes, yet');
 	}
-	my $out = $gzf->zflush('</pre><hr><pre>'.
-			PublicInbox::WwwStream::code_footer($ctx->{env}) .
-			'</pre></body></html>');
+	my $out = $gzf->zflush('</pre></body></html>');
 	$h->[3] = length($out);
 	[ $code, $h, [ $out ] ];
 }
diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm
index d8142824..c960edc5 100644
--- a/lib/PublicInbox/WwwStream.pm
+++ b/lib/PublicInbox/WwwStream.pm
@@ -11,7 +11,6 @@ use v5.10.1;
 use parent qw(Exporter PublicInbox::GzipFilter);
 our @EXPORT_OK = qw(html_oneshot);
 use PublicInbox::Hval qw(ascii_html prurl ts2str);
-our $TOR_URL = 'https://www.torproject.org/';
 
 our $CODE_URL = [ qw(
 http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git
@@ -42,8 +41,6 @@ sub html_top ($) {
 	my $desc = ascii_html($ibx->description);
 	my $title = delete($ctx->{-title_html}) // $desc;
 	my $upfx = $ctx->{-upfx} || '';
-	my $help = $upfx.'_/text/help/';
-	my $color = $upfx.'_/text/color/';
 	my $atom = $ctx->{-atom} || $upfx.'new.atom';
 	my $top = "<b>$desc</b>";
 	if (my $t_max = $ctx->{-t_max}) {
@@ -54,9 +51,11 @@ sub html_top ($) {
 		$top = qq(<a\nhref="./">$top</a>);
 	}
 	my $code = $ibx->{coderepo} ? qq( / <a\nhref=#code>code</a>) : '';
-	my $links = qq(<a\nhref="$help">help</a> / ).
-			qq(<a\nhref="$color">color</a> / ).
-			qq(<a\nhref=#mirror>mirror</a>$code / ).
+	# id=mirror must exist for legacy bookmarks
+	my $links = qq(<a\nhref="${upfx}_/text/help/">help</a> / ).
+			qq(<a\nhref="${upfx}_/text/color/">color</a> / ).
+			qq(<a\nid=mirror) .
+			qq(\nhref="${upfx}_/text/mirror/">mirror</a>$code / ).
 			qq(<a\nhref="$atom">Atom feed</a>);
 	if ($ibx->isrch) {
 		my $q_val = delete($ctx->{-q_value_html}) // '';
@@ -106,109 +105,12 @@ EOF
 	@ret; # may be empty, this sub is called as an arg for join()
 }
 
-sub code_footer ($) {
-	my ($env) = @_;
-	my $u = prurl($env, $CODE_URL);
-	my $arg = $u;
-	if ($arg =~ s!\A(https?://)([^/\.]+)\.onion/!$1\$hostname\.onion/!i) {
-		"AGPL code for this site:\n\thostname=$2\n\t" .
-		qq(torsocks git clone <a\nhref="$u">$arg</a>)
-	} else {
-		qq(AGPL code for this site: git clone <a\nhref="$u">$u</a>)
-	}
-}
-
 sub _html_end {
 	my ($ctx) = @_;
-	my $ibx = $ctx->{ibx};
-	my $desc = ascii_html($ibx->description);
-	my $s = "<a\nid=mirror>";
-	my $http = $ctx->{base_url};
-	my $dir = (split(m!/!, $http))[-1];
-	my %seen = ($http => 1);
-	if ($ibx->can('cloneurl')) { # PublicInbox::Inbox
-		$s .= "This inbox may be cloned and mirrored by anyone:</a>\n";
-		my @urls;
-		my $max = $ibx->max_git_epoch;
-		# TODO: some of these URLs may be too long and we may need to
-		# do something like code_footer() above, but these are local
-		# admin-defined
-		if (defined($max)) { # v2
-			for my $i (0..$max) {
-				# old epochs my be deleted:
-				-d "$ibx->{inboxdir}/git/$i.git" or next;
-				my $url = "$http/$i";
-				$seen{$url} = 1;
-				push @urls, "$url $dir/git/$i.git";
-			}
-			my $nr = scalar(@urls);
-			if ($nr > 1) {
-				$s .= "\n\t";
-				$s .= "# this inbox consists of $nr epochs:";
-				$urls[0] .= "\t# oldest";
-				$urls[-1] .= "\t# newest";
-			}
-		} else { # v1
-			push @urls, $http;
-		}
-		# FIXME: epoch splits can be different in other repositories,
-		# use the "cloneurl" file as-is for now:
-		for my $u (@{$ibx->cloneurl}) {
-			next if $seen{$u}++;
-			push @urls, ($u =~ /\Ahttps?:/ ?
-					qq(<a\nhref="$u">$u</a>) : $u);
-		}
-		$s .= "\n";
-		$s .= join('', map { "\tgit clone --mirror $_\n" } @urls);
-		if (my $addrs = $ibx->{address}) {
-			$addrs = join(' ', @$addrs) if ref($addrs) eq 'ARRAY';
-			my $v = defined $max ? '-V2' : '-V1';
-			$s .= <<EOF;
-
-	# If you have public-inbox 1.1+ installed, you may
-	# initialize and index your mirror using the following commands:
-	public-inbox-init $v $ibx->{name} $dir/ $http \\
-		$addrs
-	public-inbox-index $dir
-EOF
-		}
-	} else { # PublicInbox::ExtSearch
-		$s .= <<EOM;
-This is an extindex which is an amalgamation of several public-inboxes</a>
-EOM
-		my $v = $ctx->{www}->{pi_cfg}->{lc('publicInbox.wwwListing')};
-		if (($v // '') =~ /\A(?:all|match=domain)\z/) {
-			my $upfx = ($ctx->{-upfx} // ''). '../';
-			$s .= <<EOM;
-A list of them is available in the <a\nhref="$upfx">listing</a>
-EOM
-		}
-	}
-
-	my $cfg_link = ($ctx->{-upfx} // '').'_/text/config/raw';
-	$s .= <<EOF;
-
-Example <a
-href="$cfg_link">config snippet</a> for mirrors.
-EOF
-	if ($ibx->can('nntp_url')) {
-		my @nntp = map { qq(<a\nhref="$_">$_</a>) } @{$ibx->nntp_url};
-		if (@nntp) {
-			$s .= @nntp == 1 ? 'Newsgroup' : 'Newsgroups are';
-			$s .= ' available over NNTP:';
-			$s .= "\n\t" . join("\n\t", @nntp) . "\n";
-		}
-	}
-	if ($s =~ m!\b[^:]+://\w+\.onion/!) {
-		$s .= " note: .onion URLs require Tor: ";
-		$s .= qq[<a\nhref="$TOR_URL">$TOR_URL</a>];
-	}
-	'<hr><pre>'.join("\n\n",
-		$desc,
-		$s,
-		coderepos($ctx),
-		code_footer($ctx->{env})
-	).'</pre></body></html>';
+	my @cr = coderepos($ctx);
+	scalar(@cr) ?
+		'<hr><pre>'.join("\n\n", @cr).'</pre></body></html>' :
+		'</body></html>';
 }
 
 # callback for HTTP.pm (and any other PSGI servers)
diff --git a/lib/PublicInbox/WwwText.pm b/lib/PublicInbox/WwwText.pm
index 47310258..858fc2f7 100644
--- a/lib/PublicInbox/WwwText.pm
+++ b/lib/PublicInbox/WwwText.pm
@@ -7,7 +7,7 @@ use strict;
 use v5.10.1;
 use PublicInbox::Linkify;
 use PublicInbox::WwwStream;
-use PublicInbox::Hval qw(ascii_html);
+use PublicInbox::Hval qw(ascii_html prurl);
 use URI::Escape qw(uri_escape_utf8);
 use PublicInbox::GzipFilter qw(gzf_maybe);
 our $QP_URL = 'https://xapian.org/docs/queryparser.html';
@@ -23,7 +23,7 @@ sub get_text {
 	my ($ctx, $key) = @_;
 	my $code = 200;
 
-	$key = 'help' if !defined $key; # this 302s to _/text/help/
+	$key //= 'help'; # this 302s to _/text/help/
 
 	# get the raw text the same way we get mboxrds
 	my $raw = ($key =~ s!/raw\z!!);
@@ -240,12 +240,138 @@ EOS
 	1;
 }
 
+sub coderepos_raw ($$) {
+	my ($ctx, $top_url) = @_;
+	my $cr = $ctx->{ibx}->{coderepo} // return ();
+	my $cfg = $ctx->{www}->{pi_cfg};
+	my @ret;
+	for my $cr_name (@$cr) {
+		$ret[0] //= <<EOF;
+code repositories for project(s) associated with this inbox:
+EOF
+		my $urls = $cfg->get_all("coderepo.$cr_name.cgiturl");
+		if ($urls) {
+			for (@$urls) {
+				# relative or absolute URL?, prefix relative
+				# "foo.git" with appropriate number of "../"
+				my $u = m!\A(?:[a-z\+]+:)?//!i ? $_ :
+					$top_url.$_;
+				$ret[0] .= "\n\t" . prurl($ctx->{env}, $u);
+			}
+		} else {
+			$ret[0] .= qq[\n\t$cr_name.git (no URL configured)];
+		}
+	}
+	@ret; # may be empty, this sub is called as an arg for join()
+}
+
+sub _mirror_help ($$) {
+	my ($ctx, $txt) = @_;
+	my $ibx = $ctx->{ibx};
+	my $base_url = $ibx->base_url($ctx->{env});
+	chop $base_url; # no trailing slash for "git clone"
+	my $dir = (split(m!/!, $base_url))[-1];
+	my %seen = ($base_url => 1);
+	my $top_url = $base_url;
+	$top_url =~ s!/[^/]+\z!/!;
+	$$txt .= "public-inbox mirroring instructions\n\n";
+	if ($ibx->can('cloneurl')) { # PublicInbox::Inbox
+		$$txt .= "This inbox may be cloned and mirrored by anyone:\n";
+		my @urls;
+		my $max = $ibx->max_git_epoch;
+		# TODO: some of these URLs may be too long and we may need to
+		# do something like code_footer() above, but these are local
+		# admin-defined
+		if (defined($max)) { # v2
+			for my $i (0..$max) {
+				# old epochs my be deleted:
+				-d "$ibx->{inboxdir}/git/$i.git" or next;
+				my $url = "$base_url/$i";
+				$seen{$url} = 1;
+				push @urls, "$url $dir/git/$i.git";
+			}
+			my $nr = scalar(@urls);
+			if ($nr > 1) {
+				$$txt .= "\n\t";
+				$$txt .= "# this inbox consists of $nr epochs:";
+				$urls[0] .= " # oldest";
+				$urls[-1] .= " # newest";
+			}
+		} else { # v1
+			push @urls, $base_url;
+		}
+		# FIXME: epoch splits can be different in other repositories,
+		# use the "cloneurl" file as-is for now:
+		for my $u (@{$ibx->cloneurl}) {
+			next if $seen{$u}++;
+			push @urls, $u;
+		}
+		$$txt .= "\n";
+		$$txt .= join('', map { "\tgit clone --mirror $_\n" } @urls);
+		if (my $addrs = $ibx->{address}) {
+			$addrs = join(' ', @$addrs) if ref($addrs) eq 'ARRAY';
+			my $v = defined $max ? '-V2' : '-V1';
+			$$txt .= <<EOF;
+
+	# If you have public-inbox 1.1+ installed, you may
+	# initialize and index your mirror using the following commands:
+	public-inbox-init $v $ibx->{name} $dir/ $base_url \\
+		$addrs
+	public-inbox-index $dir
+EOF
+		}
+	} else { # PublicInbox::ExtSearch
+		$$txt .= <<EOM;
+This is an extindex which is an amalgamation of several public-inboxes.
+Each public-inbox needs to be mirrored individually.
+EOM
+		my $v = $ctx->{www}->{pi_cfg}->{lc('publicInbox.wwwListing')};
+		if (($v // '') =~ /\A(?:all|match=domain)\z/) {
+			$$txt .= <<EOM;
+A list of them is available at $top_url
+EOM
+		}
+	}
+	my $cfg_link = "$base_url/_/text/config/raw";
+	$$txt .= <<EOF;
+
+Example config snippet for mirrors: $cfg_link
+EOF
+	if ($ibx->can('nntp_url')) {
+		my $nntp = $ibx->nntp_url;
+		if (scalar @$nntp) {
+			$$txt .= "\n";
+			$$txt .= @$nntp == 1 ? 'Newsgroup' : 'Newsgroups are';
+			$$txt .= ' available over NNTP:';
+			$$txt .= "\n\t" . join("\n\t", @$nntp) . "\n";
+		}
+	}
+	if ($$txt =~ m!\b[^:]+://\w+\.onion/!) {
+		$$txt .= <<EOM
+
+note: .onion URLs require Tor: https://www.torproject.org/
+
+EOM
+	}
+	my $code_url = prurl($ctx->{env}, $PublicInbox::WwwStream::CODE_URL);
+	$$txt .= join("\n\n",
+		coderepos_raw($ctx, $top_url), # may be empty
+		"AGPL code for this site:\n\tgit clone $code_url");
+	1;
+}
+
 sub _default_text ($$$$) {
 	my ($ctx, $key, $hdr, $txt) = @_;
-	return _colors_help($ctx, $txt) if $key eq 'color';
-	$key eq 'config' and return $ctx->{ibx}->can('cloneurl') ?
+	if ($key eq 'mirror') {
+		return _mirror_help($ctx, $txt);
+	} elsif ($key eq 'color') {
+		return _colors_help($ctx, $txt);
+	} elsif ($key eq 'config') {
+		return $ctx->{ibx}->can('cloneurl') ?
 			inbox_config($ctx, $hdr, $txt) :
 			extindex_config($ctx, $hdr, $txt);
+	}
+
 	return if $key ne 'help'; # TODO more keys?
 
 	my $ibx = $ctx->{ibx};
diff --git a/t/psgi_mount.t b/t/psgi_mount.t
index e9547c15..7c5487f3 100644
--- a/t/psgi_mount.t
+++ b/t/psgi_mount.t
@@ -48,14 +48,9 @@ test_psgi($app, sub {
 	unlike($res->content, qr!\b\Qhttp://[^/]+/test/\E!,
 		'No URLs which are not mount-aware');
 
-	$res = $cb->(GET('/a/test/new.html'));
-	like($res->content, qr!git clone --mirror http://[^/]+/a/test\b!,
-		'clone URL in new.html is mount-aware');
-
-	$res = $cb->(GET('/a/test/blah%40example.com/'));
-	is($res->code, 200, 'OK with URLMap mount');
-	like($res->content, qr!git clone --mirror http://[^/]+/a/test\b!,
-		'clone URL in /$INBOX/$MESSAGE_ID/ is mount-aware');
+	$res = $cb->(GET('/a/test/_/text/mirror/'));
+	like($res->content, qr!git clone --mirror\s+.*?http://[^/]+/a/test\b!s,
+		'clone URL in /text/mirror is mount-aware');
 
 	$res = $cb->(GET('/a/test/blah%40example.com/raw'));
 	is($res->code, 200, 'OK with URLMap mount');

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 2/2] www_stream: description header links to top $INBOX_URL
  2021-08-28 11:50     ` [PATCH 0/2] www: split out mirror to /text/ Eric Wong
  2021-08-28 11:50       ` [PATCH 1/2] www: move mirror instructions " Eric Wong
@ 2021-08-28 11:50       ` Eric Wong
  2021-08-28 17:58       ` [PATCH 0/2] www: split out mirror to /text/ Konstantin Ryabitsev
  2 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-28 11:50 UTC (permalink / raw)
  To: meta

Making the inbox description link back to the most recent
per-inbox topics from text/ and $OID/s/ URLs seems useful,
rather than keeping the description up there.

Followup-to: 6c853f5256f3a324 ("www: improve navigation around contemporary threads")
---
 lib/PublicInbox/WwwStream.pm | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm
index c960edc5..472316c2 100644
--- a/lib/PublicInbox/WwwStream.pm
+++ b/lib/PublicInbox/WwwStream.pm
@@ -49,6 +49,8 @@ sub html_top ($) {
 	# we had some kind of query, link to /$INBOX/?t=YYYYMMDDhhmmss
 	} elsif ($ctx->{qp}->{t}) {
 		$top = qq(<a\nhref="./">$top</a>);
+	} elsif (length($upfx)) {
+		$top = qq(<a\nhref="$upfx">$top</a>);
 	}
 	my $code = $ibx->{coderepo} ? qq( / <a\nhref=#code>code</a>) : '';
 	# id=mirror must exist for legacy bookmarks

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 0/2] www: split out mirror to /text/
  2021-08-28 11:50     ` [PATCH 0/2] www: split out mirror to /text/ Eric Wong
  2021-08-28 11:50       ` [PATCH 1/2] www: move mirror instructions " Eric Wong
  2021-08-28 11:50       ` [PATCH 2/2] www_stream: description header links to top $INBOX_URL Eric Wong
@ 2021-08-28 17:58       ` Konstantin Ryabitsev
  2021-08-30 23:44         ` [PATCH 0/3] www: more footer and mirroring instructions tweaks Eric Wong
  2 siblings, 1 reply; 21+ messages in thread
From: Konstantin Ryabitsev @ 2021-08-28 17:58 UTC (permalink / raw)
  To: Eric Wong; +Cc: meta

On Sat, Aug 28, 2021 at 11:50:05AM +0000, Eric Wong wrote:
> Maybe this works better?  *shrug*
> 
> I was somewhat under the impression every page needed to
> link/advertise code under the AGPL, but maybe just one HTML page
> is fine...  We can't advertise our AGPL code to NNTP/IMAP users,
> nor to people using Atom feed readers.

I think this looks great, Eric. You went a bit further than I suggested,
though -- I do think you should keep the following at each page bottom:

<hr>
<a href="../../_/text/mirror/">Get full contents and AGPL source for this site.</a>

Or some similar wording. I do think something like that belongs on each view
just to stress that everything about the site is fully available for
replication.

-K

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 0/3] www: more footer and mirroring instructions tweaks
  2021-08-28 17:58       ` [PATCH 0/2] www: split out mirror to /text/ Konstantin Ryabitsev
@ 2021-08-30 23:44         ` Eric Wong
  2021-08-30 23:44           ` [PATCH 1/3] www_stream: extra link to mirroring information in the footer Eric Wong
                             ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-30 23:44 UTC (permalink / raw)
  To: meta; +Cc: Konstantin Ryabitsev

Some of the wording may still need tweaking, I'm preferring to
favor the data aspect over the code aspect of mirroring since
AGPL probably scares some people.

Not really sure about 3/3 or if including instructions to
grokmirror is out-of-scope for this project.

Eric Wong (3):
  www_stream: extra link to mirroring information in the footer
  www_text/mirror: spell out "external index" and "public inbox"
  www_listing: add note about mirroring information

 lib/PublicInbox/WwwListing.pm |  5 ++++-
 lib/PublicInbox/WwwStream.pm  | 24 +++++++++++++++++++-----
 lib/PublicInbox/WwwText.pm    | 15 ++++++++++-----
 3 files changed, 33 insertions(+), 11 deletions(-)

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/3] www_stream: extra link to mirroring information in the footer
  2021-08-30 23:44         ` [PATCH 0/3] www: more footer and mirroring instructions tweaks Eric Wong
@ 2021-08-30 23:44           ` Eric Wong
  2021-08-30 23:44           ` [PATCH 2/3] www_text/mirror: spell out "external index" and "public inbox" Eric Wong
  2021-08-30 23:44           ` [PATCH 3/3] www_listing: add note about mirroring information Eric Wong
  2 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-30 23:44 UTC (permalink / raw)
  To: meta; +Cc: Konstantin Ryabitsev

This may be redundant with the "mirror" link at the top right,
but maybe people will miss one.  Properly capitalize the
"Code repositories" text while we're at it.

Link: https://public-inbox.org/20210828175827.rgzwqbn7brl56oej@nitro.local/
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
---
 lib/PublicInbox/WwwStream.pm | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm
index 472316c2..a88ff972 100644
--- a/lib/PublicInbox/WwwStream.pm
+++ b/lib/PublicInbox/WwwStream.pm
@@ -89,7 +89,7 @@ sub coderepos ($) {
 	my @ret;
 	for my $cr_name (@$cr) {
 		$ret[0] //= <<EOF;
-<a id=code>code repositories for project(s) associated with this inbox:
+<a id=code>Code repositories for project(s) associated with this inbox:
 EOF
 		my $urls = $cfg->get_all("coderepo.$cr_name.cgiturl");
 		if ($urls) {
@@ -109,10 +109,24 @@ EOF
 
 sub _html_end {
 	my ($ctx) = @_;
-	my @cr = coderepos($ctx);
-	scalar(@cr) ?
-		'<hr><pre>'.join("\n\n", @cr).'</pre></body></html>' :
-		'</body></html>';
+	my $upfx = $ctx->{-upfx} || '';
+	my $m = "${upfx}_/text/mirror/";
+	my $x;
+	if ($ctx->{ibx}->can('cloneurl')) {
+		$x = <<EOF;
+This is a public inbox, see <a
+href="$m">mirroring instructions</a>
+on how to clone and mirror all data and code used for this inbox
+EOF
+	} else {
+		$x = <<EOF;
+This is an external index of several public inboxes,
+see <a href="$m">mirroring instructions</a> on how to clone and mirror
+all data and code used by this external index.
+EOF
+	}
+	chomp $x;
+	'<hr><pre>'.join("\n\n", coderepos($ctx), $x).'</pre></body></html>'
 }
 
 # callback for HTTP.pm (and any other PSGI servers)

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 2/3] www_text/mirror: spell out "external index" and "public inbox"
  2021-08-30 23:44         ` [PATCH 0/3] www: more footer and mirroring instructions tweaks Eric Wong
  2021-08-30 23:44           ` [PATCH 1/3] www_stream: extra link to mirroring information in the footer Eric Wong
@ 2021-08-30 23:44           ` Eric Wong
  2021-08-30 23:44           ` [PATCH 3/3] www_listing: add note about mirroring information Eric Wong
  2 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-30 23:44 UTC (permalink / raw)
  To: meta

"extindex" and "public-inbox" are project-specific terms which
are probably unsuitable for folks who are seeing this for the
first time.

Use "public inbox" when referring to actual public inboxes,
since "public-inbox" is merely the name for this particular
implementation and others have adopted the same concept (IMHO
the concept is more important than any particular
implementation).
---
 lib/PublicInbox/WwwText.pm | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/lib/PublicInbox/WwwText.pm b/lib/PublicInbox/WwwText.pm
index 858fc2f7..fabe39f6 100644
--- a/lib/PublicInbox/WwwText.pm
+++ b/lib/PublicInbox/WwwText.pm
@@ -246,9 +246,13 @@ sub coderepos_raw ($$) {
 	my $cfg = $ctx->{www}->{pi_cfg};
 	my @ret;
 	for my $cr_name (@$cr) {
-		$ret[0] //= <<EOF;
-code repositories for project(s) associated with this inbox:
+		$ret[0] //= do {
+			my $thing = $ctx->{ibx}->can('cloneurl') ?
+				'public inbox' : 'external index';
+			<<EOF;
+Code repositories for project(s) associated with this $thing
 EOF
+		};
 		my $urls = $cfg->get_all("coderepo.$cr_name.cgiturl");
 		if ($urls) {
 			for (@$urls) {
@@ -276,7 +280,8 @@ sub _mirror_help ($$) {
 	$top_url =~ s!/[^/]+\z!/!;
 	$$txt .= "public-inbox mirroring instructions\n\n";
 	if ($ibx->can('cloneurl')) { # PublicInbox::Inbox
-		$$txt .= "This inbox may be cloned and mirrored by anyone:\n";
+		$$txt .=
+		  "This public inbox may be cloned and mirrored by anyone:\n";
 		my @urls;
 		my $max = $ibx->max_git_epoch;
 		# TODO: some of these URLs may be too long and we may need to
@@ -322,8 +327,8 @@ EOF
 		}
 	} else { # PublicInbox::ExtSearch
 		$$txt .= <<EOM;
-This is an extindex which is an amalgamation of several public-inboxes.
-Each public-inbox needs to be mirrored individually.
+This is an external index which is an amalgamation of several public inboxes.
+Each public inbox needs to be mirrored individually.
 EOM
 		my $v = $ctx->{www}->{pi_cfg}->{lc('publicInbox.wwwListing')};
 		if (($v // '') =~ /\A(?:all|match=domain)\z/) {

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 3/3] www_listing: add note about mirroring information
  2021-08-30 23:44         ` [PATCH 0/3] www: more footer and mirroring instructions tweaks Eric Wong
  2021-08-30 23:44           ` [PATCH 1/3] www_stream: extra link to mirroring information in the footer Eric Wong
  2021-08-30 23:44           ` [PATCH 2/3] www_text/mirror: spell out "external index" and "public inbox" Eric Wong
@ 2021-08-30 23:44           ` Eric Wong
  2 siblings, 0 replies; 21+ messages in thread
From: Eric Wong @ 2021-08-30 23:44 UTC (permalink / raw)
  To: meta

Perhaps this can be expanded to include grokmirror information
in the future.  For now, just give a hint about the "mirror"
link for each inbox.
---
 lib/PublicInbox/WwwListing.pm | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/PublicInbox/WwwListing.pm b/lib/PublicInbox/WwwListing.pm
index c3779619..a9290802 100644
--- a/lib/PublicInbox/WwwListing.pm
+++ b/lib/PublicInbox/WwwListing.pm
@@ -226,7 +226,10 @@ sub psgi_triple {
 	} else {
 		$gzf->zmore('<pre>no inboxes, yet');
 	}
-	my $out = $gzf->zflush('</pre></body></html>');
+	my $out = $gzf->zflush('</pre><hr><pre>'.
+qq(This is a listing of public inboxes, see the `mirror' link of each inbox
+for instructions on how to mirror all the data and code on this site.) .
+			'</pre></body></html>');
 	$h->[3] = length($out);
 	[ $code, $h, [ $out ] ];
 }

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2021-08-30 23:44 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-16 16:36 RFE: Long .onion URL breaks mobile view Konstantin Ryabitsev
2021-08-16 22:38 ` Eric Wong
2021-08-16 22:53   ` Eric Wong
2021-08-26 12:33 ` [PATCH 0/8] various WWW + extindex stuff Eric Wong
2021-08-26 12:33   ` [PATCH 1/8] get rid of unnecessary bytes::length usage Eric Wong
2021-08-26 12:33   ` [PATCH 2/8] ds: use bytes::substr and bytes::length module-wide for now Eric Wong
2021-08-26 12:33   ` [PATCH 3/8] www_stream: sh-friendly .onion URLs wrapping Eric Wong
2021-08-26 12:33   ` [PATCH 4/8] www: avoid incorrect instructions for extindex Eric Wong
2021-08-26 12:33   ` [PATCH 5/8] www_text: fix example config snippet " Eric Wong
2021-08-26 12:33   ` [PATCH 6/8] config: do not parse altid " Eric Wong
2021-08-26 12:33   ` [PATCH 7/8] www_text: add coderepo config support " Eric Wong
2021-08-26 12:33   ` [PATCH 8/8] move ->ids_after from mm to over Eric Wong
2021-08-26 13:27   ` [PATCH 0/8] various WWW + extindex stuff Konstantin Ryabitsev
2021-08-28 11:50     ` [PATCH 0/2] www: split out mirror to /text/ Eric Wong
2021-08-28 11:50       ` [PATCH 1/2] www: move mirror instructions " Eric Wong
2021-08-28 11:50       ` [PATCH 2/2] www_stream: description header links to top $INBOX_URL Eric Wong
2021-08-28 17:58       ` [PATCH 0/2] www: split out mirror to /text/ Konstantin Ryabitsev
2021-08-30 23:44         ` [PATCH 0/3] www: more footer and mirroring instructions tweaks Eric Wong
2021-08-30 23:44           ` [PATCH 1/3] www_stream: extra link to mirroring information in the footer Eric Wong
2021-08-30 23:44           ` [PATCH 2/3] www_text/mirror: spell out "external index" and "public inbox" Eric Wong
2021-08-30 23:44           ` [PATCH 3/3] www_listing: add note about mirroring information Eric Wong

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 NNTP newsgroup(s).