Skip to content

Instantly share code, notes, and snippets.

@Hounddog
Created September 27, 2012 09:16

Revisions

  1. Hounddog created this gist Sep 27, 2012.
    241 changes: 241 additions & 0 deletions CopyPropertyTask.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,241 @@
    <?php
    /**
    * V5
    * LICENSE
    *
    * Insert License here
    *
    * @category Phing
    * @package CopyPropertyTask
    * @copyright Copyright (c) 2012 Doyousoft
    * @license $license_information
    * @version $Id
    */

    /**
    * Inlude Copytask for extending
    */
    require_once "phing/tasks/system/CopyTask.php";

    /**
    * Phing task to Match the hash values of the files to be copied
    * Enables to overwrite files if property changes
    * @category Phing
    * @package CopyPropertyTask
    * @copyright Copyright (c) 2012 Doyousoft
    * @version $Id
    * @license $license_information
    */
    class CopyPropertyTask extends CopyTask
    {
    /**
    * The main entry point where everything gets in motion.
    *
    * @access public
    * @return true on success
    * @throws BuildException
    */
    function main()
    {
    $this->validateAttributes();

    if ($this->file !== null) {
    if ($this->file->exists()) {
    if ($this->destFile === null) {
    $this->destFile = new PhingFile(
    $this->destDir, (string) $this->file->getName()
    );
    }
    if (
    $this->overwrite === true
    || (
    $this->file->lastModified()
    > $this->destFile->lastModified()
    )
    ) {
    $this->fileCopyMap[$this->file->getAbsolutePath()]
    = $this->destFile->getAbsolutePath();
    } else if (
    $this->hashMap(
    $this->file->getAbsolutePath(),
    $this->destFile->getAbsolutePath()
    )
    ) {
    $this->log('needs to be copied');
    } else {
    $this->log(
    $this->file->getName()." omitted, is up to date"
    );
    }
    } else {
    // terminate build
    $this->logError(
    "Could not find file "
    .$this->file->__toString()
    ." to copy."
    );
    }
    }

    $project = $this->getProject();

    // process filelists
    foreach ($this->filelists as $fl) {
    $fromDir = $fl->getDir($project);
    $srcFiles = $fl->getFiles($project);
    $srcDirs = array($fl->getDir($project));

    if (!$this->flatten && $this->mapperElement === null) {
    $this->completeDirMap[$fromDir->getAbsolutePath()]
    = $this->destDir->getAbsolutePath();
    }

    $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs);
    }

    // process filesets
    foreach ($this->filesets as $fs) {
    $ds = $fs->getDirectoryScanner($project);
    $fromDir = $fs->getDir($project);
    $srcFiles = $ds->getIncludedFiles();
    $srcDirs = $ds->getIncludedDirectories();

    if (!$this->flatten && $this->mapperElement === null) {
    $this->completeDirMap[$fromDir->getAbsolutePath()]
    = $this->destDir->getAbsolutePath();
    }

    $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs);
    }

    // go and copy the stuff
    $this->doWork();

    if ($this->destFile !== null) {
    $this->destDir = null;
    }
    }

    /**
    * Compares source files to destination files to see if they
    * should be copied.
    *
    * @access private
    * @param string $fromDir
    * @param string $toDir
    * @param array $files
    * @param array $dirs
    * @return void
    */
    private function _scan(&$fromDir, &$toDir, &$files, &$dirs)
    {
    /* mappers should be generic, so we get the mappers here and
    pass them on to builMap. This method is not redundan like it seems */
    $mapper = null;
    if ($this->mapperElement !== null) {
    $mapper = $this->mapperElement->getImplementation();
    } else if ($this->flatten) {
    $mapper = new FlattenMapper();
    } else {
    $mapper = new IdentityMapper();
    }
    $this->buildMap($fromDir, $toDir, $files, $mapper, $this->fileCopyMap);
    $this->buildMap($fromDir, $toDir, $dirs, $mapper, $this->dirCopyMap);
    }

    /**
    * Builds a map of filenames (from->to) that should be copied
    *
    * @access private
    * @param string $fromDir
    * @param string $toDir
    * @param array $names
    * @param object $mapper
    * @param array $map
    * @return void
    */
    private function buildMap(&$fromDir, &$toDir, &$names, &$mapper, &$map)
    {
    $toCopy = null;
    if ($this->overwrite) {
    $v = array();
    foreach ($names as $name) {
    $result = $mapper->main($name);
    if ($result !== null) {
    $v[] = $name;
    }
    }
    $toCopy = $v;
    } else if ($this->hashMap($fromDir, $toDir, $names, $mapper, $map)) {

    } else {
    $ds = new SourceFileScanner($this);
    $toCopy = $ds->restrict($names, $fromDir, $toDir, $mapper);
    }

    for ($i=0,$_i=count($toCopy); $i < $_i; $i++) {
    $src = new PhingFile($fromDir, $toCopy[$i]);
    $mapped = $mapper->main($toCopy[$i]);
    $dest = new PhingFile($toDir, $mapped[0]);
    $map[$src->getAbsolutePath()] = $dest->getAbsolutePath();
    }
    }

    /**
    * Match the file hashmap of parsed src File and target file
    * @param string &$fromDir
    * @param string &$toDir
    * @param array &$names
    * @param object &$mapper
    * @param array &$map
    */
    protected function hashMap(&$fromDir, &$toDir, &$names, &$mapper, &$map)
    {
    $v = array();
    $toCopy = null;
    foreach ($names as $name) {
    $to = $toDir . '/' . $name;
    $from = $fromDir . '/' .$name;

    $fromFile = new PhingFile($from);
    $toFile = new PhingFile($to);

    $result = null;
    if ($toFile->exists()) {
    $toHash = hash_file('md5', $toFile);

    $mapped = $mapper->main($name);
    $dest = new PhingFile($fromDir, $mapped[0]);
    if (
    (is_array($this->filterChains)) &&
    (!empty($this->filterChains))) {
    $in = $this->fileUtils->getChainedReader(
    new BufferedReader(
    new FileReader($fromFile)
    ),
    $this->filterChains, $this->getProject()
    );

    // New read() methods returns a big buffer.
    while (-1 !== ($buffer = $in->read())) { // -1 indicates EOF
    $fileContents = $buffer;
    }
    if ( $in !== null )
    $in->close();
    }
    $fromHash = md5($fileContents);
    if ($toHash !== $fromHash) {
    if ($toFile->exists() && $toFile->isFile()) {
    $toFile->delete();
    }
    }
    } else {
    $result = $mapper->main($name);
    }
    if ($result !== null) {
    $v[] = $name;
    }
    }
    $toCopy = $v;
    }
    }