#!/usr/bin/perl -w BEGIN { if ( exists $ENV{'CCM_TOOLS_HOME'} && defined $ENV{'CCM_TOOLS_HOME'} ) { if ( -d "$ENV{'CCM_TOOLS_HOME'}/lib" ) { push @INC, "$ENV{'CCM_TOOLS_HOME'}/lib"; } else { print "$ENV{'CCM_TOOLS_HOME'}/lib was not found\n"; exit 1; } } else { print "The CCM_TOOLS_HOME environment variable must be set first.\n"; exit 1; } } use strict; use CCM::Interpolate('interpolate_file'); use CCM::Runtime; use CCM::Util; use File::Find; use File::Path; use File::Spec; use Getopt::Long; use Sys::Hostname; my $OS = $^O; my $installed = 0; my $verbose = 0; my $dummy = 0; my $type = "application"; my $extends; my $extends_version; my $appname; my $webapponly = 0; my $hostname = hostname(); my $ccmversion = '6.1'; my $runtime = CCM::Runtime->new(); my $nextport; my $newdevdir = 0; GetOptions('verbose+' => \$verbose, 'dummy' => \$dummy, 'type=s' => \$type, 'extends=s' => \$extends, 'appname=s' => \$appname, 'webapponly' => \$webapponly, 'version=s' => \$ccmversion); my $ccmrootdir = defined $ENV{'CCM_ZIP_ROOT'} ? $ENV{'CCM_ZIP_ROOT'} : $OS eq 'MSWin32' ? File::Spec->catdir(File::Spec->rootdir(),'ccm') : File::Spec->rootdir(); my $templatedir = defined $ENV{'CCM_TEMPLATE_DIR'} ? $ENV{'CCM_TEMPLATE_DIR'} : File::Spec->catdir($ccmrootdir,'usr','share','ccm-devel','template'); my $ccmdevelroot = defined $ENV{'CCM_DEVEL_ROOT'} ? $ENV{'CCM_DEVEL_ROOT'} : File::Spec->catdir($ccmrootdir,'var','ccm-devel'); my $ccmtoolshome = defined $ENV{'CCM_TOOLS_HOME'} ? $ENV{'CCM_TOOLS_HOME'} : File::Spec->catdir($ccmrootdir,'usr','share','tools'); my $etcdir = File::Spec->catdir($ccmrootdir,'etc'); my $scratchdir = File::Spec->catdir($ccmrootdir,'var','tmp'); my $devdir = File::Spec->catdir($ccmdevelroot,'dev'); my $webdir = File::Spec->catdir($ccmdevelroot,'web'); my $portalloc = File::Spec->catfile($ccmrootdir,'var','lib','ccm-devel','portalloc.txt'); my $resinconf5x = File::Spec->catfile($etcdir,'ccm-devel','resin.conf.in'); my $resinconf = File::Spec->catfile($ccmtoolshome,'server','resin','conf','resin-devel.conf.in'); my $tomcatconf5x = File::Spec->catfile($etcdir,'ccm-devel','server.xml.in'); my $tomcatconf = File::Spec->catfile($ccmtoolshome,'server','tomcat','conf','server-devel.xml.in'); my $nocvsroot = File::Spec->catdir($ccmrootdir,'temp','no-cvsroot'); my $envvars = File::Spec->catfile($etcdir,'ccm-devel','envvars.in'); my $ccmdevelhome = defined $ENV{'CCM_DEVEL_HOME'} ? $ENV{'CCM_DEVEL_HOME'} : defined $ENV{'CCM_CONFIG_HOME'} ? $ENV{'CCM_CONFIG_HOME'} : File::Spec->catdir($ccmrootdir,'usr','share','ccm-devel'); my $JAVA_CMD = $runtime->getJavaCommand(); if ($OS eq 'MSWin32') { if ($#ARGV != 1) { &show_help(); } } else { if ($#ARGV != 0 && $#ARGV != 1) { &show_help(); } } my $project = $ARGV[0]; my $user = undef; if ($#ARGV == 1) { $user = $ARGV[1]; } elsif (defined $ENV{'USER'}) { $user = $ENV{'USER'}; } elsif (defined $ENV{'LOGNAME'}) { $user = $ENV{'LOGNAME'}; } else { &myerror("cannot determine username, please specify as the last argument to the command"); } my $doimport = exists $ENV{'CCM_DEVEL_CVSROOT'} ? ($webapponly ? 0 : 1) : 0; my $cvsroot; if ($doimport) { $cvsroot = $ENV{'CCM_DEVEL_CVSROOT'}; # untaint $cvsroot if ( $cvsroot =~ m!^([\w\.:/-]+)$! ) { # $cvsroot only contains alphanumeric, ':', '/', and '.' $cvsroot = $1; } else { &myerror("cvsroot contains invalid characters - $cvsroot"); } } else { $cvsroot = $nocvsroot; } if ($project =~ /^((?:\w|-)+)$/) { # $project only contains 'word' characters and is untainted $project = $1; } else { &myerror("The project name can only contain letters, numbers, hyphens and underscores"); } if ($user =~ /^((?:\w|-)+)$/) { # $user only contains 'word' characters and is untainted $user = $1; } else { &myerror("The user name can only contain letters, numbers, hyphens and underscores"); } my $logfile = File::Spec->catfile($scratchdir, "ccm-devel-create-$project-$user.log"); # untaint $ENV{'PATH'} so that we can run 'system' # $ENV{'PATH'} = '/bin:/usr/bin'; if (defined $extends && !$webapponly) { my @dirs = glob ($ENV{CCM_DIST_HOME} . "/projects/$extends-*"); if ($#dirs == -1) { &myerror("cannot find parent project '$extends' in $ENV{CCM_DIST_HOME}/projects/"); } else { my ($version, $major, $minor, $revision); foreach (@dirs) { if (m|(\d+)\.(\d+)\.(\d+)|) { my $newer = 0; if (!defined $version) { $newer = 1; } else { if ($1 > $major) { $newer = 1; } elsif ($1 == $major) { if ($2 > $minor) { $newer = 1; } elsif ($2 == $minor) { if ($3 > $revision) { $newer = 1; } } } } if ($newer) { ($major, $minor, $revision) = ($1, $2, $3); $version = "$major.$minor.$revision"; } } } $extends_version = $version; } } $appname = $project unless $appname; if (! -d File::Spec->catdir($devdir,$user)) { &myerror("'" . File::Spec->catdir($devdir,$user) . "' does not exist. The system administrator needs to" . " create your account by running 'ccm-devel-user $user'"); } &init(); my $globalvars = { 'appname' => $appname, 'buildOrder' => ($ccmversion eq '5x' || $ccmversion eq '6.0') ? " buildOrder=\"1\"" : "", 'ccm-devel-home' => (($OS eq "MSWin32") ? "/" : "") . &all_forward_slashes($ccmdevelhome), 'ccm-version' => $ccmversion, 'deploy-dir' => &all_forward_slashes("$webdir/$user/$project"), 'dev-dir' => &all_forward_slashes("$devdir/$user/$project"), 'extends' => defined $extends ? "extends=\"$extends\" extendsVersion=\"$extends_version\"" : "", 'hostname' => $hostname, 'http-port' => $nextport, 'log-dir' => File::Spec->canonpath("$webdir/$user/$project/logs"), 'package' => $project, 'port' => $nextport, 'project' => $project, 'root-dir' => File::Spec->canonpath("$webdir/$user/$project"), 'servlet-engine' => 'servlet23', 'shutdown-port' => $nextport + 1, 'type' => $type, 'user' => $user, 'versionfromattr' => ($ccmversion eq '5x' || $ccmversion eq '6.0') ? "versionFrom=\"$project\"" : "", 'webapp-dir' => File::Spec->canonpath("$webdir/$user/$project/webapps/ccm"), 'webapp-root' => File::Spec->canonpath("$webdir/$user/$project/webapps"), 'work-dir' => File::Spec->canonpath("$webdir/$user/$project/tmp") }; &sanity_check(); if (!$webapponly) { if ($doimport) { if (!$installed) { &clone_template(); &import_app(); } &checkout_app(); } else { &clone_template(); } } &make_webapp(); ¬ify_user(); &cleanup(); exit 0; sub show_help { print STDERR " syntax: ccm-devel-create.pl [--verbose] [--dummy] [--extends ] [--type project|application] [--version ] [user] If your project is based on CCM Core 5.x or 6.0, you must set the --version flag to '5x' or '6.0', accordingly. The '--extends' and '--type' options only apply to projects on CCM Core 5.x or 6.0. If your operating system does not set the \$USER or \$LOGNAME environment variable (ie, MS Windows), then supply your username as the last argument ccm-devel-create.pl project aplaws "; exit -1; } sub init { if (-f $portalloc . ".bak") { unlink $portalloc . ".bak"; } $SIG{__DIE__} = \&abort; $nextport = &next_port(); } sub sanity_check { if ($doimport) { chdir $scratchdir; if (-x "$project-$user") { rmtree("$project-$user"); if (-x "$project-$user") { &myerror("cannot remove existing project directory " . File::Spec->catdir($scratchdir,"$project-$user")); } } system("CVSROOT=$cvsroot cvs -q co -l $project 1> $logfile 2>&1") != 0 or $installed = 1; } if (-d File::Spec->catdir($devdir,$user,$project) && !$webapponly) { &myerror("a project is already checked out by the name $project"); } if (-d File::Spec->catdir($webdir,$user,$project)) { &myerror("a project has already been deployed with the name $project"); } } sub clone_template { my $basedir; if ($doimport) { chdir $scratchdir; $basedir = "$project-$user"; } else { chdir File::Spec->catdir($devdir,$user); $basedir = $project; } mkdir ($basedir, 0777) unless $dummy; $newdevdir = 1; my @dirs = (); my @files = (); my $endchars; find(sub { if (-d && $File::Find::name ne $templatedir) { push @dirs, $File::Find::name } }, $templatedir); find(sub { if (-f) { push @files, $File::Find::name } }, $templatedir); if ($OS eq 'MSWin32') { $endchars = '@@'; } else { $endchars = '::'; } foreach (@dirs) { next if /CVS/; chomp; my $templatesub = "$templatedir"; $templatesub =~ s/\\/\\\\/g; s/$templatesub.//; s/$endchars(\w+)$endchars/exists $globalvars->{$1} ? $globalvars->{$1} : $endchars . $1 . $endchars/gex; print "Cloning directory " . File::Spec->catdir($project,$_) . "\n" if $verbose; mkdir (File::Spec->catfile($basedir, $_), 0777) unless $dummy; } foreach my $src (@files) { next if $src =~ /CVS/; chomp $src; my $dst = $src; my $templatesub = $templatedir; $templatesub =~ s/\\/\\\\/g; $dst =~ s/$templatesub.//; $dst =~ s/__(\w+)__/exists $globalvars->{$1} ? $globalvars->{$1} : '__' . $1 . '__'/gex; $dst =~ s/$endchars(\w+)$endchars/exists $globalvars->{$1} ? $globalvars->{$1} : $endchars . $1 . $endchars/gex; print ("Cloning file " . File::Spec->catdir($project,$dst) . "\n") if $verbose; next if $dummy; &interpolate_file('source' => $src, 'destination' => File::Spec->catfile($basedir, $dst), 'vars' => $globalvars); } find( sub { if (m/\.sh$/ || m/\.pl$/) { chmod 0755, $File::Find::name}}, $basedir); } sub import_app { return unless $doimport; chdir File::Spec->catdir($scratchdir,"$project-$user"); print "Importing $project-$user\n" if $verbose; return if $dummy; &myrun("CVSROOT=$cvsroot cvs -q import -m 'Initial import of application template' $project $project initial 1>> $logfile 2>&1"); } sub checkout_app { return unless $doimport; chdir File::Spec->catdir($devdir,$user); print "Checking out $project\n" if $verbose; return if $dummy; &myrun("CVSROOT=$cvsroot cvs -q co $project 1>> $logfile 2>&1"); chdir $project; } sub make_webapp { if (!$webapponly) { chdir File::Spec->catdir($devdir,$user,$project); &interpolate_file('source' => "ant.properties.in", 'destination' => "ant.properties", 'vars' => $globalvars); unlink("ant.properties.in"); &myrun('ccm-configure'); } chdir File::Spec->catdir($webdir,$user); print "Creating webapp root\n" if $verbose; return if $dummy; mkdir $project, 0777; chdir $project; mkdir 'webapps', 0777; mkdir 'logs', 0777; mkdir 'conf', 0777; &do_interp($envvars, File::Spec->catfile($webdir,$user,$project,'conf','envvars')); mkdir 'tmp', 0777; mkdir 'data', 0777; my $interp_count = 0; if ($ccmversion eq '5x' || $ccmversion eq '6.0') { $interp_count = &do_interp($resinconf5x, File::Spec->catfile($webdir,$user,$project,'conf','resin.conf')) + &do_interp($tomcatconf5x, File::Spec->catfile($webdir,$user,$project,'conf','server.xml')); } else { $interp_count = &do_interp($resinconf, File::Spec->catfile($webdir,$user,$project,'conf','resin.conf')) + &do_interp($tomcatconf, File::Spec->catfile($webdir,$user,$project,'conf','server.xml')); } if ($interp_count == 0) { print "WARNING: no ccm-tools servlet container packages found\n"; } } sub do_interp { my $source = shift; my $target = shift; if (-f $source) { &interpolate_file('source' => $source, 'destination' => $target, 'vars' => $globalvars); print "wrote $target\n"; return 1; } else { return 0; } } sub cleanup { rmtree(File::Spec->catdir($scratchdir,"$project-$user")); } sub abort { &cleanup(); if (-f $portalloc . ".bak") { unlink $portalloc; rename $portalloc . ".bak", $portalloc; } if ( $newdevdir && -d File::Spec->catdir($devdir,$user,$project) ) { rmtree(File::Spec->catdir($devdir,$user,$project)); rmtree(File::Spec->catdir($webdir,$user,$project)); } print STDERR "Installation failed: $_[0]\n"; print STDERR "Install logs at $logfile\n"; exit 1; } sub notify_user { if ($webapponly) { print " The webapp root has been created, your server will run on port $nextport. Checkout your application to $devdir/$user/$project "; } else { print " Installation complete; your server will run on port $nextport. "; } } sub next_port { open PORT, "<$portalloc" or &myerror("cannot open port allocation file: $portalloc"); my $port = ; chomp $port; close PORT; &myerror("corrupt port allocation file") unless $port =~ /^\d+$/; my $nextport = $port + 2; rename $portalloc, $portalloc . ".bak"; open PORT, ">$portalloc" or &myerror("cannot write port allocation file"); print PORT $nextport, "\n"; close PORT; return $port; } sub all_forward_slashes { # takes in a string, turns all backslashes to forward slashes, and returns the string my $in = shift; $in =~ s!\\!/!g; return $in; } sub myerror { &abort(@_); } sub myrun { system(@_); if ($?) { &myerror("cannot run @_ script: $!"); } } # This is the end, my only friend, the end.