mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 00:32:41 +01:00
Port "arc liberate" to Toolsets
Summary: Ref T13395. Depends on D20991. Make "arc liberate" run as a toolset command, not a classic command. Test Plan: Ran "arc liberate"; created this diff. Maniphest Tasks: T13395 Differential Revision: https://secure.phabricator.com/D20992
This commit is contained in:
parent
0e95fcbb7f
commit
cf9469e0d1
4 changed files with 165 additions and 134 deletions
|
@ -1205,7 +1205,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistLesscLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistLesscLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistLiberateWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistLiberateWorkflow' => 'ArcanistArcWorkflow',
|
||||
'ArcanistLintEngine' => 'Phobject',
|
||||
'ArcanistLintMessage' => 'Phobject',
|
||||
'ArcanistLintMessageTestCase' => 'PhutilTestCase',
|
||||
|
|
|
@ -5,7 +5,7 @@ abstract class ArcanistArcWorkflow
|
|||
|
||||
public function supportsToolset(ArcanistToolset $toolset) {
|
||||
$key = $toolset->getToolsetKey();
|
||||
return ($key === 'arc');
|
||||
return ($key === ArcanistArcToolset::TOOLSETKEY);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,141 +1,106 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Create and update libphutil libraries.
|
||||
*
|
||||
* This workflow is unusual and involves re-executing 'arc liberate' as a
|
||||
* subprocess with `--remap` and `--verify`. This is because there is no way
|
||||
* to unload or reload a library, so every process is stuck with the library
|
||||
* definition it had when it first loaded. This is normally fine, but
|
||||
* problematic in this case because `arc liberate` modifies library definitions.
|
||||
*/
|
||||
final class ArcanistLiberateWorkflow extends ArcanistWorkflow {
|
||||
final class ArcanistLiberateWorkflow
|
||||
extends ArcanistArcWorkflow {
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'liberate';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**liberate** [__path__]
|
||||
public function getWorkflowInformation() {
|
||||
// TOOLSETS: Expand this help.
|
||||
|
||||
$help = pht(<<<EOTEXT
|
||||
Create or update an Arcanist library.
|
||||
EOTEXT
|
||||
);
|
||||
);
|
||||
|
||||
return $this->newWorkflowInformation()
|
||||
->addExample(pht('**liberate**'))
|
||||
->addExample(pht('**liberate** [__path__]'))
|
||||
->setHelp($help);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Supports: libphutil
|
||||
Create or update a libphutil library, generating required metadata
|
||||
files like \__init__.php.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getArguments() {
|
||||
public function getWorkflowArguments() {
|
||||
return array(
|
||||
'all' => array(
|
||||
'help' => pht(
|
||||
'Drop the module cache before liberating. This will completely '.
|
||||
'reanalyze the entire library. Thorough, but slow!'),
|
||||
),
|
||||
'force-update' => array(
|
||||
'help' => pht(
|
||||
'Force the library map to be updated, even in the presence of '.
|
||||
'lint errors.'),
|
||||
),
|
||||
'library-name' => array(
|
||||
'param' => 'name',
|
||||
'help' =>
|
||||
pht('Use a flag for library name rather than awaiting user input.'),
|
||||
),
|
||||
'remap' => array(
|
||||
'hide' => true,
|
||||
'help' => pht(
|
||||
'Internal. Run the remap step of liberation. You do not need to '.
|
||||
'run this unless you are debugging the workflow.'),
|
||||
),
|
||||
'verify' => array(
|
||||
'hide' => true,
|
||||
'help' => pht(
|
||||
'Internal. Run the verify step of liberation. You do not need to '.
|
||||
'run this unless you are debugging the workflow.'),
|
||||
),
|
||||
'upgrade' => array(
|
||||
'hide' => true,
|
||||
'help' => pht('Experimental. Upgrade library to v2.'),
|
||||
),
|
||||
'*' => 'argv',
|
||||
$this->newWorkflowArgument('clean')
|
||||
->setHelp(
|
||||
pht('Perform a clean rebuild, ignoring caches. Thorough, but slow.')),
|
||||
$this->newWorkflowArgument('argv')
|
||||
->setWildcard(true),
|
||||
);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
public function runWorkflow() {
|
||||
$log = $this->getLogEngine();
|
||||
|
||||
$argv = $this->getArgument('argv');
|
||||
if (count($argv) > 1) {
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
"Provide only one path to '%s'. The path should be a directory ".
|
||||
"where you want to create or update a libphutil library.",
|
||||
'arc liberate'));
|
||||
} else if (count($argv) == 0) {
|
||||
$path = getcwd();
|
||||
} else {
|
||||
$path = reset($argv);
|
||||
}
|
||||
'Provide only one path to "arc liberate". The path should identify '.
|
||||
'a directory where you want to create or update a library.'));
|
||||
} else if (!$argv) {
|
||||
$log->writeStatus(
|
||||
pht('SCAN'),
|
||||
pht('Searching for libraries in the current working directory...'));
|
||||
|
||||
$is_remap = $this->getArgument('remap');
|
||||
$is_verify = $this->getArgument('verify');
|
||||
|
||||
$path = Filesystem::resolvePath($path);
|
||||
|
||||
if (Filesystem::pathExists($path) && is_dir($path)) {
|
||||
$init = id(new FileFinder($path))
|
||||
$init_files = id(new FileFinder(getcwd()))
|
||||
->withPath('*/__phutil_library_init__.php')
|
||||
->find();
|
||||
} else {
|
||||
$init = null;
|
||||
}
|
||||
|
||||
if ($init) {
|
||||
if (count($init) > 1) {
|
||||
if (!$init_files) {
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
'Specified directory contains more than one libphutil library. '.
|
||||
'Use a more specific path.'));
|
||||
'Unable to find any libraries under the current working '.
|
||||
'directory. To create a library, provide a path.'));
|
||||
}
|
||||
|
||||
$paths = array();
|
||||
foreach ($init_files as $init) {
|
||||
$paths[] = Filesystem::resolvePath(dirname($init));
|
||||
}
|
||||
$path = Filesystem::resolvePath(dirname(reset($init)), $path);
|
||||
} else {
|
||||
$found = false;
|
||||
foreach (Filesystem::walkToRoot($path) as $dir) {
|
||||
if (Filesystem::pathExists($dir.'/__phutil_library_init__.php')) {
|
||||
$path = $dir;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
echo pht("No library currently exists at that path...\n");
|
||||
$this->liberateCreateDirectory($path);
|
||||
$this->liberateCreateLibrary($path);
|
||||
return;
|
||||
}
|
||||
$paths = array(
|
||||
Filesystem::resolvePath(head($argv)),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($paths as $path) {
|
||||
$log->writeStatus(
|
||||
pht('WORK'),
|
||||
pht(
|
||||
'Updating library: %s',
|
||||
Filesystem::readablePath($path).DIRECTORY_SEPARATOR));
|
||||
$this->liberatePath($path);
|
||||
}
|
||||
|
||||
$log->writeSuccess(
|
||||
pht('DONE'),
|
||||
pht('Updated %s librarie(s).', phutil_count($paths)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function liberatePath($path) {
|
||||
if (!Filesystem::pathExists($path.'/__phutil_library_init__.php')) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'No library currently exists at the path "%s"...',
|
||||
$path));
|
||||
$this->liberateCreateDirectory($path);
|
||||
$this->liberateCreateLibrary($path);
|
||||
return;
|
||||
}
|
||||
|
||||
$version = $this->getLibraryFormatVersion($path);
|
||||
switch ($version) {
|
||||
case 1:
|
||||
if ($this->getArgument('upgrade')) {
|
||||
return $this->upgradeLibrary($path);
|
||||
}
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
"This library is using libphutil v1, which is no ".
|
||||
"longer supported. Run '%s' to upgrade to v2.",
|
||||
'arc liberate --upgrade'));
|
||||
'This very old library is no longer supported.'));
|
||||
case 2:
|
||||
if ($this->getArgument('upgrade')) {
|
||||
throw new ArcanistUsageException(
|
||||
pht("Can't upgrade a v2 library!"));
|
||||
}
|
||||
return $this->liberateVersion2($path);
|
||||
default:
|
||||
throw new ArcanistUsageException(
|
||||
|
@ -166,32 +131,17 @@ EOTEXT
|
|||
$bin = $this->getScriptPath('support/lib/rebuild-map.php');
|
||||
|
||||
$argv = array();
|
||||
if ($this->getArgument('all')) {
|
||||
if ($this->getArgument('clean')) {
|
||||
$argv[] = '--drop-cache';
|
||||
}
|
||||
|
||||
return phutil_passthru(
|
||||
'php -f %s -- %Ls %s',
|
||||
'php -f %R -- %Ls %R',
|
||||
$bin,
|
||||
$argv,
|
||||
$path);
|
||||
}
|
||||
|
||||
private function upgradeLibrary($path) {
|
||||
$inits = id(new FileFinder($path))
|
||||
->withPath('*/__init__.php')
|
||||
->withType('f')
|
||||
->find();
|
||||
|
||||
echo pht('Removing %s files...', '__init__.php')."\n";
|
||||
foreach ($inits as $init) {
|
||||
Filesystem::remove($path.'/'.$init);
|
||||
}
|
||||
|
||||
echo pht('Upgrading library to v2...')."\n";
|
||||
$this->liberateVersion2($path);
|
||||
}
|
||||
|
||||
private function liberateCreateDirectory($path) {
|
||||
if (Filesystem::pathExists($path)) {
|
||||
if (!is_dir($path)) {
|
||||
|
@ -204,10 +154,10 @@ EOTEXT
|
|||
|
||||
echo pht("The directory '%s' does not exist.", $path);
|
||||
if (!phutil_console_confirm(pht('Do you want to create it?'))) {
|
||||
throw new ArcanistUsageException(pht('Canceled.'));
|
||||
throw new ArcanistUsageException(pht('Cancelled.'));
|
||||
}
|
||||
|
||||
execx('mkdir -p %s', $path);
|
||||
execx('mkdir -p %R', $path);
|
||||
}
|
||||
|
||||
private function liberateCreateLibrary($path) {
|
||||
|
@ -219,14 +169,10 @@ EOTEXT
|
|||
echo pht("Creating new libphutil library in '%s'.", $path)."\n";
|
||||
|
||||
do {
|
||||
$name = $this->getArgument('library-name');
|
||||
if ($name === null) {
|
||||
echo pht('Choose a name for the new library.')."\n";
|
||||
$name = phutil_console_prompt(
|
||||
pht('What do you want to name this library?'));
|
||||
} else {
|
||||
echo pht('Using library name %s.', $name)."\n";
|
||||
}
|
||||
echo pht('Choose a name for the new library.')."\n";
|
||||
$name = phutil_console_prompt(
|
||||
pht('What do you want to name this library?'));
|
||||
|
||||
if (preg_match('/^[a-z-]+$/', $name)) {
|
||||
break;
|
||||
} else {
|
||||
|
|
|
@ -115,6 +115,86 @@ abstract class ArcanistWorkflow extends Phobject {
|
|||
return $this->configurationSourceList;
|
||||
}
|
||||
|
||||
public function newPhutilWorkflow() {
|
||||
$arguments = $this->getWorkflowArguments();
|
||||
assert_instances_of($arguments, 'ArcanistWorkflowArgument');
|
||||
|
||||
$specs = mpull($arguments, 'getPhutilSpecification');
|
||||
|
||||
$phutil_workflow = id(new ArcanistPhutilWorkflow())
|
||||
->setName($this->getWorkflowName())
|
||||
->setWorkflow($this)
|
||||
->setArguments($specs);
|
||||
|
||||
$information = $this->getWorkflowInformation();
|
||||
if ($information) {
|
||||
|
||||
$examples = $information->getExamples();
|
||||
if ($examples) {
|
||||
$examples = implode("\n", $examples);
|
||||
$phutil_workflow->setExamples($examples);
|
||||
}
|
||||
|
||||
$help = $information->getHelp();
|
||||
if (strlen($help)) {
|
||||
// Unwrap linebreaks in the help text so we don't get weird formatting.
|
||||
$help = preg_replace("/(?<=\S)\n(?=\S)/", ' ', $help);
|
||||
|
||||
$phutil_workflow->setHelp($help);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $phutil_workflow;
|
||||
}
|
||||
|
||||
final protected function newWorkflowArgument($key) {
|
||||
return id(new ArcanistWorkflowArgument())
|
||||
->setKey($key);
|
||||
}
|
||||
|
||||
final protected function newWorkflowInformation() {
|
||||
return new ArcanistWorkflowInformation();
|
||||
}
|
||||
|
||||
final public function executeWorkflow(PhutilArgumentParser $args) {
|
||||
$runtime = $this->getRuntime();
|
||||
|
||||
$this->arguments = $args;
|
||||
$caught = null;
|
||||
|
||||
$runtime->pushWorkflow($this);
|
||||
|
||||
try {
|
||||
$err = $this->runWorkflow($args);
|
||||
} catch (Exception $ex) {
|
||||
$caught = $ex;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->runWorkflowCleanup();
|
||||
} catch (Exception $ex) {
|
||||
phlog($ex);
|
||||
}
|
||||
|
||||
$runtime->popWorkflow();
|
||||
|
||||
if ($caught) {
|
||||
throw $caught;
|
||||
}
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
final protected function getLogEngine() {
|
||||
return $this->getRuntime()->getLogEngine();
|
||||
}
|
||||
|
||||
protected function runWorkflowCleanup() {
|
||||
// TOOLSETS: Do we need this?
|
||||
return;
|
||||
}
|
||||
|
||||
public function __construct() {}
|
||||
|
||||
public function run() {
|
||||
|
@ -662,7 +742,12 @@ abstract class ArcanistWorkflow extends Phobject {
|
|||
}
|
||||
|
||||
final public function getArgument($key, $default = null) {
|
||||
return idx($this->arguments, $key, $default);
|
||||
// TOOLSETS: Remove this legacy code.
|
||||
if (is_array($this->arguments)) {
|
||||
return idx($this->arguments, $key, $default);
|
||||
}
|
||||
|
||||
return $this->arguments->getArg($key);
|
||||
}
|
||||
|
||||
final public function getPassedArguments() {
|
||||
|
|
Loading…
Reference in a new issue