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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user