newWorkflowInformation() ->setSynopsis( pht('Create or update an Arcanist library.')) ->addExample(pht('**liberate**')) ->addExample(pht('**liberate** [__path__]')) ->setHelp($help); } public function getWorkflowArguments() { return array( $this->newWorkflowArgument('clean') ->setHelp( pht('Perform a clean rebuild, ignoring caches. Thorough, but slow.')), $this->newWorkflowArgument('argv') ->setWildcard(true) ->setIsPathArgument(true), ); } protected function newPrompts() { return array( $this->newPrompt('arc.liberate.create') ->setDescription( pht( 'Confirms creation of a new library.')), ); } public function runWorkflow() { $log = $this->getLogEngine(); $argv = $this->getArgument('argv'); if (count($argv) > 1) { throw new ArcanistUsageException( pht( '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...')); $init_files = id(new FileFinder(getcwd())) ->withPath('*/__phutil_library_init__.php') ->find(); if (!$init_files) { throw new ArcanistUsageException( pht( '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)); } } else { $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: throw new ArcanistUsageException( pht( 'This very old library is no longer supported.')); case 2: return $this->liberateVersion2($path); default: throw new ArcanistUsageException( pht("Unknown library version '%s'!", $version)); } echo tsprintf("%s\n", pht('Done.')); } 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('support/lib/rebuild-map.php'); $argv = array(); if ($this->getArgument('clean')) { $argv[] = '--drop-cache'; } return phutil_passthru( 'php -f %R -- %Ls %R', $bin, $argv, $path); } private function liberateCreateDirectory($path) { if (Filesystem::pathExists($path)) { if (!is_dir($path)) { throw new ArcanistUsageException( pht( 'Provide a directory to create or update a libphutil library in.')); } return; } echo tsprintf( "%!\n%W\n", pht('NEW LIBRARY'), pht( 'The directory "%s" does not exist. Do you want to create it?', $path)); $query = pht('Create new library?'); $this->getPrompt('arc.liberate.create') ->setQuery($query) ->execute(); execx('mkdir -p %R', $path); } private function liberateCreateLibrary($path) { $init_path = $path.'/__phutil_library_init__.php'; if (Filesystem::pathExists($init_path)) { return; } echo pht("Creating new libphutil library in '%s'.", $path)."\n"; do { 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 { echo phutil_console_format( "%s\n", pht( 'Library name should contain only lowercase letters and hyphens.')); } } while (true); $template = "liberateVersion2($path); } private function getScriptPath($script) { $root = dirname(phutil_get_library_root('arcanist')); return $root.'/'.$script; } }