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();
 }
 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));
 }
 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();
     }
 }
 public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     $local_path = $repository->getDetail('local-path');
     // NOTE: %B was introduced somewhat recently in git's history, so pull
     // commit message information with %s and %b instead.
     list($info) = execx('(cd %s && git log -n 1 --pretty=format:%%an%%x00%%s%%n%%n%%b %s)', $local_path, $commit->getCommitIdentifier());
     list($author, $message) = explode("", $info);
     // Make sure these are valid UTF-8.
     $author = phutil_utf8ize($author);
     $message = phutil_utf8ize($message);
     $message = trim($message);
     $this->updateCommitData($author, $message);
     if ($this->shouldQueueFollowupTasks()) {
         $task = new PhabricatorWorkerTask();
         $task->setTaskClass('PhabricatorRepositoryGitCommitChangeParserWorker');
         $task->setData(array('commitID' => $commit->getID()));
         $task->save();
     }
 }
 private function triggerOwnerAudits(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     if ($repository->getDetail('herald-disabled')) {
         return;
     }
     $affected_paths = PhabricatorOwnerPathQuery::loadAffectedPaths($repository, $commit, PhabricatorUser::getOmnipotentUser());
     $affected_packages = PhabricatorOwnersPackage::loadAffectedPackages($repository, $affected_paths);
     if ($affected_packages) {
         $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->getAuditingEnabled()) {
                 $reasons = $this->checkAuditReasons($commit, $package);
                 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 parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
    {
        if ($repository->getDetail('herald-disabled')) {
            return;
        }
        $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
        $rules = HeraldRule::loadAllByContentTypeWithFullData(HeraldContentTypeConfig::CONTENT_TYPE_COMMIT);
        $adapter = new HeraldCommitAdapter($repository, $commit, $data);
        $engine = new HeraldEngine();
        $effects = $engine->applyRules($rules, $adapter);
        $engine->applyEffects($effects, $adapter);
        $email_phids = $adapter->getEmailPHIDs();
        if (!$email_phids) {
            return;
        }
        $xscript = $engine->getTranscript();
        $commit_name = $adapter->getHeraldName();
        $revision = $adapter->loadDifferentialRevision();
        $name = null;
        if ($revision) {
            $name = ' ' . $revision->getTitle();
        }
        $author_phid = $data->getCommitDetail('authorPHID');
        $reviewer_phid = $data->getCommitDetail('reviewerPHID');
        $phids = array_filter(array($author_phid, $reviewer_phid));
        $handles = array();
        if ($phids) {
            $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
        }
        if ($author_phid) {
            $author_name = $handles[$author_phid]->getName();
        } else {
            $author_name = $data->getAuthorName();
        }
        if ($reviewer_phid) {
            $reviewer_name = $handles[$reviewer_phid]->getName();
        } else {
            $reviewer_name = null;
        }
        $who = implode(', ', array_filter(array($author_name, $reviewer_name)));
        $description = $data->getCommitMessage();
        $details = PhabricatorEnv::getProductionURI('/' . $commit_name);
        $differential = $revision ? PhabricatorEnv::getProductionURI('/D' . $revision->getID()) : 'No revision.';
        $files = $adapter->loadAffectedPaths();
        sort($files);
        $files = implode("\n  ", $files);
        $xscript_id = $xscript->getID();
        $manage_uri = PhabricatorEnv::getProductionURI('/herald/view/commits/');
        $why_uri = PhabricatorEnv::getProductionURI('/herald/transcript/' . $xscript_id . '/');
        $body = <<<EOBODY
DESCRIPTION
{$description}

DETAILS
  {$details}

DIFFERENTIAL REVISION
  {$differential}

AFFECTED FILES
  {$files}

MANAGE HERALD COMMIT RULES
  {$manage_uri}

WHY DID I GET THIS EMAIL?
  {$why_uri}

EOBODY;
        $subject = "[Herald/Commit] {$commit_name} ({$who}){$name}";
        $mailer = new PhabricatorMetaMTAMail();
        $mailer->setRelatedPHID($commit->getPHID());
        $mailer->addTos($email_phids);
        $mailer->setSubject($subject);
        $mailer->setBody($body);
        $mailer->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
        if ($author_phid) {
            $mailer->setFrom($author_phid);
        }
        $mailer->saveAndSend();
    }
 private function lookupSvnCommits(PhabricatorRepository $repository, array $commits)
 {
     if (!$commits) {
         return array();
     }
     $commit_table = new PhabricatorRepositoryCommit();
     $commit_data = queryfx_all($commit_table->establishConnection('w'), 'SELECT id, commitIdentifier FROM %T
     WHERE repositoryID = %d AND commitIdentifier in (%Ls)', $commit_table->getTableName(), $repository->getID(), $commits);
     $commit_map = ipull($commit_data, 'id', 'commitIdentifier');
     $need = array();
     foreach ($commits as $commit) {
         if (empty($commit_map[$commit])) {
             $need[] = $commit;
         }
     }
     // If we are parsing a Subversion repository and have been configured to
     // import only some subdirectory of it, we may find commits which reference
     // other foreign commits outside of the directory (for instance, because of
     // a move or copy). Rather than trying to execute full parses on them, just
     // create stub commits and identify the stubs as foreign commits.
     if ($need) {
         $subpath = $repository->getDetail('svn-subpath');
         if (!$subpath) {
             $commits = implode(', ', $need);
             throw new Exception("Missing commits ({$need}) in a SVN repository which is not " . "configured for subdirectory-only parsing!");
         }
         foreach ($need as $foreign_commit) {
             $commit = new PhabricatorRepositoryCommit();
             $commit->setRepositoryID($repository->getID());
             $commit->setCommitIdentifier($foreign_commit);
             $commit->setEpoch(0);
             // Mark this commit as imported so it doesn't prevent the repository
             // from transitioning into the "Imported" state.
             $commit->setImportStatus(PhabricatorRepositoryCommit::IMPORTED_ALL);
             $commit->save();
             $data = new PhabricatorRepositoryCommitData();
             $data->setCommitID($commit->getID());
             $data->setAuthorName('');
             $data->setCommitMessage('');
             $data->setCommitDetails(array('foreign-svn-stub' => true, 'svn-subpath' => $subpath));
             $data->save();
             $commit_map[$foreign_commit] = $commit->getID();
         }
     }
     return $commit_map;
 }
 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;
 }
 private function buildDescriptionView(PhabricatorRepository $repository)
 {
     $viewer = $this->getViewer();
     $view = id(new PHUIPropertyListView())->setUser($viewer);
     $description = $repository->getDetail('description');
     if (strlen($description)) {
         $description = new PHUIRemarkupView($viewer, $description);
         $view->addTextContent($description);
         return id(new PHUIObjectBoxView())->setHeaderText(pht('Description'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->appendChild($view);
     }
     return null;
 }
 private function lookupRecursiveFileList(PhabricatorRepository $repository, array $info)
 {
     $path = $info['rawPath'];
     $rev = $info['rawCommit'];
     $path = $this->encodeSVNPath($path);
     $hashkey = md5($repository->getDetail('remote-uri') . $path . '@' . $rev);
     // This method is quite horrible. The underlying challenge is that some
     // commits in the Facebook repository are enormous, taking multiple hours
     // to 'ls -R' out of the repository and producing XML files >1GB in size.
     // If we try to SimpleXML them, the object exhausts available memory on a
     // 64G machine. Instead, cache the XML output and then parse it line by line
     // to limit space requirements.
     $cache_loc = sys_get_temp_dir() . '/diffusion.' . $hashkey . '.svnls';
     if (!Filesystem::pathExists($cache_loc)) {
         $tmp = new TempFile();
         execx('svn --non-interactive --xml ls -R %s%s@%d > %s', $repository->getDetail('remote-uri'), $path, $rev, $tmp);
         execx('mv %s %s', $tmp, $cache_loc);
     }
     $map = $this->parseRecursiveListFileData($cache_loc);
     Filesystem::remove($cache_loc);
     return $map;
 }
 protected function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     $full_name = 'r' . $repository->getCallsign() . $commit->getCommitIdentifier();
     echo "Parsing {$full_name}...\n";
     if ($this->isBadCommit($full_name)) {
         echo "This commit is marked bad!\n";
         return;
     }
     $local_path = $repository->getDetail('local-path');
     list($raw) = execx('(cd %s && git log -n1 -M -C -B --find-copies-harder --raw -t ' . '--abbrev=40 --pretty=format: %s)', $local_path, $commit->getCommitIdentifier());
     $changes = array();
     $move_away = array();
     $copy_away = array();
     $lines = explode("\n", $raw);
     foreach ($lines as $line) {
         if (!strlen(trim($line))) {
             continue;
         }
         list($old_mode, $new_mode, $old_hash, $new_hash, $more_stuff) = preg_split('/ +/', $line);
         // We may only have two pieces here.
         list($action, $src_path, $dst_path) = array_merge(explode("\t", $more_stuff), array(null));
         // Normalize the paths for consistency with the SVN workflow.
         $src_path = '/' . $src_path;
         if ($dst_path) {
             $dst_path = '/' . $dst_path;
         }
         $old_mode = intval($old_mode, 8);
         $new_mode = intval($new_mode, 8);
         $file_type = DifferentialChangeType::FILE_NORMAL;
         if ($new_mode & 040000) {
             $file_type = DifferentialChangeType::FILE_DIRECTORY;
         } else {
             if ($new_mode & 0120000) {
                 $file_type = DifferentialChangeType::FILE_SYMLINK;
             }
         }
         // TODO: We can detect binary changes as git does, through a combination
         // of running 'git check-attr' for stuff like 'binary', 'merge' or 'diff',
         // and by falling back to inspecting the first 8,000 characters of the
         // buffer for null bytes (this is seriously git's algorithm, see
         // buffer_is_binary() in xdiff-interface.c).
         $change_type = null;
         $change_path = $src_path;
         $change_target = null;
         $is_direct = true;
         switch ($action[0]) {
             case 'A':
                 $change_type = DifferentialChangeType::TYPE_ADD;
                 break;
             case 'D':
                 $change_type = DifferentialChangeType::TYPE_DELETE;
                 break;
             case 'C':
                 $change_type = DifferentialChangeType::TYPE_COPY_HERE;
                 $change_path = $dst_path;
                 $change_target = $src_path;
                 $copy_away[$change_target][] = $change_path;
                 break;
             case 'R':
                 $change_type = DifferentialChangeType::TYPE_MOVE_HERE;
                 $change_path = $dst_path;
                 $change_target = $src_path;
                 $move_away[$change_target][] = $change_path;
                 break;
             case 'T':
                 // Type of the file changed, fall through and treat it as a
                 // modification. Not 100% sure this is the right thing to do but it
                 // seems reasonable.
             // Type of the file changed, fall through and treat it as a
             // modification. Not 100% sure this is the right thing to do but it
             // seems reasonable.
             case 'M':
                 if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
                     $change_type = DifferentialChangeType::TYPE_CHILD;
                     $is_direct = false;
                 } else {
                     $change_type = DifferentialChangeType::TYPE_CHANGE;
                 }
                 break;
                 // NOTE: "U" (unmerged) and "X" (unknown) statuses are also possible
                 // in theory but shouldn't appear here.
             // NOTE: "U" (unmerged) and "X" (unknown) statuses are also possible
             // in theory but shouldn't appear here.
             default:
                 throw new Exception("Failed to parse line '{$line}'.");
         }
         $changes[$change_path] = array('repositoryID' => $repository->getID(), 'commitID' => $commit->getID(), 'path' => $change_path, 'changeType' => $change_type, 'fileType' => $file_type, 'isDirect' => $is_direct, 'commitSequence' => $commit->getEpoch(), 'targetPath' => $change_target, 'targetCommitID' => $change_target ? $commit->getID() : null);
     }
     // Add a change to '/' since git doesn't mention it.
     $changes['/'] = array('repositoryID' => $repository->getID(), 'commitID' => $commit->getID(), 'path' => '/', 'changeType' => DifferentialChangeType::TYPE_CHILD, 'fileType' => DifferentialChangeType::FILE_DIRECTORY, 'isDirect' => false, 'commitSequence' => $commit->getEpoch(), 'targetPath' => null, 'targetCommitID' => null);
     foreach ($copy_away as $change_path => $destinations) {
         if (isset($move_away[$change_path])) {
             $change_type = DifferentialChangeType::TYPE_MULTICOPY;
             $is_direct = true;
             unset($move_away[$change_path]);
         } else {
             $change_type = DifferentialChangeType::TYPE_COPY_AWAY;
             $is_direct = false;
         }
         $reference = $changes[reset($destinations)];
         $changes[$change_path] = array('repositoryID' => $repository->getID(), 'commitID' => $commit->getID(), 'path' => $change_path, 'changeType' => $change_type, 'fileType' => $reference['fileType'], 'isDirect' => $is_direct, 'commitSequence' => $commit->getEpoch(), 'targetPath' => null, 'targetCommitID' => null);
     }
     foreach ($move_away as $change_path => $destinations) {
         $reference = $changes[reset($destinations)];
         $changes[$change_path] = array('repositoryID' => $repository->getID(), 'commitID' => $commit->getID(), 'path' => $change_path, 'changeType' => DifferentialChangeType::TYPE_MOVE_AWAY, 'fileType' => $reference['fileType'], 'isDirect' => true, 'commitSequence' => $commit->getEpoch(), 'targetPath' => null, 'targetCommitID' => null);
     }
     $paths = array();
     foreach ($changes as $change) {
         $paths[$change['path']] = true;
         if ($change['targetPath']) {
             $paths[$change['targetPath']] = true;
         }
     }
     $path_map = $this->lookupOrCreatePaths(array_keys($paths));
     foreach ($changes as $key => $change) {
         $changes[$key]['pathID'] = $path_map[$change['path']];
         if ($change['targetPath']) {
             $changes[$key]['targetPathID'] = $path_map[$change['targetPath']];
         } else {
             $changes[$key]['targetPathID'] = null;
         }
     }
     $conn_w = $repository->establishConnection('w');
     $changes_sql = array();
     foreach ($changes as $change) {
         $values = array((int) $change['repositoryID'], (int) $change['pathID'], (int) $change['commitID'], $change['targetPathID'] ? (int) $change['targetPathID'] : 'null', $change['targetCommitID'] ? (int) $change['targetCommitID'] : 'null', (int) $change['changeType'], (int) $change['fileType'], (int) $change['isDirect'], (int) $change['commitSequence']);
         $changes_sql[] = '(' . implode(', ', $values) . ')';
     }
     queryfx($conn_w, 'DELETE FROM %T WHERE commitID = %d', PhabricatorRepository::TABLE_PATHCHANGE, $commit->getID());
     foreach (array_chunk($changes_sql, 256) as $sql_chunk) {
         queryfx($conn_w, 'INSERT INTO %T
       (repositoryID, pathID, commitID, targetPathID, targetCommitID,
         changeType, fileType, isDirect, commitSequence)
       VALUES %Q', PhabricatorRepository::TABLE_PATHCHANGE, implode(', ', $sql_chunk));
     }
     $this->finishParse();
 }
 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 executeSvnGetBaseSVNLogURI(PhabricatorRepository $repository)
 {
     $uri = $repository->getDetail('remote-uri');
     $subpath = $repository->getDetail('svn-subpath');
     return $uri . $subpath;
 }
 /**
  * @task pull
  */
 private function resolveUpdateFuture(PhabricatorRepository $repository, ExecFuture $future, $min_sleep)
 {
     $monogram = $repository->getMonogram();
     $this->log(pht('Resolving update for "%s".', $monogram));
     try {
         list($stdout, $stderr) = $future->resolvex();
     } catch (Exception $ex) {
         $proxy = new PhutilProxyException(pht('Error while updating the "%s" repository.', $repository->getMonogram()), $ex);
         phlog($proxy);
         return time() + $min_sleep;
     }
     if (strlen($stderr)) {
         $stderr_msg = pht('Unexpected output while updating repository "%s": %s', $monogram, $stderr);
         phlog($stderr_msg);
     }
     // For now, continue respecting this deprecated setting for raising the
     // minimum pull frequency.
     // TODO: Remove this some day once this code has been completely stable
     // for a while.
     $sleep_for = (int) $repository->getDetail('pull-frequency');
     $min_sleep = max($sleep_for, $min_sleep);
     $smart_wait = $repository->loadUpdateInterval($min_sleep);
     $this->log(pht('Based on activity in repository "%s", considering a wait of %s ' . 'seconds before update.', $repository->getMonogram(), new PhutilNumber($smart_wait)));
     return time() + $smart_wait;
 }
Пример #15
0
 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;
 }
Пример #16
0
 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 buildPatch(PhabricatorMetaMTAMail $template, PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     $attach_key = 'metamta.diffusion.attach-patches';
     $inline_key = 'metamta.diffusion.inline-patches';
     $attach_patches = PhabricatorEnv::getEnvConfig($attach_key);
     $inline_patches = PhabricatorEnv::getEnvConfig($inline_key);
     if (!$attach_patches && !$inline_patches) {
         return;
     }
     $encoding = $repository->getDetail('encoding', 'UTF-8');
     $result = null;
     $patch_error = null;
     try {
         $raw_patch = $this->loadRawPatchText($repository, $commit);
         if ($attach_patches) {
             $commit_name = $repository->formatCommitName($commit->getCommitIdentifier());
             $template->addAttachment(new PhabricatorMetaMTAAttachment($raw_patch, $commit_name . '.patch', 'text/x-patch; charset=' . $encoding));
         }
     } catch (Exception $ex) {
         phlog($ex);
         $patch_error = 'Unable to generate: ' . $ex->getMessage();
     }
     if ($patch_error) {
         $result = $patch_error;
     } else {
         if ($inline_patches) {
             $len = substr_count($raw_patch, "\n");
             if ($len <= $inline_patches) {
                 // We send email as utf8, so we need to convert the text to utf8 if
                 // we can.
                 if ($encoding) {
                     $raw_patch = phutil_utf8_convert($raw_patch, 'UTF-8', $encoding);
                 }
                 $result = phutil_utf8ize($raw_patch);
             }
         }
     }
     if ($result) {
         $result = "PATCH\n\n{$result}\n";
     }
     return $result;
 }
 private function buildActionsProperties(PhabricatorRepository $repository, PhabricatorActionListView $actions)
 {
     $viewer = $this->getRequest()->getUser();
     $view = id(new PHUIPropertyListView())->setUser($viewer)->setActionList($actions);
     $notify = $repository->getDetail('herald-disabled') ? pht('Off') : pht('On');
     $notify = phutil_tag('em', array(), $notify);
     $view->addProperty(pht('Publish/Notify'), $notify);
     $autoclose = $repository->getDetail('disable-autoclose') ? pht('Off') : pht('On');
     $autoclose = phutil_tag('em', array(), $autoclose);
     $view->addProperty(pht('Autoclose'), $autoclose);
     return $view;
 }
    public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
    {
        $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
        if (!$data) {
            // TODO: Permanent failure.
            return;
        }
        $rules = HeraldRule::loadAllByContentTypeWithFullData(HeraldContentTypeConfig::CONTENT_TYPE_COMMIT, $commit->getPHID());
        $adapter = new HeraldCommitAdapter($repository, $commit, $data);
        $engine = new HeraldEngine();
        $effects = $engine->applyRules($rules, $adapter);
        $engine->applyEffects($effects, $adapter, $rules);
        $audit_phids = $adapter->getAuditMap();
        if ($audit_phids) {
            $this->createAudits($commit, $audit_phids, $rules);
        }
        $this->createAuditsFromCommitMessage($commit, $data);
        $email_phids = $adapter->getEmailPHIDs();
        if (!$email_phids) {
            return;
        }
        if ($repository->getDetail('herald-disabled')) {
            // This just means "disable email"; audits are (mostly) idempotent.
            return;
        }
        $xscript = $engine->getTranscript();
        $revision = $adapter->loadDifferentialRevision();
        if ($revision) {
            $name = $revision->getTitle();
        } else {
            $name = $data->getSummary();
        }
        $author_phid = $data->getCommitDetail('authorPHID');
        $reviewer_phid = $data->getCommitDetail('reviewerPHID');
        $phids = array_filter(array($author_phid, $reviewer_phid, $commit->getPHID()));
        $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
        $commit_handle = $handles[$commit->getPHID()];
        $commit_name = $commit_handle->getName();
        if ($author_phid) {
            $author_name = $handles[$author_phid]->getName();
        } else {
            $author_name = $data->getAuthorName();
        }
        if ($reviewer_phid) {
            $reviewer_name = $handles[$reviewer_phid]->getName();
        } else {
            $reviewer_name = null;
        }
        $who = implode(', ', array_filter(array($author_name, $reviewer_name)));
        $description = $data->getCommitMessage();
        $commit_uri = PhabricatorEnv::getProductionURI($commit_handle->getURI());
        $differential = $revision ? PhabricatorEnv::getProductionURI('/D' . $revision->getID()) : 'No revision.';
        $files = $adapter->loadAffectedPaths();
        sort($files);
        $files = implode("\n  ", $files);
        $xscript_id = $xscript->getID();
        $manage_uri = PhabricatorEnv::getProductionURI('/herald/view/commits/');
        $why_uri = PhabricatorEnv::getProductionURI('/herald/transcript/' . $xscript_id . '/');
        $reply_handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit($commit);
        $reply_instructions = $reply_handler->getReplyHandlerInstructions();
        if ($reply_instructions) {
            $reply_instructions = "\n" . "REPLY HANDLER ACTIONS\n" . "  " . $reply_instructions . "\n";
        }
        $body = <<<EOBODY
DESCRIPTION
{$description}

DETAILS
  {$commit_uri}

DIFFERENTIAL REVISION
  {$differential}

AFFECTED FILES
  {$files}
{$reply_instructions}
MANAGE HERALD COMMIT RULES
  {$manage_uri}

WHY DID I GET THIS EMAIL?
  {$why_uri}

EOBODY;
        $prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix');
        $subject = trim("{$prefix} {$commit_name}: {$name}");
        $vary_subject = trim("{$prefix} [Commit] {$commit_name}: {$name}");
        $threading = PhabricatorAuditCommentEditor::getMailThreading($commit->getPHID());
        list($thread_id, $thread_topic) = $threading;
        $template = new PhabricatorMetaMTAMail();
        $template->setRelatedPHID($commit->getPHID());
        $template->setSubject($subject);
        $template->setVarySubject($subject);
        $template->setBody($body);
        $template->setThreadID($thread_id, $is_new = true);
        $template->addHeader('Thread-Topic', $thread_topic);
        $template->setIsBulk(true);
        $template->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
        if ($author_phid) {
            $template->setFrom($author_phid);
        }
        $mails = $reply_handler->multiplexMail($template, id(new PhabricatorObjectHandleData($email_phids))->loadHandles(), array());
        foreach ($mails as $mail) {
            $mail->saveAndSend();
        }
    }