summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2011-01-10 11:11:55 -0800
committerShawn O. Pearce <sop@google.com>2011-05-19 16:53:02 -0700
commita56d834d2b0ab466aff100ad4370fe8d4e830204 (patch)
tree018a5a7d6cc164f47813a7ea46648488f227cab6
parent3b0ecf498452f43f34faa30afd37c4eb3fbf9b86 (diff)
Move "projects" table into Git
Project settings are now saved in the project.config file of the refs/meta/config branch within each Git repository. This offers us free version control over the lifespan of the project, and will help reduce schema version issues as the configuration file is more free-form. Project owners can edit the configuration of their project by hand and push the results back up, possibly even going through code review, if the proper access rules are assigned in the project's access panel. Project users can inspect the history of the configuration by reading the history of the refs/meta/config branch with their favorite history browser. Change-Id: Id63414d86dbfb9033021f76e1d5e782373525a77 Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--Documentation/cmd-create-project.txt6
-rw-r--r--gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java52
-rw-r--r--gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java3
-rw-r--r--gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java13
-rw-r--r--gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java2
-rw-r--r--gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java58
-rw-r--r--gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java4
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java12
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java2
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java37
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java (renamed from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ProjectAccess.java)23
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java3
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java18
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java128
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java37
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java125
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java10
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java62
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java306
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java30
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java2
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java71
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java43
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java10
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java2
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java127
-rw-r--r--gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java3
-rw-r--r--gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java25
-rw-r--r--gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java24
-rw-r--r--gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java50
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java41
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java85
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java11
-rw-r--r--gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java61
-rw-r--r--gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java3
35 files changed, 1218 insertions, 271 deletions
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index 71c0d1fc65..e00e45bb33 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -13,7 +13,6 @@ SYNOPSIS
[--branch <REF>] \
[\--owner <GROUP> ...] \
[\--parent <NAME>] \
- [\--permissions-only] \
[\--description <DESC>] \
[\--submit-type <TYPE>] \
[\--use-content-merge] \
@@ -71,11 +70,6 @@ repository.*.createGroup will be used. If they don't exist,
through. If not specified, the parent is set to the default
project `\-- All Projects \--`.
-\--permissions-only::
- Create the project only to serve as a parent for other
- projects. The new project's Git repository will not be
- initialized, and cannot be cloned.
-
\--description::
Initial description of the project. If not specified,
no description is stored.
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java
index 88c85b8ff0..b720062fff 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java
@@ -17,16 +17,21 @@ package com.google.gerrit.httpd.rpc.project;
import com.google.gerrit.common.data.ProjectDetail;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
+import com.google.gwtorm.client.OrmConcurrencyException;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-import java.util.Collections;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+
+import java.io.IOException;
class ChangeProjectSettings extends Handler<ProjectDetail> {
interface Factory {
@@ -36,8 +41,8 @@ class ChangeProjectSettings extends Handler<ProjectDetail> {
private final ProjectDetailFactory.Factory projectDetailFactory;
private final ProjectControl.Factory projectControlFactory;
private final ProjectCache projectCache;
- private final ReviewDb db;
- private final GitRepositoryManager repoManager;
+ private final GitRepositoryManager mgr;
+ private final MetaDataUpdate.User metaDataUpdateFactory;
private final Project update;
@@ -45,14 +50,14 @@ class ChangeProjectSettings extends Handler<ProjectDetail> {
ChangeProjectSettings(
final ProjectDetailFactory.Factory projectDetailFactory,
final ProjectControl.Factory projectControlFactory,
- final ProjectCache projectCache, final ReviewDb db,
- final GitRepositoryManager grm,
+ final ProjectCache projectCache, final GitRepositoryManager mgr,
+ final MetaDataUpdate.User metaDataUpdateFactory,
@Assisted final Project update) {
this.projectDetailFactory = projectDetailFactory;
this.projectControlFactory = projectControlFactory;
this.projectCache = projectCache;
- this.db = db;
- this.repoManager = grm;
+ this.mgr = mgr;
+ this.metaDataUpdateFactory = metaDataUpdateFactory;
this.update = update;
}
@@ -63,17 +68,32 @@ class ChangeProjectSettings extends Handler<ProjectDetail> {
final ProjectControl projectControl =
projectControlFactory.ownerFor(projectName);
- final Project proj = db.projects().get(projectName);
- if (proj == null) {
+ final MetaDataUpdate md;
+ try {
+ md = metaDataUpdateFactory.create(projectName);
+ } catch (RepositoryNotFoundException notFound) {
throw new NoSuchProjectException(projectName);
}
+ try {
+ // TODO We really should take advantage of the Git commit DAG and
+ // ensure the current version matches the old version the caller read.
+ //
+ ProjectConfig config = ProjectConfig.read(md);
+ config.getProject().copySettingsFrom(update);
- proj.copySettingsFrom(update);
- db.projects().update(Collections.singleton(proj));
- projectCache.evict(proj);
-
- if (!projectControl.getProjectState().isSpecialWildProject()) {
- repoManager.setProjectDescription(projectName, update.getDescription());
+ md.setMessage("Modified project settings\n");
+ if (config.commit(md)) {
+ mgr.setProjectDescription(projectName, update.getDescription());
+ projectCache.evict(config.getProject());
+ } else {
+ throw new OrmConcurrencyException("Cannot update " + projectName);
+ }
+ } catch (ConfigInvalidException err) {
+ throw new OrmException("Cannot read project " + projectName, err);
+ } catch (IOException err) {
+ throw new OrmException("Cannot update project " + projectName, err);
+ } finally {
+ md.close();
}
return projectDetailFactory.create(projectName).call();
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 492dbee1cd..68ac33d437 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
@@ -32,7 +32,6 @@ import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.schema.SchemaUpdater;
import com.google.gerrit.server.schema.UpdateUI;
import com.google.gerrit.server.util.HostPlatform;
@@ -292,8 +291,6 @@ public class Init extends SiteProgram {
protected void configure() {
bind(ConsoleUI.class).toInstance(init.ui);
bind(InitFlags.class).toInstance(init.flags);
-
- bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
}
});
return createDbInjector(SINGLE_USER).createChildInjector(modules);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java
index beeed2478f..4ad274b408 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java
@@ -56,7 +56,6 @@ public class ScanTrackingIds extends SiteProgram {
private List<Change> todo;
private Injector dbInjector;
- private Injector gitInjector;
@Inject
private TrackingFooters footers;
@@ -74,17 +73,9 @@ public class ScanTrackingIds extends SiteProgram {
}
dbInjector = createDbInjector(MULTI_USER);
- gitInjector = dbInjector.createChildInjector(new LifecycleModule() {
- @Override
- protected void configure() {
- bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
- listener().to(LocalDiskRepositoryManager.Lifecycle.class);
- }
- });
-
- manager.add(dbInjector, gitInjector);
+ manager.add(dbInjector);
manager.start();
- gitInjector.injectMembers(this);
+ dbInjector.injectMembers(this);
final ReviewDb db = database.open();
try {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
index 8e3306bdf3..340168c7a2 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -22,6 +22,7 @@ import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.DatabaseModule;
+import com.google.gerrit.server.schema.SchemaModule;
import com.google.gwtorm.client.OrmException;
import com.google.inject.AbstractModule;
import com.google.inject.CreationException;
@@ -162,6 +163,7 @@ public abstract class SiteProgram extends AbstractProgram {
});
modules.add(new GerritServerConfigModule());
modules.add(new DatabaseModule());
+ modules.add(new SchemaModule());
try {
return Guice.createInjector(PRODUCTION, modules);
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java
index 7573140c2d..49f3333f96 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java
@@ -58,65 +58,37 @@ public final class Project {
}
public static enum SubmitType {
- FAST_FORWARD_ONLY('F'),
+ FAST_FORWARD_ONLY,
- MERGE_IF_NECESSARY('M'),
+ MERGE_IF_NECESSARY,
- MERGE_ALWAYS('A'),
+ MERGE_ALWAYS,
- CHERRY_PICK('C');
-
- private final char code;
-
- private SubmitType(final char c) {
- code = c;
- }
-
- public char getCode() {
- return code;
- }
-
- public static SubmitType forCode(final char c) {
- for (final SubmitType s : SubmitType.values()) {
- if (s.code == c) {
- return s;
- }
- }
- return null;
- }
+ CHERRY_PICK;
}
- @Column(id = 1)
protected NameKey name;
- @Column(id = 2, length = Integer.MAX_VALUE, notNull = false)
protected String description;
- @Column(id = 3)
protected boolean useContributorAgreements;
- @Column(id = 4)
protected boolean useSignedOffBy;
- @Column(id = 5)
- protected char submitType;
+ protected SubmitType submitType;
- @Column(id = 6, notNull = false, name = "parent_name")
protected NameKey parent;
- @Column(id = 7)
protected boolean requireChangeID;
- @Column(id = 8)
protected boolean useContentMerge;
protected Project() {
}
- public Project(final Project.NameKey newName) {
- name = newName;
- useContributorAgreements = true;
- setSubmitType(SubmitType.MERGE_IF_NECESSARY);
+ public Project(Project.NameKey nameKey) {
+ name = nameKey;
+ submitType = SubmitType.MERGE_IF_NECESSARY;
}
public Project.NameKey getNameKey() {
@@ -124,7 +96,7 @@ public final class Project {
}
public String getName() {
- return name.get();
+ return name != null ? name.get() : null;
}
public String getDescription() {
@@ -168,11 +140,11 @@ public final class Project {
}
public SubmitType getSubmitType() {
- return SubmitType.forCode(submitType);
+ return submitType;
}
public void setSubmitType(final SubmitType type) {
- submitType = type.getCode();
+ submitType = type;
}
public void copySettingsFrom(final Project update) {
@@ -188,7 +160,11 @@ public final class Project {
return parent;
}
- public void setParent(final Project.NameKey parentProjectName) {
- parent = parentProjectName;
+ public String getParentName() {
+ return parent != null ? parent.get() : null;
+ }
+
+ public void setParentName(String n) {
+ parent = n != null ? new NameKey(n) : null;
}
}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java
index 49e07ff756..c92694c257 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java
@@ -24,7 +24,6 @@ import com.google.gwtorm.client.Sequence;
* <p>
* Root entities that are at the top level of some important data graph:
* <ul>
- * <li>{@link Project}: Configuration for a single Git repository.</li>
* <li>{@link Account}: Per-user account registration, preferences, identity.</li>
* <li>{@link Change}: All review information about a single proposed change.</li>
* <li>{@link SystemConfig}: Server-wide settings, managed by administrator.</li>
@@ -94,9 +93,6 @@ public interface ReviewDb extends Schema {
AccountPatchReviewAccess accountPatchReviews();
@Relation
- ProjectAccess projects();
-
- @Relation
ChangeAccess changes();
@Relation
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 5426f346a2..3f400a6690 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -23,8 +23,6 @@ import com.google.gerrit.reviewdb.AuthType;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.FileTypeRegistry;
-import com.google.gerrit.server.GerritPersonIdent;
-import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.MimeUtilFileTypeRegistry;
import com.google.gerrit.server.ReplicationUser;
@@ -41,8 +39,7 @@ import com.google.gerrit.server.auth.ldap.LdapModule;
import com.google.gerrit.server.cache.CachePool;
import com.google.gerrit.server.events.EventFactory;
import com.google.gerrit.server.git.ChangeMergeQueue;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
+import com.google.gerrit.server.git.GitModule;
import com.google.gerrit.server.git.MergeQueue;
import com.google.gerrit.server.git.PushAllProjectsOp;
import com.google.gerrit.server.git.PushReplication;
@@ -71,7 +68,6 @@ import com.google.inject.Inject;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.runtime.RuntimeConstants;
import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.PersonIdent;
import java.util.Properties;
@@ -143,9 +139,6 @@ public class GerritGlobalModule extends FactoryModule {
SINGLETON);
bind(AnonymousUser.class);
- bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class).toProvider(
- GerritPersonIdentProvider.class);
-
bind(IdGenerator.class);
bind(CachePool.class);
install(AccountByEmailCacheImpl.module());
@@ -155,13 +148,13 @@ public class GerritGlobalModule extends FactoryModule {
install(PatchListCacheImpl.module());
install(ProjectCacheImpl.module());
install(new AccessControlModule());
+ install(new GitModule());
factory(AccountInfoCacheFactory.Factory.class);
factory(GroupInfoCacheFactory.Factory.class);
factory(ProjectState.Factory.class);
factory(RefControl.Factory.class);
- bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class);
bind(WorkQueue.class);
bind(ToolsCatalog.class);
@@ -189,7 +182,6 @@ public class GerritGlobalModule extends FactoryModule {
install(new LifecycleModule() {
@Override
protected void configure() {
- listener().to(LocalDiskRepositoryManager.Lifecycle.class);
listener().to(CachePool.Lifecycle.class);
listener().to(WorkQueue.Lifecycle.class);
listener().to(VelocityLifecycle.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
index f6dad7da90..52525e758f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
@@ -24,6 +24,7 @@ import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.server.git.CreateCodeReviewNotes;
import com.google.gerrit.server.git.MergeOp;
+import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ReceiveCommits;
import com.google.gerrit.server.mail.AbandonedSender;
import com.google.gerrit.server.mail.AddReviewerSender;
@@ -49,6 +50,7 @@ public class GerritRequestModule extends FactoryModule {
bind(ReviewDb.class).toProvider(RequestScopedReviewDbProvider.class).in(
RequestScoped.class);
bind(IdentifiedUser.RequestFactory.class).in(SINGLETON);
+ bind(MetaDataUpdate.User.class).in(RequestScoped.class);
bind(AccountResolver.class);
bind(ChangeQueryRewriter.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java
deleted file mode 100644
index 5b5dcc1f62..0000000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.config;
-
-import com.google.gerrit.reviewdb.SystemConfig;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-import java.io.File;
-
-/** Provides {@link java.io.File} annotated with {@link SitePath}. */
-public class SitePathFromSystemConfigProvider implements Provider<File> {
- private final File path;
-
- @Inject
- SitePathFromSystemConfigProvider(final SystemConfig config) {
- final String p = config.sitePath;
- path = new File(p != null && p.length() > 0 ? p : ".").getAbsoluteFile();
- }
-
- @Override
- public File get() {
- return path;
- }
-}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ProjectAccess.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java
index 738582c1eb..71e87a650c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ProjectAccess.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 The Android Open Source Project
+// Copyright (C) 2011 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.
@@ -12,18 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.server.git;
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.server.config.FactoryModule;
-public interface ProjectAccess extends Access<Project, Project.NameKey> {
- @PrimaryKey("name")
- Project get(Project.NameKey name) throws OrmException;
-
- @Query("ORDER BY name")
- ResultSet<Project> all() throws OrmException;
+/** Configures the Git support. */
+public class GitModule extends FactoryModule {
+ @Override
+ protected void configure() {
+ factory(MetaDataUpdate.InternalFactory.class);
+ bind(MetaDataUpdate.Server.class);
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
index 40f10ca874..993e4b410f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
@@ -34,6 +34,9 @@ public interface GitRepositoryManager {
/** Note tree listing commits we refuse {@code refs/meta/reject-commits} */
public static final String REF_REJECT_COMMITS = "refs/meta/reject-commits";
+ /** Configuration settings for a project {@code refs/meta/config} */
+ public static final String REF_CONFIG = "refs/meta/config";
+
/**
* Get (or open) a repository by name.
*
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 60016e5a03..caeb71cf3d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -882,6 +882,17 @@ public class MergeOp {
private void updateBranch() throws MergeException {
if (mergeTip != null && (branchTip == null || branchTip != mergeTip)) {
+ if (GitRepositoryManager.REF_CONFIG.equals(branchUpdate.getName())) {
+ try {
+ ProjectConfig cfg = new ProjectConfig(destProject.getNameKey());
+ cfg.load(db, mergeTip);
+ } catch (Exception e) {
+ throw new MergeException("Submit would store invalid"
+ + " project configuration " + mergeTip.name() + " for "
+ + destProject.getName(), e);
+ }
+ }
+
branchUpdate.setForceUpdate(false);
branchUpdate.setNewObjectId(mergeTip);
branchUpdate.setRefLogMessage("merged", true);
@@ -889,6 +900,13 @@ public class MergeOp {
switch (branchUpdate.update(rw)) {
case NEW:
case FAST_FORWARD:
+ if (GitRepositoryManager.REF_CONFIG.equals(branchUpdate.getName())) {
+ projectCache.evict(destProject);
+ ProjectState ps = projectCache.get(destProject.getNameKey());
+ repoManager.setProjectDescription(destProject.getNameKey(), //
+ ps.getProject().getDescription());
+ }
+
replication.scheduleUpdate(destBranch.getParentKey(), branchUpdate
.getName());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
new file mode 100644
index 0000000000..568c8cf9e3
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
@@ -0,0 +1,128 @@
+// Copyright (C) 2011 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.git;
+
+import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+
+/** Helps with the updating of a {@link VersionedMetaData}. */
+public class MetaDataUpdate {
+ public static class User {
+ private final InternalFactory factory;
+ private final GitRepositoryManager mgr;
+ private final PersonIdent serverIdent;
+ private final PersonIdent userIdent;
+
+ @Inject
+ User(InternalFactory factory, GitRepositoryManager mgr,
+ @GerritPersonIdent PersonIdent serverIdent, IdentifiedUser currentUser) {
+ this.factory = factory;
+ this.mgr = mgr;
+ this.serverIdent = serverIdent;
+ this.userIdent = currentUser.newCommitterIdent( //
+ serverIdent.getWhen(), //
+ serverIdent.getTimeZone());
+ }
+
+ public PersonIdent getUserPersonIdent() {
+ return userIdent;
+ }
+
+ public MetaDataUpdate create(Project.NameKey name)
+ throws RepositoryNotFoundException {
+ MetaDataUpdate md = factory.create(name, mgr.openRepository(name));
+ md.getCommitBuilder().setAuthor(userIdent);
+ md.getCommitBuilder().setCommitter(serverIdent);
+ return md;
+ }
+ }
+
+ public static class Server {
+ private final InternalFactory factory;
+ private final GitRepositoryManager mgr;
+ private final PersonIdent serverIdent;
+
+ @Inject
+ Server(InternalFactory factory, GitRepositoryManager mgr,
+ @GerritPersonIdent PersonIdent serverIdent) {
+ this.factory = factory;
+ this.mgr = mgr;
+ this.serverIdent = serverIdent;
+ }
+
+ public MetaDataUpdate create(Project.NameKey name)
+ throws RepositoryNotFoundException {
+ MetaDataUpdate md = factory.create(name, mgr.openRepository(name));
+ md.getCommitBuilder().setAuthor(serverIdent);
+ md.getCommitBuilder().setCommitter(serverIdent);
+ return md;
+ }
+ }
+
+ interface InternalFactory {
+ MetaDataUpdate create(@Assisted Project.NameKey projectName,
+ @Assisted Repository db);
+ }
+
+ private final ReplicationQueue replication;
+ private final Project.NameKey projectName;
+ private final Repository db;
+ private final CommitBuilder commit;
+
+ @Inject
+ public MetaDataUpdate(ReplicationQueue replication,
+ @Assisted Project.NameKey projectName, @Assisted Repository db) {
+ this.replication = replication;
+ this.projectName = projectName;
+ this.db = db;
+ this.commit = new CommitBuilder();
+ }
+
+ /** Set the commit message used when committing the update. */
+ public void setMessage(String message) {
+ getCommitBuilder().setMessage(message);
+ }
+
+ /** Close the cached Repository handle. */
+ public void close() {
+ getRepository().close();
+ }
+
+ Project.NameKey getProjectName() {
+ return projectName;
+ }
+
+ Repository getRepository() {
+ return db;
+ }
+
+ public CommitBuilder getCommitBuilder() {
+ return commit;
+ }
+
+ void replicate(String ref) {
+ if (replication.isEnabled()) {
+ replication.scheduleUpdate(projectName, ref);
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java
new file mode 100644
index 0000000000..ceb70d2f16
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2011 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.git;
+
+import com.google.gerrit.reviewdb.Project;
+
+/** A disabled {@link ReplicationQueue}. */
+public final class NoReplication implements ReplicationQueue {
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+
+ @Override
+ public void scheduleUpdate(Project.NameKey project, String ref) {
+ }
+
+ @Override
+ public void scheduleFullSync(Project.NameKey project, String urlMatch) {
+ }
+
+ @Override
+ public void replicateNewProject(Project.NameKey project, String head) {
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
new file mode 100644
index 0000000000..b69514cb3f
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -0,0 +1,125 @@
+// Copyright (C) 2010 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.git;
+
+import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.Project.SubmitType;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+
+import java.io.IOException;
+
+public class ProjectConfig extends VersionedMetaData {
+ private static final String PROJECT_CONFIG = "project.config";
+
+ private static final String PROJECT = "project";
+ private static final String KEY_DESCRIPTION = "description";
+
+ private static final String ACCESS = "access";
+ private static final String KEY_INHERIT_FROM = "inheritFrom";
+
+ private static final String RECEIVE = "receive";
+ private static final String KEY_REQUIRE_SIGNED_OFF_BY = "requireSignedOffBy";
+ private static final String KEY_REQUIRE_CHANGE_ID = "requireChangeId";
+ private static final String KEY_REQUIRE_CONTRIBUTOR_AGREEMENT =
+ "requireContributorAgreement";
+
+ private static final String SUBMIT = "submit";
+ private static final String KEY_ACTION = "action";
+ private static final String KEY_MERGE_CONTENT = "mergeContent";
+
+ private static final SubmitType defaultSubmitAction =
+ SubmitType.MERGE_IF_NECESSARY;
+
+ private Project.NameKey projectName;
+ private Project project;
+
+ public static ProjectConfig read(MetaDataUpdate update) throws IOException,
+ ConfigInvalidException {
+ ProjectConfig r = new ProjectConfig(update.getProjectName());
+ r.load(update);
+ return r;
+ }
+
+ public static ProjectConfig read(MetaDataUpdate update, ObjectId id)
+ throws IOException, ConfigInvalidException {
+ ProjectConfig r = new ProjectConfig(update.getProjectName());
+ r.load(update, id);
+ return r;
+ }
+
+ public ProjectConfig(Project.NameKey projectName) {
+ this.projectName = projectName;
+ }
+
+ public Project getProject() {
+ return project;
+ }
+
+ @Override
+ protected String getRefName() {
+ return GitRepositoryManager.REF_CONFIG;
+ }
+
+ @Override
+ protected void onLoad() throws IOException, ConfigInvalidException {
+ Config rc = readConfig(PROJECT_CONFIG);
+ project = new Project(projectName);
+
+ Project p = project;
+ p.setDescription(rc.getString(PROJECT, null, KEY_DESCRIPTION));
+ if (p.getDescription() == null) {
+ p.setDescription("");
+ }
+ p.setParentName(rc.getString(ACCESS, null, KEY_INHERIT_FROM));
+
+ p.setUseContributorAgreements(rc.getBoolean(RECEIVE, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, false));
+ p.setUseSignedOffBy(rc.getBoolean(RECEIVE, KEY_REQUIRE_SIGNED_OFF_BY, false));
+ p.setRequireChangeID(rc.getBoolean(RECEIVE, KEY_REQUIRE_CHANGE_ID, false));
+
+ p.setSubmitType(rc.getEnum(SUBMIT, null, KEY_ACTION, defaultSubmitAction));
+ p.setUseContentMerge(rc.getBoolean(SUBMIT, null, KEY_MERGE_CONTENT, false));
+ }
+
+ @Override
+ protected void onSave(CommitBuilder commit) throws IOException,
+ ConfigInvalidException {
+ if (commit.getMessage() == null || "".equals(commit.getMessage())) {
+ commit.setMessage("Updated project configuration\n");
+ }
+
+ Config rc = readConfig(PROJECT_CONFIG);
+ Project p = project;
+
+ if (p.getDescription() != null && !p.getDescription().isEmpty()) {
+ rc.setString(PROJECT, null, KEY_DESCRIPTION, p.getDescription());
+ } else {
+ rc.unset(PROJECT, null, KEY_DESCRIPTION);
+ }
+ set(rc, ACCESS, null, KEY_INHERIT_FROM, p.getParentName());
+
+ set(rc, RECEIVE, null, KEY_REQUIRE_CONTRIBUTOR_AGREEMENT, p.isUseContributorAgreements());
+ set(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_OFF_BY, p.isUseSignedOffBy());
+ set(rc, RECEIVE, null, KEY_REQUIRE_CHANGE_ID, p.isRequireChangeID());
+
+ set(rc, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction);
+ set(rc, SUBMIT, null, KEY_MERGE_CONTENT, p.isUseContentMerge());
+
+ saveConfig(PROJECT_CONFIG, rc);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java
index ecba4f71b7..b5f991c00e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.git;
import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.server.config.WildProjectName;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -37,17 +36,14 @@ public class PushAllProjectsOp extends DefaultQueueOp {
private final ProjectCache projectCache;
private final ReplicationQueue replication;
- private final Project.NameKey wildProject;
private final String urlMatch;
@Inject
public PushAllProjectsOp(final WorkQueue wq, final ProjectCache projectCache,
- final ReplicationQueue rq, @WildProjectName final Project.NameKey wp,
- @Assisted @Nullable final String urlMatch) {
+ final ReplicationQueue rq, @Assisted @Nullable final String urlMatch) {
super(wq);
this.projectCache = projectCache;
this.replication = rq;
- this.wildProject = wp;
this.urlMatch = urlMatch;
}
@@ -61,9 +57,7 @@ public class PushAllProjectsOp extends DefaultQueueOp {
public void run() {
try {
for (final Project.NameKey nameKey : projectCache.all()) {
- if (!nameKey.equals(wildProject)) {
- replication.scheduleFullSync(nameKey, urlMatch);
- }
+ replication.scheduleFullSync(nameKey, urlMatch);
}
} catch (RuntimeException e) {
log.error("Cannot enumerate known projects", e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index 445974fe7b..67f9929773 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -48,7 +48,9 @@ import com.google.gerrit.server.mail.MergedSender;
import com.google.gerrit.server.mail.ReplacePatchSetSender;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.RefControl;
import com.google.gwtorm.client.AtomicUpdate;
import com.google.gwtorm.client.OrmException;
@@ -141,6 +143,8 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
private final ReplicationQueue replication;
private final PatchSetInfoFactory patchSetInfoFactory;
private final ChangeHookRunner hooks;
+ private final GitRepositoryManager repoManager;
+ private final ProjectCache projectCache;
private final String canonicalWebUrl;
private final PersonIdent gerritIdent;
private final TrackingFooters trackingFooters;
@@ -175,6 +179,8 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
final ReplicationQueue replication,
final PatchSetInfoFactory patchSetInfoFactory,
final ChangeHookRunner hooks,
+ final ProjectCache projectCache,
+ final GitRepositoryManager repoManager,
@CanonicalWebUrl @Nullable final String canonicalWebUrl,
@GerritPersonIdent final PersonIdent gerritIdent,
final TrackingFooters trackingFooters,
@@ -191,6 +197,8 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
this.replication = replication;
this.patchSetInfoFactory = patchSetInfoFactory;
this.hooks = hooks;
+ this.projectCache = projectCache;
+ this.repoManager = repoManager;
this.canonicalWebUrl = canonicalWebUrl;
this.gerritIdent = gerritIdent;
this.trackingFooters = trackingFooters;
@@ -376,6 +384,13 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
}
}
+ if (GitRepositoryManager.REF_CONFIG.equals(c.getRefName())) {
+ projectCache.evict(project);
+ ProjectState ps = projectCache.get(project.getNameKey());
+ repoManager.setProjectDescription(project.getNameKey(), //
+ ps.getProject().getDescription());
+ }
+
if (!c.getRefName().startsWith(NEW_CHANGE)) {
// We only schedule direct refs updates for replication.
// Change refs are scheduled when they are created.
@@ -555,24 +570,59 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
switch (cmd.getType()) {
case CREATE:
parseCreate(cmd);
- continue;
+ break;
case UPDATE:
parseUpdate(cmd);
- continue;
+ break;
case DELETE:
parseDelete(cmd);
- continue;
+ break;
case UPDATE_NONFASTFORWARD:
parseRewind(cmd);
+ break;
+
+ default:
+ reject(cmd);
continue;
}
- // Everything else is bogus as far as we are concerned.
- //
- reject(cmd);
+ if (cmd.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED){
+ continue;
+ }
+
+ if (GitRepositoryManager.REF_CONFIG.equals(cmd.getRefName())) {
+ if (!projectControl.isOwner()) {
+ reject(cmd, "not project owner");
+ continue;
+ }
+
+ switch (cmd.getType()) {
+ case CREATE:
+ case UPDATE:
+ case UPDATE_NONFASTFORWARD:
+ try {
+ ProjectConfig cfg = new ProjectConfig(project.getNameKey());
+ cfg.load(repo, cmd.getNewId());
+ } catch (Exception e) {
+ reject(cmd, "invalid project configuration");
+ log.error("User " + currentUser.getUserName()
+ + " tried to push invalid project configuration "
+ + cmd.getNewId().name() + " for " + project.getName(), e);
+ continue;
+ }
+ break;
+
+ case DELETE:
+ break;
+
+ default:
+ reject(cmd);
+ continue;
+ }
+ }
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
new file mode 100644
index 0000000000..27ebe293db
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
@@ -0,0 +1,306 @@
+// Copyright (C) 2010 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.git;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
+import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.UnmergedPathException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.RawParseUtils;
+
+import java.io.IOException;
+
+/**
+ * Support for metadata stored within a version controlled branch.
+ * <p>
+ * Implementors are responsible for supplying implementations of the onLoad and
+ * onSave methods to read from the repository, or format an update that can
+ * later be written back to the repository.
+ */
+public abstract class VersionedMetaData {
+ private RevCommit revision;
+ private ObjectReader reader;
+ private ObjectInserter inserter;
+ private DirCache newTree;
+
+ /** @return name of the reference storing this configuration. */
+ protected abstract String getRefName();
+
+ protected abstract void onLoad() throws IOException, ConfigInvalidException;
+
+ protected abstract void onSave(CommitBuilder commit) throws IOException,
+ ConfigInvalidException;
+
+ /** @return revision of the metadata that was loaded. */
+ public ObjectId getRevision() {
+ return revision.copy();
+ }
+
+ /**
+ * Load the current version from the branch.
+ * <p>
+ * The repository is not held after the call completes, allowing the
+ * application to retain this object for long periods of time.
+ *
+ * @param db repository to access.
+ * @throws IOException
+ * @throws ConfigInvalidException
+ */
+ public void load(Repository db) throws IOException, ConfigInvalidException {
+ Ref ref = db.getRef(getRefName());
+ load(db, ref != null ? ref.getObjectId() : null);
+ }
+
+ /**
+ * Load a specific version from the repository.
+ * <p>
+ * This method is primarily useful for applying updates to a specific revision
+ * that was shown to an end-user in the user interface. If there are conflicts
+ * with another user's concurrent changes, these will be automatically
+ * detected at commit time.
+ * <p>
+ * The repository is not held after the call completes, allowing the
+ * application to retain this object for long periods of time.
+ *
+ * @param db repository to access.
+ * @param id revision to load.
+ * @throws IOException
+ * @throws ConfigInvalidException
+ */
+ public void load(Repository db, ObjectId id) throws IOException,
+ ConfigInvalidException {
+ if (id != null) {
+ reader = db.newObjectReader();
+ try {
+ revision = new RevWalk(reader).parseCommit(id);
+ onLoad();
+ } finally {
+ reader.release();
+ reader = null;
+ }
+ } else {
+ // The branch does not yet exist.
+ revision = null;
+ onLoad();
+ }
+ }
+
+ public void load(MetaDataUpdate update) throws IOException,
+ ConfigInvalidException {
+ load(update.getRepository());
+ }
+
+ public void load(MetaDataUpdate update, ObjectId id) throws IOException,
+ ConfigInvalidException {
+ load(update.getRepository(), id);
+ }
+
+ /**
+ * Update this metadata branch, recording a new commit on its reference.
+ *
+ * @param update helper information to define the update that will occur.
+ * @return true if the update was successful, false if it failed because of a
+ * concurrent update to the same reference.
+ * @throws IOException if there is a storage problem and the update cannot be
+ * executed as requested.
+ */
+ public boolean commit(MetaDataUpdate update) throws IOException {
+ final Repository db = update.getRepository();
+ final CommitBuilder commit = update.getCommitBuilder();
+
+ reader = db.newObjectReader();
+ inserter = db.newObjectInserter();
+ try {
+ final RevWalk rw = new RevWalk(reader);
+ final RevTree src = revision != null ? rw.parseTree(revision) : null;
+ final ObjectId res = writeTree(src, commit);
+
+ if (res.equals(src)) {
+ // If there are no changes to the content, don't create the commit.
+ return true;
+ }
+
+ commit.setTreeId(res);
+ if (revision != null) {
+ commit.setParentId(revision);
+ }
+
+ RefUpdate ru = db.updateRef(getRefName());
+ if (revision != null) {
+ ru.setExpectedOldObjectId(revision);
+ } else {
+ ru.setExpectedOldObjectId(ObjectId.zeroId());
+ }
+ ru.setNewObjectId(inserter.insert(commit));
+ ru.disableRefLog();
+ inserter.flush();
+
+ switch (ru.update(rw)) {
+ case NEW:
+ case FAST_FORWARD:
+ revision = rw.parseCommit(ru.getNewObjectId());
+ update.replicate(ru.getName());
+ return true;
+
+ case LOCK_FAILURE:
+ return false;
+
+ default:
+ throw new IOException("Cannot update " + ru.getName() + " in "
+ + db.getDirectory() + ": " + ru.getResult());
+ }
+ } catch (ConfigInvalidException e) {
+ throw new IOException("Cannot update " + getRefName() + " in "
+ + db.getDirectory() + ": " + e.getMessage(), e);
+ } finally {
+ inserter.release();
+ inserter = null;
+
+ reader.release();
+ reader = null;
+ }
+ }
+
+ private ObjectId writeTree(RevTree srcTree, CommitBuilder commit)
+ throws IOException, MissingObjectException, IncorrectObjectTypeException,
+ UnmergedPathException, ConfigInvalidException {
+ try {
+ newTree = readTree(srcTree);
+ onSave(commit);
+ return newTree.writeTree(inserter);
+ } finally {
+ newTree = null;
+ }
+ }
+
+ private DirCache readTree(RevTree tree) throws IOException,
+ MissingObjectException, IncorrectObjectTypeException {
+ DirCache dc = DirCache.newInCore();
+ if (tree != null) {
+ DirCacheBuilder b = dc.builder();
+ b.addTree(new byte[0], DirCacheEntry.STAGE_0, reader, tree);
+ b.finish();
+ }
+ return dc;
+ }
+
+ protected Config readConfig(String fileName) throws IOException,
+ ConfigInvalidException {
+ Config rc = new Config();
+ String text = readUTF8(fileName);
+ if (!text.isEmpty()) {
+ try {
+ rc.fromText(text);
+ } catch (ConfigInvalidException err) {
+ throw new ConfigInvalidException("Invalid config file " + fileName
+ + " in commit" + revision.name(), err);
+ }
+ }
+ return rc;
+ }
+
+ protected String readUTF8(String fileName) throws IOException {
+ byte[] raw = readFile(fileName);
+ return raw.length != 0 ? RawParseUtils.decode(raw) : "";
+ }
+
+ protected byte[] readFile(String fileName) throws IOException {
+ if (revision == null) {
+ return new byte[] {};
+ }
+
+ TreeWalk tw = TreeWalk.forPath(reader, fileName, revision.getTree());
+ if (tw != null) {
+ ObjectLoader obj = reader.open(tw.getObjectId(0), Constants.OBJ_BLOB);
+ return obj.getCachedBytes(Integer.MAX_VALUE);
+
+ } else {
+ return new byte[] {};
+ }
+ }
+
+ protected static void set(Config rc, String section, String subsection,
+ String name, String value) {
+ if (value != null) {
+ rc.setString(section, subsection, name, value);
+ } else {
+ rc.unset(section, subsection, name);
+ }
+ }
+
+ protected static void set(Config rc, String section, String subsection,
+ String name, boolean value) {
+ if (value) {
+ rc.setBoolean(section, subsection, name, value);
+ } else {
+ rc.unset(section, subsection, name);
+ }
+ }
+
+ protected static <E extends Enum<?>> void set(Config rc, String section,
+ String subsection, String name, E value, E defaultValue) {
+ if (value != defaultValue) {
+ rc.setEnum(section, subsection, name, value);
+ } else {
+ rc.unset(section, subsection, name);
+ }
+ }
+
+ protected void saveConfig(String fileName, Config cfg) throws IOException {
+ saveUTF8(fileName, cfg.toText());
+ }
+
+ protected void saveUTF8(String fileName, String text) throws IOException {
+ saveFile(fileName, text != null ? Constants.encode(text) : null);
+ }
+
+ protected void saveFile(String fileName, byte[] raw) throws IOException {
+ DirCacheEditor editor = newTree.editor();
+ if (raw != null && 0 < raw.length) {
+ final ObjectId blobId = inserter.insert(Constants.OBJ_BLOB, raw);
+ editor.add(new PathEdit(fileName) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.REGULAR_FILE);
+ ent.setObjectId(blobId);
+ }
+ });
+ } else {
+ editor.add(new DeletePath(fileName));
+ }
+ editor.finish();
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index ce0e394012..99b7a679ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -21,6 +21,7 @@ import com.google.gerrit.server.cache.Cache;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.cache.EntryCreator;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.ProjectConfig;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Module;
@@ -28,6 +29,9 @@ import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Repository;
+
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -167,27 +171,37 @@ public class ProjectCacheImpl implements ProjectCache {
static class Loader extends EntryCreator<Project.NameKey, ProjectState> {
private final ProjectState.Factory projectStateFactory;
private final SchemaFactory<ReviewDb> schema;
+ private final GitRepositoryManager mgr;
@Inject
- Loader(ProjectState.Factory psf, SchemaFactory<ReviewDb> sf) {
+ Loader(ProjectState.Factory psf, SchemaFactory<ReviewDb> sf,
+ GitRepositoryManager g) {
projectStateFactory = psf;
schema = sf;
+ mgr = g;
}
@Override
public ProjectState createEntry(Project.NameKey key) throws Exception {
final ReviewDb db = schema.open();
try {
- final Project p = db.projects().get(key);
- if (p == null) {
- return null;
+ Repository git = mgr.openRepository(key);
+ try {
+ final ProjectConfig cfg = new ProjectConfig(key);
+ cfg.load(git);
+
+ final Project p = cfg.getProject();
+ final Collection<RefRight> rights =
+ Collections.unmodifiableCollection(db.refRights().byProject(key)
+ .toList());
+ return projectStateFactory.create(p, rights);
+ } finally {
+ git.close();
}
- final Collection<RefRight> rights =
- Collections.unmodifiableCollection(db.refRights().byProject(
- p.getNameKey()).toList());
+ } catch (RepositoryNotFoundException notFound) {
+ return null;
- return projectStateFactory.create(p, rights);
} finally {
db.close();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java
index 55a36d6d74..6b66e33fd6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java
@@ -26,8 +26,6 @@ import com.google.inject.TypeLiteral;
public class DatabaseModule extends FactoryModule {
@Override
protected void configure() {
- install(new SchemaVersion.Module());
-
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).to(
new TypeLiteral<Database<ReviewDb>>() {}).in(SINGLETON);
bind(new TypeLiteral<Database<ReviewDb>>() {}).toProvider(
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
index a24471aff3..9d3682b3e4 100644
--- 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
@@ -23,8 +23,13 @@ import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RefRight;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.NoReplication;
+import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.workflow.NoOpFunction;
import com.google.gerrit.server.workflow.SubmitFunction;
import com.google.gwtjsonrpc.server.SignedToken;
@@ -37,6 +42,11 @@ import com.google.gwtorm.schema.sql.DialectPostgreSQL;
import com.google.gwtorm.schema.sql.SqlDialect;
import com.google.inject.Inject;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -50,6 +60,9 @@ public class SchemaCreator {
private final @SitePath
File site_path;
+ private final GitRepositoryManager mgr;
+ private final PersonIdent serverUser;
+
private final int versionNbr;
private final ScriptRunner index_generic;
private final ScriptRunner index_postgres;
@@ -57,20 +70,25 @@ public class SchemaCreator {
@Inject
public SchemaCreator(final SitePaths site,
- @Current final SchemaVersion version) {
- this(site.site_path, version);
+ @Current final SchemaVersion version, final GitRepositoryManager mgr,
+ @GerritPersonIdent final PersonIdent au) {
+ this(site.site_path, version, mgr, au);
}
public SchemaCreator(final @SitePath File site,
- @Current final SchemaVersion version) {
+ @Current final SchemaVersion version, final GitRepositoryManager gitMgr,
+ final @GerritPersonIdent PersonIdent au) {
site_path = site;
+ mgr = gitMgr;
+ serverUser = au;
versionNbr = version.getVersionNbr();
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 {
+ public void create(final ReviewDb db) throws OrmException, IOException,
+ ConfigInvalidException {
final JdbcSchema jdbc = (JdbcSchema) db;
final JdbcExecutor e = new JdbcExecutor(jdbc);
try {
@@ -92,7 +110,11 @@ public class SchemaCreator {
initPushTagCategory(db);
initPushUpdateBranchCategory(db);
initForgeIdentityCategory(db, sConfig);
- initWildCardProject(db);
+
+ if (mgr != null) {
+ // TODO This should never be null when initializing a site.
+ initWildCardProject();
+ }
final SqlDialect d = jdbc.getDialect();
if (d instanceof DialectH2) {
@@ -177,13 +199,38 @@ public class SchemaCreator {
return s;
}
- private void initWildCardProject(final ReviewDb c) throws OrmException {
- final Project p;
-
- p = new Project(DEFAULT_WILD_NAME);
- p.setDescription("Rights inherited by all other projects");
- p.setUseContributorAgreements(false);
- c.projects().insert(Collections.singleton(p));
+ private void initWildCardProject() throws IOException, ConfigInvalidException {
+ Repository git;
+ try {
+ git = mgr.openRepository(DEFAULT_WILD_NAME);
+ } catch (RepositoryNotFoundException notFound) {
+ // A repository may be missing if this project existed only to store
+ // inheritable permissions. For example '-- All Projects --'.
+ try {
+ git = mgr.createRepository(DEFAULT_WILD_NAME);
+ } catch (RepositoryNotFoundException err) {
+ final String name = DEFAULT_WILD_NAME.get();
+ throw new IOException("Cannot create repository " + name, err);
+ }
+ }
+ try {
+ MetaDataUpdate md =
+ new MetaDataUpdate(new NoReplication(), DEFAULT_WILD_NAME, git);
+ md.getCommitBuilder().setAuthor(serverUser);
+ md.getCommitBuilder().setCommitter(serverUser);
+
+ ProjectConfig config = ProjectConfig.read(md);
+ Project p = config.getProject();
+ p.setDescription("Rights inherited by all other projects");
+ p.setUseContributorAgreements(false);
+
+ md.setMessage("Created project\n");
+ if (!config.commit(md)) {
+ throw new IOException("Cannot create " + DEFAULT_WILD_NAME.get());
+ }
+ } finally {
+ git.close();
+ }
}
private void initVerifiedCategory(final ReviewDb c) throws OrmException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java
new file mode 100644
index 0000000000..3225e13528
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java
@@ -0,0 +1,43 @@
+// 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.lifecycle.LifecycleModule;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.GerritPersonIdentProvider;
+import com.google.gerrit.server.config.FactoryModule;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.LocalDiskRepositoryManager;
+
+import org.eclipse.jgit.lib.PersonIdent;
+
+/** Validate the schema and connect to Git. */
+public class SchemaModule extends FactoryModule {
+ @Override
+ protected void configure() {
+ install(new SchemaVersion.Module());
+
+ bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class).toProvider(
+ GerritPersonIdentProvider.class);
+
+ bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
+ install(new LifecycleModule() {
+ @Override
+ protected void configure() {
+ listener().to(LocalDiskRepositoryManager.Lifecycle.class);
+ }
+ });
+ }
+}
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
index f44eff5b18..3937aaafc4 100644
--- 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
@@ -23,6 +23,8 @@ import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
@@ -49,7 +51,13 @@ public class SchemaUpdater {
final SchemaVersion u = updater.get();
final CurrentSchemaVersion version = getSchemaVersion(db);
if (version == null) {
- creator.create(db);
+ try {
+ creator.create(db);
+ } catch (IOException e) {
+ throw new OrmException("Cannot initialize schema", e);
+ } catch (ConfigInvalidException e) {
+ throw new OrmException("Cannot initialize schema", e);
+ }
} else {
try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
index 978a15234a..b83f5402df 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
@@ -32,7 +32,7 @@ import java.util.List;
/** A version of the database schema. */
public abstract class SchemaVersion {
/** The current schema version. */
- private static final Class<? extends SchemaVersion> C = Schema_52.class;
+ private static final Class<? extends SchemaVersion> C = Schema_53.class;
public static class Module extends AbstractModule {
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
new file mode 100644
index 0000000000..af45df3d4a
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
@@ -0,0 +1,127 @@
+// Copyright (C) 2010 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.Project;
+import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.NoReplication;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+
+import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+class Schema_53 extends SchemaVersion {
+ private final GitRepositoryManager mgr;
+ private final PersonIdent serverUser;
+
+ @Inject
+ Schema_53(Provider<Schema_52> prior, GitRepositoryManager mgr,
+ @GerritPersonIdent PersonIdent serverUser) {
+ super(prior);
+ this.mgr = mgr;
+ this.serverUser = serverUser;
+ }
+
+ @Override
+ protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException,
+ SQLException {
+
+ Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
+ ResultSet rs = stmt.executeQuery("SELECT * FROM projects ORDER BY name");
+ while (rs.next()) {
+ final String name = rs.getString("name");
+ final Project.NameKey nameKey = new Project.NameKey(name);
+
+ Repository git;
+ try {
+ git = mgr.openRepository(nameKey);
+ } catch (RepositoryNotFoundException notFound) {
+ // A repository may be missing if this project existed only to store
+ // inheritable permissions. For example '-- All Projects --'.
+ try {
+ git = mgr.createRepository(nameKey);
+ } catch (RepositoryNotFoundException err) {
+ throw new OrmException("Cannot create repository " + name, err);
+ }
+ }
+ try {
+ MetaDataUpdate md =
+ new MetaDataUpdate(new NoReplication(), nameKey, git);
+ md.getCommitBuilder().setAuthor(serverUser);
+ md.getCommitBuilder().setCommitter(serverUser);
+
+ ProjectConfig config = ProjectConfig.read(md);
+ loadProject(rs, config.getProject());
+
+ md.setMessage("Import project configuration from SQL\n");
+ if (!config.commit(md)) {
+ throw new OrmException("Cannot export project " + name);
+ }
+ } catch (ConfigInvalidException err) {
+ throw new OrmException("Cannot read project " + name, err);
+ } catch (IOException err) {
+ throw new OrmException("Cannot export project " + name, err);
+ } finally {
+ git.close();
+ }
+ }
+ rs.close();
+ stmt.close();
+ }
+
+ private void loadProject(ResultSet rs, Project project) throws SQLException,
+ OrmException {
+ project.setDescription(rs.getString("description"));
+ project.setUseContributorAgreements("Y".equals(rs
+ .getString("use_contributor_agreements")));
+
+ switch (rs.getString("submit_type").charAt(0)) {
+ case 'F':
+ project.setSubmitType(Project.SubmitType.FAST_FORWARD_ONLY);
+ break;
+ case 'M':
+ project.setSubmitType(Project.SubmitType.MERGE_IF_NECESSARY);
+ break;
+ case 'A':
+ project.setSubmitType(Project.SubmitType.MERGE_ALWAYS);
+ break;
+ case 'C':
+ project.setSubmitType(Project.SubmitType.CHERRY_PICK);
+ break;
+ default:
+ throw new OrmException("Unsupported submit_type="
+ + rs.getString("submit_type") + " on project " + project.getName());
+ }
+
+ project.setUseSignedOffBy("Y".equals(rs.getString("use_signed_off_by")));
+ project.setRequireChangeID("Y".equals(rs.getString("require_change_id")));
+ project.setUseContentMerge("Y".equals(rs.getString("use_content_merge")));
+ project.setParentName(rs.getString("parent_name"));
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
index cf5d2643ed..58e645e9be 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
@@ -286,9 +286,10 @@ public class RefControlTest extends TestCase {
ProjectCache projectCache = null;
Project.NameKey wildProject = new Project.NameKey("-- All Projects --");
ProjectControl.AssistedFactory projectControlFactory = null;
+ Project project = new Project(parent);
ProjectState ps =
new ProjectState(anonymousUser, projectCache, wildProject,
- projectControlFactory, new Project(parent), localRights);
+ projectControlFactory, project, localRights);
ps.setInheritedRights(inheritedRights);
return ps;
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
index ee9af13add..3b847bfb4a 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
@@ -17,7 +17,6 @@ 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.RefRight;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
@@ -151,24 +150,6 @@ public class SchemaCreatorTest extends TestCase {
}
}
- public void testCreateSchema_WildCardProject() throws OrmException {
- final ReviewDb c = db.create().open();
- try {
- final SystemConfig cfg;
- final Project all;
-
- cfg = c.systemConfig().get(new SystemConfig.Key());
- all = c.projects().get(cfg.wildProjectName);
- assertNotNull(all);
- assertEquals("-- All Projects --", all.getName());
- assertFalse(all.isUseContributorAgreements());
- assertFalse(all.isUseSignedOffBy());
- assertFalse(all.isRequireChangeID());
- } finally {
- c.close();
- }
- }
-
public void testCreateSchema_ApprovalCategory_CodeReview()
throws OrmException {
final ReviewDb c = db.create().open();
@@ -347,18 +328,16 @@ public class SchemaCreatorTest extends TestCase {
final ReviewDb c = db.open();
try {
final SystemConfig cfg;
- final Project all;
final RefRight right;
cfg = c.systemConfig().get(new SystemConfig.Key());
- all = c.projects().get(cfg.wildProjectName);
right =
c.refRights().get(
- new RefRight.Key(all.getNameKey(), new RefRight.RefPattern(
+ new RefRight.Key(cfg.wildProjectName, new RefRight.RefPattern(
pattern), category, group));
assertNotNull(right);
- assertEquals(all.getNameKey(), right.getProjectNameKey());
+ assertEquals(cfg.wildProjectName, right.getProjectNameKey());
assertEquals(group, right.getAccountGroupId());
assertEquals(category, right.getApprovalCategoryId());
assertEquals(min, right.getMinValue());
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
index a009f24bb4..f2ba70e4a0 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
@@ -16,7 +16,12 @@ package com.google.gerrit.server.schema;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.GerritPersonIdentProvider;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
@@ -27,6 +32,9 @@ import com.google.inject.TypeLiteral;
import junit.framework.TestCase;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.PersonIdent;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
@@ -58,6 +66,22 @@ public class SchemaUpdaterTest extends TestCase {
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).toInstance(db);
bind(SitePaths.class).toInstance(paths);
install(new SchemaVersion.Module());
+
+ Config cfg = new Config();
+ cfg.setString("gerrit", null, "basePath", "git");
+ cfg.setString("user", null, "name", "Gerrit Code Review");
+ cfg.setString("user", null, "email", "gerrit@localhost");
+
+ bind(Config.class) //
+ .annotatedWith(GerritServerConfig.class) //
+ .toInstance(cfg);
+
+ bind(PersonIdent.class) //
+ .annotatedWith(GerritPersonIdent.class) //
+ .toProvider(GerritPersonIdentProvider.class);
+
+ bind(GitRepositoryManager.class) //
+ .to(LocalDiskRepositoryManager.class);
}
}).getInstance(SchemaUpdater.class);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
index fe138c6ef6..d95f17a4fd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
@@ -17,7 +17,13 @@ package com.google.gerrit.testutil;
import com.google.gerrit.reviewdb.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.GerritPersonIdentProvider;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SystemConfigProvider;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.schema.Current;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.schema.SchemaVersion;
@@ -25,13 +31,19 @@ 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 com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Key;
import com.google.inject.Provider;
import junit.framework.TestCase;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.PersonIdent;
+
import java.io.File;
+import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
@@ -84,8 +96,33 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
database = new Database<ReviewDb>(dataSource, ReviewDb.class);
schemaVersion =
- Guice.createInjector(new SchemaVersion.Module()).getBinding(
- Key.get(SchemaVersion.class, Current.class)).getProvider().get();
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ install(new SchemaVersion.Module());
+
+ bind(File.class) //
+ .annotatedWith(SitePath.class) //
+ .toInstance(new File("."));
+
+ Config cfg = new Config();
+ cfg.setString("gerrit", null, "basePath", "git");
+ cfg.setString("user", null, "name", "Gerrit Code Review");
+ cfg.setString("user", null, "email", "gerrit@localhost");
+
+ bind(Config.class) //
+ .annotatedWith(GerritServerConfig.class) //
+ .toInstance(cfg);
+
+ bind(PersonIdent.class) //
+ .annotatedWith(GerritPersonIdent.class) //
+ .toProvider(GerritPersonIdentProvider.class);
+
+ bind(GitRepositoryManager.class) //
+ .to(LocalDiskRepositoryManager.class);
+ }
+ }).getBinding(Key.get(SchemaVersion.class, Current.class))
+ .getProvider().get();
} catch (SQLException e) {
throw new OrmException(e);
}
@@ -106,7 +143,14 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
created = true;
final ReviewDb c = open();
try {
- new SchemaCreator(new File("."), schemaVersion).create(c);
+ try {
+ new SchemaCreator(new File("."), schemaVersion, null,
+ new PersonIdent("name", "email@site")).create(c);
+ } catch (IOException e) {
+ throw new OrmException("Cannot create in-memory database", e);
+ } catch (ConfigInvalidException e) {
+ throw new OrmException("Cannot create in-memory database", e);
+ }
} finally {
c.close();
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
index 07c573da3a..2f955b5aae 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
@@ -15,22 +15,24 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.config.WildProjectName;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.sshd.AdminCommand;
import com.google.gerrit.sshd.BaseCommand;
-import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
+import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -44,10 +46,10 @@ final class AdminSetParent extends BaseCommand {
private List<ProjectControl> children = new ArrayList<ProjectControl>();
@Inject
- private ReviewDb db;
+ private ProjectCache projectCache;
@Inject
- private ProjectCache projectCache;
+ private MetaDataUpdate.User metaDataUpdateFactory;
@Inject
@WildProjectName
@@ -64,7 +66,7 @@ final class AdminSetParent extends BaseCommand {
});
}
- private void updateParents() throws OrmException, UnloggedFailure {
+ private void updateParents() throws Failure {
final StringBuilder err = new StringBuilder();
final Set<Project.NameKey> grandParents = new HashSet<Project.NameKey>();
Project.NameKey newParentKey;
@@ -112,16 +114,25 @@ final class AdminSetParent extends BaseCommand {
continue;
}
- final Project child = db.projects().get(key);
- if (child == null) {
- // Race condition? Its in the cache, but not the database.
- //
- err.append("error: Project '" + name + "' not found\n");
- continue;
+ try {
+ MetaDataUpdate md = metaDataUpdateFactory.create(key);
+ try {
+ ProjectConfig config = ProjectConfig.read(md);
+ config.getProject().setParentName(newParentKey.get());
+ md.setMessage("Inherit access from " + newParentKey.get() + "\n");
+ if (!config.commit(md)) {
+ err.append("error: Could not update project " + name + "\n");
+ }
+ } finally {
+ md.close();
+ }
+ } catch (RepositoryNotFoundException notFound) {
+ err.append("error: Project " + name + " not found\n");
+ } catch (IOException e) {
+ throw new Failure(1, "Cannot update project " + name, e);
+ } catch (ConfigInvalidException e) {
+ throw new Failure(1, "Cannot update project " + name, e);
}
-
- child.setParent(newParentKey);
- db.projects().update(Collections.singleton(child));
}
// Invalidate all projects in cache since inherited rights were changed.
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java
index 103e753246..4dec3b7c39 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java
@@ -26,6 +26,8 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.ProjectCreatorGroups;
import com.google.gerrit.server.config.ProjectOwnerGroups;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
@@ -34,6 +36,7 @@ import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -49,7 +52,6 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -67,9 +69,6 @@ final class CreateProject extends BaseCommand {
@Option(name = "--parent", aliases = {"-p"}, metaVar = "NAME", usage = "parent project")
private ProjectControl newParent;
- @Option(name = "--permissions-only", usage = "create project for use only as parent")
- private boolean permissionsOnly;
-
@Option(name = "--description", aliases = {"-d"}, metaVar = "DESC", usage = "description of project")
private String projectDescription = "";
@@ -123,6 +122,9 @@ final class CreateProject extends BaseCommand {
@GerritPersonIdent
private PersonIdent serverIdent;
+ @Inject
+ MetaDataUpdate.User metaDataUpdateFactory;
+
private Project.NameKey nameKey;
@Override
@@ -138,34 +140,28 @@ final class CreateProject extends BaseCommand {
validateParameters();
nameKey = new Project.NameKey(projectName);
- if (!permissionsOnly) {
- final Repository repo = repoManager.createRepository(nameKey);
- try {
- RefUpdate u = repo.updateRef(Constants.HEAD);
- u.disableRefLog();
- u.link(branch);
-
- repoManager.setProjectDescription(nameKey, projectDescription);
+ final Repository repo = repoManager.createRepository(nameKey);
+ try {
+ RefUpdate u = repo.updateRef(Constants.HEAD);
+ u.disableRefLog();
+ u.link(branch);
- createProject();
-
- rq.replicateNewProject(nameKey, branch);
+ createProject();
+ repoManager.setProjectDescription(nameKey, projectDescription);
- if (createEmptyCommit) {
- createEmptyCommit(repo, nameKey, branch);
- }
- } finally {
- repo.close();
+ if (createEmptyCommit) {
+ createEmptyCommit(repo, nameKey, branch);
}
- } else {
- createProject();
+
+ rq.replicateNewProject(nameKey, branch);
+ } finally {
+ repo.close();
}
} catch (Exception e) {
p.print("Error when trying to create project: " + e.getMessage()
+ "\n");
p.flush();
}
-
}
});
}
@@ -176,9 +172,9 @@ final class CreateProject extends BaseCommand {
try {
CommitBuilder cb = new CommitBuilder();
cb.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[] {}));
+ cb.setAuthor(metaDataUpdateFactory.getUserPersonIdent());
cb.setCommitter(serverIdent);
- cb.setAuthor(cb.getCommitter());
- cb.setMessage("Initial empty repository");
+ cb.setMessage("Initial empty repository\n");
ObjectId id = oi.insert(cb);
oi.flush();
@@ -202,7 +198,9 @@ final class CreateProject extends BaseCommand {
}
}
- private void createProject() throws OrmException {
+ private void createProject() throws OrmException, IOException,
+ ConfigInvalidException {
+
List<RefRight> access = new ArrayList<RefRight>();
for (AccountGroup.Id ownerId : ownerIds) {
final RefRight.Key prk =
@@ -215,19 +213,30 @@ final class CreateProject extends BaseCommand {
}
db.refRights().insert(access);
- final Project newProject = new Project(nameKey);
- newProject.setDescription(projectDescription);
- newProject.setSubmitType(submitType);
- newProject.setUseContributorAgreements(contributorAgreements);
- newProject.setUseSignedOffBy(signedOffBy);
- newProject.setUseContentMerge(contentMerge);
- newProject.setRequireChangeID(requireChangeID);
- if (newParent != null) {
- newProject.setParent(newParent.getProject().getNameKey());
- }
+ Project.NameKey nameKey = new Project.NameKey(projectName);
+ MetaDataUpdate md = metaDataUpdateFactory.create(nameKey);
+ try {
+ ProjectConfig config = ProjectConfig.read(md);
+
+ Project newProject = config.getProject();
+ newProject.setDescription(projectDescription);
+ newProject.setSubmitType(submitType);
+ newProject.setUseContributorAgreements(contributorAgreements);
+ newProject.setUseSignedOffBy(signedOffBy);
+ newProject.setUseContentMerge(contentMerge);
+ newProject.setRequireChangeID(requireChangeID);
+ if (newParent != null) {
+ newProject.setParentName(newParent.getProject().getName());
+ }
- db.projects().insert(Collections.singleton(newProject));
- projectCache.onCreateProject(newProject.getNameKey());
+ md.setMessage("Created project\n");
+ if (!config.commit(md)) {
+ throw new IOException("Cannot create " + projectName);
+ }
+ } finally {
+ md.close();
+ }
+ projectCache.onCreateProject(nameKey);
}
private void validateParameters() throws Failure {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
index 342b62cc1d..b70b743844 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
@@ -16,7 +16,6 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.config.WildProjectName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
@@ -50,10 +49,6 @@ final class ListProjects extends BaseCommand {
@Inject
private GitRepositoryManager repoManager;
- @Inject
- @WildProjectName
- private Project.NameKey wildProject;
-
@Option(name = "--show-branch", aliases = {"-b"}, usage = "displays the sha of each project in the specified branch")
private String showBranch;
@@ -89,12 +84,6 @@ final class ListProjects extends BaseCommand {
try {
for (final Project.NameKey projectName : projectCache.all()) {
- if (projectName.equals(wildProject)) {
- // This project "doesn't exist". At least not as a repository.
- //
- continue;
- }
-
final ProjectState e = projectCache.get(projectName);
if (e == null) {
// If we can't get it from the cache, pretend its not present.
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
new file mode 100644
index 0000000000..3bbcc98e48
--- /dev/null
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
@@ -0,0 +1,61 @@
+// 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.httpd;
+
+import com.google.gerrit.reviewdb.ReviewDb;
+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 com.google.inject.Provider;
+
+import java.io.File;
+import java.util.List;
+
+/** Provides {@link java.io.File} annotated with {@link SitePath}. */
+class SitePathFromSystemConfigProvider implements Provider<File> {
+ private final File path;
+
+ @Inject
+ SitePathFromSystemConfigProvider(SchemaFactory<ReviewDb> schemaFactory)
+ throws OrmException {
+ path = read(schemaFactory);
+ }
+
+ @Override
+ public File get() {
+ return path;
+ }
+
+ private static File read(SchemaFactory<ReviewDb> schemaFactory)
+ throws OrmException {
+ ReviewDb db = schemaFactory.open();
+ try {
+ List<SystemConfig> all = db.systemConfig().all().toList();
+ switch (all.size()) {
+ case 1:
+ return new File(all.get(0).sitePath);
+ 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");
+ }
+ } finally {
+ db.close();
+ }
+ }
+}
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index 19c16ca91e..f1ac9454a1 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -25,9 +25,9 @@ import com.google.gerrit.server.config.GerritGlobalModule;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.MasterNodeStartup;
import com.google.gerrit.server.config.SitePath;
-import com.google.gerrit.server.config.SitePathFromSystemConfigProvider;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.DatabaseModule;
+import com.google.gerrit.server.schema.SchemaModule;
import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule;
import com.google.inject.AbstractModule;
@@ -166,6 +166,7 @@ public class WebAppInitializer extends GuiceServletContextListener {
});
modules.add(new GerritServerConfigModule());
}
+ modules.add(new SchemaModule());
modules.add(new AuthConfigModule());
return dbInjector.createChildInjector(modules);
}