[platform] fixes permissions of JRE binaries copied for update (IDEA-161223)
[idea/community.git] / platform / platform-impl / src / com / intellij / openapi / updateSettings / impl / UpdateInstaller.kt
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.updateSettings.impl
17
18 import com.intellij.ide.IdeBundle
19 import com.intellij.openapi.application.ApplicationInfo
20 import com.intellij.openapi.application.PathManager
21 import com.intellij.openapi.application.ex.ApplicationInfoEx
22 import com.intellij.openapi.diagnostic.Logger
23 import com.intellij.openapi.progress.ProgressIndicator
24 import com.intellij.openapi.util.BuildNumber
25 import com.intellij.openapi.util.SystemInfo
26 import com.intellij.openapi.util.io.FileUtil
27 import com.intellij.util.ArrayUtil
28 import com.intellij.util.Restarter
29 import com.intellij.util.io.HttpRequests
30 import java.io.File
31 import java.io.IOException
32 import java.net.URL
33 import javax.swing.UIManager
34
35 object UpdateInstaller {
36   private val patchesUrl: String
37     get() = System.getProperty("idea.patches.url") ?: ApplicationInfoEx.getInstanceEx().updateUrls.patchesUrl
38
39   @JvmStatic
40   @Throws(IOException::class)
41   fun installPlatformUpdate(patch: PatchInfo, toBuild: BuildNumber, forceHttps: Boolean, indicator: ProgressIndicator): Array<String> {
42     indicator.text = IdeBundle.message("update.downloading.patch.progress")
43
44     val product = ApplicationInfo.getInstance().build.productCode
45     val from = patch.fromBuild.asStringWithoutProductCode()
46     val to = toBuild.asStringWithoutProductCode()
47     val jdk = if (System.getProperty("idea.java.redist", "").lastIndexOf("NoJavaDistribution") >= 0) "-no-jdk" else ""
48     val patchName = "${product}-${from}-${to}-patch${jdk}-${patch.osSuffix}.jar"
49
50     val baseUrl = patchesUrl
51     val url = URL(URL(if (baseUrl.endsWith('/')) baseUrl else baseUrl + '/'), patchName)
52     val patchFile = File(getTempDir(), "patch.jar")
53     HttpRequests.request(url.toString()).gzip(false).forceHttps(forceHttps).saveToFile(patchFile, indicator)
54
55     indicator.text = IdeBundle.message("update.preparing.patch.progress")
56     return preparePatchCommand(patchFile)
57   }
58
59   @JvmStatic
60   fun installPluginUpdates(downloaders: Collection<PluginDownloader>, indicator: ProgressIndicator): Boolean {
61     indicator.text = IdeBundle.message("progress.downloading.plugins")
62
63     var installed = false
64
65     val disabledToUpdate = UpdateChecker.disabledToUpdatePlugins
66     for (downloader in downloaders) {
67       try {
68         if (downloader.pluginId !in disabledToUpdate && downloader.prepareToInstall(indicator)) {
69           val descriptor = downloader.descriptor
70           if (descriptor != null) {
71             downloader.install()
72             installed = true
73           }
74         }
75       }
76       catch (e: Exception) {
77         Logger.getInstance(UpdateChecker::class.java).info(e)
78       }
79     }
80
81     return installed
82   }
83
84   @JvmStatic
85   fun cleanupPatch() {
86     val tempDir = getTempDir()
87     if (tempDir.exists()) FileUtil.delete(tempDir)
88   }
89
90   private fun preparePatchCommand(patchFile: File): Array<String> {
91     val log4j = findLib("log4j.jar")
92     val jna = findLib("jna.jar")
93     val jnaUtils = findLib("jna-platform.jar")
94
95     val tempDir = getTempDir()
96     if (!(tempDir.exists() || tempDir.mkdirs())) {
97       throw IOException("Cannot create temp directory: $tempDir")
98     }
99
100     val log4jCopy = log4j.copyTo(File(tempDir, log4j.name), true)
101     val jnaCopy = jna.copyTo(File(tempDir, jna.name), true)
102     val jnaUtilsCopy = jnaUtils.copyTo(File(tempDir, jnaUtils.name), true)
103
104     var java = System.getProperty("java.home")
105     if (FileUtil.isAncestor(PathManager.getHomePath(), java, true)) {
106       val javaCopy = File(tempDir, "jre")
107       FileUtil.copyDir(File(java), javaCopy)
108       java = javaCopy.path
109     }
110
111     val args = arrayListOf<String>()
112
113     if (SystemInfo.isWindows) {
114       val launcher = File(PathManager.getBinPath(), "VistaLauncher.exe")
115       if (launcher.canExecute()) {
116         args += Restarter.createTempExecutable(launcher).path
117       }
118     }
119
120     args += File(java, if (SystemInfo.isWindows) "bin\\java.exe" else "bin/java").path
121     args += "-Xmx750m"
122     args += "-cp"
123     args += arrayOf(patchFile.path, log4jCopy.path, jnaCopy.path, jnaUtilsCopy.path).joinToString(File.pathSeparator)
124
125     args += "-Djna.nosys=true"
126     args += "-Djna.boot.library.path="
127     args += "-Djna.debug_load=true"
128     args += "-Djna.debug_load.jna=true"
129     args += "-Djava.io.tmpdir=${tempDir.path}"
130     args += "-Didea.updater.log=${PathManager.getLogPath()}"
131     args += "-Dswing.defaultlaf=${UIManager.getSystemLookAndFeelClassName()}"
132
133     args += "com.intellij.updater.Runner"
134     args += "install"
135     args += PathManager.getHomePath()
136
137     return ArrayUtil.toStringArray(args)
138   }
139
140   private fun findLib(libName: String): File {
141     val libFile = File(PathManager.getLibPath(), libName)
142     return if (libFile.exists()) libFile else throw IOException("Missing: ${libFile}")
143   }
144
145   private fun getTempDir() = File(PathManager.getTempPath(), "patch-update")
146 }