You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ibatis.apache.org by cb...@apache.org on 2008/08/22 19:10:32 UTC

svn commit: r688124 - in /ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis: adhoc/AdHocExecutor.java migration/Change.java migration/CommandLine.java migration/Migrator.java

Author: cbegin
Date: Fri Aug 22 10:10:31 2008
New Revision: 688124

URL: http://svn.apache.org/viewvc?rev=688124&view=rev
Log:
added changelog command for getting status info about the current migration level.

Added:
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Change.java
Modified:
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/CommandLine.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Migrator.java

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java?rev=688124&r1=688123&r2=688124&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java Fri Aug 22 10:10:31 2008
@@ -19,6 +19,19 @@
     this.forceGeneratedKeySupport = forceGeneratedKeySupport;
   }
 
+  public AdHocExecutor(String driver, String url, String username, String password, boolean forceGeneratedKeySupport) {
+    try {
+      Class driverType = Class.forName(driver);
+      DriverManager.registerDriver((Driver) driverType.newInstance());
+      connection = DriverManager.getConnection(url, username, password);
+      this.connection = connection;
+      this.typeHandlerRegistry = new TypeHandlerRegistry();
+      this.forceGeneratedKeySupport = forceGeneratedKeySupport;
+    } catch (Exception e) {
+      throw new RuntimeException("Error configuring AdHocExecutor.  Cause: " + e, e);
+    }
+  }
+
   public AdHocExecutor(Connection connection) {
     this(connection, false);
   }

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Change.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Change.java?rev=688124&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Change.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Change.java Fri Aug 22 10:10:31 2008
@@ -0,0 +1,43 @@
+package org.apache.ibatis.migration;
+
+import java.math.BigDecimal;
+
+public class Change {
+
+  private BigDecimal id;
+  private String description;
+
+  public Change() {
+  }
+
+  public Change(BigDecimal id, String description) {
+    this.id = id;
+    this.description = description;
+  }
+
+  public BigDecimal getId() {
+    return id;
+  }
+
+  public void setId(BigDecimal id) {
+    this.id = id;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public String toString() {
+    StringBuilder idstring = new StringBuilder(id.toString());
+    idstring.insert(12,":");
+    idstring.insert(10,":");
+    idstring.insert(8," ");
+    idstring.insert(6,"-");
+    idstring.insert(4,"-");
+    return id + " [" + idstring + "] " + description;
+  }
+}

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/CommandLine.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/CommandLine.java?rev=688124&r1=688123&r2=688124&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/CommandLine.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/CommandLine.java Fri Aug 22 10:10:31 2008
@@ -13,13 +13,14 @@
   private static final String PATH_PREFIX = "--path=";
   private static final String ENV_PREFIX = "--env=";
   private static final String FORCE = "--force";
+  private static final String CHANGELOG = "changelog";
   private static final String INIT = "init";
   private static final String NEW = "new";
   private static final String RUN = "run";
   private static final String VERSION = "version";
   private static final String UNDO = "undo";
   private static final Set<String> KNOWN_COMMANDS = Collections.unmodifiableSet(
-      new HashSet<String>(Arrays.asList(INIT, NEW, RUN, VERSION, UNDO)));
+      new HashSet<String>(Arrays.asList(INIT, NEW, RUN, VERSION, UNDO, CHANGELOG)));
 
   private String repository;
   private String environment;
