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); } } }
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 '%s', Phabricator will not be able to generate or render " . "diffs in multiple applications.", 'diff'); $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 '%s' Behavior", 'diff'))->setMessage(pht("The '%s' 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.", 'diff', $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 '%s' binary on this system has unexpected behavior: " . "it was expected to exit with a nonzero error code when passed " . "differing files, but did not.", 'diff')); } } $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); continue; } $version = null; switch ($vcs['versionControlSystem']) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $minimum_version = null; $bad_versions = array(); list($err, $stdout, $stderr) = exec_manual('git --version'); $version = trim(substr($stdout, strlen('git version '))); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $minimum_version = '1.5'; $bad_versions = array('1.7.1' => pht('This version of Subversion has a bug where `%s` does not work ' . 'for files added in rN (Subversion issue #2873), fixed in 1.7.2.', 'svn diff -c N')); list($err, $stdout, $stderr) = exec_manual('svn --version --quiet'); $version = trim($stdout); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $minimum_version = '1.9'; $bad_versions = array('2.1' => pht('This version of Mercurial returns a bad exit code ' . 'after a successful pull.'), '2.2' => pht('This version of Mercurial has a significant memory leak, fixed ' . 'in 2.2.1. Pushing fails with this version as well; see %s.', 'T3046#54922')); $version = PhabricatorRepositoryVersion::getMercurialVersion(); break; } if ($version === null) { $this->raiseUnknownVersionWarning($binary); } else { if ($minimum_version && version_compare($version, $minimum_version, '<')) { $this->raiseMinimumVersionWarning($binary, $minimum_version, $version); } foreach ($bad_versions as $bad_version => $details) { if ($bad_version === $version) { $this->raiseBadVersionWarning($binary, $bad_version); } } } } }
protected function loadPage() { $table = new PhabricatorRepository(); $conn_r = $table->establishConnection('r'); $data = queryfx_all($conn_r, 'SELECT * FROM %T r %Q %Q %Q %Q', $table->getTableName(), $this->buildJoinsClause($conn_r), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); $repositories = $table->loadAllFromArray($data); if ($this->needCommitCounts) { $sizes = ipull($data, 'size', 'id'); foreach ($repositories as $id => $repository) { $repository->attachCommitCount(nonempty($sizes[$id], 0)); } } if ($this->needMostRecentCommits) { $commit_ids = ipull($data, 'lastCommitID', 'id'); $commit_ids = array_filter($commit_ids); if ($commit_ids) { $commits = id(new DiffusionCommitQuery())->setViewer($this->getViewer())->withIDs($commit_ids)->execute(); } else { $commits = array(); } foreach ($repositories as $id => $repository) { $commit = null; if (idx($commit_ids, $id)) { $commit = idx($commits, $commit_ids[$id]); } $repository->attachMostRecentCommit($commit); } } return $repositories; }
/** * Rebuild a cache bucket, amending existing data if available. * * @param int Bucket key, from @{method:getBucketKey}. * @param array Existing bucket data. * @return array Rebuilt bucket data. * @task cache */ private function rebuildBucket($bucket_key, array $current_data) { // First, check if we've already rebuilt this bucket. In some cases (like // browsing a repository at some commit) it's common to issue many lookups // against one commit. If that commit has been discovered but not yet // fully imported, we'll repeatedly attempt to rebuild the bucket. If the // first rebuild did not work, subsequent rebuilds are very unlikely to // have any effect. We can just skip the rebuild in these cases. if (isset($this->rebuiltKeys[$bucket_key])) { return $current_data; } else { $this->rebuiltKeys[$bucket_key] = true; } $bucket_min = $bucket_key * $this->getBucketSize(); $bucket_max = $bucket_min + $this->getBucketSize() - 1; // We need to reload all of the commits in the bucket because there is // no guarantee that they'll get parsed in order, so we can fill large // commit IDs before small ones. Later on, we'll ignore the commits we // already know about. $table_commit = new PhabricatorRepositoryCommit(); $table_repository = new PhabricatorRepository(); $conn_r = $table_commit->establishConnection('r'); // Find all the Git and Mercurial commits in the block which have completed // change import. We can't fill the cache accurately for commits which have // not completed change import, so just pretend we don't know about them. // In these cases, we will ultimately fall back to VCS queries. $commit_rows = queryfx_all($conn_r, 'SELECT c.id FROM %T c JOIN %T r ON c.repositoryID = r.id AND r.versionControlSystem IN (%Ls) WHERE c.id BETWEEN %d AND %d AND (c.importStatus & %d) = %d', $table_commit->getTableName(), $table_repository->getTableName(), array(PhabricatorRepositoryType::REPOSITORY_TYPE_GIT, PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL), $bucket_min, $bucket_max, PhabricatorRepositoryCommit::IMPORTED_CHANGE, PhabricatorRepositoryCommit::IMPORTED_CHANGE); // If we don't have any data, just return the existing data. if (!$commit_rows) { return $current_data; } // Remove the commits we already have data for. We don't need to rebuild // these. If there's nothing left, return the existing data. $commit_ids = ipull($commit_rows, 'id', 'id'); $commit_ids = array_diff_key($commit_ids, $current_data); if (!$commit_ids) { return $current_data; } // Find all the path changes for the new commits. $path_changes = queryfx_all($conn_r, 'SELECT commitID, pathID FROM %T WHERE commitID IN (%Ld) AND (isDirect = 1 OR changeType = %d)', PhabricatorRepository::TABLE_PATHCHANGE, $commit_ids, DifferentialChangeType::TYPE_CHILD); $path_changes = igroup($path_changes, 'commitID'); // Find all the parents for the new commits. $parents = queryfx_all($conn_r, 'SELECT childCommitID, parentCommitID FROM %T WHERE childCommitID IN (%Ld) ORDER BY id ASC', PhabricatorRepository::TABLE_PARENTS, $commit_ids); $parents = igroup($parents, 'childCommitID'); // Build the actual data for the cache. foreach ($commit_ids as $commit_id) { $parent_ids = array(); if (!empty($parents[$commit_id])) { foreach ($parents[$commit_id] as $row) { $parent_ids[] = (int) $row['parentCommitID']; } } else { // We expect all rows to have parents (commits with no parents get // an explicit "0" placeholder). If we're in an older repository, the // parent information might not have been populated yet. Decline to fill // the cache if we don't have the parent information, since the fill // will be incorrect. continue; } if (isset($path_changes[$commit_id])) { $path_ids = $path_changes[$commit_id]; foreach ($path_ids as $key => $path_id) { $path_ids[$key] = (int) $path_id['pathID']; } sort($path_ids); } else { $path_ids = array(); } $value = $parent_ids; $value[] = null; foreach ($path_ids as $path_id) { $value[] = $path_id; } $current_data[$commit_id] = $value; } return $current_data; }
$conn_w = $table->establishConnection('w'); $default_path = PhabricatorEnv::getEnvConfig('repository.default-local-path'); $default_path = rtrim($default_path, '/'); foreach (new LiskMigrationIterator($table) as $repository) { $local_path = $repository->getLocalPath(); if (strlen($local_path)) { // Repository already has a modern, unique local path. continue; } $local_path = $repository->getDetail('local-path'); if (!strlen($local_path)) { // Repository does not have a local path using the older format. continue; } $random = Filesystem::readRandomCharacters(8); // Try the configured path first, then a default path, then a path with some // random noise. $paths = array($local_path, $default_path . '/' . $repository->getID() . '/', $default_path . '/' . $repository->getID() . '-' . $random . '/'); foreach ($paths as $path) { // Set, then get the path to normalize it. $repository->setLocalPath($path); $path = $repository->getLocalPath(); try { queryfx($conn_w, 'UPDATE %T SET localPath = %s WHERE id = %d', $table->getTableName(), $path, $repository->getID()); echo tsprintf("%s\n", pht('Assigned repository "%s" to local path "%s".', $repository->getDisplayName(), $path)); break; } catch (AphrontDuplicateKeyQueryException $ex) { // Ignore, try the next one. } } }
} $passphrase = new PassphraseSecret(); $passphrase->openTransaction(); $table->openTransaction(); foreach ($map as $credential_type => $credential_usernames) { $type = PassphraseCredentialType::getTypeByConstant($credential_type); foreach ($credential_usernames as $username => $credential_secrets) { foreach ($credential_secrets as $secret_plaintext => $repositories) { $callsigns = mpull($repositories, 'getCallsign'); $signs = implode(', ', $callsigns); $name = pht('Migrated Repository Credential (%s)', id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($signs)); echo pht('Creating: %s...', $name) . "\n"; $secret = id(new PassphraseSecret())->setSecretData($secret_plaintext)->save(); $secret_id = $secret->getID(); $credential = PassphraseCredential::initializeNewCredential($viewer)->setCredentialType($type->getCredentialType())->setProvidesType($type->getProvidesType())->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN)->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN)->setName($name)->setUsername($username)->setSecretID($secret_id); $credential->setPHID($credential->generatePHID()); queryfx($credential->establishConnection('w'), 'INSERT INTO %T (name, credentialType, providesType, viewPolicy, editPolicy, description, username, secretID, isDestroyed, phid, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %s, %s, %d, %d, %s, %d, %d)', $credential->getTableName(), $credential->getName(), $credential->getCredentialType(), $credential->getProvidesType(), $credential->getViewPolicy(), $credential->getEditPolicy(), $credential->getDescription(), $credential->getUsername(), $credential->getSecretID(), $credential->getIsDestroyed(), $credential->getPHID(), time(), time()); foreach ($repositories as $repository) { queryfx($conn_w, 'UPDATE %T SET credentialPHID = %s WHERE id = %d', $table->getTableName(), $credential->getPHID(), $repository->getID()); $edge_type = PhabricatorObjectUsesCredentialsEdgeType::EDGECONST; id(new PhabricatorEdgeEditor())->addEdge($repository->getPHID(), $edge_type, $credential->getPHID())->save(); } } } } $table->saveTransaction(); $passphrase->saveTransaction(); echo pht('Done.') . "\n";
$repo = idx($repositories, $repositoryID); if (!$repo) { continue; } echo pht("Migrating symbols configuration for '%s' project...\n", idx($project_row, 'name', '???')); $symbol_index_projects = $project_row['symbolIndexProjects']; $symbol_index_projects = nonempty($symbol_index_projects, '[]'); try { $symbol_index_projects = phutil_json_decode($symbol_index_projects); } catch (PhutilJSONParserException $ex) { continue; } $sources = $repo->getDetail('symbol-sources', array()); foreach ($symbol_index_projects as $index_project) { $sources[] = idx($projects_to_repos_map, $index_project); } $sources = array_filter($sources); $sources = array_unique($sources); $repo->setDetail('symbol-sources', $sources); $languages = $project_row['symbolIndexLanguages']; $languages = nonempty($languages, '[]'); try { $languages = phutil_json_decode($languages); } catch (PhutilJSONParserException $ex) { continue; } $languages = array_merge($repo->getDetail('symbol-languages', array()), $languages); $languages = array_unique($languages); $repo->setDetail('symbol-languages', $languages); queryfx($conn_w, 'UPDATE %T SET details = %s WHERE id = %d', $table_w->getTableName(), json_encode($repo->getDetails()), $repo->getID()); }
* 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. */ echo "Stripping remotes from repository default branches...\n"; $table = new PhabricatorRepository(); $conn_w = $table->establishConnection('w'); $repos = queryfx_all($conn_w, 'SELECT id, name, details FROM %T WHERE versionControlSystem = %s', $table->getTableName(), 'git'); foreach ($repos as $repo) { $details = json_decode($repo['details'], true); $old = idx($details, 'default-branch', ''); if (strpos($old, '/') === false) { continue; } $parts = explode('/', $old); $parts = array_filter($parts); $new = end($parts); $details['default-branch'] = $new; $new_details = json_encode($details); $id = $repo['id']; $name = $repo['name']; echo "Updating default branch for repository #{$id} '{$name}' from " . "'{$old}' to '{$new}' to remove the explicit remote.\n"; queryfx($conn_w, 'UPDATE %T SET details = %s WHERE id = %d', $table->getTableName(), $new_details, $id);
<?php $table = new PhabricatorRepository(); $conn_w = $table->establishConnection('w'); foreach (new LiskMigrationIterator($table) as $repository) { $slug = $repository->getRepositorySlug(); if ($slug !== null) { continue; } $clone_name = $repository->getDetail('clone-name'); if (!strlen($clone_name)) { continue; } if (!PhabricatorRepository::isValidRepositorySlug($clone_name)) { echo tsprintf("%s\n", pht('Repository "%s" has a "Clone/Checkout As" name which is no longer ' . 'valid ("%s"). You can edit the repository to give it a new, valid ' . 'short name.', $repository->getDisplayName(), $clone_name)); continue; } try { queryfx($conn_w, 'UPDATE %T SET repositorySlug = %s WHERE id = %d', $table->getTableName(), $clone_name, $repository->getID()); } catch (AphrontDuplicateKeyQueryException $ex) { echo tsprintf("%s\n", pht('Repository "%s" has a duplicate "Clone/Checkout As" name ("%s"). ' . 'Each name must now be unique. You can edit the repository to give ' . 'it a new, unique short name.', $repository->getDisplayName(), $clone_name)); } }