mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[platform] IDE update strategy reworked
- the concept of a 'new channel' dropped; no confusing "new channel" dialog anymore (IDEA-144121) - updates are not restricted by a major version (IDEA-153386) - ability added to target updates for specific builds on a server side - UI tweaks (stable channel decription changed; ignored builds editing added)
This commit is contained in:
+2
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -28,11 +28,4 @@ public class UpdateStrategyCustomization {
|
||||
public boolean forceEapUpdateChannelForEapBuilds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the updater will allow patch updates to cross major version boundaries.
|
||||
*/
|
||||
public boolean allowMajorVersionUpdate() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
-22
@@ -23,8 +23,6 @@ import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.LicensingFacade;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -33,7 +31,6 @@ import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
import java.awt.*;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author anna
|
||||
@@ -76,25 +73,6 @@ public abstract class AbstractUpdateDialog extends DialogWrapper {
|
||||
app.invokeLater(() -> app.restart(true));
|
||||
}
|
||||
|
||||
protected void initLicensingInfo(@NotNull UpdateChannel channel, @SuppressWarnings("UnusedParameters") @NotNull BuildInfo build) {
|
||||
LicensingFacade facade = LicensingFacade.getInstance();
|
||||
if (facade != null) {
|
||||
if (channel.getLicensing().equals(UpdateChannel.LICENSING_EAP)) {
|
||||
myLicenseInfo = IdeBundle.message("updates.channel.bundled.key");
|
||||
}
|
||||
else {
|
||||
Date buildDate = build.getReleaseDate();
|
||||
Date expiration = facade.getLicenseExpirationDate();
|
||||
if (buildDate != null && facade.isPerpetualForProduct(buildDate)) {
|
||||
myLicenseInfo = IdeBundle.message("updates.fallback.build");
|
||||
}
|
||||
else if (expiration != null && expiration.after(new Date())) {
|
||||
myLicenseInfo = IdeBundle.message("updates.subscription.active.till", DateFormatUtil.formatAboutDialogDate(expiration));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void configureMessageArea(@NotNull JEditorPane area) {
|
||||
String messageBody = myEnableLink ? IdeBundle.message("updates.configure.label", ShowSettingsUtil.getSettingsMenuName()) : "";
|
||||
configureMessageArea(area, messageBody, null, null);
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -22,7 +22,7 @@ public enum ChannelStatus {
|
||||
EAP("eap", "Early Access Program"),
|
||||
MILESTONE("milestone", "Milestone Releases"),
|
||||
BETA("beta", "Beta Releases or Public Previews"),
|
||||
RELEASE("release", "New Major Version Releases");
|
||||
RELEASE("release", "Stable Releases");
|
||||
|
||||
private final String myCode;
|
||||
private final String myDisplayName;
|
||||
@@ -53,4 +53,4 @@ public enum ChannelStatus {
|
||||
public String toString() {
|
||||
return myDisplayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-38
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.updateSettings.impl;
|
||||
|
||||
import com.intellij.openapi.util.BuildNumber;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -22,61 +23,48 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CheckForUpdateResult {
|
||||
private final BuildInfo myNewBuildInSelectedChannel;
|
||||
private final UpdateChannel myUpdatedChannel;
|
||||
private final UpdateChannel myChannelToPropose;
|
||||
private final List<String> myAllChannelIds;
|
||||
private final UpdateStrategy.State myState;
|
||||
private final BuildInfo myNewBuild;
|
||||
private final UpdateChannel myUpdatedChannel;
|
||||
private final Exception myError;
|
||||
|
||||
public CheckForUpdateResult(@Nullable BuildInfo newBuildInSelectedChannel,
|
||||
@Nullable UpdateChannel updated,
|
||||
@Nullable UpdateChannel channelToPropose,
|
||||
@NotNull List<String> allChannelsIds) {
|
||||
myNewBuildInSelectedChannel = newBuildInSelectedChannel;
|
||||
myUpdatedChannel = updated;
|
||||
myChannelToPropose = channelToPropose;
|
||||
myAllChannelIds = allChannelsIds;
|
||||
public CheckForUpdateResult(@Nullable BuildInfo newBuild, @Nullable UpdateChannel updatedChannel) {
|
||||
myState = UpdateStrategy.State.LOADED;
|
||||
myNewBuild = newBuild;
|
||||
myUpdatedChannel = updatedChannel;
|
||||
myError = null;
|
||||
}
|
||||
|
||||
public CheckForUpdateResult(@NotNull UpdateStrategy.State state, @Nullable Exception e) {
|
||||
myNewBuildInSelectedChannel = null;
|
||||
myUpdatedChannel = null;
|
||||
myChannelToPropose = null;
|
||||
myAllChannelIds = Collections.emptyList();
|
||||
myState = state;
|
||||
myNewBuild = null;
|
||||
myUpdatedChannel = null;
|
||||
myError = e;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BuildInfo getNewBuildInSelectedChannel() {
|
||||
return myNewBuildInSelectedChannel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UpdateChannel getUpdatedChannel() {
|
||||
return myUpdatedChannel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UpdateChannel getChannelToPropose() {
|
||||
return myChannelToPropose;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getAllChannelsIds() {
|
||||
return myAllChannelIds;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public UpdateStrategy.State getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BuildInfo getNewBuild() {
|
||||
return myNewBuild;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PatchInfo findPatchForBuild(@NotNull BuildNumber build) {
|
||||
List<PatchInfo> patches = myNewBuild != null ? myNewBuild.getPatches() : Collections.emptyList();
|
||||
return patches.stream().filter(p -> p.isAvailable() && p.getFromBuild().compareTo(build) == 0).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UpdateChannel getUpdatedChannel() {
|
||||
return myUpdatedChannel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Exception getError() {
|
||||
return myError;
|
||||
}
|
||||
}
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.BrowserUtil;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ui.BrowserHyperlinkListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
class NewChannelDialog extends AbstractUpdateDialog {
|
||||
private final UpdateChannel myChannel;
|
||||
private final BuildInfo myLatestBuild;
|
||||
|
||||
public NewChannelDialog(@NotNull UpdateChannel channel) {
|
||||
super(false);
|
||||
myChannel = channel;
|
||||
myLatestBuild = channel.getLatestBuild();
|
||||
assert myLatestBuild != null;
|
||||
|
||||
initLicensingInfo(myChannel, myLatestBuild);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return new NewChannelPanel().myPanel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Action[] createActions() {
|
||||
return new Action[]{
|
||||
getOKAction(),
|
||||
|
||||
new AbstractAction(IdeBundle.message("updates.remind.later.button")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
UpdateSettings.getInstance().forgetChannelId(myChannel.getId());
|
||||
doCancelAction();
|
||||
}
|
||||
},
|
||||
|
||||
getCancelAction()
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getOkButtonText() {
|
||||
return IdeBundle.message("updates.more.info.button");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCancelButtonText() {
|
||||
return IdeBundle.message("updates.ignore.update.button");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
BrowserUtil.browse(Objects.requireNonNull(myChannel.getHomePageUrl(), "missing URL for channel " + myChannel.getId()));
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
private class NewChannelPanel {
|
||||
private JPanel myPanel;
|
||||
private JEditorPane myMessageArea;
|
||||
private JEditorPane myLicenseArea;
|
||||
|
||||
private NewChannelPanel() {
|
||||
String message = IdeBundle.message("updates.channel.name.message", myChannel.getName(), myLatestBuild.getMessage());
|
||||
configureMessageArea(myMessageArea, message, null, BrowserHyperlinkListener.INSTANCE);
|
||||
|
||||
if (myLicenseInfo != null) {
|
||||
configureMessageArea(myLicenseArea, myLicenseInfo, null, BrowserHyperlinkListener.INSTANCE);
|
||||
}
|
||||
else {
|
||||
myLicenseArea.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.updateSettings.impl.NewChannelDialog.NewChannelPanel">
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridBagLayout">
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="515" height="56"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="1f0d5" class="javax.swing.JEditorPane" binding="myMessageArea">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="50"/>
|
||||
</grid>
|
||||
<gridbag weightx="1.0" weighty="0.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<contentType value="text/html"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="63fa1" class="javax.swing.JEditorPane" binding="myLicenseArea">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="50"/>
|
||||
</grid>
|
||||
<gridbag top="10" left="0" bottom="0" right="0" weightx="0.0" weighty="0.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<contentType value="text/html"/>
|
||||
</properties>
|
||||
</component>
|
||||
<vspacer id="e7d5c">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
<gridbag weightx="0.0" weighty="0.0"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -26,7 +26,7 @@ import javax.swing.*;
|
||||
* @author pti
|
||||
*/
|
||||
class NoUpdatesDialog extends AbstractUpdateDialog {
|
||||
protected NoUpdatesDialog(boolean enableLink) {
|
||||
NoUpdatesDialog(boolean enableLink) {
|
||||
super(enableLink);
|
||||
init();
|
||||
}
|
||||
@@ -57,4 +57,4 @@ class NoUpdatesDialog extends AbstractUpdateDialog {
|
||||
configureMessageArea(myMessageArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -38,7 +38,7 @@ class PluginUpdateInfoDialog extends AbstractUpdateDialog {
|
||||
private final Collection<PluginDownloader> myUploadedPlugins;
|
||||
private final boolean myPlatformUpdate;
|
||||
|
||||
public PluginUpdateInfoDialog(Collection<PluginDownloader> uploadedPlugins, boolean enableLink) {
|
||||
PluginUpdateInfoDialog(Collection<PluginDownloader> uploadedPlugins, boolean enableLink) {
|
||||
super(enableLink);
|
||||
myUploadedPlugins = uploadedPlugins;
|
||||
myPlatformUpdate = false;
|
||||
|
||||
+14
-57
@@ -37,9 +37,7 @@ import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.updateSettings.UpdateStrategyCustomization
|
||||
import com.intellij.openapi.util.ActionCallback
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
@@ -56,7 +54,6 @@ import com.intellij.util.ui.UIUtil
|
||||
import com.intellij.xml.util.XmlStringUtil
|
||||
import org.apache.http.client.utils.URIBuilder
|
||||
import org.jdom.JDOMException
|
||||
import org.jetbrains.annotations.Contract
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URISyntaxException
|
||||
@@ -133,9 +130,7 @@ object UpdateChecker {
|
||||
val result = checkPlatformUpdate(updateSettings)
|
||||
|
||||
if (manualCheck && result.state == UpdateStrategy.State.LOADED) {
|
||||
val settings = UpdateSettings.getInstance()
|
||||
settings.saveLastCheckedInfo()
|
||||
settings.setKnownChannelIds(result.allChannelsIds)
|
||||
UpdateSettings.getInstance().saveLastCheckedInfo()
|
||||
}
|
||||
else if (result.state == UpdateStrategy.State.CONNECTION_ERROR) {
|
||||
val e = result.error
|
||||
@@ -149,24 +144,16 @@ object UpdateChecker {
|
||||
|
||||
indicator?.text = IdeBundle.message("updates.checking.plugins")
|
||||
|
||||
val buildNumber: BuildNumber? = result.newBuild?.apiVersion
|
||||
val incompatiblePlugins: MutableCollection<IdeaPluginDescriptor>? = if (buildNumber != null) HashSet<IdeaPluginDescriptor>() else null
|
||||
|
||||
val updatedPlugins: Collection<PluginDownloader>?
|
||||
val incompatiblePlugins: MutableCollection<IdeaPluginDescriptor>?
|
||||
|
||||
if (newChannelReady(result.channelToPropose)) {
|
||||
updatedPlugins = null
|
||||
incompatiblePlugins = null
|
||||
try {
|
||||
updatedPlugins = checkPluginsUpdate(updateSettings, indicator, incompatiblePlugins, buildNumber)
|
||||
}
|
||||
else {
|
||||
val buildNumber: BuildNumber? = result.newBuildInSelectedChannel?.apiVersion
|
||||
|
||||
incompatiblePlugins = if (buildNumber != null) HashSet<IdeaPluginDescriptor>() else null
|
||||
try {
|
||||
updatedPlugins = checkPluginsUpdate(updateSettings, indicator, incompatiblePlugins, buildNumber)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed", e.message))
|
||||
return
|
||||
}
|
||||
catch (e: IOException) {
|
||||
showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed", e.message))
|
||||
return
|
||||
}
|
||||
|
||||
// show result
|
||||
@@ -215,10 +202,7 @@ object UpdateChecker {
|
||||
return CheckForUpdateResult(UpdateStrategy.State.NOTHING_LOADED, null)
|
||||
}
|
||||
|
||||
val appInfo = ApplicationInfo.getInstance()
|
||||
val majorVersion = Integer.parseInt(appInfo.majorVersion)
|
||||
val customization = UpdateStrategyCustomization.getInstance()
|
||||
val strategy = UpdateStrategy(majorVersion, appInfo.build, updateInfo, settings, customization)
|
||||
val strategy = UpdateStrategy(ApplicationInfo.getInstance().build, updateInfo, settings)
|
||||
return strategy.checkForUpdates()
|
||||
}
|
||||
|
||||
@@ -362,11 +346,6 @@ object UpdateChecker {
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
private fun newChannelReady(channelToPropose: UpdateChannel?): Boolean {
|
||||
return channelToPropose?.getLatestBuild() != null
|
||||
}
|
||||
|
||||
private fun showUpdateResult(project: Project?,
|
||||
checkForUpdateResult: CheckForUpdateResult,
|
||||
updateSettings: UpdateSettings,
|
||||
@@ -374,14 +353,14 @@ object UpdateChecker {
|
||||
incompatiblePlugins: Collection<IdeaPluginDescriptor>?,
|
||||
enableLink: Boolean,
|
||||
alwaysShowResults: Boolean) {
|
||||
val channelToPropose = checkForUpdateResult.channelToPropose
|
||||
val updatedChannel = checkForUpdateResult.updatedChannel
|
||||
val latestBuild = checkForUpdateResult.newBuildInSelectedChannel
|
||||
val newBuild = checkForUpdateResult.newBuild
|
||||
|
||||
if (updatedChannel != null && latestBuild != null) {
|
||||
if (updatedChannel != null && newBuild != null) {
|
||||
val runnable = {
|
||||
val patch = checkForUpdateResult.findPatchForBuild(ApplicationInfo.getInstance().build)
|
||||
val forceHttps = updateSettings.canUseSecureConnection()
|
||||
UpdateInfoDialog(updatedChannel, latestBuild, enableLink, forceHttps, updatedPlugins, incompatiblePlugins).show()
|
||||
UpdateInfoDialog(updatedChannel, newBuild, patch, enableLink, forceHttps, updatedPlugins, incompatiblePlugins).show()
|
||||
}
|
||||
|
||||
if (alwaysShowResults) {
|
||||
@@ -392,28 +371,6 @@ object UpdateChecker {
|
||||
showNotification(project, message, runnable, NotificationUniqueType.UPDATE_IN_CHANNEL)
|
||||
}
|
||||
}
|
||||
else if (newChannelReady(channelToPropose)) {
|
||||
val runnable = {
|
||||
val dialog = NewChannelDialog(channelToPropose!!)
|
||||
dialog.show()
|
||||
// once we informed that new product is available (when new channel was detected), remember the fact
|
||||
if (dialog.exitCode == DialogWrapper.CANCEL_EXIT_CODE &&
|
||||
checkForUpdateResult.state == UpdateStrategy.State.LOADED &&
|
||||
!updateSettings.knownChannelsIds.contains(channelToPropose.id)) {
|
||||
val newIds = ArrayList(updateSettings.knownChannelsIds)
|
||||
newIds.add(channelToPropose.id)
|
||||
updateSettings.setKnownChannelIds(newIds)
|
||||
}
|
||||
}
|
||||
|
||||
if (alwaysShowResults) {
|
||||
runnable.invoke()
|
||||
}
|
||||
else {
|
||||
val message = IdeBundle.message("updates.new.version.available", ApplicationNamesInfo.getInstance().fullProductName)
|
||||
showNotification(project, message, runnable, NotificationUniqueType.NEW_CHANNEL)
|
||||
}
|
||||
}
|
||||
else if (updatedPlugins != null && !updatedPlugins.isEmpty()) {
|
||||
val runnable = { PluginUpdateInfoDialog(updatedPlugins, enableLink).show() }
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.updateSettings.impl
|
||||
|
||||
import com.intellij.openapi.application.ApplicationInfo
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import com.intellij.openapi.util.BuildRange
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import org.jdom.Element
|
||||
import org.jdom.JDOMException
|
||||
@@ -27,23 +27,15 @@ import java.util.*
|
||||
|
||||
class UpdatesInfo(node: Element) {
|
||||
private val products = node.getChildren("product").map { Product(it) }
|
||||
|
||||
val productsCount: Int
|
||||
get() = products.size
|
||||
|
||||
fun getProduct(code: String): Product? = products.find { it.hasCode(code) }
|
||||
operator fun get(code: String): Product? = products.find { code in it.codes }
|
||||
}
|
||||
|
||||
class Product(node: Element) {
|
||||
val name: String = node.getAttributeValue("name") ?: throw JDOMException("product.name missing")
|
||||
val name: String = node.getAttributeValue("name") ?: throw JDOMException("product@name missing")
|
||||
val codes: Set<String> = node.getChildren("code").map { it.value.trim() }.toSet()
|
||||
val channels: List<UpdateChannel> = node.getChildren("channel").map { UpdateChannel(it) }
|
||||
private val codes = node.getChildren("code").map { it.value.trim() }.toSet()
|
||||
|
||||
fun hasCode(code: String): Boolean = codes.contains(code)
|
||||
|
||||
fun findUpdateChannelById(id: String): UpdateChannel? = channels.find { it.id == id }
|
||||
|
||||
fun getAllChannelIds(): List<String> = channels.map { it.id }
|
||||
override fun toString() = codes.firstOrNull() ?: "-"
|
||||
}
|
||||
|
||||
class UpdateChannel(node: Element) {
|
||||
@@ -52,74 +44,50 @@ class UpdateChannel(node: Element) {
|
||||
const val LICENSING_PRODUCTION = "production"
|
||||
}
|
||||
|
||||
val id: String = node.getAttributeValue("id") ?: throw JDOMException("channel.id missing")
|
||||
val name: String = node.getAttributeValue("name") ?: throw JDOMException("channel.name missing")
|
||||
val id: String = node.getAttributeValue("id") ?: throw JDOMException("channel@id missing")
|
||||
val status: ChannelStatus = ChannelStatus.fromCode(node.getAttributeValue("status"))
|
||||
val licensing: String = node.getAttributeValue("licensing", LICENSING_PRODUCTION)
|
||||
val majorVersion: Int = node.getAttributeValue("majorVersion")?.toInt() ?: -1
|
||||
val homePageUrl: String? = node.getAttributeValue("url")
|
||||
val feedbackUrl: String? = node.getAttributeValue("feedback")
|
||||
val evalDays: Int = node.getAttributeValue("evalDays")?.toInt() ?: 30
|
||||
private val builds = node.getChildren("build").map { BuildInfo(it) }
|
||||
val builds: List<BuildInfo> = node.getChildren("build").map { BuildInfo(it) }
|
||||
|
||||
fun getLatestBuild(): BuildInfo? = latestBuild(builds)
|
||||
fun getLatestBuild(baseline: Int): BuildInfo? = latestBuild(builds.filter { it.number.baselineVersion == baseline })
|
||||
|
||||
private fun latestBuild(builds: List<BuildInfo>) =
|
||||
builds.fold(null as BuildInfo?) { best, candidate -> if (best == null || best.compareTo(candidate) < 0) candidate else best }
|
||||
override fun toString() = id
|
||||
}
|
||||
|
||||
class BuildInfo(node: Element) : Comparable<BuildInfo> {
|
||||
val number: BuildNumber = BuildNumber.fromString(node.getAttributeValue("number") ?: throw JDOMException("build.number missing"))
|
||||
val apiVersion: BuildNumber = node.getAttributeValue("apiVersion")?.let { BuildNumber.fromString(it, number.productCode) } ?: number
|
||||
class BuildInfo(node: Element) {
|
||||
val number: BuildNumber = BuildNumber.fromString(node.getAttributeValue("number") ?: throw JDOMException("build@number missing"))
|
||||
val apiVersion: BuildNumber = BuildNumber.fromString(node.getAttributeValue("apiVersion"), number.productCode) ?: number
|
||||
val version: String = node.getAttributeValue("version") ?: ""
|
||||
val message: String = node.getChild("message")?.value ?: ""
|
||||
val releaseDate: Date? = node.getAttributeValue("releaseDate")?.let {
|
||||
try { SimpleDateFormat("yyyyMMdd", Locale.US).parse(it) } // same as the 'majorReleaseDate' in ApplicationInfo.xml
|
||||
val releaseDate: Date? = parseDate(node.getAttributeValue("releaseDate"))
|
||||
val target: BuildRange? = BuildRange.fromStrings(node.getAttributeValue("targetSince"), node.getAttributeValue("targetUntil"))
|
||||
val buttons: List<ButtonInfo> = node.getChildren("button").map { ButtonInfo(it) }
|
||||
val patches: List<PatchInfo> = node.getChildren("patch").map { PatchInfo(it) }
|
||||
|
||||
private fun parseDate(value: String?): Date? = value?.let {
|
||||
try {
|
||||
SimpleDateFormat("yyyyMMdd", Locale.US).parse(it) // same as the 'majorReleaseDate' in ApplicationInfo.xml
|
||||
}
|
||||
catch (e: ParseException) {
|
||||
Logger.getInstance(BuildInfo::class.java).info("Failed to parse build release date " + it)
|
||||
null
|
||||
}
|
||||
}
|
||||
val buttons: List<ButtonInfo> = node.getChildren("button").map { ButtonInfo(it) }
|
||||
private val patches = node.getChildren("patch").map { PatchInfo(it) }
|
||||
|
||||
/**
|
||||
* Returns -1 if version information is missing or does not match to expected format "majorVer.minorVer"
|
||||
*/
|
||||
val majorVersion: Int
|
||||
get() {
|
||||
val dotIndex = version.indexOf('.')
|
||||
if (dotIndex > 0) {
|
||||
try {
|
||||
return version.substring(0, dotIndex).toInt()
|
||||
}
|
||||
catch (ignored: NumberFormatException) { }
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
fun findPatchForCurrentBuild(): PatchInfo? = findPatchForBuild(ApplicationInfo.getInstance().build)
|
||||
|
||||
fun findPatchForBuild(currentBuild: BuildNumber): PatchInfo? =
|
||||
patches.find { it.isAvailable && it.fromBuild.asStringWithoutProductCode() == currentBuild.asStringWithoutProductCode() }
|
||||
|
||||
override fun compareTo(other: BuildInfo): Int = number.compareTo(other.number)
|
||||
|
||||
override fun toString(): String = "BuildInfo(number=$number)"
|
||||
override fun toString() = "${number}/${version}"
|
||||
}
|
||||
|
||||
class ButtonInfo(node: Element) {
|
||||
val name: String = node.getAttributeValue("name") ?: throw JDOMException("button.name missing")
|
||||
val url: String = node.getAttributeValue("url") ?: throw JDOMException("button.url missing")
|
||||
val name: String = node.getAttributeValue("name") ?: throw JDOMException("button@name missing")
|
||||
val url: String = node.getAttributeValue("url") ?: throw JDOMException("button@url missing")
|
||||
val isDownload: Boolean = node.getAttributeValue("download") != null // a button marked with this attribute is hidden when a patch is available
|
||||
|
||||
override fun toString() = name
|
||||
}
|
||||
|
||||
class PatchInfo(node: Element) {
|
||||
val fromBuild: BuildNumber = BuildNumber.fromString(node.getAttributeValue("from") ?: throw JDOMException("patch.from missing"))
|
||||
val fromBuild: BuildNumber = BuildNumber.fromString(node.getAttributeValue("from") ?: throw JDOMException("patch@from missing"))
|
||||
val size: String? = node.getAttributeValue("size")
|
||||
val isAvailable: Boolean = node.getAttributeValue("exclusions")?.split(",")?.none { it.trim() == osSuffix } ?: true
|
||||
val isAvailable: Boolean = node.getAttributeValue("exclusions")?.splitToSequence(",")?.none { it.trim() == osSuffix } ?: true
|
||||
|
||||
val osSuffix: String
|
||||
get() = if (SystemInfo.isWindows) "win" else if (SystemInfo.isMac) "mac" else if (SystemInfo.isUnix) "unix" else "unknown"
|
||||
|
||||
+39
-15
@@ -29,16 +29,20 @@ import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.BrowserHyperlinkListener;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.LicensingFacade;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -48,25 +52,26 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
private final UpdateChannel myUpdatedChannel;
|
||||
private final boolean myForceHttps;
|
||||
private final Collection<PluginDownloader> myUpdatedPlugins;
|
||||
private final BuildInfo myLatestBuild;
|
||||
private final BuildInfo myNewBuild;
|
||||
private final PatchInfo myPatch;
|
||||
private final boolean myWriteProtected;
|
||||
|
||||
protected UpdateInfoDialog(@NotNull UpdateChannel channel,
|
||||
@NotNull BuildInfo latestBuild,
|
||||
boolean enableLink,
|
||||
boolean forceHttps,
|
||||
Collection<PluginDownloader> updatedPlugins,
|
||||
Collection<IdeaPluginDescriptor> incompatiblePlugins) {
|
||||
UpdateInfoDialog(@NotNull UpdateChannel channel,
|
||||
@NotNull BuildInfo newBuild,
|
||||
@Nullable PatchInfo patch,
|
||||
boolean enableLink,
|
||||
boolean forceHttps,
|
||||
Collection<PluginDownloader> updatedPlugins,
|
||||
Collection<IdeaPluginDescriptor> incompatiblePlugins) {
|
||||
super(enableLink);
|
||||
myUpdatedChannel = channel;
|
||||
myForceHttps = forceHttps;
|
||||
myUpdatedPlugins = updatedPlugins;
|
||||
myLatestBuild = latestBuild;
|
||||
myPatch = myLatestBuild.findPatchForCurrentBuild();
|
||||
myNewBuild = newBuild;
|
||||
myPatch = patch;
|
||||
myWriteProtected = myPatch != null && !new File(PathManager.getHomePath()).canWrite();
|
||||
getCancelAction().putValue(DEFAULT_ACTION, Boolean.TRUE);
|
||||
initLicensingInfo(myUpdatedChannel, myLatestBuild);
|
||||
initLicensingInfo(myUpdatedChannel, myNewBuild);
|
||||
init();
|
||||
|
||||
if (incompatiblePlugins != null && !incompatiblePlugins.isEmpty()) {
|
||||
@@ -80,6 +85,25 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private void initLicensingInfo(@NotNull UpdateChannel channel, @NotNull BuildInfo build) {
|
||||
LicensingFacade facade = LicensingFacade.getInstance();
|
||||
if (facade != null) {
|
||||
if (channel.getLicensing().equals(UpdateChannel.LICENSING_EAP)) {
|
||||
myLicenseInfo = IdeBundle.message("updates.channel.bundled.key");
|
||||
}
|
||||
else {
|
||||
Date buildDate = build.getReleaseDate();
|
||||
Date expiration = facade.getLicenseExpirationDate();
|
||||
if (buildDate != null && facade.isPerpetualForProduct(buildDate)) {
|
||||
myLicenseInfo = IdeBundle.message("updates.fallback.build");
|
||||
}
|
||||
else if (expiration != null && expiration.after(new Date())) {
|
||||
myLicenseInfo = IdeBundle.message("updates.subscription.active.till", DateFormatUtil.formatAboutDialogDate(expiration));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return new UpdateInfoPanel().myPanel;
|
||||
@@ -105,7 +129,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
});
|
||||
}
|
||||
|
||||
List<ButtonInfo> buttons = myLatestBuild.getButtons();
|
||||
List<ButtonInfo> buttons = myNewBuild.getButtons();
|
||||
if (buttons.isEmpty()) {
|
||||
actions.add(new AbstractAction(IdeBundle.message("updates.more.info.button")) {
|
||||
@Override
|
||||
@@ -125,7 +149,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
actions.add(new AbstractAction(IdeBundle.message("updates.ignore.update.button")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String build = myLatestBuild.getNumber().asStringWithoutProductCode();
|
||||
String build = myNewBuild.getNumber().asStringWithoutProductCode();
|
||||
UpdateSettings.getInstance().getIgnoredBuildNumbers().add(build);
|
||||
doCancelAction();
|
||||
}
|
||||
@@ -143,7 +167,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
|
||||
private void downloadPatchAndRestart() {
|
||||
try {
|
||||
UpdateChecker.installPlatformUpdate(myPatch, myLatestBuild.getNumber(), myForceHttps);
|
||||
UpdateChecker.installPlatformUpdate(myPatch, myNewBuild.getNumber(), myForceHttps);
|
||||
|
||||
if (myUpdatedPlugins != null && !myUpdatedPlugins.isEmpty()) {
|
||||
new PluginUpdateInfoDialog(getContentPanel(), myUpdatedPlugins).show();
|
||||
@@ -196,7 +220,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
ApplicationInfo appInfo = ApplicationInfo.getInstance();
|
||||
ApplicationNamesInfo appNames = ApplicationNamesInfo.getInstance();
|
||||
|
||||
String message = myLatestBuild.getMessage();
|
||||
String message = myNewBuild.getMessage();
|
||||
final String fullProductName = appNames.getFullProductName();
|
||||
if (StringUtil.isEmpty(message)) {
|
||||
message = IdeBundle.message("updates.new.version.available", fullProductName);
|
||||
@@ -217,7 +241,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
appInfo.getBuild().asStringWithoutProductCode()
|
||||
)
|
||||
);
|
||||
myNewVersion.setText(formatVersion(myLatestBuild.getVersion(), myLatestBuild.getNumber().asStringWithoutProductCode()));
|
||||
myNewVersion.setText(formatVersion(myNewBuild.getVersion(), myNewBuild.getNumber().asStringWithoutProductCode()));
|
||||
|
||||
if (myPatch != null && !StringUtil.isEmptyOrSpaces(myPatch.getSize())) {
|
||||
myPatchInfo.setText(myPatch.getSize() + " MB");
|
||||
|
||||
+2
-16
@@ -38,7 +38,6 @@ import java.util.List;
|
||||
public class UpdateSettings implements PersistentStateComponent<UpdateSettings.State>, UserUpdateSettings {
|
||||
public static class State {
|
||||
@CollectionBean public final List<String> pluginHosts = new SmartList<String>();
|
||||
@CollectionBean public final List<String> knownUpdateChannels = new SmartList<String>();
|
||||
@CollectionBean public final List<String> ignoredBuildNumbers = new SmartList<String>();
|
||||
|
||||
public boolean CHECK_NEEDED = true;
|
||||
@@ -98,21 +97,6 @@ public class UpdateSettings implements PersistentStateComponent<UpdateSettings.S
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getKnownChannelsIds() {
|
||||
return new ArrayList<String>(myState.knownUpdateChannels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKnownChannelIds(@NotNull List<String> ids) {
|
||||
myState.knownUpdateChannels.clear();
|
||||
myState.knownUpdateChannels.addAll(ids);
|
||||
}
|
||||
|
||||
public void forgetChannelId(String id) {
|
||||
myState.knownUpdateChannels.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getIgnoredBuildNumbers() {
|
||||
return myState.ignoredBuildNumbers;
|
||||
@@ -150,6 +134,7 @@ public class UpdateSettings implements PersistentStateComponent<UpdateSettings.S
|
||||
return myState.SECURE_CONNECTION && NetUtils.isSniEnabled();
|
||||
}
|
||||
|
||||
//<editor-fold desc="Deprecated stuff.">
|
||||
/** @deprecated use {@link #getSelectedChannelStatus()} (to be removed in IDEA 17) */
|
||||
@SuppressWarnings("unused")
|
||||
public String getUpdateChannelType() {
|
||||
@@ -161,4 +146,5 @@ public class UpdateSettings implements PersistentStateComponent<UpdateSettings.S
|
||||
public void setUpdateChannelType(@NotNull String value) {
|
||||
myState.UPDATE_CHANNEL_TYPE = value;
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
+24
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -17,6 +17,8 @@ package com.intellij.openapi.updateSettings.impl;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationInfo;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -26,11 +28,14 @@ import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.updateSettings.UpdateStrategyCustomization;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.labels.ActionLink;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -40,6 +45,7 @@ import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author pti
|
||||
@@ -146,13 +152,14 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear
|
||||
private final UpdateSettings mySettings;
|
||||
private JPanel myPanel;
|
||||
private JCheckBox myCheckForUpdates;
|
||||
private JComboBox myUpdateChannels;
|
||||
private JComboBox<ChannelStatus> myUpdateChannels;
|
||||
private JButton myCheckNow;
|
||||
private JBLabel myChannelWarning;
|
||||
private JCheckBox myUseSecureConnection;
|
||||
private JLabel myBuildNumber;
|
||||
private JLabel myVersionNumber;
|
||||
private JLabel myLastCheckedDate;
|
||||
@SuppressWarnings("unused") private ActionLink myIgnoredBuildsLink;
|
||||
|
||||
public UpdatesSettingsPanel(boolean checkNowEnabled) {
|
||||
mySettings = UpdateSettings.getInstance();
|
||||
@@ -207,6 +214,21 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear
|
||||
myChannelWarning.setForeground(JBColor.RED);
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
myIgnoredBuildsLink = new ActionLink(IdeBundle.message("updates.settings.ignored"), new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
List<String> buildNumbers = mySettings.getIgnoredBuildNumbers();
|
||||
String text = StringUtil.join(buildNumbers, "\n");
|
||||
String result = Messages.showMultilineInputDialog(null, null, IdeBundle.message("updates.settings.ignored.title"), text, null, null);
|
||||
if (result != null) {
|
||||
buildNumbers.clear();
|
||||
buildNumbers.addAll(StringUtil.split(result, "\n"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateLastCheckedLabel() {
|
||||
long time = mySettings.getLastTimeChecked();
|
||||
myLastCheckedDate.setText(time == 0 ? IdeBundle.message("updates.last.check.never") : DateFormatUtil.formatPrettyDateTime(time));
|
||||
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.openapi.updateSettings.UpdateStrategyCustomization;
|
||||
import com.intellij.openapi.util.BuildNumber;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UpdateStrategy {
|
||||
public enum State {LOADED, CONNECTION_ERROR, NOTHING_LOADED}
|
||||
|
||||
private final int myMajorVersion;
|
||||
private final BuildNumber myCurrentBuild;
|
||||
private final UpdatesInfo myUpdatesInfo;
|
||||
private final UserUpdateSettings myUpdateSettings;
|
||||
private final ChannelStatus myChannelStatus;
|
||||
private final UpdateStrategyCustomization myStrategyCustomization;
|
||||
|
||||
/** @deprecated use {@link #UpdateStrategy(int, BuildNumber, UpdatesInfo, UserUpdateSettings, UpdateStrategyCustomization)} */
|
||||
@SuppressWarnings("unused")
|
||||
public UpdateStrategy(int majorVersion,
|
||||
@NotNull BuildNumber currentBuild,
|
||||
@NotNull UpdatesInfo updatesInfo,
|
||||
@NotNull UserUpdateSettings updateSettings) {
|
||||
this(majorVersion, currentBuild, updatesInfo, updateSettings, UpdateStrategyCustomization.getInstance());
|
||||
}
|
||||
|
||||
public UpdateStrategy(int majorVersion,
|
||||
@NotNull BuildNumber currentBuild,
|
||||
@NotNull UpdatesInfo updatesInfo,
|
||||
@NotNull UserUpdateSettings updateSettings,
|
||||
@NotNull UpdateStrategyCustomization customization) {
|
||||
myMajorVersion = majorVersion;
|
||||
myCurrentBuild = currentBuild;
|
||||
myUpdatesInfo = updatesInfo;
|
||||
myUpdateSettings = updateSettings;
|
||||
myChannelStatus = updateSettings.getSelectedChannelStatus();
|
||||
myStrategyCustomization = customization;
|
||||
}
|
||||
|
||||
public final CheckForUpdateResult checkForUpdates() {
|
||||
Product product = myUpdatesInfo.getProduct(myCurrentBuild.getProductCode());
|
||||
|
||||
if (product == null || product.getChannels().isEmpty()) {
|
||||
return new CheckForUpdateResult(State.NOTHING_LOADED, null);
|
||||
}
|
||||
|
||||
UpdateChannel updatedChannel = null;
|
||||
BuildInfo newBuild = null;
|
||||
List<UpdateChannel> activeChannels = getActiveChannels(product);
|
||||
for (UpdateChannel channel : activeChannels) {
|
||||
BuildInfo latestBuild = channel.getLatestBuild(myCurrentBuild.getBaselineVersion());
|
||||
if (latestBuild == null || latestBuild.getNumber().compareTo(myCurrentBuild) <= 0) {
|
||||
latestBuild = channel.getLatestBuild();
|
||||
}
|
||||
if (isNewVersion(latestBuild)) {
|
||||
updatedChannel = channel;
|
||||
newBuild = latestBuild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateChannel channelToPropose = null;
|
||||
for (UpdateChannel channel : product.getChannels()) {
|
||||
if (!myUpdateSettings.getKnownChannelsIds().contains(channel.getId()) &&
|
||||
channel.getMajorVersion() >= myMajorVersion &&
|
||||
channel.getStatus().compareTo(myChannelStatus) >= 0 &&
|
||||
isNewVersion(channel.getLatestBuild()) &&
|
||||
(channelToPropose == null || isBetter(channelToPropose, channel))) {
|
||||
channelToPropose = channel;
|
||||
}
|
||||
}
|
||||
|
||||
return new CheckForUpdateResult(newBuild, updatedChannel, channelToPropose, product.getAllChannelIds());
|
||||
}
|
||||
|
||||
private List<UpdateChannel> getActiveChannels(Product product) {
|
||||
List<UpdateChannel> result = new ArrayList<UpdateChannel>();
|
||||
|
||||
for (UpdateChannel channel : product.getChannels()) {
|
||||
// If the update is to a new version and on a stabler channel, choose it.
|
||||
if ((channel.getMajorVersion() >= myMajorVersion && channel.getStatus().compareTo(myChannelStatus) >= 0) &&
|
||||
(myStrategyCustomization.allowMajorVersionUpdate() ||
|
||||
channel.getMajorVersion() == myMajorVersion ||
|
||||
channel.getStatus() == ChannelStatus.EAP && myChannelStatus == ChannelStatus.EAP)) {
|
||||
// Prefer channel that has same status as our selected channel status
|
||||
if (channel.getMajorVersion() == myMajorVersion && channel.getStatus().compareTo(myChannelStatus) == 0) {
|
||||
result.add(0, channel);
|
||||
}
|
||||
else {
|
||||
result.add(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isNewVersion(BuildInfo latestBuild) {
|
||||
return latestBuild != null &&
|
||||
!myUpdateSettings.getIgnoredBuildNumbers().contains(latestBuild.getNumber().asStringWithoutProductCode()) &&
|
||||
myCurrentBuild.compareTo(latestBuild.getNumber()) < 0;
|
||||
}
|
||||
|
||||
private static boolean isBetter(UpdateChannel channelToPropose, UpdateChannel channel) {
|
||||
return channel.getMajorVersion() > channelToPropose.getMajorVersion() ||
|
||||
channel.getMajorVersion() == channelToPropose.getMajorVersion() && channel.getStatus().compareTo(channelToPropose.getStatus()) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.openapi.updateSettings.UpdateStrategyCustomization
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import java.util.*
|
||||
|
||||
class UpdateStrategy(private val currentBuild: BuildNumber, private val updates: UpdatesInfo, private val settings: UserUpdateSettings) {
|
||||
enum class State {
|
||||
LOADED, CONNECTION_ERROR, NOTHING_LOADED
|
||||
}
|
||||
|
||||
fun checkForUpdates(): CheckForUpdateResult {
|
||||
val product = updates[currentBuild.productCode]
|
||||
if (product == null || product.channels.isEmpty()) {
|
||||
return CheckForUpdateResult(State.NOTHING_LOADED, null)
|
||||
}
|
||||
|
||||
val selectedChannel = settings.selectedChannelStatus
|
||||
val ignoredBuilds = settings.ignoredBuildNumbers.toSet()
|
||||
|
||||
val result = product.channels.asSequence()
|
||||
.filter { it.status.compareTo(selectedChannel) >= 0 }
|
||||
.sortedWith(Comparator { ch1, ch2 -> ch1.status.compareTo(ch2.status) }) // by stability, asc
|
||||
.map { ch -> ch.builds.asSequence().filter { build -> isApplicable(build, ignoredBuilds) } to ch }
|
||||
.map { p -> candidateBuild(p.first) to p.second }
|
||||
.filter { p -> p.first != null }
|
||||
.maxBy { p -> p.first!!.number }
|
||||
|
||||
return CheckForUpdateResult(result?.first, result?.second)
|
||||
}
|
||||
|
||||
private fun isApplicable(candidate: BuildInfo, ignoredBuilds: Set<String>) =
|
||||
candidate.number > currentBuild &&
|
||||
candidate.number.asStringWithoutProductCode() !in ignoredBuilds &&
|
||||
candidate.target?.inRange(currentBuild) ?: true
|
||||
|
||||
private fun candidateBuild(builds: Sequence<BuildInfo>) =
|
||||
latestBuild(builds.filter { it.number.baselineVersion == currentBuild.baselineVersion }) ?: latestBuild(builds)
|
||||
|
||||
private fun latestBuild(builds: Sequence<BuildInfo>) =
|
||||
builds.fold(null as BuildInfo?) { best, candidate -> if (best == null || candidate.number > best.number) candidate else best }
|
||||
|
||||
//<editor-fold desc="Deprecated stuff.">
|
||||
|
||||
@Deprecated("use {@link #UpdateStrategy(BuildNumber, UpdatesInfo, UserUpdateSettings)}")
|
||||
constructor(@Suppress("UNUSED_PARAMETER") majorVersion: Int,
|
||||
@Suppress("UNUSED_PARAMETER") currentBuild: BuildNumber,
|
||||
@Suppress("UNUSED_PARAMETER") updatesInfo: UpdatesInfo,
|
||||
@Suppress("UNUSED_PARAMETER") updateSettings: UserUpdateSettings) : this(currentBuild, updatesInfo, updateSettings) {
|
||||
}
|
||||
|
||||
|
||||
@Deprecated("use {@link #UpdateStrategy(BuildNumber, UpdatesInfo, UserUpdateSettings)}")
|
||||
constructor(@Suppress("UNUSED_PARAMETER") majorVersion: Int,
|
||||
@Suppress("UNUSED_PARAMETER") currentBuild: BuildNumber,
|
||||
@Suppress("UNUSED_PARAMETER") updatesInfo: UpdatesInfo,
|
||||
@Suppress("UNUSED_PARAMETER") updateSettings: UserUpdateSettings,
|
||||
@Suppress("UNUSED_PARAMETER") customization: UpdateStrategyCustomization) : this(currentBuild, updatesInfo, updateSettings) {
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
}
|
||||
+78
-64
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.updateSettings.impl.UpdateSettingsConfigurable.UpdatesSettingsPanel">
|
||||
<grid id="5aa87" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="5aa87" binding="myPanel" layout-manager="GridLayoutManager" row-count="10" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="62" y="37" width="816" height="434"/>
|
||||
@@ -8,91 +8,57 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="e409a" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="10" left="0" bottom="20" right="0"/>
|
||||
<component id="1aa0e" class="javax.swing.JCheckBox" binding="myCheckForUpdates">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="2" indent="0" use-parent-layout="false"/>
|
||||
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.checkbox"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="8eae8" class="javax.swing.JComboBox" binding="myUpdateChannels">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="1aa0e" class="javax.swing.JCheckBox" binding="myCheckForUpdates">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.checkbox"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="8eae8" class="javax.swing.JComboBox" binding="myUpdateChannels">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="cc207" class="javax.swing.JButton" binding="myCheckNow">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.check.now.button"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="fdc45" class="com.intellij.ui.components.JBLabel" binding="myChannelWarning">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.unstable"/>
|
||||
<visible value="false"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="fc5f1" class="javax.swing.JCheckBox" binding="myUseSecureConnection">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.secure"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="36fbb" class="javax.swing.JLabel">
|
||||
</component>
|
||||
<component id="cc207" class="javax.swing.JButton" binding="myCheckNow">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.current.version"/>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.check.now.button"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="bd9c5" class="javax.swing.JLabel" binding="myVersionNumber">
|
||||
<component id="fdc45" class="com.intellij.ui.components.JBLabel" binding="myChannelWarning">
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="1" column="0" row-span="1" col-span="5" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="4.5.4"/>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.unstable"/>
|
||||
<visible value="false"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="6af7e" class="javax.swing.JLabel">
|
||||
<component id="fc5f1" class="javax.swing.JCheckBox" binding="myUseSecureConnection">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="2" column="0" row-span="1" col-span="4" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.build.number"/>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.secure"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b6709" class="javax.swing.JLabel" binding="myBuildNumber">
|
||||
<component id="456b6" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="3" column="0" row-span="1" col-span="4" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="3352"/>
|
||||
<text value=" "/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="db163" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.last.check"/>
|
||||
@@ -100,20 +66,68 @@
|
||||
</component>
|
||||
<component id="6b5cb" class="javax.swing.JLabel" binding="myLastCheckedDate">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="4" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="01.05.2005"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="36fbb" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.current.version"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="bd9c5" class="javax.swing.JLabel" binding="myVersionNumber">
|
||||
<constraints>
|
||||
<grid row="5" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="4.5.4"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="6af7e" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.build.number"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b6709" class="javax.swing.JLabel" binding="myBuildNumber">
|
||||
<constraints>
|
||||
<grid row="6" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="3352"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="51da0" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="7" column="0" row-span="1" col-span="4" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value=" "/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="23c67" class="com.intellij.ui.components.labels.ActionLink" binding="myIgnoredBuildsLink" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="8" column="0" row-span="1" col-span="4" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.settings.ignored"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="fdc69">
|
||||
<constraints>
|
||||
<grid row="3" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="2" column="4" row-span="7" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<vspacer id="3d6db">
|
||||
<constraints>
|
||||
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
<grid row="9" column="0" row-span="1" col-span="5" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
</children>
|
||||
|
||||
+4
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -20,13 +20,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public interface UserUpdateSettings {
|
||||
@NotNull
|
||||
List<String> getKnownChannelsIds();
|
||||
|
||||
List<String> getIgnoredBuildNumbers();
|
||||
|
||||
void setKnownChannelIds(List<String> ids);
|
||||
|
||||
@NotNull
|
||||
ChannelStatus getSelectedChannelStatus();
|
||||
}
|
||||
@NotNull ChannelStatus getSelectedChannelStatus();
|
||||
@NotNull List<String> getIgnoredBuildNumbers();
|
||||
}
|
||||
@@ -906,7 +906,6 @@ updates.error.connection.failed=Connection failed ({0}). Please check network co
|
||||
updates.error.plugin.description.failed=Failed to load plugin descriptions from: \"{0}\"
|
||||
update.notifications.title=Platform and Plugin Updates
|
||||
update.notifications.group=Platform and Plugin Updates
|
||||
updates.channel.name.message=<b>{0}</b>: {1}
|
||||
updates.channel.bundled.key=The new version has an expiration date and does not require a license key.
|
||||
updates.fallback.build=You have perpetual fallback license for the new version.
|
||||
updates.subscription.active.till=Your subscription is active until {0}.
|
||||
@@ -935,9 +934,11 @@ updates.settings.check.now.button=&Check Now
|
||||
updates.settings.checkbox=Automatically check updates for
|
||||
updates.settings.unstable=Please note that this channel is less stable than your current one.
|
||||
updates.settings.secure=Use secure connection
|
||||
updates.settings.build.number=Build number:
|
||||
updates.settings.current.version=Current version:
|
||||
updates.settings.last.check=Last checked:
|
||||
updates.settings.build.number=Build number
|
||||
updates.settings.current.version=Current version
|
||||
updates.settings.last.check=Last checked
|
||||
updates.settings.ignored=View/edit Ignored builds
|
||||
updates.settings.ignored.title=Ignored Builds
|
||||
update.plugin.host.url.message=Repository URL:
|
||||
update.no.update.hosts=No plugin repositories configured
|
||||
update.edit.plugin.host.title=Edit Repository
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.updates;
|
||||
|
||||
import com.intellij.openapi.updateSettings.impl.UpdatesInfo;
|
||||
import com.intellij.util.JdomKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
public class InfoReader {
|
||||
@NotNull
|
||||
public static UpdatesInfo read(@NotNull String fileName) {
|
||||
return read(InfoReader.class.getResource(fileName));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static UpdatesInfo read(@NotNull URL url) {
|
||||
try (InputStream stream = url.openStream()) {
|
||||
return new UpdatesInfo(JdomKt.loadElement(stream));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.updates
|
||||
|
||||
import com.intellij.openapi.updateSettings.impl.ChannelStatus
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateChannel
|
||||
import com.intellij.openapi.updateSettings.impl.UpdatesInfo
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import com.intellij.util.loadElement
|
||||
import org.junit.Test
|
||||
import java.net.URL
|
||||
import java.text.SimpleDateFormat
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class UpdateInfoParsingTest {
|
||||
@Test fun liveJetbrainsUpdateFile() {
|
||||
val info = load(URL("http://www.jetbrains.com/updates/updates.xml").readText())
|
||||
assertNotNull(info["IC"])
|
||||
}
|
||||
|
||||
@Test fun liveAndroidUpdateFile() {
|
||||
val info = load(URL("https://dl.google.com/android/studio/patches/updates.xml").readText())
|
||||
assertNotNull(info["AI"])
|
||||
}
|
||||
|
||||
@Test fun emptyChannels() {
|
||||
val info = load("""
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
</product>
|
||||
</products>""".trimIndent())
|
||||
val product = info["IU"]!!
|
||||
assertEquals("IntelliJ IDEA", product.name)
|
||||
assertEquals(0, product.channels.size)
|
||||
assertEquals(product, info["IC"])
|
||||
}
|
||||
|
||||
@Test fun oneProductOnly() {
|
||||
val info = load("""
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available. Please visit https://www.jetbrains.com/idea to learn more and download it.</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" licensing="eap" url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.520" version="10" releaseDate="20110403">
|
||||
<message>IntelliJ IDEA X RC is available. Please visit hhttp://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more.</message>
|
||||
<!-- <patch from="98.486" size="1"/> -->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
</products>""".trimIndent())
|
||||
|
||||
val product = info["IU"]!!
|
||||
assertEquals("IntelliJ IDEA", product.name)
|
||||
assertEquals(2, product.channels.size)
|
||||
|
||||
val channel = product.channels.find { it.id == "IDEA10EAP" }!!
|
||||
assertEquals(ChannelStatus.EAP, channel.status)
|
||||
assertEquals(UpdateChannel.LICENSING_EAP, channel.licensing)
|
||||
assertNotNull(channel.homePageUrl)
|
||||
assertEquals(1, channel.builds.size)
|
||||
|
||||
val build = channel.builds[0]
|
||||
assertEquals(BuildNumber.fromString("98.520"), build.number)
|
||||
assertEquals("2011-04-03", SimpleDateFormat("yyyy-MM-dd").format(build.releaseDate))
|
||||
assertEquals(0, build.patches.size)
|
||||
|
||||
assertEquals(1, product.channels.find { it.id == "idea90" }!!.builds[0].patches.size)
|
||||
}
|
||||
|
||||
@Test fun targetRanges() {
|
||||
val info = load("""
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<channel id="IDEA_EAP" status="eap">
|
||||
<build number="2016.2.123" version="2016.2" targetSince="0" targetUntil="145.*"/>
|
||||
<build number="2016.2.123" version="2016.2" targetSince="2016.1" targetUntil="2016.1.*"/>
|
||||
<build number="2016.1.11" version="2016.1"/>
|
||||
</channel>
|
||||
</product>
|
||||
</products>""".trimIndent())
|
||||
assertEquals(2, info["IU"]!!.channels[0].builds.count { it.target != null })
|
||||
}
|
||||
|
||||
private fun load(text: String) = UpdatesInfo(loadElement(text))
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.updates;
|
||||
|
||||
import com.intellij.openapi.updateSettings.UpdateStrategyCustomization;
|
||||
import com.intellij.openapi.updateSettings.impl.*;
|
||||
import com.intellij.openapi.util.BuildNumber;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class UpdateStrategyTest {
|
||||
@Test
|
||||
public void testWithUndefinedSelection() {
|
||||
// could be if somebody used before previous version of IDEA
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(9, BuildNumber.fromString("IU-98.520"), InfoReader.read("idea-same.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
assertNull(result.getNewBuildInSelectedChannel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithUserSelection() {
|
||||
// assume user has version 9 eap - and used eap channel - we want to introduce new eap
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(9, BuildNumber.fromString("IU-95.429"), InfoReader.read("idea-new9eap.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo update = result.getNewBuildInSelectedChannel();
|
||||
assertNotNull(update);
|
||||
assertEquals("95.627", update.getNumber().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnore() {
|
||||
// assume user has version 9 eap - and used eap channel - we want to introduce new eap
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP, "95.627", "98.620");
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(9, BuildNumber.fromString("IU-95.429"), InfoReader.read("idea-new9eap.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo update = result.getNewBuildInSelectedChannel();
|
||||
assertNull(update);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewChannelAppears() {
|
||||
// assume user has version 9 eap subscription (default or selected)
|
||||
// and new channel appears - eap of version 10 is there
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.RELEASE);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(9, BuildNumber.fromString("IU-95.627"), InfoReader.read("idea-newChannel-release.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo update = result.getNewBuildInSelectedChannel();
|
||||
assertNull(update);
|
||||
|
||||
UpdateChannel newChannel = result.getChannelToPropose();
|
||||
assertNotNull(newChannel);
|
||||
assertEquals("IDEA10EAP", newChannel.getId());
|
||||
assertEquals("IntelliJ IDEA X EAP", newChannel.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewChannelWithOlderBuild() {
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(10, BuildNumber.fromString("IU-107.80"), InfoReader.read("idea-newChannel.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo update = result.getNewBuildInSelectedChannel();
|
||||
assertNull(update);
|
||||
|
||||
UpdateChannel newChannel = result.getChannelToPropose();
|
||||
assertNull(newChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewChannelAndNewBuildAppear() {
|
||||
// assume user has version 9 eap subscription (default or selected)
|
||||
// and new channels appears - eap of version 10 is there
|
||||
// and new build withing old channel appears also
|
||||
// we need to show only one dialog
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(9, BuildNumber.fromString("IU-95.429"), InfoReader.read("idea-newChannel.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo update = result.getNewBuildInSelectedChannel();
|
||||
assertNotNull(update);
|
||||
assertEquals("95.627", update.getNumber().toString());
|
||||
|
||||
UpdateChannel newChannel = result.getChannelToPropose();
|
||||
assertNotNull(newChannel);
|
||||
assertEquals("IDEA10EAP", newChannel.getId());
|
||||
assertEquals("IntelliJ IDEA X EAP", newChannel.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChannelWithCurrentStatusPreferred() {
|
||||
BuildNumber currentBuild = BuildNumber.fromString("IU-139.658");
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(14, currentBuild, InfoReader.read("idea-patchAvailable.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
|
||||
UpdateChannel channel = result.getUpdatedChannel();
|
||||
assertNotNull(channel);
|
||||
assertEquals(ChannelStatus.EAP, channel.getStatus());
|
||||
|
||||
BuildInfo selectedChannel = result.getNewBuildInSelectedChannel();
|
||||
assertNotNull(selectedChannel);
|
||||
assertNotNull(selectedChannel.findPatchForBuild(currentBuild));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStableUpdatePreferredByDefault() {
|
||||
BuildNumber currentBuild = BuildNumber.fromString("IU-143.381");
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.RELEASE);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(15, currentBuild, InfoReader.read("idea-123280.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
|
||||
UpdateChannel channel = result.getUpdatedChannel();
|
||||
assertNotNull(channel);
|
||||
assertEquals(ChannelStatus.RELEASE, channel.getStatus());
|
||||
|
||||
BuildInfo build = result.getNewBuildInSelectedChannel();
|
||||
assertNotNull(build);
|
||||
assertEquals("143.382", build.getNumber().toString());
|
||||
assertNotNull(build.findPatchForBuild(currentBuild));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStableChannelProposedByDefault() {
|
||||
BuildNumber currentBuild = BuildNumber.fromString("IU-143.381");
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.RELEASE);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(15, currentBuild, InfoReader.read("idea-123280.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
UpdateChannel channelToPropose = result.getChannelToPropose();
|
||||
assertNotNull(channelToPropose);
|
||||
assertEquals("IDEA_Release", channelToPropose.getId());
|
||||
|
||||
settings.setKnownChannelIds(Collections.singletonList(channelToPropose.getId()));
|
||||
result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
assertNull(result.getChannelToPropose());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParallelCampaignsInChannel() {
|
||||
BuildNumber currentBuild = BuildNumber.fromString("IU-143.381");
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(15, currentBuild, InfoReader.read("idea-2eap.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo build = result.getNewBuildInSelectedChannel();
|
||||
assertNotNull(build);
|
||||
assertEquals("143.888", build.getNumber().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrossingParallelCampaignsInChannel() {
|
||||
BuildNumber currentBuild = BuildNumber.fromString("IU-143.888");
|
||||
TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
|
||||
UpdateStrategyCustomization customization = new UpdateStrategyCustomization();
|
||||
UpdateStrategy strategy = new UpdateStrategy(15, currentBuild, InfoReader.read("idea-2eap.xml"), settings, customization);
|
||||
|
||||
CheckForUpdateResult result = strategy.checkForUpdates();
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.getState());
|
||||
BuildInfo build = result.getNewBuildInSelectedChannel();
|
||||
assertNotNull(build);
|
||||
assertEquals("144.888", build.getNumber().toString());
|
||||
}
|
||||
|
||||
private static class TestUpdateSettings implements UserUpdateSettings {
|
||||
private final ChannelStatus myChannelStatus;
|
||||
private final List<String> myIgnoredBuildNumbers;
|
||||
private List<String> myKnownChannelIds = Collections.emptyList();
|
||||
|
||||
public TestUpdateSettings(ChannelStatus channelStatus, String... ignoredBuilds) {
|
||||
myChannelStatus = channelStatus;
|
||||
myIgnoredBuildNumbers = Arrays.asList(ignoredBuilds);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getKnownChannelsIds() {
|
||||
return myKnownChannelIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getIgnoredBuildNumbers() {
|
||||
return myIgnoredBuildNumbers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKnownChannelIds(List<String> ids) {
|
||||
myKnownChannelIds = ids;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChannelStatus getSelectedChannelStatus() {
|
||||
return myChannelStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.updates
|
||||
|
||||
import com.intellij.openapi.updateSettings.impl.*
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import com.intellij.util.loadElement
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class UpdateStrategyTest {
|
||||
@Test fun `channel contains no builds`() {
|
||||
val result = check("IU-145.258", ChannelStatus.RELEASE, """<channel id="IDEA_Release" status="release" licensing="release"/>""")
|
||||
assertNull(result.newBuild)
|
||||
}
|
||||
|
||||
@Test fun `already on the latest build`() {
|
||||
val result = check("IU-145.258", ChannelStatus.RELEASE, """
|
||||
<channel id="IDEA15_Release" status="release" licensing="release">
|
||||
<build number="143.2332" version="15.0.5"/>
|
||||
</channel>
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.258" version="2016.1"/>
|
||||
</channel>""")
|
||||
assertNull(result.newBuild)
|
||||
}
|
||||
|
||||
@Test fun `patch exclusions`() {
|
||||
val result = check("IU-145.258", ChannelStatus.RELEASE, """
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.597" version="2016.1.1">
|
||||
<patch from="145.596"/>
|
||||
<patch from="145.258" exclusions="win,mac,unix"/>
|
||||
</build>
|
||||
</channel>""")
|
||||
assertNotNull(result.findPatchForBuild(BuildNumber.fromString("145.596")))
|
||||
assertNull(result.findPatchForBuild(BuildNumber.fromString("145.258")))
|
||||
}
|
||||
|
||||
@Test fun `order of builds does not matter`() {
|
||||
val resultDesc = check("IU-143.2332", ChannelStatus.RELEASE, """
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.597" version="2016.1.1"/>
|
||||
<build number="145.258" version="2016.1"/>
|
||||
</channel>""")
|
||||
assertEquals("145.597", resultDesc.newBuild?.number.toString())
|
||||
|
||||
val resultAsc = check("IU-143.2332", ChannelStatus.RELEASE, """
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.258" version="2016.1"/>
|
||||
<build number="145.597" version="2016.1.1"/>
|
||||
</channel>""")
|
||||
assertEquals("145.597", resultAsc.newBuild?.number.toString())
|
||||
}
|
||||
|
||||
@Test fun `newer updates are preferred`() {
|
||||
val result = check("IU-145.258", ChannelStatus.EAP, """
|
||||
<channel id="IDEA_EAP" status="eap" licensing="eap">
|
||||
<build number="145.596" version="2016.1.1 EAP"/>
|
||||
</channel>
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.597" version="2016.1.1"/>
|
||||
</channel>""")
|
||||
assertEquals("145.597", result.newBuild?.number.toString())
|
||||
}
|
||||
|
||||
@Test fun `newer updates are preferred over more stable ones`() {
|
||||
val result = check("IU-145.257", ChannelStatus.EAP, """
|
||||
<channel id="IDEA_EAP" status="eap" licensing="eap">
|
||||
<build number="145.596" version="2016.1.1 EAP"/>
|
||||
</channel>
|
||||
<channel id="IDEA_Beta" status="beta" licensing="release">
|
||||
<build number="145.257" version="2016.1 RC2"/>
|
||||
</channel>
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.258" version="2016.1"/>
|
||||
</channel>""")
|
||||
assertEquals("145.596", result.newBuild?.number.toString())
|
||||
}
|
||||
|
||||
@Test fun `newer updates from non-allowed channels are ignored`() {
|
||||
val channels = """
|
||||
<channel id="IDEA_EAP" status="eap" licensing="eap">
|
||||
<build number="145.596" version="2016.1.1 EAP"/>
|
||||
</channel>
|
||||
<channel id="IDEA_Beta" status="beta" licensing="release">
|
||||
<build number="145.257" version="2016.1 RC2"/>
|
||||
</channel>
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="145.258" version="2016.1"/>
|
||||
</channel>"""
|
||||
assertEquals("145.258", check("IU-145.256", ChannelStatus.RELEASE, channels).newBuild?.number.toString())
|
||||
assertNull(check("IU-145.258", ChannelStatus.RELEASE, channels).newBuild)
|
||||
}
|
||||
|
||||
@Test fun `ignored updates are excluded`() {
|
||||
val result = check("IU-145.258", ChannelStatus.EAP, """
|
||||
<channel id="IDEA_EAP" status="eap" licensing="eap">
|
||||
<build number="145.596" version="2016.1.1 EAP"/>
|
||||
<build number="145.595" version="2016.1.1 EAP"/>
|
||||
</channel>""", listOf("145.596"))
|
||||
assertEquals("145.595", result.newBuild?.number.toString())
|
||||
}
|
||||
|
||||
@Test fun `updates can be targeted for specific builds`() {
|
||||
val channels = """
|
||||
<channel id="IDEA_EAP" status="eap" licensing="eap">
|
||||
<build number="145.596" version="2016.1.1 EAP" targetSince="145.595" targetUntil="145.*"/> <!-- this build is not for everyone -->
|
||||
<build number="145.595" version="2016.1.1 EAP"/>
|
||||
</channel>"""
|
||||
assertEquals("145.595", check("IU-145.258", ChannelStatus.EAP, channels).newBuild?.number.toString())
|
||||
assertEquals("145.596", check("IU-145.595", ChannelStatus.EAP, channels).newBuild?.number.toString())
|
||||
}
|
||||
|
||||
@Test fun `updates from the same baseline are preferred`() {
|
||||
val result = check("IU-143.2287", ChannelStatus.RELEASE, """
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="143.2332" version="15.0.5"/>
|
||||
<build number="145.597" version="2016.1.1"/>
|
||||
</channel>""")
|
||||
assertEquals("143.2332", result.newBuild?.number.toString())
|
||||
}
|
||||
|
||||
@Test fun `cross-baseline updates are perfectly legal`() {
|
||||
val result = check("IU-143.2332", ChannelStatus.EAP, """
|
||||
<channel id="IDEA_Release" status="release" licensing="release">
|
||||
<build number="143.2332" version="15.0.5"/>
|
||||
<build number="145.597" version="2016.1.1"/>
|
||||
</channel>""")
|
||||
assertEquals("145.597", result.newBuild?.number.toString())
|
||||
}
|
||||
|
||||
private fun check(currentBuild: String,
|
||||
selectedChannel: ChannelStatus,
|
||||
testData: String,
|
||||
ignoredBuilds: List<String> = emptyList()): CheckForUpdateResult {
|
||||
val updates = UpdatesInfo(loadElement("""
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
${testData}
|
||||
</product>
|
||||
</products>"""))
|
||||
val settings = object : UserUpdateSettings {
|
||||
override fun getSelectedChannelStatus() = selectedChannel
|
||||
override fun getIgnoredBuildNumbers() = ignoredBuilds
|
||||
}
|
||||
val result = UpdateStrategy(BuildNumber.fromString(currentBuild), updates, settings).checkForUpdates()
|
||||
assertEquals(UpdateStrategy.State.LOADED, result.state)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.ide.updates;
|
||||
|
||||
import com.intellij.openapi.updateSettings.impl.*;
|
||||
import com.intellij.openapi.util.BuildNumber;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class UpdatesInfoParserTest {
|
||||
@Test
|
||||
public void testLiveJetbrainsUpdateFile() throws MalformedURLException {
|
||||
UpdatesInfo info = InfoReader.read(new URL("http://www.jetbrains.com/updates/updates.xml"));
|
||||
assertNotNull(info.getProduct("IC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiveAndroidUpdateFile() throws MalformedURLException {
|
||||
UpdatesInfo info = InfoReader.read(new URL("https://dl.google.com/android/studio/patches/updates.xml"));
|
||||
assertNotNull(info.getProduct("AI"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidXmlParsing() {
|
||||
UpdatesInfo info = InfoReader.read("current.xml");
|
||||
assertEquals(5, info.getProductsCount());
|
||||
|
||||
Product product = info.getProduct("IU");
|
||||
assertNotNull(product);
|
||||
checkProduct(product, "IntelliJ IDEA", "maiaEAP", "IDEA10EAP", "idea90");
|
||||
|
||||
UpdateChannel channel = product.findUpdateChannelById("IDEA10EAP");
|
||||
assertNotNull(channel);
|
||||
assertEquals(ChannelStatus.EAP, channel.getStatus());
|
||||
assertEquals(UpdateChannel.LICENSING_EAP, channel.getLicensing());
|
||||
assertNotNull(channel.getHomePageUrl());
|
||||
assertNotNull(channel.getFeedbackUrl());
|
||||
|
||||
BuildInfo build = channel.getLatestBuild();
|
||||
assertNotNull(build);
|
||||
assertEquals(BuildNumber.fromString("98.520"), build.getNumber());
|
||||
Date date = build.getReleaseDate();
|
||||
assertNotNull(date);
|
||||
assertEquals("2011-04-03", new SimpleDateFormat("yyyy-MM-dd").format(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyChannels() {
|
||||
UpdatesInfo info = InfoReader.read("emptyChannels.xml");
|
||||
|
||||
Product product = info.getProduct("IU");
|
||||
assertNotNull(product);
|
||||
assertEquals(0, product.getChannels().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneProductOnly() {
|
||||
UpdatesInfo info = InfoReader.read("oneProductOnly.xml");
|
||||
assertNotNull(info);
|
||||
|
||||
Product product = info.getProduct("IU");
|
||||
assertNotNull(product);
|
||||
checkProduct(product, "IntelliJ IDEA", "maiaEAP", "IDEA10EAP", "idea90");
|
||||
|
||||
UpdateChannel channel = product.findUpdateChannelById("IDEA10EAP");
|
||||
assertNotNull(channel);
|
||||
|
||||
BuildInfo build = channel.getLatestBuild();
|
||||
assertNotNull(build);
|
||||
assertEquals(BuildNumber.fromString("98.520"), build.getNumber());
|
||||
}
|
||||
|
||||
private static void checkProduct(Product product, String name, String... channels) {
|
||||
assertEquals(name, product.getName());
|
||||
assertEquals(channels.length, product.getChannels().size());
|
||||
for (String channel : channels) {
|
||||
assertNotNull(product.findUpdateChannelById(channel));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" licensing="eap"
|
||||
url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="98.520" version="10" releaseDate="20110403">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
<product name="RubyMine">
|
||||
<code>RM</code>
|
||||
<channel id="rm20" name="RubyMine 2.0.2" status="Release"
|
||||
url="https://www.jetbrains.com/ruby"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="97.122" version="3.0">
|
||||
<message>RubyMine 3.0 is available.
|
||||
Please visit https://www.jetbrains.com/ruby to learn more and download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
<channel id="rm25" name="RubyMine 3.0" status="Release"
|
||||
url="https://www.jetbrains.com/ruby/"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="97.122" version="3.0">
|
||||
<message>RubyMine 3.0 is available.
|
||||
Please visit https://www.jetbrains.com/ruby to learn more and download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
<channel id="rm30" name="RubyMine 3.0" status="Release"
|
||||
url="https://www.jetbrains.com/ruby/"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="97.122" version="3.0">
|
||||
<message>RubyMine 3.0 Release Candidate 2 is available.
|
||||
Please visit https://www.jetbrains.com/ruby to learn more and download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
<channel id="rm25EAP" name="RubyMine 3.0" status="EAP"
|
||||
url="https://www.jetbrains.com/ruby/"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="97.122" version="3.0">
|
||||
<message>RubyMine 3.0 is available.
|
||||
Please visit https://www.jetbrains.com/ruby to learn more and download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
<product name="PyCharm">
|
||||
<code>PY</code>
|
||||
<channel id="pycharm" name="PyCharm 1.0" status="EAP"
|
||||
url="https://www.jetbrains.com/pycharm"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="97.87" version="1.0.1">
|
||||
<message>PyCharm 1.0.1 is available.
|
||||
Please visit www.jetbrains.com/pycharm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="pycharm10" name="PyCharm 1.0" status="Release"
|
||||
url="https://www.jetbrains.com/pycharm"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="97.87" version="1.0.1">
|
||||
<message>PyCharm 1.0.1 is available.
|
||||
Please visit www.jetbrains.com/pycharm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
<product name="PhpStorm">
|
||||
<code>PS</code>
|
||||
<channel id="WI1EAP" name="PhpStorm 1.0.2" status="EAP"
|
||||
url="https://www.jetbrains.com/phpstorm"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="95.503" version="1.0.2">
|
||||
<message>PhpStorm 1.0.2 is available.
|
||||
Please visit https://www.jetbrains.com/phpstorm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="WI1" name="PhpStorm 1.0.2" status="release"
|
||||
url="https://www.jetbrains.com/phpstorm"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="95.503" version="1.0.2">
|
||||
<message>PhpStorm 1.0.2 is available.
|
||||
Please visit https://www.jetbrains.com/phpstorm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="WI2EAP" name="PhpStorm 2.0" status="EAP"
|
||||
url="http://confluence.jetbrains.net/display/WI/"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="98.521" version="2.0">
|
||||
<message>PhpStorm 2.0 EAP update is available.
|
||||
Please visit http://confluence.jetbrains.net/display/WI/ to download it.
|
||||
</message>
|
||||
<patch from="98.458" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="WI2" name="PhpStorm 2.0" status="release"
|
||||
url="https://www.jetbrains.com/phpstorm"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="95.503" version="2.0">
|
||||
<message>PhpStorm 2.0 is available.
|
||||
Please visit https://www.jetbrains.com/phpstorm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
<product name="WebStorm">
|
||||
<code>WS</code>
|
||||
<channel id="WI1EAP" name="WebStorm 1.0.2" status="EAP"
|
||||
url="https://www.jetbrains.com/webstorm"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="95.503" version="1.0.2">
|
||||
<message>WebStorm 1.0.2 is available.
|
||||
Please visit https://www.jetbrains.com/webstorm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="WI1" name="WebStorm 1.0.2" status="release"
|
||||
url="https://www.jetbrains.com/webstorm"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="95.503" version="1.0.2">
|
||||
<message>WebStorm 1.0.2 is available.
|
||||
Please visit https://www.jetbrains.com/webstorm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="WI2EAP" name="WebStorm 2.0" status="EAP"
|
||||
url="http://confluence.jetbrains.net/display/WI/"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="98.521" version="2.0">
|
||||
<message>WebStorm 2.0 EAP update is available.
|
||||
Please visit http://confluence.jetbrains.net/display/WI/ to download it.
|
||||
</message>
|
||||
<patch from="98.458" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="WI2" name="WebStorm 2.0" status="release"
|
||||
url="https://www.jetbrains.com/webstorm"
|
||||
feedback="http://devnet.jetbrains.net/community/wi/">
|
||||
<build number="95.503" version="1.0.2">
|
||||
<message>WebStorm 1.0.2 is available.
|
||||
Please visit https://www.jetbrains.com/webstorm to download it.
|
||||
</message>
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,6 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,32 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="IDEA_15_EAP" name="IntelliJ IDEA 15 EAP" status="eap" url="" feedback="" majorVersion="15" licensing="eap">
|
||||
<build number="143.747" version="15.0.2 EAP" releaseDate="20151102">
|
||||
<message/>
|
||||
<button name="Download" url="https://confluence.jetbrains.com/display/IDEADEV/IDEA+15+EAP" download="true" />
|
||||
<button name="Release Notes" url="https://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+15+143.747.6+Release+Notes" />
|
||||
<patch from="143.381" size="from 4 to 20" />
|
||||
<patch from="143.382" size="from 4 to 18" />
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA_Beta" name="IntelliJ IDEA Beta" status="beta" url="" feedback="" majorVersion="15" licensing="eap"/>
|
||||
|
||||
<channel id="IDEA_Release" name="IntelliJ IDEA Release" status="release" url="" feedback="" majorVersion="15" licensing="release">
|
||||
<build number="143.382" version="15.0.1" releaseDate="20151102">
|
||||
<message/>
|
||||
<button name="Release Notes" url="https://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+15.0.1+Release+Notes" />
|
||||
<patch from="143.381" size="from 1 to 12" />
|
||||
</build>
|
||||
<build number="143.381" version="15" releaseDate="20151102">
|
||||
<message/>
|
||||
<button name="Download" url="https://www.jetbrains.com/idea/download/" download="true" />
|
||||
<button name="What's New" url="https://www.jetbrains.com/idea/whatsnew/"/>
|
||||
<patch from="143.380" size="from 1 to 11" />
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,20 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="IDEA_EAP" name="IntelliJ IDEA EAP" status="eap" url="" feedback="" majorVersion="15" licensing="eap">
|
||||
<build number="143.888" version="15.0.3 EAP">
|
||||
<message/>
|
||||
<button name="Download" url="" download="true" />
|
||||
<button name="Release Notes" url="" />
|
||||
</build>
|
||||
<build number="144.888" version="15.1 EAP">
|
||||
<message/>
|
||||
<button name="Download" url="" download="true" />
|
||||
<button name="Release Notes" url="" />
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,36 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" majorVersion="10"
|
||||
url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.620" version="10">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,39 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="release" majorVersion="10"
|
||||
url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.520" version="10">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
|
||||
</products>
|
||||
@@ -1,39 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" majorVersion="10"
|
||||
url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.520" version="10">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
|
||||
</products>
|
||||
@@ -1,34 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.620" version="10">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,37 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="IDEA14" name="IntelliJ IDEA 14" status="release"
|
||||
url="https://www.jetbrains.com/idea/download"
|
||||
feedback="http://youtrack.jetbrains.net"
|
||||
majorVersion="14">
|
||||
<build number="139.659" version="14.0.2" releaseDate="20141103">
|
||||
<message>IntelliJ IDEA 14.0.2 build 139.659 is available.</message>
|
||||
<button name="Download" url="https://www.jetbrains.com/idea/download" download="true"/>
|
||||
<button name="What's New" url="https://www.jetbrains.com/idea/whatsnew/index.html"/>
|
||||
<button name="Release Notes" url="https://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+14.0.2+Release+Notes"/>
|
||||
<patch from="139.224" size="30" />
|
||||
<patch from="139.225" size="30" />
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA_14_EAP" name="IntelliJ IDEA 14 EAP" status="eap"
|
||||
url="https://confluence.jetbrains.com/display/IDEADEV/IDEA+14+EAP"
|
||||
feedback="http://youtrack.jetbrains.net"
|
||||
majorVersion="14">
|
||||
<build number="139.659" version="14.0.2" releaseDate="20141103">
|
||||
<message>IntelliJ IDEA 14.0.2 build 139.659 is available.</message>
|
||||
<button name="Download" url="https://confluence.jetbrains.com/display/IDEADEV/IDEA+14+EAP" download="true"/>
|
||||
<button name="Release Notes" url="https://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+14+139.659.2+Release+Notes"/>
|
||||
<patch from="139.658" size="10" />
|
||||
<patch from="139.224" size="30" />
|
||||
<patch from="139.225" size="30" />
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
</product>
|
||||
|
||||
|
||||
</products>
|
||||
@@ -1,36 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" majorVersion="9"
|
||||
url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" majorVersion="10"
|
||||
url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.520" version="10">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
</products>
|
||||
@@ -1,36 +0,0 @@
|
||||
<products>
|
||||
<product name="IntelliJ IDEA">
|
||||
<code>IU</code>
|
||||
<code>IC</code>
|
||||
|
||||
<channel id="maiaEAP" name="IntelliJ IDEA 9 updates" status="release"
|
||||
url="https://www.jetbrains.com/idea/whatsnew"
|
||||
feedback="http://youtrack.jetbrains.net">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="idea90" name="IntelliJ IDEA 9 updates" status="release" url="https://www.jetbrains.com/idea/whatsnew">
|
||||
<build number="95.627" version="9.0.4">
|
||||
<message>IntelliJ IDEA 9.0.4 is available.
|
||||
Please visit https://www.jetbrains.com/idea to learn more and download it.
|
||||
</message>
|
||||
<patch from="95.429" size="2"/>
|
||||
</build>
|
||||
</channel>
|
||||
|
||||
<channel id="IDEA10EAP" name="IntelliJ IDEA X EAP" status="eap" url="http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP">
|
||||
<build number="98.520" version="10">
|
||||
<message>IntelliJ IDEA X RC is available.
|
||||
Please visit http://confluence.jetbrains.net/display/IDEADEV/IDEA+X+EAP to learn more and download it.
|
||||
</message>
|
||||
<!--<patch from="98.486" size="1"/>-->
|
||||
</build>
|
||||
</channel>
|
||||
</product>
|
||||
|
||||
</products>
|
||||
Reference in New Issue
Block a user