Author: kn
Date: Thu Sep 20 13:37:01 2007
New Revision: 6220

Log:
- Added the ezcBaseFile::copyRecursive() method, to recursively copy files or
  directories

Added:
    trunk/Base/tests/file_copy_recursive_test.php   (with props)
Modified:
    trunk/Base/ChangeLog
    trunk/Base/src/file.php
    trunk/Base/tests/suite.php

Modified: trunk/Base/ChangeLog
==============================================================================
--- trunk/Base/ChangeLog [iso-8859-1] (original)
+++ trunk/Base/ChangeLog [iso-8859-1] Thu Sep 20 13:37:01 2007
@@ -1,3 +1,9 @@
+1.4alpha2 - [RELEASEDATE]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Added the ezcBaseFile::copyRecursive() method, to recursively copy files or
+  directories
+
 1.4alpha1 - Tuesday 18 September 2007
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

Modified: trunk/Base/src/file.php
==============================================================================
--- trunk/Base/src/file.php [iso-8859-1] (original)
+++ trunk/Base/src/file.php [iso-8859-1] Thu Sep 20 13:37:01 2007
@@ -169,6 +169,89 @@
     }
 
     /**
+    * Recursively copy a file or directory.
+    *
+    * Recursively copy a file or directory in $source to the given
+    * destination. If a depth is given, the operation will stop, if the given
+    * recursion depth is reached. A depth of -1 means no limit, while a depth
+    * of 0 means, that only the current file or directory will be copied,
+    * without any recursion.
+    *
+    * You may optionally define modes used to create files and directories.
+    *
+    * @throws ezcBaseFileNotFoundException
+    *      If the $sourceDir directory is not a directory or does not exist.
+    * @throws ezcBaseFilePermissionException
+    *      If the $sourceDir directory could not be opened for reading, or the
+    *      destination is not writeable.
+    *
+    * @param string $source
+    * @param string $destination
+    * @param int $depth
+    * @param int $dirMode
+    * @param int $fileMode
+    * @return void
+    */
+    static public function copyRecursive( $source, $destination, $depth = -1, 
$dirMode = 0775, $fileMode = 0664 )
+    {
+        // Check if source file exists at all.
+        if ( !is_file( $source ) && !is_dir( $source ) )
+        {
+            throw new ezcBaseFileNotFoundException( $source );
+        }
+
+        // Destination file should NOT exist
+        if ( is_file( $destination ) || is_dir( $destination ) )
+        {
+            throw new ezcBaseFilePermissionException( $destination, 
ezcBaseFileException::WRITE );
+        }
+
+        // Skip non readable files in source directory
+        if ( !is_readable( $source ) )
+        {
+            return;
+        }
+
+        // Copy
+        if ( is_dir( $source ) )
+        {
+            mkdir( $destination );
+            // To ignore umask, umask() should not be changed with
+            // multithreaded servers...
+            chmod( $destination, $dirMode );
+        }
+        elseif ( is_file( $source ) )
+        {
+            copy( $source, $destination );
+            chmod( $destination, $fileMode );
+        }
+
+        if ( ( $depth === 0 ) ||
+            ( !is_dir( $source ) ) )
+        {
+            // Do not recurse (any more)
+            return;
+        }
+
+        // Recurse
+        $dh = opendir( $source );
+        while( $file = readdir( $dh ) )
+        {
+            if ( ( $file === '.' ) ||
+                ( $file === '..' ) )
+            {
+                continue;
+            }
+
+            self::copyRecursive(
+                $source . '/' . $file,
+                $destination . '/' . $file,
+                $depth - 1, $dirMode, $fileMode
+            );
+        }
+    }
+
+    /**
      * Calculates the relative path of the file/directory '$path' to a given
      * $base path.
      * This method does not touch the filesystem.

Added: trunk/Base/tests/file_copy_recursive_test.php
==============================================================================
--- trunk/Base/tests/file_copy_recursive_test.php (added)
+++ trunk/Base/tests/file_copy_recursive_test.php [iso-8859-1] Thu Sep 20 
13:37:01 2007
@@ -1,0 +1,234 @@
+<?php
+/**
+ * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ * @version //autogentag//
+ * @filesource
+ * @package Base
+ * @subpackage Tests
+ */
+
+/**
+ * @package Base
+ * @subpackage Tests
+ */
+class ezcBaseFileCopyRecursiveTest extends ezcTestCase
+{
+    protected function setUp()
+    {
+        $this->tempDir = $this->createTempDir( __CLASS__ );
+        mkdir( $this->tempDir . '/dir1' );
+        mkdir( $this->tempDir . '/dir2' );
+        mkdir( $this->tempDir . '/dir2/dir1' );
+        mkdir( $this->tempDir . '/dir2/dir1/dir1' );
+        mkdir( $this->tempDir . '/dir2/dir2' );
+        mkdir( $this->tempDir . '/dir4' );
+        mkdir( $this->tempDir . '/dir5' );
+        mkdir( $this->tempDir . '/dir6' );
+        file_put_contents( $this->tempDir . '/dir1/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir1/file2.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir1/.file3.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir2/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir2/dir1/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir2/dir1/dir1/file1.txt', 
'test' );
+        file_put_contents( $this->tempDir . '/dir2/dir1/dir1/file2.txt', 
'test' );
+        file_put_contents( $this->tempDir . '/dir2/dir2/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir4/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir4/file2.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir5/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir5/file2.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir6/file1.txt', 'test' );
+        file_put_contents( $this->tempDir . '/dir6/file2.txt', 'test' );
+        chmod( $this->tempDir . '/dir4/file1.txt', 0 );
+        chmod( $this->tempDir . '/dir5', 0 );
+        chmod( $this->tempDir . '/dir6', 0400 );
+    }
+
+    protected function tearDown()
+    {
+        chmod( $this->tempDir . '/dir5', 0700 );
+        chmod( $this->tempDir . '/dir6', 0700 );
+        $this->removeTempDir();
+    }
+
+    public function testRecursiveCopyEmptyDir()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir1',
+            $this->tempDir . '/dest'
+        );
+
+        $this->assertEquals( 
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dir1' ) ),
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) 
+        );
+
+        $this->assertSame(
+            0775,
+            fileperms( $this->tempDir . '/dest' ) & 0777,
+            'Directory mode should equal 0775.'
+        );
+    }
+
+    public function testRecursiveCopyFile()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir1/file1.txt',
+            $this->tempDir . '/dest'
+        );
+
+        $this->assertTrue(
+            is_file( $this->tempDir . '/dest' )
+        );
+
+        $this->assertSame(
+            0664,
+            fileperms( $this->tempDir . '/dest' ) & 0777,
+            'File mode should equal 0664.'
+        );
+    }
+
+    public function testRecursiveCopyEmptyDirMode()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir1',
+            $this->tempDir . '/dest',
+            -1,
+            0777,
+            0777
+        );
+
+        $this->assertEquals( 
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dir1' ) ),
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) 
+        );
+
+        $this->assertSame(
+            0777,
+            fileperms( $this->tempDir . '/dest' ) & 0777,
+            'Directory mode should equal 0777.'
+        );
+    }
+
+    public function testRecursiveCopyFileMode()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir1/file1.txt',
+            $this->tempDir . '/dest',
+            -1,
+            0777,
+            0777
+        );
+
+        $this->assertTrue(
+            is_file( $this->tempDir . '/dest' )
+        );
+
+        $this->assertSame(
+            0777,
+            fileperms( $this->tempDir . '/dest' ) & 0777,
+            'File mode should equal 0777.'
+        );
+    }
+
+    public function testRecursiveCopyFullDir()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir2',
+            $this->tempDir . '/dest'
+        );
+
+        $this->assertEquals( 
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dir2' ) ),
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) 
+        );
+    }
+
+    public function testRecursiveCopyFullDirDepthZero()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir2',
+            $this->tempDir . '/dest',
+            0
+        );
+
+        $this->assertEquals( 
+            0,
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) 
+        );
+
+        $this->assertTrue(
+            is_dir( $this->tempDir . '/dest' )
+        );
+    }
+
+    public function testRecursiveCopyFullDirLimitedDepth()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir2',
+            $this->tempDir . '/dest',
+            2
+        );
+
+        $this->assertEquals( 
+            3,
+            count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) 
+        );
+    }
+
+    public function testRecursiveCopyFailureNotExisting()
+    {
+        try
+        {
+            ezcBaseFile::copyRecursive( 
+                $this->tempDir . '/not_existing',
+                $this->tempDir . '/dest'
+            );
+        }
+        catch ( ezcBaseFileNotFoundException $e )
+        {
+            return;
+        }
+
+        $this->fail( 'Expected ezcBaseFileNotFoundException.' );
+    }
+
+    public function testRecursiveCopyFailureNotReadable()
+    {
+        ezcBaseFile::copyRecursive( 
+            $this->tempDir . '/dir5',
+            $this->tempDir . '/dest'
+        );
+
+        $this->assertFalse(
+            is_dir( $this->tempDir . '/dest' )
+        );
+
+        $this->assertFalse(
+            is_file( $this->tempDir . '/dest' )
+        );
+    }
+
+    public function testRecursiveCopyFailureNotWriteable()
+    {
+        try
+        {
+            ezcBaseFile::copyRecursive( 
+                $this->tempDir . '/dir2',
+                $this->tempDir . '/dir4'
+            );
+        }
+        catch ( ezcBaseFilePermissionException $e )
+        {
+            return;
+        }
+
+        $this->fail( 'Expected ezcBaseFilePermissionException.' );
+    }
+
+    public static function suite()
+    {
+         return new PHPUnit_Framework_TestSuite( __CLASS__ );
+    }
+}
+?>

Propchange: trunk/Base/tests/file_copy_recursive_test.php
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/Base/tests/suite.php
==============================================================================
--- trunk/Base/tests/suite.php [iso-8859-1] (original)
+++ trunk/Base/tests/suite.php [iso-8859-1] Thu Sep 20 13:37:01 2007
@@ -14,6 +14,7 @@
 require_once( "struct_test.php");
 require_once 'file_find_recursive_test.php';
 require_once 'file_is_absolute_path.php';
+require_once 'file_copy_recursive_test.php';
 require_once 'file_remove_recursive_test.php';
 require_once 'file_calculate_relative_path_test.php';
 
@@ -36,6 +37,7 @@
         $this->addTest( ezcBaseFileCalculateRelativePathTest::suite() );
         $this->addTest( ezcBaseFileFindRecursiveTest::suite() );
         $this->addTest( ezcBaseFileIsAbsoluteTest::suite() );
+        $this->addTest( ezcBaseFileCopyRecursiveTest::suite() );
         $this->addTest( ezcBaseFileRemoveRecursiveTest::suite() );
     }
 


-- 
svn-components mailing list
[email protected]
http://lists.ez.no/mailman/listinfo/svn-components

Reply via email to