user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
blob ca214ca19230c149b1b5b49833cd6283bf8e5e59 5653 bytes (raw)
name: lib/PublicInbox/LeiQuery.pm 	 # note: path name is non-authoritative(*)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
 
# Copyright (C) 2021 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>

# handles lei <q|ls-query|rm-query|mv-query> commands
package PublicInbox::LeiQuery;
use strict;
use v5.10.1;
use PublicInbox::DS qw(dwaitpid);

sub prep_ext { # externals_each callback
	my ($lxs, $exclude, $loc) = @_;
	$lxs->prepare_external($loc) unless $exclude->{$loc};
}

# the main "lei q SEARCH_TERMS" method
sub lei_q {
	my ($self, @argv) = @_;
	require PublicInbox::LeiXSearch;
	require PublicInbox::LeiOverview;
	PublicInbox::Config->json; # preload before forking
	my $opt = $self->{opt};
	# prepare any number of LeiXSearch || LeiSearch || Inbox || URL
	my $lxs = $self->{lxs} = PublicInbox::LeiXSearch->new;
	my @only = @{$opt->{only} // []};
	# --local is enabled by default unless --only is used
	# we'll allow "--only $LOCATION --local"
	if ($opt->{'local'} //= scalar(@only) ? 0 : 1) {
		my $sto = $self->_lei_store(1);
		$lxs->prepare_external($sto->search);
	}
	if (@only) {
		for my $loc (@only) {
			$lxs->prepare_external($self->ext_canonicalize($loc));
		}
	} else {
		for my $loc (@{$opt->{include} // []}) {
			$lxs->prepare_external($self->ext_canonicalize($loc));
		}
		# --external is enabled by default, but allow --no-external
		if ($opt->{external} //= 1) {
			my %x = map {;
				($self->ext_canonicalize($_), 1)
			} @{$self->{exclude} // []};
			my $ne = $self->externals_each(\&prep_ext, $lxs, \%x);
			$opt->{remote} //= !($lxs->locals - $opt->{'local'});
			if ($opt->{'local'}) {
				delete($lxs->{remotes}) if !$opt->{remote};
			} else {
				delete($lxs->{locals});
			}
		}
	}
	unless ($lxs->locals || $lxs->remotes) {
		return $self->fail('no local or remote inboxes to search');
	}
	my $xj = $lxs->concurrency($opt);
	PublicInbox::LeiOverview->new($self) or return;
	$self->atfork_prepare_wq($lxs);
	$lxs->wq_workers_start('lei_xsearch', $xj, $self->oldset);
	delete $lxs->{-ipc_atfork_child_close};
	if (my $l2m = $self->{l2m}) {
		my $mj = 4; # TODO: configurable
		$self->atfork_prepare_wq($l2m);
		$l2m->wq_workers_start('lei2mail', $mj, $self->oldset);
		delete $l2m->{-ipc_atfork_child_close};
	}

	# no forking workers after this

	my %mset_opt = map { $_ => $opt->{$_} } qw(thread limit offset);
	$mset_opt{asc} = $opt->{'reverse'} ? 1 : 0;
	$mset_opt{limit} //= 10000;
	$mset_opt{qstr} = join(' ', map {;
		# Consider spaces in argv to be for phrase search in Xapian.
		# In other words, the users should need only care about
		# normal shell quotes and not have to learn Xapian quoting.
		/\s/ ? (s/\A(\w+:)// ? qq{$1"$_"} : qq{"$_"}) : $_
	} @argv);
	if (defined(my $sort = $opt->{'sort'})) {
		if ($sort eq 'relevance') {
			$mset_opt{relevance} = 1;
		} elsif ($sort eq 'docid') {
			$mset_opt{relevance} = $mset_opt{asc} ? -1 : -2;
		} elsif ($sort =~ /\Areceived(?:-?[aA]t)?\z/) {
			# the default
		} else {
			die "unrecognized --sort=$sort\n";
		}
	}
	# descending docid order
	$mset_opt{relevance} //= -2 if $opt->{thread};
	$self->{mset_opt} = \%mset_opt;
	$self->{ovv}->ovv_begin($self);
	$lxs->do_query($self);
}

# shell completion helper called by lei__complete
sub _complete_q {
	my ($self, @argv) = @_;
	my $ext = qr/\A(?:-I|(?:--(?:include|exclude|only)))\z/;
	# $argv[-1] =~ $ext and return $self->_complete_forget_external;
	my @cur;
	while (@argv) {
		if ($argv[-1] =~ $ext) {
			my @c = $self->_complete_forget_external(@cur);
			return @c if @c;
		}
		unshift(@cur, pop @argv);
	}
	();
}

# Stuff we may pass through to curl (as of 7.64.0), see curl manpage for
# details, so most options which make sense for HTTP/HTTPS (including proxy
# support for Tor and other methods of getting past weird networks).
# Most of these are untested by us, some may not make sense for our use case
# and typos below are likely.
# n.b. some short options (-$NUMBER) are not supported since they conflict
# with other "lei q" switches.
# FIXME: Getopt::Long doesn't easily let us support support options with
# '.' in them (e.g. --http1.1)
sub curl_opt { qw(
	abstract-unix-socket=s anyauth basic cacert=s capath=s
	cert-status cert-type cert|E=s ciphers=s config|K=s@
	connect-timeout=s connect-to=s cookie-jar|c=s cookie|b=s crlfile=s
	digest disable dns-interface=s dns-ipv4-addr=s dns-ipv6-addr=s
	dns-servers=s doh-url=s egd-file=s engine=s false-start
	happy-eyeballs-timeout-ms=s haproxy-protocol header|H=s@
	http2-prior-knowledge http2 insecure|k
	interface=s ipv4 ipv6 junk-session-cookies
	key-type=s key=s limit-rate=s local-port=s location-trusted location|L
	max-redirs=i max-time=s negotiate netrc-file=s netrc-optional netrc
	no-alpn no-buffer|N no-npn no-sessionid noproxy=s ntlm-wb ntlm
	pass=s pinnedpubkey=s post301 post302 post303 preproxy=s
	proxy-anyauth proxy-basic proxy-cacert=s proxy-capath=s
	proxy-cert-type=s proxy-cert=s proxy-ciphers=s proxy-crlfile=s
	proxy-digest proxy-header=s@ proxy-insecure
	proxy-key-type=s proxy-key proxy-negotiate proxy-ntlm proxy-pass=s
	proxy-pinnedpubkey=s proxy-service-name=s proxy-ssl-allow-beast
	proxy-tls13-ciphers=s proxy-tlsauthtype=s proxy-tlspassword=s
	proxy-tlsuser=s proxy-tlsv1 proxy-user|U=s proxy=s
	proxytunnel=s pubkey=s random-file=s referer=s resolve=s
	retry-connrefused retry-delay=s retry-max-time=s retry=i
	sasl-ir service-name=s socks4=s socks4a=s socks5-basic
	socks5-gssapi-service-name=s socks5-gssapi socks5-hostname=s socks5=s
	speed-limit|Y speed-type|y ssl-allow-beast sslv2 sslv3
	suppress-connect-headers tcp-fastopen tls-max=s
	tls13-ciphers=s tlsauthtype=s tlspassword=s tlsuser=s
	tlsv1 trace-ascii=s trace-time trace=s
	unix-socket=s user-agent|A=s user|u=s
)
}

1;

debug log:

solving ca214ca1 ...
found ca214ca1 in https://80x24.org/public-inbox.git

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.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).