Merge branch 'stable-2.6'

* stable-2.6:
  Make Diffy in Diffy theme smaller
  Remove unnecessary @SuppressWarnings annotations in ChangeControl
  Update documentation to clarify how to set Global Capabilities
  Distinguish between error and timeout in intraline diff error message
  Replace Hashtable with ConcurrentMap
  Fix login redirect loop when auth.type = HTTP
  Include site header, footer and CSS on OpenID login form
  TrivialRebase: Fix custom categories
This commit is contained in:
Shawn Pearce
2013-04-25 09:31:52 -07:00
12 changed files with 303 additions and 168 deletions

View File

@@ -12,19 +12,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#gerrit_topmenu {
left: 60px;
margin-right: 60px;
padding-right: 10px;
position: relative;
}
#gerrit_header {
#diffy_logo {
display: block !important;
margin-bottom: -55px;
padding-left: 20px;
position: relative;
top: -45px;
width: 100px;
}
#gerrit_topmenu {
left: 100px;
margin-right: 100px;
padding-right: 10px;
position: relative;
width: 60px;
}

View File

@@ -1,3 +1,5 @@
<div>
<img src="static/logo.png"/>
<div id="diffy_logo">
<img width="50" height="46" src="static/logo.png"/>
</div>
</div>

View File

