inc/CommitCheck/BlankLines.php
authorAlan Knowles <alan@akbkhome.com>
Thu, 27 Jan 2011 14:22:15 +0000 (22:22 +0800)
committerAlan Knowles <alan@akbkhome.com>
Thu, 27 Jan 2011 14:22:15 +0000 (22:22 +0800)
inc/CommitCheck/BlankLines.php [deleted file]
inc/DBSchema.php
inc/DBSchema/Generic.php [new file with mode: 0644]
inc/DBSchema/SQLite.php [new file with mode: 0644]
inc/DBSchema/Table.php [new file with mode: 0644]
inc/DBSchema/pgsql.php [new file with mode: 0644]

diff --git a/inc/CommitCheck/BlankLines.php b/inc/CommitCheck/BlankLines.php
deleted file mode 100644 (file)
index 2c5fff2..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php 
-require_once 'Interface/CommitListener.php';
-
-class MTrackCommitCheck_BlankLines implements IMTrackCommitListener 
-{
-  
-    function vetoCommit($msg, $files, $actions, $checker)
-    {
-        // should only have a list of files which have been updated/added. (not deleted)
-        $ret = array();
-        if (!method_exists($checker->bridge, 'getDiffStream')) { // kludge - we should use interface....
-            return true;
-        }
-        $fp = $checker->bridge->getDiffStream();
-        $diff = stream_get_contents($fp);
-        $lines = explode("\n",$contents);
-        $seq = 0;
-        $total = 0;
-        
-        // probably a CRLF fix....
-        if (count($lines) > 100) {
-            return;
-        }
-        
-        foreach($lines as $l) {
-            $ll = trim($l);
-            if ($l != '+') {
-                $seq =0;
-                continue;
-            }
-            // got blannk line
-            $seq++;
-            
-            if ($seq > 2) {
-                return "You are adding more than 2 blank lines - please remove the new blank lines you added and try again.";
-            }
-        }
-        
-         
-         
-       return true;
-    }
-
-    function postCommit($msg, $files, $actions) {
-        return true;
-    }
-    
-}
\ No newline at end of file
index bc02f18..836dab3 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 
-require_once 'DBSchema_SQLite.php';
-require_once 'DBSchema_pgsql.php';
-require_once 'DBSchema_Table.php';
+require_once 'DBSchema/SQLite.php';
+require_once 'DBSchema/pgsql.php';
+require_once 'DBSchema/Table.php';
 
 class MTrackDBSchema {
   var $tables;
diff --git a/inc/DBSchema/Generic.php b/inc/DBSchema/Generic.php
new file mode 100644 (file)
index 0000000..8dd3548
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+
+require_once 'Interface/DBSchema_Driver.php';
+
+class MTrackDBSchema_Generic implements IMTrackDBSchema_Driver {
+  var $db;
+  var $typemap = array();
+
+  function setDB(PDO $db) {
+    $this->db = $db;
+  }
+
+  function determineVersion() {
+    try {
+      $q = $this->db->query('select version from mtrack_schema');
+      if ($q) {
+        foreach ($q as $row) {
+          return $row[0];
+        }
+      }
+    } catch (Exception $e) {
+    }
+    return null;
+  }
+
+  function computeFieldCreate($f) {
+    $str = "\t$f->name ";
+    $str .= isset($this->typemap[$f->type]) ? $this->typemap[$f->type] : $f->type;
+    if (isset($f->nullable) && $f->nullable == '0') {
+      $str .= ' NOT NULL ';
+    }
+    if (isset($f->default)) {
+      if (!strlen($f->default)) {
+        $str .= " DEFAULT ''";
+      } else {
+        $str .= " DEFAULT $f->default";
+      }
+    }
+    return $str;
+  }
+
+  function computeIndexCreate($table, $k) {
+    switch ($k->type) {
+      case 'unique':
+        $kt = ' UNIQUE ';
+        break;
+      case 'multiple':
+      default:
+        $kt = '';
+    }
+    return "CREATE $kt INDEX $k->name on $table->name (" . join(', ', $k->fields) . ")";
+  }
+
+  function createTable(MTrackDBSchema_Table $table)
+  {
+    echo "Create $table->name\n";
+
+    $pri_key = null;
+
+    $sql = array();
+    foreach ($table->fields as $f) {
+      if ($f->type == 'autoinc') {
+        $pri_key = $f->name;
+      }
+      $str = $this->computeFieldCreate($f);
+      $sql[] = $str;
+    }
+
+    if (is_array($table->keys)) foreach ($table->keys as $k) {
+      if ($k->type != 'primary') continue;
+      if ($pri_key !== null) continue;
+      $sql[] = "\tprimary key (" . join(', ', $k->fields) . ")";
+    }
+
+    $sql = "CREATE TABLE $table->name (\n" .
+      join(",\n", $sql) .
+      ")\n";
+
+#    echo $sql;
+
+    $this->db->exec($sql);
+
+    if (is_array($table->keys)) foreach ($table->keys as $k) {
+      if ($k->type == 'primary') continue;
+      $this->db->exec($this->computeIndexCreate($table, $k));
+    }
+  }
+
+  function alterTable(MTrackDBSchema_Table $from, MTrackDBSchema_Table $to)
+  {
+    /* if keys have changed, we drop the old key definitions before changing the columns */
+
+    echo "Need to alter $from->name\n";
+    throw new Exception("bang!");
+  }
+
+  function dropTable(MTrackDBSchema_Table $table)
+  {
+    echo "Drop $table->name\n";
+    $this->db->exec("drop table $table->name");
+  }
+}
\ No newline at end of file
diff --git a/inc/DBSchema/SQLite.php b/inc/DBSchema/SQLite.php
new file mode 100644 (file)
index 0000000..72c8e93
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+
+require_once 'DBSchema/Generic.php';
+
+class MTrackDBSchema_SQLite extends MTrackDBSchema_Generic {
+
+  function determineVersion() {
+    /* older versions did not have a schema version table, so we dance
+     * around a little bit, but only for sqlite, as those older versions
+     * didn't support other databases */
+    try {
+      $q = $this->db->query('select version from mtrack_schema');
+      if ($q) {
+        foreach ($q as $row) {
+          return $row[0];
+        }
+      }
+    } catch (Exception $e) {
+    }
+
+    /* do we have any tables at all? if we do, we treat that as schema
+     * version 0 */
+    foreach ($this->db->query('select count(*) from sqlite_master') as $row) {
+      if ($row[0] > 0) {
+        $this->db->exec(
+          'create table mtrack_schema (version integer not null)');
+        return 0;
+      }
+    }
+    return null;
+  }
+
+  var $typemap = array(
+    'autoinc' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
+  );
+
+  function createTable(MTrackDBSchema_Table $table)
+  {
+    parent::createTable($table);
+  }
+
+  function alterTable(MTrackDBSchema_Table $from, MTrackDBSchema_Table $to)
+  {
+    $tname = $from->name . '_' . uniqid();
+
+    $sql = array();
+    foreach ($to->fields as $f) {
+      if ($f->type == 'autoinc') {
+        $pri_key = $f->name;
+      }
+      $str = $this->computeFieldCreate($f);
+      $sql[] = $str;
+    }
+
+    $sql = "CREATE TEMPORARY TABLE $tname (\n" .
+      join(",\n", $sql) .
+      ")\n";
+
+    $this->db->exec($sql);
+
+    /* copy old data into this table */
+    $sql = "INSERT INTO $tname (";
+    $names = array();
+    foreach ($from->fields as $f) {
+      if (!isset($to->fields[$f->name])) continue;
+      $names[] = $f->name;
+    }
+    $sql .= join(', ', $names);
+    $sql .= ") SELECT " . join(', ', $names) . " from $from->name";
+
+    #echo "$sql\n";
+    $this->db->exec($sql);
+
+    $this->db->exec("DROP TABLE $from->name");
+    $this->createTable($to);
+    $sql = "INSERT INTO $from->name (";
+    $names = array();
+    foreach ($from->fields as $f) {
+      if (!isset($to->fields[$f->name])) continue;
+      $names[] = $f->name;
+    }
+    $sql .= join(', ', $names);
+    $sql .= ") SELECT " . join(', ', $names) . " from $tname";
+    #echo "$sql\n";
+    $this->db->exec($sql);
+    $this->db->exec("DROP TABLE $tname");
+  }
+
+
+}
\ No newline at end of file
diff --git a/inc/DBSchema/Table.php b/inc/DBSchema/Table.php
new file mode 100644 (file)
index 0000000..3f47f45
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+class MTrackDBSchema_Table {
+  var $name;
+  var $fields;
+  var $keys;
+  var $triggers;
+
+  /* compares two tables; returns true if they are identical,
+   * false if the definitions are altered */
+  function sameAs(MTrackDBSchema_Table $other) {
+    if ($this->name != $other->name) {
+      throw new Exception("can only compare tables with the same name!");
+    }
+    foreach (array('fields', 'keys', 'triggers') as $propname) {
+      if (!is_array($this->{$propname})) continue;
+      foreach ($this->{$propname} as $f) {
+        if (!isset($other->{$propname}[$f->name])) {
+#          echo "$propname $f->name is new\n";
+          return false;
+        }
+        $o = clone $other->{$propname}[$f->name];
+        $f = clone $f;
+        unset($o->comment);
+        unset($f->comment);
+        if ($f != $o) {
+#          echo "$propname $f->name are not equal\n";
+#          var_dump($f);
+#          var_dump($o);
+          return false;
+        }
+      }
+      if (!is_array($other->{$propname})) continue;
+      foreach ($other->{$propname} as $f) {
+        if (!isset($this->{$propname}[$f->name])) {
+#          echo "$propname $f->name was deleted\n";
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/inc/DBSchema/pgsql.php b/inc/DBSchema/pgsql.php
new file mode 100644 (file)
index 0000000..d88e4ff
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+
+require_once 'DBSchema/Generic.php';
+
+class MTrackDBSchema_pgsql extends MTrackDBSchema_Generic {
+  var $typemap = array(
+    'autoinc' => 'SERIAL UNIQUE',
+    'timestamp' => 'timestamp with time zone',
+    'blob' => 'bytea',
+  );
+
+  function alterTable(MTrackDBSchema_Table $from, MTrackDBSchema_Table $to)
+  {
+    $sql = array();
+    $actions = array();
+
+    /* if keys have changed, we drop the old key definitions before changing the columns */
+    if (is_array($from->keys)) foreach ($from->keys as $k) {
+      if (!isset($to->keys[$k->name]) || $to->keys[$k->name] != $k) {
+        if ($k->type == 'primary') {
+          $actions[] = "DROP CONSTRAINT {$from->name}_pkey";
+        } else {
+          $sql[] = "DROP INDEX $k->name";
+        }
+      }
+    }
+
+    foreach ($from->fields as $f) {
+      if (!isset($to->fields[$f->name])) {
+        $actions[] = "DROP COLUMN $f->name";
+        continue;
+      }
+    }
+    foreach ($to->fields as $f) {
+      if (isset($from->fields[$f->name])) continue;
+      $actions[] = "ADD COLUMN " . $this->computeFieldCreate($f);
+    }
+
+    /* changed and new keys */
+    if (is_array($from->keys)) foreach ($from->keys as $k) {
+      if (isset($to->keys[$k->name]) && $to->keys[$k->name] != $k) {
+        if ($k->type == 'primary') {
+          $actions[] = "ADD primary key (" . join(', ', $k->fields) . ")";
+        } else {
+          $sql[] = $this->computeIndexCreate($to, $k);
+        }
+      }
+    }
+    if (is_array($to->keys)) foreach ($to->keys as $k) {
+      if (isset($from->keys[$k->name])) continue;
+      if ($k->type == 'primary') {
+        $actions[] = "ADD primary key (" . join(', ', $k->fields) . ")";
+      } else {
+        $sql[] = $this->computeIndexCreate($to, $k);
+      }
+    }
+
+    if (count($actions)) {
+      $sql[] = "ALTER TABLE $from->name " . join(",\n", $actions);
+    }
+    echo "Need to alter $from->name\n";
+    echo "SQL:\n";
+    var_dump($sql);
+    foreach ($sql as $s) {
+      $this->db->exec($s);
+    }
+  }
+}
\ No newline at end of file