Skip to content

Commit

Permalink
Merge pull request #1078 from humanmade/1072-fix-excluded-file-size-d…
Browse files Browse the repository at this point in the history
…isplay

1072: Fix excluded files and directory included sizes
  • Loading branch information
willmot committed Sep 21, 2016
2 parents 8cb2a9d + 548227d commit cf5579a
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 30 deletions.
36 changes: 20 additions & 16 deletions admin/schedule-form-excludes.php
Expand Up @@ -96,7 +96,7 @@

$untrusted_directory = urldecode( $_GET['hmbkp_directory_browse'] );

// Only allow real sub directories of the site root to be browsed.
// Only allow real sub-directories of the site root to be browsed.
if (
false !== strpos( $untrusted_directory, Path::get_root() ) &&
is_dir( $untrusted_directory )
Expand All @@ -105,8 +105,6 @@
}
}

$exclude_string = implode( '|', $excludes->get_excludes_for_regex() );

$site_size = new Site_Size( 'file' );
$excluded_site_size = new Site_Size( 'file', $excludes );

Expand Down Expand Up @@ -186,8 +184,8 @@
/* translators: 1: Excluded size 2: Overall site size */
printf(
esc_html__( '%1$s of %2$s', 'backupwordpress' ),
esc_html( $excluded_size ),
esc_html( size_format( $size ) )
$excluded_size,
size_format( $size )
);
?>

Expand Down Expand Up @@ -231,10 +229,7 @@
$is_excluded = $is_unreadable = false;

// Check if the file is excluded.
if (
$exclude_string &&
preg_match( '(' . $exclude_string . ')', str_ireplace( trailingslashit( Path::get_root() ), '', wp_normalize_path( $file->getPathname() ) ) )
) :
if ( $excludes->is_file_excluded( $file ) ) :
$is_excluded = true;
endif;

Expand Down Expand Up @@ -298,20 +293,29 @@
$size = $site_size->filesize( $file );

if ( false !== $size ) :
$size = $size ?: '0';
$excluded_size = $excluded_site_size->filesize( $file ) ?: '0'; ?>

$size = $size;
$excluded_size = $excluded_site_size->filesize( $file ); ?>

<code>

<?php if ( $file->isDir() ) :
<?php
// Display `included of total size` info for directories and excluded files only.
if ( $file->isDir() || ( $file->isFile() && $is_excluded ) ) :

if ( $excluded_size ) {
$excluded_size = is_same_size_format( $size, $excluded_size ) ? (int) size_format( $excluded_size ) : size_format( $excluded_size );
}

$excluded_size = is_same_size_format( $size, $excluded_size ) ? (int) size_format( $excluded_size ) : size_format( $excluded_size );
if ( $size ) {
$size = size_format( $size );
}

/* translators: 1: Excluded size 2: Overall site size */
/* translators: 1: Excluded size 2: Overall directory/file size */
printf(
esc_html__( '%1$s of %2$s', 'backupwordpress' ),
esc_html( $excluded_size ),
esc_html( size_format( $size ) )
$excluded_size,
$size
);

elseif ( ! $is_unreadable ) :
Expand Down
21 changes: 21 additions & 0 deletions classes/class-excludes.php
Expand Up @@ -183,4 +183,25 @@ function( $exclude ) {
return $excludes;

}

/**
* Check if a file is excluded.
* i.e. excluded directly or is in an excluded folder.
*
* @param \SplFileInfo $file File to check if it's excluded.
*
* @return bool|null True if file is excluded, false otherwise.
* Null - if it's not a file.
*/
public function is_file_excluded( \SplFileInfo $file ) {

$exclude_string = implode( '|', $this->get_excludes_for_regex() );
$file_path_no_root = str_ireplace( trailingslashit( Path::get_root() ), '', wp_normalize_path( $file->getPathname() ) );

if ( $exclude_string && preg_match( '(' . $exclude_string . ')', $file_path_no_root ) ) {
return true;
}

return false;
}
}
37 changes: 23 additions & 14 deletions classes/class-site-size.php
Expand Up @@ -163,32 +163,38 @@ public function recursive_filesize_scanner() {
}

