Add All-Users project to store meta data for all users

This change adds a migration that creates an All-Users project for
storing meta data for all users. With this change no data is stored in
this repository yet, but future changes will e.g. store user
preferences in this repository by creating a ref per user.

Change-Id: Ib1ba5e4c2fb7a2f8e49d3bcf994c99d9e911475c
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin 2014-03-25 22:21:23 +01:00
parent b7e1b1d863
commit 2bf5eddb63
13 changed files with 246 additions and 2 deletions

View File

@ -1338,6 +1338,13 @@ relative to `gerrit.basePath`.
+ +
Defaults to `All-Projects` if not set. Defaults to `All-Projects` if not set.
[[gerrit.allUsers]]gerrit.allUsers::
+
Name of the project in which meta data of all users is stored.
The name is relative to `gerrit.basePath`.
+
Defaults to `All-Users` if not set.
[[gerrit.canonicalWebUrl]]gerrit.canonicalWebUrl:: [[gerrit.canonicalWebUrl]]gerrit.canonicalWebUrl::
+ +
The default URL for Gerrit to be accessed through. The default URL for Gerrit to be accessed through.

View File

@ -0,0 +1,36 @@
// Copyright (C) 2014 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.pgm.init;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class AllUsersNameOnInitProvider implements Provider<String> {
private final String name;
@Inject
AllUsersNameOnInitProvider(Section.Factory sections) {
String n = sections.get("gerrit", null).get("allUsers");
name = Objects.firstNonNull(
Strings.emptyToNull(n), AllUsersNameProvider.DEFAULT);
}
public String get() {
return name;
}
}

View File

@ -0,0 +1,25 @@
// Copyright (C) 2014 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.client.Project;
/** Special name of the project in which meta data for all users is stored. */
@SuppressWarnings("serial")
public class AllUsersName extends Project.NameKey {
public AllUsersName(String name) {
super(name);
}
}

View File

@ -0,0 +1,39 @@
// Copyright (C) 2014 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.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.lib.Config;
public class AllUsersNameProvider implements Provider<AllUsersName> {
public static final String DEFAULT = "All-Users";
private final AllUsersName name;
@Inject
AllUsersNameProvider(@GerritServerConfig Config cfg) {
String n = cfg.getString("gerrit", null, "allUsers");
if (n == null || n.isEmpty()) {
n = DEFAULT;
}
name = new AllUsersName(n);
}
public AllUsersName get() {
return name;
}
}

View File

