コード例 #1
0
 protected function getPathArgumentForLinterFuture($path)
 {
     $full_path = Filesystem::resolvePath($path);
     $ret = array($full_path);
     // The |path| we get fed needs to be made relative to the project_root,
     // otherwise the |engine| won't recognise it.
     $relative_path = Filesystem::readablePath($full_path, $this->getProjectRoot());
     $changed = $this->getEngine()->getPathChangedLines($relative_path);
     if ($changed !== null) {
         // Convert the ordered set of changed lines to a list of ranges.
         $changed_lines = array_keys(array_filter($changed));
         $ranges = array(array($changed_lines[0], $changed_lines[0]));
         foreach (array_slice($changed_lines, 1) as $line) {
             $range = last($ranges);
             if ($range[1] + 1 === $line) {
                 ++$range[1];
                 $ranges[last_key($ranges)] = $range;
             } else {
                 $ranges[] = array($line, $line);
             }
         }
         foreach ($ranges as $range) {
             $ret[] = sprintf('--lines=%d:%d', $range[0], $range[1]);
         }
     }
     return csprintf('%Ls', $ret);
 }
コード例 #2
0
 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());
 }
コード例 #3
0
 public function buildFileContentHashes()
 {
     $files = array();
     $root = $this->getConfiguration()->getProjectRoot();
     $finder = new FileFinder($root . '/src');
     $finder->excludePath('*/.*')->withSuffix('js')->withType('f')->setGenerateChecksums(true);
     foreach ($finder->find() as $path => $hash) {
         $path = Filesystem::readablePath($path, $root);
         $files[$path] = $hash;
     }
     return $files;
 }
コード例 #4
0
 private function findResourcesWithSuffixes(array $suffixes)
 {
     $root = $this->getPathToResources();
     $finder = id(new FileFinder($root))->withType('f')->withFollowSymlinks(true)->setGenerateChecksums(true);
     foreach ($suffixes as $suffix) {
         $finder->withSuffix($suffix);
     }
     $raw_files = $finder->find();
     $results = array();
     foreach ($raw_files as $path => $hash) {
         $readable = Filesystem::readablePath($path, $root);
         $results[$readable] = $hash;
     }
     return $results;
 }
コード例 #5
0
 /**
  * Rebuild the resource map for a resource source.
  *
  * @param CelerityPhysicalResources Resource source to rebuild.
  * @return void
  */
 private function rebuildResources(CelerityPhysicalResources $resources)
 {
     $this->log(pht('Rebuilding resource source "%s" (%s)...', $resources->getName(), get_class($resources)));
     $binary_map = $this->rebuildBinaryResources($resources);
     $this->log(pht('Found %d binary resources.', new PhutilNumber(count($binary_map))));
     $xformer = id(new CelerityResourceTransformer())->setMinify(false)->setRawURIMap(ipull($binary_map, 'uri'));
     $text_map = $this->rebuildTextResources($resources, $xformer);
     $this->log(pht('Found %d text resources.', new PhutilNumber(count($text_map))));
     $resource_graph = array();
     $requires_map = array();
     $symbol_map = array();
     foreach ($text_map as $name => $info) {
         if (isset($info['provides'])) {
             $symbol_map[$info['provides']] = $info['hash'];
             // We only need to check for cycles and add this to the requires map
             // if it actually requires anything.
             if (!empty($info['requires'])) {
                 $resource_graph[$info['provides']] = $info['requires'];
                 $requires_map[$info['hash']] = $info['requires'];
             }
         }
     }
     $this->detectGraphCycles($resource_graph);
     $name_map = ipull($binary_map, 'hash') + ipull($text_map, 'hash');
     $hash_map = array_flip($name_map);
     $package_map = $this->rebuildPackages($resources, $symbol_map, $hash_map);
     $this->log(pht('Found %d packages.', new PhutilNumber(count($package_map))));
     $component_map = array();
     foreach ($package_map as $package_name => $package_info) {
         foreach ($package_info['symbols'] as $symbol) {
             $component_map[$symbol] = $package_name;
         }
     }
     $name_map = $this->mergeNameMaps(array(array(pht('Binary'), ipull($binary_map, 'hash')), array(pht('Text'), ipull($text_map, 'hash')), array(pht('Package'), ipull($package_map, 'hash'))));
     $package_map = ipull($package_map, 'symbols');
     ksort($name_map);
     ksort($symbol_map);
     ksort($requires_map);
     ksort($package_map);
     $map_content = $this->formatMapContent(array('names' => $name_map, 'symbols' => $symbol_map, 'requires' => $requires_map, 'packages' => $package_map));
     $map_path = $resources->getPathToMap();
     $this->log(pht('Writing map "%s".', Filesystem::readablePath($map_path)));
     Filesystem::writeFile($map_path, $map_content);
 }
