initial commit
[ssoma-mda.git] / lib / Ssoma / Remover.pm
1 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2 # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
3 package Ssoma::Remover;
4 use strict;
5 use warnings;
6 use Ssoma::Git;
7 use Ssoma::GitIndexInfo;
8
9 sub new {
10         my ($class, $git) = @_;
11         bless { git => $git, ref => "refs/heads/master" }, $class;
12 }
13
14 sub remove_simple {
15         my ($self, $simple) = @_;
16         my $git = $self->{git};
17         my $sub = sub {
18                 $git->tmp_index_do(sub {
19                         $self->_remove($simple);
20                 });
21         };
22         $git->sync_do(sub { $git->tmp_git_do($sub) });
23 }
24
25 # remove an Email::Simple object from the current index
26 sub _remove {
27         my ($self, $simple) = @_;
28         my $git = $self->{git};
29         my $path = $git->mid2path($simple->header("Message-ID"));
30         my $ref = $self->{ref};
31         my $tip = $git->qx_sha1("git rev-parse $ref^0");
32         my $obj = "$tip:$path";
33         my $type = $git->type($obj);
34         my (@keep, @remove);
35         if ($type eq "tree") { # unlikely
36                 $git->each_in_tree($obj, sub {
37                         my ($blob_id, $xpath) = ($1, $2);
38                         my $tmp = $git->blob_to_simple($blob_id);
39                         if ($git->simple_eq($simple, $tmp)) {
40                                 push @remove, "$path/$xpath";
41                         } else {
42                                 push @keep, $blob_id;
43                         }
44                 });
45         } elsif ($type eq "blob") { # likely
46                 my $tmp = $git->blob_to_simple($obj);
47                 if ($git->simple_eq($simple, $tmp)) {
48                         push @remove, $path;
49                 }
50         } else {
51                 die "unhandled type=$type for obj=$obj\n";
52         }
53
54         my $gii = Ssoma::GitIndexInfo->new;
55         foreach my $rm (@remove) { $gii->remove($rm) }
56
57         if (scalar(@keep) == 1) { # convert tree back to blob
58                 my $blob_id = $keep[0];
59                 $gii->remove($path);
60                 $gii->update('100644', $blob_id, $path);
61         } elsif ((scalar(@keep) == 0) && ($type eq "tree")) {
62                 # this is not possible unless simple_eq changes over time
63                 $gii->remove($path);
64         } # else: do nothing if (@keep > 1)
65
66         # commit changes
67         $git->commit_index($gii, 1, $ref, 'rm');
68 }
69
70 1;