diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java index 4740694a05..64a4f68438 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java @@ -28,11 +28,11 @@ import com.google.gerrit.pgm.util.SiteProgram; import com.google.gerrit.reviewdb.AuthType; import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.ReviewDb; -import com.google.gerrit.reviewdb.SystemConfig; import com.google.gerrit.reviewdb.Project.SubmitType; import com.google.gerrit.server.config.ConfigUtil; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.mail.SmtpEmailSender.Encryption; +import com.google.gerrit.server.schema.SchemaUpdater; import com.google.gwtjsonrpc.server.SignedToken; import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.SchemaFactory; @@ -82,6 +82,9 @@ public class Init extends SiteProgram { @Option(name = "--no-auto-start", usage = "Don't automatically start daemon after init") private boolean noAutoStart; + @Inject + private SchemaUpdater schemaUpdater; + @Inject private GitRepositoryManager repositoryManager; @@ -137,7 +140,7 @@ public class Init extends SiteProgram { deleteOnFailure = false; inject(); - updateSystemConfig(); + schemaUpdater.update(); initGit(); } catch (Exception failure) { if (deleteOnFailure) { @@ -268,24 +271,6 @@ public class Init extends SiteProgram { chmod(0755, gerrit_sh); } - private void updateSystemConfig() throws OrmException { - final ReviewDb db = schema.open(); - try { - final SystemConfig sc = db.systemConfig().get(new SystemConfig.Key()); - if (sc == null) { - throw die("No record in system_config table"); - } - try { - sc.sitePath = getSitePath().getCanonicalPath(); - } catch (IOException e) { - sc.sitePath = getSitePath().getAbsolutePath(); - } - db.systemConfig().update(Collections.singleton(sc)); - } finally { - db.close(); - } - } - private void initGit() throws OrmException, IOException { final File root = repositoryManager.getBasePath(); if (root != null && importProjects) { diff --git a/gerrit-war/src/main/webapp/WEB-INF/sql/index_generic.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_generic.sql similarity index 100% rename from gerrit-war/src/main/webapp/WEB-INF/sql/index_generic.sql rename to gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_generic.sql diff --git a/gerrit-war/src/main/webapp/WEB-INF/sql/index_postgres.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_postgres.sql similarity index 99% rename from gerrit-war/src/main/webapp/WEB-INF/sql/index_postgres.sql rename to gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_postgres.sql index b007a3b246..455d96018d 100644 --- a/gerrit-war/src/main/webapp/WEB-INF/sql/index_postgres.sql +++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_postgres.sql @@ -17,6 +17,8 @@ CLUSTER; -- CREATE LANGUAGE plpgsql; +delimiter // + CREATE OR REPLACE FUNCTION check_schema_version (exp INT) RETURNS VARCHAR(255) @@ -34,7 +36,9 @@ BEGIN RETURN 'OK'; END; $$ LANGUAGE plpgsql; +// +delimiter ; -- Indexes to support @Query -- diff --git a/gerrit-war/src/main/webapp/WEB-INF/sql/mysql_nextval.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/mysql_nextval.sql similarity index 100% rename from gerrit-war/src/main/webapp/WEB-INF/sql/mysql_nextval.sql rename to gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/mysql_nextval.sql diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java index e5d4ba8c31..33ea3fb663 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java @@ -16,12 +16,14 @@ package com.google.gerrit.server.config; import static com.google.inject.Scopes.SINGLETON; +import com.google.gerrit.reviewdb.SystemConfig; import com.google.inject.AbstractModule; /** Creates {@link AuthConfig} from {@link GerritServerConfig}. */ public class AuthConfigModule extends AbstractModule { @Override protected void configure() { + bind(SystemConfig.class).toProvider(SystemConfigProvider.class).in(SINGLETON); bind(AuthConfig.class).in(SINGLETON); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java index 21ab1b8283..71142b9191 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java @@ -17,7 +17,6 @@ package com.google.gerrit.server.config; import static com.google.inject.Scopes.SINGLETON; import com.google.gerrit.reviewdb.ReviewDb; -import com.google.gerrit.reviewdb.SystemConfig; import com.google.gwtorm.client.SchemaFactory; import com.google.gwtorm.jdbc.Database; import com.google.inject.TypeLiteral; @@ -30,8 +29,5 @@ public class DatabaseModule extends FactoryModule { new TypeLiteral>() {}).in(SINGLETON); bind(new TypeLiteral>() {}).toProvider( ReviewDbDatabaseProvider.class).in(SINGLETON); - - bind(SystemConfig.class).toProvider(SystemConfigProvider.class).in( - SINGLETON); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java index 5621b4fb09..d3348fab94 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SystemConfigProvider.java @@ -14,33 +14,19 @@ package com.google.gerrit.server.config; -import com.google.gerrit.reviewdb.AccountGroup; -import com.google.gerrit.reviewdb.ApprovalCategory; -import com.google.gerrit.reviewdb.ApprovalCategoryValue; -import com.google.gerrit.reviewdb.Project; -import com.google.gerrit.reviewdb.ProjectRight; import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.reviewdb.SchemaVersion; import com.google.gerrit.reviewdb.SystemConfig; -import com.google.gerrit.server.workflow.NoOpFunction; -import com.google.gerrit.server.workflow.SubmitFunction; -import com.google.gwtjsonrpc.server.SignedToken; import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.SchemaFactory; -import com.google.gwtorm.client.Transaction; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.ProvisionException; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** Loads the {@link SystemConfig} from the database. */ public class SystemConfigProvider implements Provider { - private static final Project.NameKey DEFAULT_WILD_NAME = - new Project.NameKey("-- All Projects --"); private final SchemaFactory schema; @Inject @@ -56,30 +42,12 @@ public class SystemConfigProvider implements Provider { SchemaVersion sVer = getSchemaVersion(db); if (sVer == null) { - // Assume the schema is empty and try to populate it. - // - sVer = createSchema(db); + throw new OrmException("Schema not yet initialized." + + " Run init to initialize the schema."); } - - switch (sVer.versionNbr) { - case 2: - initPushTagCategory(db); - initPushUpdateBranchCategory(db); - - sVer.versionNbr = 3; - db.schemaVersion().update(Collections.singleton(sVer)); - break; - - case 15: - sVer.versionNbr = 16; - db.schemaVersion().update(Collections.singleton(sVer)); - break; - } - if (sVer.versionNbr != ReviewDb.VERSION) { - throw new OrmException("Unsupported schema version " - + sVer.versionNbr + "; expected schema version " - + ReviewDb.VERSION); + throw new OrmException("Unsupported schema version " + sVer.versionNbr + + "; expected schema version " + ReviewDb.VERSION + ". Run init to upgrade."); } final List all = db.systemConfig().all().toList(); @@ -89,8 +57,8 @@ public class SystemConfigProvider implements Provider { case 0: throw new OrmException("system_config table is empty"); default: - throw new OrmException("system_config must have exactly 1 row;" - + " found " + all.size() + " rows instead"); + throw new OrmException("system_config must have exactly 1 row;" + " found " + + all.size() + " rows instead"); } } finally { db.close(); @@ -100,26 +68,6 @@ public class SystemConfigProvider implements Provider { } } - private SchemaVersion createSchema(final ReviewDb db) throws OrmException { - db.createSchema(); - - final SchemaVersion sVer = SchemaVersion.create(); - sVer.versionNbr = ReviewDb.VERSION; - db.schemaVersion().insert(Collections.singleton(sVer)); - - final SystemConfig sConfig = initSystemConfig(db); - initOwnerCategory(db); - initReadCategory(db, sConfig); - initVerifiedCategory(db); - initCodeReviewCategory(db, sConfig); - initSubmitCategory(db); - initPushTagCategory(db); - initPushUpdateBranchCategory(db); - initWildCardProject(db); - - return sVer; - } - private SchemaVersion getSchemaVersion(final ReviewDb db) { try { return db.schemaVersion().get(new SchemaVersion.Key()); @@ -127,212 +75,4 @@ public class SystemConfigProvider implements Provider { return null; } } - - private SystemConfig initSystemConfig(final ReviewDb c) throws OrmException { - final AccountGroup admin = - new AccountGroup(new AccountGroup.NameKey("Administrators"), - new AccountGroup.Id(c.nextAccountGroupId())); - admin.setDescription("Gerrit Site Administrators"); - admin.setType(AccountGroup.Type.INTERNAL); - c.accountGroups().insert(Collections.singleton(admin)); - - final AccountGroup anonymous = - new AccountGroup(new AccountGroup.NameKey("Anonymous Users"), - new AccountGroup.Id(c.nextAccountGroupId())); - anonymous.setDescription("Any user, signed-in or not"); - anonymous.setOwnerGroupId(admin.getId()); - anonymous.setType(AccountGroup.Type.SYSTEM); - c.accountGroups().insert(Collections.singleton(anonymous)); - - final AccountGroup registered = - new AccountGroup(new AccountGroup.NameKey("Registered Users"), - new AccountGroup.Id(c.nextAccountGroupId())); - registered.setDescription("Any signed-in user"); - registered.setOwnerGroupId(admin.getId()); - registered.setType(AccountGroup.Type.SYSTEM); - c.accountGroups().insert(Collections.singleton(registered)); - - File sitePath = new File(".").getAbsoluteFile(); - if (".".equals(sitePath.getName())) { - sitePath = sitePath.getParentFile(); - } - - final SystemConfig s = SystemConfig.create(); - s.registerEmailPrivateKey = SignedToken.generateRandomKey(); - s.adminGroupId = admin.getId(); - s.anonymousGroupId = anonymous.getId(); - s.registeredGroupId = registered.getId(); - s.sitePath = sitePath.getAbsolutePath(); - c.systemConfig().insert(Collections.singleton(s)); - return s; - } - - private void initWildCardProject(final ReviewDb c) throws OrmException { - final Project p; - - p = new Project(DEFAULT_WILD_NAME, WildProjectNameProvider.WILD_PROJECT_ID); - p.setDescription("Rights inherited by all other projects"); - p.setUseContributorAgreements(false); - c.projects().insert(Collections.singleton(p)); - } - - private void initVerifiedCategory(final ReviewDb c) throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(new ApprovalCategory.Id("VRIF"), "Verified"); - cat.setPosition((short) 0); - cat.setAbbreviatedName("V"); - vals = new ArrayList(); - vals.add(value(cat, 1, "Verified")); - vals.add(value(cat, 0, "No score")); - vals.add(value(cat, -1, "Fails")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - } - - private void initCodeReviewCategory(final ReviewDb c, - final SystemConfig sConfig) throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(new ApprovalCategory.Id("CRVW"), "Code Review"); - cat.setPosition((short) 1); - cat.setAbbreviatedName("R"); - cat.setCopyMinScore(true); - vals = new ArrayList(); - vals.add(value(cat, 2, "Looks good to me, approved")); - vals.add(value(cat, 1, "Looks good to me, but someone else must approve")); - vals.add(value(cat, 0, "No score")); - vals.add(value(cat, -1, "I would prefer that you didn't submit this")); - vals.add(value(cat, -2, "Do not submit")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - - final ProjectRight approve = - new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), - sConfig.registeredGroupId)); - approve.setMaxValue((short) 1); - approve.setMinValue((short) -1); - c.projectRights().insert(Collections.singleton(approve)); - } - - private void initOwnerCategory(final ReviewDb c) throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(ApprovalCategory.OWN, "Owner"); - cat.setPosition((short) -1); - cat.setFunctionName(NoOpFunction.NAME); - vals = new ArrayList(); - vals.add(value(cat, 1, "Administer All Settings")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - } - - private void initReadCategory(final ReviewDb c, final SystemConfig sConfig) - throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(ApprovalCategory.READ, "Read Access"); - cat.setPosition((short) -1); - cat.setFunctionName(NoOpFunction.NAME); - vals = new ArrayList(); - vals.add(value(cat, 2, "Upload permission")); - vals.add(value(cat, 1, "Read access")); - vals.add(value(cat, -1, "No access")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - { - final ProjectRight read = - new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), - sConfig.anonymousGroupId)); - read.setMaxValue((short) 1); - read.setMinValue((short) 1); - c.projectRights().insert(Collections.singleton(read)); - } - { - final ProjectRight read = - new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), - sConfig.registeredGroupId)); - read.setMaxValue((short) 2); - read.setMinValue((short) 1); - c.projectRights().insert(Collections.singleton(read)); - } - { - final ProjectRight read = - new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), - sConfig.adminGroupId)); - read.setMaxValue((short) 1); - read.setMinValue((short) 1); - c.projectRights().insert(Collections.singleton(read)); - } - } - - private void initSubmitCategory(final ReviewDb c) throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(ApprovalCategory.SUBMIT, "Submit"); - cat.setPosition((short) -1); - cat.setFunctionName(SubmitFunction.NAME); - vals = new ArrayList(); - vals.add(value(cat, 1, "Submit")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - } - - private void initPushTagCategory(final ReviewDb c) throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(ApprovalCategory.PUSH_TAG, "Push Annotated Tag"); - cat.setPosition((short) -1); - cat.setFunctionName(NoOpFunction.NAME); - vals = new ArrayList(); - vals.add(value(cat, ApprovalCategory.PUSH_TAG_SIGNED, "Create Signed Tag")); - vals.add(value(cat, ApprovalCategory.PUSH_TAG_ANNOTATED, - "Create Annotated Tag")); - vals.add(value(cat, ApprovalCategory.PUSH_TAG_ANY, "Create Any Tag")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - } - - private void initPushUpdateBranchCategory(final ReviewDb c) - throws OrmException { - final Transaction txn = c.beginTransaction(); - final ApprovalCategory cat; - final ArrayList vals; - - cat = new ApprovalCategory(ApprovalCategory.PUSH_HEAD, "Push Branch"); - cat.setPosition((short) -1); - cat.setFunctionName(NoOpFunction.NAME); - vals = new ArrayList(); - vals.add(value(cat, ApprovalCategory.PUSH_HEAD_UPDATE, "Update Branch")); - vals.add(value(cat, ApprovalCategory.PUSH_HEAD_CREATE, "Create Branch")); - vals.add(value(cat, ApprovalCategory.PUSH_HEAD_REPLACE, - "Force Push Branch; Delete Branch")); - c.approvalCategories().insert(Collections.singleton(cat), txn); - c.approvalCategoryValues().insert(vals, txn); - txn.commit(); - } - - private static ApprovalCategoryValue value(final ApprovalCategory cat, - final int value, final String name) { - return new ApprovalCategoryValue(new ApprovalCategoryValue.Id(cat.getId(), - (short) value), name); - } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/WildProjectNameProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/WildProjectNameProvider.java index bf35ca8beb..ffb4cdeb65 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/WildProjectNameProvider.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/WildProjectNameProvider.java @@ -9,9 +9,9 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.ProvisionException; -class WildProjectNameProvider implements Provider { +public class WildProjectNameProvider implements Provider { /** Project.Id meaning "any and all projects on this server". */ - static final Project.Id WILD_PROJECT_ID = new Project.Id(0); + public static final Project.Id WILD_PROJECT_ID = new Project.Id(0); private final SchemaFactory schema; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java new file mode 100644 index 0000000000..c11132241d --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java @@ -0,0 +1,300 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.schema; + +import com.google.gerrit.reviewdb.AccountGroup; +import com.google.gerrit.reviewdb.ApprovalCategory; +import com.google.gerrit.reviewdb.ApprovalCategoryValue; +import com.google.gerrit.reviewdb.Project; +import com.google.gerrit.reviewdb.ProjectRight; +import com.google.gerrit.reviewdb.ReviewDb; +import com.google.gerrit.reviewdb.SchemaVersion; +import com.google.gerrit.reviewdb.SystemConfig; +import com.google.gerrit.server.config.SitePath; +import com.google.gerrit.server.config.WildProjectNameProvider; +import com.google.gerrit.server.workflow.NoOpFunction; +import com.google.gerrit.server.workflow.SubmitFunction; +import com.google.gwtjsonrpc.server.SignedToken; +import com.google.gwtorm.client.OrmException; +import com.google.gwtorm.client.Transaction; +import com.google.gwtorm.jdbc.JdbcSchema; +import com.google.gwtorm.schema.sql.DialectH2; +import com.google.gwtorm.schema.sql.DialectMySQL; +import com.google.gwtorm.schema.sql.DialectPostgreSQL; +import com.google.gwtorm.schema.sql.SqlDialect; +import com.google.inject.Inject; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; + +/** Creates the current database schema and populates initial code rows. */ +public class SchemaCreator { + private static final Project.NameKey DEFAULT_WILD_NAME = + new Project.NameKey("-- All Projects --"); + + private final File sitePath; + + private final ScriptRunner index_generic; + private final ScriptRunner index_postgres; + private final ScriptRunner mysql_nextval; + + @Inject + public SchemaCreator(final @SitePath File sitePath) { + this.sitePath = sitePath; + + index_generic = new ScriptRunner("index_generic.sql"); + index_postgres = new ScriptRunner("index_postgres.sql"); + mysql_nextval = new ScriptRunner("mysql_nextval.sql"); + } + + public void create(final ReviewDb db) throws OrmException { + final JdbcSchema jdbc = (JdbcSchema) db; + + jdbc.createSchema(); + + final SchemaVersion sVer = SchemaVersion.create(); + sVer.versionNbr = ReviewDb.VERSION; + db.schemaVersion().insert(Collections.singleton(sVer)); + + final SystemConfig sConfig = initSystemConfig(db); + initOwnerCategory(db); + initReadCategory(db, sConfig); + initVerifiedCategory(db); + initCodeReviewCategory(db, sConfig); + initSubmitCategory(db); + initPushTagCategory(db); + initPushUpdateBranchCategory(db); + initWildCardProject(db); + + final SqlDialect d = jdbc.getDialect(); + if (d instanceof DialectH2) { + index_generic.run(db); + + } else if (d instanceof DialectMySQL) { + index_generic.run(db); + mysql_nextval.run(db); + + } else if (d instanceof DialectPostgreSQL) { + index_postgres.run(db); + + } else { + throw new OrmException("Unsupported database " + d.getClass().getName()); + } + } + + private SystemConfig initSystemConfig(final ReviewDb c) throws OrmException { + final AccountGroup admin = + new AccountGroup(new AccountGroup.NameKey("Administrators"), new AccountGroup.Id(c + .nextAccountGroupId())); + admin.setDescription("Gerrit Site Administrators"); + admin.setType(AccountGroup.Type.INTERNAL); + c.accountGroups().insert(Collections.singleton(admin)); + + final AccountGroup anonymous = + new AccountGroup(new AccountGroup.NameKey("Anonymous Users"), new AccountGroup.Id(c + .nextAccountGroupId())); + anonymous.setDescription("Any user, signed-in or not"); + anonymous.setOwnerGroupId(admin.getId()); + anonymous.setType(AccountGroup.Type.SYSTEM); + c.accountGroups().insert(Collections.singleton(anonymous)); + + final AccountGroup registered = + new AccountGroup(new AccountGroup.NameKey("Registered Users"), new AccountGroup.Id(c + .nextAccountGroupId())); + registered.setDescription("Any signed-in user"); + registered.setOwnerGroupId(admin.getId()); + registered.setType(AccountGroup.Type.SYSTEM); + c.accountGroups().insert(Collections.singleton(registered)); + + final SystemConfig s = SystemConfig.create(); + s.registerEmailPrivateKey = SignedToken.generateRandomKey(); + s.adminGroupId = admin.getId(); + s.anonymousGroupId = anonymous.getId(); + s.registeredGroupId = registered.getId(); + try { + s.sitePath = sitePath.getCanonicalPath(); + } catch (IOException e) { + s.sitePath = sitePath.getAbsolutePath(); + } + c.systemConfig().insert(Collections.singleton(s)); + return s; + } + + private void initWildCardProject(final ReviewDb c) throws OrmException { + final Project p; + + p = new Project(DEFAULT_WILD_NAME, WildProjectNameProvider.WILD_PROJECT_ID); + p.setDescription("Rights inherited by all other projects"); + p.setUseContributorAgreements(false); + c.projects().insert(Collections.singleton(p)); + } + + private void initVerifiedCategory(final ReviewDb c) throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(new ApprovalCategory.Id("VRIF"), "Verified"); + cat.setPosition((short) 0); + cat.setAbbreviatedName("V"); + vals = new ArrayList(); + vals.add(value(cat, 1, "Verified")); + vals.add(value(cat, 0, "No score")); + vals.add(value(cat, -1, "Fails")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + } + + private void initCodeReviewCategory(final ReviewDb c, final SystemConfig sConfig) + throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(new ApprovalCategory.Id("CRVW"), "Code Review"); + cat.setPosition((short) 1); + cat.setAbbreviatedName("R"); + cat.setCopyMinScore(true); + vals = new ArrayList(); + vals.add(value(cat, 2, "Looks good to me, approved")); + vals.add(value(cat, 1, "Looks good to me, but someone else must approve")); + vals.add(value(cat, 0, "No score")); + vals.add(value(cat, -1, "I would prefer that you didn't submit this")); + vals.add(value(cat, -2, "Do not submit")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + + final ProjectRight approve = + new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), + sConfig.registeredGroupId)); + approve.setMaxValue((short) 1); + approve.setMinValue((short) -1); + c.projectRights().insert(Collections.singleton(approve)); + } + + private void initOwnerCategory(final ReviewDb c) throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(ApprovalCategory.OWN, "Owner"); + cat.setPosition((short) -1); + cat.setFunctionName(NoOpFunction.NAME); + vals = new ArrayList(); + vals.add(value(cat, 1, "Administer All Settings")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + } + + private void initReadCategory(final ReviewDb c, final SystemConfig sConfig) throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(ApprovalCategory.READ, "Read Access"); + cat.setPosition((short) -1); + cat.setFunctionName(NoOpFunction.NAME); + vals = new ArrayList(); + vals.add(value(cat, 2, "Upload permission")); + vals.add(value(cat, 1, "Read access")); + vals.add(value(cat, -1, "No access")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + { + final ProjectRight read = + new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), + sConfig.anonymousGroupId)); + read.setMaxValue((short) 1); + read.setMinValue((short) 1); + c.projectRights().insert(Collections.singleton(read)); + } + { + final ProjectRight read = + new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), + sConfig.registeredGroupId)); + read.setMaxValue((short) 2); + read.setMinValue((short) 1); + c.projectRights().insert(Collections.singleton(read)); + } + { + final ProjectRight read = + new ProjectRight(new ProjectRight.Key(DEFAULT_WILD_NAME, cat.getId(), + sConfig.adminGroupId)); + read.setMaxValue((short) 1); + read.setMinValue((short) 1); + c.projectRights().insert(Collections.singleton(read)); + } + } + + private void initSubmitCategory(final ReviewDb c) throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(ApprovalCategory.SUBMIT, "Submit"); + cat.setPosition((short) -1); + cat.setFunctionName(SubmitFunction.NAME); + vals = new ArrayList(); + vals.add(value(cat, 1, "Submit")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + } + + private void initPushTagCategory(final ReviewDb c) throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(ApprovalCategory.PUSH_TAG, "Push Annotated Tag"); + cat.setPosition((short) -1); + cat.setFunctionName(NoOpFunction.NAME); + vals = new ArrayList(); + vals.add(value(cat, ApprovalCategory.PUSH_TAG_SIGNED, "Create Signed Tag")); + vals.add(value(cat, ApprovalCategory.PUSH_TAG_ANNOTATED, "Create Annotated Tag")); + vals.add(value(cat, ApprovalCategory.PUSH_TAG_ANY, "Create Any Tag")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + } + + private void initPushUpdateBranchCategory(final ReviewDb c) throws OrmException { + final Transaction txn = c.beginTransaction(); + final ApprovalCategory cat; + final ArrayList vals; + + cat = new ApprovalCategory(ApprovalCategory.PUSH_HEAD, "Push Branch"); + cat.setPosition((short) -1); + cat.setFunctionName(NoOpFunction.NAME); + vals = new ArrayList(); + vals.add(value(cat, ApprovalCategory.PUSH_HEAD_UPDATE, "Update Branch")); + vals.add(value(cat, ApprovalCategory.PUSH_HEAD_CREATE, "Create Branch")); + vals.add(value(cat, ApprovalCategory.PUSH_HEAD_REPLACE, "Force Push Branch; Delete Branch")); + c.approvalCategories().insert(Collections.singleton(cat), txn); + c.approvalCategoryValues().insert(vals, txn); + txn.commit(); + } + + private static ApprovalCategoryValue value(final ApprovalCategory cat, final int value, + final String name) { + return new ApprovalCategoryValue(new ApprovalCategoryValue.Id(cat.getId(), (short) value), name); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java new file mode 100644 index 0000000000..5ef73c3d59 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java @@ -0,0 +1,79 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.schema; + +import com.google.gerrit.reviewdb.ReviewDb; +import com.google.gerrit.reviewdb.SchemaVersion; +import com.google.gerrit.reviewdb.SystemConfig; +import com.google.gerrit.server.config.SitePath; +import com.google.gwtorm.client.OrmException; +import com.google.gwtorm.client.SchemaFactory; +import com.google.inject.Inject; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; + +/** Creates or updates the current database schema. */ +public class SchemaUpdater { + private final SchemaFactory schema; + private final File sitePath; + private final SchemaCreator creator; + + @Inject + SchemaUpdater(final SchemaFactory schema, + final @SitePath File sitePath, + final SchemaCreator creator) { + this.schema = schema; + this.sitePath = sitePath; + this.creator = creator; + } + + public void update() throws OrmException { + final ReviewDb db = schema.open(); + try { + final SchemaVersion version = getSchemaVersion(db); + if (version == null) { + creator.create(db); + + } else { + updateSystemConfig(db); + } + } finally { + db.close(); + } + } + + private SchemaVersion getSchemaVersion(final ReviewDb db) { + try { + return db.schemaVersion().get(new SchemaVersion.Key()); + } catch (OrmException e) { + return null; + } + } + + private void updateSystemConfig(final ReviewDb db) throws OrmException { + final SystemConfig sc = db.systemConfig().get(new SystemConfig.Key()); + if (sc == null) { + throw new OrmException("No record in system_config table"); + } + try { + sc.sitePath = sitePath.getCanonicalPath(); + } catch (IOException e) { + sc.sitePath = sitePath.getAbsolutePath(); + } + db.systemConfig().update(Collections.singleton(sc)); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java new file mode 100644 index 0000000000..34c47a80a9 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java @@ -0,0 +1,123 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.schema; + +import com.google.gerrit.reviewdb.ReviewDb; +import com.google.gwtorm.client.OrmException; +import com.google.gwtorm.jdbc.JdbcSchema; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +/** Parses a SQL script from a resource file and later runs it. */ +class ScriptRunner { + private final String name; + private final List commands; + + ScriptRunner(final String name) { + try { + this.name = name; + this.commands = parse(name); + } catch (IOException e) { + throw new IllegalStateException("Cannot parse " + name, e); + } + } + + void run(final ReviewDb db) throws OrmException { + try { + final Connection c = ((JdbcSchema) db).getConnection(); + final Statement stmt = c.createStatement(); + try { + for (String sql : commands) { + try { + stmt.execute(sql); + } catch (SQLException e) { + throw new OrmException("Error in " + name + ":\n" + sql, e); + } + } + } finally { + stmt.close(); + } + } catch (SQLException e) { + throw new OrmException("Cannot run statements for " + name, e); + } + } + + private List parse(final String name) throws IOException { + InputStream in = ReviewDb.class.getResourceAsStream(name); + if (in == null) { + throw new FileNotFoundException("SQL script " + name + " not found"); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); + try { + String delimiter = ";"; + List commands = new ArrayList(); + StringBuilder buffer = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + if (line.isEmpty()) { + continue; + } + if (line.startsWith("--")) { + continue; + } + + if (buffer.length() == 0 && line.toLowerCase().startsWith("delimiter ")) { + delimiter = line.substring("delimiter ".length()).trim(); + continue; + } + + if (buffer.length() > 0) { + buffer.append('\n'); + } + buffer.append(line); + + if (isDone(delimiter, line, buffer)) { + String cmd = buffer.toString(); + commands.add(cmd); + buffer = new StringBuilder(); + } + } + if (buffer.length() > 0) { + commands.add(buffer.toString()); + } + return commands; + } finally { + br.close(); + } + } + + private boolean isDone(String delimiter, String line, StringBuilder buffer) { + if (";".equals(delimiter)) { + return buffer.charAt(buffer.length() - 1) == ';'; + + } else if (line.equals(delimiter)) { + buffer.setLength(buffer.length() - delimiter.length()); + return true; + + } else { + return false; + } + } +} diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java similarity index 96% rename from gerrit-server/src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java rename to gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java index 77a3ee2156..00fa2c2785 100644 --- a/gerrit-server/src/test/java/com/google/gerrit/server/config/SystemConfigProviderTest.java +++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.gerrit.server.config; +package com.google.gerrit.server.schema; import com.google.gerrit.reviewdb.AccountGroup; import com.google.gerrit.reviewdb.ApprovalCategory; @@ -22,6 +22,8 @@ import com.google.gerrit.reviewdb.ProjectRight; import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.reviewdb.SchemaVersion; import com.google.gerrit.reviewdb.SystemConfig; +import com.google.gerrit.server.config.SystemConfigProvider; +import com.google.gerrit.server.config.WildProjectNameProvider; import com.google.gerrit.server.workflow.NoOpFunction; import com.google.gerrit.server.workflow.SubmitFunction; import com.google.gerrit.testutil.TestDatabase; @@ -33,7 +35,7 @@ import java.io.File; import java.sql.SQLException; import java.util.HashSet; -public class SystemConfigProviderTest extends TestCase { +public class SchemaCreatorTest extends TestCase { private ApprovalCategory.Id codeReview = new ApprovalCategory.Id("CRVW"); private TestDatabase db; @@ -65,6 +67,7 @@ public class SystemConfigProviderTest extends TestCase { // Create the schema using the current schema version. // + db.create(); final SystemConfig config = getSystemConfig(); final SchemaVersion version = getSchemaVersion(); assertNotNull(version); @@ -89,7 +92,8 @@ public class SystemConfigProviderTest extends TestCase { assertTrue(20 < config.registerEmailPrivateKey.length()); } - public void testSubsequentGetReads() { + public void testSubsequentGetReads() throws OrmException { + db.create(); final SystemConfig exp = getSystemConfig(); final SystemConfig act = getSystemConfig(); @@ -102,6 +106,7 @@ public class SystemConfigProviderTest extends TestCase { } public void testCreateSchema_Group_Administrators() throws OrmException { + db.create(); final SystemConfig config = getSystemConfig(); final ReviewDb c = db.open(); try { @@ -116,6 +121,7 @@ public class SystemConfigProviderTest extends TestCase { } public void testCreateSchema_Group_AnonymousUsers() throws OrmException { + db.create(); final SystemConfig config = getSystemConfig(); final ReviewDb c = db.open(); try { @@ -130,6 +136,7 @@ public class SystemConfigProviderTest extends TestCase { } public void testCreateSchema_Group_RegisteredUsers() throws OrmException { + db.create(); final SystemConfig config = getSystemConfig(); final ReviewDb c = db.open(); try { @@ -308,12 +315,14 @@ public class SystemConfigProviderTest extends TestCase { public void testCreateSchema_DefaultAccess_AnonymousUsers() throws OrmException { + db.create(); final SystemConfig config = getSystemConfig(); assertDefaultRight(config.anonymousGroupId, ApprovalCategory.READ, 1, 1); } public void testCreateSchema_DefaultAccess_RegisteredUsers() throws OrmException { + db.create(); final SystemConfig config = getSystemConfig(); assertDefaultRight(config.registeredGroupId, ApprovalCategory.READ, 1, 2); assertDefaultRight(config.registeredGroupId, codeReview, -1, 1); @@ -321,6 +330,7 @@ public class SystemConfigProviderTest extends TestCase { public void testCreateSchema_DefaultAccess_Administrators() throws OrmException { + db.create(); final SystemConfig config = getSystemConfig(); assertDefaultRight(config.adminGroupId, ApprovalCategory.READ, 1, 1); } diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/TestDatabase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/TestDatabase.java index 7dc504fc5f..51c006ff08 100644 --- a/gerrit-server/src/test/java/com/google/gerrit/testutil/TestDatabase.java +++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/TestDatabase.java @@ -15,12 +15,13 @@ package com.google.gerrit.testutil; import com.google.gerrit.reviewdb.ReviewDb; -import com.google.gerrit.server.config.SystemConfigProvider; +import com.google.gerrit.server.schema.SchemaCreator; import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.SchemaFactory; import com.google.gwtorm.jdbc.Database; import com.google.gwtorm.jdbc.SimpleDataSource; +import java.io.File; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; @@ -55,6 +56,7 @@ public class TestDatabase implements SchemaFactory { private Connection openHandle; private Database database; + private boolean created; public TestDatabase() throws OrmException { try { @@ -84,8 +86,16 @@ public class TestDatabase implements SchemaFactory { } /** Ensure the database schema has been created and initialized. */ - public TestDatabase create() { - new SystemConfigProvider(this).get(); + public TestDatabase create() throws OrmException { + if (!created) { + created = true; + final ReviewDb c = open(); + try { + new SchemaCreator(new File(".")).create(c); + } finally { + c.close(); + } + } return this; }