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

com.intellij.openapi.updateSettings.impl.PluginDownloader Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition platform-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * 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.intellij.openapi.updateSettings.impl;

import com.intellij.ide.IdeBundle;
import com.intellij.ide.plugins.*;
import com.intellij.ide.startup.StartupActionScriptManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.BuildNumber;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.io.HttpRequests;
import com.intellij.util.io.ZipUtil;
import com.intellij.util.text.VersionComparatorUtil;
import org.apache.http.client.utils.URIBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * @author anna
 * @since 10-Aug-2007
 */
public class PluginDownloader {
  private static final Logger LOG = Logger.getInstance("#" + PluginDownloader.class.getName());

  private static final String FILENAME = "filename=";

  private final String myPluginId;
  private final String myPluginUrl;
  private final String myPluginName;
  private String myPluginVersion;
  private BuildNumber myBuildNumber;

  private File myFile;
  private File myOldFile;
  private String myDescription;
  private List myDepends;
  private IdeaPluginDescriptor myDescriptor;
  private boolean myForceHttps;

  private PluginDownloader(@NotNull String pluginId,
                           @NotNull String pluginUrl,
                           @Nullable String pluginName,
                           @Nullable String pluginVersion,
                           @Nullable BuildNumber buildNumber) {
    myPluginId = pluginId;
    myPluginUrl = pluginUrl;
    myPluginVersion = pluginVersion;
    myPluginName = pluginName;
    myBuildNumber = buildNumber;
  }

  public String getPluginId() {
    return myPluginId;
  }

  public String getPluginVersion() {
    return myPluginVersion;
  }

  public String getPluginName() {
    return myPluginName != null ? myPluginName : myPluginId;
  }

  public BuildNumber getBuildNumber() {
    return myBuildNumber;
  }

  public String getDescription() {
    return myDescription;
  }

  public void setDescription(String description) {
    myDescription = description;
  }

  public List getDepends() {
    return myDepends;
  }

  public void setDepends(List depends) {
    myDepends = depends;
  }

  public IdeaPluginDescriptor getDescriptor() {
    return myDescriptor;
  }

  public void setDescriptor(IdeaPluginDescriptor descriptor) {
    myDescriptor = descriptor;
  }

  public void setForceHttps(boolean forceHttps) {
    myForceHttps = forceHttps;
  }

  public boolean prepareToInstall(@NotNull ProgressIndicator indicator) throws IOException {
    if (myFile != null) {
      return true;
    }

    IdeaPluginDescriptor descriptor = null;
    if (!Boolean.getBoolean(StartupActionScriptManager.STARTUP_WIZARD_MODE) && PluginManager.isPluginInstalled(PluginId.getId(myPluginId))) {
      //store old plugins file
      descriptor = PluginManager.getPlugin(PluginId.getId(myPluginId));
      LOG.assertTrue(descriptor != null);
      if (myPluginVersion != null && compareVersionsSkipBroken(descriptor, myPluginVersion) <= 0) {
        LOG.info("Plugin " + myPluginId + ": current version (max) " + myPluginVersion);
        return false;
      }
      myOldFile = descriptor.getPath();
    }

    // download plugin
    String errorMessage = IdeBundle.message("unknown.error");
    try {
      myFile = downloadPlugin(indicator);
    }
    catch (IOException ex) {
      myFile = null;
      LOG.warn(ex);
      errorMessage = ex.getMessage();
    }
    if (myFile == null) {
      if (ApplicationManager.getApplication() != null) {
        final String text = IdeBundle.message("error.plugin.was.not.installed", getPluginName(), errorMessage);
        final String title = IdeBundle.message("title.failed.to.download");
        ApplicationManager.getApplication().invokeLater(new Runnable() {
          @Override
          public void run() {
            Messages.showErrorDialog(text, title);
          }
        });
      }
      return false;
    }

    IdeaPluginDescriptorImpl actualDescriptor = loadDescriptionFromJar(myFile);
    if (actualDescriptor != null) {
      InstalledPluginsState state = InstalledPluginsState.getInstanceIfLoaded();
      if (state != null && state.wasUpdated(actualDescriptor.getPluginId())) {
        return false; //already updated
      }

      myPluginVersion = actualDescriptor.getVersion();
      if (descriptor != null && compareVersionsSkipBroken(descriptor, myPluginVersion) <= 0) {
        LOG.info("Plugin " + myPluginId + ": current version (max) " + myPluginVersion);
        return false; //was not updated
      }

      setDescriptor(actualDescriptor);

      if (PluginManagerCore.isIncompatible(actualDescriptor, myBuildNumber)) {
        LOG.info("Plugin " + myPluginId + " is incompatible with current installation " +
                 "(since:" + actualDescriptor.getSinceBuild() + " until:" + actualDescriptor.getUntilBuild() + ")");
        return false; //host outdated plugins, no compatible plugin for new version
      }
    }
    return true;
  }

