Line # Revision Author
1 47 dpavlin #!/usr/bin/perl
2 use strict;
3 use warnings;
4 use SVN::Dump;
5 48 dpavlin use Shell qw/svnadmin cp find svn rm/;
6 47 dpavlin use Cwd qw/abs_path/;
7 50 dpavlin use Data::Dump qw/dump/;
8 47 dpavlin
9 my $base = shift @ARGV;
10 $base ||= 'svn/';
11
12 50 dpavlin my $checkout = "$base/checkout";
13
14 my $to_dump = 0;
15
16 47 dpavlin die "usage: $0 temp-base-directory (default: $base)\n" unless ( -e $base );
17
18 my $mode = 'move';
19 50 dpavlin my ( $from, $to ) = ( "$base/from", "$base/to/" );
20 my ( $from_list, $to_list ) = ( "$base/from.lst", "$base/to.lst" );
21 47 dpavlin
22 50 dpavlin sub rep_url {
23 return 'file:///' . abs_path(shift);
24 }
25
26 47 dpavlin sub create_list {
27 my ( $dir, $path ) = @_;
28 50 dpavlin my $list = svn('ls', '-R', rep_url($from));
29 47 dpavlin open(my $fh, '>', $path) || die "can't create $path: $!";
30 print $fh $list;
31 close($fh);
32 if ( ! -s $path ) {
33 unlink($path);
34 die "ABORT: created zero size $path\n";
35 }
36 warn "created: $path ", -s $path, "bytes\n";
37 }
38
39 die "please copy repository on which to perfrom operation to $from\n" if ( ! -e $from );
40
41 50 dpavlin warn "##> collect all paths from repository $from\n";
42 create_list( $from, $from_list );
43 47 dpavlin
44 50 dpavlin if ( ! -e $to_list ) {
45 cp( $from_list, $to_list );
46 die "created $to_list\nplease edit it to reflect new layout\n";
47 48 dpavlin }
48
49 49 dpavlin my $map;
50 50 dpavlin my $mkdir;
51 49 dpavlin
52 50 dpavlin open(my $fh_from, '<', $from_list ) || die "can't open $from_list: $!";
53 open(my $fh_to, '<', $to_list ) || die "can't open $to_list: $!";
54 while( my $path_from = <$fh_from> ) {
55 chomp($path_from);
56 my $path_to = <$fh_to> || die "list shorter, probably corrupt: $to_list\n";
57 chomp($path_to);
58 $map->{$path_from} = $path_to;
59 if ( $path_to =~ m{^(.+)/\Q$path_from\E$}) {
60 if ( ! $mkdir->{$1} ) {
61 $mkdir->{$1}++;
62 warn "##> will create $1 in new layout\n";
63 }
64 }
65 49 dpavlin }
66
67 50 dpavlin sub remap {
68 my ($path,$kind) = @_;
69 $path =~ s|/*$|/| if $kind && $kind eq 'dir';
70 if (defined( $map->{$path} )) {
71 my $to = $map->{$path};
72 warn "##> $path -> $to\n";
73 return $to;
74 } else {
75 warn "??> '$path'\n" if $path;
76 return $path;
77 }
78 }
79
80 warn "map = ",dump( $map ),$/;
81 warn "mkdir = ", dump( $mkdir ),$/;
82
83 48 dpavlin if ( -e $to ) {
84 #die "$to allready exists! remove it to re-create repository\n";
85 rm('-Rf',$to);
86 }
87 47 dpavlin
88 48 dpavlin svnadmin('create', $to);
89 open(my $fh_in, '-|', "svnadmin dump $from") || die "can't dump $from: $!";
90 open(my $fh_out, '|-', "svnadmin load $to") || die "can't load $to: $!";
91 50 dpavlin open($fh_out, '>', "$base/to.dump") || die "can't dump to $base/to.dump: $!" if $to_dump;
92 47 dpavlin
93 48 dpavlin my $dump = SVN::Dump->new( { fh => $fh_in } );
94 47 dpavlin
95 50 dpavlin warn "## converting subversion repository $from -> $to\n";
96 47 dpavlin
97 48 dpavlin while ( my $rec = $dump->next_record() ) {
98 50 dpavlin
99 if ( $rec->type() eq 'revision' && $rec->get_header( 'Revision-number' ) == 1 && $mkdir ) {
100 # copy revision record
101 print $fh_out $rec->as_string();
102 # fetch dirs sorted by length
103 foreach my $dir ( sort { length($a) <=> length($b) } keys %$mkdir ) {
104 print $fh_out <<"__NODE_ADD_DIR__";
105
106 Node-path: $dir
107 Node-kind: dir
108 Node-action: add
109 Prop-content-length: 10
110 Content-length: 10
111
112 PROPS-END
113
114
115 __NODE_ADD_DIR__
116 warn "##> inserted mkdir $dir\n";
117 }
118 next;
119 47 dpavlin }
120 48 dpavlin
121 my $path = $rec->get_header('Node-path');
122 50 dpavlin my $kind = $rec->get_header('Node-kind');
123 if ( $path ) {
124 52 dpavlin my $new_path = remap($path,$kind);
125 if ( $new_path eq '' ) {
126 warn "##> skipped $kind $path\n";
127 next;
128 }
129 $rec->set_header('Node-path', $new_path );
130 50 dpavlin if ( $path = $rec->get_header('Node-copyfrom-path') ) {
131 $rec->set_header('Node-copyfrom-path', remap($path,$kind) );
132 }
133 49 dpavlin }
134 48 dpavlin
135 print $fh_out $rec->as_string();
136 47 dpavlin }
137 50 dpavlin
138 if ($@) {
139 warn "ERROR: $@\n";
140 warn "##> content imported into $to\n";
141 svn('ls','-R', rep_url($to));
142 }
143
144 close($fh_in);
145 close($fh_out);
146
147 if ( $to_dump ) {
148 svnadmin('verify',$to);
149 } else {
150 rm('-Rf', $checkout) if -e $checkout;
151 svn('co', rep_url($to), $checkout);
152 }