Merge branch 'dev-spearce'

* dev-spearce: (33 commits)
  Use transactions to handle comments when possible
  Avoid opening extra ReviewDb connection in PatchSetInfoFactory
  Minor ORM cleanups to support other backends
  Add command to output a Protobuf message file for the DB
  Support gwtorm 1.2
  Fix reference of Database<T> to SchemaFactory<T>
  Support Velocity 1.5
  Move replication queue binding out of GerritGlobalModule
  Remove static initialization of Velocity
  Move WorkQueue out of GerritGlobalModule
  Support auth.type = CUSTOM_EXTENSION
  Extract Git /p/ module configuration
  Make WebSession an abstract interface
  Move GitRepositoryManager setup out of SchemaModule
  Move SmtpEmailSender to its own module
  Make Address, EmailHeader visible to other EmailSenders
  Disable SSH Keys in the web UI if SSHD is disabled
  Refactor how we tie the SSH objects into the HTTP injector
  daemon: Allow httpd without sshd
  Allow sshd.listenAddress = off to disable the daemon
  ...

Conflicts:
	gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
	gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java

Change-Id: If957ce2eeb9b1de4ed2b134b0db129c336900442
This commit is contained in:
Shawn O. Pearce
2011-11-01 18:18:06 -07:00
80 changed files with 1272 additions and 520 deletions

View File