コード例 #6
0
 public function run()
 {
     $repository_api = $this->getRepositoryAPI();
     $project_root = $this->getWorkingCopy()->getProjectRoot();
     $in_paths = $this->getArgument('paths');
     $paths = array();
     foreach ($in_paths as $key => $path) {
         $full_path = Filesystem::resolvePath($path);
         $paths[$key] = Filesystem::readablePath($full_path, $project_root);
     }
     if (!$paths) {
         throw new ArcanistUsageException("Specify a path to browse");
     }
     $base_uri = $this->getBaseURI();
     $browser = $this->getBrowserCommand();
     foreach ($paths as $path) {
         $ret_code = phutil_passthru("%s %s", $browser, $base_uri . $path);
         if ($ret_code) {
             throw new ArcanistUsageException("It seems we failed to open the browser; Perhaps you should try to " . "set the 'browser' config option. The command we tried to use was: " . $browser);
         }
     }
     return 0;
 }
コード例 #7
0
ファイル: ArcanistLinter.php プロジェクト: milindc2031/Test
 protected final function addLintMessage(ArcanistLintMessage $message)
 {
     $root = $this->getProjectRoot();
     $path = Filesystem::resolvePath($message->getPath(), $root);
     $message->setPath(Filesystem::readablePath($path, $root));
     $this->messages[] = $message;
     return $message;
 }
コード例 #8
0
 /**
  * Build a map of all source files in a library to hashes of their content.
  * Returns an array like this:
  *
  *   array(
  *     'src/parser/ExampleParser.php' => '60b725f10c9c85c70d97880dfe8191b3',
  *     // ...
  *   );
  *
  * @return dict  Map of library-relative paths to content hashes.
  * @task source
  */
 private function loadSourceFileMap()
 {
     $root = $this->getPath();
     $init = $this->getPathForLibraryInit();
     if (!Filesystem::pathExists($init)) {
         throw new Exception(pht("Provided path '%s' is not a %s library.", $root, 'phutil'));
     }
     $files = id(new FileFinder($root))->withType('f')->withSuffix('php')->excludePath('*/.*')->setGenerateChecksums(true)->find();
     $map = array();
     foreach ($files as $file => $hash) {
         $file = Filesystem::readablePath($file, $root);
         $file = ltrim($file, '/');
         if (dirname($file) == '.') {
             // We don't permit normal source files at the root level, so just ignore
             // them; they're special library files.
             continue;
         }
         if (dirname($file) == 'extensions') {
             // Ignore files in the extensions/ directory.
             continue;
         }
         // We include also filename in the hash to handle cases when the file is
         // moved without modifying its content.
         $map[$file] = md5($hash . $file);
     }
     return $map;
 }
