diff options
author | Eric Wong <e@80x24.org> | 2020-12-13 22:38:48 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2020-12-19 09:32:08 +0000 |
commit | 2755c6f839f0a0552cd134160e1691380511a61a (patch) | |
tree | a575ed8bcc44a238ca0a9517658d4d967c6300d6 /script | |
parent | 8f4253f567852ef56e3a484c9881d4f113e5dc89 (diff) | |
download | public-inbox-2755c6f839f0a0552cd134160e1691380511a61a.tar.gz |
The start of lei, a Local Email Interface. It'll support a daemon via FD passing to avoid startup time penalties if IO::FDPass is installed, but fall back to a slow one-shot mode if not. Compared to traditional socket daemon, FD passing should allow us to eventually do stuff like run "git show" and still have proper terminal support for pager and color.
Diffstat (limited to 'script')
-rwxr-xr-x | script/lei | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/script/lei b/script/lei new file mode 100755 index 00000000..1b5af3a1 --- /dev/null +++ b/script/lei @@ -0,0 +1,58 @@ +#!perl -w +# Copyright (C) 2020 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use v5.10.1; +use Cwd qw(cwd); +use IO::Socket::UNIX; + +if (eval { require IO::FDPass; 1 }) { # use daemon to reduce load time + my $path = do { + my $runtime_dir = ($ENV{XDG_RUNTIME_DIR} // '') . '/lei'; + if ($runtime_dir eq '/lei') { + require File::Spec; + $runtime_dir = File::Spec->tmpdir."/lei-$<"; + } + unless (-d $runtime_dir && -w _) { + require File::Path; + File::Path::mkpath($runtime_dir, 0, 0700); + } + "$runtime_dir/sock"; + }; + my $sock = IO::Socket::UNIX->new(Peer => $path, Type => SOCK_STREAM); + unless ($sock) { # start the daemon if not started + my $err = $!; + require PublicInbox::LeiDaemon; + $err = PublicInbox::LeiDaemon::lazy_start($path, $err); + # try connecting again anyways, unlink+bind may be racy + $sock = IO::Socket::UNIX->new(Peer => $path, + Type => SOCK_STREAM) // die + "connect($path): $! (bind($path): $err)"; + } + my $pwd = $ENV{PWD}; + my $cwd = cwd(); + if ($pwd) { # prefer ENV{PWD} if it's a symlink to real cwd + my @st_cwd = stat($cwd) or die "stat(cwd=$cwd): $!\n"; + my @st_pwd = stat($pwd); + # make sure st_dev/st_ino match for {PWD} to be valid + $pwd = $cwd if (!@st_pwd || $st_pwd[1] != $st_cwd[1] || + $st_pwd[0] != $st_cwd[0]); + } else { + $pwd = $cwd; + } + local $ENV{PWD} = $pwd; + $sock->autoflush(1); + IO::FDPass::send(fileno($sock), $_) for (0..2); + my $buf = "$$\0\0>" . join("]\0[", @ARGV) . "\0\0>"; + while (my ($k, $v) = each %ENV) { $buf .= "$k=$v\0" } + $buf .= "\0\0"; + print $sock $buf or die "print(sock, buf): $!"; + local $/ = "\n"; + while (my $line = <$sock>) { + $line =~ /\Aexit=([0-9]+)\n\z/ and exit($1 + 0); + die $line; + } +} else { # for systems lacking IO::FDPass + require PublicInbox::LeiDaemon; + PublicInbox::LeiDaemon::oneshot(); +} |