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); + } + } + }