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