541 lines
14 KiB
PHP
541 lines
14 KiB
PHP
<?php
|
|
/*
|
|
* $Id: CvsTask.php 905 2010-10-05 16:28:03Z mrook $
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* This software consists of voluntary contributions made by many individuals
|
|
* and is licensed under the LGPL. For more information please see
|
|
* <http://phing.info>.
|
|
*/
|
|
|
|
require_once 'phing/Task.php';
|
|
include_once 'phing/tasks/system/ExecTask.php';
|
|
include_once 'phing/types/Commandline.php';
|
|
|
|
/**
|
|
* Task for performing CVS operations.
|
|
*
|
|
* NOTE: This implementation has been moved here from Cvs.java with
|
|
* the addition of some accessors for extensibility. Another task
|
|
* can extend this with some customized output processing.
|
|
*
|
|
* @author Hans Lellelid <hans@xmpl.org> (Phing)
|
|
* @author costin@dnt.ro (Ant)
|
|
* @author stefano@apache.org (Ant)
|
|
* @author Wolfgang Werner <wwerner@picturesafe.de> (Ant)
|
|
* @author Kevin Ross <kevin.ross@bredex.com> (Ant)
|
|
* @version $Revision: 905 $
|
|
* @package phing.tasks.system
|
|
*/
|
|
class CvsTask extends Task {
|
|
|
|
/**
|
|
* Default compression level to use, if compression is enabled via
|
|
* setCompression( true ).
|
|
*/
|
|
const DEFAULT_COMPRESSION_LEVEL = 3;
|
|
|
|
private $cmd;
|
|
|
|
/**
|
|
* List of Commandline children
|
|
* @var array Commandline[]
|
|
*/
|
|
private $commandlines = array();
|
|
|
|
/**
|
|
* the CVSROOT variable.
|
|
*/
|
|
private $cvsRoot;
|
|
|
|
/**
|
|
* the CVS_RSH variable.
|
|
*/
|
|
private $cvsRsh;
|
|
|
|
/**
|
|
* the package/module to check out.
|
|
*/
|
|
private $cvsModule;
|
|
|
|
/**
|
|
* the default command.
|
|
*/
|
|
private static $default_command = "checkout";
|
|
|
|
/**
|
|
* the CVS command to execute.
|
|
*/
|
|
private $command = null;
|
|
|
|
/**
|
|
* suppress information messages.
|
|
*/
|
|
private $quiet = false;
|
|
|
|
/**
|
|
* compression level to use.
|
|
*/
|
|
private $compression = 0;
|
|
|
|
/**
|
|
* report only, don't change any files.
|
|
*/
|
|
private $noexec = false;
|
|
|
|
/**
|
|
* CVS port
|
|
*/
|
|
private $port = 0;
|
|
|
|
/**
|
|
* CVS password file
|
|
* @var File
|
|
*/
|
|
private $passFile = null;
|
|
|
|
/**
|
|
* the directory where the checked out files should be placed.
|
|
* @var File
|
|
*/
|
|
private $dest;
|
|
|
|
private $error;
|
|
|
|
private $output;
|
|
|
|
/**
|
|
* If true it will stop the build if cvs exits with error.
|
|
* Default is false. (Iulian)
|
|
* @var boolean
|
|
*/
|
|
private $failOnError = false;
|
|
|
|
public function init() {
|
|
$this->cmd = new Commandline();
|
|
}
|
|
|
|
/**
|
|
* Sets up the environment for toExecute and then runs it.
|
|
* @param Commandline $toExecute
|
|
* @throws BuildException
|
|
*/
|
|
protected function runCommand(Commandline $toExecute) {
|
|
|
|
// We are putting variables into the script's environment
|
|
// and not removing them (!) This should be fine, but is
|
|
// worth remembering and testing.
|
|
|
|
if ($this->port > 0) {
|
|
putenv("CVS_CLIENT_PORT=".$this->port);
|
|
}
|
|
|
|
// Need a better cross platform integration with <cvspass>, so
|
|
// use the same filename.
|
|
|
|
if ($this->passFile === null) {
|
|
$defaultPassFile = new PhingFile(Phing::getProperty("cygwin.user.home", Phing::getProperty("user.home"))
|
|
. DIRECTORY_SEPARATOR . ".cvspass");
|
|
if($defaultPassFile->exists()) {
|
|
$this->setPassfile($defaultPassFile);
|
|
}
|
|
}
|
|
|
|
if ($this->passFile !== null) {
|
|
if ($this->passFile->isFile() && $this->passFile->canRead()) {
|
|
putenv("CVS_PASSFILE=" . $this->passFile->__toString());
|
|
$this->log("Using cvs passfile: " . $this->passFile->__toString(), Project::MSG_INFO);
|
|
} elseif (!$this->passFile->canRead()) {
|
|
$this->log("cvs passfile: " . $this->passFile->__toString()
|
|
. " ignored as it is not readable", Project::MSG_WARN);
|
|
} else {
|
|
$this->log("cvs passfile: " . $this->passFile->__toString()
|
|
. " ignored as it is not a file",
|
|
Project::MSG_WARN);
|
|
}
|
|
}
|
|
|
|
if ($this->cvsRsh !== null) {
|
|
putenv("CVS_RSH=".$this->cvsRsh);
|
|
}
|
|
|
|
// Use the ExecTask to handle execution of the command
|
|
$exe = new ExecTask($this->project);
|
|
$exe->setProject($this->project);
|
|
|
|
//exe.setAntRun(project);
|
|
if ($this->dest === null) {
|
|
$this->dest = $this->project->getBaseDir();
|
|
}
|
|
|
|
if (!$this->dest->exists()) {
|
|
$this->dest->mkdirs();
|
|
}
|
|
|
|
if ($this->output !== null) {
|
|
$exe->setOutput($this->output);
|
|
}
|
|
|
|
if ($this->error !== null) {
|
|
$exe->setError($this->error);
|
|
}
|
|
|
|
$exe->setDir($this->dest);
|
|
|
|
if (is_object($toExecute)) {
|
|
$toExecuteStr = $toExecute->__toString(); // unfortunately no more automagic for initial 5.0.0 release :(
|
|
}
|
|
|
|
$exe->setCommand($toExecuteStr);
|
|
|
|
try {
|
|
$actualCommandLine = $toExecuteStr; // we converted to string above
|
|
$this->log($actualCommandLine, Project::MSG_INFO);
|
|
$retCode = $exe->execute();
|
|
$this->log("retCode=" . $retCode, Project::MSG_DEBUG);
|
|
/*Throw an exception if cvs exited with error. (Iulian)*/
|
|
if ($this->failOnError && $retCode !== 0) {
|
|
throw new BuildException("cvs exited with error code "
|
|
. $retCode
|
|
. PHP_EOL
|
|
. "Command line was ["
|
|
. $toExecute->describeCommand() . "]", $this->getLocation());
|
|
}
|
|
} catch (IOException $e) {
|
|
if ($this->failOnError) {
|
|
throw new BuildException($e, $this->getLocation());
|
|
} else {
|
|
$this->log("Caught exception: " . $e, Project::MSG_WARN);
|
|
}
|
|
} catch (BuildException $e) {
|
|
if ($this->failOnError) {
|
|
throw $e;
|
|
} else {
|
|
$t = $e->getCause();
|
|
if ($t === null) {
|
|
$t = $e;
|
|
}
|
|
$this->log("Caught exception: " . $t, Project::MSG_WARN);
|
|
}
|
|
} catch (Exception $e) {
|
|
if ($this->failOnError) {
|
|
throw new BuildException($e, $this->getLocation());
|
|
} else {
|
|
$this->log("Caught exception: " . $e, Project::MSG_WARN);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return void
|
|
* @throws BuildException
|
|
*/
|
|
public function main() {
|
|
|
|
$savedCommand = $this->getCommand();
|
|
|
|
if ($this->getCommand() === null && empty($this->commandlines)) {
|
|
// re-implement legacy behaviour:
|
|
$this->setCommand(self::$default_command);
|
|
}
|
|
|
|
$c = $this->getCommand();
|
|
$cloned = null;
|
|
if ($c !== null) {
|
|
$cloned = $this->cmd->__copy();
|
|
$cloned->createArgument(true)->setLine($c);
|
|
$this->addConfiguredCommandline($cloned, true);
|
|
}
|
|
|
|
try {
|
|
for ($i = 0, $vecsize=count($this->commandlines); $i < $vecsize; $i++) {
|
|
$this->runCommand($this->commandlines[$i]);
|
|
}
|
|
|
|
// finally {
|
|
if ($cloned !== null) {
|
|
$this->removeCommandline($cloned);
|
|
}
|
|
$this->setCommand($savedCommand);
|
|
|
|
} catch (Exception $e) {
|
|
// finally {
|
|
if ($cloned !== null) {
|
|
$this->removeCommandline($cloned);
|
|
}
|
|
$this->setCommand($savedCommand);
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The CVSROOT variable.
|
|
*
|
|
* @param string $root
|
|
*/
|
|
public function setCvsRoot($root) {
|
|
|
|
// Check if not real cvsroot => set it to null
|
|
if ($root !== null) {
|
|
if (trim($root) == "") {
|
|
$root = null;
|
|
}
|
|
}
|
|
|
|
$this->cvsRoot = $root;
|
|
}
|
|
|
|
public function getCvsRoot() {
|
|
return $this->cvsRoot;
|
|
}
|
|
|
|
/**
|
|
* The CVS_RSH variable.
|
|
*
|
|
* @param rsh
|
|
*/
|
|
public function setCvsRsh($rsh) {
|
|
// Check if not real cvsrsh => set it to null
|
|
if ($rsh !== null) {
|
|
if (trim($rsh) == "") {
|
|
$rsh = null;
|
|
}
|
|
}
|
|
|
|
$this->cvsRsh = $rsh;
|
|
}
|
|
|
|
public function getCvsRsh() {
|
|
return $this->cvsRsh;
|
|
}
|
|
|
|
/**
|
|
* Port used by CVS to communicate with the server.
|
|
*
|
|
* @param int $port
|
|
*/
|
|
public function setPort($port){
|
|
$this->port = $port;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getPort() {
|
|
return $this->port;
|
|
}
|
|
|
|
/**
|
|
* Password file to read passwords from.
|
|
*
|
|
* @param passFile
|
|
*/
|
|
public function setPassfile(PhingFile $passFile) {
|
|
$this->passFile = $passFile;
|
|
}
|
|
|
|
/**
|
|
* @return File
|
|
*/
|
|
public function getPassFile() {
|
|
return $this->passFile;
|
|
}
|
|
|
|
/**
|
|
* The directory where the checked out files should be placed.
|
|
*
|
|
* @param PhingFile $dest
|
|
*/
|
|
public function setDest(PhingFile $dest) {
|
|
$this->dest = $dest;
|
|
}
|
|
|
|
public function getDest() {
|
|
return $this->dest;
|
|
}
|
|
|
|
/**
|
|
* The package/module to operate upon.
|
|
*
|
|
* @param string $p
|
|
*/
|
|
public function setModule($m) {
|
|
$this->cvsModule = $m;
|
|
}
|
|
|
|
public function getModule(){
|
|
return $this->cvsModule;
|
|
}
|
|
|
|
/**
|
|
* The tag of the package/module to operate upon.
|
|
* @param string $p
|
|
*/
|
|
public function setTag($p) {
|
|
// Check if not real tag => set it to null
|
|
if ($p !== null && trim($p) !== "") {
|
|
$this->appendCommandArgument("-r");
|
|
$this->appendCommandArgument($p);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This needs to be public to allow configuration
|
|
* of commands externally.
|
|
*/
|
|
public function appendCommandArgument($arg) {
|
|
$this->cmd->createArgument()->setValue($arg);
|
|
}
|
|
|
|
/**
|
|
* Use the most recent revision no later than the given date.
|
|
* @param p
|
|
*/
|
|
public function setDate($p) {
|
|
if ($p !== null && trim($p) !== "") {
|
|
$this->appendCommandArgument("-D");
|
|
$this->appendCommandArgument($p);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The CVS command to execute.
|
|
* @param string $c
|
|
*/
|
|
public function setCommand($c) {
|
|
$this->command = $c;
|
|
}
|
|
|
|
public function getCommand() {
|
|
return $this->command;
|
|
}
|
|
|
|
/**
|
|
* If true, suppress informational messages.
|
|
* @param boolean $q
|
|
*/
|
|
public function setQuiet($q) {
|
|
$this->quiet = $q;
|
|
}
|
|
|
|
/**
|
|
* If true, report only and don't change any files.
|
|
*
|
|
* @param boolean $ne
|
|
*/
|
|
public function setNoexec($ne) {
|
|
$this->noexec = (boolean) $ne;
|
|
}
|
|
|
|
/**
|
|
* Stop the build process if the command exits with
|
|
* a return code other than 0.
|
|
* Defaults to false.
|
|
* @param boolean $failOnError
|
|
*/
|
|
public function setFailOnError($failOnError) {
|
|
$this->failOnError = (boolean) $failOnError;
|
|
}
|
|
|
|
/**
|
|
* Configure a commandline element for things like cvsRoot, quiet, etc.
|
|
* @return string
|
|
*/
|
|
protected function configureCommandline($c) {
|
|
if ($c === null) {
|
|
return;
|
|
}
|
|
$c->setExecutable("cvs");
|
|
|
|
if ($this->cvsModule !== null) {
|
|
$c->createArgument()->setLine($this->cvsModule);
|
|
}
|
|
if ($this->compression > 0 && $this->compression < 10) {
|
|
$c->createArgument(true)->setValue("-z" . $this->compression);
|
|
}
|
|
if ($this->quiet) {
|
|
$c->createArgument(true)->setValue("-q");
|
|
}
|
|
if ($this->noexec) {
|
|
$c->createArgument(true)->setValue("-n");
|
|
}
|
|
if ($this->cvsRoot !== null) {
|
|
$c->createArgument(true)->setLine("-d" . $this->cvsRoot);
|
|
}
|
|
}
|
|
|
|
protected function removeCommandline(Commandline $c) {
|
|
$idx = array_search($c, $this->commandlines, true);
|
|
if ($idx === false) {
|
|
return false;
|
|
}
|
|
$this->commandlines = array_splice($this->commandlines, $idx, 1);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Configures and adds the given Commandline.
|
|
* @param insertAtStart If true, c is
|
|
*/
|
|
public function addConfiguredCommandline(Commandline $c, $insertAtStart = false) {
|
|
if ($c === null) {
|
|
return;
|
|
}
|
|
$this->configureCommandline($c);
|
|
if ($insertAtStart) {
|
|
array_unshift($this->commandlines, $c);
|
|
} else {
|
|
array_push($this->commandlines, $c);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* If set to a value 1-9 it adds -zN to the cvs command line, else
|
|
* it disables compression.
|
|
* @param int $level
|
|
*/
|
|
public function setCompressionLevel($level) {
|
|
$this->compression = $level;
|
|
}
|
|
|
|
/**
|
|
* If true, this is the same as compressionlevel="3".
|
|
*
|
|
* @param boolean $usecomp If true, turns on compression using default
|
|
* level, AbstractCvsTask.DEFAULT_COMPRESSION_LEVEL.
|
|
*/
|
|
public function setCompression($usecomp) {
|
|
$this->setCompressionLevel($usecomp ?
|
|
self::DEFAULT_COMPRESSION_LEVEL : 0);
|
|
}
|
|
|
|
/**
|
|
* File to which output should be written.
|
|
* @param PhingFile $output
|
|
*/
|
|
function setOutput(PhingFile $f) {
|
|
$this->output = $f;
|
|
}
|
|
|
|
/**
|
|
* File to which error output should be written.
|
|
* @param PhingFile $output
|
|
*/
|
|
function setError(PhingFile $f) {
|
|
$this->error = $f;
|
|
}
|
|
|
|
}
|