# -*- mode: Perl -*- # Copyright (c) 2007-2008 Fabien Tassin # Description: MozClient::VCS - Main class # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ############################################################################ package MozClient::VCS; # This is the main class. It should not be used directly. VCS specific classes # should be instantiated instead. They inherit from this main class and # overwrite some methods according to VCS requirements. use Carp; use strict; my $nobinonly = "nobinonly"; # List of dependencies my $dependencies = { 'cvs' => '/usr/bin/cvs', 'mercurial' => '/usr/bin/hg', 'git' => '/usr/bin/git', 'quilt' => '/usr/bin/quilt', 'wget' => '/usr/bin/wget', }; ############################################################################ sub new { my $class = shift; my $conf = shift; my $opt = shift; my $self = {}; @{$self}{keys %$conf} = values %$conf; $self->{'want_branch'} = $$opt{'branch'}; $self->{'want_listtags'} = 1 if $$opt{'list-tags'}; $self->{'want_tag'} = $$opt{'tag'}; $self->{'have_date'} = $$opt{'date'}; $self->{'preserve_vcs'} = $$opt{'preserve-vcs'}; $self->{'debug'} = $$opt{'debug'}; $self->{'want_branch'} = $$conf{'MOZCLIENT_BRANCH'} if defined $$conf{'MOZCLIENT_BRANCH'} && !defined $self->{'want_branch'}; # The following options overwrite the conf files $self->{'MOZCLIENT_EMBEDDED'} = 1 if $$opt{'embedded'}; $self->{'MOZ_CO_MODULE'} = $$opt{'modules'} if defined $$opt{'modules'}; bless($self, $class); $self; } sub vcs { my $self = shift; $self->{'MOZCLIENT_VCS'}; } sub work_dir { my $self = shift; $self->{'work-dir'} = shift if @_; $self->{'work-dir'}; } sub debug { my $self = shift; $self->{'debug'} = shift if @_; $self->{'debug'}; } sub LOG { my $self = shift; my $str = shift; printf "LOG: $str\n", @_ if $self->debug; } sub LOG2 { my $self = shift; my $str = shift; printf "$str\n", @_; } sub check_dependencies { my $self = shift; $self->LOG("MozClient::check_dependencies()"); my $missing = []; map { push @$missing, $_ unless -x $$dependencies{$_}} keys %$dependencies; carp "# Error: missing dependencies. Please install " . (join ", ", @$missing) . "\n" if $#$missing >= 0; 1; } sub cleanup_dir { my $self = shift; if (-d $self->work_dir) { $self->LOG("MozClient::cleanup_dir()"); $self->run_system("rm -rf " . $self->work_dir); } } sub prepare_dir { my $self = shift; $self->LOG("MozClient::prepare_dir()"); $self->cleanup_dir(); $self->mkdir($self->work_dir, 0755); } sub run_system { my $self = shift; $self->LOG2("\$ %s", @_); my $cmd = sprintf "%s", @_; my $args = &main::_split_args($cmd); my $ret = system(@$args); $ret == 0 || confess "Can't run '$cmd': error code $ret"; } sub run_shell { my $self = shift; $self->LOG2("\$ %s", @_); my $cmd = shift; return `$cmd`; } sub chdir { my $self = shift; $self->LOG2("\$ cd %s", @_); my $dir = shift; CORE::chdir($dir) || confess "Can't chdir($dir): $!"; } sub unlink { my $self = shift; $self->LOG2("\$ rm %s", @_); my $file = shift; CORE::unlink($file) || confess "Can't unlink($file): $!"; } sub mkdir { my $self = shift; my $dir = shift; my $mode = shift; $self->LOG2("\$ mkdir %s", $dir); CORE::mkdir($dir, $mode) || confess "Can't mkdir($dir, $mode): $!"; } sub want_list_tags { my $self = shift; defined $self->{'want_listtags'} && $self->{'want_listtags'}; } sub list_tags { my $self = shift; $self->LOG("MozClient::list_tags()"); confess "Error: list_tags() not supported for " . $self->vcs; } # Execute the command defined in MOZCLIENT_POSTCOCMD after the checkout sub do_post_co_commands { my $self = shift; $self->LOG("MozClient::do_post_co_commands()"); $self->chdir($self->work_dir); $self->run_shell($self->{'MOZCLIENT_POSTCOCMD'}); $self->chdir(".."); } sub get_client { my $self = shift; $self->LOG("MozClient::get_client()"); confess "Can't MozClient::get_client() for " . $self->vcs; } sub set_tag { my $self = shift; $self->LOG("MozClient::set_tag()"); confess "Can't MozClient::set_tag() for " . $self->vcs; } sub set_revdate { my $self = shift; $self->LOG("MozClient::set_revdate()"); confess "Can't MozClient::set_revdate() for " . $self->vcs; } sub convert_revdate { my $self = shift; $self->LOG("MozClient::convert_revdate()"); confess "Can't MozClient::convert_revdate() for " . $self->vcs; } sub do_dynamic_tag { my $self = shift; $self->LOG("MozClient::do_dynamic_tag()"); confess "Error: do_dynamic_tag() not supported for " . $self->vcs; } sub setup { my $self = shift; $self->LOG("MozClient::setup()"); $self->{'mozclient_date'} = ""; $self->{'moz_co_tag'} = ""; if (!defined $self->{'want_tag'} && defined $self->{'MOZCLIENT_DYNTAG'}) { $self->do_dynamic_tag(); } if (defined $self->{'want_tag'}) { # We want a tag, we can either let mozclient compute the version or # specify our own (using -t TAG=version) if (defined $self->{'have_date'}) { warn "Warning: can't use -d and -t together. Ignoring -d"; undef $self->{'have_date'}; } $self->{'want_tag'} =~ m/([^=]*)(=?)(.*)/; $self->{'ltag'} = $1; $self->{'dtag'} = $3; $self->set_tag($1); } else { # we don't want a specific tag, so go for a date and possibly a branch if (!defined $self->{'have_date'}) { chomp($self->{'have_date'} = `$self->{'MOZCLIENT_GETDATE'}`); } $self->{'mozclient_date'} = '-D "' . $self->convert_revdate($self->{'have_date'}) . '"'; $self->{'co_tag'} = ''; $self->{'co_tag'} = "-r " . $self->{'want_branch'} if defined $self->{'want_branch'}; } } sub checkout { my $self = shift; $self->LOG("MozClient::checkout()"); confess "Can't MozClient::checkout() for " . $self->vcs; } sub nobin_cleanup { my $self = shift; $self->LOG("MozClient::nobin_cleanup()"); $self->chdir($self->work_dir . "/" . $self->{'MOZCLIENT_MOZDIRNAME'}); my $cmd = sprintf "sh %s > REMOVED+${nobinonly}.txt 2>&1", $self->{'MOZCLIENT_EXCLUDE_SCRIPT'}; if (-e $self->{'MOZCLIENT_EXCLUDE_SCRIPT'}) { $self->run_shell($cmd); } else { $self->LOG("*warn* can't find " . $self->{'MOZCLIENT_EXCLUDE_SCRIPT'}); } # Run a package specific clean-up script, if any my $pkg_script = $self->{'MOZCLIENT_EXCLUDE_SCRIPT'}; $pkg_script =~ m,/([^/]*)$,; my $pkg = $self->{'MOZCLIENT_APPNAME'} . '-' . $1; $pkg_script =~ s,(.*)/.*,$1/$pkg,; $self->run_shell("sh $pkg_script >> REMOVED+${nobinonly}.txt 2>&1") if -e $pkg_script; # Remove the log if it's empty $self->unlink("REMOVED+${nobinonly}.txt") if -e "REMOVED+${nobinonly}.txt" && -z "REMOVED+${nobinonly}.txt"; $self->chdir("../.."); } sub tar_exclude { my $self = shift; $self->LOG("MozClient::tar_exclude()"); # nothing []; } sub pack { my $self = shift; $self->LOG("MozClient::pack()"); my $tar_exclude = ""; unless ($self->{'preserve_vcs'}) { my $dirs = $self->tar_exclude();; if (defined $self->{'MOZCLIENT_TAREXCLUDE'}) { for my $item (@{$self->{'MOZCLIENT_TAREXCLUDE'}}) { push @$dirs, "--exclude $item"; } } $tar_exclude = join " ", @$dirs; } my $tversion; if (defined $self->{'want_tag'} && defined $self->{'dtag'} && length $self->{'dtag'} > 0) { $tversion = $self->{'dtag'}; } else { $self->chdir($self->work_dir); chomp($tversion = `$self->{'MOZCLIENT_GETVERSION'}`); $tversion .= $self->{'MOZCLIENT_SEPARATOR'} . $self->{'MOZCLIENT_VCS'} . $self->{'have_date'} unless defined $self->{'want_tag'}; $self->LOG2("\$ tversion=`" . $self->{'MOZCLIENT_GETVERSION'} . "` # => $tversion"); $self->chdir(".."); } my $version = $tversion; $version .= "+${nobinonly}" if -f $self->work_dir . "/" . $self->{'MOZCLIENT_MOZDIRNAME'} . "/REMOVED+${nobinonly}.txt"; my $cmd = sprintf "rm -rf %s/%s-%s", $self->work_dir, $self->{'MOZCLIENT_APPNAME'}, $version; $self->run_system($cmd); if ($self->{'MOZCLIENT_EMBEDDED'} || $self->{'MOZCLIENT_WANTMOZDIR'}) { my $dir = sprintf "%s/%s-%s", $self->work_dir, $self->{'MOZCLIENT_APPNAME'}, $version; $self->mkdir($dir, 0755); } if ($self->{'MOZCLIENT_EMBEDDED'}) { my $project = $self->{'MOZCLIENT_PROJECT'}; $project =~ s,/.*,,; if ($self->{'MOZCLIENT_WANTMOZDIR'}) { $self->chdir($self->work_dir); my $cmd = sprintf "tar jcf %s-%s/%s-%s-source.tar.bz2 %s %s", $self->{'MOZCLIENT_APPNAME'}, $version, $project, $tversion, $tar_exclude, $self->{'MOZCLIENT_MOZDIRNAME'}; $self->run_system($cmd); $self->chdir(".."); } else { # Embedded tarball but without the toplevel mozilla dir $self->chdir($self->work_dir . "/" . $self->{'MOZCLIENT_MOZDIRNAME'}); my $cmd = sprintf "tar jcf ../%s-%s/%s-%s-source.tar.bz2 %s .", $self->{'MOZCLIENT_APPNAME'}, $version, $project, $tversion, $tar_exclude; $self->run_system($cmd); $self->chdir("../.."); } } else { my $cmd = sprintf "mv %s/%s %s/%s-%s/", $self->work_dir, $self->{'MOZCLIENT_MOZDIRNAME'}, $self->work_dir, $self->{'MOZCLIENT_APPNAME'}, $version; $self->run_system("$cmd"); } $self->unlink($self->{'MOZCLIENT_APPNAME'} . "_$version.orig.tar.gz") if -f $self->{'MOZCLIENT_APPNAME'} . "_$version.orig.tar.gz"; $self->chdir($self->work_dir); $cmd = sprintf "tar zcf ../%s_%s.orig.tar.gz %s %s-%s", $self->{'MOZCLIENT_APPNAME'}, $version, $tar_exclude, $self->{'MOZCLIENT_APPNAME'}, $version; $self->run_shell($cmd); $self->chdir(".."); $self->run_system("rm -rf " . $self->work_dir); $self->run_system("ls -l " . $self->{'MOZCLIENT_APPNAME'} . "_$version.orig.tar.gz"); } 1;