All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.batch.bootstrap.BatchPluginInstaller Maven / Gradle / Ivy

There is a newer version: 25.1.0.102122
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.batch.bootstrap;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.Plugin;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.RemotePlugin;
import org.sonar.core.platform.RemotePluginFile;
import org.sonar.home.cache.FileCache;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsResponse;

import static java.lang.String.format;

/**
 * Downloads the plugins installed on server and stores them in a local user cache
 * (see {@link FileCacheProvider}).
 */
public class BatchPluginInstaller implements PluginInstaller {

  private static final Logger LOG = Loggers.get(BatchPluginInstaller.class);
  private static final String PLUGINS_INDEX_URL = "/deploy/plugins/index.txt";

  private final FileCache fileCache;
  private final BatchPluginPredicate pluginPredicate;
  private final BatchWsClient wsClient;

  public BatchPluginInstaller(BatchWsClient wsClient, FileCache fileCache, BatchPluginPredicate pluginPredicate) {
    this.fileCache = fileCache;
    this.pluginPredicate = pluginPredicate;
    this.wsClient = wsClient;
  }

  @Override
  public Map installRemotes() {
    return loadPlugins(listRemotePlugins());
  }

  private Map loadPlugins(List remotePlugins) {
    Map infosByKey = new HashMap<>();

    Profiler profiler = Profiler.create(LOG).startDebug("Load plugins");

    for (RemotePlugin remotePlugin : remotePlugins) {
      if (pluginPredicate.apply(remotePlugin.getKey())) {
        File jarFile = download(remotePlugin);
        PluginInfo info = PluginInfo.create(jarFile);
        infosByKey.put(info.getKey(), info);
      }
    }

    profiler.stopDebug();
    return infosByKey;
  }

  /**
   * Returns empty on purpose. This method is used only by tests.
   * @see org.sonar.batch.mediumtest.BatchMediumTester
   */
  @Override
  public Map installLocals() {
    return Collections.emptyMap();
  }

  @VisibleForTesting
  File download(final RemotePlugin remote) {
    try {
      final RemotePluginFile file = remote.file();
      return fileCache.get(file.getFilename(), file.getHash(), new FileDownloader(remote.getKey()));
    } catch (Exception e) {
      throw new IllegalStateException("Fail to download plugin: " + remote.getKey(), e);
    }
  }

  /**
   * Gets information about the plugins installed on server (filename, checksum)
   */
  @VisibleForTesting
  List listRemotePlugins() {
    try {
      String pluginIndex = loadPluginIndex();
      String[] rows = StringUtils.split(pluginIndex, CharUtils.LF);
      List result = Lists.newArrayList();
      for (String row : rows) {
        result.add(RemotePlugin.unmarshal(row));
      }
      return result;

    } catch (Exception e) {
      throw new IllegalStateException("Fail to load plugin index: " + PLUGINS_INDEX_URL, e);
    }
  }

  private String loadPluginIndex() {
    Profiler profiler = Profiler.create(LOG).startInfo("Load plugins index");
    GetRequest getRequest = new GetRequest(PLUGINS_INDEX_URL);
    String str;
    try (Reader reader = wsClient.call(getRequest).contentReader()) {
      str = IOUtils.toString(reader);
    } catch(IOException e) {
      throw new IllegalStateException(e);
    }
    
    profiler.stopInfo();
    return str;
  }

  private class FileDownloader implements FileCache.Downloader {
    private String key;

    FileDownloader(String key) {
      this.key = key;
    }

    @Override
    public void download(String filename, File toFile) throws IOException {
      String url = format("/deploy/plugins/%s/%s", key, filename);
      if (LOG.isDebugEnabled()) {
        LOG.debug("Download plugin {} to {}", filename, toFile);
      } else {
        LOG.info("Download {}", filename);
      }

      WsResponse response = wsClient.call(new GetRequest(url));
      try (InputStream stream = response.contentStream()) {
        FileUtils.copyInputStreamToFile(stream, toFile);
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy