
Скрипт на perl'e для заливки сайта из git-репозитория
Вашему вниманию релиз-скрипт. При первом запуске клонирует репозиторий, делает checkout и подготавливает архивы файлов и бд для заливки сайта на сервер. При последующих запусках заливает изменения из коммитов, которые есть в мастерской ветке с последнего успешно залитого коммита.
#!perl # -d:ptkdb # -T use UploadConfig qw($opt); my $file = "./params"; my $params2save = {}; my $dir = "./" . $opt->{project}; my @files2upload; use lib './lib'; use strict; use warnings; #use Git::Class; use Git::Repository; use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); use Net::FTP; use Data::Dumper; $Data::Dumper::Terse = 1; use File::Path qw(rmtree); Upload(); sub Upload { my $filestoupload = getProject(); # parse files before upload dir_walk( $dir, \&parseFile ); unless ( 0 + @$filestoupload ) { createArchives(); } else { ftpUpload($filestoupload); } writeLastCommit(); } sub getProject { my ( $git, $worktree, @files ); #clean rmtree( $opt->{uploadfilesdir} ); my $lastcommit = getLastCommit(); #$lastcommit=1; unless ($lastcommit) { rmtree( "./" . $opt->{project} ); # #clones Git::Repository->run( clone => $opt->{repo} => $dir ); $git = Git::Repository->new( work_tree => $dir ); $git->run( checkout => "master" ); } else { #pull $git = Git::Repository->new( work_tree => $dir ); $git->run( pull => $opt->{repo}, "master" ); #@files =$git->run("diff --name-only ".$lastcommit); my $cmd = $git->command( diff => '--diff-filter=ACM', '--name-only', $lastcommit ); my $log = $cmd->stdout; while (<$log>) { chomp; push @files, $_; print $_. "\n"; } #$cmd->close(); } # die "123"; # Get Last Commit my $out; my $cmd = $git->command( log => '--pretty=oneline', '-1' ); my $log = $cmd->stdout; while (<$log>) { $out .= $_; } # $cmd->close; if ( $out =~ /(\S+)/mi ) { $params2save->{lastCommit} = $1; } return \@files; } sub getLastCommit { local $/ = undef; open my $fh, "<", $file or return undef; my $content = <$fh>; close $fh; #return eval { $content }; return $content; } sub writeLastCommit { open my $fh, ">", $file or die $!; #print $fh Dumper( $params2save->{lastCommit} ); print $fh $params2save->{lastCommit}; close $fh; } sub deleteAllFilesExept { my @files = @{ $_[0] }; } sub parseFile { my $file = shift; my $shortfile = $file; $shortfile =~ s{.*/}{}; return unless ( $opt->{toChange}->{$shortfile} ); my %toChange = %{ $opt->{toChange}->{$shortfile} }; if ( -f $file ) { print "Converting: $file\n"; local $/ = undef; open my $fh, "<", $file or die $!; my $content = <$fh>; close $fh; while ( my ( $old, $new ) = each %toChange ) { if ( $content =~ /$old/ ) { $content =~ s/$old/$new/si; } } open $fh, ">", $file or die "Can't open file $file: $!"; print $fh $content; close $fh; } } sub createArchives { my @arc; mkdir $opt->{uploadfilesdir}; #cgi foreach my $arch ( keys %{ $opt->{zipfiles} } ) { my $zip = Archive::Zip->new(); # my $member = $zip->addDirectory('/'); my $member; my @files; if ( ref $opt->{zipfiles}->{$arch} eq "ARRAY" ) { @files = @{ $opt->{zipfiles}->{$arch} }; } else { push @files, $opt->{zipfiles}->{$arch}; } foreach my $fn (@files) { dir_walk( $opt->{project} . "/" . $fn, sub { my $file = shift; $file =~ s/\.\///; my $zipfile = $file; $zipfile =~ s/^[A-Za-z0-9- ]+\///; my $shortfile = $file; $shortfile =~ s{.*/}{}; my @dirs = split( /\//, $file ); return if ( $fn eq "." and 0 + @dirs > 2 ); unless ( is_in_array( \@dirs, $opt->{toChange}->{excludeFiles} ) ) { $zip->addFile( $file, $zipfile ); print "/$zipfile zipped from $file \n"; } } ); } die 'ZIP write error' unless $zip->writeToFileNamed( $opt->{uploadfilesdir} . "/" . $arch ) == AZ_OK; print "ready $arch\n"; push @arc, $opt->{uploadfilesdir} . "/" . $arch; } return \@arc; } sub ftpUpload { my $files = shift; my $ftp = Net::FTP->new( $opt->{ftp}->{server}, Debug => 0, Passive => 1 ) or die "Cannot connect to some.host.name: $@"; $ftp->login( $opt->{ftp}->{login}, $opt->{ftp}->{password} ) or die "Cannot login ", $ftp->message; $ftp->binary(); print "\n\n uploading files: \n\n"; foreach my $fn (@$files) { next if ( is_in_array( $fn, $opt->{toChange}->{excludeFiles} ) ); my $source = $opt->{project} . "/" . $fn; print "uploading $source\n"; if ( $fn =~ /cgi-bin/ ) { $fn =~ s/cgi-bin\///; my $uploadfn = $opt->{ftp}->{put}->{cgi} . $fn; $uploadfn =~ /(.*\/)(.*?)(\.[^.]*)/g; my $dir = $1; my $dist = $2 . $3; $ftp->cwd($dir); $ftp->put( $source, $dist ) or die "Cannot put $source to $opt->{ftp}->{put}->{cgi}.$fn ", $ftp->message; } else { my $uploadfn = $opt->{ftp}->{put}->{www} . $fn; $uploadfn =~ /(.*\/)(.*?)(\.[^.]*)/g; my $dir = $1; my $dist = $2 . $3; print $dir," ", $dist; $ftp->cwd($dir); $ftp->put( $source, $dist ) or die "Cannot put $source to $opt->{ftp}->{put}->{www}.$fn ", $ftp->message; } } $ftp->quit; } sub dir_walk { my ( $top, $filefunc, $dirfunc ) = @_; my $DIR; if ( -d $top ) { my $file; unless ( opendir $DIR, $top ) { warn "Couldn't open directory top: $!; skipping.\n"; return; } my @results; while ( $file = readdir $DIR ) { next if $file eq '.' || $file eq '..'; push @results, dir_walk( "$top/$file", $filefunc, $dirfunc ); } return $dirfunc ? $dirfunc->( $top, @results ) : (); } elsif ( -f $top ) { return $filefunc ? $filefunc->($top) : (); } } sub is_in_array { my @elements; if ( ref $_[0] eq "ARRAY" ) { @elements = @{ $_[0] } } else { push @elements, $_[0] } my @array; if ( ref $_[1] eq "ARRAY" ) { @array = @{ $_[1] } } else { @array = @_ } die join( ', ', @elements ), "\n", join( ', ', @array ) if ( join(@elements) =~ /git/ ); foreach my $element (@elements) { return 1 if ( grep $_ eq $element, @array ); } return undef; }
Пример файла с настройками:
package UploadConfig; use strict; #use vars qw(@ISA @EXPORT); #use Exporter; use base 'Exporter'; our @EXPORT=qw($opt); our $opt = { project => "site", repo => "c:/sn/xampp/htdocs/site/.git", tempdir => "./temp", uploadfilesdir => "./upload", ftp => { 'server' => 'ftp.***.ru', 'login' => "ftp", 'password' => "***", 'put' => { 'cgi' => "/site.ru/cgi/", 'www' => "/site.ru/docs/", } }, zipfiles => { "cgi.zip" => "cgi-bin", "docs.zip" => [ "images", "js", "cms", "css", "txt", "." ], #!"." - только файлы из корня "db.zip" => "db.sql", }, lastCommitFile => ".lastcommit", toChange => { "main.pl" => { qr{ #\[~\?uselib\].*#\[~!uselib\]}si => qq{ #[~?uselib] my \$serverpath="/home/site/site.ru/"; use lib "/home/site/site.ru/cgi/fuc"; use lib "/home/site/site.ru/cgi/lib"; use lib "/home/site/site.ru/cgi"; #[~!uselib]}, "#!perl\.exe" => "#!/usr/bin/perl" }, excludeFiles => ["MyConfig.pm", ".git"], } };