@@ -90,6 +90,7 @@ public class RulesCache {
}
}
private final boolean enableProjectRules;
private final File cacheDir;
private final File rulesDir;
private final GitRepositoryManager gitMgr;
@@ -99,6 +100,7 @@ public class RulesCache {
@Inject
protected RulesCache(@GerritServerConfig Config config, SitePaths site,
GitRepositoryManager gm) {
enableProjectRules = config.getBoolean("rules", null, "enable", true);
cacheDir = site.resolve(config.getString("cache", null, "directory"));
rulesDir = cacheDir != null ? new File(cacheDir, "rules") : null;
gitMgr = gm;
@@ -117,7 +119,7 @@ public class RulesCache {
Project.NameKey project,
ObjectId rulesId)
throws CompileException {
if (project == null || rulesId == null) {
if (!enableProjectRules || project == null || rulesId == null) {
return defaultMachine;
}

View File

@@ -51,7 +51,7 @@ public final class StoredValues {
PatchSetInfoFactory patchInfoFactory =
env.getInjector().getInstance(PatchSetInfoFactory.class);
try {
return patchInfoFactory.get(patchSetId);
return patchInfoFactory.get(REVIEW_DB.get(engine), patchSetId);
} catch (PatchSetInfoNotAvailableException e) {
throw new SystemException(e.getMessage());
}

View File

@@ -33,16 +33,21 @@ public class RequestCleanup implements Runnable {
LoggerFactory.getLogger(RequestCleanup.class);
private final List<Runnable> cleanup = new LinkedList<Runnable>();
private boolean ran;
/** Register a task to be completed after the request ends. */
public void add(final Runnable task) {
synchronized (cleanup) {
if (ran) {
throw new IllegalStateException("Request has already been cleaned up");
}
cleanup.add(task);
}
}
public void run() {
synchronized (cleanup) {
ran = true;
for (final Iterator<Runnable> i = cleanup.iterator(); i.hasNext();) {
try {
i.next().run();

View File

@@ -21,7 +21,7 @@ import com.google.inject.Inject;
import java.util.Collections;
import java.util.Set;
public final class DefaultRealm implements Realm {
public class DefaultRealm implements Realm {
private final EmailExpander emailExpander;
private final AccountByEmailCache byEmail;

View File

@@ -22,7 +22,6 @@ import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.ProvisionException;
import com.google.inject.Singleton;
import net.sf.ehcache.CacheManager;
@@ -214,8 +213,8 @@ public class CachePool {
}
}
private void configureDefaultCache() {
final CacheConfiguration c = new CacheConfiguration();
private CacheConfiguration newConfiguration() {
CacheConfiguration c = new CacheConfiguration();
c.setMaxElementsInMemory(1024);
c.setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy.LFU);
@@ -232,19 +231,17 @@ public class CachePool {
c.setDiskSpoolBufferSizeMB(5);
c.setDiskExpiryThreadIntervalSeconds(60 * 60);
}
return c;
}
mgr.setDefaultCacheConfiguration(c);
private void configureDefaultCache() {
mgr.setDefaultCacheConfiguration(newConfiguration());
}
private CacheConfiguration newCache(final String name) {
try {
final CacheConfiguration c;
c = mgr.getDefaultCacheConfiguration().clone();
c.setName(name);
return c;
} catch (CloneNotSupportedException e) {
throw new ProvisionException("Cannot configure cache " + name, e);
}
CacheConfiguration c = newConfiguration();
c.setName(name);
return c;
}
}
}

View File

@@ -140,6 +140,7 @@ public class AuthConfig {
case LDAP:
case LDAP_BIND:
case CLIENT_SSL_CERT_LDAP:
case CUSTOM_EXTENSION:
// Its safe to assume yes for an HTTP authentication type, as the
// only way in is through some external system that the admin trusts
//

View File

@@ -17,7 +17,6 @@ package com.google.gerrit.server.config;
import static com.google.inject.Scopes.SINGLETON;
import com.google.gerrit.common.data.ApprovalTypes;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.reviewdb.AuthType;
import com.google.gerrit.rules.PrologModule;
@@ -43,17 +42,13 @@ import com.google.gerrit.server.git.ChangeMergeQueue;
import com.google.gerrit.server.git.GitModule;
import com.google.gerrit.server.git.MergeQueue;
import com.google.gerrit.server.git.PushAllProjectsOp;
import com.google.gerrit.server.git.PushReplication;
import com.google.gerrit.server.git.ReloadSubmitQueueOp;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.git.SecureCredentialsProvider;
import com.google.gerrit.server.git.TagCache;
import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.mail.EmailSender;
import com.google.gerrit.server.mail.FromAddressGenerator;
import com.google.gerrit.server.mail.FromAddressGeneratorProvider;
import com.google.gerrit.server.mail.SmtpEmailSender;
import com.google.gerrit.server.mail.VelocityRuntimeProvider;
import com.google.gerrit.server.patch.PatchListCacheImpl;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.AccessControlModule;
@@ -68,51 +63,14 @@ import com.google.gerrit.server.util.IdGenerator;
import com.google.gerrit.server.workflow.FunctionState;
import com.google.inject.Inject;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeInstance;
import org.eclipse.jgit.lib.Config;
import java.util.Properties;
/** Starts global state with standard dependencies. */
public class GerritGlobalModule extends FactoryModule {
private final AuthType loginType;
public static class VelocityLifecycle implements LifecycleListener {
private final SitePaths site;
@Inject
VelocityLifecycle(final SitePaths site) {
this.site = site;
}
@Override
public void start() {
String rl = "resource.loader";
String pkg = "org.apache.velocity.runtime.resource.loader";
Properties p = new Properties();
p.setProperty(rl, "file, class");
p.setProperty("file." + rl + ".class", pkg + ".FileResourceLoader");
p.setProperty("file." + rl + ".path", site.mail_dir.getAbsolutePath());
p.setProperty("class." + rl + ".class", pkg + ".ClasspathResourceLoader");
p.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
"org.apache.velocity.runtime.log.SimpleLog4JLogSystem" );
p.setProperty("runtime.log.logsystem.log4j.category", "velocity");
try {
Velocity.init(p);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void stop() {
}
}
@Inject
GerritGlobalModule(final AuthConfig authConfig,
@GerritServerConfig final Config config) {
@@ -129,6 +87,9 @@ public class GerritGlobalModule extends FactoryModule {
install(new LdapModule());
break;
case CUSTOM_EXTENSION:
break;
default:
bind(Realm.class).to(DefaultRealm.class);
break;
@@ -161,21 +122,21 @@ public class GerritGlobalModule extends FactoryModule {
bind(PermissionCollection.Factory.class);
bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class);
bind(WorkQueue.class);
bind(ToolsCatalog.class);
bind(EventFactory.class);
bind(TransferConfig.class);
bind(ReplicationQueue.class).to(PushReplication.class).in(SINGLETON);
factory(SecureCredentialsProvider.Factory.class);
factory(PushAllProjectsOp.Factory.class);
bind(MergeQueue.class).to(ChangeMergeQueue.class).in(SINGLETON);
factory(ReloadSubmitQueueOp.Factory.class);
bind(RuntimeInstance.class)
.toProvider(VelocityRuntimeProvider.class)
.in(SINGLETON);
bind(FromAddressGenerator.class).toProvider(
FromAddressGeneratorProvider.class).in(SINGLETON);
bind(EmailSender.class).to(SmtpEmailSender.class).in(SINGLETON);
bind(PatchSetInfoFactory.class);
bind(IdentifiedUser.GenericFactory.class).in(SINGLETON);
@@ -188,8 +149,6 @@ public class GerritGlobalModule extends FactoryModule {
@Override
protected void configure() {
listener().to(CachePool.Lifecycle.class);
listener().to(WorkQueue.Lifecycle.class);
listener().to(VelocityLifecycle.class);
}
});
}

View File

@@ -17,7 +17,7 @@ package com.google.gerrit.server.config;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.RequestCleanup;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.jdbc.Database;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
@@ -26,11 +26,11 @@ import com.google.inject.Singleton;
/** Provides {@link ReviewDb} database handle live only for this request. */
@Singleton
final class RequestScopedReviewDbProvider implements Provider<ReviewDb> {
private final Database<ReviewDb> schema;
private final SchemaFactory<ReviewDb> schema;
private final Provider<RequestCleanup> cleanup;
@Inject
RequestScopedReviewDbProvider(final Database<ReviewDb> schema,
RequestScopedReviewDbProvider(final SchemaFactory<ReviewDb> schema,
final Provider<RequestCleanup> cleanup) {
this.schema = schema;
this.cleanup = cleanup;

View File

@@ -15,9 +15,11 @@
package com.google.gerrit.server.git;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -54,6 +56,20 @@ public class LocalDiskRepositoryManager implements GitRepositoryManager {
private static final String UNNAMED =
"Unnamed repository; edit this file to name it for gitweb.";
public static class Module extends AbstractModule {
@Override
protected void configure() {
bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
install(new LifecycleModule() {
@Override
protected void configure() {
listener().to(LocalDiskRepositoryManager.Lifecycle.class);
}
});
}
}
public static class Lifecycle implements LifecycleListener {
private final Config cfg;

View File

@@ -1309,7 +1309,7 @@ public class MergeOp {
// Go back to the patch set that was actually merged.
//
try {
c.setCurrentPatchSet(patchSetInfoFactory.get(merged));
c.setCurrentPatchSet(patchSetInfoFactory.get(schema, merged));
} catch (PatchSetInfoNotAvailableException e1) {
log.error("Cannot read merged patch set " + merged, e1);
}

View File

@@ -72,6 +72,13 @@ import java.util.concurrent.TimeUnit;
public class PushReplication implements ReplicationQueue {
static final Logger log = LoggerFactory.getLogger(PushReplication.class);
public static class Module extends AbstractModule {
@Override
protected void configure() {
bind(ReplicationQueue.class).to(PushReplication.class);
}
}
static {
// Install our own factory which always runs in batch mode, as we
// have no UI available for interactive prompting.

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.git;
import com.google.gerrit.lifecycle.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.reviewdb.Project.NameKey;
import com.google.gerrit.server.util.IdGenerator;
import com.google.inject.Inject;
@@ -61,6 +62,14 @@ public class WorkQueue {
}
}
public static class Module extends LifecycleModule {
@Override
protected void configure() {
bind(WorkQueue.class);
listener().to(Lifecycle.class);
}
}
private static final Logger log = LoggerFactory.getLogger(WorkQueue.class);
private static final UncaughtExceptionHandler LOG_UNCAUGHT_EXCEPTION =
new UncaughtExceptionHandler() {

View File

@@ -16,8 +16,8 @@ package com.google.gerrit.server.mail;
import java.io.UnsupportedEncodingException;
class Address {
static Address parse(final String in) {
public class Address {
public static Address parse(final String in) {
final int lt = in.indexOf('<');
final int gt = in.indexOf('>');
final int at = in.indexOf("@");
@@ -37,15 +37,23 @@ class Address {
final String name;
final String email;
Address(String email) {
public Address(String email) {
this(null, email);
}
Address(String name, String email) {
public Address(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
@Override
public String toString() {
try {
@@ -55,7 +63,7 @@ class Address {
}
}
String toHeaderString() throws UnsupportedEncodingException {
public String toHeaderString() throws UnsupportedEncodingException {
if (name != null) {
return quotedPhrase(name) + " <" + email + ">";
} else if (isSimple()) {

View File

@@ -72,7 +72,8 @@ public abstract class ChangeEmail extends OutgoingEmail {
final IdentifiedUser user = args.identifiedUserFactory.create(id);
final Set<AccountGroup.UUID> gids = user.getEffectiveGroups();
for (final AccountGroup.UUID gid : gids) {
if (args.groupCache.get(gid).isEmailOnlyAuthors()) {
AccountGroup group = args.groupCache.get(gid);
if (group != null && group.isEmailOnlyAuthors()) {
emailOnlyAuthors = true;
break;
}
@@ -136,7 +137,7 @@ public abstract class ChangeEmail extends OutgoingEmail {
if (patchSet != null && patchSetInfo == null) {
try {
patchSetInfo = args.patchSetInfoFactory.get(patchSet.getId());
patchSetInfo = args.patchSetInfoFactory.get(args.db.get(), patchSet.getId());
} catch (PatchSetInfoNotAvailableException err) {
patchSetInfo = null;
}

View File

@@ -21,7 +21,6 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
@@ -31,6 +30,8 @@ import com.google.gerrit.server.query.change.ChangeQueryRewriter;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.apache.velocity.runtime.RuntimeInstance;
import javax.annotation.Nullable;
class EmailArguments {
@@ -49,7 +50,7 @@ class EmailArguments {
final ChangeQueryBuilder.Factory queryBuilder;
final Provider<ChangeQueryRewriter> queryRewriter;
final Provider<ReviewDb> db;
final SitePaths site;
final RuntimeInstance velocityRuntime;
@Inject
EmailArguments(GitRepositoryManager server, ProjectCache projectCache,
@@ -61,7 +62,7 @@ class EmailArguments {
AllProjectsName allProjectsName,
ChangeQueryBuilder.Factory queryBuilder,
Provider<ChangeQueryRewriter> queryRewriter, Provider<ReviewDb> db,
SitePaths site) {
RuntimeInstance velocityRuntime) {
this.server = server;
this.projectCache = projectCache;
this.groupCache = groupCache;
@@ -76,6 +77,6 @@ class EmailArguments {
this.queryBuilder = queryBuilder;
this.queryRewriter = queryRewriter;
this.db = db;
this.site = site;
this.velocityRuntime = velocityRuntime;
}
}

View File

@@ -20,28 +20,33 @@ import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
abstract class EmailHeader {
abstract boolean isEmpty();
public abstract class EmailHeader {
public abstract boolean isEmpty();
abstract void write(Writer w) throws IOException;
public abstract void write(Writer w) throws IOException;
static class String extends EmailHeader {
public static class String extends EmailHeader {
private java.lang.String value;
String(java.lang.String v) {
public String(java.lang.String v) {
value = v;
}
public java.lang.String getString() {
return value;
}
@Override
boolean isEmpty() {
public boolean isEmpty() {
return value == null || value.length() == 0;
}
@Override
void write(Writer w) throws IOException {
public void write(Writer w) throws IOException {
if (needsQuotedPrintable(value)) {
w.write(quotedPrintable(value));
} else {
@@ -84,20 +89,24 @@ abstract class EmailHeader {
return r.toString();
}
static class Date extends EmailHeader {
public static class Date extends EmailHeader {
private java.util.Date value;
Date(java.util.Date v) {
public Date(java.util.Date v) {
value = v;
}
public java.util.Date getDate() {
return value;
}
@Override
boolean isEmpty() {
public boolean isEmpty() {
return value == null;
}
@Override
void write(Writer w) throws IOException {
public void write(Writer w) throws IOException {
final SimpleDateFormat fmt;
// Mon, 1 Jun 2009 10:49:44 -0700
fmt = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
@@ -105,17 +114,21 @@ abstract class EmailHeader {
}
}
static class AddressList extends EmailHeader {
public static class AddressList extends EmailHeader {
private final List<Address> list = new ArrayList<Address>();
AddressList() {
public AddressList() {
}
AddressList(Address addr) {
public AddressList(Address addr) {
add(addr);
}
void add(Address addr) {
public List<Address> getAddressList() {
return Collections.unmodifiableList(list);
}
public void add(Address addr) {
list.add(addr);
}
@@ -128,12 +141,12 @@ abstract class EmailHeader {
}
@Override
boolean isEmpty() {
public boolean isEmpty() {
return list.isEmpty();
}
@Override
void write(Writer w) throws IOException {
public void write(Writer w) throws IOException {
int len = 8;
boolean firstAddress = true;
boolean needComma = false;

View File

@@ -20,12 +20,16 @@ import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.mail.EmailHeader.AddressList;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.InternalContextAdapterImpl;
import org.apache.velocity.runtime.RuntimeInstance;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.eclipse.jgit.util.SystemReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
@@ -349,24 +353,41 @@ public abstract class OutgoingEmail {
protected String velocify(String template) throws EmailException {
try {
StringWriter w = new StringWriter();
Velocity.evaluate(velocityContext, w, "OutgoingEmail", template);
return w.toString();
} catch(Exception e) {
throw new EmailException("Velocity template " + template, e);
RuntimeInstance runtime = args.velocityRuntime;
String templateName = "OutgoingEmail";
SimpleNode tree = runtime.parse(new StringReader(template), templateName);
InternalContextAdapterImpl ica = new InternalContextAdapterImpl(velocityContext);
ica.pushCurrentTemplateName(templateName);
try {
tree.init(ica, runtime);
StringWriter w = new StringWriter();
tree.render(ica, w);
return w.toString();
} finally {
ica.popCurrentTemplateName();
}
} catch (Exception e) {
throw new EmailException("Cannot format velocity template: " + template, e);
}
}
protected String velocifyFile(String name) throws EmailException {
if (!Velocity.resourceExists(name)) {
name = "com/google/gerrit/server/mail/" + name;
}
try {
RuntimeInstance runtime = args.velocityRuntime;
Template template;
try {
template = runtime.getTemplate(name, "UTF-8");
} catch (org.apache.velocity.exception.ResourceNotFoundException notFound) {
name = "com/google/gerrit/server/mail/" + name;
template = runtime.getTemplate(name, "UTF-8");
}
StringWriter w = new StringWriter();
Velocity.mergeTemplate(name, "UTF-8", velocityContext, w);
template.merge(velocityContext, w);
return w.toString();
} catch(Exception e) {
throw new EmailException("Velocity template " + name + ".\n", e);
} catch (EmailException e) {
throw e;
} catch (Exception e) {
throw new EmailException("Cannot format velocity template " + name, e);
}
}

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.server.mail;
import com.google.gerrit.common.Version;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -40,6 +41,13 @@ import java.util.Set;
/** Sends email via a nearby SMTP server. */
@Singleton
public class SmtpEmailSender implements EmailSender {
public static class Module extends AbstractModule {
@Override
protected void configure() {
bind(EmailSender.class).to(SmtpEmailSender.class);
}
}
public static enum Encryption {
NONE, SSL, TLS;
}

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2011 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.mail;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeInstance;
import java.util.Properties;
/** Configures Velocity template engine for sending email. */
public class VelocityRuntimeProvider implements Provider<RuntimeInstance> {
private final SitePaths site;
@Inject
VelocityRuntimeProvider(SitePaths site) {
this.site = site;
}
public RuntimeInstance get() {
String rl = "resource.loader";
String pkg = "org.apache.velocity.runtime.resource.loader";
Properties p = new Properties();
p.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
"org.apache.velocity.runtime.log.SimpleLog4JLogSystem" );
p.setProperty("runtime.log.logsystem.log4j.category", "velocity");
if (site.mail_dir.isDirectory()) {
p.setProperty(rl, "file, class");
p.setProperty("file." + rl + ".class", pkg + ".FileResourceLoader");
p.setProperty("file." + rl + ".path", site.mail_dir.getAbsolutePath());
p.setProperty("class." + rl + ".class", pkg + ".ClasspathResourceLoader");
} else {
p.setProperty(rl, "class");
p.setProperty("class." + rl + ".class", pkg + ".ClasspathResourceLoader");
}
RuntimeInstance ri = new RuntimeInstance();
try {
ri.init(p);
} catch (Exception err) {
throw new ProvisionException("Cannot configure Velocity templates", err);
}
return ri;
}
}

View File

@@ -25,7 +25,6 @@ import com.google.gerrit.reviewdb.UserIdentity;
import com.google.gerrit.server.account.AccountByEmailCache;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -49,15 +48,12 @@ import java.util.Set;
@Singleton
public class PatchSetInfoFactory {
private final GitRepositoryManager repoManager;
private final SchemaFactory<ReviewDb> schemaFactory;
private final AccountByEmailCache byEmailCache;
@Inject
public PatchSetInfoFactory(final GitRepositoryManager grm,
final SchemaFactory<ReviewDb> schemaFactory,
final AccountByEmailCache byEmailCache) {
this.repoManager = grm;
this.schemaFactory = schemaFactory;
this.byEmailCache = byEmailCache;
}
@@ -68,16 +64,13 @@ public class PatchSetInfoFactory {
info.setAuthor(toUserIdentity(src.getAuthorIdent()));
info.setCommitter(toUserIdentity(src.getCommitterIdent()));
info.setRevId(src.getName());
return info;
}
public PatchSetInfo get(PatchSet.Id patchSetId)
throws PatchSetInfoNotAvailableException {
ReviewDb db = null;
public PatchSetInfo get(ReviewDb db, PatchSet.Id patchSetId)
throws PatchSetInfoNotAvailableException {
Repository repo = null;
try {
db = schemaFactory.open();
final PatchSet patchSet = db.patchSets().get(patchSetId);
final Change change = db.changes().get(patchSet.getId().getParentKey());
final Project.NameKey projectKey = change.getProject();
@@ -97,9 +90,6 @@ public class PatchSetInfoFactory {
} catch (IOException e) {
throw new PatchSetInfoNotAvailableException(e);
} finally {
if (db != null) {
db.close();
}
if (repo != null) {
repo.close();
}

View File

@@ -116,18 +116,25 @@ public class PublishComments implements Callable<VoidResult> {
}
drafts = drafts();
publishDrafts();
db.changes().beginTransaction(changeId);
try {
publishDrafts();
final boolean isCurrent = patchSetId.equals(change.currentPatchSetId());
if (isCurrent && change.getStatus().isOpen()) {
publishApprovals(ctl);
} else if (! approvals.isEmpty()) {
throw new InvalidChangeOperationException("Change is closed");
} else {
publishMessageOnly();
final boolean isCurrent = patchSetId.equals(change.currentPatchSetId());
if (isCurrent && change.getStatus().isOpen()) {
publishApprovals(ctl);
} else if (!approvals.isEmpty()) {
throw new InvalidChangeOperationException("Change is closed");
} else {
publishMessageOnly();
}
touchChange();
db.commit();
} finally {
db.rollback();
}
touchChange();
email();
fireHook();
return VoidResult.INSTANCE;
@@ -280,7 +287,7 @@ public class PublishComments implements Callable<VoidResult> {
}
private List<PatchLineComment> drafts() throws OrmException {
return db.patchComments().draft(patchSetId, user.getAccountId()).toList();
return db.patchComments().draftByPatchSetAuthor(patchSetId, user.getAccountId()).toList();
}
private void email() {
@@ -288,7 +295,7 @@ public class PublishComments implements Callable<VoidResult> {
if (message != null) {
final CommentSender cm = commentSenderFactory.create(change);
cm.setFrom(user.getAccountId());
cm.setPatchSet(patchSet, patchSetInfoFactory.get(patchSetId));
cm.setPatchSet(patchSet, patchSetInfoFactory.get(db, patchSetId));
cm.setChangeMessage(message);
cm.setPatchLineComments(drafts);
cm.send();

View File

@@ -16,7 +16,6 @@ package com.google.gerrit.server.schema;
import static com.google.inject.Scopes.SINGLETON;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.config.AllProjectsName;
@@ -24,8 +23,6 @@ import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import org.eclipse.jgit.lib.PersonIdent;
@@ -44,13 +41,5 @@ public class SchemaModule extends FactoryModule {
bind(String.class).annotatedWith(AnonymousCowardName.class).toProvider(
AnonymousCowardNameProvider.class);
bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
install(new LifecycleModule() {
@Override
protected void configure() {
listener().to(LocalDiskRepositoryManager.Lifecycle.class);
}
});
}
}

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2010 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.ssh;
import com.google.gerrit.server.ssh.SshInfo;
import com.jcraft.jsch.HostKey;
import java.util.Collections;
import java.util.List;
class NoSshInfo implements SshInfo {
@Override
public List<HostKey> getHostKeys() {
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2010 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.ssh;
import com.google.gerrit.common.errors.InvalidSshKeyException;
import com.google.gerrit.reviewdb.AccountSshKey;
class NoSshKeyCache implements SshKeyCache {
@Override
public void evict(String username) {
}
@Override
public AccountSshKey create(AccountSshKey.Id id, String encoded)
throws InvalidSshKeyException {
throw new InvalidSshKeyException();
}
}

View File

@@ -0,0 +1,28 @@
// Copyright (C) 2010 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.ssh;
import com.google.inject.AbstractModule;
/**
* Disables the SSH support by stubbing out relevant objects.
*/
public class NoSshModule extends AbstractModule {
@Override
protected void configure() {
bind(SshInfo.class).to(NoSshInfo.class);
bind(SshKeyCache.class).to(NoSshKeyCache.class);
}
}