コード例 #9
0
 /**
  * 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;
 }
コード例 #10
0
 private function renderStackTrace($trace)
 {
     $libraries = PhutilBootloader::getInstance()->getAllLibraries();
     // TODO: Make this configurable?
     $host = 'https://secure.phabricator.com';
     $browse = array('arcanist' => $host . '/diffusion/ARC/browse/origin:master/src/', 'phutil' => $host . '/diffusion/PHU/browse/origin:master/src/', 'phabricator' => $host . '/diffusion/P/browse/origin:master/src/');
     $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($browse[$lib])) {
                 $file_name = phutil_render_tag('a', array('href' => $browse[$lib] . $relative . '$' . $part['line'], 'title' => $file, 'target' => '_blank'), 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>';
 }
コード例 #11
0
 /**
  * Workflows like 'lint' and 'unit' operate on a list of working copy paths.
  * The user can either specify the paths explicitly ("a.js b.php"), or by
  * specfifying a revision ("--rev a3f10f1f") to select all paths modified
  * since that revision, or by omitting both and letting arc choose the
  * default relative revision.
  *
  * This method takes the user's selections and returns the paths that the
  * workflow should act upon.
  *
  * @param   list          List of explicitly provided paths.
  * @param   string|null   Revision name, if provided.
  * @param   mask          Mask of ArcanistRepositoryAPI flags to exclude.
  *                        Defaults to ArcanistRepositoryAPI::FLAG_UNTRACKED.
  * @return  list          List of paths the workflow should act on.
  */
 protected function selectPathsForWorkflow(array $paths, $rev, $omit_mask = null)
 {
     if ($omit_mask === null) {
         $omit_mask = ArcanistRepositoryAPI::FLAG_UNTRACKED;
     }
     if ($paths) {
         $working_copy = $this->getWorkingCopy();
         foreach ($paths as $key => $path) {
             $full_path = Filesystem::resolvePath($path);
             if (!Filesystem::pathExists($full_path)) {
                 throw new ArcanistUsageException("Path '{$path}' does not exist!");
             }
             $relative_path = Filesystem::readablePath($full_path, $working_copy->getProjectRoot());
             $paths[$key] = $relative_path;
         }
     } else {
         $repository_api = $this->getRepositoryAPI();
         if ($rev) {
             $this->parseBaseCommitArgument(array($rev));
         }
         $paths = $repository_api->getWorkingCopyStatus();
         foreach ($paths as $path => $flags) {
             if ($flags & $omit_mask) {
                 unset($paths[$path]);
             }
         }
         $paths = array_keys($paths);
     }
     return array_values($paths);
 }
コード例 #12
0
 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>';
 }
コード例 #13
0
ファイル: ArcanistLinter.php プロジェクト: rafikk/arcanist
 protected function addLintMessage(ArcanistLintMessage $message)
 {
     if (!$this->getEngine()->getCommitHookMode()) {
         $root = $this->getEngine()->getWorkingCopy()->getProjectRoot();
         $path = Filesystem::resolvePath($message->getPath(), $root);
         $message->setPath(Filesystem::readablePath($path, $root));
     }
     $this->messages[] = $message;
     return $message;
 }
