diff --git a/resources/sql/autopatches/20150503.repositorysymbols.1.sql b/resources/sql/autopatches/20150503.repositorysymbols.1.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20150503.repositorysymbols.1.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_repository.repository_symbol + ADD repositoryPHID varbinary(64) NOT NULL AFTER arcanistProjectID; diff --git a/resources/sql/autopatches/20150503.repositorysymbols.2.php b/resources/sql/autopatches/20150503.repositorysymbols.2.php new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20150503.repositorysymbols.2.php @@ -0,0 +1,26 @@ +setViewer(PhabricatorUser::getOmnipotentUser()) + ->needRepositories(true) + ->execute(); + +$table = new PhabricatorRepositorySymbol(); +$conn_w = $table->establishConnection('w'); + +foreach ($projects as $project) { + $repo = $project->getRepository(); + + if (!$repo) { + continue; + } + + echo pht("Migrating symbols for '%s' project...\n", $project->getName()); + + queryfx( + $conn_w, + 'UPDATE %T SET repositoryPHID = %s WHERE arcanistProjectID = %d', + $table->getTableName(), + $repo->getPHID(), + $project->getID()); +} diff --git a/resources/sql/autopatches/20150503.repositorysymbols.3.sql b/resources/sql/autopatches/20150503.repositorysymbols.3.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20150503.repositorysymbols.3.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_repository.repository_symbol + DROP COLUMN arcanistProjectID; diff --git a/scripts/symbols/clear_project_symbols.php b/scripts/symbols/clear_project_symbols.php deleted file mode 100755 --- a/scripts/symbols/clear_project_symbols.php +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env php -loadOneWhere( - 'name = %s', $argv[1]); -if (!$project) { - throw new Exception('No such arcanist project.'); -} - -$input = file_get_contents('php://stdin'); -$normalized = array(); -foreach (explode("\n", trim($input)) as $path) { - // emulate the behavior of the symbol generation scripts - $normalized[] = '/'.ltrim($path, './'); -} -$paths = PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( - $normalized); - -$symbol = new PhabricatorRepositorySymbol(); -$conn_w = $symbol->establishConnection('w'); - -foreach (array_chunk(array_values($paths), 128) as $chunk) { - queryfx( - $conn_w, - 'DELETE FROM %T WHERE arcanistProjectID = %d AND pathID IN (%Ld)', - $symbol->getTableName(), - $project->getID(), - $chunk); -} diff --git a/scripts/symbols/clear_repository_symbols.php b/scripts/symbols/clear_repository_symbols.php new file mode 100755 --- /dev/null +++ b/scripts/symbols/clear_repository_symbols.php @@ -0,0 +1,58 @@ +#!/usr/bin/env php +setSynopsis(<<parseStandardArguments(); +$args->parse( + array( + array( + 'name' => 'callsign', + 'wildcard' => true, + ), + )); + +$callsigns = $args->getArg('callsign'); +if (count($callsigns) !== 1) { + $args->printHelpAndExit(); +} + +$callsign = head($callsigns); +$repository = id(new PhabricatorRepositoryQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withCallsigns($callsigns) + ->executeOne(); + +if (!$repository) { + echo pht("Repository '%s' does not exist.", $callsign); + exit(1); +} + +$input = file_get_contents('php://stdin'); +$normalized = array(); +foreach (explode("\n", trim($input)) as $path) { + // Emulate the behavior of the symbol generation scripts. + $normalized[] = '/'.ltrim($path, './'); +} +$paths = PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( + $normalized); + +$symbol = new PhabricatorRepositorySymbol(); +$conn_w = $symbol->establishConnection('w'); + +foreach (array_chunk(array_values($paths), 128) as $chunk) { + queryfx( + $conn_w, + 'DELETE FROM %T WHERE repositoryPHID = %s AND pathID IN (%Ld)', + $symbol->getTableName(), + $repository->getPHID(), + $chunk); +} diff --git a/scripts/symbols/generate_ctags_symbols.php b/scripts/symbols/generate_ctags_symbols.php --- a/scripts/symbols/generate_ctags_symbols.php +++ b/scripts/symbols/generate_ctags_symbols.php @@ -4,79 +4,94 @@ $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/__init_script__.php'; +$args = new PhutilArgumentParser($argv); +$args->setSynopsis(<<parseStandardArguments(); + if (ctags_check_executable() == false) { echo phutil_console_format( - "Could not find Exuberant ctags. Make sure it is installed and\n". - "available in executable path.\n\n". - "Exuberant ctags project page: http://ctags.sourceforge.net/\n"); + "%s\n\n%s\n", + pht( + 'Could not find Exuberant Ctags. Make sure it is installed and '. + 'available in executable path.'), + pht( + 'Exuberant Ctags project page: %s', + 'http://ctags.sourceforge.net/')); exit(1); } -if ($argc !== 1 || posix_isatty(STDIN)) { +if (posix_isatty(STDIN)) { echo phutil_console_format( - "usage: find . -type f -name '*.py' | ./generate_ctags_symbols.php\n"); + "%s\n", + pht( + 'Usage: %s', + "find . -type f -name '*.py' | ./generate_ctags_symbols.php")); exit(1); } $input = file_get_contents('php://stdin'); -$input = trim($input); -$input = explode("\n", $input); - $data = array(); $futures = array(); -foreach ($input as $file) { +foreach (explode("\n", trim($input)) as $file) { $file = Filesystem::readablePath($file); $futures[$file] = ctags_get_parser_future($file); } -$futures = id(new FutureIterator($futures)) - ->limit(8); -foreach ($futures as $file => $future) { +$futures = new FutureIterator($futures); +foreach ($futures->limit(8) as $file => $future) { $tags = $future->resolve(); $tags = explode("\n", $tags[1]); foreach ($tags as $tag) { $parts = explode(';', $tag); - // skip lines that we can not parse + + // Skip lines that we can not parse. if (count($parts) < 2) { continue; } - // split ctags information + // Split ctags information. $tag_info = explode("\t", $parts[0]); - // split exuberant ctags "extension fields" (additional information) + + // Split exuberant ctags "extension fields" (additional information). $parts[1] = trim($parts[1], "\t \""); $extension_fields = explode("\t", $parts[1]); - // skip lines that we can not parse + // Skip lines that we can not parse. if (count($tag_info) < 3 || count($extension_fields) < 2) { continue; } - // default $context to empty + // Default context to empty. $extension_fields[] = ''; list($token, $file_path, $line_num) = $tag_info; list($type, $language, $context) = $extension_fields; - // skip lines with tokens containing a space + // Skip lines with tokens containing a space. if (strpos($token, ' ') !== false) { continue; } - // strip "language:" + // Strip "language:" $language = substr($language, 9); // To keep consistent with "Separate with commas, for example: php, py" // in Arcanist Project edit form. $language = str_ireplace('python', 'py', $language); - // also, "normalize" c++ and c# + // Also, "normalize" C++ and C#. $language = str_ireplace('c++', 'cpp', $language); $language = str_ireplace('c#', 'cs', $language); - // Ruby has "singleton method", for example + // Ruby has "singleton method", for example. $type = substr(str_replace(' ', '_', $type), 0, 12); + // class:foo, struct:foo, union:foo, enum:foo, ... $context = last(explode(':', $context, 2)); @@ -89,25 +104,18 @@ } } -function ctags_get_parser_future($file_path) { - $future = new ExecFuture('ctags -n --fields=Kls -o - %s', - $file_path); +function ctags_get_parser_future($path) { + $future = new ExecFuture('ctags -n --fields=Kls -o - %s', $path); return $future; } function ctags_check_executable() { - $future = new ExecFuture('ctags --version'); - $result = $future->resolve(); - - if (empty($result[1])) { - return false; - } - - return true; + $result = exec_manual('ctags --version'); + return !empty($result[1]); } function print_symbol($file, $line_num, $type, $token, $context, $language) { - // get rid of relative path + // Get rid of relative path. $file = explode('/', $file); if ($file[0] == '.' || $file[0] == '..') { array_shift($file); diff --git a/scripts/symbols/generate_php_symbols.php b/scripts/symbols/generate_php_symbols.php --- a/scripts/symbols/generate_php_symbols.php +++ b/scripts/symbols/generate_php_symbols.php @@ -4,28 +4,36 @@ $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/__init_script__.php'; -if ($argc !== 1 || posix_isatty(STDIN)) { +$args = new PhutilArgumentParser($argv); +$args->setSynopsis(<<parseStandardArguments(); + +if (posix_isatty(STDIN)) { echo phutil_console_format( - "usage: find . -type f -name '*.php' | ./generate_php_symbols.php\n"); + "%s\n", + pht( + 'Usage: %s', + "find . -type f -name '*.php' | ./generate_php_symbols.php")); exit(1); } $input = file_get_contents('php://stdin'); -$input = trim($input); -$input = explode("\n", $input); - $data = array(); $futures = array(); -foreach ($input as $file) { +foreach (explode("\n", trim($input)) as $file) { $file = Filesystem::readablePath($file); $data[$file] = Filesystem::readFile($file); $futures[$file] = PhutilXHPASTBinary::getParserFuture($data[$file]); } -$futures = id(new FutureIterator($futures)) - ->limit(8); -foreach ($futures as $file => $future) { +$futures = new FutureIterator($futures); +foreach ($futures->limit(8) as $file => $future) { $tree = XHPASTTree::newFromDataAndResolvedExecFuture( $data[$file], $future->resolve()); @@ -36,7 +44,7 @@ $functions = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); foreach ($functions as $function) { $name = $function->getChildByIndex(2); - // Skip anonymous functions + // Skip anonymous functions. if (!$name->getConcreteString()) { continue; } @@ -67,8 +75,8 @@ } foreach ($scopes as $scope) { - // this prints duplicate symbols in the case of nested classes - // luckily, PHP doesn't allow those + // This prints duplicate symbols in the case of nested classes. + // Luckily, PHP doesn't allow those. list($class, $class_name) = $scope; $consts = $class->selectDescendantsOfType( @@ -100,15 +108,15 @@ } } -function print_symbol($file, $type, $token, $context = null) { +function print_symbol($file, $type, XHPASTNode $node, $context = null) { $parts = array( $context ? $context->getConcreteString() : '', - // variable tokens are `$name`, not just `name`, so strip the $ off of + // Variable tokens are `$name`, not just `name`, so strip the "$"" off of // class field names - ltrim($token->getConcreteString(), '$'), + ltrim($node->getConcreteString(), '$'), $type, 'php', - $token->getLineNumber(), + $node->getLineNumber(), '/'.ltrim($file, './'), ); echo implode(' ', $parts)."\n"; diff --git a/scripts/symbols/import_project_symbols.php b/scripts/symbols/import_project_symbols.php deleted file mode 100755 --- a/scripts/symbols/import_project_symbols.php +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env php -setSynopsis(<<parseStandardArguments(); -$args->parse( - array( - array( - 'name' => 'no-purge', - 'help' => 'Do not clear all symbols for this project before '. - 'uploading new symbols. Useful for incremental updating.', - ), - array( - 'name' => 'ignore-errors', - 'help' => 'If a line can\'t be parsed, ignore that line and '. - 'continue instead of exiting.', - ), - array( - 'name' => 'max-transaction', - 'param' => 'num-syms', - 'default' => '100000', - 'help' => 'Maximum number of symbols that should '. - 'be part of a single transaction', - ), - array( - 'name' => 'more', - 'wildcard' => true, - ), - )); - -$more = $args->getArg('more'); -if (count($more) !== 1) { - $args->printHelpAndExit(); -} - -$project_name = head($more); -$project = id(new PhabricatorRepositoryArcanistProject())->loadOneWhere( - 'name = %s', - $project_name); - -if (!$project) { - // TODO: Provide a less silly way to do this explicitly, or just do it right - // here. - echo "Project '{$project_name}' is unknown. Upload a diff to implicitly ". - "create it.\n"; - exit(1); -} - -echo "Parsing input from stdin...\n"; -$input = file_get_contents('php://stdin'); -$input = trim($input); -$input = explode("\n", $input); - - -function commit_symbols ($syms, $project, $no_purge) { - echo "Looking up path IDs...\n"; - $path_map = - PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( - ipull($syms, 'path')); - - $symbol = new PhabricatorRepositorySymbol(); - $conn_w = $symbol->establishConnection('w'); - - echo "Preparing queries...\n"; - $sql = array(); - foreach ($syms as $dict) { - $sql[] = qsprintf( - $conn_w, - '(%d, %s, %s, %s, %s, %d, %d)', - $project->getID(), - $dict['ctxt'], - $dict['name'], - $dict['type'], - $dict['lang'], - $dict['line'], - $path_map[$dict['path']]); - } - - if (!$no_purge) { - echo "Purging old syms...\n"; - queryfx($conn_w, - 'DELETE FROM %T WHERE arcanistProjectID = %d', - $symbol->getTableName(), - $project->getID()); - } - - echo "Loading ".number_format(count($sql))." syms...\n"; - foreach (array_chunk($sql, 128) as $chunk) { - queryfx($conn_w, - 'INSERT INTO %T - (arcanistProjectID, symbolContext, symbolName, symbolType, - symbolLanguage, lineNumber, pathID) VALUES %Q', - $symbol->getTableName(), - implode(', ', $chunk)); - } - -} - -function check_string_value($value, $field_name, $line_no, $max_length) { - if (strlen($value) > $max_length) { - throw new Exception( - "{$field_name} '{$value}' defined on line #{$line_no} is too long, ". - "maximum {$field_name} length is {$max_length} characters."); - } - - if (!phutil_is_utf8_with_only_bmp_characters($value)) { - throw new Exception( - "{$field_name} '{$value}' defined on line #{$line_no} is not a valid ". - "UTF-8 string, ". - "it should contain only UTF-8 characters."); - } -} - -$no_purge = $args->getArg('no-purge'); -$symbols = array(); -foreach ($input as $key => $line) { - try { - $line_no = $key + 1; - $matches = null; - $ok = preg_match( - '/^((?P[^ ]+)? )?(?P[^ ]+) (?P[^ ]+) '. - '(?P[^ ]+) (?P\d+) (?P.*)$/', - $line, - $matches); - if (!$ok) { - throw new Exception( - "Line #{$line_no} of input is invalid. Expected five or six ". - "space-delimited fields: maybe symbol context, symbol name, symbol ". - "type, symbol language, line number, path. ". - "For example:\n\n". - "idx function php 13 /path/to/some/file.php\n\n". - "Actual line was:\n\n". - "{$line}"); - } - if (empty($matches['context'])) { - $matches['context'] = ''; - } - $context = $matches['context']; - $name = $matches['name']; - $type = $matches['type']; - $lang = $matches['lang']; - $line_number = $matches['line']; - $path = $matches['path']; - - check_string_value($context, 'Symbol context', $line_no, 128); - check_string_value($name, 'Symbol name', $line_no, 128); - check_string_value($type, 'Symbol type', $line_no, 12); - check_string_value($lang, 'Symbol language', $line_no, 32); - check_string_value($path, 'Path', $line_no, 512); - - if (!strlen($path) || $path[0] != '/') { - throw new Exception( - "Path '{$path}' defined on line #{$line_no} is invalid. Paths should ". - "begin with '/' and specify a path from the root of the project, like ". - "'/src/utils/utils.php'."); - } - - $symbols[] = array( - 'ctxt' => $context, - 'name' => $name, - 'type' => $type, - 'lang' => $lang, - 'line' => $line_number, - 'path' => $path, - ); - } catch (Exception $e) { - if ($args->getArg('ignore-errors')) { - continue; - } else { - throw $e; - } - } - - if (count ($symbols) >= $args->getArg('max-transaction')) { - try { - echo "Committing {$args->getArg('max-transaction')} symbols....\n"; - commit_symbols($symbols, $project, $no_purge); - $no_purge = true; - unset($symbols); - $symbols = array(); - } catch (Exception $e) { - if ($args->getArg('ignore-errors')) { - continue; - } else { - throw $e; - } - } - } -} - -if (count($symbols)) { - commit_symbols($symbols, $project, $no_purge); -} - -echo "Done.\n"; diff --git a/scripts/symbols/import_repository_symbols.php b/scripts/symbols/import_repository_symbols.php new file mode 100755 --- /dev/null +++ b/scripts/symbols/import_repository_symbols.php @@ -0,0 +1,228 @@ +#!/usr/bin/env php +setSynopsis(<<parseStandardArguments(); +$args->parse( + array( + array( + 'name' => 'no-purge', + 'help' => pht( + 'Do not clear all symbols for this repository before '. + 'uploading new symbols. Useful for incremental updating.'), + ), + array( + 'name' => 'ignore-errors', + 'help' => pht( + "If a line can't be parsed, ignore that line and ". + "continue instead of exiting."), + ), + array( + 'name' => 'max-transaction', + 'param' => 'num-syms', + 'default' => '100000', + 'help' => pht( + 'Maximum number of symbols that should '. + 'be part of a single transaction.'), + ), + array( + 'name' => 'more', + 'wildcard' => true, + ), + )); + +$more = $args->getArg('more'); +if (count($more) !== 1) { + $args->printHelpAndExit(); +} + +$callsign = head($more); +$repository = id(new PhabricatorRepository())->loadOneWhere( + 'callsign = %s', + $callsign); + +if (!$repository) { + echo pht("Repository '%s' does not exist.", $callsign); + exit(1); +} + +if (!function_exists('posix_isatty') || posix_isatty(STDIN)) { + echo pht('Parsing input from stdin...'), "\n"; +} + +$input = file_get_contents('php://stdin'); +$input = trim($input); +$input = explode("\n", $input); + + +function commit_symbols( + array $symbols, + PhabricatorRepository $repository, + $no_purge) { + + echo pht('Looking up path IDs...'), "\n"; + $path_map = + PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( + ipull($symbols, 'path')); + + $symbol = new PhabricatorRepositorySymbol(); + $conn_w = $symbol->establishConnection('w'); + + echo pht('Preparing queries...'), "\n"; + $sql = array(); + foreach ($symbols as $dict) { + $sql[] = qsprintf( + $conn_w, + '(%s, %s, %s, %s, %s, %d, %d)', + $repository->getPHID(), + $dict['ctxt'], + $dict['name'], + $dict['type'], + $dict['lang'], + $dict['line'], + $path_map[$dict['path']]); + } + + if (!$no_purge) { + echo pht('Purging old symbols...'), "\n"; + queryfx( + $conn_w, + 'DELETE FROM %T WHERE repositoryPHID = %s', + $symbol->getTableName(), + $repository->getPHID()); + } + + echo pht('Loading %s symbols...', new PhutilNumber(count($sql))), "\n"; + foreach (array_chunk($sql, 128) as $chunk) { + queryfx( + $conn_w, + 'INSERT INTO %T + (repositoryPHID, symbolContext, symbolName, symbolType, + symbolLanguage, lineNumber, pathID) VALUES %Q', + $symbol->getTableName(), + implode(', ', $chunk)); + } +} + +function check_string_value($value, $field_name, $line_no, $max_length) { + if (strlen($value) > $max_length) { + throw new Exception( + pht( + "%s '%s' defined on line #%d is too long, ". + "maximum %s length is %d characters.", + $field_name, + $value, + $line_no, + $field_name, + $max_length)); + } + + if (!phutil_is_utf8_with_only_bmp_characters($value)) { + throw new Exception( + pht( + "%s '%s' defined on line #%d is not a valid ". + "UTF-8 string, it should contain only UTF-8 characters.", + $field_name, + $value, + $line_no)); + } +} + +$no_purge = $args->getArg('no-purge'); +$symbols = array(); +foreach ($input as $key => $line) { + try { + $line_no = $key + 1; + $matches = null; + $ok = preg_match( + '/^((?P[^ ]+)? )?(?P[^ ]+) (?P[^ ]+) '. + '(?P[^ ]+) (?P\d+) (?P.*)$/', + $line, + $matches); + if (!$ok) { + throw new Exception( + pht( + "Line #%d of input is invalid. Expected five or six space-delimited ". + "fields: maybe symbol context, symbol name, symbol type, symbol ". + "language, line number, path. For example:\n\n%s\n\n". + "Actual line was:\n\n%s", + $line_no, + 'idx function php 13 /path/to/some/file.php', + $line)); + } + if (empty($matches['context'])) { + $matches['context'] = ''; + } + $context = $matches['context']; + $name = $matches['name']; + $type = $matches['type']; + $lang = $matches['lang']; + $line_number = $matches['line']; + $path = $matches['path']; + + check_string_value($context, 'Symbol context', $line_no, 128); + check_string_value($name, 'Symbol name', $line_no, 128); + check_string_value($type, 'Symbol type', $line_no, 12); + check_string_value($lang, 'Symbol language', $line_no, 32); + check_string_value($path, 'Path', $line_no, 512); + + if (!strlen($path) || $path[0] != '/') { + throw new Exception( + pht( + "Path '%s' defined on line #%d is invalid. Paths should begin with ". + "'%s' and specify a path from the root of the project, like '%s'.", + $path, + $line_no, + '/', + '/src/utils/utils.php')); + } + + $symbols[] = array( + 'ctxt' => $context, + 'name' => $name, + 'type' => $type, + 'lang' => $lang, + 'line' => $line_number, + 'path' => $path, + ); + } catch (Exception $e) { + if ($args->getArg('ignore-errors')) { + continue; + } else { + throw $e; + } + } + + if (count ($symbols) >= $args->getArg('max-transaction')) { + try { + echo pht( + "Committing %s symbols...\n", + new PhutilNumber($args->getArg('max-transaction'))); + commit_symbols($symbols, $repository, $no_purge); + $no_purge = true; + unset($symbols); + $symbols = array(); + } catch (Exception $e) { + if ($args->getArg('ignore-errors')) { + continue; + } else { + throw $e; + } + } + } +} + +if (count($symbols)) { + commit_symbols($symbols, $repository, $no_purge); +} + +echo pht('Done.'), "\n"; diff --git a/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php --- a/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php +++ b/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php @@ -8,7 +8,7 @@ } public function getMethodDescription() { - return 'Retrieve Diffusion symbol information.'; + return pht('Retrieve Diffusion symbol information.'); } protected function defineParamTypes() { @@ -51,7 +51,6 @@ } $query->needPaths(true); - $query->needArcanistProjects(true); $query->needRepositories(true); $results = $query->execute(); diff --git a/src/applications/diffusion/controller/DiffusionSymbolController.php b/src/applications/diffusion/controller/DiffusionSymbolController.php --- a/src/applications/diffusion/controller/DiffusionSymbolController.php +++ b/src/applications/diffusion/controller/DiffusionSymbolController.php @@ -24,25 +24,25 @@ $query->setLanguage($request->getStr('lang')); } - if ($request->getStr('projects')) { - $phids = $request->getStr('projects'); + if ($request->getStr('repositories')) { + $phids = $request->getStr('repositories'); $phids = explode(',', $phids); $phids = array_filter($phids); if ($phids) { - $projects = id(new PhabricatorRepositoryArcanistProject()) - ->loadAllWhere( - 'phid IN (%Ls)', - $phids); - $projects = mpull($projects, 'getID'); - if ($projects) { - $query->setProjectIDs($projects); + $repos = id(new PhabricatorRepositoryQuery()) + ->setViewer($request->getUser()) + ->withPHIDs($phids) + ->execute(); + + $repos = mpull($repos, 'getPHID'); + if ($repos) { + $query->withRepositoryPHIDs($repos); } } } $query->needPaths(true); - $query->needArcanistProjects(true); $query->needRepositories(true); $symbols = $query->execute(); @@ -73,13 +73,6 @@ $rows = array(); foreach ($symbols as $symbol) { - $project = $symbol->getArcanistProject(); - if ($project) { - $project_name = $project->getName(); - } else { - $project_name = '-'; - } - $file = $symbol->getPath(); $line = $symbol->getLineNumber(); @@ -110,7 +103,7 @@ $symbol->getSymbolContext(), $symbol->getSymbolName(), $symbol->getSymbolLanguage(), - $project_name, + $repo->getMonogram(), $location, ); } @@ -122,7 +115,7 @@ pht('Context'), pht('Name'), pht('Language'), - pht('Project'), + pht('Repository'), pht('File'), )); $table->setColumnClasses( diff --git a/src/applications/diffusion/query/DiffusionSymbolQuery.php b/src/applications/diffusion/query/DiffusionSymbolQuery.php --- a/src/applications/diffusion/query/DiffusionSymbolQuery.php +++ b/src/applications/diffusion/query/DiffusionSymbolQuery.php @@ -16,12 +16,11 @@ private $namePrefix; private $name; - private $projectIDs; + private $repositoryPHIDs; private $language; private $type; private $needPaths; - private $needArcanistProject; private $needRepositories; @@ -72,8 +71,8 @@ /** * @task config */ - public function setProjectIDs(array $project_ids) { - $this->projectIDs = $project_ids; + public function withRepositoryPHIDs(array $repository_phids) { + $this->repositoryPHIDs = $repository_phids; return $this; } @@ -108,15 +107,6 @@ /** * @task config */ - public function needArcanistProjects($need_arcanist_projects) { - $this->needArcanistProjects = $need_arcanist_projects; - return $this; - } - - - /** - * @task config - */ public function needRepositories($need_repositories) { $this->needRepositories = $need_repositories; return $this; @@ -132,10 +122,10 @@ public function execute() { if ($this->name && $this->namePrefix) { throw new Exception( - 'You can not set both a name and a name prefix!'); + pht('You can not set both a name and a name prefix!')); } else if (!$this->name && !$this->namePrefix) { throw new Exception( - 'You must set a name or a name prefix!'); + pht('You must set a name or a name prefix!')); } $symbol = new PhabricatorRepositorySymbol(); @@ -155,9 +145,6 @@ if ($this->needPaths) { $this->loadPaths($symbols); } - if ($this->needArcanistProjects || $this->needRepositories) { - $this->loadArcanistProjects($symbols); - } if ($this->needRepositories) { $this->loadRepositories($symbols); } @@ -208,11 +195,11 @@ $this->namePrefix); } - if ($this->projectIDs) { + if ($this->repositoryPHIDs) { $where[] = qsprintf( $conn_r, - 'arcanistProjectID IN (%Ld)', - $this->projectIDs); + 'repositoryPHID IN (%Ls)', + $this->repositoryPHIDs); } if ($this->language) { @@ -253,46 +240,18 @@ /** * @task internal */ - private function loadArcanistProjects(array $symbols) { - assert_instances_of($symbols, 'PhabricatorRepositorySymbol'); - $projects = id(new PhabricatorRepositoryArcanistProject())->loadAllWhere( - 'id IN (%Ld)', - mpull($symbols, 'getArcanistProjectID')); - foreach ($symbols as $symbol) { - $project = idx($projects, $symbol->getArcanistProjectID()); - $symbol->attachArcanistProject($project); - } - } - - - /** - * @task internal - */ private function loadRepositories(array $symbols) { assert_instances_of($symbols, 'PhabricatorRepositorySymbol'); - $projects = mpull($symbols, 'getArcanistProject'); - $projects = array_filter($projects); - - $repo_ids = mpull($projects, 'getRepositoryID'); - $repo_ids = array_filter($repo_ids); - - if ($repo_ids) { - $repos = id(new PhabricatorRepositoryQuery()) - ->setViewer($this->getViewer()) - ->withIDs($repo_ids) - ->execute(); - } else { - $repos = array(); - } + $repos = id(new PhabricatorRepositoryQuery()) + ->setViewer($this->viewer) + ->withPHIDs(mpull($symbols, 'getRepositoryPHID')) + ->execute(); + $repos = mpull($repos, null, 'getPHID'); foreach ($symbols as $symbol) { - $proj = $symbol->getArcanistProject(); - if ($proj) { - $symbol->attachRepository(idx($repos, $proj->getRepositoryID())); - } else { - $symbol->attachRepository(null); - } + $repository = idx($repos, $symbol->getRepositoryPHID()); + $symbol->attachRepository($repository); } } diff --git a/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php b/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php --- a/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php +++ b/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php @@ -32,7 +32,6 @@ ->setViewer($viewer) ->setNamePrefix($raw_query) ->setLimit(15) - ->needArcanistProjects(true) ->needRepositories(true) ->needPaths(true) ->execute(); @@ -40,14 +39,14 @@ $lang = $symbol->getSymbolLanguage(); $name = $symbol->getSymbolName(); $type = $symbol->getSymbolType(); - $proj = $symbol->getArcanistProject()->getName(); + $repo = $symbol->getRepository()->getName(); $results[] = id(new PhabricatorTypeaheadResult()) ->setName($name) ->setURI($symbol->getURI()) ->setPHID(md5($symbol->getURI())) // Just needs to be unique. ->setDisplayName($name) - ->setDisplayType(strtoupper($lang).' '.ucwords($type).' ('.$proj.')') + ->setDisplayType(strtoupper($lang).' '.ucwords($type).' ('.$repo.')') ->setPriorityType('symb'); } } diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -1163,10 +1163,15 @@ $projects = id(new PhabricatorRepositoryArcanistProject()) ->loadAllWhere('repositoryID = %d', $this->getID()); foreach ($projects as $project) { - // note each project deletes its PhabricatorRepositorySymbols $project->delete(); } + queryfx( + $this->establishConnection('w'), + 'DELETE FROM %T WHERE repositoryPHID = %s', + id(new PhabricatorRepositorySymbol())->getTableName(), + $this->getPHID()); + $commits = id(new PhabricatorRepositoryCommit()) ->loadAllWhere('repositoryID = %d', $this->getID()); foreach ($commits as $commit) { diff --git a/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php b/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php --- a/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php +++ b/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php @@ -45,20 +45,6 @@ PhabricatorRepositoryArcanistProjectPHIDType::TYPECONST); } - public function delete() { - $this->openTransaction(); - - queryfx( - $this->establishConnection('w'), - 'DELETE FROM %T WHERE arcanistProjectID = %d', - id(new PhabricatorRepositorySymbol())->getTableName(), - $this->getID()); - - $result = parent::delete(); - $this->saveTransaction(); - return $result; - } - public function getRepository() { return $this->assertAttached($this->repository); } diff --git a/src/applications/repository/storage/PhabricatorRepositorySymbol.php b/src/applications/repository/storage/PhabricatorRepositorySymbol.php --- a/src/applications/repository/storage/PhabricatorRepositorySymbol.php +++ b/src/applications/repository/storage/PhabricatorRepositorySymbol.php @@ -8,7 +8,7 @@ */ final class PhabricatorRepositorySymbol extends PhabricatorRepositoryDAO { - protected $arcanistProjectID; + protected $repositoryPHID; protected $symbolContext; protected $symbolName; protected $symbolType; @@ -17,12 +17,10 @@ protected $lineNumber; private $path = self::ATTACHABLE; - private $arcanistProject = self::ATTACHABLE; private $repository = self::ATTACHABLE; protected function getConfiguration() { return array( - self::CONFIG_IDS => self::IDS_MANUAL, self::CONFIG_TIMESTAMPS => false, self::CONFIG_COLUMN_SCHEMA => array( 'id' => null, @@ -42,13 +40,6 @@ } public function getURI() { - if (!$this->repository) { - // This symbol is in the index, but we don't know which Repository it's - // part of. Usually this means the Arcanist Project hasn't been linked - // to a Repository. We can't generate a URI, so just fail. - return null; - } - $request = DiffusionRequest::newFromDictionary( array( 'user' => PhabricatorUser::getOmnipotentUser(), @@ -75,18 +66,9 @@ return $this->assertAttached($this->repository); } - public function attachRepository($repository) { + public function attachRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; } - public function getArcanistProject() { - return $this->assertAttached($this->arcanistProject); - } - - public function attachArcanistProject($project) { - $this->arcanistProject = $project; - return $this; - } - }