}
my @c_opt = qw(c=s@ C=s@ quiet|q);
+my @lxs_opt = (qw(remote! local! external! include|I=s@ exclude=s@ only=s@
+ import-remote! no-torsocks torsocks=s),
+ PublicInbox::LeiQuery::curl_opt());
# we generate shell completion + help using %CMD and %OPTDESC,
# see lei__complete() and PublicInbox::LeiHelp
our %CMD = ( # sorted in order of importance/use:
'q' => [ '--stdin|SEARCH_TERMS...', 'search for messages matching terms',
'stdin|', # /|\z/ must be first for lone dash
+ @lxs_opt,
qw(save-as=s output|mfolder|o=s format|f=s dedupe|d=s threads|t+
- sort|s=s reverse|r offset=i remote! local! external! pretty
- include|I=s@ exclude=s@ only=s@ jobs|j=s globoff|g augment|a
- import-remote! import-before! lock=s@ rsyncable
- alert=s@ mua=s no-torsocks torsocks=s verbose|v+), @c_opt,
- PublicInbox::LeiQuery::curl_opt(), opt_dash('limit|n=i', '[0-9]+') ],
+ sort|s=s reverse|r offset=i pretty jobs|j=s globoff|g augment|a
+ import-before! lock=s@ rsyncable alert=s@ mua=s verbose|v+), @c_opt,
+ opt_dash('limit|n=i', '[0-9]+') ],
-'show' => [ 'MID|OID', 'show a given object (Message-ID or object ID)',
- qw(type=s solve! format|f=s dedupe|d=s threads|t remote local!
- verbose|v+), @c_opt, pass_through('git show') ],
+'blob' => [ 'OID', 'display a git blob object, solving if necessary',
+ qw(git-dir=s@ cwd! verbose|v+ oid-a|A=s path-a|a=s path-b|b=s),
+ @lxs_opt, @c_opt ],
'add-external' => [ 'LOCATION',
'add/set priority of a publicinbox|extindex for extra matches',
'leistore.dir' => 'top-level storage location',
);
-my @WQ_KEYS = qw(lxs l2m imp mrr cnv p2q mark); # internal workers
+my @WQ_KEYS = qw(lxs l2m imp mrr cnv p2q mark sol); # internal workers
# pronounced "exit": x_it(1 << 8) => exit(1); x_it(13) => SIGPIPE
sub x_it ($$) {
}
} else { # worker, Net::NNTP (Net::Cmd) uses STDERR directly
open STDERR, '+>&='.fileno($self->{2}) or warn "open $!";
- delete $self->{0};
}
for (delete @$self{qw(3 old_1 au_done)}) {
close($_) if defined($_);
}
sub pkt_op_pair {
- my ($self, $ops) = @_;
+ my ($self) = @_;
require PublicInbox::OnDestroy;
require PublicInbox::PktOp;
my $end = PublicInbox::OnDestroy->new($$, \&_delete_pkt_op, $self);
- @$self{qw(pkt_op_c pkt_op_p)} = PublicInbox::PktOp->pair($ops);
+ @$self{qw(pkt_op_c pkt_op_p)} = PublicInbox::PktOp->pair;
$end;
}
($ops ? %$ops : ()),
};
$ops->{''} //= [ \&dclose, $lei ];
- my $end = $lei->pkt_op_pair($ops);
+ my $end = $lei->pkt_op_pair;
$wq->wq_workers_start($ident, $jobs, $lei->oldset, { lei => $lei });
delete $lei->{pkt_op_p};
- my $op = delete $lei->{pkt_op_c};
+ my $op_c = delete $lei->{pkt_op_c};
@$end = ();
$lei->event_step_init;
- # oneshot needs $op, daemon-mode uses DS->EventLoop to handle $op
- $lei->{oneshot} ? $op : undef;
+ ($op_c, $ops);
}
sub _help {
};
}
-sub lei_show {
- my ($self, @argv) = @_;
-}
-
sub _config {
my ($self, @argv) = @_;
my %env = (%{$self->{env}}, GIT_CONFIG => undef);
x_it($self, $?) if $?;
}
-sub lei_init {
- my ($self, $dir) = @_;
- my $cfg = _lei_cfg($self, 1);
- my $cur = $cfg->{'leistore.dir'};
- $dir //= store_path($self);
- $dir = rel2abs($self, $dir);
- my @cur = stat($cur) if defined($cur);
- $cur = File::Spec->canonpath($cur // $dir);
- my @dir = stat($dir);
- my $exists = "# leistore.dir=$cur already initialized" if @dir;
- if (@cur) {
- if ($cur eq $dir) {
- _lei_store($self, 1)->done;
- return qerr($self, $exists);
- }
-
- # some folks like symlinks and bind mounts :P
- if (@dir && "@cur[1,0]" eq "@dir[1,0]") {
- lei_config($self, 'leistore.dir', $dir);
- _lei_store($self, 1)->done;
- return qerr($self, "$exists (as $cur)");
- }
- return fail($self, <<"");
-E: leistore.dir=$cur already initialized and it is not $dir
-
- }
- lei_config($self, 'leistore.dir', $dir);
- _lei_store($self, 1)->done;
- $exists //= "# leistore.dir=$dir newly initialized";
- return qerr($self, $exists);
-}
-
sub lei_daemon_pid { puts shift, $$ }
sub lei_daemon_kill {
kill($sig, $$) or fail($self, "kill($sig, $$): $!");
}
-sub lei_help { _help($_[0]) }
-
# Shell completion helper. Used by lei-completion.bash and hopefully
# other shells. Try to do as much here as possible to avoid redundancy
# and improve maintainability.
}
my %path_to_fd = ('/dev/stdin' => 0, '/dev/stdout' => 1, '/dev/stderr' => 2);
-$path_to_fd{"/dev/fd/$_"} = $path_to_fd{"/proc/self/fd/$_"} for (0..2);
-sub fopen {
- my ($self, $mode, $path) = @_;
- rel2abs($self, $path);
+$path_to_fd{"/dev/fd/$_"} = $_ for (0..2);
+
+# this also normalizes the path
+sub path_to_fd {
+ my ($self, $path) = @_;
+ $path = rel2abs($self, $path);
$path =~ tr!/!/!s;
- if (defined(my $fd = $path_to_fd{$path})) {
- return $self->{$fd};
- }
- if ($path =~ m!\A/(?:dev|proc/self)/fd/[0-9]+\z!) {
- return fail($self, "cannot open $path from daemon");
- }
- open my $fh, $mode, $path or return;
- $fh;
+ $path_to_fd{$path} // (
+ ($path =~ m!\A/(?:dev|proc/self)/fd/[0-9]+\z!) ?
+ fail($self, "cannot open $path from daemon") : -1
+ );
}
# caller needs to "-t $self->{1}" to check if tty
}
}
close(delete $self->{1}) if $self->{1}; # may reap_compress
- if (my $sto = delete $self->{sto}) {
- $sto->ipc_do('done');
- }
$self->close if $self->{-event_init_done}; # PublicInbox::DS::close
}