コード例 #14
0
    $uri = '/res/' . substr($hash, 0, 8) . $path;
    $runtime_map[$path] = array('hash' => $hash, 'uri' => $uri, 'disk' => $path, 'type' => $type);
}
echo "\n";
$xformer = id(new CelerityResourceTransformer())->setMinify(false)->setRawResourceMap($runtime_map);
echo "Finding transformable static resources...\n";
$finder = id(new FileFinder($root))->withType('f')->withSuffix('js')->withSuffix('css')->withFollowSymlinks(true)->setGenerateChecksums(true);
if (!$with_custom) {
    $finder->excludePath('./rsrc/custom');
}
$files = $finder->find();
echo "Processing " . count($files) . " files";
$file_map = array();
foreach ($files as $path => $raw_hash) {
    echo ".";
    $path = '/' . Filesystem::readablePath($path, $root);
    $data = Filesystem::readFile($root . $path);
    $data = $xformer->transformResource($path, $data);
    $hash = md5($data);
    $hash = md5($hash . $path . $resource_hash);
    $file_map[$path] = array('hash' => $hash, 'disk' => $path);
}
echo "\n";
$resource_graph = array();
$hash_map = array();
$parser = new PhutilDocblockParser();
foreach ($file_map as $path => $info) {
    $type = CelerityResourceTransformer::getResourceType($path);
    $data = Filesystem::readFile($root . $info['disk']);
    $matches = array();
    $ok = preg_match('@/[*][*].*?[*]/@s', $data, $matches);
コード例 #15
0
 /**
  * Build a map of all source files in a library to hashes of their content.
  * Returns an array like this:
  *
  *   array(
  *     'src/parser/ExampleParser.php' => '60b725f10c9c85c70d97880dfe8191b3',
  *     // ...
  *   );
  *
  * @return  dict    Map of library-relative paths to content hashes.
  * @task source
  */
 private function loadSourceFileMap()
 {
     $root = $this->getPath();
     $init = $this->getPathForLibraryInit();
     if (!Filesystem::pathExists($init)) {
         throw new Exception("Provided path '{$root}' is not a phutil library.");
     }
     $files = id(new FileFinder($root))->withType('f')->withSuffix('php')->excludePath('*/.*')->setGenerateChecksums(true)->find();
     $map = array();
     foreach ($files as $file => $hash) {
         if (basename($file) == '__init__.php') {
             // TODO: Remove this once we kill __init__.php. This just makes the
             // script run faster until we do, so testing and development is less
             // annoying.
             continue;
         }
         $file = Filesystem::readablePath($file, $root);
         $file = ltrim($file, '/');
         if (dirname($file) == '.') {
             // We don't permit normal source files at the root level, so just ignore
             // them; they're special library files.
             continue;
         }
         // We include also filename in the hash to handle cases when the file is
         // moved without modifying its content.
         $map[$file] = md5($hash . $file);
     }
     return $map;
 }
コード例 #16
0
 public function testGetTestPaths()
 {
     $tests = array('empty' => array(array(), array()), 'test file' => array(array(__FILE__), array(__FILE__)), 'test directory' => array(array(dirname(__FILE__)), array(dirname(dirname(__FILE__)) . '/__tests__/__tests__/', dirname(dirname(__FILE__)) . '/__tests__/', dirname(dirname(dirname(__FILE__))) . '/__tests__/', phutil_get_library_root('arcanist') . '/__tests__/')), 'normal directory' => array(array(dirname(dirname(__FILE__))), array(dirname(dirname(__FILE__)) . '/__tests__/', dirname(dirname(dirname(__FILE__))) . '/__tests__/', phutil_get_library_root('arcanist') . '/__tests__/')), 'library root' => array(array(phutil_get_library_root('arcanist')), array(phutil_get_library_root('arcanist') . '/__tests__/')));
     $test_engine = id(new PhutilUnitTestEngine())->setWorkingCopy($this->getWorkingCopy());
     $library = phutil_get_current_library_name();
     $library_root = phutil_get_library_root($library);
     foreach ($tests as $name => $test) {
         list($paths, $test_paths) = $test;
         $expected = array();
         foreach ($test_paths as $path) {
             $expected[] = array('library' => $library, 'path' => Filesystem::readablePath($path, $library_root));
         }
         $test_engine->setPaths($paths);
         $this->assertEqual($expected, array_values($test_engine->getTestPaths()), pht('Test paths for: "%s"', $name));
     }
 }
コード例 #17
0
 private function loadSourceHash(PhutilSprite $sprite)
 {
     $inputs = array();
     foreach ($this->scales as $scale) {
         $file = $sprite->getSourceFile($scale);
         // If two users have a project in different places, like:
         //
         //    /home/alincoln/project
         //    /home/htaft/project
         //
         // ...we want to ignore the `/home/alincoln` part when hashing the sheet,
         // since the sprites don't change when the project directory moves. If
         // the base path is set, build the hashes using paths relative to the
         // base path.
         $file_key = $file;
         if ($this->basePath) {
             $file_key = Filesystem::readablePath($file, $this->basePath);
         }
         if (empty($this->hashes[$file_key])) {
             $this->hashes[$file_key] = md5(Filesystem::readFile($file));
         }
         $inputs[] = $file_key;
         $inputs[] = $this->hashes[$file_key];
     }
     $inputs[] = $sprite->getSourceX();
     $inputs[] = $sprite->getSourceY();
     $inputs[] = $sprite->getSourceW();
     $inputs[] = $sprite->getSourceH();
     return md5(implode(':', $inputs));
 }
コード例 #18
0
 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;
 }
コード例 #19
0
ファイル: phutil_symbols.php プロジェクト: endlessm/libphutil
function phutil_fail_on_unsupported_feature(XHPASTNode $node, $file, $what)
{
    $line = $node->getLineNumber();
    $message = phutil_console_wrap(pht('`%s` has limited support for features introduced after PHP 5.2.3. ' . 'This library uses an unsupported feature (%s) on line %d of %s.', 'arc liberate', $what, $line, Filesystem::readablePath($file)));
    $result = array('error' => $message, 'line' => $line, 'file' => $file);
    $json = new PhutilJSON();
    echo $json->encodeFormatted($result);
    exit(0);
}
 private function loadLibraryFiles($root)
 {
     $files = id(new FileFinder($root))->withType('f')->withSuffix('php')->excludePath('*/.*')->setGenerateChecksums(true)->find();
     $map = array();
     foreach ($files as $file => $hash) {
         $file = Filesystem::readablePath($file, $root);
         $file = ltrim($file, '/');
         if (dirname($file) == '.') {
             continue;
         }
         if (dirname($file) == 'extensions') {
             continue;
         }
         $map[$file] = md5($hash . $file);
     }
     return $map;
 }
