#!/usr/bin/perl # help with rc file format change at v3.4 -- help upgrade v3 rc files from # v3.3 and below to the new v3.4 and above format # once you upgrade gitolite past 3.4, you may want to use the new rc file # format, because it's really much nicer (just to recap: the old format will # still work, in fact internally the new format gets converted to the old # format before actually being used. However, the new format makes it much # easier to enable and disable features). # PLEASE SEE WARNINGS BELOW # this program helps you upgrade your rc file. # STEPS # cd gitolite-source-repo-clone # contrib/utils/upgrade-rc33 /path/to/old.gitolite.rc > new.gitolite.rc # WARNINGS # make sure you also READ ALL ERROR/WARNING MESSAGES GENERATED # make sure you EXAMINE THE FILE AND CHECK THAT EVERYTHING LOOKS GOOD before using it # be especially careful about # variables which contains single/double quotes or other special characters # variables that stretch across multiple lines # features which take arguments (like 'renice') # new features you've enabled which don't exist in the default rc # ---------------------------------------------------------------------- use strict; use warnings; use 5.10.0; use Cwd; use Data::Dumper; $Data::Dumper::Terse = 1; $Data::Dumper::Indent = 1; $Data::Dumper::Sortkeys = 1; BEGIN { $ENV{HOME} = getcwd; $ENV{HOME} .= "/.home.rcupgrade.$$"; mkdir $ENV{HOME} or die "mkdir '$ENV{HOME}': $!\n"; } END { system("rm -rf ./.home.rcupgrade.$$"); } use lib "./src/lib"; use Gitolite::Rc; { no warnings 'redefine'; sub Gitolite::Common::gl_log { } } # ---------------------------------------------------------------------- # everything happens inside a fresh v3.6.1+ gitolite clone; no other # directories are used. # the old rc file to be migrated is somewhere *else* and is supplied as a # command line argument. # ---------------------------------------------------------------------- my $oldrc = shift or die "need old rc filename as arg-1\n"; { package rcup; do $oldrc; } my %oldrc; { no warnings 'once'; %oldrc = %rcup::RC; } delete $rcup::{RC}; { my @extra = sort keys %rcup::; warn "**** WARNING ****\nyou have variables declared outside the %RC hash; you must handle them manually\n" if @extra; } # this is the new rc text being built up my $newrc = glrc('default-text'); # ---------------------------------------------------------------------- # default disable all features in newrc map { disable( $_, 'sq' ) } (qw(help desc info perms writable ssh-authkeys git-config daemon gitweb)); # map { disable($_, '') } (qw(GIT_CONFIG_KEYS)); set_s('HOSTNAME'); set_s( 'UMASK', 'num' ); set_s( 'GIT_CONFIG_KEYS', 'sq' ); set_s( 'LOG_EXTRA', 'num' ); set_s( 'DISPLAY_CPU_TIME', 'num' ); set_s( 'CPU_TIME_WARN_LIMIT', 'num' ); set_s('SITE_INFO'); set_s('LOCAL_CODE'); if ( $oldrc{WRITER_CAN_UPDATE_DESC} ) { die "tell Sitaram he changed the default rc too much" unless $newrc =~ /rc variables used by various features$/m; $newrc =~ s/(rc variables used by various features\n)/$1\n # backward compat\n WRITER_CAN_UPDATE_DESC => 1,\n/; delete $oldrc{WRITER_CAN_UPDATE_DESC}; } if ( $oldrc{ROLES} ) { my $t = ''; for my $r ( sort keys %{ $oldrc{ROLES} } ) { $t .= ( " " x 8 ) . $r . ( " " x ( 28 - length($r) ) ) . "=> 1,\n"; } $newrc =~ s/(ROLES *=> *\{\n).*?\n( *\},)/$1$t$2/s; delete $oldrc{ROLES}; } if ( $oldrc{DEFAULT_ROLE_PERMS} ) { warn "DEFAULT_ROLE_PERMS has been replaced by per repo option\nsee http://gitolite.com/gitolite/wild.html\n"; delete $oldrc{DEFAULT_ROLE_PERMS}; } # the following is a bit like the reverse of what the new Rc.pm does... for my $l ( split /\n/, $Gitolite::Rc::non_core ) { next if $l =~ /^ *#/ or $l !~ /\S/; my ( $name, $where, $module ) = split ' ', $l; $module = $name if $module eq '.'; ( $module = $name ) .= "::" . lc($where) if $module eq '::'; # if you find $module as an element of $where, enable $name enable($name) if miw( $module, $where ); } # now deal with commands if ( $oldrc{COMMANDS} ) { for my $c ( sort keys %{ $oldrc{COMMANDS} } ) { if ( $oldrc{COMMANDS}{$c} == 1 ) { enable($c); # we don't handle anything else right (and so far only git-annex # is affected, as far as I remember) delete $oldrc{COMMANDS}{$c}; } } } print $newrc; for my $w (qw(INPUT POST_COMPILE PRE_CREATE ACCESS_1 POST_GIT PRE_GIT ACCESS_2 POST_CREATE SYNTACTIC_SUGAR)) { delete $oldrc{$w} unless scalar( @{ $oldrc{$w} } ); } delete $oldrc{COMMANDS} unless scalar keys %{ $oldrc{COMMANDS} }; exit 0 unless %oldrc; warn "the following parts of the old rc were NOT converted:\n"; print STDERR Dumper \%oldrc; # ---------------------------------------------------------------------- # set scalars that the new file defaults to "commented out" sub set_s { my ( $key, $type ) = @_; $type ||= ''; return unless exists $oldrc{$key}; # special treatment for UMASK $oldrc{$key} = substr( "00" . sprintf( "%o", $oldrc{$key} ), -4 ) if ( $key eq 'UMASK' ); $newrc =~ s/# $key /$key /; # uncomment if needed if ( $type eq 'num' ) { $newrc =~ s/$key ( *=> *).*/$key $1$oldrc{$key},/; } elsif ( $type eq 'sq' ) { $newrc =~ s/$key ( *=> *).*/$key $1'$oldrc{$key}',/; } else { $newrc =~ s/$key ( *=> *).*/$key $1"$oldrc{$key}",/; } delete $oldrc{$key}; } sub disable { my ( $key, $type ) = @_; if ( $type eq 'sq' ) { $newrc =~ s/^( *)'$key'/$1# '$key'/m; } else { $newrc =~ s/^( *)$key\b/$1# $key/m; } } sub enable { my $key = shift; $newrc =~ s/^( *)# *'$key'/$1'$key'/m; return if $newrc =~ /^ *'$key'/m; $newrc =~ s/(add new commands here.*\n)/$1 '$key',\n/; } sub miw { my ( $m, $w ) = @_; return 0 unless $oldrc{$w}; my @in = @{ $oldrc{$w} }; my @out = grep { !/^$m$/ } @{ $oldrc{$w} }; $oldrc{$w} = \@out; return not scalar(@in) == scalar(@out); }