Permalink
Browse files

Move evolution scripts to the conf/ directory.

  • Loading branch information...
1 parent 3a0382e commit 021b6f2dae1235acae32972887a8633f4e04b6a3 @guillaumebort guillaumebort committed Jan 26, 2012
@@ -68,7 +68,7 @@ object Helpers extends Status with HeaderNames {
/**
* Apply pending evolutions for the given DB.
*/
- def evolutionFor(dbName: String) = play.api.db.evolutions.OfflineEvolutions.applyScript(new java.io.File("."), this.getClass.getClassLoader, dbName)
+ def evolutionFor(dbName: String) = play.api.db.evolutions.OfflineEvolutions.applyScript(this.getClass.getClassLoader, dbName)
/**
* Extracts the Content-Type of this Content value.
@@ -105,4 +105,25 @@ public InputStream resourceAsStream(String relativePath) {
).asJava();
}
+ /**
+ * Returns `true` if the application is `DEV` mode.
+ */
+ public boolean isDev() {
+ return play.api.Play.isDev(application);
+ }
+
+ /**
+ * Returns `true` if the application is `PROD` mode.
+ */
+ public boolean isProd() {
+ return play.api.Play.isProd(application);
+ }
+
+ /**
+ * Returns `true` if the application is `TEST` mode.
+ */
+ public boolean isTest() {
+ return play.api.Play.isTest(application);
+ }
+
}
@@ -6,14 +6,31 @@
public class Play {
/**
- * Returns the currently running application, or `null` if not defined.
+ * Returns the currently running application.
*/
public static Application application() {
- play.api.Application app = play.api.Play.unsafeApplication();
- if(app == null) {
- return null;
- }
- return new Application(app);
+ return new Application(play.api.Play.current());
+ }
+
+ /**
+ * Returns `true` if the current application is `DEV` mode.
+ */
+ public static boolean isDev() {
+ return play.api.Play.isDev(play.api.Play.current());
+ }
+
+ /**
+ * Returns `true` if the current application is `PROD` mode.
+ */
+ public static boolean isProd() {
+ return play.api.Play.isProd(play.api.Play.current());
+ }
+
+ /**
+ * Returns `true` if the current application is `TEST` mode.
+ */
+ public static boolean isTest() {
+ return play.api.Play.isTest(play.api.Play.current());
}
}
@@ -78,14 +78,16 @@ public void onStart() {
servers.put(key, EbeanServerFactory.create(config));
// DDL
- boolean evolutionsEnabled = !"disabled".equals(application.configuration().getString("evolutions"));
- if(evolutionsEnabled) {
- String evolutionScript = generateEvolutionScript(servers.get(key), config);
- if(evolutionScript != null) {
- File evolutions = application.getFile("db/evolutions/" + key + "/1.sql");
- if(!evolutions.exists() || Files.readFile(evolutions).startsWith("# --- Created by Ebean DDL")) {
- Files.createDirectory(application.getFile("db/evolutions/" + key));
- Files.writeFileIfChanged(evolutions, evolutionScript);
+ if(!application.isProd()) {
+ boolean evolutionsEnabled = !"disabled".equals(application.configuration().getString("evolutions"));
+ if(evolutionsEnabled) {
+ String evolutionScript = generateEvolutionScript(servers.get(key), config);
+ if(evolutionScript != null) {
+ File evolutions = application.getFile("conf/evolutions/" + key + "/1.sql");
+ if(!evolutions.exists() || Files.readFile(evolutions).startsWith("# --- Created by Ebean DDL")) {
+ Files.createDirectory(application.getFile("conf/evolutions/" + key));
+ Files.writeFileIfChanged(evolutions, evolutionScript);
+ }
}
}
}
@@ -4,6 +4,7 @@ import java.io._
import java.sql.{ Date, Connection, SQLException }
import scalax.file._
+import scalax.io.JavaConverters._
import play.core._
@@ -74,8 +75,8 @@ object Evolutions {
def updateEvolutionScript(db: String = "default", revision: Int = 1, comment: String = "Generated", ups: String, downs: String)(implicit application: Application) {
import play.api.libs._
- val evolutions = application.getFile("db/evolutions/" + db + "/" + revision + ".sql");
- Files.createDirectory(application.getFile("db/evolutions/" + db));
+ val evolutions = application.getFile("conf/evolutions/" + db + "/" + revision + ".sql");
+ Files.createDirectory(application.getFile("conf/evolutions/" + db));
Files.writeFileIfChanged(evolutions,
"""|# --- %s
|
@@ -90,10 +91,6 @@ object Evolutions {
// --
- private def evolutionsDirectory(applicationPath: File, db: String): Option[File] = {
- Option(new File(applicationPath, "db/evolutions/" + db)).filter(_.exists)
- }
-
private def executeQuery(sql: String)(implicit c: Connection) = {
c.createStatement.executeQuery(sql)
}
@@ -279,8 +276,8 @@ object Evolutions {
* @param applicationPath the application path
* @param db the database name
*/
- def evolutionScript(api: DBApi, applicationPath: File, db: String) = {
- val application = applicationEvolutions(applicationPath, db)
+ def evolutionScript(api: DBApi, applicationClassloader: ClassLoader, db: String) = {
+ val application = applicationEvolutions(applicationClassloader, db)
val database = databaseEvolutions(api, db)
val (nonConflictingDowns, dRest) = database.span(e => !application.headOption.exists(e.revision <= _.revision))
@@ -332,54 +329,52 @@ object Evolutions {
/**
* Reads the evolutions from the application.
*
- * @param applicationPath the application path
* @param db the database name
*/
- def applicationEvolutions(applicationPath: File, db: String) = {
- evolutionsDirectory(applicationPath, db).map { dir =>
+ def applicationEvolutions(applicationClassloader: ClassLoader, db: String) = {
- val evolutionScript = """^([0-9]+)[.]sql$""".r
- val upsMarker = """^#.*!Ups.*$""".r
- val downsMarker = """^#.*!Downs.*$""".r
+ val upsMarker = """^#.*!Ups.*$""".r
+ val downsMarker = """^#.*!Downs.*$""".r
- val UPS = "UPS"
- val DOWNS = "DOWNS"
- val UNKNOWN = "UNKNOWN"
+ val UPS = "UPS"
+ val DOWNS = "DOWNS"
+ val UNKNOWN = "UNKNOWN"
- val mapUpsAndDowns: PartialFunction[String, String] = {
- case upsMarker() => UPS
- case downsMarker() => DOWNS
- case _ => UNKNOWN
- }
+ val mapUpsAndDowns: PartialFunction[String, String] = {
+ case upsMarker() => UPS
+ case downsMarker() => DOWNS
+ case _ => UNKNOWN
+ }
- val isMarker: PartialFunction[String, Boolean] = {
- case upsMarker() => true
- case downsMarker() => true
- case _ => false
+ val isMarker: PartialFunction[String, Boolean] = {
+ case upsMarker() => true
+ case downsMarker() => true
+ case _ => false
+ }
+
+ Collections.unfoldLeft(1) { revision =>
+ Option(applicationClassloader.getResourceAsStream("evolutions/" + db + "/" + revision + ".sql")).map { stream =>
+ (revision + 1, (revision, stream.asInput.slurpString))
}
+ }.sortBy(_._1).map {
+ case (revision, script) => {
+
+ val parsed = Collections.unfoldLeft(("", script.split('\n').toList.map(_.trim))) {
+ case (_, Nil) => None
+ case (context, lines) => {
+ val (some, next) = lines.span(l => !isMarker(l))
+ Some((next.headOption.map(c => (mapUpsAndDowns(c), next.tail)).getOrElse("" -> Nil),
+ context -> some.mkString("\n")))
+ }
+ }.reverse.drop(1).groupBy(i => i._1).mapValues { _.map(_._2).mkString("\n").trim }
- Path(dir).children().toSeq.map(f => f.name -> f).collect {
- case (evolutionScript(revision), script) => Integer.parseInt(revision) -> script.slurpString
- }.toList.sortBy(_._1).map {
- case (revision, script) => {
-
- val parsed = Collections.unfoldLeft(("", script.split('\n').toList.map(_.trim))) {
- case (_, Nil) => None
- case (context, lines) => {
- val (some, next) = lines.span(l => !isMarker(l))
- Some((next.headOption.map(c => (mapUpsAndDowns(c), next.tail)).getOrElse("" -> Nil),
- context -> some.mkString("\n")))
- }
- }.reverse.drop(1).groupBy(i => i._1).mapValues { _.map(_._2).mkString("\n").trim }
-
- Evolution(
- revision,
- parsed.get(UPS).getOrElse(""),
- parsed.get(DOWNS).getOrElse(""))
- }
- }.reverse
+ Evolution(
+ revision,
+ parsed.get(UPS).getOrElse(""),
+ parsed.get(DOWNS).getOrElse(""))
+ }
+ }.reverse
- }.getOrElse(Nil)
}
}
@@ -410,10 +405,17 @@ class EvolutionsPlugin(app: Application) extends Plugin {
api.datasources.foreach {
case (db, (ds, _)) => {
- val script = evolutionScript(api, app.path, db)
+ val script = evolutionScript(api, app.classloader, db)
if (!script.isEmpty) {
app.mode match {
case Mode.Test => Evolutions.applyScript(api, db, script)
+ case Mode.Prod if app.configuration.getBoolean("applyEvolutions." + db).filter(_ == true).isDefined => Evolutions.applyScript(api, db, script)
+ case Mode.Prod => {
+ Logger("play").warn("Your production database [" + db + "] needs evolutions! \n\n" + toHumanReadableScript(script))
+ Logger("play").warn("Run with -DapplyEvolutions." + db + "=true if you want to run them automatically (be careful)")
+
+ throw InvalidDatabaseRevision(db, toHumanReadableScript(script))
+ }
case _ => throw InvalidDatabaseRevision(db, toHumanReadableScript(script))
}
}
@@ -435,14 +437,14 @@ object OfflineEvolutions {
* @param classloader the classloader used to load the driver
* @param dbName the database name
*/
- def applyScript(applicationPath: File, classloader: ClassLoader, dbName: String) {
+ def applyScript(classloader: ClassLoader, dbName: String) {
import play.api._
val api = DBApi(
Map(dbName -> DBApi.createDataSource(
Configuration.load().getConfig("db." + dbName).get, classloader)))
- val script = Evolutions.evolutionScript(api, applicationPath, dbName)
+ val script = Evolutions.evolutionScript(api, classloader, dbName)
if (!Play.maybeApplication.exists(_.mode == Mode.Test)) {
Logger("play").warn("Applying evolution script for database '" + dbName + "':\n\n" + Evolutions.toHumanReadableScript(script))
@@ -13,7 +13,7 @@ object Collections {
* {{{
* unfoldLeft(0) { state match
* case a if a > 100 => None
- * case a => a + 1
+ * case a => (a + 1, a + 1)
* }
* }}}
*
@@ -148,7 +148,7 @@ class ReloadableApplication(sbtLink: SBTLink) extends ApplicationProvider {
import play.api.db.evolutions._
Some {
- OfflineEvolutions.applyScript(path, Play.current.classloader, db)
+ OfflineEvolutions.applyScript(Play.current.classloader, db)
sbtLink.forceReload()
Redirect(request.queryString.get("redirect").filterNot(_.isEmpty).map(_(0)).getOrElse("/"))
}
@@ -16,6 +16,7 @@ import PlayExceptions._
import PlayKeys._
import scala.annotation.tailrec
+import scala.collection.JavaConverters._
trait PlayCommands extends PlayJvm {
this: PlayReloader =>
@@ -788,7 +789,7 @@ trait PlayCommands extends PlayJvm {
import java.lang.{ ProcessBuilder => JProcessBuilder }
val builder = new JProcessBuilder(Seq(
- "java") ++ properties.map { case (key, value) => "-D" + key + "=" + value } ++ Seq("-Dhttp.port=" + port, "-cp", classpath, "play.core.server.NettyServer", extracted.currentProject.base.getCanonicalPath): _*)
+ "java") ++ (properties ++ System.getProperties.asScala).map { case (key, value) => "-D" + key + "=" + value } ++ Seq("-Dhttp.port=" + port, "-cp", classpath, "play.core.server.NettyServer", extracted.currentProject.base.getCanonicalPath): _*)
new Thread {
override def run {
@@ -0,0 +1,59 @@
+package test
+
+import org.specs2.mutable._
+
+import play.api.test._
+import play.api.test.Helpers._
+
+import play.api.data._
+import play.api.data.Forms._
+
+class FormSpec extends Specification {
+
+ val userForm = Form(
+ tuple(
+ "email" -> text,
+ "address" -> optional(
+ single("city" -> nonEmptyText)
+ )
+ )
+ )
+
+ "the userForm" should {
+
+ "don't bind the address if missing" in {
+
+ val (email, address) = userForm.bind(
+ Map("email" -> "coco")
+ ).get
+
+ email must equalTo("coco")
+ address must beNone
+
+ }
+
+ "don't bind the address if blank" in {
+
+ val (email, address) = userForm.bind(
+ Map("email" -> "coco", "address.city" -> "")
+ ).get
+
+ email must equalTo("coco")
+ address must beNone
+
+ }
+
+ "bind the address" in {
+
+ val (email, address) = userForm.bind(
+ Map("email" -> "coco", "address.city" -> "Paris")
+ ).get
+
+ email must equalTo("coco")
+ address must beSome.which(_ == "Paris")
+
+ }
+
+ }
+
+}
Oops, something went wrong.

0 comments on commit 021b6f2

Please sign in to comment.