summaryrefslogtreecommitdiff
path: root/contrib/fast-import/import-tars.perl
blob: 6309d146e74a428520d09cbff4dc8d9a429ec001 (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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/perl

## tar archive frontend for git-fast-import
##
## For example:
##
##  mkdir project; cd project; git init
##  perl import-tars.perl *.tar.bz2
##  git whatchanged import-tars
##

use strict;
die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV;

my $branch_name = 'import-tars';
my $branch_ref = "refs/heads/$branch_name";
my $author_name = $ENV{'GIT_AUTHOR_NAME'} || 'T Ar Creator';
my $author_email = $ENV{'GIT_AUTHOR_EMAIL'} || 'tar@example.com';
my $committer_name = $ENV{'GIT_COMMITTER_NAME'} || `git config --get user.name`;
my $committer_email = $ENV{'GIT_COMMITTER_EMAIL'} || `git config --get user.email`;

chomp($committer_name, $committer_email);

open(FI, '|-', 'git', 'fast-import', '--quiet')
	or die "Unable to start git fast-import: $!\n";
foreach my $tar_file (@ARGV)
{
	my $commit_time = time;
	$tar_file =~ m,([^/]+)$,;
	my $tar_name = $1;

	if ($tar_name =~ s/\.(tar\.gz|tgz)$//) {
		open(I, '-|', 'gunzip', '-c', $tar_file)
			or die "Unable to gunzip -c $tar_file: $!\n";
	} elsif ($tar_name =~ s/\.(tar\.bz2|tbz2)$//) {
		open(I, '-|', 'bunzip2', '-c', $tar_file)
			or die "Unable to bunzip2 -c $tar_file: $!\n";
	} elsif ($tar_name =~ s/\.tar\.Z$//) {
		open(I, '-|', 'uncompress', '-c', $tar_file)
			or die "Unable to uncompress -c $tar_file: $!\n";
	} elsif ($tar_name =~ s/\.tar$//) {
		open(I, $tar_file) or die "Unable to open $tar_file: $!\n";
	} else {
		die "Unrecognized compression format: $tar_file\n";
	}

	my $author_time = 0;
	my $next_mark = 1;
	my $have_top_dir = 1;
	my ($top_dir, %files);

	while (read(I, $_, 512) == 512) {
		my ($name, $mode, $uid, $gid, $size, $mtime,
			$chksum, $typeflag, $linkname, $magic,
			$version, $uname, $gname, $devmajor, $devminor,
			$prefix) = unpack 'Z100 Z8 Z8 Z8 Z12 Z12
			Z8 Z1 Z100 Z6
			Z2 Z32 Z32 Z8 Z8 Z*', $_;
		last unless length($name);
		if ($name eq '././@LongLink') {
			# GNU tar extension
			if (read(I, $_, 512) != 512) {
				die ('Short archive');
			}
			$name = unpack 'Z257', $_;
			next unless $name;

			my $dummy;
			if (read(I, $_, 512) != 512) {
				die ('Short archive');
			}
			($dummy, $mode, $uid, $gid, $size, $mtime,
			$chksum, $typeflag, $linkname, $magic,
			$version, $uname, $gname, $devmajor, $devminor,
			$prefix) = unpack 'Z100 Z8 Z8 Z8 Z12 Z12
			Z8 Z1 Z100 Z6
			Z2 Z32 Z32 Z8 Z8 Z*', $_;
		}
		next if $name =~ m{/\z};
		$mode = oct $mode;
		$size = oct $size;
		$mtime = oct $mtime;
		next if $typeflag == 5; # directory

		print FI "blob\n", "mark :$next_mark\n", "data $size\n";
		while ($size > 0 && read(I, $_, 512) == 512) {
			print FI substr($_, 0, $size);
			$size -= 512;
		}
		print FI "\n";

		my $path;
		if ($prefix) {
			$path = "$prefix/$name";
		} else {
			$path = "$name";
		}
		$files{$path} = [$next_mark++, $mode];

		$author_time = $mtime if $mtime > $author_time;
		$path =~ m,^([^/]+)/,;
		$top_dir = $1 unless $top_dir;
		$have_top_dir = 0 if $top_dir ne $1;
	}

	print FI <<EOF;
commit $branch_ref
author $author_name <$author_email> $author_time +0000
committer $committer_name <$committer_email> $commit_time +0000
data <<END_OF_COMMIT_MESSAGE
Imported from $tar_file.
END_OF_COMMIT_MESSAGE

deleteall
EOF

	foreach my $path (keys %files)
	{
		my ($mark, $mode) = @{$files{$path}};
		$path =~ s,^([^/]+)/,, if $have_top_dir;
		printf FI "M %o :%i %s\n", $mode & 0111 ? 0755 : 0644, $mark, $path;
	}
	print FI "\n";

	print FI <<EOF;
tag $tar_name
from $branch_ref
tagger $author_name <$author_email> $author_time +0000
data <<END_OF_TAG_MESSAGE
Package $tar_name
END_OF_TAG_MESSAGE

EOF

	close I;
}
close FI;