public static function newAPIFromWorkingCopyIdentity(ArcanistWorkingCopyIdentity $working_copy) { $root = $working_copy->getProjectRoot(); if (!$root) { throw new ArcanistUsageException("There is no readable '.arcconfig' file in the working directory or " . "any parent directory. Create an '.arcconfig' file to configure arc."); } // check if we're in an svn working copy list($err) = exec_manual('svn info'); if (!$err) { $api = newv('ArcanistSubversionAPI', array($root)); $api->workingCopyIdentity = $working_copy; return $api; } if (Filesystem::pathExists($root . '/.hg')) { $api = newv('ArcanistMercurialAPI', array($root)); $api->workingCopyIdentity = $working_copy; return $api; } $git_root = self::discoverGitBaseDirectory($root); if ($git_root) { if (!Filesystem::pathsAreEquivalent($root, $git_root)) { throw new ArcanistUsageException("'.arcconfig' file is located at '{$root}', but working copy root " . "is '{$git_root}'. Move '.arcconfig' file to the working copy root."); } $api = newv('ArcanistGitAPI', array($root)); $api->workingCopyIdentity = $working_copy; return $api; } throw new ArcanistUsageException("The current working directory is not part of a working copy for a " . "supported version control system (svn, git or mercurial)."); }
/** * NOTE: SPOOKY BLACK MAGIC * * When arc is run in a copy of arcanist other than itself, or a copy of * libphutil other than the one we loaded, reenter the script and force it * to use the current working directory instead of the default. * * In the case of execution inside arcanist/, we force execution of the local * arc binary. * * In the case of execution inside libphutil/, we force the local copy to load * instead of the one selected by default rules. * * @param PhutilConsole Console. * @param ArcanistWorkingCopyIdentity The current working copy. * @param array Original arc arguments. * @return void */ function reenter_if_this_is_arcanist_or_libphutil(PhutilConsole $console, ArcanistWorkingCopyIdentity $working_copy, array $original_argv) { $project_id = $working_copy->getProjectID(); if ($project_id != 'arcanist' && $project_id != 'libphutil') { // We're not in a copy of arcanist or libphutil. return; } $library_names = array('arcanist' => 'arcanist', 'libphutil' => 'phutil'); $library_root = phutil_get_library_root($library_names[$project_id]); $project_root = $working_copy->getProjectRoot(); if (Filesystem::isDescendant($library_root, $project_root)) { // We're in a copy of arcanist or libphutil, but already loaded the correct // copy. Continue execution normally. return; } if ($project_id == 'libphutil') { $console->writeLog("This is libphutil! Forcing this copy to load...\n"); $original_argv[0] = dirname(phutil_get_library_root('arcanist')) . '/bin/arc'; $libphutil_path = $project_root; } else { $console->writeLog("This is arcanist! Forcing this copy to run...\n"); $original_argv[0] = $project_root . '/bin/arc'; $libphutil_path = dirname(phutil_get_library_root('phutil')); } if (phutil_is_windows()) { $err = phutil_passthru('set ARC_PHUTIL_PATH=%s & %Ls', $libphutil_path, $original_argv); } else { $err = phutil_passthru('ARC_PHUTIL_PATH=%s %Ls', $libphutil_path, $original_argv); } exit($err); }
function arcanist_load_libraries($load, $must_load, $lib_source, ArcanistWorkingCopyIdentity $working_copy, $config_trace_mode) { if (!$load) { return; } if (!is_array($load)) { $error = "Libraries specified by {$lib_source} are invalid; expected " . "a list. Check your configuration."; $console = PhutilConsole::getConsole(); $console->writeErr("WARNING: %s\n", $error); return; } foreach ($load as $location) { // Try to resolve the library location. We look in several places, in // order: // // 1. Inside the working copy. This is for phutil libraries within the // project. For instance "library/src" will resolve to // "./library/src" if it exists. // 2. In the same directory as the working copy. This allows you to // check out a library alongside a working copy and reference it. // If we haven't resolved yet, "library/src" will try to resolve to // "../library/src" if it exists. // 3. Using normal libphutil resolution rules. Generally, this means // that it checks for libraries next to libphutil, then libraries // in the PHP include_path. // // Note that absolute paths will just resolve absolutely through rule (1). $resolved = false; // Check inside the working copy. This also checks absolute paths, since // they'll resolve absolute and just ignore the project root. $resolved_location = Filesystem::resolvePath($location, $working_copy->getProjectRoot()); if (Filesystem::pathExists($resolved_location)) { $location = $resolved_location; $resolved = true; } // If we didn't find anything, check alongside the working copy. if (!$resolved) { $resolved_location = Filesystem::resolvePath($location, dirname($working_copy->getProjectRoot())); if (Filesystem::pathExists($resolved_location)) { $location = $resolved_location; $resolved = true; } } if ($config_trace_mode) { echo "Loading phutil library from '{$location}'...\n"; } $error = null; try { phutil_load_library($location); } catch (PhutilBootloaderException $ex) { $error = "Failed to load phutil library at location '{$location}'. " . "This library is specified by {$lib_source}. Check that the " . "setting is correct and the library is located in the right " . "place."; if ($must_load) { throw new ArcanistUsageException($error); } else { file_put_contents('php://stderr', phutil_console_wrap('WARNING: ' . $error . "\n\n")); } } catch (PhutilLibraryConflictException $ex) { if ($ex->getLibrary() != 'arcanist') { throw $ex; } $arc_dir = dirname(dirname(__FILE__)); $error = "You are trying to run one copy of Arcanist on another copy of " . "Arcanist. This operation is not supported. To execute Arcanist " . "operations against this working copy, run './bin/arc' (from the " . "current working copy) not some other copy of 'arc' (you ran one " . "from '{$arc_dir}')."; throw new ArcanistUsageException($error); } } }