Merge branch 'master' into gwt-2.0

* master:
  Fix reading the $site_path/etc/ssh_host_key in serialized form
  Never compress a pid file under $site_path/logs
  Clean up the DWIMery for database.* configuration settings
  Completely remove GerritServer.properties
  Fix duplicate branches showing in the Branches tab
  Refactor GitRepositoryManager to be an interface

Conflicts:
	tools/gwtui_dbg.launch
	tools/gwtui_mac.launch

Change-Id: If50811015fa24804013338fa4261fc347c2a8812
This commit is contained in:
Shawn O. Pearce
2009-12-19 20:47:44 -08:00
26 changed files with 675 additions and 422 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
/.project /.project
/.settings/org.maven.ide.eclipse.prefs /.settings/org.maven.ide.eclipse.prefs
/GerritServer.properties
/test_site /test_site

View File

@@ -531,7 +531,7 @@ records about user accounts and change reviews.
---- ----
[database] [database]
type = postgres type = POSTGRESQL
hostname = localhost hostname = localhost
database = reviewdb database = reviewdb
username = gerrit2 username = gerrit2
@@ -544,17 +544,21 @@ Type of database server to connect to. If set this value will be
used to automatically create correct database.driver and database.url used to automatically create correct database.driver and database.url
values to open the connection. values to open the connection.
+ +
* `Postgres` or `PostgreSQL` * `POSTGRESQL`
+ +
Connect to a PostgreSQL database server. Connect to a PostgreSQL database server.
+ +
* `H2` * `H2`
+ +
Connect to a local (or remote) H2 database. Connect to a local embedded H2 database.
+ +
* `MySQL` * `MYSQL`
+ +
Connect to a MySQL database server. Connect to a MySQL database server.
+
* `JDBC`
+
Connect using a JDBC driver class name and URL.
+ +
If not specified, database.driver and database.url are used as-is, If not specified, database.driver and database.url are used as-is,
@@ -571,10 +575,10 @@ of the server named by database.type.
[[database.database]]database.database:: [[database.database]]database.database::
+ +
For PostgreSQL or MySQL, the name of the database on the server. For POSTGRESQL or MYSQL, the name of the database on the server.
+ +
For H2, this is the path to the database, and if not absolute is For H2, this is the path to the database, and if not absolute is
relative to `$site_path`. relative to `'$site_path'`.
[[database.username]]database.username:: [[database.username]]database.username::
+ +
@@ -586,13 +590,15 @@ Password to authenticate to the database server with.
[[database.driver]]database.driver:: [[database.driver]]database.driver::
+ +
Name of the JDBC driver class to connect to the database. Name of the JDBC driver class to connect to the database with.
Setting this usually isn't necessary, set database.type instead. Setting this usually isn't necessary as it can be derived from
database.type or database.url for any supported database.
[[database.url]]database.url:: [[database.url]]database.url::
+ +
JDBC style URL for the database. Setting this usually isn't 'jdbc:' URL for the database. Setting this variable usually
necessary, set database.type instead. isn't necessary as it can be constructed from the all of the
above properties.
[[gerrit]]Section gerrit [[gerrit]]Section gerrit

View File

@@ -82,9 +82,9 @@ Duplicate the existing `pgm_daemon` launch configuration:
* Modify the name to be unique. * Modify the name to be unique.
* Switch to Arguments tab. * Switch to Arguments tab.
* Edit the -d flag to match the path used during 'init'. The * Edit the `-d` program argument flag to match the path used during
template launch configuration resolves to ../test_site since 'init'. The template launch configuration resolves to ../test_site
that is what the documentation recommends. since that is what the documentation recommends.
* Switch to Common tab. * Switch to Common tab.
* Change Save as to be Local file. * Change Save as to be Local file.
@@ -93,12 +93,22 @@ Duplicate the existing `pgm_daemon` launch configuration:
Running Hosted Mode Running Hosted Mode
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
* Copy Duplicate the existing `gwtui_any` (or `gwtui_mac` if on Mac OS X)
`gerrit-war/src/main/webapp/WEB-INF/extra/GerritServer.properties_example` launch configuration:
to
`gerrit-parent/GerritServer.properties`. * Run -> Debug Configurations ...
* Edit to match your database parameters. * Java Application -> `gwtui_any`
* Run the `gwtui_any` or `gwtui_mac` launch configuration. * Right click, Duplicate
* Modify the name to be unique.
* Switch to Arguments tab.
* Edit the `-Dgerrit.site_path=` VM argument to match the path
used during 'init'. The template launch configuration resolves
to ../test_site since that is what the documentation recommends.
* Switch to Common tab.
* Change Save as to be Local file.
GERRIT GERRIT

View File

@@ -39,6 +39,11 @@ limitations under the License.
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.junit</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.google.gwt</groupId> <groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId> <artifactId>gwt-servlet</artifactId>

View File

