office-gobmx/bin/lo-pack-sources
2011-07-25 01:02:17 +03:00

655 lines
21 KiB
Perl
Executable file

#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if $running_under_some_shell;
#!/usr/bin/perl
use strict;
use File::Copy;
use File::Temp qw/ tempfile tempdir /;
# get libreoffice-build version from the given libreoffice-build sources
sub get_config_version($)
{
my ($lo_build_dir) = @_;
my $version;
open (CONFIGURE, "$lo_build_dir/configure.in") ||
die "can't open \"$lo_build_dir/configure.in\" for reading: $!\n";
while (my $line = <CONFIGURE>) {
chomp $line;
if ($line =~ /AC_INIT\s*\(\s*libreoffice-build\s*,\s*([\w\.]*)\)/) {
$version="$1";
}
}
close (CONFIGURE);
return $version;
}
# set libreoffice-build version in the given libreoffice-build sources
sub set_config_version($$)
{
my ($lo_build_dir, $version) = @_;
my $configure = "$lo_build_dir/configure.in";
open (CONFIGURE, "$configure") ||
die "can't open \"$configure\" for reading: $!\n";
my ( $tmp_fh, $tmp_filename ) = tempfile( "$configure.XXXXXX" );
if ( !defined $tmp_fh ) {
close (CONFIGURE);
die "Error: can't create temporary file: \"$configure.XXXXXX\"\n";
}
while (my $line = <CONFIGURE>) {
chomp $line;
if ($line =~ /^(\s*AC_INIT\s*\(\s*libreoffice-build\s*,\s*)([\w\.]*)(\s*\)\s*)$/) {
print ${tmp_fh} "$1$version$3\n";
} else {
print ${tmp_fh} "$line\n";
}
}
close (CONFIGURE);
close (${tmp_fh});
# preserve permissions on target file by applying them to temp file
my ( $mode, $uid, $gid ) = ( stat($configure) )[ 2, 4, 5 ];
$mode = $mode & 07777;
chmod $mode, $tmp_filename;
chown $uid, $gid, $tmp_filename;
rename ($tmp_filename, $configure) ||
die "Can't rename \"$tmp_filename\" to \"$configure\": $!\n";
}
# increment the version for a test build:
# + add 'a' if the version ended with a number
# + bump the letter otherwise
sub inc_test_version($)
{
my ($version) = @_;
my $lastchar = chop $version;
my $new_version;
if ($lastchar =~ /\d/) {
return "$version" . "$lastchar" . "a";
} elsif ($lastchar =~ /\w/) {
# select next letter alhabeticaly: a->b, b->c, ...
$lastchar =~ tr/0a-zA-Z/a-zA-Z0/;
return "$version" . "$lastchar";
} else {
die "Can't generate test version from \"$version$lastchar\n";
}
}
sub get_release_version($$$$)
{
my ($config_version, $state_config_version, $state_release_version, $inc_version) = @_;
my $release_version;
if (defined $state_config_version &&
defined $state_release_version &&
"$state_config_version" eq "$config_version") {
$release_version = "$state_release_version";
} else {
$release_version = "$config_version";
}
if ( defined $inc_version ) {
$release_version = inc_test_version($release_version);
}
return $release_version;
}
sub generate_lo_build_blacklist($)
{
my ($blacklist) = @_;
# FIXME: crazy hacks to copy libreoffice-build without too big and useless subdirectories and to show a progress
open (BLACKLIST, ">$blacklist") || die "Can't open $blacklist: $!\n";
# IMPORTANT: Do not remove .git directories because "git log" is called during "make dist"
print BLACKLIST "*/.svn\n";
print BLACKLIST "rawbuild/*\n";
print BLACKLIST "build/*\n";
print BLACKLIST "clone/*\n";
print BLACKLIST "src/libreoffice-*.tar.bz2\n";
print BLACKLIST "src/????????????????????????????????-*\n";
close BLACKLIST;
}
sub generate_lo_piece_blacklist($)
{
my ($blacklist) = @_;
# FIXME: crazy hacks to copy libreoffice-build without too big and useless subdirectories and to show a progress
open (BLACKLIST, ">$blacklist") || die "Can't open $blacklist: $!\n";
# IMPORTANT: Do not remove .git directories because "git log" is called during "make dist"
print BLACKLIST ".git\n";
print BLACKLIST ".gitignore\n";
print BLACKLIST ".gitattributes\n";
print BLACKLIST "autom4te.cache/*\n";
print BLACKLIST "autom4te.cache\n";
print BLACKLIST "autogen.lastrun\n";
print BLACKLIST "clone/*\n";
print BLACKLIST "config.log\n";
print BLACKLIST "config.parms\n";
print BLACKLIST "git-hooks\n";
print BLACKLIST "Env.Host.sh\n";
print BLACKLIST "src/tmp*\n";
print BLACKLIST "src/fetch.log\n";
print BLACKLIST "src/libreoffice-*.tar.bz2\n";
print BLACKLIST "src/????????????????????????????????-*\n";
print BLACKLIST "warn\n";
close BLACKLIST;
}
# remove symlinks to clone subdir
sub remove_module_symlinks($$)
{
my ($tempdir, $piece_tarball_name) = @_;
print STDERR "find $tempdir/$piece_tarball_name -mindepth 1 -maxdepth 1 -type l -exec rm {} \\;\n";
system ("find $tempdir/$piece_tarball_name -mindepth 1 -maxdepth 1 -type l -exec rm {} \\;") &&
die "Error: can't delete symlinks to clone dir in $tempdir: $!\n";
}
# copy files to temp dir; showing a progress; using a black list
sub copy_dir_filter_and_show_progress($$$)
{
my ($source_dir, $target_dir, $blacklist) = @_;
print "Copying \"$source_dir\" -> \"$target_dir\"...";
# FIXME: crazy hacks to copy dir with a blacklist and showing a progress
system ("tar -cf - -C $source_dir -X $blacklist \.\/ | " .
"tar -xf - -C $target_dir --checkpoint 2>&1 | " .
"awk '{ ORS=\"\" ; if (++nlines\%50 == 0) printf \".\"; fflush() }'") &&
die "Error: copying failed: $!\n";
print "\n";
}
# copy the local version of libreoffice-build into a tmp directory
# omit the .svn subdirectories
sub copy_lo_build_to_tempdir($)
{
my ($lo_build_dir) = @_;
my $tempdir = tempdir( 'libreoffice-XXXXXX', DIR => File::Spec->tmpdir );
my $blacklist = "$tempdir/libreoffice-build.copy.blacklist";
generate_lo_build_blacklist($blacklist);
copy_dir_filter_and_show_progress($lo_build_dir, $tempdir, $blacklist);
unlink $blacklist;
return $tempdir;
}
# copy the piece lo source directory into a tmp directory
# omit the .git subdirectories
sub copy_lo_piece_to_tempdir($$$)
{
my ($piece_dir, $piece, $piece_tarball_name) = @_;
my $tempdir = tempdir( 'libreoffice-XXXXXX', DIR => File::Spec->tmpdir );
my $blacklist = "$tempdir/libreoffice-$piece.copy.blacklist";
mkdir "$tempdir/$piece_tarball_name" || die "Can't create directory \"$tempdir/$piece_tarball_name\": $!\n";
generate_lo_piece_blacklist($blacklist);
copy_dir_filter_and_show_progress("$piece_dir", "$tempdir/$piece_tarball_name", $blacklist);
remove_module_symlinks($tempdir, $piece_tarball_name);
unlink $blacklist;
return $tempdir;
}
sub generate_lo_piece_changelog($$$)
{
my ($lo_piece_clone, $lo_piece_release_dir, $piece) = @_;
print "Generating changelog for $piece...\n";
print "1:$lo_piece_clone, 2:$lo_piece_release_dir, 3:$piece\n";
# FIXME: crazy hacks to copy dir with a blacklist and showing a progress
system ("cd $lo_piece_clone && " .
"git log --date=short --pretty='format:@%cd %an <%ae> [%H]%n%n%s%n%n%e%b' | " .
" sed -e 's|^\([^@]\)|\t\1|' -e 's|^@||' >$lo_piece_release_dir/ChangeLog" ) &&
die "Error: generating failed: $!\n";
}
sub run_autoreconf($$)
{
my ($dir, $piece) = @_;
print "Running autoreconf for $piece...\n";
system ("cd $dir && " .
"autoreconf -f -i && " .
"rm -rf autom4te.cache && " .
"cd - >/dev/null 2>&1") && die "Error: autoreconf failed: $!\n";
}
sub generate_version_file($$$)
{
my ($dir, $piece, $release_version) = @_;
# FIXME: crazy hacks to copy libreoffice-build without too big and useless subdirectories and to show a progress
open (VERFILE, ">$dir/$piece.ver") || die "Can't open $dir/lo-$piece.ver: $!\n";
print VERFILE "lo_bootstrap_ver=$release_version\n";
close VERFILE;
}
sub release_lo_build($)
{
my ($lo_build_dir) = @_;
print "Creating libreoffice-build tarball...\n";
system ("cd $lo_build_dir && " .
"./autogen.sh --with-distro=GoOoLinux && " .
"make dist && " .
"cd - >/dev/null 2>&1") && die "Error: releasing failed: $!\n";
}
sub release_lo_piece($$)
{
my ($lo_piece_dir, $piece_tarball_name) = @_;
print "Creating $piece_tarball_name.tar.bz2...";
system ("cd $lo_piece_dir && " .
"tar -cjf $piece_tarball_name.tar.bz2 --checkpoint * 2>&1 | awk '{ ORS=\"\" ; if (++nlines\%50 == 0) printf \".\"; fflush() }' && " .
"cd - >/dev/null 2>&1") && die "Error: releasing failed: $!\n";
print "\n";
}
sub generate_md5($$$)
{
my ($dir, $tarball_name, $tarball_suffix) = @_;
print "Generating MD5...\n";
system ("cd $dir && " .
"md5sum $tarball_name$tarball_suffix >$tarball_name$tarball_suffix.md5 && " .
"cd - >/dev/null 2>&1") && die "Error: releasing failed: $!\n";
}
sub default_releases_state_file($)
{
my ($lo_build_dir) = @_;
my $rootdir = $lo_build_dir;
$rootdir =~ s/^(.*?)\/?[^\/]+\/?$/$1/;
my $releases_state_file;
if ($rootdir) {
$releases_state_file = "$rootdir/.releases";
} else {
$releases_state_file = ".releases";
}
return "$releases_state_file";
}
sub default_releases_archive($)
{
my ($lo_build_dir) = @_;
my $rootdir = $lo_build_dir;
$rootdir =~ s/^(.*?)\/?[^\/]+\/?$/$1/;
my $releases_archive_dir;
if ($rootdir) {
$releases_archive_dir = "$rootdir/archive";
} else {
$releases_archive_dir = "archive";
}
return "$releases_archive_dir";
}
sub load_releases_state($)
{
my ($releases_state_file) = @_;
my $state_config_version;
my $state_release_version;
if (open (STATE, "$releases_state_file")) {
while (my $line = <STATE>) {
chomp $line;
if ($line =~ /^\s*configure_version\s*=\s*(.*)$/) {
$state_config_version = "$1";
} elsif ($line =~ /^\s*released_version\s*=\s*(.*)$/) {
$state_release_version = "$1";
}
}
close (STATE);
}
return $state_config_version, $state_release_version;
}
sub save_releases_state($$$)
{
my ($releases_state_file, $config_version, $release_version) = @_;
open (STATE, '>', "$releases_state_file") ||
die "Can't open \"$releases_state_file\" for writing: $!\n";
print STATE "configure_version = $config_version\n";
print STATE "released_version = $release_version\n";
close (STATE);
}
sub remove_tempdir($)
{
my ($tempdir) = @_;
# print "Cleaning $tempdir...\n";
system ("rm -rf $tempdir") && die "Error: rm failed: $!\n";
}
sub save_file($$$)
{
my ($source_dir, $target_dir, $file) = @_;
unless ( -d "$target_dir" ) {
mkdir ("$target_dir") ||
die "Can't create directory \"$target_dir\": $!\n";
}
if ( -f "$target_dir/$file" ) {
print "Warning: $target_dir/$file already exists and will be replaced\n";
unlink ("$target_dir/$file");
}
print "Copying into archive: $target_dir/$file ...\n";
copy ("$source_dir/$file", "$target_dir/$file") ||
die "Error: Can't copy $source_dir/$file to $target_dir/$file: $!\n";
}
sub check_if_file_exists($$)
{
my ($file, $force) = @_;
if (-e $file) {
if (defined $force) {
print "Warning: $file already exists and will be replaced!\n";
} else {
die "Error: $file alrady exists.\n".
" Use --force if you want to replace it.\n";
}
}
}
sub check_if_tarball_already_released($$$)
{
my ($tarball, $releases_archive_dir, $force) = @_;
check_if_file_exists($tarball, $force);
check_if_file_exists("$releases_archive_dir/$tarball", $force) if (defined $releases_archive_dir);
}
sub check_if_already_released($$$$$$)
{
my ($lo_build_tarball_name, $p_piece_tarball_name, $releases_archive_dir, $force, $pack_lo_build, $pack_lo_pieces) = @_;
check_if_tarball_already_released("$lo_build_tarball_name.tar.gz", $releases_archive_dir, $force) if ($pack_lo_build);
if ($pack_lo_pieces) {
foreach my $tarball_name ( values %{$p_piece_tarball_name} ) {
check_if_tarball_already_released("$tarball_name.tar.bz2", $releases_archive_dir, $force);
}
}
}
sub prepare_lo_build_tarball($$$$)
{
my ($lo_build_dir, $release_version, $md5, $lo_build_tarball_name) = @_;
my $temp_dir = copy_lo_build_to_tempdir("$lo_build_dir");
set_config_version($temp_dir, $release_version);
release_lo_build($temp_dir);
generate_md5($temp_dir, $lo_build_tarball_name, ".tar.gz") if (defined $md5);
return $temp_dir;
}
sub prepare_lo_piece_tarball($$$$$)
{
my ($piece_dir, $release_version, $md5, $piece, $piece_tarball_name) = @_;
my $temp_dir = copy_lo_piece_to_tempdir($piece_dir, $piece, $piece_tarball_name);
generate_lo_piece_changelog($piece_dir, "$temp_dir/$piece_tarball_name", $piece);
run_autoreconf("$temp_dir/$piece_tarball_name", $piece) if ($piece eq 'bootstrap');
generate_version_file("$temp_dir/$piece_tarball_name", $piece, $release_version) if ($piece eq 'bootstrap');
release_lo_piece($temp_dir, $piece_tarball_name);
generate_md5($temp_dir, $piece_tarball_name, ".tar.bz2") if (defined $md5);
return $temp_dir;
}
sub move_tarball_to_final_location($$$$)
{
my ($temp_dir, $releases_archive_dir, $md5, $tarball) = @_;
save_file($temp_dir, ".", "$tarball");
save_file($temp_dir, ".", "$tarball.md5") if (defined $md5);
if ( defined $releases_archive_dir ) {
save_file($temp_dir, $releases_archive_dir, "$tarball");
save_file($temp_dir, $releases_archive_dir, "$tarball.md5") if (defined $md5);
}
remove_tempdir($temp_dir);
}
sub generate_tarballs($$$$$$$$$)
{
my ($source_dir, $releases_archive_dir, $release_version, $md5, $lo_build_tarball_name, $p_piece_tarball_name, $pack_lo_build, $pack_lo_pieces, $is_lo_build_dir) = @_;
if ($pack_lo_build) {
# my $temp_dir=prepare_lo_build_tarball($source_dir, $release_version, $md5, $lo_build_tarball_name);
# move_tarball_to_final_location($temp_dir, $releases_archive_dir, $md5, "$lo_build_tarball_name.tar.gz");
my $temp_dir=prepare_lo_piece_tarball($source_dir, $release_version, $md5, "bootstrap", $lo_build_tarball_name);
move_tarball_to_final_location($temp_dir, $releases_archive_dir, $md5, "$lo_build_tarball_name.tar.bz2");
}
if ($pack_lo_pieces) {
my $piece_dir = $source_dir;
foreach my $piece ( keys %{$p_piece_tarball_name} ) {
print "\n--- Generating $piece ---\n";
$piece_dir = "$source_dir/clone/$piece" if ($is_lo_build_dir);
my $temp_dir=prepare_lo_piece_tarball($piece_dir, $release_version, $md5, $piece, $p_piece_tarball_name->{$piece});
move_tarball_to_final_location($temp_dir, $releases_archive_dir, $md5, "$p_piece_tarball_name->{$piece}.tar.bz2");
}
}
}
sub usage()
{
print "This tool helps to pack the libreoffice-build and piece sources\n\n" .
"Usage:\n".
"\tlo-pack-sources [--help] [--force] [--version]\n" .
"\t [--set-version=<ver>] [--inc-version] [--md5]\n" .
"\t [--no-lo-build] [--no-lo-pieces] [--piece=<piece>]\n" .
"\t [dir]\n\n" .
"Options:\n\n" .
"\t--help: print this help\n" .
"\t--force: replace an already existing release of the same version\n" .
"\t--version: just print version of the released package but do not\n" .
"\t\trelease it; the version is affected by the other options, e.g.\n" .
"\t\t--inc-version\n" .
"\t--set-version: force another version\n" .
"\t--inc-version: increment the latest version; there is a difference\n" .
"\t\tbetween test release (default) and final (not yet supported)\n" .
"\t--md5: generate md5 sum for the final tarball\n" .
"\t--no-lo-build: do not pack the libreoffice-build tarball\n" .
"\t--no-lo-pieces: do not pack the libreoffice-build piece sources\n" .
"\t--piece=<piece>: pack just a single piece, .e.g. \"writer\",\n" .
"\tdir: path of the source directory, either libreoffice-build or piece\n";
}
my $ptf;
my $md5;
my $inc_version;
my $config_version;
my $set_version;
my $get_config_version;
my $release_version;
my $pack_lo_build=1;
my $pack_lo_pieces=1;
my $source_dir;
my $releases_archive_dir;
my $releases_state_file;
my $state_config_version;
my $state_release_version;
my $lo_build_tarball_name;
my $lo_build_tempdir;
my $force;
my $verbose=1;
my $is_lo_build_dir=0;
my @pieces=("artwork", "base", "calc", "components",
"extensions", "extras", "filters", "help", "impress",
"libs-core", "libs-extern", "libs-extern-sys", "libs-gui",
"postprocess", "sdk", "testing", "translations", "ure", "writer");
my %piece_tarball_name;
###################
# Arguments parsing
###################
for my $arg (@ARGV) {
if ($arg eq '--help' || $arg eq '-h') {
usage;
exit 0;
} elsif ($arg eq '--force') {
$force=1;
} elsif ($arg eq '--md5') {
$md5=1;
} elsif ($arg eq '--version') {
$get_config_version=1;
$verbose = undef;
} elsif ($arg eq '--inc-version') {
$inc_version=1
} elsif ($arg =~ m/--set-version=(.*)/) {
$set_version="$1";
} elsif ($arg eq '--no-lo-build') {
$pack_lo_build=0;
} elsif ($arg eq '--no-lo-pieces') {
$pack_lo_pieces=0;
} elsif ($arg =~ m/--piece=(.*)/) {
# process just one piece and do not pack libreoffice-build
@pieces=();
push @pieces, "$1";
$pack_lo_build=0;
} elsif ($arg =~ /^-/ ) {
die "Error: unknown option: $arg\n";
} else {
if (! defined $source_dir) {
$source_dir = $arg;
} else {
die "Error: Too many arguments $arg\n";
}
}
}
###################
# Initial checks
###################
unless ( defined $source_dir ) {
die "Error: undefined source directory, try --help\n";
}
unless ( -d "$source_dir" ) {
die "Error: is not a directory: $source_dir\n";
}
# check if it is a valid libreoffice-bootstrap directory
$is_lo_build_dir=1 if (-f "$source_dir/autogen.sh" && -f "$source_dir/set_soenv.in");
# all tarballs are generated from the libreoffice-bootstrap directory
if (@pieces > 1 && $is_lo_build_dir == 0 ) {
die "Error: \"$source_dir\" is not a valid libreoffice-bootstrap directory\n";
}
# just a single piece tarball can be generated from piece directory; version must be explicitely set in this case
if (@pieces == 1 && $is_lo_build_dir == 0 && ! defined $set_version ) {
die "Error: version must be set using the --set-version=<version> option\n" unless (defined $set_version);
}
if (defined $set_version && defined $inc_version) {
die "Error: --set-version and --inc-version options can't be used together\n";
}
###################
# Main logic
###################
print "Source: $source_dir\n" if ($verbose);
if ($is_lo_build_dir) {
# detect some paths
$releases_state_file = default_releases_state_file($source_dir) unless (defined $releases_state_file);
$releases_archive_dir = default_releases_archive($source_dir) unless (defined $releases_archive_dir);
# detect versions
$config_version = get_config_version($source_dir);
($state_config_version, $state_release_version) = load_releases_state($releases_state_file);
if (defined $set_version) {
$release_version = "$set_version";
} else {
$release_version = get_release_version($config_version, $state_config_version, $state_release_version, $inc_version);
}
} else {
# must be single piece release with predefined version
$release_version = "$set_version";
}
# define tarball names
$lo_build_tarball_name = "libreoffice-bootstrap-$release_version";
foreach my $piece (@pieces) {
$piece_tarball_name{$piece} = "libreoffice-$piece-$release_version";
}
print "Default version : $config_version\n" if ($verbose && defined $config_version);
print "Last used version : $state_release_version\n" if ($verbose && defined $state_release_version);
print "New version : $release_version\n" if ($verbose);
# do the real job
if ( defined $get_config_version ) {
print "$release_version\n";
} else {
check_if_already_released($lo_build_tarball_name, \%piece_tarball_name, $releases_archive_dir, $force, $pack_lo_build, $pack_lo_pieces);
# give a chance to stop the process
print ("\nWaiting 3 seconds...\n");
sleep 3;
generate_tarballs($source_dir, $releases_archive_dir, $release_version, $md5, $lo_build_tarball_name, \%piece_tarball_name, $pack_lo_build, $pack_lo_pieces, $is_lo_build_dir);
if ( defined $releases_state_file ) {
save_releases_state($releases_state_file, $config_version, $release_version);
}
}