コード例 #21
0
 /**
  * Get a human-readable description of the scratch file location.
  *
  * @param string  Scratch file name.
  * @return mixed  String, or false on failure.
  * @task scratch
  */
 public function getReadableScratchFilePath($path)
 {
     $full_path = $this->getScratchFilePath($path);
     if ($full_path) {
         return Filesystem::readablePath($full_path, $this->getPath());
     } else {
         return false;
     }
 }
コード例 #22
0
 public function raiseLintInModule($key, $code, $desc, $places, $text = null)
 {
     if ($places) {
         foreach ($places as $place) {
             list($file, $offset) = explode(':', $place);
             $this->willLintPath(Filesystem::readablePath($this->getModulePathOnDisk($key) . '/' . $file, $this->getEngine()->getWorkingCopy()->getProjectRoot()));
             return $this->raiseLintAtOffset($offset, $code, $desc, $text);
         }
     } else {
         $this->willLintPath($this->getModuleDisplayName($key));
         return $this->raiseLintAtPath($code, $desc);
     }
 }
コード例 #23
0
 public function run()
 {
     $bootloader = PhutilBootloader::getInstance();
     $affected_modules = 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);
         if (!is_dir($path)) {
             $path = dirname($path);
         }
         if ($path == $library_root) {
             continue;
         }
         $library_path = Filesystem::readablePath($path, $library_root);
         do {
             // Add the module and all parent modules as affected modules, which
             // means we'll look for __tests__ to run here and in any containing
             // module.
             $affected_modules[$library_name . ':' . $library_path] = array('name' => $library_name, 'root' => $library_root, 'path' => $library_path);
             $library_path = dirname($library_path);
         } while ($library_path != '.');
     }
     $tests = array();
     foreach ($affected_modules as $library_info) {
         $library_name = $library_info['name'];
         $library_root = $library_info['root'];
         $module = $library_info['path'];
         if (basename($module) == '__tests__') {
             // Okay, this is a __tests__ module.
         } else {
             $exists = $bootloader->moduleExists($library_name, $module . '/__tests__');
             if ($exists) {
                 // This is a module which has a __tests__ module in it.
                 $module .= '/__tests__';
             } else {
                 // Look for a parent named __tests__.
                 $rpos = strrpos($module, '/__tests__');
                 if ($rpos === false) {
                     // No tests to run since there is no child or parent module named
                     // __tests__.
                     continue;
                 }
                 // Select the parent named __tests__.
                 $module = substr($module, 0, $rpos + strlen('/__tests__'));
             }
         }
         $module_key = $library_name . ':' . $module;
         $tests[$module_key] = array('library' => $library_name, 'root' => $library_root, 'module' => $module);
     }
     if (!$tests) {
         throw new ArcanistNoEffectException("No tests to run.");
     }
     $run_tests = array();
     foreach ($tests as $test) {
         $symbols = id(new PhutilSymbolLoader())->setType('class')->setLibrary($test['library'])->setModule($test['module'])->setAncestorClass('ArcanistPhutilTestCase')->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. You may need to rebuild the phutil library map.");
     }
     $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) {
         PhutilSymbolLoader::loadClass($test_class);
         $test_case = newv($test_class, array());
         $test_case->setEnableCoverage($enable_coverage);
         $test_case->setProjectRoot($this->getWorkingCopy()->getProjectRoot());
         $test_case->setPaths($this->getPaths());
         $results[] = $test_case->run();
     }
     if ($results) {
         $results = call_user_func_array('array_merge', $results);
     }
     return $results;
 }