/**
* Get the total filesize for a given file or directory
* Get the total filesize for a given file or directory. Aware of exclusions.
*
* If $file is a file then just return the result of `filesize()`.
* If $file is a directory then recursively calculate the size.
* If $file is a file then return the result of `filesize()` or 0 if it's excluded.
* If $file is a directory then recursively calculate the size without
* the size of excluded files/directories.
*
* @param \SplFileInfo $file The file or directory you want to know the size of
* @param \SplFileInfo $file The file or directory you want to know the size of.
*
* @return int The total filesize of the file or directory
* @return int The total filesize of the file or directory without
* the size of excluded files/directories.
*/
public function filesize( \SplFileInfo $file ) {

// Skip missing or unreadable files
// Skip missing or unreadable files.
if ( ! file_exists( $file->getPathname() ) || ! $file->getRealpath() || ! $file->isReadable() ) {
return 0;
}

// If it's a file then just pass back the filesize
// If it's a file then return its filesize or 0 if it's excluded.
if ( $file->isFile() ) {
return $file->getSize();

if ( $this->excludes && $this->excludes->is_file_excluded( $file ) ) {
return 0;
} else {
return $file->getSize();
}
}

// If it's a directory then pull it from the cached filesize array
// If it's a directory then pull it from the cached filesize array.
if ( $file->isDir() ) {
return $this->directory_filesize( $file );
}

}

