summaryrefslogtreecommitdiff
path: root/perl/Git/SVN/GlobSpec.pm
blob: f2c1e1f6fbe8899cd3f871d4fefcee2c5939f2a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package Git::SVN::GlobSpec;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();

sub new {
	my ($class, $glob, $pattern_ok) = @_;
	my $re = $glob;
	$re =~ s!/+$!!g; # no need for trailing slashes
	my (@left, @right, @patterns);
	my $state = "left";
	my $die_msg = "Only one set of wildcards " .
				"(e.g. '*' or '*/*/*') is supported: $glob\n";
	for my $part (split(m|/|, $glob)) {
		if ($pattern_ok && $part =~ /[{}]/ &&
			 $part !~ /^\{[^{}]+\}/) {
			die "Invalid pattern in '$glob': $part\n";
		}
		my $nstars = $part =~ tr/*//;
		if ($nstars > 1) {
			die "Only one '*' is allowed in a pattern: '$part'\n";
		}
		if ($part =~ /(.*)\*(.*)/) {
			die $die_msg if $state eq "right";
			my ($l, $r) = ($1, $2);
			$state = "pattern";
			my $pat = quotemeta($l) . '[^/]*' . quotemeta($r);
			push(@patterns, $pat);
		} elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
			die $die_msg if $state eq "right";
			$state = "pattern";
			my $p = quotemeta($1);
			$p =~ s/\\,/|/g;
			push(@patterns, "(?:$p)");
		} else {
			if ($state eq "left") {
				push(@left, $part);
			} else {
				push(@right, $part);
				$state = "right";
			}
		}
	}
	my $depth = @patterns;
	if ($depth == 0) {
		die "One '*' is needed in glob: '$glob'\n";
	}
	my $left = join('/', @left);
	my $right = join('/', @right);
	$re = join('/', @patterns);
	$re = join('\/',
		   grep(length, quotemeta($left),
                                "($re)(?=/|\$)",
                                quotemeta($right)));
	my $left_re = qr/^\/\Q$left\E(\/|$)/;
	bless { left => $left, right => $right, left_regex => $left_re,
	        regex => qr/$re/, glob => $glob, depth => $depth }, $class;
}

sub full_path {
	my ($self, $path) = @_;
	return (length $self->{left} ? "$self->{left}/" : '') .
	       $path . (length $self->{right} ? "/$self->{right}" : '');
}

1;