1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00
phorge-phorge/scripts/symbols/import_project_symbols.php
Alan Huang a8d6af0f42 Infrastructure changes to support scoped symbols
Summary:
 - import_project_symbols supports an optional extra field, which is the
   context of the symbol.
 - Symbol query can take a symbol argument, either as a parameter or a
   URL component (so you can now jump nav to `s Zerg/rush`, for
   example).
 - Conduit method not yet updated. Will do that later.

NOTE: Not providing a context is distinct from providing an empty
context, because an empty context stands for top-level context, i.e.
functions and classes for PHP. It will not find class methods, etc. It
is possible that we should use some weird token that could not normally
be a context name to stand in for empty context.

Test Plan: Do a bunch of symbol searches.

Reviewers: epriestley

Reviewed By: epriestley

CC: nh, aran, Korvin

Maniphest Tasks: T1602

Differential Revision: https://secure.phabricator.com/D3148
2012-08-07 09:28:49 -07:00

172 lines
4.7 KiB
PHP
Executable file

#!/usr/bin/env php
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* 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';
$args = new PhutilArgumentParser($argv);
$args->setSynopsis(<<<EOSYNOPSIS
**import_project_symbols.php** [__options__] __project_name__ < symbols
Import project symbols (symbols are read from stdin).
EOSYNOPSIS
);
$args->parseStandardArguments();
$args->parse(
array(
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);
$symbols = array();
foreach ($input as $key => $line) {
$line_no = $key + 1;
$matches = null;
$ok = preg_match(
'/^((?P<context>[^ ]+)? )?(?P<name>[^ ]+) (?P<type>[^ ]+) '.
'(?P<lang>[^ ]+) (?P<line>\d+) (?P<path>.*)$/',
$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'];
if (strlen($context) > 128) {
throw new Exception(
"Symbol context '{$context}' defined on line #{$line_no} is too long, ".
"maximum symbol context length is 128 characters.");
}
if (strlen($name) > 128) {
throw new Exception(
"Symbol name '{$name}' defined on line #{$line_no} is too long, maximum ".
"symbol name length is 128 characters.");
}
if (strlen($type) > 12) {
throw new Exception(
"Symbol type '{$type}' defined on line #{$line_no} is too long, maximum ".
"symbol type length is 12 characters.");
}
if (strlen($lang) > 32) {
throw new Exception(
"Symbol language '{$lang}' defined on line #{$line_no} is too long, ".
"maximum symbol language length is 32 characters.");
}
if (!strlen($path) || $path[0] != 0) {
throw new Exception(
"Path '{$path}' defined on line #{$line_no} is invalid. Paths should be ".
"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,
);
}
echo "Looking up path IDs...\n";
$path_map = PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths(
ipull($symbols, 'path'));
$symbol = new PhabricatorRepositorySymbol();
$conn_w = $symbol->establishConnection('w');
echo "Preparing queries...\n";
$sql = array();
foreach ($symbols 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']]);
}
echo "Purging old symbols...\n";
queryfx(
$conn_w,
'DELETE FROM %T WHERE arcanistProjectID = %d',
$symbol->getTableName(),
$project->getID());
echo "Loading ".number_format(count($sql))." symbols...\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));
}
echo "Done.\n";