X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;ds=sidebyside;f=devel%2Fnmbug%2Fnmbug;h=b18ded7b7c1e48cf7b54a1e6901cb92c7cbf1961;hb=dd24fdd33a3c06b2c2ad6bcb8e7d18bc8442f51f;hp=fe103b3b7c5ac2794733e3cff3f2e2ffbb4901f4;hpb=16aa65ba2575fd504c31d9671d8c5150f8e8adf1;p=notmuch diff --git a/devel/nmbug/nmbug b/devel/nmbug/nmbug index fe103b3b..b18ded7b 100755 --- a/devel/nmbug/nmbug +++ b/devel/nmbug/nmbug @@ -13,10 +13,7 @@ my $NMBGIT = $ENV{NMBGIT} || $ENV{HOME}.'/.nmbug'; $NMBGIT .= '/.git' if (-d $NMBGIT.'/.git'); -my $TAGPREFIX = $ENV{NMBPREFIX} || 'notmuch::'; - -# magic hash for git -my $EMPTYBLOB = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'; +my $TAGPREFIX = defined($ENV{NMBPREFIX}) ? $ENV{NMBPREFIX} : 'notmuch::'; # for encoding @@ -29,6 +26,7 @@ my $ESCAPED_RX = qr{$ESCAPE_CHAR([A-Fa-f0-9]{2})}; my %command = ( archive => \&do_archive, checkout => \&do_checkout, + clone => \&do_clone, commit => \&do_commit, fetch => \&do_fetch, help => \&do_help, @@ -39,12 +37,20 @@ my %command = ( status => \&do_status, ); +# Convert prefix into form suitable for literal matching against +# notmuch dump --format=batch-tag output. +my $ENCPREFIX = encode_for_fs ($TAGPREFIX); +$ENCPREFIX =~ s/:/%3a/g; + my $subcommand = shift || usage (); if (!exists $command{$subcommand}) { usage (); } +# magic hash for git +my $EMPTYBLOB = git (qw{hash-object -t blob /dev/null}); + &{$command{$subcommand}}(@ARGV); sub git_pipe { @@ -120,6 +126,16 @@ sub do_archive { system ('git', "--git-dir=$NMBGIT", 'archive', 'HEAD'); } +sub do_clone { + my $repository = shift; + + my $tempwork = tempdir ('/tmp/nmbug-clone.XXXXXX', CLEANUP => 1); + system ('git', 'clone', '--no-checkout', '--separate-git-dir', $NMBGIT, + $repository, $tempwork) == 0 + or die "'git clone' exited with nonzero value\n"; + git ('config', '--unset', 'core.worktree'); + git ('config', 'core.bare', 'true'); +} sub is_committed { my $status = shift; @@ -203,9 +219,9 @@ sub index_tags { my $index = $NMBGIT.'/nmbug.index'; - my $query = join ' ', map ("tag:$_", get_tags ($TAGPREFIX)); + my $query = join ' ', map ("tag:\"$_\"", get_tags ($TAGPREFIX)); - my $fh = spawn ('-|', qw/notmuch dump --/, $query) + my $fh = spawn ('-|', qw/notmuch dump --format=batch-tag --/, $query) or die "notmuch dump: $!"; git ('read-tree', '--empty'); @@ -214,22 +230,30 @@ sub index_tags { or die 'git update-index'; while (<$fh>) { - m/ ( [^ ]* ) \s+ \( ([^\)]* ) \) /x || die 'syntax error in dump'; - my ($id,$rest) = ($1,$2); - #strip prefixes before writing - my @tags = grep { s/^$TAGPREFIX//; } split (' ', $rest); + chomp(); + my ($rest,$id) = split(/ -- id:/); + + if ($id =~ s/^"(.*)"\s*$/$1/) { + # xapian quoted string, dequote. + $id =~ s/""/"/g; + } + + #strip prefixes from tags before writing + my @tags = grep { s/^[+]$ENCPREFIX//; } split (' ', $rest); index_tags_for_msg ($git,$id, 'A', @tags); } unless (close $git) { die "'git update-index --index-info' exited with nonzero value\n"; } unless (close $fh) { - die "'notmuch dump -- $query' exited with nonzero value\n"; + die "'notmuch dump --format=batch-tag -- $query' exited with nonzero value\n"; } return $index; } +# update the git index to either create or delete an empty file. +# Neither argument should be encoded/escaped. sub index_tags_for_msg { my $fh = shift; my $msgid = shift; @@ -254,6 +278,20 @@ sub do_checkout { do_sync (action => 'checkout'); } +sub quote_for_xapian { + my $str = shift; + $str =~ s/"/""/g; + return '"' . $str . '"'; +} + +sub pair_to_batch_line { + my ($action, $pair) = @_; + + # the tag should already be suitably encoded + + return $action . $ENCPREFIX . $pair->{tag} . + ' -- id:' . quote_for_xapian ($pair->{id})."\n"; +} sub do_sync { @@ -270,17 +308,20 @@ sub do_sync { $D_action = '-'; } - foreach my $pair (@{$status->{added}}) { + my $notmuch = spawn ({}, '|-', qw/notmuch tag --batch/) + or die 'notmuch tag --batch'; - notmuch ('tag', $A_action.$TAGPREFIX.$pair->{tag}, - 'id:'.$pair->{id}); + foreach my $pair (@{$status->{added}}) { + print $notmuch pair_to_batch_line ($A_action, $pair); } foreach my $pair (@{$status->{deleted}}) { - notmuch ('tag', $D_action.$TAGPREFIX.$pair->{tag}, - 'id:'.$pair->{id}); + print $notmuch pair_to_batch_line ($D_action, $pair); } + unless (close $notmuch) { + die "'notmuch tag --batch' exited with nonzero value\n"; + } } @@ -302,21 +343,24 @@ To discard your changes, run 'nmbug checkout' sub do_pull { my $remote = shift || 'origin'; + my $branch = shift || 'master'; git ( 'fetch', $remote); - do_merge (); + do_merge ("$remote/$branch"); } sub do_merge { + my $commit = shift || '@{upstream}'; + insist_committed (); my $tempwork = tempdir ('/tmp/nmbug-merge.XXXXXX', CLEANUP => 1); git ( { GIT_WORK_TREE => $tempwork }, 'checkout', '-f', 'HEAD'); - git ( { GIT_WORK_TREE => $tempwork }, 'merge', 'FETCH_HEAD'); + git ( { GIT_WORK_TREE => $tempwork }, 'merge', $commit); do_checkout (); } @@ -377,11 +421,10 @@ sub do_status { sub is_unmerged { + my $commit = shift || '@{upstream}'; - return 0 if (! -f $NMBGIT.'/FETCH_HEAD'); - - my $fetch_head = git ('rev-parse', 'FETCH_HEAD'); - my $base = git ( 'merge-base', 'HEAD', 'FETCH_HEAD'); + my $fetch_head = git ('rev-parse', $commit); + my $base = git ( 'merge-base', 'HEAD', $commit); return ($base ne $fetch_head); @@ -443,7 +486,7 @@ sub diff_index { sub diff_refs { my $filter = shift; my $ref1 = shift || 'HEAD'; - my $ref2 = shift || 'FETCH_HEAD'; + my $ref2 = shift || '@{upstream}'; my $fh= git_pipe ( 'diff', "--diff-filter=$filter", '--name-only', $ref1, $ref2); @@ -531,10 +574,11 @@ git. Any extra arguments are used (one per line) as a commit message. push local nmbug git state to remote repo -=item B [remote] +=item B [remote] [branch] pull (merge) remote repo changes to notmuch. B is equivalent to -B followed by B. +B followed by B. The default remote is C, and +the default branch is C. =back @@ -542,6 +586,12 @@ B followed by B. =over 8 +=item B repository + +Create a local nmbug repository from a remote source. This wraps +C, adding some options to avoid creating a working tree +while preserving remote-tracking branches and upstreams. + =item B Update the notmuch database from git. This is mainly useful to discard @@ -559,12 +609,12 @@ print help [for subcommand] =item B [parameters] A simple wrapper for git log. After running C, you can -inspect the changes with C +inspect the changes with C -=item B +=item B [commit] -Merge changes from FETCH_HEAD into HEAD, and load the result into -notmuch. +Merge changes from C into HEAD, and load the result into +notmuch. The default commit is C<@{upstream}>. =item B