protected function doLock($wait) { $conn = $this->conn; if (!$conn) { // Try to reuse a connection from the connection pool. $conn = array_pop(self::$pool); } if (!$conn) { // NOTE: Using the 'repository' database somewhat arbitrarily, mostly // because the first client of locks is the repository daemons. We must // always use the same database for all locks, but don't access any // tables so we could use any valid database. We could build a // database-free connection instead, but that's kind of messy and we // might forget about it in the future if we vertically partition the // application. $dao = new PhabricatorRepository(); // NOTE: Using "force_new" to make sure each lock is on its own // connection. $conn = $dao->establishConnection('w', $force_new = true); // NOTE: Since MySQL will disconnect us if we're idle for too long, we set // the wait_timeout to an enormous value, to allow us to hold the // connection open indefinitely (or, at least, for 24 days). $max_allowed_timeout = 2147483; queryfx($conn, 'SET wait_timeout = %d', $max_allowed_timeout); } $result = queryfx_one($conn, 'SELECT GET_LOCK(%s, %f)', 'phabricator:' . $this->lockname, $wait); $ok = head($result); if (!$ok) { throw new PhutilLockException($this->getName()); } $this->conn = $conn; }
private function getRawDiff(PhabricatorRepository $repository, $commit, $use_log, $try_harder) { $flags = array('-n1', '-M', '-C', '-B', '--raw', '-t', '--abbrev=40'); if ($try_harder) { $flags[] = '--find-copies-harder'; } if ($use_log) { // This is the first commit so we need to use "log". We know it's not a // merge commit because it couldn't be merging anything, so this is safe. // NOTE: "--pretty=format: " is to disable diff output, we only want the // part we get from "--raw". $future = $repository->getLocalCommandFuture('log %Ls --pretty=format: %s', $flags, $commit); } else { // Otherwise, we can use "diff", which will give us output for merges. // We diff against the first parent, as this is generally the expectation // and results in sensible behavior. $future = $repository->getLocalCommandFuture('diff %Ls %s^1 %s', $flags, $commit, $commit); } // Don't spend more than 30 seconds generating the slower output. if ($try_harder) { $future->setTimeout(30); } list($raw) = $future->resolvex(); return $raw; }
protected function executeUpdate(PhabricatorRepository $repository, $local_path) { // This is a local command, but needs credentials. $future = $repository->getRemoteCommandFuture('pull -u'); $future->setCWD($local_path); try { $future->resolvex(); } catch (CommandException $ex) { $err = $ex->getError(); $stdout = $ex->getStdOut(); // NOTE: Between versions 2.1 and 2.1.1, Mercurial changed the behavior // of "hg pull" to return 1 in case of a successful pull with no changes. // This behavior has been reverted, but users who updated between Feb 1, // 2012 and Mar 1, 2012 will have the erroring version. Do a dumb test // against stdout to check for this possibility. // See: https://github.com/facebook/phabricator/issues/101/ // NOTE: Mercurial has translated versions, which translate this error // string. In a translated version, the string will be something else, // like "aucun changement trouve". There didn't seem to be an easy way // to handle this (there are hard ways but this is not a common problem // and only creates log spam, not application failures). Assume English. // TODO: Remove this once we're far enough in the future that deployment // of 2.1 is exceedingly rare? if ($err == 1 && preg_match('/no changes found/', $stdout)) { return; } else { throw $ex; } } }
protected function executeUpdate(PhabricatorRepository $repository, $local_path) { // Run a bunch of sanity checks to detect people checking out repositories // inside other repositories, making empty directories, pointing the local // path at some random file or path, etc. list($err, $stdout) = $repository->execLocalCommand('rev-parse --show-toplevel'); if ($err) { // Try to raise a more tailored error message in the more common case // of the user creating an empty directory. (We could try to remove it, // but might not be able to, and it's much simpler to raise a good // message than try to navigate those waters.) if (is_dir($local_path)) { $files = Filesystem::listDirectory($local_path, $include_hidden = true); if (!$files) { throw new Exception("Expected to find a git repository at '{$local_path}', but there " . "is an empty directory there. Remove the directory: the daemon " . "will run 'git clone' for you."); } } throw new Exception("Expected to find a git repository at '{$local_path}', but there is " . "a non-repository directory (with other stuff in it) there. Move or " . "remove this directory (or reconfigure the repository to use a " . "different directory), and then either clone a repository yourself " . "or let the daemon do it."); } else { $repo_path = rtrim($stdout, "\n"); if (empty($repo_path)) { throw new Exception("Expected to find a git repository at '{$local_path}', but " . "there was no result from `git rev-parse --show-toplevel`. " . "Something is misconfigured or broken. The git repository " . "may be inside a '.git/' directory."); } if (!Filesystem::pathsAreEquivalent($repo_path, $local_path)) { throw new Exception("Expected to find repo at '{$local_path}', but the actual " . "git repository root for this directory is '{$repo_path}'. " . "Something is misconfigured. The repository's 'Local Path' should " . "be set to some place where the daemon can check out a working " . "copy, and should not be inside another git repository."); } } // This is a local command, but needs credentials. $future = $repository->getRemoteCommandFuture('fetch --all --prune'); $future->setCWD($local_path); $future->resolvex(); }
private static function loadPackagesForPaths(PhabricatorRepository $repository, array $paths, $limit = 0) { $package = new PhabricatorOwnersPackage(); $path = new PhabricatorOwnersPath(); $conn = $package->establishConnection('r'); $repository_clause = qsprintf($conn, 'AND p.repositoryPHID = %s', $repository->getPHID()); $limit_clause = ''; if (!empty($limit)) { $limit_clause = qsprintf($conn, 'LIMIT %d', $limit); } $data = queryfx_all($conn, 'SELECT pkg.id FROM %T pkg JOIN %T p ON p.packageID = pkg.id WHERE p.path IN (%Ls) %Q ORDER BY LENGTH(p.path) DESC %Q', $package->getTableName(), $path->getTableName(), $paths, $repository_clause, $limit_clause); $ids = ipull($data, 'id'); if (empty($ids)) { return array(); } $order = array(); foreach ($ids as $id) { if (empty($order[$id])) { $order[$id] = true; } } $packages = $package->loadAllWhere('id in (%Ld)', array_keys($order)); $packages = array_select_keys($packages, array_keys($order)); return $packages; }
protected function getCommitHashes(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { list($stdout) = $repository->execxLocalCommand('log -n 1 --format=%s %s --', '%T', $commit->getCommitIdentifier()); $commit_hash = $commit->getCommitIdentifier(); $tree_hash = trim($stdout); return array(array(ArcanistDifferentialRevisionHash::HASH_GIT_COMMIT, $commit_hash), array(ArcanistDifferentialRevisionHash::HASH_GIT_TREE, $tree_hash)); }
private function updateBranchStates(PhabricatorRepository $repository, array $branches) { assert_instances_of($branches, 'DiffusionRepositoryRef'); $all_cursors = id(new PhabricatorRepositoryRefCursorQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withRepositoryPHIDs(array($repository->getPHID()))->execute(); $state_map = array(); $type_branch = PhabricatorRepositoryRefCursor::TYPE_BRANCH; foreach ($all_cursors as $cursor) { if ($cursor->getRefType() !== $type_branch) { continue; } $raw_name = $cursor->getRefNameRaw(); $hash = $cursor->getCommitIdentifier(); $state_map[$raw_name][$hash] = $cursor; } foreach ($branches as $branch) { $cursor = idx($state_map, $branch->getShortName(), array()); $cursor = idx($cursor, $branch->getCommitIdentifier()); if (!$cursor) { continue; } $fields = $branch->getRawFields(); $cursor_state = (bool) $cursor->getIsClosed(); $branch_state = (bool) idx($fields, 'closed'); if ($cursor_state != $branch_state) { $cursor->setIsClosed((int) $branch_state)->save(); } } }
private function checkIfRepositoryIsFullyImported(PhabricatorRepository $repository) { // Check if the repository has the "Importing" flag set. We want to clear // the flag if we can. $importing = $repository->getDetail('importing'); if (!$importing) { // This repository isn't marked as "Importing", so we're done. return; } // Look for any commit which hasn't imported. $unparsed_commit = queryfx_one($repository->establishConnection('r'), 'SELECT * FROM %T WHERE repositoryID = %d AND (importStatus & %d) != %d LIMIT 1', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID(), PhabricatorRepositoryCommit::IMPORTED_ALL, PhabricatorRepositoryCommit::IMPORTED_ALL); if ($unparsed_commit) { // We found a commit which still needs to import, so we can't clear the // flag. return; } // Clear the "importing" flag. $repository->openTransaction(); $repository->beginReadLocking(); $repository = $repository->reload(); $repository->setDetail('importing', false); $repository->save(); $repository->endReadLocking(); $repository->saveTransaction(); }
private function markReachable(PhabricatorRepository $repository) { if (!$repository->isGit()) { throw new PhutilArgumentUsageException(pht('Only Git repositories are supported, this repository ("%s") is ' . 'not a Git repository.', $repository->getDisplayName())); } $viewer = $this->getViewer(); $commits = id(new DiffusionCommitQuery())->setViewer($viewer)->withRepository($repository)->execute(); $flag = PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE; $graph = new PhabricatorGitGraphStream($repository); foreach ($commits as $commit) { $identifier = $commit->getCommitIdentifier(); try { $graph->getCommitDate($identifier); $unreachable = false; } catch (Exception $ex) { $unreachable = true; } // The commit has proper reachability, so do nothing. if ($commit->isUnreachable() === $unreachable) { $this->untouchedCount++; continue; } if ($unreachable) { echo tsprintf("%s: %s\n", $commit->getMonogram(), pht('Marking commit unreachable.')); $commit->writeImportStatusFlag($flag); } else { echo tsprintf("%s: %s\n", $commit->getMonogram(), pht('Marking commit reachable.')); $commit->clearImportStatusFlag($flag); } } }
protected function executeUpdate(PhabricatorRepository $repository, $local_path) { // This is a local command, but needs credentials. $future = $repository->getRemoteCommandFuture('fetch --all'); $future->setCWD($local_path); $future->resolvex(); }
protected function executeChecks() { if (phutil_is_windows()) { $bin_name = 'where'; } else { $bin_name = 'which'; } if (!Filesystem::binaryExists($bin_name)) { $message = pht("Without '%s', Phabricator can not test for the availability " . "of other binaries.", $bin_name); $this->raiseWarning($bin_name, $message); // We need to return here if we can't find the 'which' / 'where' binary // because the other tests won't be valid. return; } if (!Filesystem::binaryExists('diff')) { $message = pht("Without 'diff', Phabricator will not be able to generate or render " . "diffs in multiple applications."); $this->raiseWarning('diff', $message); } else { $tmp_a = new TempFile(); $tmp_b = new TempFile(); $tmp_c = new TempFile(); Filesystem::writeFile($tmp_a, 'A'); Filesystem::writeFile($tmp_b, 'A'); Filesystem::writeFile($tmp_c, 'B'); list($err) = exec_manual('diff %s %s', $tmp_a, $tmp_b); if ($err) { $this->newIssue('bin.diff.same')->setName(pht("Unexpected 'diff' Behavior"))->setMessage(pht("The 'diff' binary on this system has unexpected behavior: " . "it was expected to exit without an error code when passed " . "identical files, but exited with code %d.", $err)); } list($err) = exec_manual('diff %s %s', $tmp_a, $tmp_c); if (!$err) { $this->newIssue('bin.diff.diff')->setName(pht("Unexpected 'diff' Behavior"))->setMessage(pht("The 'diff' binary on this system has unexpected behavior: " . "it was expected to exit with a nonzero error code when passed " . "differing files, but did not.")); } } $table = new PhabricatorRepository(); $vcses = queryfx_all($table->establishConnection('r'), 'SELECT DISTINCT versionControlSystem FROM %T', $table->getTableName()); foreach ($vcses as $vcs) { switch ($vcs['versionControlSystem']) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binary = 'git'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binary = 'svn'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binary = 'hg'; break; default: $binary = null; break; } if (!$binary) { continue; } if (!Filesystem::binaryExists($binary)) { $message = pht('You have at least one repository configured which uses this ' . 'version control system. It will not work without the VCS binary.'); $this->raiseWarning($binary, $message); } } }
public function __construct(PhabricatorRepository $repository, $commit) { $this->repository = $repository; $future = $repository->getLocalCommandFuture('log --template %s --rev %s', '{rev}\\1{node}\\1{date}\\1{parents}\\2', hgsprintf('reverse(ancestors(%s))', $commit)); $this->iterator = new LinesOfALargeExecFuture($future); $this->iterator->setDelimiter(""); $this->iterator->rewind(); }
public static final function linkCommit(PhabricatorRepository $repository, $commit, $summary = '') { $commit_name = $repository->formatCommitName($commit, $local = true); if (strlen($summary)) { $commit_name .= ': ' . $summary; } return phutil_tag('a', array('href' => $repository->getCommitURI($commit)), $commit_name); }
public function __construct(PhabricatorRepository $repository) { $this->repository = $repository; $future = $repository->getLocalCommandFuture("log --template '{rev}{node}{date}{parents}'"); $this->iterator = new LinesOfALargeExecFuture($future); $this->iterator->setDelimiter(""); $this->iterator->rewind(); }
private function getDefaultRefName(PhabricatorRepository $repository, DifferentialDiff $diff) { $onto = $diff->loadTargetBranch(); if ($onto !== null) { return $onto; } return $repository->getDefaultBranch(); }
public function __construct(PhabricatorRepository $repository, $start_commit) { $this->repository = $repository; $future = $repository->getLocalCommandFuture('log --format=%s %s --', '%H%x01%P%x01%ct', $start_commit); $this->iterator = new LinesOfALargeExecFuture($future); $this->iterator->setDelimiter("\n"); $this->iterator->rewind(); }
protected final function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { $viewer = PhabricatorUser::getOmnipotentUser(); $refs_raw = DiffusionQuery::callConduitWithDiffusionRequest($viewer, DiffusionRequest::newFromDictionary(array('repository' => $repository, 'user' => $viewer)), 'diffusion.querycommits', array('repositoryPHID' => $repository->getPHID(), 'phids' => array($commit->getPHID()), 'bypassCache' => true, 'needMessages' => true)); if (empty($refs_raw['data'])) { throw new Exception(pht('Unable to retrieve details for commit "%s"!', $commit->getPHID())); } $ref = DiffusionCommitRef::newFromConduitResult(head($refs_raw['data'])); $this->parseCommitWithRef($repository, $commit, $ref); }
private function findGitHubRepo(PhabricatorRepository $repository) { $repo_uri = $repository->getRemoteURIObject(); $repo_path = $repo_uri->getPath(); if (substr($repo_path, -4) == '.git') { $repo_path = substr($repo_path, 0, -4); } $repo_path = ltrim($repo_path, '/'); return $repo_path; }
public static function newHTTPAuthorization(PhabricatorRepository $repository, PhabricatorUser $viewer, $operation) { $lfs_user = self::HTTP_USERNAME; $lfs_pass = Filesystem::readRandomCharacters(32); $lfs_hash = PhabricatorHash::digest($lfs_pass); $ttl = PhabricatorTime::getNow() + phutil_units('1 day in seconds'); $token = id(new PhabricatorAuthTemporaryToken())->setTokenResource($repository->getPHID())->setTokenType(self::TOKENTYPE)->setTokenCode($lfs_hash)->setUserPHID($viewer->getPHID())->setTemporaryTokenProperty('lfs.operation', $operation)->setTokenExpires($ttl)->save(); $authorization_header = base64_encode($lfs_user . ':' . $lfs_pass); return 'Basic ' . $authorization_header; }
public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL) { return; } if (!$repository->isHosted()) { return; } return $this->createActionView($revision, pht('Land to Hosted Repository')); }
protected static final function initQueryObject($base_class, PhabricatorRepository $repository) { $map = array(PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'Git', PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'Mercurial', PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => 'Svn'); $name = idx($map, $repository->getVersionControlSystem()); if (!$name) { throw new Exception(pht('Unsupported VCS!')); } $class = str_replace('Diffusion', 'Diffusion' . $name, $base_class); $obj = new $class(); return $obj; }
private function triggerOwnerAudits(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { if (!$repository->shouldPublish()) { return; } $affected_paths = PhabricatorOwnerPathQuery::loadAffectedPaths($repository, $commit, PhabricatorUser::getOmnipotentUser()); $affected_packages = PhabricatorOwnersPackage::loadAffectedPackages($repository, $affected_paths); if (!$affected_packages) { return; } $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID()); $commit->attachCommitData($data); $author_phid = $data->getCommitDetail('authorPHID'); $revision_id = $data->getCommitDetail('differential.revisionID'); if ($revision_id) { $revision = id(new DifferentialRevisionQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIDs(array($revision_id))->needReviewerStatus(true)->executeOne(); } else { $revision = null; } $requests = id(new PhabricatorRepositoryAuditRequest())->loadAllWhere('commitPHID = %s', $commit->getPHID()); $requests = mpull($requests, null, 'getAuditorPHID'); foreach ($affected_packages as $package) { $request = idx($requests, $package->getPHID()); if ($request) { // Don't update request if it exists already. continue; } if ($package->isArchived()) { // Don't trigger audits if the package is archived. continue; } if ($package->getAuditingEnabled()) { $reasons = $this->checkAuditReasons($commit, $package, $author_phid, $revision); if ($reasons) { $audit_status = PhabricatorAuditStatusConstants::AUDIT_REQUIRED; } else { $audit_status = PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED; } } else { $reasons = array(); $audit_status = PhabricatorAuditStatusConstants::NONE; } $relationship = new PhabricatorRepositoryAuditRequest(); $relationship->setAuditorPHID($package->getPHID()); $relationship->setCommitPHID($commit->getPHID()); $relationship->setAuditReasons($reasons); $relationship->setAuditStatus($audit_status); $relationship->save(); $requests[$package->getPHID()] = $relationship; } $commit->updateAuditStatus($requests); $commit->save(); }
public function didParseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommitData $data) { $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $data->getCommitDetail('authorPHID')); if (!$user) { return; } $prefixes = array('resolves' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'fixes' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'wontfix' => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, 'wontfixes' => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, 'spite' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'spites' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'invalidate' => ManiphestTaskStatus::STATUS_CLOSED_INVALID, 'invaldiates' => ManiphestTaskStatus::STATUS_CLOSED_INVALID, 'close' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'closes' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'ref' => null, 'refs' => null, 'references' => null, 'cf.' => null); $suffixes = array('as resolved' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'as fixed' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'as wontfix' => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, 'as spite' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'out of spite' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'as invalid' => ManiphestTaskStatus::STATUS_CLOSED_INVALID, '' => null); $prefix_regex = array(); foreach ($prefixes as $prefix => $resolution) { $prefix_regex[] = preg_quote($prefix, '/'); } $prefix_regex = implode('|', $prefix_regex); $suffix_regex = array(); foreach ($suffixes as $suffix => $resolution) { $suffix_regex[] = preg_quote($suffix, '/'); } $suffix_regex = implode('|', $suffix_regex); $matches = null; $ok = preg_match_all("/({$prefix_regex})\\s+T(\\d+)\\s*({$suffix_regex})/i", $this->renderValueForCommitMessage($is_edit = false), $matches, PREG_SET_ORDER); if (!$ok) { return; } foreach ($matches as $set) { $prefix = strtolower($set[1]); $task_id = (int) $set[2]; $suffix = strtolower($set[3]); $status = idx($suffixes, $suffix); if (!$status) { $status = idx($prefixes, $prefix); } $tasks = id(new ManiphestTaskQuery())->withTaskIDs(array($task_id))->execute(); $task = idx($tasks, $task_id); if (!$task) { // Task doesn't exist, or the user can't see it. continue; } id(new PhabricatorEdgeEditor())->setUser($user)->addEdge($task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT, $commit->getPHID())->save(); if (!$status) { // Text like "Ref T123", don't change the task status. continue; } if ($task->getStatus() != ManiphestTaskStatus::STATUS_OPEN) { // Task is already closed. continue; } $commit_name = $repository->formatCommitName($commit->getCommitIdentifier()); $call = new ConduitCall('maniphest.update', array('id' => $task->getID(), 'status' => $status, 'comments' => "Closed by commit {$commit_name}.")); $call->setUser($user); $call->execute(); } }
private function pushToHgRepository(PhabricatorRepository $proxy) { $future = $proxy->getRemoteCommandFuture('push --verbose --rev tip -- %P', $proxy->getRemoteURIEnvelope()); try { $future->setCWD($proxy->getLocalPath())->resolvex(); } catch (CommandException $ex) { if (preg_match('/no changes found/', $ex->getStdOut())) { // mercurial says nothing changed, but that's good } else { throw $ex; } } }
private static function lookupPaths(array $paths) { $repository = new PhabricatorRepository(); $conn_w = $repository->establishConnection('w'); $result_map = array(); foreach (array_chunk($paths, 128) as $path_chunk) { $chunk_map = queryfx_all($conn_w, 'SELECT path, id FROM %T WHERE path IN (%Ls)', PhabricatorRepository::TABLE_PATH, $path_chunk); foreach ($chunk_map as $row) { $result_map[$row['path']] = $row['id']; } } return $result_map; }
/** * Verify that the "origin" remote exists, and points at the correct URI. * * This catches or corrects some types of misconfiguration, and also repairs * an issue where Git 1.7.1 does not create an "origin" for `--bare` clones. * See T4041. * * @param PhabricatorRepository Repository to verify. * @return void */ protected function verifyGitOrigin(PhabricatorRepository $repository) { try { list($remotes) = $repository->execxLocalCommand('remote show -n origin'); } catch (CommandException $ex) { throw new PhutilProxyException(pht('Expected to find a Git working copy at path "%s", but the ' . 'path exists and is not a valid working copy. If you remove ' . 'this directory, the daemons will automatically recreate it ' . 'correctly. Phabricator will not destroy the directory for you ' . 'because it can not be sure that it does not contain important ' . 'data.', $repository->getLocalPath()), $ex); } $matches = null; if (!preg_match('/^\\s*Fetch URL:\\s*(.*?)\\s*$/m', $remotes, $matches)) { throw new Exception(pht("Expected '%s' in '%s'.", 'Fetch URL', 'git remote show -n origin')); } $remote_uri = $matches[1]; $expect_remote = $repository->getRemoteURI(); if ($remote_uri == 'origin') { // If a remote does not exist, git pretends it does and prints out a // made up remote where the URI is the same as the remote name. This is // definitely not correct. // Possibly, we should use `git remote --verbose` instead, which does not // suffer from this problem (but is a little more complicated to parse). $valid = false; $exists = false; } else { $normal_type_git = PhabricatorRepositoryURINormalizer::TYPE_GIT; $remote_normal = id(new PhabricatorRepositoryURINormalizer($normal_type_git, $remote_uri))->getNormalizedPath(); $expect_normal = id(new PhabricatorRepositoryURINormalizer($normal_type_git, $expect_remote))->getNormalizedPath(); $valid = $remote_normal == $expect_normal; $exists = true; } if (!$valid) { if (!$exists) { // If there's no "origin" remote, just create it regardless of how // strongly we own the working copy. There is almost no conceivable // scenario in which this could do damage. $this->log(pht('Remote "origin" does not exist. Creating "origin", with ' . 'URI "%s".', $expect_remote)); $repository->execxLocalCommand('remote add origin %P', $repository->getRemoteURIEnvelope()); // NOTE: This doesn't fetch the origin (it just creates it), so we won't // know about origin branches until the next "pull" happens. That's fine // for our purposes, but might impact things in the future. } else { if ($repository->canDestroyWorkingCopy()) { // Bad remote, but we can try to repair it. $this->log(pht('Remote "origin" exists, but is pointed at the wrong URI, "%s". ' . 'Resetting origin URI to "%s.', $remote_uri, $expect_remote)); $repository->execxLocalCommand('remote set-url origin %P', $repository->getRemoteURIEnvelope()); } else { // Bad remote and we aren't comfortable repairing it. $message = pht('Working copy at "%s" has a mismatched origin URI, "%s". ' . 'The expected origin URI is "%s". Fix your configuration, or ' . 'set the remote URI correctly. To avoid breaking anything, ' . 'Phabricator will not automatically fix this.', $repository->getLocalPath(), $remote_uri, $expect_remote); throw new Exception($message); } } } }
private function pushToHgRepository(PhabricatorRepository $repository, PhabricatorRepositoryURI $mirror_uri) { $argv = array('push --verbose --rev tip -- %P', $mirror_uri->getURIEnvelope()); $future = $mirror_uri->newCommandEngine()->setArgv($argv)->newFuture(); try { $future->setCWD($repository->getLocalPath())->resolvex(); } catch (CommandException $ex) { if (preg_match('/no changes found/', $ex->getStdOut())) { // mercurial says nothing changed, but that's good } else { throw $ex; } } }
/** * Creates and/or cleans a workspace for the requested repo. * * return ArcanistMercurialAPI */ public static function getCleanMercurialWorkspace(PhabricatorRepository $repo) { $origin_path = $repo->getLocalPath(); $path = rtrim($origin_path, '/'); $path = $path . '__workspace'; if (!Filesystem::pathExists($path)) { $repo->execxLocalCommand('clone -- file://%s %s', $origin_path, $path); } $workspace = new ArcanistMercurialAPI($path); $workspace->execxLocal('pull'); $workspace->execxLocal('update --clean default'); $workspace->reloadWorkingCopy(); return $workspace; }
public static final function nameCommit(PhabricatorRepository $repository, $commit) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $commit_name = substr($commit, 0, 12); break; default: $commit_name = $commit; break; } $callsign = $repository->getCallsign(); return "r{$callsign}{$commit_name}"; }
public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { $uri = $repository->getDetail('remote-uri'); $log = $this->getSVNLogXMLObject($uri, $commit->getCommitIdentifier(), $verbose = false); $entry = $log->logentry[0]; $author = (string) $entry->author; $message = (string) $entry->msg; $this->updateCommitData($author, $message); if ($this->shouldQueueFollowupTasks()) { $task = new PhabricatorWorkerTask(); $task->setTaskClass('PhabricatorRepositorySvnCommitChangeParserWorker'); $task->setData(array('commitID' => $commit->getID())); $task->save(); } }