  public static int compareVersionsSkipBroken(@NotNull IdeaPluginDescriptor descriptor, String newPluginVersion) {
    int state = comparePluginVersions(newPluginVersion, descriptor.getVersion());
    if (PluginManagerCore.isBrokenPlugin(descriptor) && state < 0) {
      state = 1;
    }
    return state;
  }

  public static int comparePluginVersions(String newPluginVersion, String oldPluginVersion) {
    return VersionComparatorUtil.compare(newPluginVersion, oldPluginVersion);
  }

  @Nullable
  public static IdeaPluginDescriptorImpl loadDescriptionFromJar(final File file) throws IOException {
    IdeaPluginDescriptorImpl descriptor = PluginManagerCore.loadDescriptorFromJar(file);
    if (descriptor == null) {
      if (file.getName().endsWith(".zip")) {
        final File outputDir = FileUtil.createTempDirectory("plugin", "");
        try {
          ZipUtil.extract(file, outputDir, null);
          final File[] files = outputDir.listFiles();
          if (files != null && files.length == 1) {
            descriptor = PluginManagerCore.loadDescriptor(files[0], PluginManagerCore.PLUGIN_XML);
          }
        }
        finally {
          FileUtil.delete(outputDir);
        }
      }
    }
    return descriptor;
  }

  public void install() throws IOException {
    LOG.assertTrue(myFile != null);
    if (myOldFile != null) {
      // add command to delete the 'action script' file
      StartupActionScriptManager.ActionCommand deleteOld = new StartupActionScriptManager.DeleteCommand(myOldFile);
      StartupActionScriptManager.addActionCommand(deleteOld);
    }
    PluginInstaller.install(myFile, getPluginName(), true);
    InstalledPluginsState state = InstalledPluginsState.getInstanceIfLoaded();
    if (state != null) {
      state.onPluginInstall(myDescriptor);
    }
  }

  @NotNull
  private File downloadPlugin(@NotNull final ProgressIndicator indicator) throws IOException {
    File pluginsTemp = new File(PathManager.getPluginTempPath());
    if (!pluginsTemp.exists() && !pluginsTemp.mkdirs()) {
      throw new IOException(IdeBundle.message("error.cannot.create.temp.dir", pluginsTemp));
    }
    final File file = FileUtil.createTempFile(pluginsTemp, "plugin_", "_download", true, false);

    indicator.checkCanceled();
    indicator.setText2(IdeBundle.message("progress.downloading.plugin", getPluginName()));

    return HttpRequests.request(myPluginUrl).gzip(false).forceHttps(myForceHttps).connect(new HttpRequests.RequestProcessor() {
      @Override
      public File process(@NotNull HttpRequests.Request request) throws IOException {
        request.saveToFile(file, indicator);

        String fileName = guessFileName(request.getConnection(), file);
        File newFile = new File(file.getParentFile(), fileName);
        FileUtil.rename(file, newFile);
        return newFile;
      }
    });
  }

