/**
 * Return the contents of `$directory` as a single depth list ordered by total filesize.
 *
 * Will schedule background threads to recursively calculate the filesize of subdirectories.
 * The total filesize of each directory and subdirectory is cached in a transient for 1 week.
 *
 * @param string $directory The directory to list
 *
 * @todo doesn't really belong in this class, should just be a function
 * @return array            returns an array of files ordered by filesize
 */
function list_directory_by_total_filesize($directory, Excludes $excludes)
{
    $files = $files_with_no_size = $empty_files = $files_with_size = $unreadable_files = array();
    if (!is_dir($directory)) {
        return $files;
    }
    $finder = new \Symfony\Component\Finder\Finder();
    $finder->followLinks();
    $finder->ignoreDotFiles(false);
    $finder->ignoreUnreadableDirs();
    $finder->depth('== 0');
    $site_size = new Site_Size('file', $excludes);
    $files = $finder->in($directory);
    foreach ($files as $entry) {
        // Get the total filesize for each file and directory
        $filesize = $site_size->filesize($entry);
        if ($filesize) {
            // If there is already a file with exactly the same filesize then let's keep increasing the filesize of this one until we don't have a clash
            while (array_key_exists($filesize, $files_with_size)) {
                $filesize++;
            }
            $files_with_size[$filesize] = $entry;
        } elseif (0 === $filesize) {
            $empty_files[] = $entry;
        } else {
            $files_with_no_size[] = $entry;
        }
    }
    // Sort files by filesize, largest first
    krsort($files_with_size);
    // Add 0 byte files / directories to the bottom
    $files = $files_with_size + array_merge($empty_files, $unreadable_files);
    // Add directories that are still calculating to the top
    if ($files_with_no_size) {
        // We have to loop as merging or concatenating the array would re-flow the keys which we don't want because the filesize is stored in the key
        foreach ($files_with_no_size as $entry) {
            array_unshift($files, $entry);
        }
    }
    return $files;
}
Esempio n. 2
0
 /**
  * Retrieve all files in the given directory and add them to the parsing list.
  *
  * @param string $path A path to a folder, may be relative, absolute or
  *  even phar.
  *
  * @return void
  */
 public function addDirectory($path)
 {
     $finder = new \Symfony\Component\Finder\Finder();
     $patterns = $this->getIgnorePatterns()->getRegularExpression();
     if ($this->follow_symlinks) {
         $finder->followLinks();
     }
     // restrict names to those ending in the given extensions
     $finder->files()->in($path)->name('/\\.(' . implode('|', $this->allowed_extensions->getArrayCopy()) . ')$/')->ignoreDotFiles($this->getIgnoreHidden())->filter(function (\SplFileInfo $file) use($patterns) {
         if (!$patterns) {
             return true;
         }
         // apply ignore list on path instead of file, finder
         // can't do that by default
         return !preg_match($patterns, $file->getPathname());
     });
     try {
         /** @var \SplFileInfo $file */
         foreach ($finder as $file) {
             $file = new File($file);
             $path = $file->getRealPath() ? $file->getRealPath() : $file->getPathname();
             $this[$path] = $file;
         }
     } catch (\LogicException $e) {
         // if a logic exception is thrown then no folders were included
         // for phpDocumentor this is not an issue since we accept separate
         // files as well
     }
 }