6 use FindBin qw($RealBin);
16 my $SVN_REPO="file:///home/svn/samba";
17 my $SVN_BRANCH="branches/SAMBA_4_0/";
18 my $SVN_PATH="$SVN_REPO/$SVN_BRANCH";
19 my $PATCH_PATH="$ENV{HOME}/svnmirror/samba4-sync.patches";
20 my $AUTHORS_PATH="$ENV{HOME}/svnmirror/samba4-sync.scripts/svn-authors";
21 my $GIT_PATH="$ENV{HOME}/svnmirror/samba4-sync.git";
23 my $LAST_SVN_REV_PATH = "$PATCH_PATH/latest.rev";
25 $ENV{LANG} = "en_US.UTF-8";
27 sub get_last_svn_rev()
29 my $v = util::FileLoad($LAST_SVN_REV_PATH);
32 $v = $def if $v eq "";
36 print "get_last_svn_rev: $v\n";
40 sub set_last_svn_rev($)
44 util::FileSave($LAST_SVN_REV_PATH, $v);
45 print "set_last_svn_rev: $v\n";
51 my $infocmd = "svn info --non-interactive $SVN_PATH";
52 my $info = `$infocmd` || confess "$infocmd: failed";
55 if ($v =~ /\nRevision: (\d+)/) {
58 $v = $def if $v eq $info;
62 print "get_cur_svn_rev: $v\n";
68 my $f = util::FileLoad($AUTHORS_PATH);
69 my @lines = split("\n", $f);
72 foreach my $l (@lines) {
73 if ($l =~ /^([\w\-]+) = (.*)$/) {
78 confess "line: $l: invalid";
89 $authors = load_authors() unless defined($authors);
91 my $out = $authors->{$in};
93 confess "author: $in:not found" unless defined($out);
101 my $delim = "------------------------------------------------------------------------";
102 my @tmp1 = split($delim, $in);
103 my @tmp2 = split("\n", $tmp1[0]);
107 last unless $l =~ /^[ \t]*$/;
111 my $out = join("\n", @tmp2);
126 return 1 if $in eq ".";
127 return 1 if $in =~ /\/$/;
131 sub construct_chunk($)
134 return undef unless defined($chunk->{content}->{lines});
135 my @content = @{$chunk->{content}->{lines}};
137 my @hdr = splice(@content, 0, 5);
139 confess "hdr[0]" unless $hdr[0] =~ /^Index: /;
140 confess "hdr[1]" unless $hdr[1] =~ /^[=]+$/;
141 confess "hdr[2]" unless $hdr[2] =~ /^--- /;
142 confess "hdr[3]" unless $hdr[3] =~ /^\+\+\+ /;
143 confess "hdr[4]" unless $hdr[4] =~ /^\@@ /;
145 $hdr[0] =~ s/^Index: ([^\n]+)$/diff --git a\/$1 b\/$1/g;
146 $hdr[2] =~ s/--- ([^\(]+)\(revision 0\)/--- \/dev\/null/g;
147 $hdr[2] =~ s/--- ([^\(]+)\([^\n]+/--- a\/$1/g;
148 $hdr[3] =~ s/\+\+\+ ([^\(]+)\(revision 0\)/+++ \/dev\/null/g;
149 $hdr[3] =~ s/\+\+\+ ([^\(]+)\([^\n]+/+++ b\/$1/g;
151 if ($hdr[4] =~ /\@\@ -\d+,\d+ \+0,0 \@\@/) {
152 $hdr[3] = "+++ /dev/null";
155 my $oldsha1 = "1234567";
156 my $newsha1 = "7654321";
159 if (grep(/svn:executable/, @{$chunk->{properties}->{lines}})) {
160 print join("\n", @{$chunk->{properties}->{lines}});
161 $mode = "new file mode 100755\n";
164 if ($hdr[2] =~ /\/dev\/null/) {
165 $oldsha1 = "0000000";
166 $mode = "new file mode 100644\n" if $mode eq "";
169 if ($hdr[3] =~ /\/dev\/null/) {
170 $newsha1 = "0000000";
171 $mode = "deleted file mode 100644\n";
174 $hdr[1] = $mode."index $oldsha1..$newsha1";
176 splice(@content, 0, 0, @hdr);
178 my $out = join("\n", @content);
183 sub strip_svn_properties($)
186 my @in = split("\n", $in);
190 foreach my $l (@in) {
191 if ($l =~ /^Index: ([\w\.\_\-\/]+)/) {
192 #print "content: $1\n";
195 $chunk->{type} = "content";
197 confess "$1 content exists" if defined($chunks->{$1}) and defined($chunks->{$1}->{content});
198 $chunks->{$1}->{content} = $chunk;
199 } elsif ($l =~ /^Property changes on: ([\w\.\_\-\/]+)/) {
200 #print "properties(".is_dir($1)."): $1\n";
203 $chunk->{type} = "property";
205 confess "$1 properties exists" if defined($chunks->{$1}) and defined($chunks->{$1}->{properties});
206 $chunks->{$1}->{properties} = $chunk unless is_dir($1);
209 push(@{$chunk->{lines}}, $l);
212 #print Data::Dumper::Dumper($chunks);
215 foreach $chunk (values %{$chunks}) {
216 #print Data::Dumper::Dumper($chunk);
217 my $v = construct_chunk($chunk);
218 push(@out, $v) if defined($v);
221 my $out = join("\n", @out);
222 return undef if $out eq "";
232 confess("binary diff") if ($in =~ /Cannot display: file marked as a binary type/);
233 return undef unless ($in =~ /^Index: [\w\.\_\-\/]+/);
235 $out = strip_svn_properties($in);
240 sub get_new_svn_revs($$)
242 my ($lastrev, $currev) = @_;
243 my $nextrev = $lastrev + 1;
244 return undef if $nextrev > $currev;
245 my $logcmd = "svn log --non-interactive -r $nextrev:$currev $SVN_PATH";
246 my $log = `$logcmd` || confess "$logcmd: failed";
249 while($log =~ /\nr(\d+) \| (\w+) \| ([^\|]+) \|.*?line(s?)\n(.*)$/s) {
251 $revs->{$1}->{svnrev} = $1;
252 $revs->{$1}->{author} = fix_author($2);
253 $revs->{$1}->{log} = fix_log($5);
254 $revs->{$1}->{date} = fix_date($3);
264 my $diffcmd = "svn diff --non-interactive -r $orev:$rev $SVN_PATH";
265 my $diff = `$diffcmd` || confess "$diffcmd: failed";
267 return fix_diff($diff);
270 sub generate_patch($$)
273 my @log = split("\n", $r->{log});
274 my $subject = shift @log;
275 my $body = join("\n", @log);
278 $p .= "From 123456780abcdef\n";
279 $p .= "From: $r->{author}\n";
280 $p .= "Date: $r->{date}\n";
281 $p .= "Subject: [PATCH] r$r->{svnrev}: $subject\n";
285 $p .= "\n---\nsvn-sync script\n\n";
293 my $applycmd = "cd $GIT_PATH && git am --whitespace=nowarn --binary $r->{patch_path}";
295 my $apply = `$applycmd` || confess "$applycmd: failed";
302 foreach my $rev (sort keys %{$revs}) {
303 my $r = $revs->{$rev};
304 $r->{patch_path} = "$PATCH_PATH/$r->{svnrev}.patch";
305 my $diff = get_svn_diff($r->{svnrev});
306 next unless defined($diff);
307 my $patch = generate_patch($r, $diff);
309 util::FileSave($r->{patch_path}, $patch);
311 set_last_svn_rev($r);
322 my $lastrev = get_last_svn_rev();
323 my $currev = get_cur_svn_rev();
325 my $revs = get_new_svn_revs($lastrev, $currev);
326 store_patches($revs);
327 #print Data::Dumper::Dumper($revs);