mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Rough cut of repository tracking
Summary: Basic scaffolding for repository tracking, plus daemon infrastructure (Timelines, Cursors) and some fixes (memory usage, mysql_connect() junk). Test Plan: parsed Javelin git commit history via daemon Reviewers: CC:
This commit is contained in:
parent
9f1b50ad2c
commit
57495c4287
38 changed files with 1176 additions and 39 deletions
28
resources/sql/patches/004.daemonrepos.sql
Normal file
28
resources/sql/patches/004.daemonrepos.sql
Normal file
|
@ -0,0 +1,28 @@
|
|||
create table phabricator_repository.repository_commit (
|
||||
id int unsigned not null auto_increment primary key,
|
||||
repositoryPHID varchar(64) binary not null,
|
||||
phid varchar(64) binary not null,
|
||||
commitIdentifier varchar(40) binary not null,
|
||||
epoch int unsigned not null,
|
||||
unique key (phid),
|
||||
unique key (repositoryPHID, commitIdentifier)
|
||||
);
|
||||
|
||||
create database phabricator_timeline;
|
||||
create table phabricator_timeline.timeline_event (
|
||||
id int unsigned not null auto_increment primary key,
|
||||
type char(4) binary not null,
|
||||
key (type, id)
|
||||
);
|
||||
|
||||
create table phabricator_timeline.timeline_eventdata (
|
||||
id int unsigned not null auto_increment primary key,
|
||||
eventID int unsigned not null,
|
||||
eventData longblob not null,
|
||||
unique key (eventID)
|
||||
);
|
||||
|
||||
create table phabricator_timeline.timeline_cursor (
|
||||
name varchar(255) not null primary key,
|
||||
position int unsigned not null
|
||||
);
|
|
@ -171,6 +171,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
|
||||
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
|
||||
'PhabricatorController' => 'applications/base/controller/base',
|
||||
'PhabricatorDaemon' => 'infrastructure/daemon/base',
|
||||
'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
|
||||
'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
|
||||
'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
|
||||
|
@ -251,13 +252,20 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
|
||||
'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
|
||||
'PhabricatorRepository' => 'applications/repository/storage/repository',
|
||||
'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit',
|
||||
'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base',
|
||||
'PhabricatorRepositoryCommitParserDaemon' => 'applications/repository/daemon/commitparser',
|
||||
'PhabricatorRepositoryController' => 'applications/repository/controller/base',
|
||||
'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create',
|
||||
'PhabricatorRepositoryDAO' => 'applications/repository/storage/base',
|
||||
'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base',
|
||||
'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit',
|
||||
'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git',
|
||||
'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification',
|
||||
'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive',
|
||||
'PhabricatorRepositoryGitPullDaemon' => 'applications/repository/daemon/gitpull',
|
||||
'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
|
||||
'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
|
||||
'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument',
|
||||
'PhabricatorSearchBaseController' => 'applications/search/controller/base',
|
||||
'PhabricatorSearchController' => 'applications/search/controller/search',
|
||||
|
@ -274,6 +282,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchQuery' => 'applications/search/storage/query',
|
||||
'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
|
||||
'PhabricatorStandardPageView' => 'view/page/standard',
|
||||
'PhabricatorTimelineCursor' => 'applications/timeline/storage/cursor',
|
||||
'PhabricatorTimelineDAO' => 'applications/timeline/storage/base',
|
||||
'PhabricatorTimelineEvent' => 'applications/timeline/storage/event',
|
||||
'PhabricatorTimelineEventData' => 'applications/timeline/storage/eventdata',
|
||||
'PhabricatorTimelineIterator' => 'applications/timeline/cursor/iterator',
|
||||
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
|
||||
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
|
||||
'PhabricatorUser' => 'applications/people/storage/user',
|
||||
|
@ -430,6 +443,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorConduitLogController' => 'PhabricatorConduitController',
|
||||
'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
|
||||
'PhabricatorController' => 'AphrontController',
|
||||
'PhabricatorDaemon' => 'PhutilDaemon',
|
||||
'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
|
||||
'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
|
||||
'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
|
||||
|
@ -500,12 +514,18 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRemarkupRuleDifferential' => 'PhutilRemarkupRule',
|
||||
'PhabricatorRemarkupRuleManiphest' => 'PhutilRemarkupRule',
|
||||
'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
|
||||
'PhabricatorRepositoryCommitParserDaemon' => 'PhabricatorRepositoryDaemon',
|
||||
'PhabricatorRepositoryController' => 'PhabricatorController',
|
||||
'PhabricatorRepositoryCreateController' => 'PhabricatorController',
|
||||
'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
|
||||
'PhabricatorRepositoryEditController' => 'PhabricatorController',
|
||||
'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
|
||||
'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController',
|
||||
'PhabricatorRepositoryGitPullDaemon' => 'PhabricatorRepositoryDaemon',
|
||||
'PhabricatorRepositoryListController' => 'PhabricatorController',
|
||||
'PhabricatorSearchBaseController' => 'PhabricatorController',
|
||||
'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
|
||||
|
@ -518,6 +538,10 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor',
|
||||
'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
|
||||
'PhabricatorStandardPageView' => 'AphrontPageView',
|
||||
'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
|
||||
'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
|
||||
'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
|
||||
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
|
||||
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
|
||||
'PhabricatorUser' => 'PhabricatorUserDAO',
|
||||
|
|
|
@ -20,28 +20,38 @@ class DarkConsoleErrorLogPluginAPI {
|
|||
|
||||
private static $errors = array();
|
||||
|
||||
private static $discardMode = false;
|
||||
|
||||
public static function enableDiscardMode() {
|
||||
self::$discardMode = true;
|
||||
}
|
||||
|
||||
public static function getErrors() {
|
||||
return self::$errors;
|
||||
}
|
||||
|
||||
public static function handleError($num, $str, $file, $line, $cxt) {
|
||||
self::$errors[] = array(
|
||||
'event' => 'error',
|
||||
'num' => $num,
|
||||
'str' => $str,
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
'cxt' => $cxt,
|
||||
'trace' => debug_backtrace(),
|
||||
);
|
||||
if (!self::$discardMode) {
|
||||
self::$errors[] = array(
|
||||
'event' => 'error',
|
||||
'num' => $num,
|
||||
'str' => $str,
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
'cxt' => $cxt,
|
||||
'trace' => debug_backtrace(),
|
||||
);
|
||||
}
|
||||
error_log("{$file}:{$line} {$str}");
|
||||
}
|
||||
|
||||
public static function handleException($ex) {
|
||||
self::$errors[] = array(
|
||||
'event' => 'exception',
|
||||
'exception' => $ex,
|
||||
);
|
||||
if (!self::$discardMode) {
|
||||
self::$errors[] = array(
|
||||
'event' => 'exception',
|
||||
'exception' => $ex,
|
||||
);
|
||||
}
|
||||
error_log($ex);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,16 @@ class DarkConsoleServicesPluginAPI {
|
|||
|
||||
private static $events = array();
|
||||
|
||||
private static $discardMode = false;
|
||||
|
||||
public static function enableDiscardMode() {
|
||||
self::$discardMode = true;
|
||||
}
|
||||
|
||||
public static function addEvent(array $event) {
|
||||
self::$events[] = $event;
|
||||
if (!self::$discardMode) {
|
||||
self::$events[] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getEvents() {
|
||||
|
|
|
@ -165,7 +165,8 @@ class AphrontDefaultApplicationConfiguration
|
|||
'/repository/' => array(
|
||||
'$' => 'PhabricatorRepositoryListController',
|
||||
'create/$' => 'PhabricatorRepositoryCreateController',
|
||||
'edit/(?P<id>\d+)/$' => 'PhabricatorRepositoryEditController',
|
||||
'edit/(?P<id>\d+)/(?:(?P<view>\w+)?/)?$' =>
|
||||
'PhabricatorRepositoryEditController',
|
||||
'delete/(?P<id>\d+)/$' => 'PhabricatorRepositoryDeleteController',
|
||||
),
|
||||
|
||||
|
|
|
@ -26,5 +26,7 @@ final class PhabricatorPHIDConstants {
|
|||
const PHID_TYPE_PROJ = 'PROJ';
|
||||
const PHID_TYPE_UNKNOWN = '????';
|
||||
const PHID_TYPE_MAGIC = '!!!!';
|
||||
const PHID_TYPE_REPO = 'REPO';
|
||||
const PHID_TYPE_CMIT = 'CMIT';
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
final class PhabricatorRepositoryType {
|
||||
|
||||
const REPOSITORY_TYPE_GIT = 'git';
|
||||
const REPOSITORY_TYPE_SVN = 'svn';
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryType.php');
|
|
@ -30,8 +30,8 @@ class PhabricatorRepositoryCreateController extends PhabricatorController {
|
|||
$repository = new PhabricatorRepository();
|
||||
|
||||
$type_map = array(
|
||||
'svn' => 'Subversion',
|
||||
'git' => 'Git',
|
||||
'svn' => 'Subversion',
|
||||
);
|
||||
$errors = array();
|
||||
|
||||
|
|
|
@ -19,9 +19,13 @@
|
|||
class PhabricatorRepositoryEditController extends PhabricatorController {
|
||||
|
||||
private $id;
|
||||
private $view;
|
||||
private $repository;
|
||||
private $sideNav;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = idx($data, 'id');
|
||||
$this->id = $data['id'];
|
||||
$this->view = idx($data, 'view');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
@ -34,6 +38,11 @@ class PhabricatorRepositoryEditController extends PhabricatorController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$views = array(
|
||||
'basic' => 'Basics',
|
||||
'tracking' => 'Tracking',
|
||||
);
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
if ($vcs == DifferentialRevisionControlSystem::GIT) {
|
||||
if (!$repository->getDetail('github-token')) {
|
||||
|
@ -41,16 +50,60 @@ class PhabricatorRepositoryEditController extends PhabricatorController {
|
|||
$repository->setDetail('github-token', $token);
|
||||
$repository->save();
|
||||
}
|
||||
|
||||
$views['github'] = 'Github';
|
||||
}
|
||||
|
||||
$e_name = true;
|
||||
$this->repository = $repository;
|
||||
|
||||
if (!isset($views[$this->view])) {
|
||||
reset($views);
|
||||
$this->view = key($views);
|
||||
}
|
||||
|
||||
$nav = new AphrontSideNavView();
|
||||
foreach ($views as $view => $name) {
|
||||
$nav->addNavItem(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'class' => ($view == $this->view
|
||||
? 'aphront-side-nav-selected'
|
||||
: null),
|
||||
'href' => '/repository/edit/'.$repository->getID().'/'.$view.'/',
|
||||
),
|
||||
phutil_escape_html($name)));
|
||||
}
|
||||
|
||||
$this->sideNav = $nav;
|
||||
|
||||
switch ($this->view) {
|
||||
case 'basic':
|
||||
return $this->processBasicRequest();
|
||||
case 'tracking':
|
||||
return $this->processTrackingRequest();
|
||||
case 'github':
|
||||
return $this->processGithubRequest();
|
||||
default:
|
||||
throw new Exception("Unknown view.");
|
||||
}
|
||||
}
|
||||
|
||||
protected function processBasicRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$repository = $this->repository;
|
||||
$repository_id = $repository->getID();
|
||||
|
||||
$type_map = array(
|
||||
'svn' => 'Subversion',
|
||||
'git' => 'Git',
|
||||
);
|
||||
|
||||
$errors = array();
|
||||
|
||||
$e_name = true;
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$repository->setName($request->getStr('name'));
|
||||
|
||||
|
@ -64,9 +117,8 @@ class PhabricatorRepositoryEditController extends PhabricatorController {
|
|||
if (!$errors) {
|
||||
$repository->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/repository/');
|
||||
->setURI('/repository/edit/'.$repository_id.'/basic/?saved=true');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$error_view = null;
|
||||
|
@ -74,9 +126,14 @@ class PhabricatorRepositoryEditController extends PhabricatorController {
|
|||
$error_view = new AphrontErrorView();
|
||||
$error_view->setErrors($errors);
|
||||
$error_view->setTitle('Form Errors');
|
||||
} else if ($request->getStr('saved')) {
|
||||
$error_view = new AphrontErrorView();
|
||||
$error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||
$error_view->setTitle('Changes Saved');
|
||||
$error_view->appendChild(
|
||||
'Repository changes were saved.');
|
||||
}
|
||||
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form
|
||||
->setUser($user)
|
||||
|
@ -97,29 +154,187 @@ class PhabricatorRepositoryEditController extends PhabricatorController {
|
|||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Type')
|
||||
->setName('type')
|
||||
->setValue($repository->getVersionControlSystem()));
|
||||
|
||||
|
||||
$form
|
||||
->setValue($repository->getVersionControlSystem()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('PHID')
|
||||
->setName('phid')
|
||||
->setValue($repository->getPHID()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Save')
|
||||
->addCancelButton('/repository/'));
|
||||
->setValue('Save'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Edit Repository');
|
||||
$panel->appendChild($form);
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
|
||||
$phid = $repository->getID();
|
||||
|
||||
$nav = $this->sideNav;
|
||||
|
||||
$nav->appendChild($error_view);
|
||||
$nav->appendChild($panel);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Edit Repository',
|
||||
));
|
||||
}
|
||||
|
||||
private function processTrackingRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$repository = $this->repository;
|
||||
$repository_id = $repository->getID();
|
||||
|
||||
$errors = array();
|
||||
|
||||
$e_uri = null;
|
||||
$e_path = null;
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$tracking = ($request->getStr('tracking') == 'enabled' ? true : false);
|
||||
$repository->setDetail('tracking-enabled', $tracking);
|
||||
$repository->setDetail('remote-uri', $request->getStr('uri'));
|
||||
$repository->setDetail('local-path', $request->getStr('path'));
|
||||
$repository->setDetail(
|
||||
'pull-frequency',
|
||||
max(1, $request->getInt('frequency')));
|
||||
|
||||
if ($tracking) {
|
||||
if (!$repository->getDetail('remote-uri')) {
|
||||
$e_uri = 'Required';
|
||||
$errors[] = "Repository URI is required.";
|
||||
}
|
||||
if (!$repository->getDetail('local-path')) {
|
||||
$e_path = 'Required';
|
||||
$errors[] = "Local path is required.";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$repository->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/repository/edit/'.$repository_id.'/tracking/?saved=true');
|
||||
}
|
||||
}
|
||||
|
||||
$error_view = null;
|
||||
if ($errors) {
|
||||
$error_view = new AphrontErrorView();
|
||||
$error_view->setErrors($errors);
|
||||
$error_view->setTitle('Form Errors');
|
||||
} else if ($request->getStr('saved')) {
|
||||
$error_view = new AphrontErrorView();
|
||||
$error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||
$error_view->setTitle('Changes Saved');
|
||||
$error_view->appendChild(
|
||||
'Tracking changes were saved. You may need to restart the daemon '.
|
||||
'before changes will take effect.');
|
||||
}
|
||||
|
||||
$uri_caption = null;
|
||||
$path_caption = null;
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case 'git':
|
||||
$uri_caption =
|
||||
'The user the tracking daemon runs as must have permission to '.
|
||||
'<tt>git clone</tt> from this URI.';
|
||||
$path_caption =
|
||||
'Directory where the daemon should look to find a copy of the '.
|
||||
'repository (or create one if it does not yet exist). The daemon '.
|
||||
'will regularly pull remote changes into this working copy.';
|
||||
break;
|
||||
case 'svn':
|
||||
$uri_caption =
|
||||
'The user the tracking daemon runs as must have permission to '.
|
||||
'<tt>svn log</tt> from this URI.';
|
||||
break;
|
||||
}
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form
|
||||
->setUser($user)
|
||||
->setAction('/repository/edit/'.$repository->getID().'/tracking/')
|
||||
->appendChild(
|
||||
'<p class="aphront-form-instructions">Phabricator can track '.
|
||||
'repositories, importing commits as they happen and notifying '.
|
||||
'Differential, Diffusion, Herald, and other services. To enable '.
|
||||
'tracking for a repository, configure it here and then start (or '.
|
||||
'restart) the PhabricatorRepositoryTrackingDaemon.</p>')
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Repository')
|
||||
->setValue($repository->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('tracking')
|
||||
->setLabel('Tracking')
|
||||
->setOptions(array(
|
||||
'disabled' => 'Disabled',
|
||||
'enabled' => 'Enabled',
|
||||
))
|
||||
->setValue(
|
||||
$repository->getDetail('tracking-enabled')
|
||||
? 'enabled'
|
||||
: 'disabled'))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('uri')
|
||||
->setLabel('URI')
|
||||
->setValue($repository->getDetail('remote-uri'))
|
||||
->setError($e_uri)
|
||||
->setCaption($uri_caption))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('path')
|
||||
->setLabel('Local Path')
|
||||
->setValue($repository->getDetail('local-path'))
|
||||
->setError($e_path)
|
||||
->setCaption($path_caption))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('frequency')
|
||||
->setLabel('Pull Frequency')
|
||||
->setValue($repository->getDetail('pull-frequency', 15))
|
||||
->setCaption(
|
||||
'Number of seconds daemon should sleep between requests. Larger '.
|
||||
'numbers reduce load but also decrease responsiveness.'))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Save'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Repository Tracking');
|
||||
$panel->appendChild($form);
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
|
||||
$nav = $this->sideNav;
|
||||
$nav->appendChild($error_view);
|
||||
$nav->appendChild($panel);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Edit Repository Tracking',
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
private function processGithubRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$repository = $this->repository;
|
||||
$repository_id = $repository->getID();
|
||||
|
||||
$token = $repository->getDetail('github-token');
|
||||
$path = '/github-post-receive/'.$phid.'/'.$token.'/';
|
||||
$path = '/github-post-receive/'.$repository_id.'/'.$token.'/';
|
||||
$post_uri = PhabricatorEnv::getURI($path);
|
||||
|
||||
$gitform = new AphrontFormView();
|
||||
$gitform
|
||||
->setUser($user)
|
||||
->setAction('/repository/edit/'.$repository->getID().'/')
|
||||
->appendChild(
|
||||
'<p class="aphront-form-instructions">You can configure GitHub to '.
|
||||
'notify Phabricator after changes are pushed. Log into GitHub, go '.
|
||||
|
@ -178,15 +393,13 @@ class PhabricatorRepositoryEditController extends PhabricatorController {
|
|||
$github->appendChild($gitform);
|
||||
$github->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
|
||||
$nav = $this->sideNav;
|
||||
$nav->appendChild($github);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
$error_view,
|
||||
$panel,
|
||||
$github,
|
||||
),
|
||||
array(
|
||||
'title' => 'Edit Repository',
|
||||
'title' => 'Repository Github Integration',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ phutil_require_module('phabricator', 'applications/repository/storage/repository
|
|||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/static');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/error');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenav');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'filesystem');
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorRepositoryDaemon extends PhabricatorDaemon {
|
||||
|
||||
protected function loadRepository() {
|
||||
$argv = $this->getArgv();
|
||||
if (count($argv) !== 1) {
|
||||
throw new Exception("No repository PHID provided!");
|
||||
}
|
||||
|
||||
$repository = id(new PhabricatorRepository())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$argv[0]);
|
||||
|
||||
if (!$repository) {
|
||||
throw new Exception("No such repository exists!");
|
||||
}
|
||||
|
||||
return $repository;
|
||||
}
|
||||
|
||||
}
|
15
src/applications/repository/daemon/base/__init__.php
Normal file
15
src/applications/repository/daemon/base/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
||||
phutil_require_module('phabricator', 'infrastructure/daemon/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryDaemon.php');
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorRepositoryCommitDiscoveryDaemon
|
||||
extends PhabricatorRepositoryDaemon {
|
||||
|
||||
private $repository;
|
||||
|
||||
final protected function getRepository() {
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
final public function run() {
|
||||
$this->repository = $this->loadRepository();
|
||||
|
||||
$sleep = 15;
|
||||
while (true) {
|
||||
$found = $this->discoverCommits();
|
||||
if ($found) {
|
||||
$sleep = 15;
|
||||
} else {
|
||||
$sleep = min($sleep + 15, 60 * 15);
|
||||
}
|
||||
$this->sleep($sleep);
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function discoverCommits();
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/repository/daemon/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryCommitDiscoveryDaemon.php');
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorRepositoryGitCommitDiscoveryDaemon
|
||||
extends PhabricatorRepositoryCommitDiscoveryDaemon {
|
||||
|
||||
private $lastCommit;
|
||||
private $commitCache = array();
|
||||
|
||||
protected function discoverCommits() {
|
||||
// NOTE: PhabricatorRepositoryGitPullDaemon does the actual pulls, this
|
||||
// just parses HEAD.
|
||||
|
||||
$repository = $this->getRepository();
|
||||
|
||||
// TODO: this should be a constant somewhere
|
||||
if ($repository->getVersionControlSystem() != 'git') {
|
||||
throw new Exception("Repository is not a git repository.");
|
||||
}
|
||||
|
||||
$repository_phid = $repository->getPHID();
|
||||
|
||||
$repo_base = $repository->getDetail('local-path');
|
||||
list($commit) = execx(
|
||||
'(cd %s && git log -n1 --pretty="%%H")',
|
||||
$repo_base);
|
||||
$commit = trim($commit);
|
||||
|
||||
if ($commit === $this->lastCommit ||
|
||||
$this->isKnownCommit($commit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->lastCommit = $commit;
|
||||
$this->discoverCommit($commit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function discoverCommit($commit) {
|
||||
$discover = array();
|
||||
$insert = array();
|
||||
|
||||
$repository = $this->getRepository();
|
||||
$repo_base = $repository->getDetail('local-path');
|
||||
|
||||
$discover[] = $commit;
|
||||
$insert[] = $commit;
|
||||
|
||||
while (true) {
|
||||
$target = array_pop($discover);
|
||||
list($parents) = execx(
|
||||
'(cd %s && git log -n1 --pretty="%%P" %s)',
|
||||
$repo_base,
|
||||
$target);
|
||||
$parents = array_filter(explode(' ', trim($parents)));
|
||||
foreach ($parents as $parent) {
|
||||
if (!$this->isKnownCommit($parent)) {
|
||||
echo "{$target} has parent {$parent}\n";
|
||||
$discover[] = $parent;
|
||||
$insert[] = $parent;
|
||||
}
|
||||
}
|
||||
if (empty($discover)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
$target = array_pop($insert);
|
||||
list($epoch) = execx(
|
||||
'(cd %s && git log -n1 --pretty="%%at" %s)',
|
||||
$repo_base,
|
||||
$target);
|
||||
$epoch = trim($epoch);
|
||||
|
||||
$commit = new PhabricatorRepositoryCommit();
|
||||
$commit->setRepositoryPHID($this->getRepository()->getPHID());
|
||||
$commit->setCommitIdentifier($target);
|
||||
$commit->setEpoch($epoch);
|
||||
try {
|
||||
$commit->save();
|
||||
$event = new PhabricatorTimelineEvent(
|
||||
'cmit',
|
||||
array(
|
||||
'id' => $commit->getID(),
|
||||
));
|
||||
$event->recordEvent();
|
||||
} catch (AphrontQueryDuplicateKeyException $ex) {
|
||||
// Ignore. This can happen because we discover the same new commit
|
||||
// more than once when looking at history, or because of races or
|
||||
// data inconsistency or cosmic radiation; in any case, we're still
|
||||
// in a good state if we ignore the failure.
|
||||
}
|
||||
if (empty($insert)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function isKnownCommit($target) {
|
||||
if (isset($this->commitCache[$target])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$commit = id(new PhabricatorRepositoryCommit())->loadOneWhere(
|
||||
'repositoryPHID = %s AND commitIdentifier = %s',
|
||||
$this->getRepository()->getPHID(),
|
||||
$target);
|
||||
|
||||
if (!$commit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->commitCache[$target] = true;
|
||||
if (count($this->commitCache) > 16) {
|
||||
array_shift($this->commitCache);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/repository/daemon/commitdiscovery/base');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/event');
|
||||
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryGitCommitDiscoveryDaemon.php');
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorRepositoryCommitParserDaemon
|
||||
extends PhabricatorRepositoryDaemon {
|
||||
|
||||
}
|
12
src/applications/repository/daemon/commitparser/__init__.php
Normal file
12
src/applications/repository/daemon/commitparser/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/repository/daemon/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryCommitParserDaemon.php');
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorRepositoryGitPullDaemon
|
||||
extends PhabricatorRepositoryDaemon {
|
||||
|
||||
public function run() {
|
||||
$repository = $this->loadRepository();
|
||||
|
||||
if ($repository->getVersionControlSystem() != 'git') {
|
||||
throw new Exception("Not a git repository!");
|
||||
}
|
||||
|
||||
$tracked = $repository->getDetail('tracking-enabled');
|
||||
if (!$tracked) {
|
||||
throw new Exception("Tracking is not enabled for this repository.");
|
||||
}
|
||||
|
||||
$local_path = $repository->getDetail('local-path');
|
||||
$remote_uri = $repository->getDetail('remote-uri');
|
||||
|
||||
if (!$local_path) {
|
||||
throw new Exception("No local path is available for this repository.");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (!Filesystem::pathExists($local_path)) {
|
||||
if (!$remote_uri) {
|
||||
throw new Exception("No remote URI is available.");
|
||||
}
|
||||
execx('mkdir -p %s', dirname($local_path));
|
||||
execx('git clone %s %s', $remote_uri, rtrim($local_path, '/'));
|
||||
} else {
|
||||
execx('(cd %s && git pull)', $local_path);
|
||||
}
|
||||
$this->sleep($repository->getDetail('pull-frequency', 15));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
15
src/applications/repository/daemon/gitpull/__init__.php
Normal file
15
src/applications/repository/daemon/gitpull/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/repository/daemon/base');
|
||||
|
||||
phutil_require_module('phutil', 'filesystem');
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryGitPullDaemon.php');
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorRepositoryCommit extends PhabricatorRepositoryDAO {
|
||||
|
||||
protected $repositoryPHID;
|
||||
protected $phid;
|
||||
protected $commitIdentifier;
|
||||
protected $epoch;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_CMIT);
|
||||
}
|
||||
|
||||
}
|
14
src/applications/repository/storage/commit/__init__.php
Normal file
14
src/applications/repository/storage/commit/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepositoryCommit.php');
|
|
@ -35,7 +35,8 @@ class PhabricatorRepository extends PhabricatorRepositoryDAO {
|
|||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID('REPO');
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_REPO);
|
||||
}
|
||||
|
||||
public function getDetail($key, $default = null) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/base');
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorTimelineIterator implements Iterator {
|
||||
|
||||
protected $cursorName;
|
||||
protected $eventTypes;
|
||||
|
||||
protected $cursor;
|
||||
|
||||
protected $index = -1;
|
||||
protected $events = array();
|
||||
|
||||
const LOAD_CHUNK_SIZE = 128;
|
||||
|
||||
public function __construct($cursor_name, array $event_types) {
|
||||
$this->cursorName = $cursor_name;
|
||||
$this->eventTypes = $event_types;
|
||||
}
|
||||
|
||||
protected function loadEvents() {
|
||||
if (!$this->cursor) {
|
||||
$this->cursor = id(new PhabricatorTimelineCursor())->loadOneWhere(
|
||||
'name = %s',
|
||||
$this->cursorName);
|
||||
if (!$this->cursor) {
|
||||
$cursor = new PhabricatorTimelineCursor();
|
||||
$cursor->setName($this->cursorName);
|
||||
$cursor->setPosition(0);
|
||||
$cursor->save();
|
||||
|
||||
$this->cursor = $cursor;
|
||||
}
|
||||
}
|
||||
|
||||
$event = new PhabricatorTimelineEvent();
|
||||
$event_data = new PhabricatorTimelineEventData();
|
||||
$raw_data = queryfx_all(
|
||||
$event->establishConnection('r'),
|
||||
'SELECT event.*, event_data.eventData eventData
|
||||
FROM %T event WHERE event.id > %d AND event.type in (%Ls)
|
||||
LEFT JOIN %T event_data ON event_data.eventID = event.id
|
||||
ORDER BY event.id ASC LIMIT %d',
|
||||
$event->getTableName(),
|
||||
$this->cursor->getPosition(),
|
||||
$this->eventTypes,
|
||||
$event_data->getTableName(),
|
||||
self::LOAD_CHUNK_SIZE);
|
||||
|
||||
$events = $event->loadAllFromArray($raw_data);
|
||||
$events = mpull($events, null, 'getID');
|
||||
$raw_data = ipull($raw_data, 'eventData', 'id');
|
||||
foreach ($raw_data as $id => $data) {
|
||||
if ($data) {
|
||||
$decoded = json_decode($data, true);
|
||||
$events[$id]->setData($decoded);
|
||||
}
|
||||
}
|
||||
|
||||
$this->events = $events;
|
||||
|
||||
if ($this->events) {
|
||||
$this->events = array_values($this->events);
|
||||
$this->index = 0;
|
||||
} else {
|
||||
$this->cursor = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function current() {
|
||||
return $this->events[$this->index];
|
||||
}
|
||||
|
||||
public function key() {
|
||||
return $this->events[$this->index]->getID();
|
||||
}
|
||||
|
||||
public function next() {
|
||||
if ($this->valid()) {
|
||||
$this->cursor->setPosition($this->key());
|
||||
$this->cursor->save();
|
||||
}
|
||||
|
||||
$this->index++;
|
||||
if (!$this->valid()) {
|
||||
$this->loadEvents();
|
||||
}
|
||||
}
|
||||
|
||||
public function valid() {
|
||||
return isset($this->events[$this->index]);
|
||||
}
|
||||
|
||||
public function rewind() {
|
||||
if (!$this->valid()) {
|
||||
$this->loadEvents();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
src/applications/timeline/cursor/iterator/__init__.php
Normal file
17
src/applications/timeline/cursor/iterator/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/cursor');
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/event');
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/eventdata');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorTimelineIterator.php');
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorTimelineDAO extends PhabricatorLiskDAO {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'timeline';
|
||||
}
|
||||
|
||||
}
|
12
src/applications/timeline/storage/base/__init__.php
Normal file
12
src/applications/timeline/storage/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/base/storage/lisk');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorTimelineDAO.php');
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorTimelineCursor extends PhabricatorTimelineDAO {
|
||||
|
||||
protected $name;
|
||||
protected $position;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_IDS => self::IDS_MANUAL,
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
}
|
12
src/applications/timeline/storage/cursor/__init__.php
Normal file
12
src/applications/timeline/storage/cursor/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorTimelineCursor.php');
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorTimelineEvent extends PhabricatorTimelineDAO {
|
||||
|
||||
protected $type;
|
||||
private $data;
|
||||
|
||||
public function __construct($type, $data = null) {
|
||||
parent::__construct();
|
||||
|
||||
if (strlen($type) !== 4) {
|
||||
throw new Exception("Event types must be exactly 4 characters long.");
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function recordEvent() {
|
||||
if ($this->getID()) {
|
||||
throw new Exception("Event has already been recorded!");
|
||||
}
|
||||
|
||||
$this->save();
|
||||
|
||||
if ($this->data !== null) {
|
||||
$data = new PhabricatorTimelineEventData();
|
||||
$data->setEventID($this->getID());
|
||||
$data->setEventData($this->data);
|
||||
$data->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function setData($data) {
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getData() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
}
|
13
src/applications/timeline/storage/event/__init__.php
Normal file
13
src/applications/timeline/storage/event/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/base');
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/eventdata');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorTimelineEvent.php');
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class PhabricatorTimelineEventData extends PhabricatorTimelineDAO {
|
||||
|
||||
protected $eventID;
|
||||
protected $eventData;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'eventData' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
}
|
12
src/applications/timeline/storage/eventdata/__init__.php
Normal file
12
src/applications/timeline/storage/eventdata/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/timeline/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorTimelineEventData.php');
|
33
src/infrastructure/daemon/base/PhabricatorDaemon.php
Normal file
33
src/infrastructure/daemon/base/PhabricatorDaemon.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorDaemon extends PhutilDaemon {
|
||||
|
||||
protected function willRun() {
|
||||
parent::willRun();
|
||||
|
||||
// Both of these store unbounded amounts of log data; make them discard it
|
||||
// instead so that daemons do not require unbounded amounts of memory.
|
||||
DarkConsoleServicesPluginAPI::enableDiscardMode();
|
||||
DarkConsoleErrorLogPluginAPI::enableDiscardMode();
|
||||
|
||||
$phabricator = phutil_get_library_root('phabricator');
|
||||
$root = dirname($phabricator);
|
||||
require_once $root.'/scripts/__init_env__.php';
|
||||
}
|
||||
}
|
16
src/infrastructure/daemon/base/__init__.php
Normal file
16
src/infrastructure/daemon/base/__init__.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
|
||||
phutil_require_module('phabricator', 'aphront/console/plugin/services/api');
|
||||
|
||||
phutil_require_module('phutil', 'daemon/base');
|
||||
phutil_require_module('phutil', 'moduleutils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorDaemon.php');
|
|
@ -119,6 +119,16 @@ class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
|
|||
|
||||
$start = microtime(true);
|
||||
|
||||
if (!function_exists('mysql_connect')) {
|
||||
// We have to '@' the actual call since it can spew all sorts of silly
|
||||
// noise, but it will also silence fatals caused by not having MySQL
|
||||
// installed, which has bitten me on three separate occasions. Make sure
|
||||
// such failures are explicit and loud.
|
||||
throw new Exception(
|
||||
"About to call mysql_connect(), but the PHP MySQL extension is not ".
|
||||
"available!");
|
||||
}
|
||||
|
||||
$conn = @mysql_connect(
|
||||
$host,
|
||||
$user,
|
||||
|
|
Loading…
Reference in a new issue