public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_name = true; $e_callsign = true; $repository = new PhabricatorRepository(); $type_map = PhabricatorRepositoryType::getAllRepositoryTypes(); $errors = array(); if ($request->isFormPost()) { $repository->setName($request->getStr('name')); $repository->setCallsign($request->getStr('callsign')); $repository->setVersionControlSystem($request->getStr('type')); if (!strlen($repository->getName())) { $e_name = 'Required'; $errors[] = 'Repository name is required.'; } else { $e_name = null; } if (!strlen($repository->getCallsign())) { $e_callsign = 'Required'; $errors[] = 'Callsign is required.'; } else { if (!preg_match('/^[A-Z]+$/', $repository->getCallsign())) { $e_callsign = 'Invalid'; $errors[] = 'Callsign must be ALL UPPERCASE LETTERS.'; } else { $e_callsign = null; } } if (empty($type_map[$repository->getVersionControlSystem()])) { $errors[] = 'Invalid version control system.'; } if (!$errors) { try { $repository->save(); return id(new AphrontRedirectResponse())->setURI('/repository/edit/' . $repository->getID() . '/'); } catch (AphrontQueryDuplicateKeyException $ex) { $e_callsign = 'Duplicate'; $errors[] = 'Callsign must be unique. Another repository already ' . 'uses that callsign.'; } } } $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); $error_view->setTitle('Form Errors'); } $form = new AphrontFormView(); $form->setUser($user)->setAction('/repository/create/')->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($repository->getName())->setError($e_name)->setCaption('Human-readable repository name.'))->appendChild('<p class="aphront-form-instructions">Select a "Callsign" — a ' . 'short, uppercase string to identify revisions in this repository. If ' . 'you choose "EX", revisions in this repository will be identified ' . 'with the prefix "rEX".</p>')->appendChild(id(new AphrontFormTextControl())->setLabel('Callsign')->setName('callsign')->setValue($repository->getCallsign())->setError($e_callsign)->setCaption('Short, UPPERCASE identifier. Once set, it can not be changed.'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Type')->setName('type')->setOptions($type_map)->setValue($repository->getVersionControlSystem()))->appendChild(id(new AphrontFormSubmitControl())->setValue('Create Repository')->addCancelButton('/repository/')); $panel = new AphrontPanelView(); $panel->setHeader('Create Repository'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Create Repository')); }
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; }
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}"; }
/** * returns PhabricatorActionView or an array of PhabricatorActionView or null. */ public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { return; } if ($repository->isHosted()) { return; } try { // These throw when failing. $this->init($viewer, $repository); $this->findGitHubRepo($repository); } catch (Exception $e) { return; } return $this->createActionView($revision, pht('Land to GitHub'))->setIcon('fa-cloud-upload'); }
private function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $parser = 'PhabricatorRepositoryGitCommitChangeParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $parser = 'PhabricatorRepositoryMercurialCommitChangeParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $parser = 'PhabricatorRepositorySvnCommitChangeParserWorker'; break; default: throw new Exception(pht('No support yet.')); } $parser_object = newv($parser, array(array())); return $parser_object->parseChangesForUnitTest($repository, $commit); }
public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { return; } if (!$repository->isHosted()) { return; } if (!$repository->isWorkingCopyBare()) { return; } // TODO: This temporarily disables this action, because it doesn't work // and is confusing to users. If you want to use it, comment out this line // for now and we'll provide real support eventually. return; return $this->createActionView($revision, pht('Land to Hosted Repository')); }
public function handleProtocols(PhabricatorRepository $repository) { $request = $this->getRequest(); $user = $request->getUser(); $type = $repository->getVersionControlSystem(); $is_svn = $type == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN; $v_http_mode = $repository->getDetail('serve-over-http', PhabricatorRepository::SERVE_OFF); $v_ssh_mode = $repository->getDetail('serve-over-ssh', PhabricatorRepository::SERVE_OFF); $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); $prev_uri = $this->getRepositoryControllerURI($repository, 'edit/hosting/'); if ($request->isFormPost()) { $v_http_mode = $request->getStr('http'); $v_ssh_mode = $request->getStr('ssh'); $xactions = array(); $template = id(new PhabricatorRepositoryTransaction()); $type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP; $type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH; if (!$is_svn) { $xactions[] = id(clone $template)->setTransactionType($type_http)->setNewValue($v_http_mode); } $xactions[] = id(clone $template)->setTransactionType($type_ssh)->setNewValue($v_ssh_mode); id(new PhabricatorRepositoryEditor())->setContinueOnNoEffect(true)->setContentSourceFromRequest($request)->setActor($user)->applyTransactions($repository, $xactions); return id(new AphrontRedirectResponse())->setURI($edit_uri); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit Protocols')); $title = pht('Edit Protocols (%s)', $repository->getName()); $rw_message = pht('Phabricator will serve a read-write copy of this repository.'); if (!$repository->isHosted()) { $rw_message = array($rw_message, phutil_tag('br'), phutil_tag('br'), pht('%s: This repository is hosted elsewhere, so Phabricator can not ' . 'perform writes. This mode will act like "Read Only" for ' . 'repositories hosted elsewhere.', phutil_tag('strong', array(), 'WARNING'))); } $ssh_control = id(new AphrontFormRadioButtonControl())->setName('ssh')->setLabel(pht('SSH'))->setValue($v_ssh_mode)->addButton(PhabricatorRepository::SERVE_OFF, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_OFF), pht('Phabricator will not serve this repository over SSH.'))->addButton(PhabricatorRepository::SERVE_READONLY, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READONLY), pht('Phabricator will serve a read-only copy of this repository ' . 'over SSH.'))->addButton(PhabricatorRepository::SERVE_READWRITE, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READWRITE), $rw_message); $http_control = id(new AphrontFormRadioButtonControl())->setName('http')->setLabel(pht('HTTP'))->setValue($v_http_mode)->addButton(PhabricatorRepository::SERVE_OFF, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_OFF), pht('Phabricator will not serve this repository over HTTP.'))->addButton(PhabricatorRepository::SERVE_READONLY, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READONLY), pht('Phabricator will serve a read-only copy of this repository ' . 'over HTTP.'))->addButton(PhabricatorRepository::SERVE_READWRITE, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READWRITE), $rw_message); if ($is_svn) { $http_control = id(new AphrontFormMarkupControl())->setLabel(pht('HTTP'))->setValue(phutil_tag('em', array(), pht('Phabricator does not currently support HTTP access to ' . 'Subversion repositories.'))); } $form = id(new AphrontFormView())->setUser($user)->appendRemarkupInstructions(pht('Phabricator can serve repositories over various protocols. You can ' . 'configure server protocols here.'))->appendChild($ssh_control); if (!PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')) { $form->appendRemarkupInstructions(pht('NOTE: The configuration setting [[ %s | %s ]] is currently ' . 'disabled. You must enable it to activate authenticated access ' . 'to repositories over HTTP.', '/config/edit/diffusion.allow-http-auth/', 'diffusion.allow-http-auth')); } $form->appendChild($http_control)->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save Changes'))->addCancelButton($prev_uri, pht('Back'))); $object_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setForm($form); return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => $title)); }
/** * Returns PhabricatorActionView or an array of PhabricatorActionView or null. */ public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { // TODO: This temporarily disables this action, because it doesn't work // and is confusing to users. If you want to use it, comment out this line // for now and we'll provide real support eventually. return; $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { return; } if ($repository->isHosted()) { return; } try { // These throw when failing. $this->init($viewer, $repository); $this->findGitHubRepo($repository); } catch (Exception $e) { return; } return $this->createActionView($revision, pht('Land to GitHub'))->setIcon('fa-cloud-upload'); }
private function buildRepositoryStatus(PhabricatorRepository $repository) { $viewer = $this->getRequest()->getUser(); $is_cluster = $repository->getAlmanacServicePHID(); $view = new PHUIStatusListView(); $messages = id(new PhabricatorRepositoryStatusMessage())->loadAllWhere('repositoryID = %d', $repository->getID()); $messages = mpull($messages, null, 'getStatusType'); if ($repository->isTracked()) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Repository Active'))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')->setTarget(pht('Repository Inactive'))->setNote(pht('Activate this repository to begin or resume import.'))); return $view; } $binaries = array(); $svnlook_check = false; switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binaries[] = 'git'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binaries[] = 'svn'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binaries[] = 'hg'; break; } if ($repository->isHosted()) { if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binaries[] = 'git-http-backend'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binaries[] = 'svnserve'; $binaries[] = 'svnadmin'; $binaries[] = 'svnlook'; $svnlook_check = true; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binaries[] = 'hg'; break; } } if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binaries[] = 'git-receive-pack'; $binaries[] = 'git-upload-pack'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binaries[] = 'svnserve'; $binaries[] = 'svnadmin'; $binaries[] = 'svnlook'; $svnlook_check = true; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binaries[] = 'hg'; break; } } } $binaries = array_unique($binaries); if (!$is_cluster) { // We're only checking for binaries if we aren't running with a cluster // configuration. In theory, we could check for binaries on the // repository host machine, but we'd need to make this more complicated // to do that. foreach ($binaries as $binary) { $where = Filesystem::resolveBinary($binary); if (!$where) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))->setNote(pht("Unable to find this binary in the webserver's PATH. You may " . "need to configure %s.", $this->getEnvConfigLink()))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Found Binary %s', phutil_tag('tt', array(), $binary)))->setNote(phutil_tag('tt', array(), $where))); } } // This gets checked generically above. However, for svn commit hooks, we // need this to be in environment.append-paths because subversion strips // PATH. if ($svnlook_check) { $where = Filesystem::resolveBinary('svnlook'); if ($where) { $path = substr($where, 0, strlen($where) - strlen('svnlook')); $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths'); $in_path = false; foreach ($dirs as $dir) { if (Filesystem::isDescendant($path, $dir)) { $in_path = true; break; } } if (!$in_path) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))->setNote(pht('Unable to find this binary in `%s`. ' . 'You need to configure %s and include %s.', 'environment.append-paths', $this->getEnvConfigLink(), $path))); } } } } $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd'); $daemon_instructions = pht('Use %s to start daemons. See %s.', phutil_tag('tt', array(), 'bin/phd start'), phutil_tag('a', array('href' => $doc_href), pht('Managing Daemons with phd'))); $pull_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))->setLimit(1)->execute(); if ($pull_daemon) { // TODO: In a cluster environment, we need a daemon on this repository's // host, specifically, and we aren't checking for that right now. This // is a reasonable proxy for things being more-or-less correctly set up, // though. $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Pull Daemon Running'))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Pull Daemon Not Running'))->setNote($daemon_instructions)); } $task_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))->setLimit(1)->execute(); if ($task_daemon) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Task Daemon Running'))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Task Daemon Not Running'))->setNote($daemon_instructions)); } if ($is_cluster) { // Just omit this status check for now in cluster environments. We // could make a service call and pull it from the repository host // eventually. } else { if ($repository->usesLocalWorkingCopy()) { $local_parent = dirname($repository->getLocalPath()); if (Filesystem::pathExists($local_parent)) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Storage Directory OK'))->setNote(phutil_tag('tt', array(), $local_parent))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('No Storage Directory'))->setNote(pht('Storage directory %s does not exist, or is not readable by ' . 'the webserver. Create this directory or make it readable.', phutil_tag('tt', array(), $local_parent)))); return $view; } $local_path = $repository->getLocalPath(); $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); if ($message) { switch ($message->getStatusCode()) { case PhabricatorRepositoryStatusMessage::CODE_ERROR: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Initialization Error'))->setNote($message->getParameter('message'))); return $view; case PhabricatorRepositoryStatusMessage::CODE_OKAY: if (Filesystem::pathExists($local_path)) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Working Copy OK'))->setNote(phutil_tag('tt', array(), $local_path))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Working Copy Error'))->setNote(pht('Working copy %s has been deleted, or is not ' . 'readable by the webserver. Make this directory ' . 'readable. If it has been deleted, the daemons should ' . 'restore it automatically.', phutil_tag('tt', array(), $local_path)))); return $view; } break; case PhabricatorRepositoryStatusMessage::CODE_WORKING: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')->setTarget(pht('Initializing Working Copy'))->setNote(pht('Daemons are initializing the working copy.'))); return $view; default: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Unknown Init Status'))->setNote($message->getStatusCode())); return $view; } } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')->setTarget(pht('No Working Copy Yet'))->setNote(pht('Waiting for daemons to build a working copy.'))); return $view; } } } $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); if ($message) { switch ($message->getStatusCode()) { case PhabricatorRepositoryStatusMessage::CODE_ERROR: $message = $message->getParameter('message'); $suggestion = null; if (preg_match('/Permission denied \\(publickey\\)./', $message)) { $suggestion = pht('Public Key Error: This error usually indicates that the ' . 'keypair you have configured does not have permission to ' . 'access the repository.'); } $message = phutil_escape_html_newlines($message); if ($suggestion !== null) { $message = array(phutil_tag('strong', array(), $suggestion), phutil_tag('br'), phutil_tag('br'), phutil_tag('em', array(), pht('Raw Error')), phutil_tag('br'), $message); } $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Update Error'))->setNote($message)); return $view; case PhabricatorRepositoryStatusMessage::CODE_OKAY: $ago = PhabricatorTime::getNow() - $message->getEpoch(); $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Updates OK'))->setNote(pht('Last updated %s (%s ago).', phabricator_datetime($message->getEpoch(), $viewer), phutil_format_relative_time_detailed($ago)))); break; } } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')->setTarget(pht('Waiting For Update'))->setNote(pht('Waiting for daemons to read updates.'))); } if ($repository->isImporting()) { $progress = queryfx_all($repository->establishConnection('r'), 'SELECT importStatus, count(*) N FROM %T WHERE repositoryID = %d GROUP BY importStatus', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID()); $done = 0; $total = 0; foreach ($progress as $row) { $total += $row['N'] * 4; $status = $row['importStatus']; if ($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_HERALD) { $done += $row['N']; } } if ($total) { $percentage = 100 * ($done / $total); } else { $percentage = 0; } // Cap this at "99.99%", because it's confusing to users when the actual // fraction is "99.996%" and it rounds up to "100.00%". if ($percentage > 99.98999999999999) { $percentage = 99.98999999999999; } $percentage = sprintf('%.2f%%', $percentage); $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')->setTarget(pht('Importing'))->setNote(pht('%s Complete', $percentage))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Fully Imported'))); } if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')->setTarget(pht('Prioritized'))->setNote(pht('This repository will be updated soon!'))); } return $view; }
private function buildPropertiesTable(PhabricatorRepository $repository) { $properties = array(); $properties['Name'] = $repository->getName(); $properties['Callsign'] = $repository->getCallsign(); $properties['Description'] = $repository->getDetail('description'); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $properties['Clone URI'] = $repository->getPublicRemoteURI(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $properties['Repository Root'] = $repository->getPublicRemoteURI(); break; } $rows = array(); foreach ($properties as $key => $value) { $rows[] = array(phutil_escape_html($key), phutil_escape_html($value)); } $table = new AphrontTableView($rows); $table->setColumnClasses(array('header', 'wide')); $panel = new AphrontPanelView(); $panel->setHeader('Repository Properties'); $panel->appendChild($table); return $panel; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $shortcuts = id(new PhabricatorRepositoryShortcut())->loadAll(); if ($shortcuts) { $shortcuts = msort($shortcuts, 'getSequence'); $rows = array(); foreach ($shortcuts as $shortcut) { $rows[] = array(phutil_render_tag('a', array('href' => $shortcut->getHref()), phutil_escape_html($shortcut->getName())), phutil_escape_html($shortcut->getDescription())); } $shortcut_table = new AphrontTableView($rows); $shortcut_table->setHeaders(array('Link', '')); $shortcut_table->setColumnClasses(array('pri', 'wide')); $shortcut_panel = new AphrontPanelView(); $shortcut_panel->setHeader('Shortcuts'); $shortcut_panel->appendChild($shortcut_table); } else { $shortcut_panel = null; } $repository = new PhabricatorRepository(); $repositories = $repository->loadAll(); foreach ($repositories as $key => $repo) { if (!$repo->isTracked()) { unset($repositories[$key]); } } $repository_ids = mpull($repositories, 'getID'); $summaries = array(); $commits = array(); if ($repository_ids) { $summaries = queryfx_all($repository->establishConnection('r'), 'SELECT * FROM %T WHERE repositoryID IN (%Ld)', PhabricatorRepository::TABLE_SUMMARY, $repository_ids); $summaries = ipull($summaries, null, 'repositoryID'); $commit_ids = array_filter(ipull($summaries, 'lastCommitID')); if ($commit_ids) { $commit = new PhabricatorRepositoryCommit(); $commits = $commit->loadAllWhere('id IN (%Ld)', $commit_ids); $commits = mpull($commits, null, 'getRepositoryID'); } } $rows = array(); foreach ($repositories as $repository) { $id = $repository->getID(); $commit = idx($commits, $id); $size = idx(idx($summaries, $id, array()), 'size', 0); $date = '-'; $time = '-'; if ($commit) { $date = phabricator_date($commit->getEpoch(), $user); $time = phabricator_time($commit->getEpoch(), $user); } $rows[] = array(phutil_render_tag('a', array('href' => '/diffusion/' . $repository->getCallsign() . '/'), phutil_escape_html($repository->getName())), phutil_escape_html($repository->getDetail('description')), PhabricatorRepositoryType::getNameForRepositoryType($repository->getVersionControlSystem()), $size ? number_format($size) : '-', $commit ? DiffusionView::linkCommit($repository, $commit->getCommitIdentifier()) : '-', $date, $time); } $repository_tool_uri = PhabricatorEnv::getProductionURI('/repository/'); $repository_tool = phutil_render_tag('a', array('href' => $repository_tool_uri), 'repository tool'); $no_repositories_txt = 'This instance of Phabricator does not have any ' . 'configured repositories. '; if ($user->getIsAdmin()) { $no_repositories_txt .= 'To setup one or more repositories, visit the ' . $repository_tool . '.'; } else { $no_repositories_txt .= 'Ask an administrator to setup one or more ' . 'repositories via the ' . $repository_tool . '.'; } $table = new AphrontTableView($rows); $table->setNoDataString($no_repositories_txt); $table->setHeaders(array('Repository', 'Description', 'VCS', 'Commits', 'Last', 'Date', 'Time')); $table->setColumnClasses(array('pri', 'wide', '', 'n', 'n', '', 'right')); $panel = new AphrontPanelView(); $panel->setHeader('Browse Repositories'); $panel->appendChild($table); $crumbs = $this->buildCrumbs(); return $this->buildStandardPageResponse(array($crumbs, $shortcut_panel, $panel), array('title' => 'Diffusion')); }
private function isCommitOnBranch(PhabricatorRepository $repo, PhabricatorRepositoryCommit $commit, ReleephBranch $releeph_branch) { switch ($repo->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: list($output) = $repo->execxLocalCommand('branch --all --no-color --contains %s', $commit->getCommitIdentifier()); $remote_prefix = 'remotes/origin/'; $branches = array(); foreach (array_filter(explode("\n", $output)) as $line) { $tokens = explode(' ', $line); $ref = last($tokens); if (strncmp($ref, $remote_prefix, strlen($remote_prefix)) === 0) { $branch = substr($ref, strlen($remote_prefix)); $branches[$branch] = $branch; } } return idx($branches, $releeph_branch->getName()); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(DiffusionRequest::newFromDictionary(array('user' => $this->getUser(), 'repository' => $repo, 'commit' => $commit->getCommitIdentifier()))); $path_changes = $change_query->loadChanges(); $commit_paths = mpull($path_changes, 'getPath'); $branch_path = $releeph_branch->getName(); $in_branch = array(); $ex_branch = array(); foreach ($commit_paths as $path) { if (strncmp($path, $branch_path, strlen($branch_path)) === 0) { $in_branch[] = $path; } else { $ex_branch[] = $path; } } if ($in_branch && $ex_branch) { $error = pht('CONFUSION: commit %s in %s contains %d path change(s) that were ' . 'part of a Releeph branch, but also has %d path change(s) not ' . 'part of a Releeph branch!', $commit->getCommitIdentifier(), $repo->getCallsign(), count($in_branch), count($ex_branch)); phlog($error); } return !empty($in_branch); break; } }
private function insertTask(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, $data = array()) { $vcs = $repository->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $class = 'PhabricatorRepositoryGitCommitMessageParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $class = 'PhabricatorRepositorySvnCommitMessageParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $class = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; break; default: throw new Exception("Unknown repository type '{$vcs}'!"); } $task = new PhabricatorWorkerTask(); $task->setTaskClass($class); $data['commitID'] = $commit->getID(); $task->setData($data); $task->save(); }
public function getAbsoluteRepositoryPath(PhabricatorRepository $repository, DifferentialDiff $diff = null) { $base = '/'; if ($diff && $diff->getSourceControlPath()) { $base = id(new PhutilURI($diff->getSourceControlPath()))->getPath(); } $path = $this->getFilename(); $path = rtrim($base, '/') . '/' . ltrim($path, '/'); $vcs = $repository->getVersionControlSystem(); if ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) { $prefix = $repository->getDetail('remote-uri'); $prefix = id(new PhutilURI($prefix))->getPath(); if (!strncmp($path, $prefix, strlen($prefix))) { $path = substr($path, strlen($prefix)); } $path = '/' . ltrim($path, '/'); } return $path; }
protected function buildDictForRepository(PhabricatorRepository $repository) { return array('name' => $repository->getName(), 'phid' => $repository->getPHID(), 'callsign' => $repository->getCallsign(), 'vcs' => $repository->getVersionControlSystem(), 'uri' => PhabricatorEnv::getProductionURI($repository->getURI()), 'remoteURI' => (string) $repository->getPublicRemoteURI(), 'tracking' => $repository->getDetail('tracking-enabled'), 'description' => $repository->getDetail('description')); }
private function renderCloneCommand(PhabricatorRepository $repository, $uri, $serve_mode = null, $manage_uri = null) { require_celerity_resource('diffusion-icons-css'); Javelin::initBehavior('select-on-click'); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $command = csprintf('git clone %R', $uri); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $command = csprintf('hg clone %R', $uri); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: if ($repository->isHosted()) { $command = csprintf('svn checkout %R %R', $uri, $repository->getCloneName()); } else { $command = csprintf('svn checkout %R', $uri); } break; } $input = javelin_tag('input', array('type' => 'text', 'value' => (string) $command, 'class' => 'diffusion-clone-uri', 'sigil' => 'select-on-click', 'readonly' => 'true')); $extras = array(); if ($serve_mode) { if ($serve_mode === PhabricatorRepository::SERVE_READONLY) { $extras[] = pht('(Read Only)'); } } if ($manage_uri) { if ($this->getRequest()->getUser()->isLoggedIn()) { $extras[] = phutil_tag('a', array('href' => $manage_uri), pht('Manage Credentials')); } } if ($extras) { $extras = phutil_implode_html(' ', $extras); $extras = phutil_tag('div', array('class' => 'diffusion-clone-extras'), $extras); } return array($input, $extras); }
/** * Note this code is somewhat similar to the buildPatch method in * @{class:DifferentialReviewRequestMail}. * * @return @{class:AphrontRedirectResponse} */ private function buildRawDiffResponse(DifferentialRevision $revision, array $changesets, array $vs_changesets, array $vs_map, PhabricatorRepository $repository = null) { assert_instances_of($changesets, 'DifferentialChangeset'); assert_instances_of($vs_changesets, 'DifferentialChangeset'); $viewer = $this->getRequest()->getUser(); id(new DifferentialHunkQuery())->setViewer($viewer)->withChangesets($changesets)->needAttachToChangesets(true)->execute(); $diff = new DifferentialDiff(); $diff->attachChangesets($changesets); $raw_changes = $diff->buildChangesList(); $changes = array(); foreach ($raw_changes as $changedict) { $changes[] = ArcanistDiffChange::newFromDictionary($changedict); } $loader = id(new PhabricatorFileBundleLoader())->setViewer($viewer); $bundle = ArcanistBundle::newFromChanges($changes); $bundle->setLoadFileDataCallback(array($loader, 'loadFileData')); $vcs = $repository ? $repository->getVersionControlSystem() : null; switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $raw_diff = $bundle->toGitPatch(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: default: $raw_diff = $bundle->toUnifiedDiff(); break; } $request_uri = $this->getRequest()->getRequestURI(); // this ends up being something like // D123.diff // or the verbose // D123.vs123.id123.whitespaceignore-all.diff // lame but nice to include these options $file_name = ltrim($request_uri->getPath(), '/') . '.'; foreach ($request_uri->getQueryParams() as $key => $value) { if ($key == 'download') { continue; } $file_name .= $key . $value . '.'; } $file_name .= 'diff'; $file = PhabricatorFile::buildFromFileDataOrHash($raw_diff, array('name' => $file_name, 'ttl' => 60 * 60 * 24, 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file->attachToObject($revision->getPHID()); unset($unguarded); return $file->getRedirectResponse(); }
private function insertTask(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, $data = array()) { $vcs = $repository->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $class = 'PhabricatorRepositoryGitCommitMessageParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $class = 'PhabricatorRepositorySvnCommitMessageParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $class = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; break; default: throw new Exception(pht("Unknown repository type '%s'!", $vcs)); } $data['commitID'] = $commit->getID(); PhabricatorWorker::scheduleTask($class, $data); }
/** * Note this code is somewhat similar to the buildPatch method in * @{class:DifferentialReviewRequestMail}. * * @return @{class:AphrontRedirectResponse} */ private function buildRawDiffResponse(array $changesets, array $vs_changesets, array $vs_map, PhabricatorRepository $repository = null) { assert_instances_of($changesets, 'DifferentialChangeset'); assert_instances_of($vs_changesets, 'DifferentialChangeset'); $engine = new PhabricatorDifferenceEngine(); $generated_changesets = array(); foreach ($changesets as $changeset) { $changeset->attachHunks($changeset->loadHunks()); $right = $changeset->makeNewFile(); $choice = $changeset; $vs = idx($vs_map, $changeset->getID()); if ($vs == -1) { $left = $right; $right = $changeset->makeOldFile(); } else { if ($vs) { $choice = $vs_changeset = $vs_changesets[$vs]; $vs_changeset->attachHunks($vs_changeset->loadHunks()); $left = $vs_changeset->makeNewFile(); } else { $left = $changeset->makeOldFile(); } } $synthetic = $engine->generateChangesetFromFileContent($left, $right); if (!$synthetic->getAffectedLineCount()) { $filetype = $choice->getFileType(); if ($filetype == DifferentialChangeType::FILE_TEXT || $filetype == DifferentialChangeType::FILE_SYMLINK) { continue; } } $choice->attachHunks($synthetic->getHunks()); $generated_changesets[] = $choice; } $diff = new DifferentialDiff(); $diff->attachChangesets($generated_changesets); $diff_dict = $diff->getDiffDict(); $changes = array(); foreach ($diff_dict['changes'] as $changedict) { $changes[] = ArcanistDiffChange::newFromDictionary($changedict); } $bundle = ArcanistBundle::newFromChanges($changes); $bundle->setLoadFileDataCallback(array($this, 'loadFileByPHID')); $vcs = $repository ? $repository->getVersionControlSystem() : null; switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $raw_diff = $bundle->toGitPatch(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: default: $raw_diff = $bundle->toUnifiedDiff(); break; } $request_uri = $this->getRequest()->getRequestURI(); // this ends up being something like // D123.diff // or the verbose // D123.vs123.id123.whitespaceignore-all.diff // lame but nice to include these options $file_name = ltrim($request_uri->getPath(), '/') . '.'; foreach ($request_uri->getQueryParams() as $key => $value) { if ($key == 'download') { continue; } $file_name .= $key . $value . '.'; } $file_name .= 'diff'; $file = PhabricatorFile::buildFromFileDataOrHash($raw_diff, array('name' => $file_name)); return id(new AphrontRedirectResponse())->setURI($file->getBestURI()); }
private function getRequestDirectoryPath(PhabricatorRepository $repository) { $request = $this->getRequest(); $request_path = $request->getRequestURI()->getPath(); $info = PhabricatorRepository::parseRepositoryServicePath($request_path, $repository->getVersionControlSystem()); $base_path = $info['path']; // For Git repositories, strip an optional directory component if it // isn't the name of a known Git resource. This allows users to clone // repositories as "/diffusion/X/anything.git", for example. if ($repository->isGit()) { $known = array('info', 'git-upload-pack', 'git-receive-pack'); foreach ($known as $key => $path) { $known[$key] = preg_quote($path, '@'); } $known = implode('|', $known); if (preg_match('@^/([^/]+)/(' . $known . ')(/|$)@', $base_path)) { $base_path = preg_replace('@^/([^/]+)@', '', $base_path); } } return $base_path; }
/** * Internal. Use @{method:newFromDictionary}, not this method. * * @param PhabricatorRepository Repository object. * @return DiffusionRequest New request object. * @task new */ private static final function newFromRepository(PhabricatorRepository $repository) { $map = array(PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'DiffusionGitRequest', PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => 'DiffusionSvnRequest', PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'DiffusionMercurialRequest'); $class = idx($map, $repository->getVersionControlSystem()); if (!$class) { throw new Exception(pht('Unknown version control system!')); } $object = new $class(); $object->repository = $repository; return $object; }
private function isReadOnlyRequest(PhabricatorRepository $repository) { $request = $this->getRequest(); $method = $_SERVER['REQUEST_METHOD']; // TODO: This implementation is safe by default, but very incomplete. switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $service = $request->getStr('service'); $path = $this->getRequestDirectoryPath($repository); // NOTE: Service names are the reverse of what you might expect, as they // are from the point of view of the server. The main read service is // "git-upload-pack", and the main write service is "git-receive-pack". if ($method == 'GET' && $path == '/info/refs' && $service == 'git-upload-pack') { return true; } if ($path == '/git-upload-pack') { return true; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $cmd = $request->getStr('cmd'); if ($cmd == 'batch') { $cmds = idx($this->getMercurialArguments(), 'cmds'); return DiffusionMercurialWireProtocol::isReadOnlyBatchCommand($cmds); } return DiffusionMercurialWireProtocol::isReadOnlyCommand($cmd); case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: break; } return false; }
private function insertTask(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, $data = array()) { $vcs = $repository->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $class = 'PhabricatorRepositoryGitCommitMessageParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $class = 'PhabricatorRepositorySvnCommitMessageParserWorker'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $class = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; break; default: throw new Exception(pht("Unknown repository type '%s'!", $vcs)); } $data['commitID'] = $commit->getID(); // If the repository is importing for the first time, we schedule tasks // at IMPORT priority, which is very low. Making progress on importing a // new repository for the first time is less important than any other // daemon task. // If the repostitory has finished importing and we're just catching up // on recent commits, we schedule discovery at COMMIT priority, which is // slightly below the default priority. // Note that followup tasks and triggered tasks (like those generated by // Herald or Harbormaster) will queue at DEFAULT priority, so that each // commit tends to fully import before we start the next one. This tends // to give imports fairly predictable progress. See T11677 for some // discussion. if ($repository->isImporting()) { $task_priority = PhabricatorWorker::PRIORITY_IMPORT; } else { $task_priority = PhabricatorWorker::PRIORITY_COMMIT; } $options = array('priority' => $task_priority); PhabricatorWorker::scheduleTask($class, $data, $options); }