@@ -34,7 +34,7 @@ import com.google.gerrit.httpd.GitWebConfig;
import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.SitePaths; 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.project.NoSuchProjectException; import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -77,12 +77,12 @@ class GitWebServlet extends HttpServlet {
private final Set<String> deniedActions; private final Set<String> deniedActions;
private final int bufferSize = 8192; private final int bufferSize = 8192;
private final File gitwebCgi; private final File gitwebCgi;
private final GitRepositoryManager repoManager; private final LocalDiskRepositoryManager repoManager;
private final ProjectControl.Factory projectControl; private final ProjectControl.Factory projectControl;
private final EnvList _env; private final EnvList _env;
@Inject @Inject
GitWebServlet(final GitRepositoryManager repoManager, GitWebServlet(final LocalDiskRepositoryManager repoManager,
final ProjectControl.Factory projectControl, final ProjectControl.Factory projectControl,
final SitePaths site, final GerritConfig gerritConfig, final SitePaths site, final GerritConfig gerritConfig,
final GitWebConfig gitWebConfig) throws IOException { final GitWebConfig gitWebConfig) throws IOException {

View File

@@ -64,6 +64,7 @@ class ListBranches extends Handler<List<Branch>> {
| ProjectControl.VISIBLE); | ProjectControl.VISIBLE);
final List<Branch> branches = new ArrayList<Branch>(); final List<Branch> branches = new ArrayList<Branch>();
Branch headBranch = null;
final Repository db = repoManager.openRepository(projectName.get()); final Repository db = repoManager.openRepository(projectName.get());
try { try {
final Map<String, Ref> all = db.getAllRefs(); final Map<String, Ref> all = db.getAllRefs();
@@ -84,14 +85,18 @@ class ListBranches extends Handler<List<Branch>> {
} }
for (final Ref ref : all.values()) { for (final Ref ref : all.values()) {
if (Constants.HEAD.equals(ref.getOrigName())) { if (Constants.HEAD.equals(ref.getOrigName())
final Branch b = createBranch(Constants.HEAD); && !ref.getOrigName().equals(ref.getName())) {
// HEAD is a symbolic reference to another branch, instead of
// showing the resolved value, show the name it references.
//
headBranch = createBranch(Constants.HEAD);
String target = ref.getName(); String target = ref.getName();
if (target.startsWith(Constants.R_HEADS)) { if (target.startsWith(Constants.R_HEADS)) {
target = target.substring(Constants.R_HEADS.length()); target = target.substring(Constants.R_HEADS.length());
} }
b.setRevision(new RevId(target)); headBranch.setRevision(new RevId(target));
branches.add(b); continue;
} }
if (ref.getName().startsWith(Constants.R_HEADS)) { if (ref.getName().startsWith(Constants.R_HEADS)) {
@@ -111,6 +116,9 @@ class ListBranches extends Handler<List<Branch>> {
return a.getName().compareTo(b.getName()); return a.getName().compareTo(b.getName());
} }
}); });
if (headBranch != null) {
branches.add(0, headBranch);
}
return branches; return branches;
} }

View File

@@ -0,0 +1,239 @@
// 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.rpc.project;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.classextension.EasyMock.createStrictMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import com.google.gerrit.reviewdb.Branch;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.server.StandardKeyEncoder;
import org.easymock.IExpectationSetters;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ListBranchesTest extends LocalDiskRepositoryTestCase {
static {
KeyUtil.setEncoderImpl(new StandardKeyEncoder());
}
private ObjectId idA;
private Project.NameKey name;
private Repository realDb;
private Repository mockDb;
private ProjectControl.Factory pcf;
private ProjectControl pc;
private GitRepositoryManager grm;
@Override
protected void setUp() throws Exception {
super.setUp();
idA = ObjectId.fromString("df84c2f4f7ce7e0b25cdeac84b8870bcff319885");
name = new Project.NameKey("test");
realDb = createBareRepository();
mockDb = createStrictMock(Repository.class);
pc = createStrictMock(ProjectControl.class);
pcf = createStrictMock(ProjectControl.Factory.class);
grm = createStrictMock(GitRepositoryManager.class);
}
private IExpectationSetters<ProjectControl> validate()
throws NoSuchProjectException {
return expect(pcf.validateFor(eq(name), //
eq(ProjectControl.OWNER | ProjectControl.VISIBLE)));
}
private void doReplay() {
replay(mockDb, pc, pcf, grm);
}
private void doVerify() {
verify(mockDb, pc, pcf, grm);
}
private void set(String branch, ObjectId id) throws IOException {
final RefUpdate u = realDb.updateRef(R_HEADS + branch);
u.setForceUpdate(true);
u.setNewObjectId(id);
switch (u.update()) {
case NEW:
case FAST_FORWARD:
case FORCED:
break;
default:
fail("unexpected update failure " + branch + " " + u.getResult());
}
}
public void testProjectNotVisible() throws Exception {
final NoSuchProjectException err = new NoSuchProjectException(name);
validate().andThrow(err);
doReplay();
try {
new ListBranches(pcf, grm, name).call();
fail("did not throw when expected not authorized");
} catch (NoSuchProjectException e2) {
assertSame(err, e2);
}
doVerify();
}
private List<Branch> permitted(boolean getFullBranch)
throws NoSuchProjectException, IOException {
validate().andReturn(pc);
expect(grm.openRepository(eq(name.get()))).andReturn(mockDb);
expect(mockDb.getAllRefs()).andDelegateTo(realDb);
if (getFullBranch) {
expect(mockDb.getFullBranch()).andDelegateTo(realDb);
}
mockDb.close();
expectLastCall();
doReplay();
final List<Branch> r = new ListBranches(pcf, grm, name).call();
doVerify();
assertNotNull(r);
return r;
}
public void testEmptyProject() throws Exception {
List<Branch> r = permitted(true);
assertEquals(1, r.size());
Branch b = r.get(0);
assertNotNull(b);
assertNotNull(b.getNameKey());
assertSame(name, b.getNameKey().getParentKey());
assertEquals(HEAD, b.getNameKey().get());
assertEquals(HEAD, b.getName());
assertEquals(HEAD, b.getShortName());
assertNotNull(b.getRevision());
assertEquals("master", b.getRevision().get());
}
public void testMasterBranch() throws Exception {
set("master", idA);
List<Branch> r = permitted(false);
assertEquals(2, r.size());
Branch b = r.get(0);
assertNotNull(b);
assertNotNull(b.getNameKey());
assertSame(name, b.getNameKey().getParentKey());
assertEquals(HEAD, b.getNameKey().get());
assertEquals(HEAD, b.getName());
assertEquals(HEAD, b.getShortName());
assertNotNull(b.getRevision());
assertEquals("master", b.getRevision().get());
b = r.get(1);
assertNotNull(b);
assertNotNull(b.getNameKey());
assertSame(name, b.getNameKey().getParentKey());
assertEquals(R_HEADS + "master", b.getNameKey().get());
assertEquals(R_HEADS + "master", b.getName());
assertEquals("master", b.getShortName());
assertNotNull(b.getRevision());
assertEquals(idA.name(), b.getRevision().get());
}
public void testBranchNotHead() throws Exception {
set("foo", idA);
List<Branch> r = permitted(true);
assertEquals(2, r.size());
Branch b = r.get(0);
assertNotNull(b);
assertNotNull(b.getNameKey());
assertSame(name, b.getNameKey().getParentKey());
assertEquals(HEAD, b.getNameKey().get());
assertEquals(HEAD, b.getName());
assertEquals(HEAD, b.getShortName());
assertNotNull(b.getRevision());
assertEquals("master", b.getRevision().get());
b = r.get(1);
assertNotNull(b);
assertNotNull(b.getNameKey());
assertSame(name, b.getNameKey().getParentKey());
assertEquals(R_HEADS + "foo", b.getNameKey().get());
assertEquals(R_HEADS + "foo", b.getName());
assertEquals("foo", b.getShortName());
assertNotNull(b.getRevision());
assertEquals(idA.name(), b.getRevision().get());
}
public void testSortByName() throws Exception {
Map<String, Ref> u = new LinkedHashMap<String, Ref>();
u.put("foo", new Ref(Ref.Storage.LOOSE, R_HEADS + "foo", idA));
u.put("bar", new Ref(Ref.Storage.LOOSE, R_HEADS + "bar", idA));
u.put(HEAD, new Ref(Ref.Storage.LOOSE, HEAD, R_HEADS + "master", null));
validate().andReturn(pc);
expect(grm.openRepository(eq(name.get()))).andReturn(mockDb);
expect(mockDb.getAllRefs()).andReturn(u);
mockDb.close();
expectLastCall();
doReplay();
final List<Branch> r = new ListBranches(pcf, grm, name).call();
doVerify();
assertNotNull(r);
assertEquals(3, r.size());
assertEquals(HEAD, r.get(0).getShortName());
assertEquals("bar", r.get(1).getShortName());
assertEquals("foo", r.get(2).getShortName());
}
}

