| // 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(); |
| } |
| } |
| } |