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:
commit
725fed4269
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
/.project
|
||||
/.settings/org.maven.ide.eclipse.prefs
|
||||
/GerritServer.properties
|
||||
/test_site
|
||||
|
@ -531,7 +531,7 @@ records about user accounts and change reviews.
|
||||
|
||||
----
|
||||
[database]
|
||||
type = postgres
|
||||
type = POSTGRESQL
|
||||
hostname = localhost
|
||||
database = reviewdb
|
||||
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
|
||||
values to open the connection.
|
||||
+
|
||||
* `Postgres` or `PostgreSQL`
|
||||
* `POSTGRESQL`
|
||||
+
|
||||
Connect to a PostgreSQL database server.
|
||||
+
|
||||
* `H2`
|
||||
+
|
||||
Connect to a local (or remote) H2 database.
|
||||
Connect to a local embedded H2 database.
|
||||
+
|
||||
* `MySQL`
|
||||
* `MYSQL`
|
||||
+
|
||||
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,
|
||||
@ -571,10 +575,10 @@ of the server named by database.type.
|
||||
|
||||
[[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
|
||||
relative to `$site_path`.
|
||||
relative to `'$site_path'`.
|
||||
|
||||
[[database.username]]database.username::
|
||||
+
|
||||
@ -586,13 +590,15 @@ Password to authenticate to the database server with.
|
||||
|
||||
[[database.driver]]database.driver::
|
||||
+
|
||||
Name of the JDBC driver class to connect to the database.
|
||||
Setting this usually isn't necessary, set database.type instead.
|
||||
Name of the JDBC driver class to connect to the database with.
|
||||
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::
|
||||
+
|
||||
JDBC style URL for the database. Setting this usually isn't
|
||||
necessary, set database.type instead.
|
||||
'jdbc:' URL for the database. Setting this variable usually
|
||||
isn't necessary as it can be constructed from the all of the
|
||||
above properties.
|
||||
|
||||
|
||||
[[gerrit]]Section gerrit
|
||||
|
@ -82,9 +82,9 @@ Duplicate the existing `pgm_daemon` launch configuration:
|
||||
* Modify the name to be unique.
|
||||
|
||||
* Switch to Arguments tab.
|
||||
* Edit the -d flag to match the path used during 'init'. The
|
||||
template launch configuration resolves to ../test_site since
|
||||
that is what the documentation recommends.
|
||||
* Edit the `-d` program argument flag 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.
|
||||
@ -93,12 +93,22 @@ Duplicate the existing `pgm_daemon` launch configuration:
|
||||
Running Hosted Mode
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Copy
|
||||
`gerrit-war/src/main/webapp/WEB-INF/extra/GerritServer.properties_example`
|
||||
to
|
||||
`gerrit-parent/GerritServer.properties`.
|
||||
* Edit to match your database parameters.
|
||||
* Run the `gwtui_any` or `gwtui_mac` launch configuration.
|
||||
Duplicate the existing `gwtui_any` (or `gwtui_mac` if on Mac OS X)
|
||||
launch configuration:
|
||||
|
||||
* Run -> Debug Configurations ...
|
||||
* Java Application -> `gwtui_any`
|
||||
* 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
|
||||
|
@ -39,6 +39,11 @@ limitations under the License.
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit.junit</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.gwt</groupId>
|
||||
<artifactId>gwt-servlet</artifactId>
|
||||
|
@ -34,7 +34,7 @@ import com.google.gerrit.httpd.GitWebConfig;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
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.ProjectControl;
|
||||
import com.google.inject.Inject;
|
||||
@ -77,12 +77,12 @@ class GitWebServlet extends HttpServlet {
|
||||
private final Set<String> deniedActions;
|
||||
private final int bufferSize = 8192;
|
||||
private final File gitwebCgi;
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final LocalDiskRepositoryManager repoManager;
|
||||
private final ProjectControl.Factory projectControl;
|
||||
private final EnvList _env;
|
||||
|
||||
@Inject
|
||||
GitWebServlet(final GitRepositoryManager repoManager,
|
||||
GitWebServlet(final LocalDiskRepositoryManager repoManager,
|
||||
final ProjectControl.Factory projectControl,
|
||||
final SitePaths site, final GerritConfig gerritConfig,
|
||||
final GitWebConfig gitWebConfig) throws IOException {
|
||||
|
@ -64,6 +64,7 @@ class ListBranches extends Handler<List<Branch>> {
|
||||
| ProjectControl.VISIBLE);
|
||||
|
||||
final List<Branch> branches = new ArrayList<Branch>();
|
||||
Branch headBranch = null;
|
||||
final Repository db = repoManager.openRepository(projectName.get());
|
||||
try {
|
||||
final Map<String, Ref> all = db.getAllRefs();
|
||||
@ -84,14 +85,18 @@ class ListBranches extends Handler<List<Branch>> {
|
||||
}
|
||||
|
||||
for (final Ref ref : all.values()) {
|
||||
if (Constants.HEAD.equals(ref.getOrigName())) {
|
||||
final Branch b = createBranch(Constants.HEAD);
|
||||
if (Constants.HEAD.equals(ref.getOrigName())
|
||||
&& !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();
|
||||
if (target.startsWith(Constants.R_HEADS)) {
|
||||
target = target.substring(Constants.R_HEADS.length());
|
||||
}
|
||||
b.setRevision(new RevId(target));
|
||||
branches.add(b);
|
||||
headBranch.setRevision(new RevId(target));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ref.getName().startsWith(Constants.R_HEADS)) {
|
||||
@ -111,6 +116,9 @@ class ListBranches extends Handler<List<Branch>> {
|
||||
return a.getName().compareTo(b.getName());
|
||||
}
|
||||
});
|
||||
if (headBranch != null) {
|
||||
branches.add(0, headBranch);
|
||||
}
|
||||
return branches;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -38,11 +38,6 @@ limitations under the License.
|
||||
<artifactId>log4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
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.WebModule;
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
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.pgm.util.RuntimeShutdown;
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
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 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.server.config.SitePath;
|
||||
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.GitRepositoryManager;
|
||||
import com.google.gerrit.server.schema.SchemaUpdater;
|
||||
@ -176,13 +177,17 @@ public class Init extends SiteProgram {
|
||||
|
||||
void importGit() throws OrmException, IOException {
|
||||
if (flags.importProjects) {
|
||||
System.err.println("Scanning " + repositoryManager.getBasePath());
|
||||
gitProjectImporter.run(new GitProjectImporter.Messages() {
|
||||
@Override
|
||||
public void warning(String msg) {
|
||||
public void info(String msg) {
|
||||
System.err.println(msg);
|
||||
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(InitFlags.class).toInstance(init.flags);
|
||||
|
||||
bind(GitRepositoryManager.class);
|
||||
bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
|
||||
bind(GitProjectImporter.class);
|
||||
}
|
||||
});
|
||||
|
@ -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.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.DataSourceProvider;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.schema.DataSourceProvider;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@ -82,7 +82,6 @@ class InitDatabase implements InitStep {
|
||||
break;
|
||||
}
|
||||
|
||||
case POSTGRES:
|
||||
case POSTGRESQL:
|
||||
case MYSQL: {
|
||||
userPassAuth = true;
|
||||
|
@ -19,8 +19,8 @@ import static com.google.gerrit.pgm.init.InitUtil.savePublic;
|
||||
import static com.google.gerrit.pgm.init.InitUtil.saveSecure;
|
||||
|
||||
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.schema.DataSourceProvider;
|
||||
import com.google.gerrit.server.util.SocketUtil;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
@ -96,7 +96,8 @@ public class LogFileCompressor implements Runnable {
|
||||
|
||||
private boolean isLive(final File entry) {
|
||||
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) {
|
||||
|
@ -21,6 +21,7 @@ import com.google.gerrit.lifecycle.LifecycleModule;
|
||||
import com.google.gerrit.server.config.DatabaseModule;
|
||||
import com.google.gerrit.server.config.GerritServerConfigModule;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.schema.DataSourceProvider;
|
||||
import com.google.gwtorm.client.OrmException;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.CreationException;
|
||||
|
@ -48,6 +48,11 @@ limitations under the License.
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
|
@ -37,6 +37,7 @@ import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.auth.ldap.LdapModule;
|
||||
import com.google.gerrit.server.cache.CachePool;
|
||||
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.MergeOp;
|
||||
import com.google.gerrit.server.git.MergeQueue;
|
||||
@ -111,7 +112,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
factory(AccountInfoCacheFactory.Factory.class);
|
||||
factory(ProjectState.Factory.class);
|
||||
|
||||
bind(GitRepositoryManager.class);
|
||||
bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
|
||||
bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class);
|
||||
bind(WorkQueue.class);
|
||||
|
||||
@ -141,7 +142,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
install(new LifecycleModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
listener().to(GitRepositoryManager.Lifecycle.class);
|
||||
listener().to(LocalDiskRepositoryManager.Lifecycle.class);
|
||||
listener().to(CachePool.Lifecycle.class);
|
||||
listener().to(WorkQueue.Lifecycle.class);
|
||||
}
|
||||
|
@ -32,15 +32,16 @@ import java.util.Set;
|
||||
/** Imports all projects found within the repository manager. */
|
||||
public class GitProjectImporter {
|
||||
public interface Messages {
|
||||
void info(String msg);
|
||||
void warning(String msg);
|
||||
}
|
||||
|
||||
private final GitRepositoryManager repositoryManager;
|
||||
private final LocalDiskRepositoryManager repositoryManager;
|
||||
private final SchemaFactory<ReviewDb> schema;
|
||||
private Messages messages;
|
||||
|
||||
@Inject
|
||||
GitProjectImporter(final GitRepositoryManager repositoryManager,
|
||||
GitProjectImporter(final LocalDiskRepositoryManager repositoryManager,
|
||||
final SchemaFactory<ReviewDb> schema) {
|
||||
this.repositoryManager = repositoryManager;
|
||||
this.schema = schema;
|
||||
@ -48,6 +49,7 @@ public class GitProjectImporter {
|
||||
|
||||
public void run(final Messages msg) throws OrmException, IOException {
|
||||
messages = msg;
|
||||
messages.info("Scanning " + repositoryManager.getBasePath());
|
||||
final ReviewDb db = schema.open();
|
||||
try {
|
||||
final HashSet<String> have = new HashSet<String>();
|
||||
|
@ -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");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -14,75 +14,22 @@
|
||||
|
||||
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;
|
||||
|
||||
/** 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.
|
||||
*
|
||||
@ -92,22 +39,8 @@ public class GitRepositoryManager {
|
||||
* @throws RepositoryNotFoundException the name does not denote an existing
|
||||
* repository, or the name cannot be read as a repository.
|
||||
*/
|
||||
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 abstract Repository openRepository(String name)
|
||||
throws RepositoryNotFoundException;
|
||||
|
||||
/**
|
||||
* Create (and open) a repository by name.
|
||||
@ -118,25 +51,8 @@ public class GitRepositoryManager {
|
||||
* @throws RepositoryNotFoundException the name does not denote an existing
|
||||
* repository, or the name cannot be read as a repository.
|
||||
*/
|
||||
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 abstract Repository createRepository(String name)
|
||||
throws RepositoryNotFoundException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* this process.
|
||||
*/
|
||||
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 abstract String getProjectDescription(final String name)
|
||||
throws RepositoryNotFoundException, IOException;
|
||||
|
||||
/**
|
||||
* 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 description new description text for the repository.
|
||||
*/
|
||||
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
|
||||
}
|
||||
public abstract void setProjectDescription(final String name,
|
||||
final String description);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -12,10 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// 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.server.config.ConfigUtil;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gwtorm.jdbc.SimpleDataSource;
|
||||
@ -71,132 +72,87 @@ public final class DataSourceProvider implements Provider<DataSource>,
|
||||
}
|
||||
|
||||
public static enum Type {
|
||||
DEFAULT, JDBC, POSTGRES, POSTGRESQL, H2, MYSQL;
|
||||
H2, POSTGRESQL, MYSQL, JDBC;
|
||||
}
|
||||
|
||||
private DataSource open(final SitePaths site, final Config cfg,
|
||||
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 url = optional(cfg, "url");
|
||||
String username = optional(cfg, "username");
|
||||
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.startsWith("jdbc:postgresql:")) {
|
||||
type = Type.POSTGRES;
|
||||
} 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:")) {
|
||||
if (url == null || url.isEmpty()) {
|
||||
if (type == null) {
|
||||
if (url != null && !url.isEmpty()) {
|
||||
type = Type.JDBC;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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: {
|
||||
final String pfx = "jdbc:h2:";
|
||||
driver = "org.h2.Driver";
|
||||
if (url == null) {
|
||||
switch (type) {
|
||||
case H2: {
|
||||
String database = optional(cfg, "database");
|
||||
if (database == null || database.isEmpty()) {
|
||||
database = "db/ReviewDB";
|
||||
}
|
||||
|
||||
File db = site.resolve(database);
|
||||
try {
|
||||
db = db.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MYSQL: {
|
||||
final String pfx = "jdbc:mysql://";
|
||||
driver = "com.mysql.jdbc.Driver";
|
||||
if (url == null) {
|
||||
case POSTGRESQL: {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
b.append(pfx);
|
||||
b.append(hostname);
|
||||
if (port != null && !port.isEmpty()) {
|
||||
b.append(":");
|
||||
b.append(port);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (url == null || !url.startsWith(pfx)) {
|
||||
throw new IllegalArgumentException("database.url must be " + pfx
|
||||
+ " and not " + url);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DEFAULT:
|
||||
case JDBC:
|
||||
default:
|
||||
driver = required(cfg, "driver");
|
||||
url = required(cfg, "url");
|
||||
if (!url.startsWith("jdbc:")) {
|
||||
throw new IllegalArgumentException("database.url must be jdbc: style");
|
||||
case MYSQL: {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
b.append("jdbc:mysql://");
|
||||
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 JDBC:
|
||||
driver = required(cfg, "driver");
|
||||
url = required(cfg, "url");
|
||||
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;
|
||||
@ -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) {
|
||||
return config.getString("database", null, name);
|
||||
}
|
@ -22,6 +22,7 @@ import com.google.inject.ProvisionException;
|
||||
import org.apache.sshd.common.KeyPairProvider;
|
||||
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
|
||||
import org.apache.sshd.common.util.SecurityUtils;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@ -37,33 +38,42 @@ class HostKeyProvider implements Provider<KeyPairProvider> {
|
||||
|
||||
@Override
|
||||
public KeyPairProvider get() {
|
||||
final File anyKey = site.ssh_key;
|
||||
final File objKey = site.ssh_key;
|
||||
final File rsaKey = site.ssh_rsa;
|
||||
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()) {
|
||||
keys.add(rsaKey.getAbsolutePath());
|
||||
stdKeys.add(rsaKey.getAbsolutePath());
|
||||
}
|
||||
if (dsaKey.exists()) {
|
||||
keys.add(dsaKey.getAbsolutePath());
|
||||
stdKeys.add(dsaKey.getAbsolutePath());
|
||||
}
|
||||
|
||||
if (anyKey.exists() && !keys.isEmpty()) {
|
||||
// If both formats of host key exist, we don't know which format
|
||||
// should be authoritative. Complain and abort.
|
||||
//
|
||||
keys.add(anyKey.getAbsolutePath());
|
||||
throw new ProvisionException("Multiple host keys exist: " + keys);
|
||||
}
|
||||
if (objKey.exists()) {
|
||||
if (stdKeys.isEmpty()) {
|
||||
SimpleGeneratorHostKeyProvider p = new SimpleGeneratorHostKeyProvider();
|
||||
p.setPath(objKey.getAbsolutePath());
|
||||
return p;
|
||||
|
||||
if (keys.isEmpty()) {
|
||||
throw new ProvisionException("No SSH keys under " + site.etc_dir);
|
||||
} else {
|
||||
// Both formats of host key exist, we don't know which format
|
||||
// should be authoritative. Complain and abort.
|
||||
//
|
||||
stdKeys.add(objKey.getAbsolutePath());
|
||||
throw new ProvisionException("Multiple host keys exist: " + stdKeys);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (stdKeys.isEmpty()) {
|
||||
throw new ProvisionException("No SSH keys under " + site.etc_dir);
|
||||
}
|
||||
if (!SecurityUtils.isBouncyCastleRegistered()) {
|
||||
throw new ProvisionException("Bouncy Castle Crypto not installed;"
|
||||
+ " needed to read server host keys: " + stdKeys + "");
|
||||
}
|
||||
return new FileKeyPairProvider(stdKeys
|
||||
.toArray(new String[stdKeys.size()]));
|
||||
}
|
||||
if (!SecurityUtils.isBouncyCastleRegistered()) {
|
||||
throw new ProvisionException("Bouncy Castle Crypto not installed;"
|
||||
+ " needed to read server host keys: " + keys + "");
|
||||
}
|
||||
return new FileKeyPairProvider(keys.toArray(new String[keys.size()]));
|
||||
}
|
||||
}
|
||||
|
@ -15,18 +15,10 @@
|
||||
package com.google.gerrit.httpd;
|
||||
|
||||
import com.google.gerrit.lifecycle.LifecycleListener;
|
||||
import com.google.gwtorm.jdbc.SimpleDataSource;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.ProvisionException;
|
||||
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.NamingException;
|
||||
import javax.sql.DataSource;
|
||||
@ -61,49 +53,10 @@ final class ReviewDbDataSourceProvider implements Provider<DataSource>,
|
||||
try {
|
||||
return (DataSource) new InitialContext().lookup(dsName);
|
||||
} catch (NamingException namingErr) {
|
||||
final Properties p = readGerritDataSource();
|
||||
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);
|
||||
}
|
||||
throw new ProvisionException("No DataSource " + dsName, namingErr);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
Class<?> type = Class.forName("org.apache.commons.dbcp.BasicDataSource");
|
||||
|
@ -27,6 +27,7 @@ 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.sshd.SshModule;
|
||||
import com.google.gerrit.sshd.commands.MasterCommandModule;
|
||||
import com.google.inject.AbstractModule;
|
||||
@ -57,6 +58,7 @@ public class WebAppInitializer extends GuiceServletContextListener {
|
||||
private static final Logger log =
|
||||
LoggerFactory.getLogger(WebAppInitializer.class);
|
||||
|
||||
private File sitePath;
|
||||
private Injector dbInjector;
|
||||
private Injector cfgInjector;
|
||||
private Injector sysInjector;
|
||||
@ -66,6 +68,11 @@ public class WebAppInitializer extends GuiceServletContextListener {
|
||||
|
||||
private synchronized void init() {
|
||||
if (manager == null) {
|
||||
final String path = System.getProperty("gerrit.site_path");
|
||||
if (path != null) {
|
||||
sitePath = new File(path);
|
||||
}
|
||||
|
||||
try {
|
||||
dbInjector = createDbInjector();
|
||||
} catch (CreationException ce) {
|
||||
@ -115,28 +122,50 @@ public class WebAppInitializer extends GuiceServletContextListener {
|
||||
|
||||
private Injector createDbInjector() {
|
||||
final List<Module> modules = new ArrayList<Module>();
|
||||
modules.add(new LifecycleModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider(
|
||||
ReviewDbDataSourceProvider.class).in(SINGLETON);
|
||||
listener().to(ReviewDbDataSourceProvider.class);
|
||||
}
|
||||
});
|
||||
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() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider(
|
||||
ReviewDbDataSourceProvider.class).in(SINGLETON);
|
||||
listener().to(ReviewDbDataSourceProvider.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
modules.add(new DatabaseModule());
|
||||
return Guice.createInjector(PRODUCTION, modules);
|
||||
}
|
||||
|
||||
private Injector createCfgInjector() {
|
||||
final List<Module> modules = new ArrayList<Module>();
|
||||
modules.add(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(File.class).annotatedWith(SitePath.class).toProvider(
|
||||
SitePathFromSystemConfigProvider.class).in(SINGLETON);
|
||||
}
|
||||
});
|
||||
modules.add(new GerritServerConfigModule());
|
||||
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() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(File.class).annotatedWith(SitePath.class).toProvider(
|
||||
SitePathFromSystemConfigProvider.class).in(SINGLETON);
|
||||
}
|
||||
});
|
||||
modules.add(new GerritServerConfigModule());
|
||||
}
|
||||
modules.add(new AuthConfigModule());
|
||||
return dbInjector.createChildInjector(modules);
|
||||
}
|
||||
|
@ -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
|
@ -31,5 +31,5 @@
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl / -war ${resource_loc:/gerrit-gwtui/target}/gwt-hosted-mode -server com.google.gerrit.gwtdebug.GerritDebugLauncher com.google.gerrit.GerritGwtUI"/>
|
||||
<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.VM_ARGUMENTS" value="-Xmx256M -DGerritServer=${resource_loc:/gerrit-parent/GerritServer.properties}"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256M -Dgerrit.site_path=${resource_loc:/gerrit-parent}/../test_site"/>
|
||||
</launchConfiguration>
|
||||
|
Loading…
x
Reference in New Issue
Block a user