@@ -226,7 +226,7 @@ class TrivialRebase:
# We don't care about previous submit attempts
continue
else:
self.AppendAcctApproval(acct_approvals, approval['account_id'], '--%s %s' %
self.AppendAcctApproval(approval['account_id'], '--%s %s' %
(approval['category_id'].lower().replace(' ', '-'),
approval['value']))

View File

@@ -21,6 +21,7 @@ import com.google.common.base.Strings;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.httpd.template.SiteHeaderFooter;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -60,14 +61,18 @@ class BecomeAnyAccountLoginServlet extends HttpServlet {
private final SchemaFactory<ReviewDb> schema;
private final Provider<WebSession> webSession;
private final AccountManager accountManager;
private final SiteHeaderFooter headers;
@Inject
BecomeAnyAccountLoginServlet(final Provider<WebSession> ws,
final SchemaFactory<ReviewDb> sf,
final AccountManager am, final ServletContext servletContext) {
final AccountManager am,
final ServletContext servletContext,
SiteHeaderFooter shf) {
webSession = ws;
schema = sf;
accountManager = am;
headers = shf;
}
@Override
@@ -149,7 +154,7 @@ class BecomeAnyAccountLoginServlet extends HttpServlet {
private byte[] prepareHtmlOutput() throws IOException, OrmException {
final String pageName = "BecomeAnyAccount.html";
final Document doc = HtmlDomUtil.parseFile(getClass(), pageName);
Document doc = headers.parse(getClass(), pageName);
if (doc == null) {
throw new FileNotFoundException("No " + pageName + " in webapp");
}

View File

@@ -119,14 +119,17 @@ class HttpAuthFilter implements Filter {
WebSession session = sessionProvider.get();
if (session.isSignedIn()) {
String user = getRemoteUser(req);
AccountExternalId.Key id = session.getLastLoginExternalId();
return user != null
&& id != null
&& id.equals(new AccountExternalId.Key(SCHEME_GERRIT, user));
return user == null || correctUser(user, session);
}
return false;
}
private static boolean correctUser(String user, WebSession session) {
AccountExternalId.Key id = session.getLastLoginExternalId();
return id != null
&& id.equals(new AccountExternalId.Key(SCHEME_GERRIT, user));
}
String getRemoteUser(HttpServletRequest req) {
if (AUTHORIZATION.equals(loginHeader)) {
String user = emptyToNull(req.getRemoteUser());

View File

@@ -19,6 +19,7 @@ import com.google.common.base.Strings;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.httpd.template.SiteHeaderFooter;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountUserNameException;
@@ -26,7 +27,6 @@ import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.auth.AuthenticationUnavailableException;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.SitePaths;
import com.google.gwtexpui.server.CacheHeaders;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.File;
import java.io.IOException;
import javax.annotation.Nullable;
@@ -57,17 +56,17 @@ class LdapLoginServlet extends HttpServlet {
private final AccountManager accountManager;
private final Provider<WebSession> webSession;
private final Provider<String> urlProvider;
private final SitePaths sitePaths;
private final SiteHeaderFooter headers;
@Inject
LdapLoginServlet(AccountManager accountManager,
Provider<WebSession> webSession,
@CanonicalWebUrl @Nullable Provider<String> urlProvider,
SitePaths sitePaths) {
SiteHeaderFooter headers) {
this.accountManager = accountManager;
this.webSession = webSession;
this.urlProvider = urlProvider;
this.sitePaths = sitePaths;
this.headers = headers;
if (Strings.isNullOrEmpty(urlProvider.get())) {
log.error("gerrit.canonicalWebUrl must be set in gerrit.config");
@@ -83,13 +82,7 @@ class LdapLoginServlet extends HttpServlet {
cancel += "#" + token;
}
Document doc =
HtmlDomUtil.parseFile(LdapLoginServlet.class, "LoginForm.html");
injectCssFile(doc, "gerrit_sitecss", sitePaths.site_css);
injectXmlFile(doc, "gerrit_header", sitePaths.site_header);
injectXmlFile(doc, "gerrit_footer", sitePaths.site_footer);
Document doc = headers.parse(LdapLoginServlet.class, "LoginForm.html");
HtmlDomUtil.find(doc, "hostName").setTextContent(req.getServerName());
HtmlDomUtil.find(doc, "login_form").setAttribute("action", self);
HtmlDomUtil.find(doc, "cancel_link").setAttribute("href", cancel);
@@ -114,42 +107,6 @@ class LdapLoginServlet extends HttpServlet {
}
}
private void injectCssFile(final Document hostDoc, final String id,
final File src) throws IOException {
final Element banner = HtmlDomUtil.find(hostDoc, id);
if (banner != null) {
while (banner.getFirstChild() != null) {
banner.removeChild(banner.getFirstChild());
}
String css = HtmlDomUtil.readFile(src.getParentFile(), src.getName());
if (css == null) {
banner.getParentNode().removeChild(banner);
} else {
banner.removeAttribute("id");
banner.appendChild(hostDoc.createCDATASection("\n" + css + "\n"));
}
}
}
private void injectXmlFile(final Document hostDoc, final String id,
final File src) throws IOException {
final Element banner = HtmlDomUtil.find(hostDoc, id);
if (banner != null) {
while (banner.getFirstChild() != null) {
banner.removeChild(banner.getFirstChild());
}
Document html = HtmlDomUtil.parseFile(src);
if (html == null) {
banner.getParentNode().removeChild(banner);
} else {
final Element content = html.getDocumentElement();
banner.appendChild(hostDoc.importNode(content, true));
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {

View File

@@ -0,0 +1,150 @@
// Copyright (C) 2013 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.template;
import com.google.common.base.Strings;
import com.google.gerrit.httpd.HtmlDomUtil;
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.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.File;
import java.io.IOException;
@Singleton
public class SiteHeaderFooter {
private static final Logger log = LoggerFactory.getLogger(SiteHeaderFooter.class);
private final boolean refreshHeaderFooter;
private final SitePaths sitePaths;
private volatile Template template;
@Inject
SiteHeaderFooter(@GerritServerConfig Config cfg, SitePaths sitePaths) {
this.refreshHeaderFooter = cfg.getBoolean("site", "refreshHeaderFooter", true);
this.sitePaths = sitePaths;
Template t = new Template(sitePaths);
try {
t.load();
} catch (IOException e) {
log.warn("Cannot load site header or footer", e);
}
template = t;
}
public Document parse(Class<?> clazz, String name) throws IOException {
Template t = template;
if (refreshHeaderFooter && t.isStale()) {
t = new Template(sitePaths);
try {
t.load();
template = t;
} catch (IOException e) {
log.warn("Cannot refresh site header or footer", e);
t = template;
}
}
Document doc = HtmlDomUtil.parseFile(clazz, name);
injectCss(doc, "gerrit_sitecss", t.css);
injectXml(doc, "gerrit_header", t.header);
injectXml(doc, "gerrit_footer", t.footer);
return doc;
}
private void injectCss(Document doc, String id, String content) {
Element e = HtmlDomUtil.find(doc, id);
if (e != null) {
if (!Strings.isNullOrEmpty(content)) {
while (e.getFirstChild() != null) {
e.removeChild(e.getFirstChild());
}
e.removeAttribute("id");
e.appendChild(doc.createCDATASection("\n" + content + "\n"));
} else {
e.getParentNode().removeChild(e);
}
}
}
private void injectXml(Document doc, String id, Element d) {
Element e = HtmlDomUtil.find(doc, id);
if (e != null) {
if (d != null) {
while (e.getFirstChild() != null) {
e.removeChild(e.getFirstChild());
}
e.appendChild(doc.importNode(d, true));
} else {
e.getParentNode().removeChild(e);
}
}
}
private static class Template {
private final FileInfo cssFile;
private final FileInfo headerFile;
private final FileInfo footerFile;
String css;
Element header;
Element footer;
Template(SitePaths site) {
cssFile = new FileInfo(site.site_css);
headerFile = new FileInfo(site.site_header);
footerFile = new FileInfo(site.site_footer);
}
void load() throws IOException {
css = HtmlDomUtil.readFile(
cssFile.path.getParentFile(),
cssFile.path.getName());
header = readXml(headerFile);
footer = readXml(footerFile);
}
boolean isStale() {
return cssFile.isStale() || headerFile.isStale() || footerFile.isStale();
}
private static Element readXml(FileInfo src) throws IOException {
Document d = HtmlDomUtil.parseFile(src.path);
return d != null ? d.getDocumentElement() : null;
}
}
private static class FileInfo {
final File path;
final long time;
FileInfo(File p) {
path = p;
time = path.lastModified();
}
boolean isStale() {
return time != path.lastModified();
}
}
}

View File

@@ -29,51 +29,59 @@
}
})();
</script>
<style id="gerrit_sitecss" type="text/css"></style>
</head>
<body>
<h2>Sign In</h2>
<table border="0">
<tr>
<th>Username:</th>
<td>
<form method="GET">
<input type="text" size="30" name="user_name" />
<input type="submit" value="Become Account" />
</form>
</td>
</tr>
<div id="gerrit_topmenu" style="height:45px;" class="gerritTopMenu"></div>
<div id="gerrit_header"></div>
<div id="gerrit_body" class="gerritBody">
<h2>Sign In</h2>
<table border="0">
<tr>
<th>Username:</th>
<td>
<form method="GET">
<input type="text" size="30" name="user_name" />
<input type="submit" value="Become Account" />
</form>
</td>
</tr>
<tr>
<th>Email Address:</th>
<td>
<form method="GET">
<input type="text" size="30" name="preferred_email" />
<input type="submit" value="Become Account" />
</form>
</td>
</tr>
<tr>
<th>Email Address:</th>
<td>
<form method="GET">
<input type="text" size="30" name="preferred_email" />
<input type="submit" value="Become Account" />
</form>
</td>
</tr>
<tr>
<th>Account ID:</th>
<td>
<form method="GET">
<input type="text" size="12" name="account_id" />
<input type="submit" value="Become Account" />
</form>
</td>
</tr>
<tr>
<th>Account ID:</th>
<td>
<form method="GET">
<input type="text" size="12" name="account_id" />
<input type="submit" value="Become Account" />
</form>
</td>
</tr>
<tr>
<th>Choose:</th>
<td id="userlist"/>
</tr>
</table>
<tr>
<th>Choose:</th>
<td id="userlist"/>
</tr>
</table>
<hr />
<h2>Register</h2>
<form method="POST">
<input type="hidden" name="action" value="create_account" />
<input type="submit" value="New Account" />
</form>
<hr />
<h2>Register</h2>
<form method="POST">
<input type="hidden" name="action" value="create_account" />
<input type="submit" value="New Account" />
</form>
</div>
<div style="clear: both; margin-top: 15px; padding-top: 2px; margin-bottom: 15px;">
<div id="gerrit_footer"></div>
</div>
</body>
</html>

View File

@@ -13,7 +13,7 @@
margin-left: 45px;
}
</style>
<style id="gerrit_sitecss" type="text/css"></style>
<style id="gerrit_sitecss" type="text/css"></style>
</head>
<body>
<div id="gerrit_topmenu" style="height:45px;" class="gerritTopMenu"></div>
@@ -56,28 +56,28 @@
</tr>
</table>
</form>
<script type="text/javascript">
var login_form = document.getElementById('login_form');
var f_user = document.getElementById('f_user');
var f_pass = document.getElementById('f_pass');
f_user.onkeydown = function(e) {
if (e.keyCode == 13) {
f_pass.focus();
return false;
}
}
f_pass.onkeydown = function(e) {
if (e.keyCode == 13) {
login_form.submit();
return false;
}
}
f_user.focus();
</script>
<div style="clear: both; margin-top: 15px; padding-top: 2px; margin-bottom: 15px;">
<div id="gerrit_footer"></div>
</div>
</div>
<script type="text/javascript">
var login_form = document.getElementById('login_form');
var f_user = document.getElementById('f_user');
var f_pass = document.getElementById('f_pass');
f_user.onkeydown = function(e) {
if (e.keyCode == 13) {
f_pass.focus();
return false;
}
}
f_pass.onkeydown = function(e) {
if (e.keyCode == 13) {
login_form.submit();
return false;
}
}
f_user.focus();
</script>
</body>
</html>

View File

@@ -23,6 +23,7 @@ import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.auth.openid.OpenIdUrls;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.template.SiteHeaderFooter;
import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.CanonicalWebUrl;
@@ -62,15 +63,18 @@ class LoginForm extends HttpServlet {
private final OpenIdServiceImpl impl;
private final int maxRedirectUrlLength;
private final String ssoUrl;
private final SiteHeaderFooter header;
@Inject
LoginForm(
@CanonicalWebUrl @Nullable Provider<String> urlProvider,
@GerritServerConfig Config config,
AuthConfig authConfig,
OpenIdServiceImpl impl) {
OpenIdServiceImpl impl,
SiteHeaderFooter header) {
this.urlProvider = urlProvider;
this.impl = impl;
this.header = header;
this.maxRedirectUrlLength = config.getInt(
"openid", "maxRedirectUrlLength",
10);
@@ -231,7 +235,7 @@ class LoginForm extends HttpServlet {
cancel += "#" + token;
}
Document doc = HtmlDomUtil.parseFile(LoginForm.class, "LoginForm.html");
Document doc = header.parse(LoginForm.class, "LoginForm.html");
HtmlDomUtil.find(doc, "hostName").setTextContent(req.getServerName());
HtmlDomUtil.find(doc, "login_form").setAttribute("action", self);
HtmlDomUtil.find(doc, "cancel_link").setAttribute("href", cancel);

View File

@@ -27,50 +27,58 @@
background: #fff url('data:image/gif;base64,R0lGODlhEAAQAMQAAO3t7eHh4srKyvz8/P5pDP9rENLS0v/28P/17tXV1dHEvPDw8M3Nzfn5+d3d3f5jA97Syvnv6MfLzcfHx/1mCPx4Kc/S1Pf189C+tP+xgv/k1N3OxfHy9NLV1/39/f///yH5BAAAAAAALAAAAAAQABAAAAVq4CeOZGme6KhlSDoexdO6H0IUR+otwUYRkMDCUwIYJhLFTyGZJACAwQcgEAQ4kVuEE2AIGAOPQQAQwXCfS8KQGAwMjIYIUSi03B7iJ+AcnmclHg4TAh0QDzIpCw4WGBUZeikDFzk0lpcjIQA7') no-repeat scroll 5px 50%
}
</style>
<style id="gerrit_sitecss" type="text/css"></style>
</head>
<body>
<h1>Sign In to Gerrit Code Review at <span id="hostName">example.com</span></h1>
<form method="POST" action="#" id="login_form">
<input type="hidden" name="link" id="f_link" value="1" />
<div id="logo_box"><div id="logo_img"></div></div>
<div id="error_message">Invalid OpenID identifier.</div>
<div>
<input type="text"
name="id"
id="f_openid"
size="60"
tabindex="1" />
</div>
<div>
<input name="rememberme" id="f_remember"
type="checkbox"
value="1"
tabindex="2" />
<label for="f_remember">Remember me</label>
</div>
<div style="margin-bottom: 25px;">
<input type="submit" value="Sign In" id="f_submit" tabindex="3" />
<a href="../" id="cancel_link">Cancel</a>
</div>
<div id="gerrit_topmenu" style="height:45px;" class="gerritTopMenu"></div>
<div id="gerrit_header"></div>
<div id="gerrit_body" class="gerritBody">
<h1>Sign In to Gerrit Code Review at <span id="hostName">example.com</span></h1>
<form method="POST" action="#" id="login_form">
<input type="hidden" name="link" id="f_link" value="1" />
<div id="logo_box"><div id="logo_img"></div></div>
<div id="error_message">Invalid OpenID identifier.</div>
<div>
<input type="text"
name="id"
id="f_openid"
size="60"
tabindex="1" />
</div>
<div>
<input name="rememberme" id="f_remember"
type="checkbox"
value="1"
tabindex="2" />
<label for="f_remember">Remember me</label>
</div>
<div style="margin-bottom: 25px;">
<input type="submit" value="Sign In" id="f_submit" tabindex="3" />
<a href="../" id="cancel_link">Cancel</a>
</div>
<div id="provider_google">
<img height="16" width="16" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABsUlEQVR42rWSy0sbYRRH88fYhW5KQXThIkUQN6ISJFBBW6FFBN2UqlC78LVKFlHIoqWGakF8gUZ8gajVzKSKZpQmAWtK0pBmhkxmSgPuiuaYmRKhSEwU/ODyDZfzO8ydOxbLQx1NB0H4y8FBlmMpy9LyOavrKUoKB4IXvBsIIopRPJ441dY/2Fr8fAtFSxO0dkRy4eA1PDp+TkVlmGhMKS5IJOFpbYgj6fQalhV4UhVm0esvLojELimv1JiYOPwPflS2gM93WNoIXZ1nPC4/IRDQzYDTqTA0PM2dtuCZ8vGmV6SvP5srL/da5c+4TnNLFlvTMYmEVrpkazuM2x1naOQ7Dc1fqLOmaayXkaSz4hLHewm7fY+Z2R0iP+JmYGpym/q6DDb76u0CwR+g9+0FHz4u3wAdLh9VNWu5UX4VlqysfaXRDoODNz+aw7nDs9ZPpNPpwgJV1WhvF6m1/qb79T6fpwXm5kVGRnd5/mIdQSzwH2iahq7/27nxiq5xLy9fbdDWsUtPzyausRVC4VMMzmAMNv9syTdkWTZLVVUymYx5J5NJs5dKpVAUxaw8Z/SM7BV+fz9Uc4yYRAAAAABJRU5ErkJggg==" />
<a href="?id=https://www.google.com/accounts/o8/id" id="id_google">Sign in with a Google Account</a>
</div>
<div id="provider_yahoo">
<img height="16" width="16" src="data:image/gif;base64,R0lGODlhEAAQAPECAAAAAP8AAP///8zMzCH5BAEAAAMALAAAAAAQABAAAAIqnI+py30BY3AgAjCkfJDjiIAQlgUkNxqWkqrm0honKk7KhZOzw/f+fygAADs=" />
<a href="?id=https://me.yahoo.com" id="id_yahoo">Sign in with a Yahoo! ID</a>
</div>
<div id="provider_google">
<img height="16" width="16" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABsUlEQVR42rWSy0sbYRRH88fYhW5KQXThIkUQN6ISJFBBW6FFBN2UqlC78LVKFlHIoqWGakF8gUZ8gajVzKSKZpQmAWtK0pBmhkxmSgPuiuaYmRKhSEwU/ODyDZfzO8ydOxbLQx1NB0H4y8FBlmMpy9LyOavrKUoKB4IXvBsIIopRPJ441dY/2Fr8fAtFSxO0dkRy4eA1PDp+TkVlmGhMKS5IJOFpbYgj6fQalhV4UhVm0esvLojELimv1JiYOPwPflS2gM93WNoIXZ1nPC4/IRDQzYDTqTA0PM2dtuCZ8vGmV6SvP5srL/da5c+4TnNLFlvTMYmEVrpkazuM2x1naOQ7Dc1fqLOmaayXkaSz4hLHewm7fY+Z2R0iP+JmYGpym/q6DDb76u0CwR+g9+0FHz4u3wAdLh9VNWu5UX4VlqysfaXRDoODNz+aw7nDs9ZPpNPpwgJV1WhvF6m1/qb79T6fpwXm5kVGRnd5/mIdQSzwH2iahq7/27nxiq5xLy9fbdDWsUtPzyausRVC4VMMzmAMNv9syTdkWTZLVVUymYx5J5NJs5dKpVAUxaw8Z/SM7BV+fz9Uc4yYRAAAAABJRU5ErkJggg==" />
<a href="?id=https://www.google.com/accounts/o8/id" id="id_google">Sign in with a Google Account</a>
</div>
<div id="provider_yahoo">
<img height="16" width="16" src="data:image/gif;base64,R0lGODlhEAAQAPECAAAAAP8AAP///8zMzCH5BAEAAAMALAAAAAAQABAAAAIqnI+py30BY3AgAjCkfJDjiIAQlgUkNxqWkqrm0honKk7KhZOzw/f+fygAADs=" />
<a href="?id=https://me.yahoo.com" id="id_yahoo">Sign in with a Yahoo! ID</a>
</div>
<div style="margin-top: 25px;">
<h2>What is OpenID?</h2>
<p>OpenID provides secure single-sign-on, without revealing your passwords to this website.</p>
<p>There are many OpenID providers available. You may already be member of one!</p>
<p><a href="http://openid.net/get/" target="_blank">Get OpenID</a></p>
</div>
</form>
<div style="margin-top: 25px;">
<h2>What is OpenID?</h2>
<p>OpenID provides secure single-sign-on, without revealing your passwords to this website.</p>
<p>There are many OpenID providers available. You may already be member of one!</p>
<p><a href="http://openid.net/get/" target="_blank">Get OpenID</a></p>
</div>
</form>
</div>
<div style="clear: both; margin-top: 15px; padding-top: 2px; margin-bottom: 15px;">
<div id="gerrit_footer"></div>
</div>
<script type="text/javascript" language="javascript">
<script type="text/javascript">
var f_openid = document.getElementById('f_openid');
var f_submit = document.getElementById('f_submit');
if (f_openid.value == '')

View File

@@ -50,7 +50,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -95,7 +94,7 @@ public class PluginLoader implements LifecycleListener {
disabled = Maps.newConcurrentMap();
broken = Maps.newHashMap();
toCleanup = Queues.newArrayDeque();
cleanupHandles = new Hashtable<Plugin,CleanupHandle>();
cleanupHandles = Maps.newConcurrentMap();
cleaner = pct;
long checkFrequency = ConfigUtil.getTimeUnit(cfg,