@ -25,6 +25,9 @@ public interface ProjectCache {
/** @return the parent state for all projects on this server. */ /** @return the parent state for all projects on this server. */
public ProjectState getAllProjects(); public ProjectState getAllProjects();
/** @return the project state of the project storing meta data for all users. */
public ProjectState getAllUsers();
/** /**
* Get the cached data for a project by its unique name. * Get the cached data for a project by its unique name.
* *

View File

@ -22,6 +22,7 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -74,6 +75,7 @@ public class ProjectCacheImpl implements ProjectCache {
} }
private final AllProjectsName allProjectsName; private final AllProjectsName allProjectsName;
private final AllUsersName allUsersName;
private final LoadingCache<String, ProjectState> byName; private final LoadingCache<String, ProjectState> byName;
private final LoadingCache<ListKey, SortedSet<Project.NameKey>> list; private final LoadingCache<ListKey, SortedSet<Project.NameKey>> list;
private final Lock listLock; private final Lock listLock;
@ -82,10 +84,12 @@ public class ProjectCacheImpl implements ProjectCache {
@Inject @Inject
ProjectCacheImpl( ProjectCacheImpl(
final AllProjectsName allProjectsName, final AllProjectsName allProjectsName,
final AllUsersName allUsersName,
@Named(CACHE_NAME) LoadingCache<String, ProjectState> byName, @Named(CACHE_NAME) LoadingCache<String, ProjectState> byName,
@Named(CACHE_LIST) LoadingCache<ListKey, SortedSet<Project.NameKey>> list, @Named(CACHE_LIST) LoadingCache<ListKey, SortedSet<Project.NameKey>> list,
ProjectCacheClock clock) { ProjectCacheClock clock) {
this.allProjectsName = allProjectsName; this.allProjectsName = allProjectsName;
this.allUsersName = allUsersName;
this.byName = byName; this.byName = byName;
this.list = list; this.list = list;
this.listLock = new ReentrantLock(true /* fair */); this.listLock = new ReentrantLock(true /* fair */);
@ -103,6 +107,16 @@ public class ProjectCacheImpl implements ProjectCache {
return state; return state;
} }
@Override
public ProjectState getAllUsers() {
ProjectState state = get(allUsersName);
if (state == null) {
// This should never occur.
throw new IllegalStateException("Missing project " + allUsersName);
}
return state;
}
@Override @Override
public ProjectState get(final Project.NameKey projectName) { public ProjectState get(final Project.NameKey projectName) {
try { try {

View File

@ -0,0 +1,55 @@
// Copyright (C) 2014 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.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
/** Creates the {@code All-Users} repository. */
public class AllUsersCreator {
private final GitRepositoryManager mgr;
private final AllUsersName allUsersName;
@Inject
AllUsersCreator(GitRepositoryManager mgr, AllUsersName allUsersName) {
this.mgr = mgr;
this.allUsersName = allUsersName;
}
public void create() throws IOException, ConfigInvalidException {
Repository git = null;
try {
git = mgr.openRepository(allUsersName);
} catch (RepositoryNotFoundException notFound) {
try {
git = mgr.createRepository(allUsersName);
} catch (RepositoryNotFoundException err) {
String name = allUsersName.get();
throw new IOException("Cannot create repository " + name, err);
}
} finally {
if (git != null) {
git.close();
}
}
}
}

View File

@ -42,6 +42,7 @@ public class SchemaCreator {
File site_path; File site_path;
private final AllProjectsCreator allProjectsCreator; private final AllProjectsCreator allProjectsCreator;
private final AllUsersCreator allUsersCreator;
private final PersonIdent serverUser; private final PersonIdent serverUser;
private final DataSourceType dataSourceType; private final DataSourceType dataSourceType;
@ -54,18 +55,21 @@ public class SchemaCreator {
public SchemaCreator(SitePaths site, public SchemaCreator(SitePaths site,
@Current SchemaVersion version, @Current SchemaVersion version,
AllProjectsCreator ap, AllProjectsCreator ap,
AllUsersCreator auc,
@GerritPersonIdent PersonIdent au, @GerritPersonIdent PersonIdent au,
DataSourceType dst) { DataSourceType dst) {
this(site.site_path, version, ap, au, dst); this(site.site_path, version, ap, auc, au, dst);
} }
public SchemaCreator(@SitePath File site, public SchemaCreator(@SitePath File site,
@Current SchemaVersion version, @Current SchemaVersion version,
AllProjectsCreator ap, AllProjectsCreator ap,
AllUsersCreator auc,
@GerritPersonIdent PersonIdent au, @GerritPersonIdent PersonIdent au,
DataSourceType dst) { DataSourceType dst) {
site_path = site; site_path = site;
allProjectsCreator = ap; allProjectsCreator = ap;
allUsersCreator = auc;
serverUser = au; serverUser = au;
dataSourceType = dst; dataSourceType = dst;
versionNbr = version.getVersionNbr(); versionNbr = version.getVersionNbr();
@ -90,6 +94,7 @@ public class SchemaCreator {
.setAdministrators(GroupReference.forGroup(admin)) .setAdministrators(GroupReference.forGroup(admin))
.setBatchUsers(GroupReference.forGroup(batch)) .setBatchUsers(GroupReference.forGroup(batch))
.create(); .create();
allUsersCreator.create();
dataSourceType.getIndexScript().run(db); dataSourceType.getIndexScript().run(db);
} }

View File

@ -20,6 +20,8 @@ import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.GerritPersonIdentProvider; import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllProjectsNameProvider; import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.AnonymousCowardName; import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider; import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.FactoryModule; import com.google.gerrit.server.config.FactoryModule;
@ -39,6 +41,10 @@ public class SchemaModule extends FactoryModule {
.toProvider(AllProjectsNameProvider.class) .toProvider(AllProjectsNameProvider.class)
.in(SINGLETON); .in(SINGLETON);
bind(AllUsersName.class)
.toProvider(AllUsersNameProvider.class)
.in(SINGLETON);
bind(String.class).annotatedWith(AnonymousCowardName.class).toProvider( bind(String.class).annotatedWith(AnonymousCowardName.class).toProvider(
AnonymousCowardNameProvider.class); AnonymousCowardNameProvider.class);
} }

View File

@ -32,7 +32,7 @@ import java.util.List;
/** A version of the database schema. */ /** A version of the database schema. */
public abstract class SchemaVersion { public abstract class SchemaVersion {
/** The current schema version. */ /** The current schema version. */
public static final Class<Schema_94> C = Schema_94.class; public static final Class<Schema_95> C = Schema_95.class;
public static class Module extends AbstractModule { public static class Module extends AbstractModule {
@Override @Override

View File

@ -0,0 +1,45 @@
// Copyright (C) 2014 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.server.ReviewDb;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import java.io.IOException;
import java.sql.SQLException;
public class Schema_95 extends SchemaVersion {
private final AllUsersCreator allUsersCreator;
@Inject
Schema_95(Provider<Schema_94> prior, AllUsersCreator allUsersCreator) {
super(prior);
this.allUsersCreator = allUsersCreator;
}
@Override
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException,
SQLException {
try {
allUsersCreator.create();
} catch (IOException | ConfigInvalidException e) {
throw new OrmException(e);
}
}
}

View File

@ -155,6 +155,11 @@ public class Util {
return get(allProjectsName); return get(allProjectsName);
} }
@Override
public ProjectState getAllUsers() {
return null;
}
@Override @Override
public ProjectState get(Project.NameKey projectName) { public ProjectState get(Project.NameKey projectName) {
return all.get(projectName); return all.get(projectName);

View File

@ -29,6 +29,8 @@ import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
import com.google.gerrit.server.change.MergeabilityChecksExecutorModule; import com.google.gerrit.server.change.MergeabilityChecksExecutorModule;
import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllProjectsNameProvider; import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.AnonymousCowardName; import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider; import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.CanonicalWebUrlModule; import com.google.gerrit.server.config.CanonicalWebUrlModule;
@ -132,6 +134,8 @@ public class InMemoryModule extends FactoryModule {
.toProvider(AnonymousCowardNameProvider.class); .toProvider(AnonymousCowardNameProvider.class);
bind(AllProjectsName.class) bind(AllProjectsName.class)
.toProvider(AllProjectsNameProvider.class); .toProvider(AllProjectsNameProvider.class);
bind(AllUsersName.class)
.toProvider(AllUsersNameProvider.class);
bind(GitRepositoryManager.class) bind(GitRepositoryManager.class)
.to(InMemoryRepositoryManager.class); .to(InMemoryRepositoryManager.class);
bind(InMemoryRepositoryManager.class).in(SINGLETON); bind(InMemoryRepositoryManager.class).in(SINGLETON);