コード例 #24
0
 public function execute(PhutilArgumentParser $args)
 {
     $viewer = $this->getViewer();
     $device_name = $args->getArg('device');
     if (!strlen($device_name)) {
         throw new PhutilArgumentUsageException(pht('Specify a device with --device.'));
     }
     $device = id(new AlmanacDeviceQuery())->setViewer($viewer)->withNames(array($device_name))->executeOne();
     if (!$device) {
         throw new PhutilArgumentUsageException(pht('No such device "%s" exists!', $device_name));
     }
     $identify_as = $args->getArg('identify-as');
     $raw_device = $device_name;
     if (strlen($identify_as)) {
         $raw_device = $identify_as;
     }
     $identity_device = id(new AlmanacDeviceQuery())->setViewer($viewer)->withNames(array($raw_device))->executeOne();
     if (!$identity_device) {
         throw new PhutilArgumentUsageException(pht('No such device "%s" exists!', $raw_device));
     }
     $private_key_path = $args->getArg('private-key');
     if (!strlen($private_key_path)) {
         throw new PhutilArgumentUsageException(pht('Specify a private key with --private-key.'));
     }
     if (!Filesystem::pathExists($private_key_path)) {
         throw new PhutilArgumentUsageException(pht('No private key exists at path "%s"!', $private_key_path));
     }
     $raw_private_key = Filesystem::readFile($private_key_path);
     $phd_user = PhabricatorEnv::getEnvConfig('phd.user');
     if (!$phd_user) {
         throw new PhutilArgumentUsageException(pht('Config option "phd.user" is not set. You must set this option ' . 'so the private key can be stored with the correct permissions.'));
     }
     $tmp = new TempFile();
     list($err) = exec_manual('chown %s %s', $phd_user, $tmp);
     if ($err) {
         throw new PhutilArgumentUsageException(pht('Unable to change ownership of an identity file to daemon user ' . '"%s". Run this command as %s or root.', $phd_user, $phd_user));
     }
     $stored_public_path = AlmanacKeys::getKeyPath('device.pub');
     $stored_private_path = AlmanacKeys::getKeyPath('device.key');
     $stored_device_path = AlmanacKeys::getKeyPath('device.id');
     if (!$args->getArg('force')) {
         if (Filesystem::pathExists($stored_public_path)) {
             throw new PhutilArgumentUsageException(pht('This host already has a registered public key ("%s"). ' . 'Remove this key before registering the host, or use ' . '--force to overwrite it.', Filesystem::readablePath($stored_public_path)));
         }
         if (Filesystem::pathExists($stored_private_path)) {
             throw new PhutilArgumentUsageException(pht('This host already has a registered private key ("%s"). ' . 'Remove this key before registering the host, or use ' . '--force to overwrite it.', Filesystem::readablePath($stored_private_path)));
         }
     }
     // NOTE: We're writing the private key here so we can change permissions
     // on it without causing weird side effects to the file specified with
     // the `--private-key` flag. The file needs to have restrictive permissions
     // before `ssh-keygen` will willingly operate on it.
     $tmp_private = new TempFile();
     Filesystem::changePermissions($tmp_private, 0600);
     execx('chown %s %s', $phd_user, $tmp_private);
     Filesystem::writeFile($tmp_private, $raw_private_key);
     list($raw_public_key) = execx('ssh-keygen -y -f %s', $tmp_private);
     $key_object = PhabricatorAuthSSHPublicKey::newFromRawKey($raw_public_key);
     $public_key = id(new PhabricatorAuthSSHKeyQuery())->setViewer($this->getViewer())->withKeys(array($key_object))->withIsActive(true)->executeOne();
     if (!$public_key) {
         throw new PhutilArgumentUsageException(pht('The public key corresponding to the given private key is not ' . 'yet known to Phabricator. Associate the public key with an ' . 'Almanac device in the web interface before registering hosts ' . 'with it.'));
     }
     if ($public_key->getObjectPHID() !== $device->getPHID()) {
         $public_phid = $public_key->getObjectPHID();
         $public_handles = $viewer->loadHandles(array($public_phid));
         $public_handle = $public_handles[$public_phid];
         throw new PhutilArgumentUsageException(pht('The public key corresponding to the given private key is already ' . 'associated with an object ("%s") other than the specified ' . 'device ("%s"). You can not use a single private key to identify ' . 'multiple devices or users.', $public_handle->getFullName(), $device->getName()));
     }
     if (!$public_key->getIsTrusted()) {
         throw new PhutilArgumentUsageException(pht('The public key corresponding to the given private key is ' . 'properly associated with the device, but is not yet trusted. ' . 'Trust this key before registering devices with it.'));
     }
     echo tsprintf("%s\n", pht('Installing public key...'));
     $tmp_public = new TempFile();
     Filesystem::changePermissions($tmp_public, 0600);
     execx('chown %s %s', $phd_user, $tmp_public);
     Filesystem::writeFile($tmp_public, $raw_public_key);
     execx('mv -f %s %s', $tmp_public, $stored_public_path);
     echo tsprintf("%s\n", pht('Installing private key...'));
     execx('mv -f %s %s', $tmp_private, $stored_private_path);
     echo tsprintf("%s\n", pht('Installing device %s...', $raw_device));
     // The permissions on this file are more open because the webserver also
     // needs to read it.
     $tmp_device = new TempFile();
     Filesystem::changePermissions($tmp_device, 0644);
     execx('chown %s %s', $phd_user, $tmp_device);
     Filesystem::writeFile($tmp_device, $raw_device);
     execx('mv -f %s %s', $tmp_device, $stored_device_path);
     echo tsprintf("**<bg:green> %s </bg>** %s\n", pht('HOST REGISTERED'), pht('This host has been registered as "%s" and a trusted keypair ' . 'has been installed.', $raw_device));
 }
