'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-01-31 21:07:05 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create and update libphutil libraries.
|
|
|
|
*
|
|
|
|
* This workflow is unusual and involves reexecuting '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.
|
|
|
|
*
|
|
|
|
* @group workflow
|
|
|
|
*/
|
2012-01-31 21:07:05 +01:00
|
|
|
final class ArcanistLiberateWorkflow extends ArcanistBaseWorkflow {
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
|
2012-03-05 19:02:37 +01:00
|
|
|
public function getCommandSynopses() {
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
return phutil_console_format(<<<EOTEXT
|
|
|
|
**liberate** [__path__]
|
2012-03-05 19:02:37 +01:00
|
|
|
EOTEXT
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCommandHelp() {
|
|
|
|
return phutil_console_format(<<<EOTEXT
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
Supports: libphutil
|
|
|
|
Create or update a libphutil library, generating required metadata
|
2011-08-02 19:12:36 +02:00
|
|
|
files like \__init__.php.
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
EOTEXT
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getArguments() {
|
|
|
|
return array(
|
|
|
|
'all' => array(
|
|
|
|
'help' =>
|
|
|
|
"Drop the module cache before liberating. This will completely ".
|
|
|
|
"reanalyze the entire library. Thorough, but slow!",
|
|
|
|
),
|
|
|
|
'force-update' => array(
|
|
|
|
'help' =>
|
|
|
|
"Force the library map to be updated, even in the presence of ".
|
|
|
|
"lint errors.",
|
|
|
|
),
|
|
|
|
'remap' => array(
|
|
|
|
'hide' => true,
|
|
|
|
'help' =>
|
|
|
|
"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' =>
|
|
|
|
"Internal. Run the verify step of liberation. You do not need to ".
|
|
|
|
"run this unless you are debugging the workflow.",
|
|
|
|
),
|
2012-05-30 23:18:11 +02:00
|
|
|
'upgrade' => array(
|
|
|
|
'hide' => true,
|
|
|
|
'help' => "Experimental. Upgrade library to v2.",
|
|
|
|
),
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
'*' => 'argv',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run() {
|
|
|
|
$argv = $this->getArgument('argv');
|
|
|
|
if (count($argv) > 1) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Provide only one path to 'arc liberate'. The path should be a ".
|
|
|
|
"directory where you want to create or update a libphutil library.");
|
|
|
|
} else if (count($argv) == 0) {
|
|
|
|
$path = getcwd();
|
|
|
|
} else {
|
|
|
|
$path = reset($argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
$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))
|
|
|
|
->withPath('*/__phutil_library_init__.php')
|
|
|
|
->find();
|
|
|
|
} else {
|
|
|
|
$init = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($init) {
|
|
|
|
if (count($init) > 1) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Specified directory contains more than one libphutil library. Use ".
|
|
|
|
"a more specific path.");
|
|
|
|
}
|
|
|
|
$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;
|
2012-06-21 20:52:16 +02:00
|
|
|
$found = true;
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!$found) {
|
|
|
|
echo "No library currently exists at that path...\n";
|
|
|
|
$this->liberateCreateDirectory($path);
|
|
|
|
$this->liberateCreateLibrary($path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-30 23:18:11 +02:00
|
|
|
$version = $this->getLibraryFormatVersion($path);
|
|
|
|
switch ($version) {
|
|
|
|
case 1:
|
|
|
|
if ($this->getArgument('upgrade')) {
|
|
|
|
return $this->upgradeLibrary($path);
|
|
|
|
}
|
2012-06-26 21:40:42 +02:00
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"This library is using libphutil v1, which is no longer supported. ".
|
|
|
|
"Run 'arc liberate --upgrade' to upgrade to v2.");
|
2012-05-30 23:18:11 +02:00
|
|
|
case 2:
|
|
|
|
if ($this->getArgument('upgrade')) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Can't upgrade a v2 library!");
|
|
|
|
}
|
|
|
|
return $this->liberateVersion2($path);
|
|
|
|
default:
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Unknown library version '{$version}'!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getLibraryFormatVersion($path) {
|
|
|
|
$map_file = $path.'/__phutil_library_map__.php';
|
|
|
|
if (!Filesystem::pathExists($map_file)) {
|
|
|
|
// Default to library v1.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
$map = Filesystem::readFile($map_file);
|
|
|
|
|
|
|
|
$matches = null;
|
|
|
|
if (preg_match('/@phutil-library-version (\d+)/', $map, $matches)) {
|
|
|
|
return (int)$matches[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function liberateVersion2($path) {
|
|
|
|
$bin = $this->getScriptPath('scripts/phutil_rebuild_map.php');
|
|
|
|
|
|
|
|
return phutil_passthru(
|
|
|
|
'%s %C %s',
|
|
|
|
$bin,
|
|
|
|
$this->getArgument('all') ? '--drop-cache' : '',
|
|
|
|
$path);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function upgradeLibrary($path) {
|
|
|
|
$inits = id(new FileFinder($path))
|
|
|
|
->withPath('*/__init__.php')
|
|
|
|
->withType('f')
|
|
|
|
->find();
|
|
|
|
|
|
|
|
echo "Removing __init__.php files...\n";
|
|
|
|
foreach ($inits as $init) {
|
|
|
|
Filesystem::remove($path.'/'.$init);
|
|
|
|
}
|
|
|
|
|
|
|
|
echo "Upgrading library to v2...\n";
|
|
|
|
$this->liberateVersion2($path);
|
|
|
|
}
|
|
|
|
|
'arc liberate', convenience wrapper for various libphutil operations
Summary:
The story for creating and maintaining libphutil libraries and modules
is pretty terrible right now: you need to know a bunch of secret scripts and
dark magic. Provide 'arc liberate' which endeavors to always do the right thing
and put a library in the correct state.
Test Plan:
Ran liberate on libphutil, arcanist, phabricator; created new
libphutil libraries, added classes to them, liberated everything, introduced
errors etc and liberated that stuff, nothing was obviously broken in a terrible
way..?
Reviewed By: aran
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, epriestley
Differential Revision: 269
2011-05-12 01:30:22 +02:00
|
|
|
private function liberateCreateDirectory($path) {
|
|
|
|
if (Filesystem::pathExists($path)) {
|
|
|
|
if (!is_dir($path)) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Provide a directory to create or update a libphutil library in.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
echo "The directory '{$path}' does not exist.";
|
|
|
|
if (!phutil_console_confirm('Do you want to create it?')) {
|
|
|
|
throw new ArcanistUsageException("Cancelled.");
|
|
|
|
}
|
|
|
|
|
|
|
|
execx('mkdir -p %s', $path);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function liberateCreateLibrary($path) {
|
|
|
|
$init_path = $path.'/__phutil_library_init__.php';
|
|
|
|
if (Filesystem::pathExists($init_path)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
echo "Creating new libphutil library in '{$path}'.\n";
|
|
|
|
echo "Choose a name for the new library.\n";
|
|
|
|
do {
|
|
|
|
$name = phutil_console_prompt('What do you want to name this library?');
|
|
|
|
if (preg_match('/^[a-z]+$/', $name)) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
echo "Library name should contain only lowercase letters.\n";
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
$template =
|
|
|
|
"<?php\n\n".
|
|
|
|
"phutil_register_library('{$name}', __FILE__);\n";
|
|
|
|
|
|
|
|
echo "Writing '__phutil_library_init__.php' to '{$init_path}'...\n";
|
|
|
|
Filesystem::writeFile($init_path, $template);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function getScriptPath($script) {
|
|
|
|
$root = dirname(phutil_get_library_root('arcanist'));
|
|
|
|
return $root.'/'.$script;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|