  @NotNull
  private String guessFileName(@NotNull URLConnection connection, @NotNull File file) throws IOException {
    String fileName = null;

    final String contentDisposition = connection.getHeaderField("Content-Disposition");
    LOG.debug("header: " + contentDisposition);

    if (contentDisposition != null && contentDisposition.contains(FILENAME)) {
      final int startIdx = contentDisposition.indexOf(FILENAME);
      final int endIdx = contentDisposition.indexOf(';', startIdx);
      fileName = contentDisposition.substring(startIdx + FILENAME.length(), endIdx > 0 ? endIdx : contentDisposition.length());

      if (StringUtil.startsWithChar(fileName, '\"') && StringUtil.endsWithChar(fileName, '\"')) {
        fileName = fileName.substring(1, fileName.length() - 1);
      }
    }

    if (fileName == null) {
      // try to find a filename in an URL
      final String usedURL = connection.getURL().toString();
      fileName = usedURL.substring(usedURL.lastIndexOf('/') + 1);
      if (fileName.length() == 0 || fileName.contains("?")) {
        fileName = myPluginUrl.substring(myPluginUrl.lastIndexOf('/') + 1);
      }
    }

    if (!PathUtil.isValidFileName(fileName)) {
      FileUtil.delete(file);
      throw new IOException("Invalid filename returned by a server");
    }

    return fileName;
  }

  // creators-converters

  public static PluginDownloader createDownloader(@NotNull IdeaPluginDescriptor descriptor) throws IOException {
    return createDownloader(descriptor, null, null);
  }

  @NotNull
  public static PluginDownloader createDownloader(@NotNull IdeaPluginDescriptor descriptor,
                                                  @Nullable String host,
                                                  @Nullable BuildNumber buildNumber) throws IOException {
    try {
      String url = getUrl(descriptor, host, buildNumber);
      String id = descriptor.getPluginId().getIdString();
      PluginDownloader downloader = new PluginDownloader(id, url, descriptor.getName(), descriptor.getVersion(), buildNumber);
      downloader.setDescriptor(descriptor);
      downloader.setDescription(descriptor.getDescription());
      List depends;
      if (descriptor instanceof PluginNode) {
        depends = ((PluginNode)descriptor).getDepends();
      }
      else {
        depends = new ArrayList(Arrays.asList(descriptor.getDependentPluginIds()));
      }
      downloader.setDepends(depends);
      return downloader;
    }
    catch (URISyntaxException e) {
      throw new IOException(e);
    }
  }

  @NotNull
  private static String getUrl(@NotNull IdeaPluginDescriptor descriptor,
                               @Nullable String host,
                               @Nullable BuildNumber buildNumber) throws URISyntaxException, MalformedURLException {
    if (host != null && descriptor instanceof PluginNode) {
      String url = ((PluginNode)descriptor).getDownloadUrl();
      return new URI(url).isAbsolute() ? url : new URL(new URL(host), url).toExternalForm();
    }
    else {
      Application app = ApplicationManager.getApplication();
      ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance();

      String buildNumberAsString = buildNumber != null ? buildNumber.asString() :
                                   app != null ? ApplicationInfo.getInstance().getApiVersion() :
                                   appInfo.getBuild().asString();

      String uuid = app != null ? UpdateChecker.getInstallationUID(PropertiesComponent.getInstance()) : UUID.randomUUID().toString();

      URIBuilder uriBuilder = new URIBuilder(appInfo.getPluginsDownloadUrl());
      uriBuilder.addParameter("action", "download");
      uriBuilder.addParameter("id", descriptor.getPluginId().getIdString());
      uriBuilder.addParameter("build", buildNumberAsString);
      uriBuilder.addParameter("uuid", uuid);
      return uriBuilder.toString();
    }
  }

  @Nullable
  public static PluginNode createPluginNode(@Nullable String host, @NotNull PluginDownloader downloader) {
    IdeaPluginDescriptor descriptor = downloader.getDescriptor();
    if (descriptor instanceof PluginNode) {
      return (PluginNode)descriptor;
    }

    PluginNode node = new PluginNode(PluginId.getId(downloader.getPluginId()));
    node.setName(downloader.getPluginName());
    node.setVersion(downloader.getPluginVersion());
    node.setRepositoryName(host);
    node.setDownloadUrl(downloader.myPluginUrl);
    node.setDepends(downloader.getDepends(), null);
    node.setDescription(downloader.getDescription());
    return node;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy