#!/usr/bin/perl # # Converts a git repository from hex to base64 # use Compress::Zlib; use Digest::SHA1 qw(sha1 sha1_hex sha1_base64); use bytes; $flat = 1; # Set to 1 to use flat base64 representation sub get_hex_file($$) { my($root, $hex) = @_; my($h1) = substr($hex,0,2); my($h2) = substr($hex,2); my($data, @st, $sig); open(HX, '<', "$root/$h1/$h2") or die "$0: $root/$h1/$h2: $!\n"; @st = stat(HX); if ( read(HX, $data, $st[7]) != $st[7] ) { die "$0: $root/$h1/$h2: read error: $!\n"; } $sig = sha1_hex($data); $data = uncompress($data); if ( !defined($data) ) { die "$0: $root/$h1/$h2: failed to uncompress\n"; } close(HX); if ( $sig ne $hex ) { die "$0: $root/$h1/$h2 doesn\'t match its own signature: $sig\n"; } return $data; } sub write_file($$) { my($root, $data) = @_; $data = compress($data, Z_BEST_COMPRESSION); if ( !defined($data) ) { die "$0: $root/$pf: failed to compress\n"; } my($name) = sha1_base64($data); $name =~ tr/\//_/; # Hybrid of regular and filesystem safe base64 my($pf); if ( $flat ) { $pf = $name; } else { my($px) = substr($name,0,2); $pf = $px.'/'.substr($name,2); mkdir("$root/$px", 0777); } open(WF, '>', "$root/$pf") or die "$0: $root/$pf: $!\n"; if ( !print WF $data ) { die "$0: $root/$pf: write error: $!\n"; } close(WF); return $name; } sub handle_file($$$) { my($root, $newroot, $hex) = @_; my($data, $tdata, $odata, $object_type, $he); $data = get_hex_file($root, $hex); $data =~ /^((\S+) ([0-9]+)\0)/s; $tdata = $1; $odata = "$'"; $object_type = $2; # Did we already do this file? $he = $hash_equiv{$hex}; return $he if ( defined($he) ); if ( $object_type eq 'commit' ) { while ( $odata =~ /^(\S+ )([0-9a-f]{40})$/m ) { my($h) = $2; my($pre) = $`.$1; my($suf) = "$'"; # Make sure we process precedents $he = handle_file($root, $newroot, $h); if ( !defined($he) ) { die "$0: unhandled hash: $h\n"; } $odata = $pre.$he.$suf; } $data = $tdata.$odata; } $he = write_file($newroot, $data); $hash_equiv{$hex} = $he; return $he; } sub recurse($$) { my($root, $newroot) = @_; my($i,$x,$e); %hash_equiv = (); for ( $i = 0 ; $i < 256 ; $i++ ) { $x = sprintf("%02x", $i); next unless ( opendir(RDIR, "$root/$x") ); while ( $e = readdir(RDIR) ) { if ( $e =~ /^[0-9a-f]{38}$/ ) { handle_file($root, $newroot, "$x$e"); } } closedir(RDIR); } } ($old_root, $new_root) = @ARGV; mkdir($new_root, 0777) or die "$0: cannot mkdir $new_root: $!\n"; mkdir("$new_root/objects", 0777) or die "$0: cannot mkdir $new_root/objects: $!\n"; recurse("$old_root/objects", "$new_root/objects"); open(HEAD, '<', "$old_root/HEAD") or exit 0; $head = ; chomp $head; if ( defined($hash_equiv{$head}) ) { $head = $hash_equiv{$head}; } else { print STDERR "Warning: HEAD not found: $head\n"; exit 1; } close(HEAD); open(NEWHEAD, '>', "$new_root/HEAD") or die "$0: cannot write new HEAD file\n"; print NEWHEAD $head, "\n"; close(NEWHEAD);