本文整理汇总了PHP中Filesystem::isDescendant方法的典型用法代码示例。如果您正苦于以下问题:PHP Filesystem::isDescendant方法的具体用法?PHP Filesystem::isDescendant怎么用?PHP Filesystem::isDescendant使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Filesystem
的用法示例。
在下文中一共展示了Filesystem::isDescendant方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的PHP代码示例。
示例1: loadOneSkinSpecification
public static function loadOneSkinSpecification($name)
{
// Only allow skins which we know to exist to load. This prevents loading
// skins like "../../secrets/evil/".
$all = self::loadAllSkinSpecifications();
if (empty($all[$name])) {
throw new Exception(pht('Blog skin "%s" is not a valid skin!', $name));
}
$paths = PhabricatorEnv::getEnvConfig('phame.skins');
$base = dirname(phutil_get_library_root('phabricator'));
foreach ($paths as $path) {
$path = Filesystem::resolvePath($path, $base);
$skin_path = $path . DIRECTORY_SEPARATOR . $name;
if (is_dir($skin_path)) {
// Double check that the skin really lives in the skin directory.
if (!Filesystem::isDescendant($skin_path, $path)) {
throw new Exception(pht('Blog skin "%s" is not located in path "%s"!', $name, $path));
}
$spec = self::loadSkinSpecification($skin_path);
if ($spec) {
$spec->setName($name);
return $spec;
}
}
}
return null;
}
示例2: deleteDocumentsByHash
protected function deleteDocumentsByHash(array $hashes)
{
$root = $this->getConfig('root');
$cache = $this->getPublishCache();
foreach ($hashes as $hash) {
$paths = $cache->getAtomPathsFromCache($hash);
foreach ($paths as $path) {
$abs = $root . DIRECTORY_SEPARATOR . $path;
Filesystem::remove($abs);
// If the parent directory is now empty, clean it up.
$dir = dirname($abs);
while (true) {
if (!Filesystem::isDescendant($dir, $root)) {
// Directory is outside of the root.
break;
}
if (Filesystem::listDirectory($dir)) {
// Directory is not empty.
break;
}
Filesystem::remove($dir);
$dir = dirname($dir);
}
}
$cache->removeAtomPathsFromCache($hash);
$cache->deleteAtomFromIndex($hash);
}
}
示例3: testisDescendant
public function testisDescendant()
{
$test_cases = array(array(__FILE__, dirname(__FILE__), true), array(dirname(__FILE__), dirname(dirname(__FILE__)), true), array(dirname(__FILE__), phutil_get_library_root_for_path(__FILE__), true), array(dirname(dirname(__FILE__)), dirname(__FILE__), false), array(dirname(__FILE__) . '/quack', dirname(__FILE__), false));
foreach ($test_cases as $test_case) {
list($path, $root, $expected) = $test_case;
$this->assertEqual($expected, Filesystem::isDescendant($path, $root), sprintf('Filesystem::isDescendant(%s, %s)', phutil_var_export($path), phutil_var_export($root)));
}
}
示例4: render
public function render()
{
$user = $this->getUser();
$trace = $this->trace;
$libraries = PhutilBootloader::getInstance()->getAllLibraries();
// TODO: Make this configurable?
$path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/';
$callsigns = array('arcanist' => 'ARC', 'phutil' => 'PHU', 'phabricator' => 'P');
$rows = array();
$depth = count($trace);
foreach ($trace as $part) {
$lib = null;
$file = idx($part, 'file');
$relative = $file;
foreach ($libraries as $library) {
$root = phutil_get_library_root($library);
if (Filesystem::isDescendant($file, $root)) {
$lib = $library;
$relative = Filesystem::readablePath($file, $root);
break;
}
}
$where = '';
if (isset($part['class'])) {
$where .= $part['class'] . '::';
}
if (isset($part['function'])) {
$where .= $part['function'] . '()';
}
if ($file) {
if (isset($callsigns[$lib])) {
$attrs = array('title' => $file);
try {
$attrs['href'] = $user->loadEditorLink('/src/' . $relative, $part['line'], $callsigns[$lib]);
} catch (Exception $ex) {
// The database can be inaccessible.
}
if (empty($attrs['href'])) {
$attrs['href'] = sprintf($path, $callsigns[$lib]) . str_replace(DIRECTORY_SEPARATOR, '/', $relative) . '$' . $part['line'];
$attrs['target'] = '_blank';
}
$file_name = phutil_tag('a', $attrs, $relative);
} else {
$file_name = phutil_tag('span', array('title' => $file), $relative);
}
$file_name = hsprintf('%s : %d', $file_name, $part['line']);
} else {
$file_name = phutil_tag('em', array(), '(Internal)');
}
$rows[] = array($depth--, $lib, $file_name, $where);
}
$table = new AphrontTableView($rows);
$table->setHeaders(array(pht('Depth'), pht('Library'), pht('File'), pht('Where')));
$table->setColumnClasses(array('n', '', '', 'wide'));
return phutil_tag('div', array('class' => 'exception-trace'), $table->render());
}
示例5: readCoverage
public function readCoverage($cover_file)
{
$coverage_dom = new DOMDocument();
$coverage_dom->loadXML(Filesystem::readFile($cover_file));
$modified = $this->getPaths();
$reports = array();
$classes = $coverage_dom->getElementsByTagName("class");
foreach ($classes as $class) {
$path = $class->getAttribute("filename");
$root = $this->getWorkingCopy()->getProjectRoot();
if (in_array($path, $modified) === false) {
continue;
}
if (!Filesystem::isDescendant($path, $root)) {
continue;
}
// get total line count in file
$line_count = count(phutil_split_lines(Filesystem::readFile($path)));
$coverage = "";
$start_line = 1;
$lines = $this->unitTestEngineGetLines($class);
for ($ii = 0; $ii < count($lines); $ii++) {
$line = $lines[$ii];
$next_line = $line["number"];
for ($start_line; $start_line < $next_line; $start_line++) {
$coverage .= "N";
}
if ($line["hits"] === 0) {
$coverage .= "U";
} else {
if ($line["hits"] > 0) {
$coverage .= "C";
}
}
$start_line++;
}
if ($start_line < $line_count) {
foreach (range($start_line, $line_count) as $line_num) {
$coverage .= "N";
}
}
$reports[$path] = $coverage;
}
return $reports;
}
示例6: isFirstParty
/**
* Returns true if an application is first-party (developed by Phacility)
* and false otherwise.
*
* @return bool True if this application is developed by Phacility.
*/
public final function isFirstParty()
{
$where = id(new ReflectionClass($this))->getFileName();
$root = phutil_get_library_root('phabricator');
if (!Filesystem::isDescendant($where, $root)) {
return false;
}
if (Filesystem::isDescendant($where, $root . '/extensions')) {
return false;
}
return true;
}
示例7: getTestPaths
/**
* Returns the paths in which we should look for tests to execute.
*
* @return list<string> A list of paths in which to search for test cases.
*/
public function getTestPaths()
{
$root = $this->getWorkingCopy()->getProjectRoot();
$paths = array();
foreach ($this->getPaths() as $path) {
$library_root = phutil_get_library_root_for_path($path);
if (!$library_root) {
continue;
}
$library_name = phutil_get_library_name_for_root($library_root);
if (!$library_name) {
throw new Exception(pht("Attempting to run unit tests on a libphutil library which has " . "not been loaded, at:\n\n" . " %s\n\n" . "This probably means one of two things:\n\n" . " - You may need to add this library to %s.\n" . " - You may be running tests on a copy of libphutil or " . "arcanist using a different copy of libphutil or arcanist. " . "This operation is not supported.\n", $library_root, '.arcconfig.'));
}
$path = Filesystem::resolvePath($path, $root);
$library_path = Filesystem::readablePath($path, $library_root);
if (!Filesystem::isDescendant($path, $library_root)) {
// We have encountered some kind of symlink maze -- for instance, $path
// is some symlink living outside the library that links into some file
// inside the library. Just ignore these cases, since the affected file
// does not actually lie within the library.
continue;
}
if (is_file($path) && preg_match('@(?:^|/)__tests__/@', $path)) {
$paths[$library_name . ':' . $library_path] = array('library' => $library_name, 'path' => $library_path);
continue;
}
foreach (Filesystem::walkToRoot($path, $library_root) as $subpath) {
if ($subpath == $library_root) {
$paths[$library_name . ':.'] = array('library' => $library_name, 'path' => '__tests__/');
} else {
$library_subpath = Filesystem::readablePath($subpath, $library_root);
$paths[$library_name . ':' . $library_subpath] = array('library' => $library_name, 'path' => $library_subpath . '/__tests__/');
}
}
}
return $paths;
}
示例8: findTestFile
/**
* Search for test cases for a given file in a large number of "reasonable"
* locations. See @{method:getSearchLocationsForTests} for specifics.
*
* TODO: Add support for finding tests in testsuite folders from
* phpunit.xml configuration.
*
* @param string PHP file to locate test cases for.
* @return string|null Path to test cases, or null.
*/
private function findTestFile($path)
{
$root = $this->projectRoot;
$path = Filesystem::resolvePath($path, $root);
$file = basename($path);
$possible_files = array($file, substr($file, 0, -4) . 'Test.php');
$search = self::getSearchLocationsForTests($path);
foreach ($search as $search_path) {
foreach ($possible_files as $possible_file) {
$full_path = $search_path . $possible_file;
if (!Filesystem::pathExists($full_path)) {
// If the file doesn't exist, it's clearly a miss.
continue;
}
if (!Filesystem::isDescendant($full_path, $root)) {
// Don't look above the project root.
continue;
}
if (0 == strcasecmp(Filesystem::resolvePath($full_path), $path)) {
// Don't return the original file.
continue;
}
return $full_path;
}
}
return null;
}
示例9: getTestsForPaths
private function getTestsForPaths()
{
$project_root = $this->getWorkingCopy()->getProjectRoot();
$look_here = array();
foreach ($this->getPaths() as $path) {
$library_root = phutil_get_library_root_for_path($path);
if (!$library_root) {
continue;
}
$library_name = phutil_get_library_name_for_root($library_root);
if (!$library_name) {
throw new Exception("Attempting to run unit tests on a libphutil library which has not " . "been loaded, at:\n\n" . " {$library_root}\n\n" . "This probably means one of two things:\n\n" . " - You may need to add this library to .arcconfig.\n" . " - You may be running tests on a copy of libphutil or arcanist\n" . " using a different copy of libphutil or arcanist. This\n" . " operation is not supported.");
}
$path = Filesystem::resolvePath($path, $project_root);
if (!is_dir($path)) {
$path = dirname($path);
}
if ($path == $library_root) {
$look_here[$library_name . ':.'] = array('library' => $library_name, 'path' => '');
} else {
if (!Filesystem::isDescendant($path, $library_root)) {
// We have encountered some kind of symlink maze -- for instance, $path
// is some symlink living outside the library that links into some file
// inside the library. Just ignore these cases, since the affected file
// does not actually lie within the library.
continue;
} else {
$library_path = Filesystem::readablePath($path, $library_root);
do {
$look_here[$library_name . ':' . $library_path] = array('library' => $library_name, 'path' => $library_path);
$library_path = dirname($library_path);
} while ($library_path != '.');
}
}
}
// Look for any class that extends ArcanistPhutilTestCase inside a
// __tests__ directory in any parent directory of every affected file.
//
// The idea is that "infrastructure/__tests__/" tests defines general tests
// for all of "infrastructure/", and those tests run for any change in
// "infrastructure/". However, "infrastructure/concrete/rebar/__tests__/"
// defines more specific tests that run only when rebar/ (or some
// subdirectory) changes.
$run_tests = array();
foreach ($look_here as $path_info) {
$library = $path_info['library'];
$path = $path_info['path'];
$symbols = id(new PhutilSymbolLoader())->setType('class')->setLibrary($library)->setPathPrefix(($path ? $path . '/' : '') . '__tests__/')->setAncestorClass('ArcanistPhutilTestCase')->setConcreteOnly(true)->selectAndLoadSymbols();
foreach ($symbols as $symbol) {
$run_tests[$symbol['name']] = true;
}
}
$run_tests = array_keys($run_tests);
return $run_tests;
}
示例10: runUnitTests
public function runUnitTests()
{
// Build any unit tests
$this->make('build-tests');
// Now find all the test programs
$root = $this->getProjectRoot();
$futures = array();
$cg_files = array();
$obj_files = array();
$coverage = $this->getEnableCoverage();
$tests = $this->getTestsToRun();
foreach ($tests as $relname => $test) {
if ($coverage) {
$cg = new TempFile();
$cg_files[$relname] = $cg;
$obj_files[] = $test;
$test = 'valgrind --tool=callgrind --collect-jumps=yes ' . '--callgrind-out-file=' . $cg . ' ' . $test;
}
$futures[$relname] = new ExecFuture($test);
}
$results = array();
// Use a smaller limit for SunOS because my test VM has crappy
// timing characteristics and that causes timer.t to fail
$limit = PHP_OS == 'SunOS' ? 1 : 4;
foreach (Futures($futures)->limit($limit) as $test => $future) {
list($err, $stdout, $stderr) = $future->resolve();
$results[$test] = $this->parseTestResults($test, $err, $stdout, $stderr);
}
if ($coverage) {
// Find all executables, not just the test executables.
// We need to do this because the test executables may not
// include all of the possible code (linker decides to omit
// it from the image) so we see a skewed representation of
// the source lines.
$fp = popen("find {$root} -type f -name \\*.a -o -name \\*.so -o -name \\*.dylib", "r");
while (true) {
$line = fgets($fp);
if ($line === false) {
break;
}
$obj_files[] = trim($line);
}
// Parse line information from the objects
foreach ($obj_files as $object) {
PhenomDwarfLineInfo::loadObject($object);
}
// Now process coverage data files
foreach ($cg_files as $relname => $cg) {
$CG = new PhenomCallgrindFile((string) $cg);
$CG->parse();
$source_files = array();
foreach ($CG->getSourceFiles() as $filename) {
if (Filesystem::isDescendant($filename, $root) && !preg_match("/(thirdparty|tests)/", $filename)) {
$source_files[$filename] = $filename;
}
}
$cov = array();
foreach ($source_files as $filename) {
$relsrc = substr($filename, strlen($root) + 1);
$cov[$relsrc] = PhenomCallgrindFile::mergeSourceLineData($filename, array($CG));
}
// Update the coverage data for that test.
// arcanist will merge the final results
$results[$relname]->setCoverage($cov);
}
}
return $results;
}
示例11: reenter_if_this_is_arcanist_or_libphutil
/**
* NOTE: SPOOKY BLACK MAGIC
*
* When arc is run in a copy of arcanist other than itself, or a copy of
* libphutil other than the one we loaded, reenter the script and force it
* to use the current working directory instead of the default.
*
* In the case of execution inside arcanist/, we force execution of the local
* arc binary.
*
* In the case of execution inside libphutil/, we force the local copy to load
* instead of the one selected by default rules.
*
* @param PhutilConsole Console.
* @param ArcanistWorkingCopyIdentity The current working copy.
* @param array Original arc arguments.
* @return void
*/
function reenter_if_this_is_arcanist_or_libphutil(PhutilConsole $console, ArcanistWorkingCopyIdentity $working_copy, array $original_argv)
{
$project_id = $working_copy->getProjectID();
if ($project_id != 'arcanist' && $project_id != 'libphutil') {
// We're not in a copy of arcanist or libphutil.
return;
}
$library_names = array('arcanist' => 'arcanist', 'libphutil' => 'phutil');
$library_root = phutil_get_library_root($library_names[$project_id]);
$project_root = $working_copy->getProjectRoot();
if (Filesystem::isDescendant($library_root, $project_root)) {
// We're in a copy of arcanist or libphutil, but already loaded the correct
// copy. Continue execution normally.
return;
}
if ($project_id == 'libphutil') {
$console->writeLog("This is libphutil! Forcing this copy to load...\n");
$original_argv[0] = dirname(phutil_get_library_root('arcanist')) . '/bin/arc';
$libphutil_path = $project_root;
} else {
$console->writeLog("This is arcanist! Forcing this copy to run...\n");
$original_argv[0] = $project_root . '/bin/arc';
$libphutil_path = dirname(phutil_get_library_root('phutil'));
}
if (phutil_is_windows()) {
$err = phutil_passthru('set ARC_PHUTIL_PATH=%s & %Ls', $libphutil_path, $original_argv);
} else {
$err = phutil_passthru('ARC_PHUTIL_PATH=%s %Ls', $libphutil_path, $original_argv);
}
exit($err);
}
示例12: getCommitFileList
protected function getCommitFileList(array $revision)
{
$repository_api = $this->getRepositoryAPI();
$revision_id = $revision['id'];
$commit_paths = $this->getConduit()->callMethodSynchronous('differential.getcommitpaths', array('revision_id' => $revision_id));
$dir_paths = array();
foreach ($commit_paths as $path) {
$path = dirname($path);
while ($path != '.') {
$dir_paths[$path] = true;
$path = dirname($path);
}
}
$commit_paths = array_fill_keys($commit_paths, true);
$status = $repository_api->getSVNStatus();
$modified_but_not_included = array();
foreach ($status as $path => $mask) {
if (!empty($dir_paths[$path])) {
$commit_paths[$path] = true;
}
if (!empty($commit_paths[$path])) {
continue;
}
foreach ($commit_paths as $will_commit => $ignored) {
if (Filesystem::isDescendant($path, $will_commit)) {
throw new ArcanistUsageException("This commit includes the directory '{$will_commit}', but " . "it contains a modified path ('{$path}') which is NOT included " . "in the commit. Subversion can not handle this operation and " . "will commit the path anyway. You need to sort out the working " . "copy changes to '{$path}' before you may proceed with the " . "commit.");
}
}
$modified_but_not_included[] = $path;
}
if ($modified_but_not_included) {
$prefix = pht('Locally modified path(s) are not included in this revision:', count($modified_but_not_included));
$prompt = pht('They will NOT be committed. Commit this revision anyway?', count($modified_but_not_included));
$this->promptFileWarning($prefix, $prompt, $modified_but_not_included);
}
$do_not_exist = array();
foreach ($commit_paths as $path => $ignored) {
$disk_path = $repository_api->getPath($path);
if (file_exists($disk_path)) {
continue;
}
if (is_link($disk_path)) {
continue;
}
if (idx($status, $path) & ArcanistRepositoryAPI::FLAG_DELETED) {
continue;
}
$do_not_exist[] = $path;
unset($commit_paths[$path]);
}
if ($do_not_exist) {
$prefix = pht('Revision includes changes to path(s) that do not exist:', count($do_not_exist));
$prompt = "Commit this revision anyway?";
$this->promptFileWarning($prefix, $prompt, $do_not_exist);
}
$files = array_keys($commit_paths);
if (empty($files)) {
throw new ArcanistUsageException("There is nothing left to commit. None of the modified paths exist.");
}
return $files;
}
示例13: renderStackTrace
private function renderStackTrace($trace, PhabricatorUser $user)
{
$libraries = PhutilBootloader::getInstance()->getAllLibraries();
$version = PhabricatorEnv::getEnvConfig('phabricator.version');
if (preg_match('/[^a-f0-9]/i', $version)) {
$version = '';
}
// TODO: Make this configurable?
$path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/';
$callsigns = array('arcanist' => 'ARC', 'phutil' => 'PHU', 'phabricator' => 'P');
$rows = array();
$depth = count($trace);
foreach ($trace as $part) {
$lib = null;
$file = idx($part, 'file');
$relative = $file;
foreach ($libraries as $library) {
$root = phutil_get_library_root($library);
if (Filesystem::isDescendant($file, $root)) {
$lib = $library;
$relative = Filesystem::readablePath($file, $root);
break;
}
}
$where = '';
if (isset($part['class'])) {
$where .= $part['class'] . '::';
}
if (isset($part['function'])) {
$where .= $part['function'] . '()';
}
if ($file) {
if (isset($callsigns[$lib])) {
$attrs = array('title' => $file);
try {
$attrs['href'] = $user->loadEditorLink('/src/' . $relative, $part['line'], $callsigns[$lib]);
} catch (Exception $ex) {
// The database can be inaccessible.
}
if (empty($attrs['href'])) {
$attrs['href'] = sprintf($path, $callsigns[$lib]) . str_replace(DIRECTORY_SEPARATOR, '/', $relative) . ($version && $lib == 'phabricator' ? ';' . $version : '') . '$' . $part['line'];
$attrs['target'] = '_blank';
}
$file_name = phutil_render_tag('a', $attrs, phutil_escape_html($relative));
} else {
$file_name = phutil_render_tag('span', array('title' => $file), phutil_escape_html($relative));
}
$file_name = $file_name . ' : ' . (int) $part['line'];
} else {
$file_name = '<em>(Internal)</em>';
}
$rows[] = array($depth--, phutil_escape_html($lib), $file_name, phutil_escape_html($where));
}
$table = new AphrontTableView($rows);
$table->setHeaders(array('Depth', 'Library', 'File', 'Where'));
$table->setColumnClasses(array('n', '', '', 'wide'));
return '<div class="exception-trace">' . '<div class="exception-trace-header">Stack Trace</div>' . $table->render() . '</div>';
}
示例14: run
public function run()
{
$bootloader = PhutilBootloader::getInstance();
$project_root = $this->getWorkingCopy()->getProjectRoot();
$look_here = array();
foreach ($this->getPaths() as $path) {
$library_root = phutil_get_library_root_for_path($path);
if (!$library_root) {
continue;
}
$library_name = phutil_get_library_name_for_root($library_root);
if (!$library_name) {
throw new Exception("Attempting to run unit tests on a libphutil library which has not " . "been loaded, at:\n\n" . " {$library_root}\n\n" . "This probably means one of two things:\n\n" . " - You may need to add this library to .arcconfig.\n" . " - You may be running tests on a copy of libphutil or arcanist\n" . " using a different copy of libphutil or arcanist. This\n" . " operation is not supported.");
}
$path = Filesystem::resolvePath($path, $project_root);
if (!is_dir($path)) {
$path = dirname($path);
}
if ($path == $library_root) {
continue;
}
if (!Filesystem::isDescendant($path, $library_root)) {
// We have encountered some kind of symlink maze -- for instance, $path
// is some symlink living outside the library that links into some file
// inside the library. Just ignore these cases, since the affected file
// does not actually lie within the library.
continue;
}
$library_path = Filesystem::readablePath($path, $library_root);
do {
$look_here[$library_name . ':' . $library_path] = array('library' => $library_name, 'path' => $library_path);
$library_path = dirname($library_path);
} while ($library_path != '.');
}
// Look for any class that extends ArcanistPhutilTestCase inside a
// __tests__ directory in any parent directory of every affected file.
//
// The idea is that "infrastructure/__tests__/" tests defines general tests
// for all of "infrastructure/", and those tests run for any change in
// "infrastructure/". However, "infrastructure/concrete/rebar/__tests__/"
// defines more specific tests that run only when rebar/ (or some
// subdirectory) changes.
$run_tests = array();
foreach ($look_here as $path_info) {
$library = $path_info['library'];
$path = $path_info['path'];
$symbols = id(new PhutilSymbolLoader())->setType('class')->setLibrary($library)->setPathPrefix($path . '/__tests__/')->setAncestorClass('ArcanistPhutilTestCase')->setConcreteOnly(true)->selectAndLoadSymbols();
foreach ($symbols as $symbol) {
$run_tests[$symbol['name']] = true;
}
}
$run_tests = array_keys($run_tests);
if (!$run_tests) {
throw new ArcanistNoEffectException("No tests to run.");
}
$enable_coverage = $this->getEnableCoverage();
if ($enable_coverage !== false) {
if (!function_exists('xdebug_start_code_coverage')) {
if ($enable_coverage === true) {
throw new ArcanistUsageException("You specified --coverage but xdebug is not available, so " . "coverage can not be enabled for PhutilUnitTestEngine.");
}
} else {
$enable_coverage = true;
}
}
$results = array();
foreach ($run_tests as $test_class) {
$test_case = newv($test_class, array());
$test_case->setEnableCoverage($enable_coverage);
$test_case->setProjectRoot($project_root);
$test_case->setPaths($this->getPaths());
$results[] = $test_case->run();
}
if ($results) {
$results = call_user_func_array('array_merge', $results);
}
return $results;
}
示例15: readCoverage
public function readCoverage($cover_file, $source_path)
{
$coverage_dom = new DOMDocument();
$coverage_dom->loadXML(Filesystem::readFile($cover_file));
$reports = array();
$classes = $coverage_dom->getElementsByTagName('class');
foreach ($classes as $class) {
$path = $class->getAttribute('filename');
$root = $this->getWorkingCopy()->getProjectRoot();
if (!Filesystem::isDescendant($path, $root)) {
continue;
}
// get total line count in file
$line_count = count(phutil_split_lines(Filesystem::readFile($path)));
$coverage = '';
$start_line = 1;
$lines = $class->getElementsByTagName('line');
for ($ii = 0; $ii < $lines->length; $ii++) {
$line = $lines->item($ii);
$next_line = intval($line->getAttribute('number'));
for ($start_line; $start_line < $next_line; $start_line++) {
$coverage .= 'N';
}
if (intval($line->getAttribute('hits')) == 0) {
$coverage .= 'U';
} else {
if (intval($line->getAttribute('hits')) > 0) {
$coverage .= 'C';
}
}
$start_line++;
}
if ($start_line < $line_count) {
foreach (range($start_line, $line_count) as $line_num) {
$coverage .= 'N';
}
}
$reports[$path] = $coverage;
}
return $reports;
}