View File

@@ -38,11 +38,6 @@ limitations under the License.
<artifactId>log4j</artifactId> <artifactId>log4j</artifactId>
</dependency> </dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>

View File

@@ -14,7 +14,7 @@
package com.google.gerrit.pgm; package com.google.gerrit.pgm;
import static com.google.gerrit.pgm.util.DataSourceProvider.Context.MULTI_USER; import static com.google.gerrit.server.schema.DataSourceProvider.Context.MULTI_USER;
import com.google.gerrit.httpd.HttpCanonicalWebUrlProvider; import com.google.gerrit.httpd.HttpCanonicalWebUrlProvider;
import com.google.gerrit.httpd.WebModule; import com.google.gerrit.httpd.WebModule;

View File

@@ -14,7 +14,7 @@
package com.google.gerrit.pgm; package com.google.gerrit.pgm;
import static com.google.gerrit.pgm.util.DataSourceProvider.Context.SINGLE_USER; import static com.google.gerrit.server.schema.DataSourceProvider.Context.SINGLE_USER;
import com.google.gerrit.lifecycle.LifecycleManager; import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.pgm.util.RuntimeShutdown; import com.google.gerrit.pgm.util.RuntimeShutdown;

View File

@@ -14,7 +14,7 @@
package com.google.gerrit.pgm; package com.google.gerrit.pgm;
import static com.google.gerrit.pgm.util.DataSourceProvider.Context.SINGLE_USER; import static com.google.gerrit.server.schema.DataSourceProvider.Context.SINGLE_USER;
import static com.google.inject.Stage.PRODUCTION; import static com.google.inject.Stage.PRODUCTION;
import com.google.gerrit.common.PageLinks; import com.google.gerrit.common.PageLinks;
@@ -30,6 +30,7 @@ import com.google.gerrit.pgm.util.IoUtil;
import com.google.gerrit.pgm.util.SiteProgram; import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.server.config.SitePath; import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.git.GitProjectImporter; import com.google.gerrit.server.git.GitProjectImporter;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.schema.SchemaUpdater; import com.google.gerrit.server.schema.SchemaUpdater;
@@ -176,13 +177,17 @@ public class Init extends SiteProgram {
void importGit() throws OrmException, IOException { void importGit() throws OrmException, IOException {
if (flags.importProjects) { if (flags.importProjects) {
System.err.println("Scanning " + repositoryManager.getBasePath());
gitProjectImporter.run(new GitProjectImporter.Messages() { gitProjectImporter.run(new GitProjectImporter.Messages() {
@Override @Override
public void warning(String msg) { public void info(String msg) {
System.err.println(msg); System.err.println(msg);
System.err.flush(); System.err.flush();
} }
@Override
public void warning(String msg) {
info(msg);
}
}); });
} }
} }
@@ -247,7 +252,7 @@ public class Init extends SiteProgram {
bind(ConsoleUI.class).toInstance(init.ui); bind(ConsoleUI.class).toInstance(init.ui);
bind(InitFlags.class).toInstance(init.flags); bind(InitFlags.class).toInstance(init.flags);
bind(GitRepositoryManager.class); bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
bind(GitProjectImporter.class); bind(GitProjectImporter.class);
} }
}); });

View File

