blob: 97ab18899c2235dfa1b7642fc8bb20bec5d01154 [file] [log] [blame]
// 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.googlesource.gerrit.plugins.gitiles;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.webui.BranchWebLink;
import com.google.gerrit.extensions.webui.FileHistoryWebLink;
import com.google.gerrit.extensions.webui.FileWebLink;
import com.google.gerrit.extensions.webui.ParentWebLink;
import com.google.gerrit.extensions.webui.PatchSetWebLink;
import com.google.gerrit.extensions.webui.ProjectWebLink;
import com.google.gerrit.extensions.webui.TagWebLink;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
import com.google.gitiles.ArchiveFormat;
import com.google.gitiles.DefaultUrls;
import com.google.gitiles.GitilesAccess;
import com.google.gitiles.GitilesUrls;
import com.google.inject.Inject;
import com.google.inject.Provides;
import com.google.inject.ProvisionException;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.transport.resolver.RepositoryResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class PluginModule extends LifecycleModule {
private final boolean noWebLinks;
private final String cloneUrlType;
private static final Logger log = LoggerFactory.getLogger(Module.class);
@Inject
PluginModule(PluginConfigFactory configFactory) {
Config config = configFactory.getGlobalPluginConfig("gitiles");
this.noWebLinks = config.getBoolean("gerrit", null, "noWebLinks", false);
this.cloneUrlType = config.getString("gerrit", null, "cloneUrlType");
}
@Override
protected void configure() {
if (!noWebLinks) {
DynamicSet.bind(binder(), BranchWebLink.class).to(GitilesWeblinks.class);
DynamicSet.bind(binder(), FileHistoryWebLink.class).to(GitilesWeblinks.class);
DynamicSet.bind(binder(), FileWebLink.class).to(GitilesWeblinks.class);
DynamicSet.bind(binder(), ParentWebLink.class).to(GitilesWeblinks.class);
DynamicSet.bind(binder(), PatchSetWebLink.class).to(GitilesWeblinks.class);
DynamicSet.bind(binder(), ProjectWebLink.class).to(GitilesWeblinks.class);
DynamicSet.bind(binder(), TagWebLink.class).to(GitilesWeblinks.class);
}
bind(GitilesAccess.Factory.class).to(GerritGitilesAccess.Factory.class);
bind(new TypeLiteral<RepositoryResolver<HttpServletRequest>>() {}).to(Resolver.class);
listener().to(Lifecycle.class);
}
private Optional<String> getSshCloneUrl(URL gerritUrl, List<String> advertisedSshAddresses) {
try {
if (!advertisedSshAddresses.isEmpty()) {
String addr = advertisedSshAddresses.get(0);
int index = addr.indexOf(":");
String port = "";
if (index != -1) {
port = addr.substring(index);
}
if (addr.startsWith("*:") || "".equals(addr)) {
if (gerritUrl != null && gerritUrl.getHost() != null) {
addr = gerritUrl.getHost();
} else {
addr = getLocalHostName();
}
} else {
if (index != -1) {
addr = addr.substring(0, index);
}
}
return Optional.of("ssh://" + addr + port + "/");
}
} catch (UnknownHostException e) {
log.error("Unable to get SSH clone url.", e);
return Optional.empty();
}
return Optional.empty();
}
private Optional<String> getHttpCloneUrl(Config gerritConfig) {
Optional<String> httpUrl =
Optional.ofNullable(gerritConfig.getString("gerrit", null, "gitHttpUrl"));
if (httpUrl.isEmpty()) {
return getDefaultCloneUrl(gerritConfig);
}
return httpUrl;
}
private Optional<String> getGitCloneUrl(Config gerritConfig) {
Optional<String> gitUrl =
Optional.ofNullable(gerritConfig.getString("gerrit", null, "canonicalGitUrl"));
if (gitUrl.isEmpty()) {
return getDefaultCloneUrl(gerritConfig);
}
return gitUrl;
}
private Optional<String> getDefaultCloneUrl(Config gerritConfig) {
return Optional.ofNullable(gerritConfig.getString("gerrit", null, "canonicalWebUrl"));
}
private Optional<String> getUserConfig(
Config gerritConfig, URL u, @SshAdvertisedAddresses List<String> advertisedSshAddresses) {
Optional<String> gitUrl = Optional.empty();
// Try to use user's config first.
if (this.cloneUrlType != null) {
switch (this.cloneUrlType) {
case "ssh":
gitUrl = getSshCloneUrl(u, advertisedSshAddresses);
break;
case "http":
gitUrl = getHttpCloneUrl(gerritConfig);
break;
case "git":
gitUrl = getGitCloneUrl(gerritConfig);
break;
}
if (gitUrl.isEmpty()) {
log.info(
"Failed to use clone url type configuration."
+ " Using default type (prefer SSH, then HTTP, then Git).");
}
}
return gitUrl;
}
@Provides
GitilesUrls getGitilesUrls(
@GerritServerConfig Config gerritConfig,
@Nullable @CanonicalWebUrl String gerritUrl,
@SshAdvertisedAddresses List<String> advertisedSshAddresses)
throws MalformedURLException, UnknownHostException {
URL u;
String hostName;
if (gerritUrl != null) {
u = new URL(gerritUrl);
hostName = u.getHost() != null ? u.getHost() : getLocalHostName();
} else {
u = null;
hostName = "Gerrit";
}
// If no config is set, or we can't get the chosen type of URL determined in the config,
// arbitrarily prefer SSH, then HTTP, then git.
String gitUrl =
Stream.of(
getUserConfig(gerritConfig, u, advertisedSshAddresses),
getSshCloneUrl(u, advertisedSshAddresses),
getHttpCloneUrl(gerritConfig),
getGitCloneUrl(gerritConfig))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseThrow(
() ->
new ProvisionException(
"Unable to determine any canonical git URL from gerrit.config"));
return new DefaultUrls(hostName, gitUrl, gerritUrl);
}
private String getLocalHostName() throws UnknownHostException {
return InetAddress.getLocalHost().getCanonicalHostName();
}
@Singleton
static class Lifecycle implements LifecycleListener {
@Override
public void start() {
// Do nothing.
}
@Override
public void stop() {
ArchiveFormat.unregisterAll();
}
}
}