From 984c21dda421c4d2c104d72e4954e8ee44a815f3 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 31 Jan 2017 22:55:58 +0000 Subject: search: hoist out git directory search index helper We will be reusing this for indexing normal (code) repositories using git and Xapian, too. --- MANIFEST | 2 ++ lib/PublicInbox/GitIdx.pm | 67 ++++++++++++++++++++++++++++++++++++++++ lib/PublicInbox/SearchIdx.pm | 73 +++----------------------------------------- t/git_idx.t | 24 +++++++++++++++ t/search.t | 25 --------------- 5 files changed, 98 insertions(+), 93 deletions(-) create mode 100644 lib/PublicInbox/GitIdx.pm create mode 100644 t/git_idx.t diff --git a/MANIFEST b/MANIFEST index 29b98e90..9e4e7cab 100644 --- a/MANIFEST +++ b/MANIFEST @@ -58,6 +58,7 @@ lib/PublicInbox/Git.pm lib/PublicInbox/GitAsync.pm lib/PublicInbox/GitAsyncWr.pm lib/PublicInbox/GitHTTPBackend.pm +lib/PublicInbox/GitIdx.pm lib/PublicInbox/HTTP.pm lib/PublicInbox/HTTPD.pm lib/PublicInbox/HTTPD/Async.pm @@ -154,6 +155,7 @@ t/git-http-backend.t t/git.fast-import-data t/git.t t/git_async.t +t/git_idx.t t/html_index.t t/httpd-corner.psgi t/httpd-corner.t diff --git a/lib/PublicInbox/GitIdx.pm b/lib/PublicInbox/GitIdx.pm new file mode 100644 index 00000000..919672a9 --- /dev/null +++ b/lib/PublicInbox/GitIdx.pm @@ -0,0 +1,67 @@ +# Copyright (C) 2017 all contributors +# License: AGPL-3.0+ +package PublicInbox::GitIdx; +use strict; +use warnings; +use base qw(Exporter); +our @EXPORT = qw(git_umask_for with_umask); +use PublicInbox::Git; +use constant { + PERM_UMASK => 0, + OLD_PERM_GROUP => 1, + OLD_PERM_EVERYBODY => 2, + PERM_GROUP => 0660, + PERM_EVERYBODY => 0664, +}; + +sub _git_config_perm ($) { + my ($git) = @_; + my @cmd = qw(config core.sharedRepository); + $git = PublicInbox::Git->new($git) unless ref $git; + my $perm = $git->qx(@cmd); + chomp $perm if defined $perm; + return PERM_GROUP if (!defined($perm) || $perm eq ''); + return PERM_UMASK if ($perm eq 'umask'); + return PERM_GROUP if ($perm eq 'group'); + if ($perm =~ /\A(?:all|world|everybody)\z/) { + return PERM_EVERYBODY; + } + return PERM_GROUP if ($perm =~ /\A(?:true|yes|on|1)\z/); + return PERM_UMASK if ($perm =~ /\A(?:false|no|off|0)\z/); + + my $i = oct($perm); + return PERM_UMASK if ($i == PERM_UMASK); + return PERM_GROUP if ($i == OLD_PERM_GROUP); + return PERM_EVERYBODY if ($i == OLD_PERM_EVERYBODY); + + if (($i & 0600) != 0600) { + die "core.sharedRepository mode invalid: ". + sprintf('%.3o', $i) . "\nOwner must have permissions\n"; + } + ($i & 0666); +} + +sub git_umask_for ($) { + my ($git) = @_; + my $perm = _git_config_perm($git); + my $rv = $perm; + return umask if $rv == 0; + + # set +x bit if +r or +w were set + $rv |= 0100 if ($rv & 0600); + $rv |= 0010 if ($rv & 0060); + $rv |= 0001 if ($rv & 0006); + (~$rv & 0777); +} + +sub with_umask ($$) { + my ($umask, $cb) = @_; + my $old = umask $umask; + my $rv = eval { $cb->() }; + my $err = $@; + umask $old; + die $err if $@; + $rv; +} + +1; diff --git a/lib/PublicInbox/SearchIdx.pm b/lib/PublicInbox/SearchIdx.pm index 87ee0d46..5adc17d3 100644 --- a/lib/PublicInbox/SearchIdx.pm +++ b/lib/PublicInbox/SearchIdx.pm @@ -16,19 +16,13 @@ $Email::MIME::ContentType::STRICT_PARAMS = 0; use base qw(PublicInbox::Search); use PublicInbox::MID qw/mid_clean id_compress mid_mime/; use PublicInbox::MsgIter; +use PublicInbox::GitIdx; use Carp qw(croak); use POSIX qw(strftime); require PublicInbox::Git; *xpfx = *PublicInbox::Search::xpfx; use constant MAX_MID_SIZE => 244; # max term size - 1 in Xapian -use constant { - PERM_UMASK => 0, - OLD_PERM_GROUP => 1, - OLD_PERM_EVERYBODY => 2, - PERM_GROUP => 0660, - PERM_EVERYBODY => 0664, -}; sub new { my ($class, $inbox, $creat) = @_; @@ -46,11 +40,10 @@ sub new { } require Search::Xapian::WritableDatabase; my $self = bless { git_dir => $git_dir, -altid => $altid }, $class; - my $perm = $self->_git_config_perm; - my $umask = _umask_for($perm); - $self->{umask} = $umask; + my $git = $self->{git} = PublicInbox::Git->new($git_dir); + my $umask = git_umask_for($git); + $self->{'umask'} = $umask; $self->{lock_path} = "$git_dir/ssoma.lock"; - $self->{git} = PublicInbox::Git->new($git_dir); $self->{creat} = ($creat || 0) == 1; $self; } @@ -407,7 +400,7 @@ sub do_cat_mail { sub index_sync { my ($self, $opts) = @_; - with_umask($self, sub { $self->_index_sync($opts) }); + with_umask($self->{'umask'}, sub { $self->_index_sync($opts) }); } sub rlog { @@ -582,62 +575,6 @@ sub merge_threads { } } -sub _read_git_config_perm { - my ($self) = @_; - my @cmd = qw(config core.sharedRepository); - my $fh = PublicInbox::Git->new($self->{git_dir})->popen(@cmd); - local $/ = "\n"; - my $perm = <$fh>; - chomp $perm if defined $perm; - $perm; -} - -sub _git_config_perm { - my $self = shift; - my $perm = scalar @_ ? $_[0] : _read_git_config_perm($self); - return PERM_GROUP if (!defined($perm) || $perm eq ''); - return PERM_UMASK if ($perm eq 'umask'); - return PERM_GROUP if ($perm eq 'group'); - if ($perm =~ /\A(?:all|world|everybody)\z/) { - return PERM_EVERYBODY; - } - return PERM_GROUP if ($perm =~ /\A(?:true|yes|on|1)\z/); - return PERM_UMASK if ($perm =~ /\A(?:false|no|off|0)\z/); - - my $i = oct($perm); - return PERM_UMASK if ($i == PERM_UMASK); - return PERM_GROUP if ($i == OLD_PERM_GROUP); - return PERM_EVERYBODY if ($i == OLD_PERM_EVERYBODY); - - if (($i & 0600) != 0600) { - die "core.sharedRepository mode invalid: ". - sprintf('%.3o', $i) . "\nOwner must have permissions\n"; - } - ($i & 0666); -} - -sub _umask_for { - my ($perm) = @_; # _git_config_perm return value - my $rv = $perm; - return umask if $rv == 0; - - # set +x bit if +r or +w were set - $rv |= 0100 if ($rv & 0600); - $rv |= 0010 if ($rv & 0060); - $rv |= 0001 if ($rv & 0006); - (~$rv & 0777); -} - -sub with_umask { - my ($self, $cb) = @_; - my $old = umask $self->{umask}; - my $rv = eval { $cb->() }; - my $err = $@; - umask $old; - die $err if $@; - $rv; -} - sub DESTROY { # order matters for unlocking $_[0]->{xdb} = undef; diff --git a/t/git_idx.t b/t/git_idx.t new file mode 100644 index 00000000..65667cfc --- /dev/null +++ b/t/git_idx.t @@ -0,0 +1,24 @@ +# Copyright (C) 2015 all contributors +# License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt) +use strict; +use warnings; +use Test::More; +use File::Temp qw/tempdir/; +use Email::MIME; +my $tmpdir = tempdir('pi-git-idx-XXXXXX', TMPDIR => 1, CLEANUP => 1); +my $git_dir = "$tmpdir/a.git"; +use_ok 'PublicInbox::Git'; +use_ok 'PublicInbox::GitIdx'; +my $git = PublicInbox::Git->new($git_dir); +is(0, system(qw(git init -q --bare), $git_dir), "git init (main)"); + +$git->qx(qw(config core.sharedRepository 0644)); +is(git_umask_for($git_dir), oct '022', 'umask is correct for 644'); + +$git->qx(qw(config core.sharedRepository 0664)); +is(git_umask_for($git_dir), oct '002', 'umask is correct for 664'); + +$git->qx(qw(config core.sharedRepository group)); +is(git_umask_for($git_dir), oct '007', 'umask is correct for "group"'); + +done_testing(); diff --git a/t/search.t b/t/search.t index c9c4e346..2e29b827 100644 --- a/t/search.t +++ b/t/search.t @@ -26,31 +26,6 @@ my $rw_commit = sub { $rw->_xdb_acquire->begin_transaction; }; -{ - # git repository perms - is(PublicInbox::SearchIdx->_git_config_perm(undef), - &PublicInbox::SearchIdx::PERM_GROUP, - "undefined permission is group"); - is(PublicInbox::SearchIdx::_umask_for( - PublicInbox::SearchIdx->_git_config_perm('0644')), - 0022, "644 => umask(0022)"); - is(PublicInbox::SearchIdx::_umask_for( - PublicInbox::SearchIdx->_git_config_perm('0600')), - 0077, "600 => umask(0077)"); - is(PublicInbox::SearchIdx::_umask_for( - PublicInbox::SearchIdx->_git_config_perm('0640')), - 0027, "640 => umask(0027)"); - is(PublicInbox::SearchIdx::_umask_for( - PublicInbox::SearchIdx->_git_config_perm('group')), - 0007, 'group => umask(0007)'); - is(PublicInbox::SearchIdx::_umask_for( - PublicInbox::SearchIdx->_git_config_perm('everybody')), - 0002, 'everybody => umask(0002)'); - is(PublicInbox::SearchIdx::_umask_for( - PublicInbox::SearchIdx->_git_config_perm('umask')), - umask, 'umask => existing umask'); -} - { my $root = Email::MIME->create( header_str => [ -- cgit v1.2.3-24-ge0c7