@@ -16,11 +16,11 @@ package com.google.gerrit.pgm.init;
import static com.google.gerrit.pgm.init.InitUtil.die; import static com.google.gerrit.pgm.init.InitUtil.die;
import static com.google.gerrit.pgm.init.InitUtil.username; import static com.google.gerrit.pgm.init.InitUtil.username;
import static com.google.gerrit.pgm.util.DataSourceProvider.Type.H2; import static com.google.gerrit.server.schema.DataSourceProvider.Type.H2;
import com.google.gerrit.pgm.util.ConsoleUI; import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.pgm.util.DataSourceProvider;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@@ -82,7 +82,6 @@ class InitDatabase implements InitStep {
break; break;
} }
case POSTGRES:
case POSTGRESQL: case POSTGRESQL:
case MYSQL: { case MYSQL: {
userPassAuth = true; userPassAuth = true;

View File

@@ -19,8 +19,8 @@ import static com.google.gerrit.pgm.init.InitUtil.savePublic;
import static com.google.gerrit.pgm.init.InitUtil.saveSecure; import static com.google.gerrit.pgm.init.InitUtil.saveSecure;
import com.google.gerrit.pgm.util.ConsoleUI; import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.pgm.util.DataSourceProvider;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.util.SocketUtil; import com.google.gerrit.server.util.SocketUtil;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;

View File

@@ -96,7 +96,8 @@ public class LogFileCompressor implements Runnable {
private boolean isLive(final File entry) { private boolean isLive(final File entry) {
final String name = entry.getName(); final String name = entry.getName();
return ErrorLogFile.LOG_NAME.equals(name); return ErrorLogFile.LOG_NAME.equals(name) //
|| name.endsWith(".pid");
} }
private boolean isCompressed(final File entry) { private boolean isCompressed(final File entry) {

View File

@@ -21,6 +21,7 @@ import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.DatabaseModule; import com.google.gerrit.server.config.DatabaseModule;
import com.google.gerrit.server.config.GerritServerConfigModule; import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath; import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gwtorm.client.OrmException; import com.google.gwtorm.client.OrmException;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.CreationException; import com.google.inject.CreationException;

View File

@@ -48,6 +48,11 @@ limitations under the License.
<artifactId>ehcache-core</artifactId> <artifactId>ehcache-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
<dependency> <dependency>
<groupId>commons-net</groupId> <groupId>commons-net</groupId>
<artifactId>commons-net</artifactId> <artifactId>commons-net</artifactId>

View File

@@ -37,6 +37,7 @@ import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.auth.ldap.LdapModule; import com.google.gerrit.server.auth.ldap.LdapModule;
import com.google.gerrit.server.cache.CachePool; import com.google.gerrit.server.cache.CachePool;
import com.google.gerrit.server.git.ChangeMergeQueue; import com.google.gerrit.server.git.ChangeMergeQueue;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeOp; import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.git.MergeQueue; import com.google.gerrit.server.git.MergeQueue;
@@ -111,7 +112,7 @@ public class GerritGlobalModule extends FactoryModule {
factory(AccountInfoCacheFactory.Factory.class); factory(AccountInfoCacheFactory.Factory.class);
factory(ProjectState.Factory.class); factory(ProjectState.Factory.class);
bind(GitRepositoryManager.class); bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class); bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class);
bind(WorkQueue.class); bind(WorkQueue.class);
@@ -141,7 +142,7 @@ public class GerritGlobalModule extends FactoryModule {
install(new LifecycleModule() { install(new LifecycleModule() {
@Override @Override
protected void configure() { protected void configure() {
listener().to(GitRepositoryManager.Lifecycle.class); listener().to(LocalDiskRepositoryManager.Lifecycle.class);
listener().to(CachePool.Lifecycle.class); listener().to(CachePool.Lifecycle.class);
listener().to(WorkQueue.Lifecycle.class); listener().to(WorkQueue.Lifecycle.class);
} }

View File

@@ -32,15 +32,16 @@ import java.util.Set;
/** Imports all projects found within the repository manager. */ /** Imports all projects found within the repository manager. */
public class GitProjectImporter { public class GitProjectImporter {
public interface Messages { public interface Messages {
void info(String msg);
void warning(String msg); void warning(String msg);
} }
private final GitRepositoryManager repositoryManager; private final LocalDiskRepositoryManager repositoryManager;
private final SchemaFactory<ReviewDb> schema; private final SchemaFactory<ReviewDb> schema;
private Messages messages; private Messages messages;
@Inject @Inject
GitProjectImporter(final GitRepositoryManager repositoryManager, GitProjectImporter(final LocalDiskRepositoryManager repositoryManager,
final SchemaFactory<ReviewDb> schema) { final SchemaFactory<ReviewDb> schema) {
this.repositoryManager = repositoryManager; this.repositoryManager = repositoryManager;
this.schema = schema; this.schema = schema;
@@ -48,6 +49,7 @@ public class GitProjectImporter {
public void run(final Messages msg) throws OrmException, IOException { public void run(final Messages msg) throws OrmException, IOException {
messages = msg; messages = msg;
messages.info("Scanning " + repositoryManager.getBasePath());
final ReviewDb db = schema.open(); final ReviewDb db = schema.open();
try { try {
final HashSet<String> have = new HashSet<String>(); final HashSet<String> have = new HashSet<String>();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2008 The Android Open Source Project // Copyright (C) 2009 The Android Open Source Project
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -14,75 +14,22 @@
package com.google.gerrit.server.git; package com.google.gerrit.server.git;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.LockFile;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.WindowCache;
import org.eclipse.jgit.lib.WindowCacheConfig;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
/** Class managing Git repositories. */
@Singleton
public class GitRepositoryManager {
private static final Logger log =
LoggerFactory.getLogger(GitRepositoryManager.class);
private static final String UNNAMED =
"Unnamed repository; edit this file to name it for gitweb.";
public static class Lifecycle implements LifecycleListener {
private final Config cfg;
@Inject
Lifecycle(@GerritServerConfig final Config cfg) {
this.cfg = cfg;
}
@Override
public void start() {
final WindowCacheConfig c = new WindowCacheConfig();
c.fromConfig(cfg);
WindowCache.reconfigure(c);
}
@Override
public void stop() {
}
}
private final File basePath;
@Inject
GitRepositoryManager(final SitePaths site,
@GerritServerConfig final Config cfg) {
basePath = site.resolve(cfg.getString("gerrit", null, "basePath"));
if (basePath == null) {
throw new IllegalStateException("gerrit.basePath must be configured");
}
}
/** @return base directory under which all projects are stored. */
public File getBasePath() {
return basePath;
}
/**
* Manages Git repositories for the Gerrit server process.
* <p>
* Implementations of this interface should be a {@link Singleton} and
* registered in Guice so they are globally available within the server
* environment.
*/
public interface GitRepositoryManager {
/** /**
* Get (or open) a repository by name. * Get (or open) a repository by name.
* *
@@ -92,22 +39,8 @@ public class GitRepositoryManager {
* @throws RepositoryNotFoundException the name does not denote an existing * @throws RepositoryNotFoundException the name does not denote an existing
* repository, or the name cannot be read as a repository. * repository, or the name cannot be read as a repository.
*/ */
public Repository openRepository(String name) public abstract Repository openRepository(String name)
throws RepositoryNotFoundException { throws RepositoryNotFoundException;
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
try {
final FileKey loc = FileKey.lenient(new File(basePath, name));
return RepositoryCache.open(loc);
} catch (IOException e1) {
final RepositoryNotFoundException e2;
e2 = new RepositoryNotFoundException("Cannot open repository " + name);
e2.initCause(e1);
throw e2;
}
}
/** /**
* Create (and open) a repository by name. * Create (and open) a repository by name.
@@ -118,25 +51,8 @@ public class GitRepositoryManager {
* @throws RepositoryNotFoundException the name does not denote an existing * @throws RepositoryNotFoundException the name does not denote an existing
* repository, or the name cannot be read as a repository. * repository, or the name cannot be read as a repository.
*/ */
public Repository createRepository(String name) public abstract Repository createRepository(String name)
throws RepositoryNotFoundException { throws RepositoryNotFoundException;
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
try {
if (!name.endsWith(".git")) {
name = name + ".git";
}
final FileKey loc = FileKey.exact(new File(basePath, name));
return RepositoryCache.open(loc, false);
} catch (IOException e1) {
final RepositoryNotFoundException e2;
e2 = new RepositoryNotFoundException("Cannot open repository " + name);
e2.initCause(e1);
throw e2;
}
}
/** /**
* Read the {@code GIT_DIR/description} file for gitweb. * Read the {@code GIT_DIR/description} file for gitweb.
@@ -150,29 +66,8 @@ public class GitRepositoryManager {
* @throws IOException the description file exists, but is not readable by * @throws IOException the description file exists, but is not readable by
* this process. * this process.
*/ */
public String getProjectDescription(final String name) public abstract String getProjectDescription(final String name)
throws RepositoryNotFoundException, IOException { throws RepositoryNotFoundException, IOException;
final Repository e = openRepository(name);
final File d = new File(e.getDirectory(), "description");
String description;
try {
description = RawParseUtils.decode(IO.readFully(d));
} catch (FileNotFoundException err) {
return null;
}
if (description != null) {
description = description.trim();
if (description.isEmpty()) {
description = null;
}
if (UNNAMED.equals(description)) {
description = null;
}
}
return description;
}
/** /**
* Set the {@code GIT_DIR/description} file for gitweb. * Set the {@code GIT_DIR/description} file for gitweb.
@@ -183,48 +78,6 @@ public class GitRepositoryManager {
* @param name the repository name, relative to the base directory. * @param name the repository name, relative to the base directory.
* @param description new description text for the repository. * @param description new description text for the repository.
*/ */
public void setProjectDescription(final String name, final String description) { public abstract void setProjectDescription(final String name,
// Update git's description file, in case gitweb is being used final String description);
//
try {
final Repository e;
final LockFile f;
e = openRepository(name);
f = new LockFile(new File(e.getDirectory(), "description"));
if (f.lock()) {
String d = description;
if (d != null) {
d = d.trim();
if (d.length() > 0) {
d += "\n";
}
} else {
d = "";
}
f.write(Constants.encode(d));
f.commit();
}
e.close();
} catch (RepositoryNotFoundException e) {
log.error("Cannot update description for " + name, e);
} catch (IOException e) {
log.error("Cannot update description for " + name, e);
}
}
private boolean isUnreasonableName(final String name) {
if (name.length() == 0) return true; // no empty paths
if (name.indexOf('\\') >= 0) return true; // no windows/dos stlye paths
if (name.charAt(0) == '/') return true; // no absolute paths
if (new File(name).isAbsolute()) return true; // no absolute paths
if (name.startsWith("../")) return true; // no "l../etc/passwd"
if (name.contains("/../")) return true; // no "foo/../etc/passwd"
if (name.contains("/./")) return true; // "foo/./foo" is insane to ask
if (name.contains("//")) return true; // windows UNC path can be "//..."
return false; // is a reasonable name
}
} }

View File

@@ -0,0 +1,191 @@
// Copyright (C) 2008 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.lifecycle.LifecycleListener;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.LockFile;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.WindowCache;
import org.eclipse.jgit.lib.WindowCacheConfig;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/** Manages Git repositories stored on the local filesystem. */
@Singleton
public class LocalDiskRepositoryManager implements GitRepositoryManager {
private static final Logger log =
LoggerFactory.getLogger(LocalDiskRepositoryManager.class);
private static final String UNNAMED =
"Unnamed repository; edit this file to name it for gitweb.";
public static class Lifecycle implements LifecycleListener {
private final Config cfg;
@Inject
Lifecycle(@GerritServerConfig final Config cfg) {
this.cfg = cfg;
}
@Override
public void start() {
final WindowCacheConfig c = new WindowCacheConfig();
c.fromConfig(cfg);
WindowCache.reconfigure(c);
}
@Override
public void stop() {
}
}
private final File basePath;
@Inject
LocalDiskRepositoryManager(final SitePaths site,
@GerritServerConfig final Config cfg) {
basePath = site.resolve(cfg.getString("gerrit", null, "basePath"));
if (basePath == null) {
throw new IllegalStateException("gerrit.basePath must be configured");
}
}
/** @return base directory under which all projects are stored. */
public File getBasePath() {
return basePath;
}
public Repository openRepository(String name)
throws RepositoryNotFoundException {
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
try {
final FileKey loc = FileKey.lenient(new File(basePath, name));
return RepositoryCache.open(loc);
} catch (IOException e1) {
final RepositoryNotFoundException e2;
e2 = new RepositoryNotFoundException("Cannot open repository " + name);
e2.initCause(e1);
throw e2;
}
}
public Repository createRepository(String name)
throws RepositoryNotFoundException {
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
try {
if (!name.endsWith(".git")) {
name = name + ".git";
}
final FileKey loc = FileKey.exact(new File(basePath, name));
return RepositoryCache.open(loc, false);
} catch (IOException e1) {
final RepositoryNotFoundException e2;
e2 = new RepositoryNotFoundException("Cannot open repository " + name);
e2.initCause(e1);
throw e2;
}
}
public String getProjectDescription(final String name)
throws RepositoryNotFoundException, IOException {
final Repository e = openRepository(name);
final File d = new File(e.getDirectory(), "description");
String description;
try {
description = RawParseUtils.decode(IO.readFully(d));
} catch (FileNotFoundException err) {
return null;
}
if (description != null) {
description = description.trim();
if (description.isEmpty()) {
description = null;
}
if (UNNAMED.equals(description)) {
description = null;
}
}
return description;
}
public void setProjectDescription(final String name, final String description) {
// Update git's description file, in case gitweb is being used
//
try {
final Repository e;
final LockFile f;
e = openRepository(name);
f = new LockFile(new File(e.getDirectory(), "description"));
if (f.lock()) {
String d = description;
if (d != null) {
d = d.trim();
if (d.length() > 0) {
d += "\n";
}
} else {
d = "";
}
f.write(Constants.encode(d));
f.commit();
}
e.close();
} catch (RepositoryNotFoundException e) {
log.error("Cannot update description for " + name, e);
} catch (IOException e) {
log.error("Cannot update description for " + name, e);
}
}
private boolean isUnreasonableName(final String name) {
if (name.length() == 0) return true; // no empty paths
if (name.indexOf('\\') >= 0) return true; // no windows/dos stlye paths
if (name.charAt(0) == '/') return true; // no absolute paths
if (new File(name).isAbsolute()) return true; // no absolute paths
if (name.startsWith("../")) return true; // no "l../etc/passwd"
if (name.contains("/../")) return true; // no "foo/../etc/passwd"
if (name.contains("/./")) return true; // "foo/./foo" is insane to ask
if (name.contains("//")) return true; // windows UNC path can be "//..."
return false; // is a reasonable name
}
}

View File

@@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package com.google.gerrit.pgm.util; package com.google.gerrit.server.schema;
import static com.google.gerrit.server.config.ConfigUtil.getEnum;
import com.google.gerrit.lifecycle.LifecycleListener; import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gwtorm.jdbc.SimpleDataSource; import com.google.gwtorm.jdbc.SimpleDataSource;
@@ -71,132 +72,87 @@ public final class DataSourceProvider implements Provider<DataSource>,
} }
public static enum Type { public static enum Type {
DEFAULT, JDBC, POSTGRES, POSTGRESQL, H2, MYSQL; H2, POSTGRESQL, MYSQL, JDBC;
} }
private DataSource open(final SitePaths site, final Config cfg, private DataSource open(final SitePaths site, final Config cfg,
final Context context) { final Context context) {
Type type = ConfigUtil.getEnum(cfg, "database", null, "type", Type.DEFAULT); Type type = getEnum(cfg, "database", null, "type", Type.values(), null);
String driver = optional(cfg, "driver"); String driver = optional(cfg, "driver");
String url = optional(cfg, "url"); String url = optional(cfg, "url");
String username = optional(cfg, "username"); String username = optional(cfg, "username");
String password = optional(cfg, "password"); String password = optional(cfg, "password");
String hostname = optional(cfg, "hostname");
String port = optional(cfg, "port");
if (hostname == null) {
hostname = "localhost";
}
if (Type.DEFAULT == type && (driver == null || driver.isEmpty())) { if (url == null || url.isEmpty()) {
if (url != null && url.isEmpty()) { if (type == null) {
if (url != null && !url.isEmpty()) {
if (url.startsWith("jdbc:postgresql:")) { type = Type.JDBC;
type = Type.POSTGRES; } else {
} else if (url.startsWith("postgresql:")) {
url = "jdbc:" + url;
type = Type.POSTGRES;
} else if (url.startsWith("postgres:")) {
url = "jdbc:postgresql:" + url.substring(url.indexOf(':') + 1);
type = Type.POSTGRES;
} else if (url.startsWith("jdbc:h2:")) {
type = Type.H2;
} else if (url.startsWith("h2:")) {
url = "jdbc:" + url;
type = Type.H2;
} else if (url.startsWith("jdbc:mysql:")) {
type = Type.MYSQL;
} else if (url.startsWith("mysql:")) {
url = "jdbc:" + url;
type = Type.MYSQL;
}
} else if (url == null || url.isEmpty()) {
type = Type.H2; type = Type.H2;
} }
} }
switch (type) { switch (type) {
case POSTGRES:
case POSTGRESQL: {
final String pfx = "jdbc:postgresql://";
driver = "org.postgresql.Driver";
if (url == null) {
final StringBuilder b = new StringBuilder();
b.append(pfx);
b.append(hostname);
if (port != null && !port.isEmpty()) {
b.append(":");
b.append(port);
}
b.append("/");
b.append(required(cfg, "database"));
url = b.toString();
}
if (url == null || !url.startsWith(pfx)) {
throw new IllegalArgumentException("database.url must be " + pfx
+ " and not " + url);
}
break;
}
case H2: { case H2: {
final String pfx = "jdbc:h2:";
driver = "org.h2.Driver";
if (url == null) {
String database = optional(cfg, "database"); String database = optional(cfg, "database");
if (database == null || database.isEmpty()) { if (database == null || database.isEmpty()) {
database = "db/ReviewDB"; database = "db/ReviewDB";
} }
File db = site.resolve(database); File db = site.resolve(database);
try { try {
db = db.getCanonicalFile(); db = db.getCanonicalFile();
} catch (IOException e) { } catch (IOException e) {
db = db.getAbsoluteFile(); db = db.getAbsoluteFile();
} }
url = pfx + db.toURI().toString(); url = "jdbc:h2:" + db.toURI().toString();
} break;
if (url == null || !url.startsWith(pfx)) {
throw new IllegalArgumentException("database.url must be " + pfx
+ " and not " + url);
} }
case POSTGRESQL: {
final StringBuilder b = new StringBuilder();
b.append("jdbc:postgresql://");
b.append(hostname(optional(cfg, "hostname")));
b.append(port(optional(cfg, "port")));
b.append("/");
b.append(required(cfg, "database"));
url = b.toString();
break; break;
} }
case MYSQL: { case MYSQL: {
final String pfx = "jdbc:mysql://";
driver = "com.mysql.jdbc.Driver";
if (url == null) {
final StringBuilder b = new StringBuilder(); final StringBuilder b = new StringBuilder();
b.append(pfx); b.append("jdbc:mysql://");
b.append(hostname); b.append(hostname(optional(cfg, "hostname")));
if (port != null && !port.isEmpty()) { b.append(port(optional(cfg, "port")));
b.append(":");
b.append(port);
}
b.append("/"); b.append("/");
b.append(required(cfg, "database")); b.append(required(cfg, "database"));
url = b.toString(); url = b.toString();
}
if (url == null || !url.startsWith(pfx)) {
throw new IllegalArgumentException("database.url must be " + pfx
+ " and not " + url);
}
break; break;
} }
case DEFAULT:
case JDBC: case JDBC:
default:
driver = required(cfg, "driver"); driver = required(cfg, "driver");
url = required(cfg, "url"); url = required(cfg, "url");
if (!url.startsWith("jdbc:")) {
throw new IllegalArgumentException("database.url must be jdbc: style");
}
break; break;
default:
throw new IllegalArgumentException(type + " not supported");
}
}
if (driver == null || driver.isEmpty()) {
if (url.startsWith("jdbc:h2:")) {
driver = "org.h2.Driver";
} else if (url.startsWith("jdbc:postgresql:")) {
driver = "org.postgresql.Driver";
} else if (url.startsWith("jdbc:mysql:")) {
driver = "com.mysql.jdbc.Driver";
} else {
throw new IllegalArgumentException("database.driver must be set");
}
} }
boolean usePool; boolean usePool;
@@ -252,6 +208,23 @@ public final class DataSourceProvider implements Provider<DataSource>,
} }
} }
private static String hostname(String hostname) {
if (hostname == null || hostname.isEmpty()) {
hostname = "localhost";
} else if (hostname.contains(":") && !hostname.startsWith("[")) {
hostname = "[" + hostname + "]";
}
return hostname;
}
private static String port(String port) {
if (port != null && !port.isEmpty()) {
return ":" + port;
}
return "";
}
private static String optional(final Config config, final String name) { private static String optional(final Config config, final String name) {
return config.getString("database", null, name); return config.getString("database", null, name);
} }

View File

@@ -22,6 +22,7 @@ import com.google.inject.ProvisionException;
import org.apache.sshd.common.KeyPairProvider; import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider; import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.util.SecurityUtils; import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@@ -37,33 +38,42 @@ class HostKeyProvider implements Provider<KeyPairProvider> {
@Override @Override
public KeyPairProvider get() { public KeyPairProvider get() {
final File anyKey = site.ssh_key; final File objKey = site.ssh_key;
final File rsaKey = site.ssh_rsa; final File rsaKey = site.ssh_rsa;
final File dsaKey = site.ssh_dsa; final File dsaKey = site.ssh_dsa;
final List<String> keys = new ArrayList<String>(2); final List<String> stdKeys = new ArrayList<String>(2);
if (rsaKey.exists()) { if (rsaKey.exists()) {
keys.add(rsaKey.getAbsolutePath()); stdKeys.add(rsaKey.getAbsolutePath());
} }
if (dsaKey.exists()) { if (dsaKey.exists()) {
keys.add(dsaKey.getAbsolutePath()); stdKeys.add(dsaKey.getAbsolutePath());
} }
if (anyKey.exists() && !keys.isEmpty()) { if (objKey.exists()) {
// If both formats of host key exist, we don't know which format if (stdKeys.isEmpty()) {
SimpleGeneratorHostKeyProvider p = new SimpleGeneratorHostKeyProvider();
p.setPath(objKey.getAbsolutePath());
return p;
} else {
// Both formats of host key exist, we don't know which format
// should be authoritative. Complain and abort. // should be authoritative. Complain and abort.
// //
keys.add(anyKey.getAbsolutePath()); stdKeys.add(objKey.getAbsolutePath());
throw new ProvisionException("Multiple host keys exist: " + keys); throw new ProvisionException("Multiple host keys exist: " + stdKeys);
} }
if (keys.isEmpty()) { } else {
if (stdKeys.isEmpty()) {
throw new ProvisionException("No SSH keys under " + site.etc_dir); throw new ProvisionException("No SSH keys under " + site.etc_dir);
} }
if (!SecurityUtils.isBouncyCastleRegistered()) { if (!SecurityUtils.isBouncyCastleRegistered()) {
throw new ProvisionException("Bouncy Castle Crypto not installed;" throw new ProvisionException("Bouncy Castle Crypto not installed;"
+ " needed to read server host keys: " + keys + ""); + " needed to read server host keys: " + stdKeys + "");
}
return new FileKeyPairProvider(stdKeys
.toArray(new String[stdKeys.size()]));
} }
return new FileKeyPairProvider(keys.toArray(new String[keys.size()]));
} }
} }

View File

@@ -15,18 +15,10 @@
package com.google.gerrit.httpd; package com.google.gerrit.httpd;
import com.google.gerrit.lifecycle.LifecycleListener; import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gwtorm.jdbc.SimpleDataSource;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.ProvisionException; import com.google.inject.ProvisionException;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.sql.DataSource; import javax.sql.DataSource;
@@ -61,47 +53,8 @@ final class ReviewDbDataSourceProvider implements Provider<DataSource>,
try { try {
return (DataSource) new InitialContext().lookup(dsName); return (DataSource) new InitialContext().lookup(dsName);
} catch (NamingException namingErr) { } catch (NamingException namingErr) {
final Properties p = readGerritDataSource(); throw new ProvisionException("No DataSource " + dsName, namingErr);
if (p == null) {
throw new ProvisionException("Initialization error:\n"
+ " * No DataSource " + dsName + "\n"
+ " * No -DGerritServer=GerritServer.properties"
+ " on Java command line", namingErr);
} }
try {
return new SimpleDataSource(p);
} catch (SQLException se) {
throw new ProvisionException("Database unavailable", se);
}
}
}
private static Properties readGerritDataSource() throws ProvisionException {
final Properties srvprop = new Properties();
String name = System.getProperty("GerritServer");
if (name == null) {
name = "GerritServer.properties";
}
try {
final InputStream in = new FileInputStream(name);
try {
srvprop.load(in);
} finally {
in.close();
}
} catch (IOException e) {
throw new ProvisionException("Cannot read " + name, e);
}
final Properties dbprop = new Properties();
for (final Map.Entry<Object, Object> e : srvprop.entrySet()) {
final String key = (String) e.getKey();
if (key.startsWith("database.")) {
dbprop.put(key.substring("database.".length()), e.getValue());
}
}
return dbprop;
} }
private void closeDataSource(final DataSource ds) { private void closeDataSource(final DataSource ds) {

View File

@@ -27,6 +27,7 @@ import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.MasterNodeStartup; import com.google.gerrit.server.config.MasterNodeStartup;
import com.google.gerrit.server.config.SitePath; import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePathFromSystemConfigProvider; import com.google.gerrit.server.config.SitePathFromSystemConfigProvider;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.sshd.SshModule; import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule; import com.google.gerrit.sshd.commands.MasterCommandModule;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
@@ -57,6 +58,7 @@ public class WebAppInitializer extends GuiceServletContextListener {
private static final Logger log = private static final Logger log =
LoggerFactory.getLogger(WebAppInitializer.class); LoggerFactory.getLogger(WebAppInitializer.class);
private File sitePath;
private Injector dbInjector; private Injector dbInjector;
private Injector cfgInjector; private Injector cfgInjector;
private Injector sysInjector; private Injector sysInjector;
@@ -66,6 +68,11 @@ public class WebAppInitializer extends GuiceServletContextListener {
private synchronized void init() { private synchronized void init() {
if (manager == null) { if (manager == null) {
final String path = System.getProperty("gerrit.site_path");
if (path != null) {
sitePath = new File(path);
}
try { try {
dbInjector = createDbInjector(); dbInjector = createDbInjector();
} catch (CreationException ce) { } catch (CreationException ce) {
@@ -115,6 +122,21 @@ public class WebAppInitializer extends GuiceServletContextListener {
private Injector createDbInjector() { private Injector createDbInjector() {
final List<Module> modules = new ArrayList<Module>(); final List<Module> modules = new ArrayList<Module>();
if (sitePath != null) {
modules.add(new LifecycleModule() {
@Override
protected void configure() {
bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
bind(DataSourceProvider.Context.class).toInstance(
DataSourceProvider.Context.MULTI_USER);
bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider(
DataSourceProvider.class).in(SINGLETON);
listener().to(DataSourceProvider.class);
}
});
modules.add(new GerritServerConfigModule());
} else {
modules.add(new LifecycleModule() { modules.add(new LifecycleModule() {
@Override @Override
protected void configure() { protected void configure() {
@@ -123,12 +145,18 @@ public class WebAppInitializer extends GuiceServletContextListener {
listener().to(ReviewDbDataSourceProvider.class); listener().to(ReviewDbDataSourceProvider.class);
} }
}); });
}
modules.add(new DatabaseModule()); modules.add(new DatabaseModule());
return Guice.createInjector(PRODUCTION, modules); return Guice.createInjector(PRODUCTION, modules);
} }
private Injector createCfgInjector() { private Injector createCfgInjector() {
final List<Module> modules = new ArrayList<Module>(); final List<Module> modules = new ArrayList<Module>();
if (sitePath == null) {
// If we didn't get the site path from the system property
// we need to get it from the database, as that's our old
// method of locating the site path on disk.
//
modules.add(new AbstractModule() { modules.add(new AbstractModule() {
@Override @Override
protected void configure() { protected void configure() {
@@ -137,6 +165,7 @@ public class WebAppInitializer extends GuiceServletContextListener {
} }
}); });
modules.add(new GerritServerConfigModule()); modules.add(new GerritServerConfigModule());
}
modules.add(new AuthConfigModule()); modules.add(new AuthConfigModule());
return dbInjector.createChildInjector(modules); return dbInjector.createChildInjector(modules);
} }

View File

@@ -1,32 +0,0 @@
# Any properties starting with "database." will be fed to the JDBC driver,
# after removing the "database." prefix.
#
# The following "special" properties are removed from that set:
#
# database.driver : Class name of the driver to load.
# database.url : The connection URL
#
# H2
# (driver included)
#
# database.driver = org.h2.Driver
# database.url = jdbc:h2:file:ReviewDb
# PostgreSQL
# (driver included)
#
# database.driver = org.postgresql.Driver
# database.url = jdbc:postgresql:reviewdb
# database.user = gerrit2
# database.password = supersecretcode
# MySQL 5.0
# curl -O http://repo1.maven.org/maven2/mysql/mysql-connector-java/5.0.8/mysql-connector-java-5.0.8.jar
#
# database.classpath = mysql-connector-java-5.0.8.jar
# database.driver = com.mysql.jdbc.Driver
# database.url = jdbc:mysql://localhost/reviewdb?user=gerrit2&password=secretcode

View File

@@ -31,5 +31,5 @@
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl /&#10;-war ${resource_loc:/gerrit-gwtui/target}/gwt-hosted-mode&#10;-server com.google.gerrit.gwtdebug.GerritDebugLauncher&#10;com.google.gerrit.GerritGwtUI"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl /&#10;-war ${resource_loc:/gerrit-gwtui/target}/gwt-hosted-mode&#10;-server com.google.gerrit.gwtdebug.GerritDebugLauncher&#10;com.google.gerrit.GerritGwtUI"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="gerrit-gwtdbug"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="gerrit-gwtdbug"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.maven.ide.eclipse.launchconfig.sourcepathProvider"/> <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.maven.ide.eclipse.launchconfig.sourcepathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256M&#10;-DGerritServer=${resource_loc:/gerrit-parent/GerritServer.properties}"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256M&#10;&#10;-Dgerrit.site_path=${resource_loc:/gerrit-parent}/../test_site"/>
</launchConfiguration> </launchConfiguration>