コード例 #25
0
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
$root = dirname(dirname(dirname(__FILE__)));
require_once $root . '/scripts/__init_script__.php';
if ($argc !== 1 || posix_isatty(STDIN)) {
    echo phutil_console_format("usage: find . -type f -name '*.php' | ./generate_php_symbols.php\n");
    exit(1);
}
$input = file_get_contents('php://stdin');
$input = trim($input);
$input = explode("\n", $input);
$data = array();
$futures = array();
foreach ($input as $file) {
    $file = Filesystem::readablePath($file);
    $data[$file] = Filesystem::readFile($file);
    $futures[$file] = xhpast_get_parser_future($data[$file]);
}
foreach (Futures($futures)->limit(8) as $file => $future) {
    $tree = XHPASTTree::newFromDataAndResolvedExecFuture($data[$file], $future->resolve());
    $root = $tree->getRootNode();
    $scopes = array();
    $functions = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION');
    foreach ($functions as $function) {
        $name = $function->getChildByIndex(2);
        print_symbol($file, 'function', $name);
    }
    $classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION');
    foreach ($classes as $class) {
        $class_name = $class->getChildByIndex(1);
コード例 #26
0
 private function findFilesInProject()
 {
     $raw_hashes = id(new FileFinder($this->getConfig('root')))->excludePath('*/.*')->withType('f')->setGenerateChecksums(true)->find();
     $version = $this->getDivinerAtomWorldVersion();
     $file_hashes = array();
     foreach ($raw_hashes as $file => $md5_hash) {
         $rel_file = Filesystem::readablePath($file, $this->getConfig('root'));
         // We want the hash to change if the file moves or Diviner gets updated,
         // not just if the file content changes. Derive a hash from everything
         // we care about.
         $file_hashes[$rel_file] = md5("{$rel_file}{$md5_hash}{$version}") . 'F';
     }
     return $file_hashes;
 }
コード例 #27
0
$args = new PhutilArgumentParser($argv);
$args->setTagline('regenerate CSS sprite sheets');
$args->setSynopsis(<<<EOHELP
**sprites**
    Rebuild CSS sprite sheets.

EOHELP
);
$args->parseStandardArguments();
$args->parse(array(array('name' => 'source', 'param' => 'directory', 'help' => 'Directory with sprite sources.')));
$srcroot = $args->getArg('source');
if (!$srcroot) {
    throw new Exception("You must specify a source directory with '--source'.");
}
$webroot = dirname(phutil_get_library_root('phabricator')) . '/webroot/rsrc';
$webroot = Filesystem::readablePath($webroot);
function glx($x)
{
    return 60 + 48 * $x;
}
function gly($y)
{
    return 110 + 48 * $y;
}
$sheet = new PhutilSpriteSheet();
$at = '@';
$sheet->setCSSHeader(<<<EOCSS
/**
 * @provides autosprite-css
 * {$at}generated
 */
コード例 #28
0
 public function run()
 {
     $console = PhutilConsole::getConsole();
     $is_force = $this->getArgument('force');
     $things = $this->getArgument('paths');
     if (!$things) {
         throw new ArcanistUsageException(pht('Specify one or more paths or objects to browse. Use the command ' . '"%s" if you want to browse this directory.', 'arc browse .'));
     }
     $things = array_fuse($things);
     $objects = $this->getConduit()->callMethodSynchronous('phid.lookup', array('names' => array_keys($things)));
     $uris = array();
     foreach ($objects as $name => $object) {
         $uris[] = $object['uri'];
         $console->writeOut(pht('Opening **%s** as an object.', $name) . "\n");
         unset($things[$name]);
     }
     if ($this->hasRepositoryAPI()) {
         $repository_api = $this->getRepositoryAPI();
         $project_root = $this->getWorkingCopy()->getProjectRoot();
         // First, try to resolve arguments as symbolic commits.
         $commits = array();
         foreach ($things as $key => $thing) {
             if ($thing == '.') {
                 // Git resolves '.' like HEAD, but it should be interpreted to mean
                 // "the current directory". Just skip resolution and fall through.
                 continue;
             }
             try {
                 $commit = $repository_api->getCanonicalRevisionName($thing);
                 if ($commit) {
                     $commits[$commit] = $key;
                 }
             } catch (Exception $ex) {
                 // Ignore.
             }
         }
         if ($commits) {
             $commit_info = $this->getConduit()->callMethodSynchronous('diffusion.querycommits', array('repositoryPHID' => $this->getRepositoryPHID(), 'names' => array_keys($commits)));
             foreach ($commit_info['identifierMap'] as $ckey => $cphid) {
                 $thing = $commits[$ckey];
                 unset($things[$thing]);
                 $uris[] = $commit_info['data'][$cphid]['uri'];
                 $console->writeOut(pht('Opening **%s** as a commit.', $thing) . "\n");
             }
         }
         // If we fail, try to resolve them as paths.
         foreach ($things as $key => $path) {
             $lines = null;
             $parts = explode(':', $path);
             if (count($parts) > 1) {
                 $lines = array_pop($parts);
             }
             $path = implode(':', $parts);
             $full_path = Filesystem::resolvePath($path);
             if (!$is_force && !Filesystem::pathExists($full_path)) {
                 continue;
             }
             $console->writeOut(pht('Opening **%s** as a repository path.', $key) . "\n");
             unset($things[$key]);
             if ($full_path == $project_root) {
                 $path = '';
             } else {
                 $path = Filesystem::readablePath($full_path, $project_root);
             }
             $base_uri = $this->getBaseURI();
             $uri = $base_uri . $path;
             if ($lines) {
                 $uri = $uri . '$' . $lines;
             }
             $uris[] = $uri;
         }
     } else {
         if ($things) {
             $console->writeOut("%s\n", pht("The current working directory is not a repository working " . "copy, so remaining arguments can not be resolved as paths or " . "commits. To browse paths or symbolic commits in Diffusion, run " . "'%s' from inside a working copy.", 'arc browse'));
         }
     }
     foreach ($things as $thing) {
         $console->writeOut("%s\n", pht('Unable to find an object named **%s**, no such commit exists in ' . 'the remote, and no such path exists in the working copy. Use ' . '__%s__ to treat this as a path anyway.', $thing, '--force'));
     }
     if ($uris) {
         $this->openURIsInBrowser($uris);
     }
     return 0;
 }
コード例 #29
0
 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;
 }
コード例 #30
0
 private function renderFindResults(array $results)
 {
     $drequest = $this->getDiffusionRequest();
     $rows = array();
     foreach ($results as $result) {
         $href = $drequest->generateURI(array('action' => 'browse', 'path' => $result));
         $readable = Filesystem::readablePath($result, $drequest->getPath());
         $rows[] = array(phutil_tag('a', array('href' => $href), $readable));
     }
     $table = id(new AphrontTableView($rows))->setHeaders(array(pht('Path')))->setColumnClasses(array('wide'))->setNoDataString(pht('The pattern you searched for did not match the names of any ' . 'files.'));
     return $table;
 }