public function directory_filesize( \SplFileInfo $file ) {
Expand All @@ -197,18 +203,19 @@ public function directory_filesize( \SplFileInfo $file ) {
if ( $file->getRealPath() === PATH::get_root() && $this->excludes ) {

$directory_sizes = get_transient( 'hmbkp_root_size' );

if ( $directory_sizes ) {
return $directory_sizes;
return (int) $directory_sizes;
}
}

// If we haven't calculated the site size yet then kick it off in a thread
// If we haven't calculated the site size yet then kick it off in a thread.
$directory_sizes = $this->get_cached_filesizes();

if ( ! is_array( $directory_sizes ) ) {
$this->rebuild_directory_filesizes();

// Intentionally return null so the caller can tell that the size is being calculated
// Intentionally return null so the caller can tell that the size is being calculated.
return null;
}

Expand All @@ -219,7 +226,9 @@ public function directory_filesize( \SplFileInfo $file ) {
$directory_sizes = array_flip( preg_grep( '(' . wp_normalize_path( $file->getRealPath() ) . ')', array_flip( $directory_sizes ) ) );

if ( $this->excludes ) {

$excludes = implode( '|', $this->excludes->get_excludes_for_regex() );

if ( $excludes ) {
// Use PREG_GREP_INVERT to remove any filepaths which match an exclude rule
$directory_sizes = array_flip( preg_grep( '(' . $excludes . ')', array_flip( $directory_sizes ), PREG_GREP_INVERT ) );
Expand All @@ -234,7 +243,7 @@ public function directory_filesize( \SplFileInfo $file ) {
}

// Directory size is now just a sum of all files across all sub directories.
return $directory_sizes;
return (int) $directory_sizes;

}

Expand Down
72 changes: 72 additions & 0 deletions tests/test-excludes.php
Expand Up @@ -9,6 +9,7 @@ public function setUp() {
$this->setup_test_data();
Path::get_instance()->set_path( $this->test_data . '/tmp' );
Path::get_instance()->set_root( $this->test_data );
$this->root = new \SplFileInfo( Path::get_root() );

$this->backup = new Mock_File_Backup_Engine;
}
Expand Down Expand Up @@ -261,6 +262,77 @@ public function testWildCard() {

}

/**
* File is excluded directly (either in the root or any non-excluded sub-directory).
*
* Main test: Excludes->is_file_excluded( $file )
* Expected: true.
*/
public function test_excluded_file_directly_is_excluded() {

$file_path = $this->test_data . '/test-data.txt';
$file = new \SplFileInfo( $file_path );

// Check the file is created and its size is NOT 0.
$this->assertContains( $this->root->getPath(), $file->getPath() );
$this->assertNotSame( $file->getSize(), 0 );

// Exclude file directly.
$excluded_file = new Excludes( $file_path );

// Check the file is excluded - true.
$this->assertContains( basename( $file->getPathname() ), $excluded_file->get_user_excludes() );
$this->assertTrue( $excluded_file->is_file_excluded( $file ) );
}

/**
* File is excluded as a result of being in an excluded directory.
*
* Main test: Excludes->is_file_excluded( $file )
* Expected: true.
*/
public function test_excluded_file_via_parent_directory_is_excluded() {

$file_path = $this->test_data . '/test-data.txt';
$file = new \SplFileInfo( $file_path );

// Check the file is created and its size is NOT 0.
$this->assertContains( $this->root->getPath(), $file->getPath() );
$this->assertNotSame( $file->getSize(), 0 );

// Exclude the parent directory, so the file in it is excluded by "inheritance".
$excluded_dir_name = basename( $file->getPath() ); // test-data directory, the parent dir of the file.
$excluded_dir = new Excludes( $excluded_dir_name );

// Check the directory is excluded. File in that directory should be excluded too.
$this->assertContains( $excluded_dir_name, $excluded_dir->get_user_excludes() );
$this->assertTrue( $excluded_dir->is_file_excluded( $file ) );
}

/**
* File is NOT excluded directly (either in the root or any non-excluded sub-directory).
*
* Main test: Excludes->is_file_excluded( $file )
* Expected: false.
*/
public function test_non_excluded_file_is_excluded() {

$file_path = $this->test_data . '/test-data.txt';
$file = new \SplFileInfo( $file_path );

// Check the file is created and its size is NOT 0.
$this->assertContains( $this->root->getPath(), $file->getPath() );
$this->assertNotSame( $file->getSize(), 0 );

// Do NOT exclude the parent directory, so the file in it is also non excluded by "inheritance".
$non_excluded_dir_name = basename( $file->getPath() ); // test-data directory, the parent dir of the file.
$non_excluded_dir = new Excludes();

// Check the directory is NOT excluded. File in that directory should be NOT excluded too.
$this->assertNotContains( $non_excluded_dir_name, $non_excluded_dir->get_user_excludes() );
$this->assertFalse( $non_excluded_dir->is_file_excluded( $file ) );
}

private function get_and_prepare_files() {

$finder = $this->backup->get_files();
Expand Down
67 changes: 67 additions & 0 deletions tests/test-site-size.php
Expand Up @@ -105,4 +105,71 @@ public function test_site_size_with_filescanner_complete_equals_database_plus_fi
$this->assertEquals( $size_complete->get_site_size(), $size_database->get_site_size() + $size_file->get_site_size() );

}

/**
* File is excluded directly (either in the root or any non-excluded sub-directory).
*
* Main test: Site_Size->filesize( $file )
* Expected: file size should be 0.
*/
public function test_file_size_excluded_directly() {

$file_path = $this->test_data . '/test-data.txt';
$file = new \SplFileInfo( $file_path );

// Check the file is created and its size is NOT 0.
$this->assertContains( $this->root->getPath(), $file->getPath() );
$this->assertNotSame( $file->getSize(), 0 );

// Exclude file directly - file size should be 0.
$excluded_file_site_size = new Site_Size( 'file', new Excludes( $file_path ) );
$this->assertSame( $excluded_file_site_size->filesize( $file ), 0 );
}

/**
* File is excluded as a result of being in an excluded directory.
*
* Main test: Site_Size->filesize( $file )
* Expected: file size should be 0.
*/
public function test_file_size_excluded_via_parent_directory() {

$file_path = $this->test_data . '/test-data.txt';
$file = new \SplFileInfo( $file_path );

// Check the file is created and its size is NOT 0.
$this->assertContains( $this->root->getPath(), $file->getPath() );
$this->assertNotSame( $file->getSize(), 0 );

// Exclude the parent directory, so the file in it is excluded by "inheritance" - file size should be 0.
$excluded_dir_name = basename( $file->getPath() ); // test-data directory, the parent dir of the file.
$excluded_dir = new Excludes( $excluded_dir_name );
$excluded_dir_site_size = new Site_Size( 'file', $excluded_dir );

// Check the directory is excluded. File size in that directory should return 0.
$this->assertContains( $excluded_dir_name, $excluded_dir->get_user_excludes() );
$this->assertSame( $excluded_dir_site_size->filesize( $file ), 0 );
}

/**
* File is NOT excluded directly (either in the root or any non-excluded sub-directory).
*
* Main test: Site_Size->filesize( $file )
* Expected: file size should be what it is.
*/
public function test_file_size_not_excluded_directly() {

$file_path = $this->test_data . '/test-data.txt';
$file = new \SplFileInfo( $file_path );

// Check the file is created and its size is NOT 0.
$this->assertContains( $this->root->getPath(), $file->getPath() );
$this->assertNotSame( $file->getSize(), 0 );

// Check file size via BWP function. It should NOT be 0, should be the same size as via getSize().
$site_size = new Site_Size( 'file' );
$this->assertNotSame( $site_size->filesize( $file ), 0 );
$this->assertSame( $site_size->filesize( $file ), $file->getSize() );
}

}

0 comments on commit cf5579a

Please sign in to comment.