fix nothing changed logic, when only one revision has changed
[metze/old/samba4-sync/samba4-sync.scripts/.git] / samba4-sync.pl
1 #!/usr/bin/perl
2 #
3
4 use strict;
5
6 use FindBin qw($RealBin);
7
8 use lib "$RealBin";
9 use util;
10
11 use POSIX;
12 use Data::Dumper;
13 use File::stat;
14 use Carp;
15
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";
22
23 my $LAST_SVN_REV_PATH = "$PATCH_PATH/latest.rev";
24
25 sub get_last_svn_rev()
26 {
27         my $v = util::FileLoad($LAST_SVN_REV_PATH);
28         my $def = 25600;
29
30         $v = $def if $v eq "";
31         $v *= 1;
32         $v = $def if $v == 0;
33
34         print "get_last_svn_rev: $v\n";
35         return $v;
36 }
37
38 sub set_last_svn_rev($)
39 {
40         my ($r) = @_;
41         my $v = $r->{svnrev};
42         util::FileSave($LAST_SVN_REV_PATH, $v);
43         print "set_last_svn_rev: $v\n";
44 }
45
46 sub get_cur_svn_rev()
47 {
48         my $def = 25650;
49         my $infocmd = "LANG=C svn info --non-interactive $SVN_PATH";
50         my $info = `$infocmd` || confess "$infocmd: failed";
51
52         my $v = $info;
53         if ($v =~ /\nRevision: (\d+)/) {
54                 $v = $1;
55         }
56         $v = $def if $v eq $info;
57         $v *= 1;
58         $v = $def if $v == 0;
59
60         print "get_cur_svn_rev: $v\n";
61         return $v;
62 }
63
64 sub load_authors()
65 {
66         my $f = util::FileLoad($AUTHORS_PATH);
67         my @lines = split("\n", $f);
68         my $authors = undef;
69
70         foreach my $l (@lines) {
71                 if ($l =~ /^([\w\-]+) = (.*)$/) {
72                         $authors->{$1} = $2;
73                         next;
74                 }
75
76                 confess "line: $l: invalid";
77         }
78
79         return $authors;
80 }
81
82 sub fix_author($)
83 {
84         my ($in) = @_;
85         my $authors = undef;
86
87         $authors = load_authors() unless defined($authors);
88
89         my $out = $authors->{$in};
90
91         confess "author: $in:not found" unless defined($out);
92
93         return $out;
94 }
95
96 sub fix_log($)
97 {
98         my ($in) = @_;
99         my $delim = "------------------------------------------------------------------------";
100         my @tmp1 = split($delim, $in);
101         my @tmp2 = split("\n", $tmp1[0]);
102
103         while (1){
104                 my $l = $tmp2[0];
105                 last unless $l =~ /^[ \t]*$/;
106                 shift(@tmp2);
107         }
108
109         my $out = join("\n", @tmp2);
110
111         return $out;
112 }
113
114 sub fix_date($)
115 {
116         my ($in) = @_;
117
118         return $in;
119 }
120
121 sub is_dir($)
122 {
123         my ($in) = @_;
124         return 1 if $in eq ".";
125         return 1 if $in =~ /\/$/;
126         return 0;
127 }
128
129 sub construct_chunk($)
130 {
131         my ($chunk) = @_;
132
133         my $out = join("\n", @{$chunk->{content}->{lines}});
134
135         $out =~ s/^Index: ([^\n]+)\n[=]+/diff -u a\/$1 b\/$1/g;
136         $out =~ s/--- ([^\(]+)\(revision: 0\)/--- \/dev\/null/g;
137         $out =~ s/--- ([^\(]+)\([^\n]+/--- a\/$1/g;
138         $out =~ s/\+\+\+ ([^\(]+)\(revision: 0\)/+++ \/dev\/null/g;
139         $out =~ s/\+\+\+ ([^\(]+)\([^\n]+/+++ b\/$1/g;
140
141         return $out;
142 }
143
144 sub strip_svn_properties($)
145 {
146         my ($in) = @_;
147         my @in = split("\n", $in);
148
149         my $chunk = undef;
150         my $chunks = undef;
151         foreach my $l (@in) {
152                 if ($l =~ /^Index: ([\w\.\_\-\/]+)/) {
153                         #print "content: $1\n";
154
155                         $chunk = undef;
156                         $chunk->{type} = "content";
157                         $chunk->{file} = $1;
158                         confess "$1 content exists" if defined($chunks->{$1}) and defined($chunks->{$1}->{content});
159                         $chunks->{$1}->{content} = $chunk;
160                 } elsif ($l =~ /^Property changes on: ([\w\.\_\-\/]+)/) {
161                         #print "properties(".is_dir($1)."): $1\n";
162
163                         $chunk = undef;
164                         $chunk->{type} = "property";
165                         $chunk->{path} = $1;
166                         confess "$1 properties exists" if defined($chunks->{$1}) and defined($chunks->{$1}->{properties});
167                         $chunks->{$1}->{properties} = $chunk unless is_dir($1);
168                 }
169
170                 push(@{$chunk->{lines}}, $l);
171         }
172
173         #print Data::Dumper::Dumper($chunks);
174
175         my @out = ();
176         foreach $chunk (values %{$chunks}) {
177                 #print Data::Dumper::Dumper($chunk);
178                 my $v = construct_chunk($chunk);
179                 push(@out, $v);
180         }
181
182         my $out = join("\n", @out);
183         return undef if $out eq "";
184
185         return $out;
186 }
187
188 sub fix_diff($)
189 {
190         my ($in) = @_;
191         my $out = $in;
192
193         confess("binary diff") if ($in =~ /Cannot display: file marked as a binary type/);
194         return undef unless ($in =~ /^Index: [\w\.\_\-\/]+/);
195
196         $out = strip_svn_properties($in);
197
198         return $out;
199 }
200
201 sub get_new_svn_revs($$)
202 {
203         my ($lastrev, $currev) = @_;
204         my $nextrev = $lastrev + 1;
205         return undef if $nextrev > $currev;
206         my $logcmd = "LANG=C svn log --non-interactive -r $nextrev:$currev $SVN_PATH";
207         my $log = `$logcmd` || confess "$logcmd: failed";
208         my $revs = undef;
209
210         while($log =~ /\nr(\d+) \| (\w+) \| ([^\|]+) \|.*?line(s?)\n(.*)$/s) {
211                 $log = $5;
212                 $revs->{$1}->{svnrev} = $1;
213                 $revs->{$1}->{author} = fix_author($2);
214                 $revs->{$1}->{log}    = fix_log($5);
215                 $revs->{$1}->{date}   = fix_date($3);
216         }
217
218         return $revs;
219 }
220
221 sub get_svn_diff($)
222 {
223         my ($rev) = @_;
224         my $orev = $rev - 1;
225         my $diffcmd = "LANG=C svn diff --non-interactive -r $orev:$rev $SVN_PATH";
226         my $diff = `$diffcmd` || confess "$diffcmd: failed";
227
228         return fix_diff($diff); 
229 }
230
231 sub generate_patch($$)
232 {
233         my ($r, $diff) = @_;
234         my @log = split("\n", $r->{log});
235         my $subject = shift @log;
236         my $body = join("\n", @log);
237         my $p = "";
238
239         $p .= "From 123456780abcdef\n";
240         $p .= "From: $r->{author}\n";
241         $p .= "Date: $r->{date}\n";
242         $p .= "Subject: [PATCH] r$r->{svnrev}: $subject\n";
243         $p .= "$body\n";
244         $p .= "\n";
245         $p .= $diff;
246         $p .= "\n---\nsvn-sync script\n\n";
247
248         return $p;
249 }
250
251 sub apply_patch($)
252 {
253         my ($r) = @_;
254         my $applycmd = "cd $GIT_PATH && git am --binary $r->{patch_path}";
255
256         my $apply = `$applycmd` || confess "$applycmd: failed";
257 }
258
259 sub store_patches($)
260 {
261         my ($revs) = @_;
262
263         foreach my $rev (sort keys %{$revs}) {
264                 my $r = $revs->{$rev};
265                 $r->{patch_path} = "$PATCH_PATH/$r->{svnrev}.patch";
266                 my $diff = get_svn_diff($r->{svnrev});
267                 next unless defined($diff);
268                 my $patch = generate_patch($r, $diff);
269                 #print $patch;
270                 util::FileSave($r->{patch_path}, $patch);
271                 apply_patch($r);
272                 set_last_svn_rev($r);
273         }
274 }
275
276 sub apply_patches($)
277 {
278         my ($revs) = @_;
279
280         
281 }
282
283 my $lastrev = get_last_svn_rev();
284 my $currev = get_cur_svn_rev();
285
286 my $revs = get_new_svn_revs($lastrev, $currev);
287 store_patches($revs);
288 #print Data::Dumper::Dumper($revs);
289