/** * 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; }
/** * 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 } }