@@ -84,6 +85,8 @@
       migrator.initialize();
     } else if (NEW.equals(command)) {
       migrator.newMigration(params);
+    } else if (CHANGELOG.equals(command)) {
+      migrator.printChangelog();
     } else if (RUN.equals(command)) {
       migrator.runPendingMigrations();
     } else if (VERSION.equals(command)) {
@@ -123,6 +126,7 @@
     out.println("  init               Creates (if necessary) and initializes a migration path.");
     out.println("  new <description>  Creates a new migration with the provided description.");
     out.println("  run                Run all unapplied migrations.");
+    out.println("  changelog          Prints the changelog from the database.");
     out.println("  version <version>  Migrates the database up or down to the specified version.");
     out.println("  undo               Undoes the last migration applied to the database.");
     out.println();

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Migrator.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Migrator.java?rev=688124&r1=688123&r2=688124&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Migrator.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Migrator.java Fri Aug 22 10:10:31 2008
@@ -1,11 +1,14 @@
 package org.apache.ibatis.migration;
 
 import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.adhoc.AdHocExecutor;
 
 import java.math.BigInteger;
+import java.math.BigDecimal;
 import java.io.*;
 import java.text.SimpleDateFormat;
 import java.sql.Date;
+import java.sql.SQLException;
 import java.util.*;
 
 public class Migrator {
@@ -38,8 +41,8 @@
     if (description == null) {
       throw new MigrationException("No description specified for new migration.");
     }
-    Map<String,String> variables = new HashMap<String,String>();
-    variables.put("description",description);
+    Map<String, String> variables = new HashMap<String, String>();
+    variables.put("description", description);
     ensureEnvironment(environment);
     String filename = getTimestamp() + "_" + description.replace(' ', '_') + ".sql";
     copyResourceTo("org/apache/ibatis/migration/template_migration.sql", repositoryFile(filename), variables);
@@ -50,11 +53,13 @@
     try {
       String[] filenames = repository.list();
       Arrays.sort(filenames);
-      for(String filename : filenames) {
+      for (String filename : filenames) {
         if (filename.endsWith(".sql")) {
-          System.out.println(horizontalLine("Applying: " + filename,80));
+          System.out.println(horizontalLine("Applying: " + filename, 80));
           ScriptRunner runner = getScriptRunner();
-          runner.runScript(new MigrationReader(new FileReader(repositoryFile(filename)),false));
+          runner.runScript(new MigrationReader(new FileReader(repositoryFile(filename)), false));
+          Change change = parseChangeFromFilename(filename);
+          insertChangelog(change);
         }
       }
     } catch (Exception e) {
@@ -63,22 +68,33 @@
   }
 
   public void migrateToVersion(BigInteger version) {
-    System.out.println("Migrating to: " + version);
+    getChangelog();
+  }
+
+  public void printChangelog() {
+    List<Change> changelog = getChangelog();
+    System.out.println("ID             TIMESTAMP             DESCRIPTION");
+    System.out.println(horizontalLine("",60));
+    for (Change change : changelog) {
+      System.out.println(change);
+    }
   }
 
   public void undoLastMigration() {
     try {
       String[] filenames = repository.list();
-      Arrays.sort(filenames,new Comparator(){
+      Arrays.sort(filenames, new Comparator() {
         public int compare(Object o1, Object o2) {
-          return ((Comparable)o2).compareTo(o1);
+          return ((Comparable) o2).compareTo(o1);
         }
       });
-      for(String filename : filenames) {
+      for (String filename : filenames) {
         if (filename.endsWith(".sql")) {
-          System.out.println(horizontalLine("Undoing: " + filename,80));
+          System.out.println(horizontalLine("Undoing: " + filename, 80));
           ScriptRunner runner = getScriptRunner();
-          runner.runScript(new MigrationReader(new FileReader(repositoryFile(filename)),true));
+          runner.runScript(new MigrationReader(new FileReader(repositoryFile(filename)), true));
+          Change change = parseChangeFromFilename(filename);
+          deleteChange(change);
         }
       }
     } catch (Exception e) {
@@ -86,12 +102,69 @@
     }
   }
 
+  private void insertChangelog(Change change) {
+    try {
+      AdHocExecutor executor = getAdHocExecutor();
+      executor.insert("insert into CHANGELOG (ID, DESCRIPTION) values (?,?)", change.getId(), change.getDescription());
+    } catch (SQLException e) {
+      throw new MigrationException("Error querying last applied migration.  Cause: " + e, e);
+    }
+  }
+
+  private void deleteChange(Change change) {
+    try {
+      AdHocExecutor executor = getAdHocExecutor();
+      executor.delete("delete from CHANGELOG where id = ?", change.getId());
+    } catch (SQLException e) {
+      throw new MigrationException("Error querying last applied migration.  Cause: " + e, e);
+    }
+  }
+
+  private Change parseChangeFromFilename(String filename) {
+    Change change = new Change();
+    String[] parts = filename.split("\\.")[0].split("_");
+    change.setId(new BigDecimal(parts[0]));
+    StringBuilder builder = new StringBuilder();
+    for (int i=1; i < parts.length; i++) {
+      if (i > 1) builder.append(" ");
+      builder.append(parts[i]);
+    }
+    change.setDescription(builder.toString());
+    return change;
+  }
+
+  private List<Change>getChangelog() {
+    try {
+      AdHocExecutor executor = getAdHocExecutor();
+      List<Map<String,Object>> changelog = executor.selectAll("select ID, DESCRIPTION from CHANGELOG order by id");
+      List<Change> changes = new ArrayList<Change>();
+      for(Map<String,Object> change : changelog) {
+        changes.add(new Change(new BigDecimal(change.get("ID").toString()),change.get("DESCRIPTION").toString()));
+      }
+      return changes;
+    } catch (SQLException e) {
+      throw new MigrationException("Error querying last applied migration.  Cause: " + e, e);
+    }
+  }
+
+  private AdHocExecutor getAdHocExecutor() {
+    Properties props = getEnvironmentProperties();
+    String driver = props.getProperty("driver");
+    String url = props.getProperty("url");
+    String username = props.getProperty("username");
+    String password = props.getProperty("password");
+    AdHocExecutor executor = new AdHocExecutor(driver, url, username, password, false);
+    return executor;
+  }
+
   private String horizontalLine(String caption, int length) {
     StringBuilder builder = new StringBuilder();
-    builder.append("========== ");
-    builder.append(caption);
-    builder.append(" ");
-    for (int i=0; i < length - caption.length() - 2; i++) {
+    builder.append("==========");
+    if (caption.length() > 0) {
+      caption = " "+caption+" ";
+      builder.append(caption);
+    }
+    for (int i = 0; i < length - caption.length(); i++) {
       builder.append("=");
     }
     return builder.toString();
@@ -108,14 +181,14 @@
   }
 
   private File repositoryFile(String fileName) {
-    return new File(repository.getAbsolutePath()+File.separator+fileName);
+    return new File(repository.getAbsolutePath() + File.separator + fileName);
   }
 
   private void copyResourceTo(String resource, File toFile) {
-    copyResourceTo(resource,toFile,null);
+    copyResourceTo(resource, toFile, null);
   }
 
-  private void copyResourceTo(String resource, File toFile, Map<String,String> variables) {
+  private void copyResourceTo(String resource, File toFile, Map<String, String> variables) {
     System.out.println("Creating: " + toFile.getName());
     try {
       LineNumberReader reader = new LineNumberReader(Resources.getResourceAsReader(this.getClass().getClassLoader(), resource));
@@ -124,7 +197,7 @@
         try {
           String line;
           while ((line = reader.readLine()) != null) {
-            line = parsePlaceholders(line,variables);
+            line = parsePlaceholders(line, variables);
             writer.println(line);
           }
         } finally {
@@ -157,7 +230,7 @@
   }
 
   private File environmentFile(String environment) {
-    return repositoryFile(environment+".properties");
+    return repositoryFile(environment + ".properties");
   }
 
   private void createIfNecessary(File path) {
@@ -170,7 +243,7 @@
     }
   }
 
-  private String parsePlaceholders(String string, Map<String,String> variables) {
+  private String parsePlaceholders(String string, Map<String, String> variables) {
     final String OPEN = "${";
     final String CLOSE = "}";
     String newString = string;
@@ -197,21 +270,29 @@
 
   private ScriptRunner getScriptRunner() {
     try {
-      Properties props = new Properties();
-      String filename = repository + File.separator + environment + ".properties";
-      File file = new File(filename);
-      if (!file.exists()) {
-        throw new MigrationException("Could not find environment properties file: " + filename);
-      }
-      props.load(new FileInputStream(file));
+      Properties props = getEnvironmentProperties();
       String driver = props.getProperty("driver");
       String url = props.getProperty("url");
       String username = props.getProperty("username");
       String password = props.getProperty("password");
-      return new ScriptRunner(driver,url,username,password,false,!force);
+      return new ScriptRunner(driver, url, username, password, false, !force);
     } catch (Exception e) {
       throw new MigrationException("Error creating ScriptRunner.  Cause: " + e, e);
     }
   }
 
+  private Properties getEnvironmentProperties() {
+    try {
+      Properties props = new Properties();
+      File file = environmentFile(environment);
+      if (!file.exists()) {
+        throw new MigrationException("Could not find environment properties file: " + file.getAbsolutePath());
+      }
+      props.load(new FileInputStream(file));
+      return props;
+    } catch (IOException e) {
+      throw new MigrationException("Error loading environment properties.  Cause: " + e, e);
+    }
+  }
+
 }