Page MenuHomePhabricator

D10496.diff
No OneTemporary

D10496.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1360,9 +1360,11 @@
'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php',
'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php',
'PhabricatorConfigSchemaQuery' => 'applications/config/schema/PhabricatorConfigSchemaQuery.php',
+ 'PhabricatorConfigSchemaSpec' => 'applications/config/schema/PhabricatorConfigSchemaSpec.php',
'PhabricatorConfigServerSchema' => 'applications/config/schema/PhabricatorConfigServerSchema.php',
'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php',
'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php',
+ 'PhabricatorConfigStorageSchema' => 'applications/config/schema/PhabricatorConfigStorageSchema.php',
'PhabricatorConfigTableSchema' => 'applications/config/schema/PhabricatorConfigTableSchema.php',
'PhabricatorConfigTransaction' => 'applications/config/storage/PhabricatorConfigTransaction.php',
'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php',
@@ -4216,11 +4218,11 @@
'PhabricatorConduitTokenController' => 'PhabricatorConduitController',
'PhabricatorConfigAllController' => 'PhabricatorConfigController',
'PhabricatorConfigApplication' => 'PhabricatorApplication',
- 'PhabricatorConfigColumnSchema' => 'Phobject',
+ 'PhabricatorConfigColumnSchema' => 'PhabricatorConfigStorageSchema',
'PhabricatorConfigConfigPHIDType' => 'PhabricatorPHIDType',
'PhabricatorConfigController' => 'PhabricatorController',
'PhabricatorConfigDatabaseController' => 'PhabricatorConfigController',
- 'PhabricatorConfigDatabaseSchema' => 'Phobject',
+ 'PhabricatorConfigDatabaseSchema' => 'PhabricatorConfigStorageSchema',
'PhabricatorConfigDatabaseSource' => 'PhabricatorConfigProxySource',
'PhabricatorConfigDefaultSource' => 'PhabricatorConfigProxySource',
'PhabricatorConfigDictionarySource' => 'PhabricatorConfigSource',
@@ -4252,9 +4254,11 @@
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
'PhabricatorConfigResponse' => 'AphrontHTMLResponse',
'PhabricatorConfigSchemaQuery' => 'Phobject',
- 'PhabricatorConfigServerSchema' => 'Phobject',
+ 'PhabricatorConfigSchemaSpec' => 'Phobject',
+ 'PhabricatorConfigServerSchema' => 'PhabricatorConfigStorageSchema',
'PhabricatorConfigStackSource' => 'PhabricatorConfigSource',
- 'PhabricatorConfigTableSchema' => 'Phobject',
+ 'PhabricatorConfigStorageSchema' => 'Phobject',
+ 'PhabricatorConfigTableSchema' => 'PhabricatorConfigStorageSchema',
'PhabricatorConfigTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorConfigValidationException' => 'Exception',
diff --git a/src/applications/config/application/PhabricatorConfigApplication.php b/src/applications/config/application/PhabricatorConfigApplication.php
--- a/src/applications/config/application/PhabricatorConfigApplication.php
+++ b/src/applications/config/application/PhabricatorConfigApplication.php
@@ -42,7 +42,10 @@
'edit/(?P<key>[\w\.\-]+)/' => 'PhabricatorConfigEditController',
'group/(?P<key>[^/]+)/' => 'PhabricatorConfigGroupController',
'welcome/' => 'PhabricatorConfigWelcomeController',
- 'database/(?:(?P<database>[^/]+)/(?:(?P<table>[^/]+)/)?)?'
+ 'database/'.
+ '(?:(?P<database>[^/]+)/'.
+ '(?:(?P<table>[^/]+)/'.
+ '(?:(?P<column>[^/]+)/)?)?)?'
=> 'PhabricatorConfigDatabaseController',
'(?P<verb>ignore|unignore)/(?P<key>[^/]+)/'
=> 'PhabricatorConfigIgnoreController',
diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseController.php b/src/applications/config/controller/PhabricatorConfigDatabaseController.php
--- a/src/applications/config/controller/PhabricatorConfigDatabaseController.php
+++ b/src/applications/config/controller/PhabricatorConfigDatabaseController.php
@@ -5,10 +5,12 @@
private $database;
private $table;
+ private $column;
public function willProcessRequest(array $data) {
$this->database = idx($data, 'database');
$this->table = idx($data, 'table');
+ $this->column = idx($data, 'column');
}
public function processRequest() {
@@ -31,22 +33,34 @@
$actual = $query->loadActualSchema();
$expect = $query->loadExpectedSchema();
+ $comp = $query->buildComparisonSchema($expect, $actual);
- if ($this->table) {
- return $this->renderTable(
+ if ($this->column) {
+ return $this->renderColumn(
+ $comp,
+ $expect,
$actual,
+ $this->database,
+ $this->table,
+ $this->column);
+ } else if ($this->table) {
+ return $this->renderTable(
+ $comp,
$expect,
+ $actual,
$this->database,
$this->table);
} else if ($this->database) {
return $this->renderDatabase(
- $actual,
+ $comp,
$expect,
+ $actual,
$this->database);
} else {
return $this->renderServer(
- $actual,
- $expect);
+ $comp,
+ $expect,
+ $actual);
}
}
@@ -83,41 +97,29 @@
private function renderServer(
- PhabricatorConfigServerSchema $schema,
- PhabricatorConfigServerSchema $expect) {
-
- $icon_ok = id(new PHUIIconView())
- ->setIconFont('fa-check-circle green');
+ PhabricatorConfigServerSchema $comp,
+ PhabricatorConfigServerSchema $expect,
+ PhabricatorConfigServerSchema $actual) {
- $icon_warn = id(new PHUIIconView())
- ->setIconFont('fa-exclamation-circle yellow');
+ $charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET;
+ $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION;
$rows = array();
- foreach ($schema->getDatabases() as $database_name => $database) {
-
- $expect_database = $expect->getDatabase($database_name);
- if ($expect_database) {
- $expect_set = $expect_database->getCharacterSet();
- $expect_collation = $expect_database->getCollation();
-
- if ($database->isSameSchema($expect_database)) {
- $icon = $icon_ok;
- } else {
- $icon = $icon_warn;
- }
+ foreach ($comp->getDatabases() as $database_name => $database) {
+ $actual_database = $actual->getDatabase($database_name);
+ if ($actual_database) {
+ $charset = $actual_database->getCharacterSet();
+ $collation = $actual_database->getCollation();
} else {
- $expect_set = null;
- $expect_collation = null;
- $icon = $icon_warn;
+ $charset = null;
+ $collation = null;
}
- $actual_set = $database->getCharacterSet();
- $actual_collation = $database->getCollation();
-
-
+ $status = $database->getStatus();
+ $issues = $database->getIssues();
$rows[] = array(
- $icon,
+ $this->renderIcon($status),
phutil_tag(
'a',
array(
@@ -125,10 +127,8 @@
'/database/'.$database_name.'/'),
),
$database_name),
- $actual_set,
- $expect_set,
- $actual_collation,
- $expect_collation,
+ $this->renderAttr($charset, $database->hasIssue($charset_issue)),
+ $this->renderAttr($collation, $database->hasIssue($collation_issue)),
);
}
@@ -138,13 +138,11 @@
null,
pht('Database'),
pht('Charset'),
- pht('Expected Charset'),
pht('Collation'),
- pht('Expected Collation'),
))
->setColumnClasses(
array(
- '',
+ null,
'wide pri',
null,
null,
@@ -152,26 +150,38 @@
$title = pht('Database Status');
+ $properties = $this->buildProperties(
+ array(
+ ),
+ $comp->getIssues());
+
$box = id(new PHUIObjectBoxView())
->setHeaderText($title)
+ ->addPropertyList($properties)
->appendChild($table);
return $this->buildResponse($title, $box);
}
private function renderDatabase(
- PhabricatorConfigServerSchema $schema,
+ PhabricatorConfigServerSchema $comp,
PhabricatorConfigServerSchema $expect,
+ PhabricatorConfigServerSchema $actual,
$database_name) {
- $database = $schema->getDatabase($database_name);
+ $database = $comp->getDatabase($database_name);
if (!$database) {
return new Aphront404Response();
}
$rows = array();
foreach ($database->getTables() as $table_name => $table) {
+
+ $status = $table->getStatus();
+ $issues = $table->getIssues();
+
$rows[] = array(
+ $this->renderIcon($status),
phutil_tag(
'a',
array(
@@ -186,31 +196,74 @@
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
+ null,
pht('Table'),
pht('Collation'),
))
->setColumnClasses(
array(
+ null,
'wide pri',
null,
));
$title = pht('Database Status: %s', $database_name);
+ $actual_database = $actual->getDatabase($database_name);
+ if ($actual_database) {
+ $actual_charset = $actual_database->getCharacterSet();
+ $actual_collation = $actual_database->getCollation();
+ } else {
+ $actual_charset = null;
+ $actual_collation = null;
+ }
+
+ $expect_database = $expect->getDatabase($database_name);
+ if ($expect_database) {
+ $expect_charset = $expect_database->getCharacterSet();
+ $expect_collation = $expect_database->getCollation();
+ } else {
+ $expect_charset = null;
+ $expect_collation = null;
+ }
+
+ $properties = $this->buildProperties(
+ array(
+ array(
+ pht('Character Set'),
+ $actual_charset,
+ ),
+ array(
+ pht('Expected Character Set'),
+ $expect_charset,
+ ),
+ array(
+ pht('Collation'),
+ $actual_collation,
+ ),
+ array(
+ pht('Expected Collation'),
+ $expect_collation,
+ ),
+ ),
+ $database->getIssues());
+
$box = id(new PHUIObjectBoxView())
->setHeaderText($title)
+ ->addPropertyList($properties)
->appendChild($table);
return $this->buildResponse($title, $box);
}
private function renderTable(
- PhabricatorConfigServerSchema $schema,
+ PhabricatorConfigServerSchema $comp,
PhabricatorConfigServerSchema $expect,
+ PhabricatorConfigServerSchema $actual,
$database_name,
$table_name) {
- $database = $schema->getDatabase($database_name);
+ $database = $comp->getDatabase($database_name);
if (!$database) {
return new Aphront404Response();
}
@@ -222,17 +275,30 @@
$rows = array();
foreach ($table->getColumns() as $column_name => $column) {
+ $status = $column->getStatus();
+
$rows[] = array(
- $column_name,
+ $this->renderIcon($status),
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => $this->getApplicationURI(
+ 'database/'.
+ $database_name.'/'.
+ $table_name.'/'.
+ $column_name.'/'),
+ ),
+ $column_name),
$column->getColumnType(),
$column->getCharacterSet(),
$column->getCollation(),
);
}
- $table = id(new AphrontTableView($rows))
+ $table_view = id(new AphrontTableView($rows))
->setHeaders(
array(
+ null,
pht('Table'),
pht('Column Type'),
pht('Character Set'),
@@ -240,6 +306,7 @@
))
->setColumnClasses(
array(
+ null,
'wide pri',
null,
null,
@@ -248,11 +315,133 @@
$title = pht('Database Status: %s.%s', $database_name, $table_name);
+ $properties = $this->buildProperties(
+ array(
+ ),
+ $table->getIssues());
+
$box = id(new PHUIObjectBoxView())
->setHeaderText($title)
- ->appendChild($table);
+ ->addPropertyList($properties)
+ ->appendChild($table_view);
+
+ return $this->buildResponse($title, $box);
+ }
+
+ private function renderColumn(
+ PhabricatorConfigServerSchema $comp,
+ PhabricatorConfigServerSchema $expect,
+ PhabricatorConfigServerSchema $actual,
+ $database_name,
+ $table_name,
+ $column_name) {
+
+ $database = $comp->getDatabase($database_name);
+ if (!$database) {
+ return new Aphront404Response();
+ }
+
+ $table = $database->getTable($table_name);
+ if (!$table) {
+ return new Aphront404Response();
+ }
+
+ $column = $table->getColumn($column_name);
+ if (!$table) {
+ return new Aphront404Response();
+ }
+
+ $title = pht(
+ 'Database Status: %s.%s.%s',
+ $database_name,
+ $table_name,
+ $column_name);
+
+ $properties = $this->buildProperties(
+ array(
+ ),
+ $column->getIssues());
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->addPropertyList($properties);
return $this->buildResponse($title, $box);
}
+ private function renderIcon($status) {
+ switch ($status) {
+ case PhabricatorConfigStorageSchema::STATUS_OKAY:
+ $icon = 'fa-check-circle green';
+ break;
+ case PhabricatorConfigStorageSchema::STATUS_WARN:
+ $icon = 'fa-exclamation-circle yellow';
+ break;
+ case PhabricatorConfigStorageSchema::STATUS_FAIL:
+ default:
+ $icon = 'fa-times-circle red';
+ break;
+ }
+
+ return id(new PHUIIconView())
+ ->setIconFont($icon);
+ }
+
+ private function renderAttr($attr, $issue) {
+ if ($issue) {
+ return phutil_tag(
+ 'span',
+ array(
+ 'style' => 'color: #aa0000;',
+ ),
+ $attr);
+ } else {
+ return $attr;
+ }
+ }
+
+ private function buildProperties(array $properties, array $issues) {
+ $view = id(new PHUIPropertyListView())
+ ->setUser($this->getRequest()->getUser());
+
+ foreach ($properties as $property) {
+ list($key, $value) = $property;
+ $view->addProperty($key, $value);
+ }
+
+ $status_view = new PHUIStatusListView();
+ if (!$issues) {
+ $status_view->addItem(
+ id(new PHUIStatusItemView())
+ ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
+ ->setTarget(pht('No Schema Issues')));
+ } else {
+ foreach ($issues as $issue) {
+ $note = PhabricatorConfigStorageSchema::getIssueDescription($issue);
+
+ $status = PhabricatorConfigStorageSchema::getIssueStatus($issue);
+ switch ($status) {
+ case PhabricatorConfigStorageSchema::STATUS_WARN:
+ $icon = PHUIStatusItemView::ICON_WARNING;
+ $color = 'yellow';
+ break;
+ case PhabricatorConfigStorageSchema::STATUS_FAIL:
+ default:
+ $icon = PHUIStatusItemView::ICON_REJECT;
+ $color = 'red';
+ break;
+ }
+
+ $item = id(new PHUIStatusItemView())
+ ->setTarget(PhabricatorConfigStorageSchema::getIssueName($issue))
+ ->setIcon($icon, $color)
+ ->setNote($note);
+
+ $status_view->addItem($item);
+ }
+ }
+ $view->addProperty(pht('Schema Status'), $status_view);
+
+ return $view;
+ }
}
diff --git a/src/applications/config/schema/PhabricatorConfigColumnSchema.php b/src/applications/config/schema/PhabricatorConfigColumnSchema.php
--- a/src/applications/config/schema/PhabricatorConfigColumnSchema.php
+++ b/src/applications/config/schema/PhabricatorConfigColumnSchema.php
@@ -1,8 +1,8 @@
<?php
-final class PhabricatorConfigColumnSchema extends Phobject {
+final class PhabricatorConfigColumnSchema
+ extends PhabricatorConfigStorageSchema {
- private $name;
private $characterSet;
private $collation;
private $columnType;
@@ -16,6 +16,10 @@
return $this->columnType;
}
+ protected function getSubschemata() {
+ return array();
+ }
+
public function setCollation($collation) {
$this->collation = $collation;
return $this;
@@ -34,13 +38,28 @@
return $this->characterSet;
}
- public function setName($name) {
- $this->name = $name;
- return $this;
+ public function compareToSimilarSchema(
+ PhabricatorConfigStorageSchema $expect) {
+
+ $issues = array();
+ if ($this->getCharacterSet() != $expect->getCharacterSet()) {
+ $issues[] = self::ISSUE_CHARSET;
+ }
+
+ if ($this->getCollation() != $expect->getCollation()) {
+ $issues[] = self::ISSUE_COLLATION;
+ }
+
+ if ($this->getColumnType() != $expect->getColumnType()) {
+ $issues[] = self::ISSUE_COLUMNTYPE;
+ }
+
+ return $issues;
}
- public function getName() {
- return $this->name;
+ public function newEmptyClone() {
+ $clone = clone $this;
+ return $clone;
}
}
diff --git a/src/applications/config/schema/PhabricatorConfigDatabaseSchema.php b/src/applications/config/schema/PhabricatorConfigDatabaseSchema.php
--- a/src/applications/config/schema/PhabricatorConfigDatabaseSchema.php
+++ b/src/applications/config/schema/PhabricatorConfigDatabaseSchema.php
@@ -1,8 +1,8 @@
<?php
-final class PhabricatorConfigDatabaseSchema extends Phobject {
+final class PhabricatorConfigDatabaseSchema
+ extends PhabricatorConfigStorageSchema {
- private $name;
private $characterSet;
private $collation;
private $tables = array();
@@ -25,16 +25,29 @@
return idx($this->tables, $key);
}
- public function isSameSchema(PhabricatorConfigDatabaseSchema $expect) {
- return ($this->toDictionary() === $expect->toDictionary());
+ protected function getSubschemata() {
+ return $this->getTables();
}
- public function toDictionary() {
- return array(
- 'name' => $this->getName(),
- 'characterSet' => $this->getCharacterSet(),
- 'collation' => $this->getCollation(),
- );
+ public function compareToSimilarSchema(
+ PhabricatorConfigStorageSchema $expect) {
+
+ $issues = array();
+ if ($this->getCharacterSet() != $expect->getCharacterSet()) {
+ $issues[] = self::ISSUE_CHARSET;
+ }
+
+ if ($this->getCollation() != $expect->getCollation()) {
+ $issues[] = self::ISSUE_COLLATION;
+ }
+
+ return $issues;
+ }
+
+ public function newEmptyClone() {
+ $clone = clone $this;
+ $clone->tables = array();
+ return $clone;
}
public function setCollation($collation) {
@@ -55,13 +68,4 @@
return $this->characterSet;
}
- public function setName($name) {
- $this->name = $name;
- return $this;
- }
-
- public function getName() {
- return $this->name;
- }
-
}
diff --git a/src/applications/config/schema/PhabricatorConfigSchemaQuery.php b/src/applications/config/schema/PhabricatorConfigSchemaQuery.php
--- a/src/applications/config/schema/PhabricatorConfigSchemaQuery.php
+++ b/src/applications/config/schema/PhabricatorConfigSchemaQuery.php
@@ -92,7 +92,6 @@
return $server_schema;
}
-
public function loadExpectedSchema() {
$databases = $this->getDatabaseNames();
@@ -119,17 +118,101 @@
$utf8_collate = 'binary';
}
+ $specs = id(new PhutilSymbolLoader())
+ ->setAncestorClass('PhabricatorConfigSchemaSpec')
+ ->loadObjects();
+
$server_schema = new PhabricatorConfigServerSchema();
- foreach ($databases as $database_name) {
- $database_schema = id(new PhabricatorConfigDatabaseSchema())
- ->setName($database_name)
- ->setCharacterSet($utf8_charset)
- ->setCollation($utf8_collate);
+ foreach ($specs as $spec) {
+ $spec->setUTF8Charset($utf8_charset);
+ $spec->setUTF8Collate($utf8_collate);
- $server_schema->addDatabase($database_schema);
+ $spec->buildSchemata($server_schema);
}
return $server_schema;
}
+ public function buildComparisonSchema(
+ PhabricatorConfigServerSchema $expect,
+ PhabricatorConfigServerSchema $actual) {
+
+ $comp_server = $actual->newEmptyClone();
+
+ $all_databases = $actual->getDatabases() + $expect->getDatabases();
+ foreach ($all_databases as $database_name => $database_template) {
+ $actual_database = $actual->getDatabase($database_name);
+ $expect_database = $expect->getDatabase($database_name);
+
+ $issues = $this->compareSchemata($expect_database, $actual_database);
+
+ $comp_database = $database_template->newEmptyClone()
+ ->setIssues($issues);
+
+ if (!$actual_database) {
+ $actual_database = $expect_database->newEmptyClone();
+ }
+ if (!$expect_database) {
+ $expect_database = $actual_database->newEmptyClone();
+ }
+
+ $all_tables =
+ $actual_database->getTables() +
+ $expect_database->getTables();
+ foreach ($all_tables as $table_name => $table_template) {
+ $actual_table = $actual_database->getTable($table_name);
+ $expect_table = $expect_database->getTable($table_name);
+
+ $issues = $this->compareSchemata($expect_table, $actual_table);
+
+ $comp_table = $table_template->newEmptyClone()
+ ->setIssues($issues);
+
+ if (!$actual_table) {
+ $actual_table = $expect_table->newEmptyClone();
+ }
+ if (!$expect_table) {
+ $expect_table = $actual_table->newEmptyClone();
+ }
+
+ $all_columns =
+ $actual_table->getColumns() +
+ $expect_table->getColumns();
+ foreach ($all_columns as $column_name => $column_template) {
+ $actual_column = $actual_table->getColumn($column_name);
+ $expect_column = $expect_table->getColumn($column_name);
+
+ $issues = $this->compareSchemata($expect_column, $actual_column);
+
+ $comp_column = $column_template->newEmptyClone()
+ ->setIssues($issues);
+
+ $comp_table->addColumn($comp_column);
+ }
+ $comp_database->addTable($comp_table);
+ }
+ $comp_server->addDatabase($comp_database);
+ }
+
+ return $comp_server;
+ }
+
+ private function compareSchemata(
+ PhabricatorConfigStorageSchema $expect = null,
+ PhabricatorConfigStorageSchema $actual = null) {
+
+ if (!$expect && !$actual) {
+ throw new Exception(pht('Can not compare two missing schemata!'));
+ } else if ($expect && !$actual) {
+ $issues = array(PhabricatorConfigStorageSchema::ISSUE_MISSING);
+ } else if ($actual && !$expect) {
+ $issues = array(PhabricatorConfigStorageSchema::ISSUE_SURPLUS);
+ } else {
+ $issues = $actual->compareTo($expect);
+ }
+
+ return $issues;
+ }
+
+
}
diff --git a/src/applications/config/schema/PhabricatorConfigSchemaSpec.php b/src/applications/config/schema/PhabricatorConfigSchemaSpec.php
new file mode 100644
--- /dev/null
+++ b/src/applications/config/schema/PhabricatorConfigSchemaSpec.php
@@ -0,0 +1,7 @@
+<?php
+
+abstract class PhabricatorConfigSchemaSpec extends Phobject {
+
+ abstract public function buildSchemata(PhabricatorConfigServerSchema $server);
+
+}
diff --git a/src/applications/config/schema/PhabricatorConfigServerSchema.php b/src/applications/config/schema/PhabricatorConfigServerSchema.php
--- a/src/applications/config/schema/PhabricatorConfigServerSchema.php
+++ b/src/applications/config/schema/PhabricatorConfigServerSchema.php
@@ -1,6 +1,7 @@
<?php
-final class PhabricatorConfigServerSchema extends Phobject {
+final class PhabricatorConfigServerSchema
+ extends PhabricatorConfigStorageSchema {
private $databases = array();
@@ -22,4 +23,19 @@
return idx($this->getDatabases(), $key);
}
+ protected function getSubschemata() {
+ return $this->getDatabases();
+ }
+
+ public function compareToSimilarSchema(
+ PhabricatorConfigStorageSchema $expect) {
+ return array();
+ }
+
+ public function newEmptyClone() {
+ $clone = clone $this;
+ $clone->databases = array();
+ return $clone;
+ }
+
}
diff --git a/src/applications/config/schema/PhabricatorConfigStorageSchema.php b/src/applications/config/schema/PhabricatorConfigStorageSchema.php
new file mode 100644
--- /dev/null
+++ b/src/applications/config/schema/PhabricatorConfigStorageSchema.php
@@ -0,0 +1,172 @@
+<?php
+
+abstract class PhabricatorConfigStorageSchema extends Phobject {
+
+ const ISSUE_MISSING = 'missing';
+ const ISSUE_SURPLUS = 'surplus';
+ const ISSUE_CHARSET = 'charset';
+ const ISSUE_COLLATION = 'collation';
+ const ISSUE_COLUMNTYPE = 'columntype';
+ const ISSUE_SUBWARN = 'subwarn';
+ const ISSUE_SUBFAIL = 'subfail';
+
+ const STATUS_OKAY = 'okay';
+ const STATUS_WARN = 'warn';
+ const STATUS_FAIL = 'fail';
+
+ private $issues = array();
+ private $name;
+
+ abstract public function newEmptyClone();
+ abstract protected function compareToSimilarSchema(
+ PhabricatorConfigStorageSchema $expect);
+ abstract protected function getSubschemata();
+
+ public function compareTo(PhabricatorConfigStorageSchema $expect) {
+ if (get_class($expect) != get_class($this)) {
+ throw new Exception(pht('Classes must match to compare schemata!'));
+ }
+
+ if ($this->getName() != $expect->getName()) {
+ throw new Exception(pht('Names must match to compare schemata!'));
+ }
+
+ return $this->compareToSimilarSchema($expect);
+ }
+
+ public function setName($name) {
+ $this->name = $name;
+ return $this;
+ }
+
+ public function getName() {
+ return $this->name;
+ }
+
+ public function setIssues(array $issues) {
+ $this->issues = array_fuse($issues);
+ return $this;
+ }
+
+ public function getIssues() {
+ $issues = $this->issues;
+
+ foreach ($this->getSubschemata() as $sub) {
+ switch ($sub->getStatus()) {
+ case self::STATUS_WARN:
+ $issues[self::ISSUE_SUBWARN] = self::ISSUE_SUBWARN;
+ break;
+ case self::STATUS_FAIL:
+ $issues[self::ISSUE_SUBFAIL] = self::ISSUE_SUBFAIL;
+ break;
+ }
+ }
+
+ return $issues;
+ }
+
+ public function hasIssue($issue) {
+ return (bool)idx($this->getIssues(), $issue);
+ }
+
+ public function getAllIssues() {
+ $issues = $this->getIssues();
+ foreach ($this->getSubschemata() as $sub) {
+ $issues += $sub->getAllIssues();
+ }
+ return $issues;
+ }
+
+ public function getStatus() {
+ $status = self::STATUS_OKAY;
+ foreach ($this->getAllIssues() as $issue) {
+ $issue_status = self::getIssueStatus($issue);
+ $status = self::getStrongestStatus($status, $issue_status);
+ }
+ return $status;
+ }
+
+ public static function getIssueName($issue) {
+ switch ($issue) {
+ case self::ISSUE_MISSING:
+ return pht('Missing');
+ case self::ISSUE_SURPLUS:
+ return pht('Surplus');
+ case self::ISSUE_CHARSET:
+ return pht('Wrong Character Set');
+ case self::ISSUE_COLLATION:
+ return pht('Wrong Collation');
+ case self::ISSUE_COLUMNTYPE:
+ return pht('Wrong Column Type');
+ case self::ISSUE_SUBWARN:
+ return pht('Subschemata Have Warnings');
+ case self::ISSUE_SUBFAIL:
+ return pht('Subschemata Have Failures');
+ default:
+ throw new Exception(pht('Unknown schema issue "%s"!', $issue));
+ }
+ }
+
+ public static function getIssueDescription($issue) {
+ switch ($issue) {
+ case self::ISSUE_MISSING:
+ return pht('This schema is expected to exist, but does not.');
+ case self::ISSUE_SURPLUS:
+ return pht('This schema is not expected to exist.');
+ case self::ISSUE_CHARSET:
+ return pht('This schema can use a better character set.');
+ case self::ISSUE_COLLATION:
+ return pht('This schema can use a better collation.');
+ case self::ISSUE_COLUMNTYPE:
+ return pht('This schema can use a better column type.');
+ case self::ISSUE_SUBWARN:
+ return pht('Subschemata have setup warnings.');
+ case self::ISSUE_SUBFAIL:
+ return pht('Subschemata have setup failures.');
+ default:
+ throw new Exception(pht('Unknown schema issue "%s"!', $issue));
+ }
+ }
+
+ public static function getIssueStatus($issue) {
+ switch ($issue) {
+ case self::ISSUE_MISSING:
+ case self::ISSUE_SUBFAIL:
+ return self::STATUS_FAIL;
+ case self::ISSUE_SURPLUS:
+ case self::ISSUE_CHARSET:
+ case self::ISSUE_COLLATION:
+ case self::ISSUE_COLUMNTYPE:
+ case self::ISSUE_SUBWARN:
+ return self::STATUS_WARN;
+ default:
+ throw new Exception(pht('Unknown schema issue "%s"!', $issue));
+ }
+ }
+
+ public static function getStatusSeverity($status) {
+ switch ($status) {
+ case self::STATUS_FAIL:
+ return 2;
+ case self::STATUS_WARN:
+ return 1;
+ case self::STATUS_OKAY:
+ return 0;
+ default:
+ throw new Exception(pht('Unknown schema status "%s"!', $status));
+ }
+ }
+
+ public static function getStrongestStatus($u, $v) {
+ $u_sev = self::getStatusSeverity($u);
+ $v_sev = self::getStatusSeverity($v);
+
+ if ($u_sev >= $v_sev) {
+ return $u;
+ } else {
+ return $v;
+ }
+ }
+
+
+}
diff --git a/src/applications/config/schema/PhabricatorConfigTableSchema.php b/src/applications/config/schema/PhabricatorConfigTableSchema.php
--- a/src/applications/config/schema/PhabricatorConfigTableSchema.php
+++ b/src/applications/config/schema/PhabricatorConfigTableSchema.php
@@ -1,8 +1,8 @@
<?php
-final class PhabricatorConfigTableSchema extends Phobject {
+final class PhabricatorConfigTableSchema
+ extends PhabricatorConfigStorageSchema {
- private $name;
private $collation;
private $columns = array();
@@ -20,6 +20,14 @@
return $this->columns;
}
+ public function getColumn($key) {
+ return idx($this->getColumns(), $key);
+ }
+
+ protected function getSubschemata() {
+ return $this->getColumns();
+ }
+
public function setCollation($collation) {
$this->collation = $collation;
return $this;
@@ -29,13 +37,21 @@
return $this->collation;
}
- public function setName($name) {
- $this->name = $name;
- return $this;
+ public function compareToSimilarSchema(
+ PhabricatorConfigStorageSchema $expect) {
+
+ $issues = array();
+ if ($this->getCollation() != $expect->getCollation()) {
+ $issues[] = self::ISSUE_COLLATION;
+ }
+
+ return $issues;
}
- public function getName() {
- return $this->name;
+ public function newEmptyClone() {
+ $clone = clone $this;
+ $clone->columns = array();
+ return $clone;
}
}

File Metadata

Mime Type
text/plain
Expires
Sun, Aug 31, 3:37 AM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
8496823
Default Alt Text
D10496.diff (30 KB)

Event Timeline