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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#gerrit_topmenu {
left: 60px;
margin-right: 60px;
padding-right: 10px;
position: relative;
}
#gerrit_header { #diffy_logo {
display: block !important; display: block !important;
margin-bottom: -55px; margin-bottom: -55px;
padding-left: 20px; padding-left: 20px;
position: relative; position: relative;
top: -45px; top: -45px;
width: 100px; width: 60px;
}
#gerrit_topmenu {
left: 100px;
margin-right: 100px;
padding-right: 10px;
position: relative;
} }

View File

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

View File

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

View File

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

View File

@@ -119,14 +119,17 @@ class HttpAuthFilter implements Filter {
WebSession session = sessionProvider.get(); WebSession session = sessionProvider.get();
if (session.isSignedIn()) { if (session.isSignedIn()) {
String user = getRemoteUser(req); String user = getRemoteUser(req);
AccountExternalId.Key id = session.getLastLoginExternalId(); return user == null || correctUser(user, session);
return user != null
&& id != null
&& id.equals(new AccountExternalId.Key(SCHEME_GERRIT, user));
} }
return false; 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) { String getRemoteUser(HttpServletRequest req) {
if (AUTHORIZATION.equals(loginHeader)) { if (AUTHORIZATION.equals(loginHeader)) {
String user = emptyToNull(req.getRemoteUser()); 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.common.PageLinks;
import com.google.gerrit.httpd.HtmlDomUtil; import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.WebSession; 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.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountUserNameException; 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.account.AuthResult;
import com.google.gerrit.server.auth.AuthenticationUnavailableException; import com.google.gerrit.server.auth.AuthenticationUnavailableException;
import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.SitePaths;
import com.google.gwtexpui.server.CacheHeaders; import com.google.gwtexpui.server.CacheHeaders;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -57,17 +56,17 @@ class LdapLoginServlet extends HttpServlet {
private final AccountManager accountManager; private final AccountManager accountManager;
private final Provider<WebSession> webSession; private final Provider<WebSession> webSession;
private final Provider<String> urlProvider; private final Provider<String> urlProvider;
private final SitePaths sitePaths; private final SiteHeaderFooter headers;
@Inject @Inject
LdapLoginServlet(AccountManager accountManager, LdapLoginServlet(AccountManager accountManager,
Provider<WebSession> webSession, Provider<WebSession> webSession,
@CanonicalWebUrl @Nullable Provider<String> urlProvider, @CanonicalWebUrl @Nullable Provider<String> urlProvider,
SitePaths sitePaths) { SiteHeaderFooter headers) {
this.accountManager = accountManager; this.accountManager = accountManager;
this.webSession = webSession; this.webSession = webSession;
this.urlProvider = urlProvider; this.urlProvider = urlProvider;
this.sitePaths = sitePaths; this.headers = headers;
if (Strings.isNullOrEmpty(urlProvider.get())) { if (Strings.isNullOrEmpty(urlProvider.get())) {
log.error("gerrit.canonicalWebUrl must be set in gerrit.config"); log.error("gerrit.canonicalWebUrl must be set in gerrit.config");
@@ -83,13 +82,7 @@ class LdapLoginServlet extends HttpServlet {
cancel += "#" + token; cancel += "#" + token;
} }
Document doc = Document doc = headers.parse(LdapLoginServlet.class, "LoginForm.html");
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);
HtmlDomUtil.find(doc, "hostName").setTextContent(req.getServerName()); HtmlDomUtil.find(doc, "hostName").setTextContent(req.getServerName());
HtmlDomUtil.find(doc, "login_form").setAttribute("action", self); HtmlDomUtil.find(doc, "login_form").setAttribute("action", self);
HtmlDomUtil.find(doc, "cancel_link").setAttribute("href", cancel); 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 @Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException { 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,8 +29,12 @@
} }
})(); })();
</script> </script>
<style id="gerrit_sitecss" type="text/css"></style>
</head> </head>
<body> <body>
<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> <h2>Sign In</h2>
<table border="0"> <table border="0">
<tr> <tr>
@@ -75,5 +79,9 @@
<input type="hidden" name="action" value="create_account" /> <input type="hidden" name="action" value="create_account" />
<input type="submit" value="New Account" /> <input type="submit" value="New Account" />
</form> </form>
</div>
<div style="clear: both; margin-top: 15px; padding-top: 2px; margin-bottom: 15px;">
<div id="gerrit_footer"></div>
</div>
</body> </body>
</html> </html>

View File

@@ -56,6 +56,10 @@
</tr> </tr>
</table> </table>
</form> </form>
<div style="clear: both; margin-top: 15px; padding-top: 2px; margin-bottom: 15px;">
<div id="gerrit_footer"></div>
</div>
</div>
<script type="text/javascript"> <script type="text/javascript">
var login_form = document.getElementById('login_form'); var login_form = document.getElementById('login_form');
@@ -75,9 +79,5 @@
} }
f_user.focus(); f_user.focus();
</script> </script>
<div style="clear: both; margin-top: 15px; padding-top: 2px; margin-bottom: 15px;">
<div id="gerrit_footer"></div>
</div>
</div>
</body> </body>
</html> </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.common.auth.openid.OpenIdUrls;
import com.google.gerrit.extensions.restapi.Url; import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.httpd.HtmlDomUtil; import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.template.SiteHeaderFooter;
import com.google.gerrit.reviewdb.client.AuthType; import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.server.config.CanonicalWebUrl;
@@ -62,15 +63,18 @@ class LoginForm extends HttpServlet {
private final OpenIdServiceImpl impl; private final OpenIdServiceImpl impl;
private final int maxRedirectUrlLength; private final int maxRedirectUrlLength;
private final String ssoUrl; private final String ssoUrl;
private final SiteHeaderFooter header;
@Inject @Inject
LoginForm( LoginForm(
@CanonicalWebUrl @Nullable Provider<String> urlProvider, @CanonicalWebUrl @Nullable Provider<String> urlProvider,
@GerritServerConfig Config config, @GerritServerConfig Config config,
AuthConfig authConfig, AuthConfig authConfig,
OpenIdServiceImpl impl) { OpenIdServiceImpl impl,
SiteHeaderFooter header) {
this.urlProvider = urlProvider; this.urlProvider = urlProvider;
this.impl = impl; this.impl = impl;
this.header = header;
this.maxRedirectUrlLength = config.getInt( this.maxRedirectUrlLength = config.getInt(
"openid", "maxRedirectUrlLength", "openid", "maxRedirectUrlLength",
10); 10);
@@ -231,7 +235,7 @@ class LoginForm extends HttpServlet {
cancel += "#" + token; 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, "hostName").setTextContent(req.getServerName());
HtmlDomUtil.find(doc, "login_form").setAttribute("action", self); HtmlDomUtil.find(doc, "login_form").setAttribute("action", self);
HtmlDomUtil.find(doc, "cancel_link").setAttribute("href", cancel); HtmlDomUtil.find(doc, "cancel_link").setAttribute("href", cancel);

View File

@@ -27,8 +27,12 @@
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% 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>
<style id="gerrit_sitecss" type="text/css"></style>
</head> </head>
<body> <body>
<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> <h1>Sign In to Gerrit Code Review at <span id="hostName">example.com</span></h1>
<form method="POST" action="#" id="login_form"> <form method="POST" action="#" id="login_form">
<input type="hidden" name="link" id="f_link" value="1" /> <input type="hidden" name="link" id="f_link" value="1" />
@@ -69,8 +73,12 @@
<p><a href="http://openid.net/get/" target="_blank">Get OpenID</a></p> <p><a href="http://openid.net/get/" target="_blank">Get OpenID</a></p>
</div> </div>
</form> </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_openid = document.getElementById('f_openid');
var f_submit = document.getElementById('f_submit'); var f_submit = document.getElementById('f_submit');
if (f_openid.value == '') if (f_openid.value == '')

View File

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