mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Utility class for creating and executing system commands and shell scripts
This commit is contained in:
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
@@ -32,6 +30,7 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.system.ExecUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
@@ -41,8 +40,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import static com.intellij.util.containers.CollectionFactory.hashMap;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class CreateDesktopEntryAction extends AnAction {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.actions.CreateDesktopEntryAction");
|
||||
@@ -87,7 +87,8 @@ public class CreateDesktopEntryAction extends AnAction {
|
||||
if (!StringUtil.isEmptyOrSpaces(message)) {
|
||||
LOG.warn(e);
|
||||
Notifications.Bus.notify(
|
||||
new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Unable to create desktop entry", message, NotificationType.ERROR)
|
||||
new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Failed to create desktop entry", message, NotificationType.ERROR),
|
||||
event.getProject()
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -98,19 +99,9 @@ public class CreateDesktopEntryAction extends AnAction {
|
||||
});
|
||||
}
|
||||
|
||||
private static void check() {
|
||||
final GeneralCommandLine cmd = new GeneralCommandLine();
|
||||
cmd.setExePath("which");
|
||||
cmd.addParameter("xdg-desktop-menu");
|
||||
|
||||
try {
|
||||
final Process process = cmd.createProcess();
|
||||
final int result = process.waitFor();
|
||||
if (result != 0) throw new Exception("'" + cmd.getCommandLineString() + "' : " + result);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(ApplicationBundle.message("desktop.entry.xdg.missing"), e);
|
||||
}
|
||||
private static void check() throws IOException, InterruptedException {
|
||||
final int result = ExecUtil.execAndGetResult("which", "xdg-desktop-menu");
|
||||
if (result != 0) throw new RuntimeException(ApplicationBundle.message("desktop.entry.xdg.missing"));
|
||||
}
|
||||
|
||||
private static File prepare() throws IOException {
|
||||
@@ -134,19 +125,13 @@ public class CreateDesktopEntryAction extends AnAction {
|
||||
|
||||
final String wmClass = AppUIUtil.getFrameClass();
|
||||
|
||||
final InputStream stream = CreateDesktopEntryAction.class.getClassLoader().getResourceAsStream("entry.desktop");
|
||||
assert stream != null : CreateDesktopEntryAction.class.getClassLoader();
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
String content = FileUtil.loadTextAndClose(new InputStreamReader(stream));
|
||||
content = StringUtil.replace(content, "$NAME$", name);
|
||||
content = StringUtil.replace(content, "$SCRIPT$", execPath);
|
||||
content = StringUtil.replace(content, "$ICON$", iconPath);
|
||||
content = StringUtil.replace(content, "$WM_CLASS$", wmClass);
|
||||
final String content = ExecUtil.loadTemplate(CreateDesktopEntryAction.class.getClassLoader(), "entry.desktop",
|
||||
hashMap(asList("$NAME$", "$SCRIPT$", "$ICON$", "$WM_CLASS$"),
|
||||
asList(name, execPath, iconPath, wmClass)));
|
||||
|
||||
final String entryName = wmClass + ".desktop";
|
||||
final File entryFile = new File(FileUtil.getTempDirectory(), entryName);
|
||||
FileUtil.writeToFile(entryFile, content);
|
||||
|
||||
return entryFile;
|
||||
}
|
||||
|
||||
@@ -193,14 +178,10 @@ public class CreateDesktopEntryAction extends AnAction {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void install(final File entryFile) throws ExecutionException, InterruptedException {
|
||||
final GeneralCommandLine cmd = new GeneralCommandLine();
|
||||
cmd.setExePath("xdg-desktop-menu");
|
||||
cmd.addParameters("install", "--mode", "user", entryFile.getAbsolutePath());
|
||||
private static void install(final File entryFile) throws IOException, InterruptedException {
|
||||
try {
|
||||
final Process process = cmd.createProcess();
|
||||
final int result = process.waitFor();
|
||||
if (result != 0) throw new RuntimeException("'" + cmd.getCommandLineString() + "' : " + result);
|
||||
final int result = ExecUtil.execAndGetResult("xdg-desktop-menu", "install", "--mode", "user", entryFile.getAbsolutePath());
|
||||
if (result != 0) throw new RuntimeException("'" + entryFile.getAbsolutePath() + "' : " + result);
|
||||
}
|
||||
finally {
|
||||
if (!entryFile.delete()) LOG.error("Failed to delete temp file '" + entryFile + "'");
|
||||
|
||||
+37
-87
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
* Copyright 2000-2011 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,11 +15,12 @@
|
||||
*/
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -27,18 +28,15 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.system.ExecUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import static com.intellij.util.containers.CollectionFactory.hashMap;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -48,8 +46,7 @@ public class CreateLauncherScriptAction extends AnAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
Project project = e.getData(PlatformDataKeys.PROJECT);
|
||||
showDialog(project);
|
||||
showDialog(e.getProject());
|
||||
}
|
||||
|
||||
public static void showDialog(Project project) {
|
||||
@@ -67,7 +64,7 @@ public class CreateLauncherScriptAction extends AnAction {
|
||||
final File scriptFile = createLauncherScriptFile();
|
||||
final File scriptTarget = new File(pathName);
|
||||
if (scriptTarget.exists()) {
|
||||
int rc = Messages.showOkCancelDialog(project, "The file " + scriptTarget + " already exists. Would you like to overwrite it?",
|
||||
int rc = Messages.showOkCancelDialog(project, ApplicationBundle.message("launcher.script.overwrite", scriptTarget),
|
||||
"Create Launcher Script", Messages.getQuestionIcon());
|
||||
if (rc != 0) {
|
||||
return;
|
||||
@@ -79,94 +76,47 @@ public class CreateLauncherScriptAction extends AnAction {
|
||||
!scriptFile.renameTo(scriptTarget)) {
|
||||
final String launcherScriptContainingDirPath = launcherScriptContainingDir.getCanonicalPath();
|
||||
final String installationScriptSrc =
|
||||
"#!/bin/sh\n" +
|
||||
// create all intermediate folders
|
||||
"mkdir -p " + launcherScriptContainingDirPath + "\n" +
|
||||
// Copy file & change owner to root
|
||||
// uid 0 = root
|
||||
// gid 0 = root || wheel (MacOS)
|
||||
"install -g 0 -o 0 " + scriptFile.getCanonicalPath() + " " + pathName;
|
||||
final File installationScript = createTempExecutableScript("launcher_installer", installationScriptSrc);
|
||||
|
||||
sudo(installationScript.getCanonicalPath(),
|
||||
installationScriptSrc,
|
||||
"Please enter your password to create a launcher script in a " + launcherScriptContainingDirPath);
|
||||
"mkdir -p \"" + launcherScriptContainingDirPath + "\"\n" +
|
||||
// copy file and change ownership to root (UID 0 = root, GID 0 = root (wheel on Macs))
|
||||
"install -g 0 -o 0 \"" + scriptFile.getCanonicalPath() + "\" \"" + pathName + "\"";
|
||||
final File installationScript = ExecUtil.createTempExecutableScript("launcher_installer", ".sh", installationScriptSrc);
|
||||
ExecUtil.sudo(installationScript.getAbsolutePath(),
|
||||
ApplicationBundle.message("launcher.script.sudo.prompt", launcherScriptContainingDirPath));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(e);
|
||||
Messages.showErrorDialog(project, "Failed to create launcher script: " + e.getMessage(), "Create Launcher Script");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean sudo(final String installationScriptPath,
|
||||
final String installScriptSrc,
|
||||
final String prompt) throws IOException, ScriptException, ExecutionException {
|
||||
if (SystemInfo.isMac) {
|
||||
final ScriptEngine engine = new ScriptEngineManager(null).getEngineByName("AppleScript");
|
||||
if (engine == null) {
|
||||
throw new IOException("Could not find AppleScript engine");
|
||||
}
|
||||
engine.eval("do shell script \"" + installationScriptPath + "\" with administrator privileges");
|
||||
}
|
||||
else {
|
||||
GeneralCommandLine cmdLine = new GeneralCommandLine();
|
||||
if (SystemInfo.isGnome) {
|
||||
cmdLine.setExePath("gksudo");
|
||||
cmdLine.addParameters("--message", prompt);
|
||||
}
|
||||
else if (SystemInfo.isKDE) {
|
||||
cmdLine.setExePath("kdesudo");
|
||||
final String message = e.getMessage();
|
||||
if (!StringUtil.isEmptyOrSpaces(message)) {
|
||||
LOG.warn(e);
|
||||
Notifications.Bus.notify(
|
||||
new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Failed to create launcher script", message, NotificationType.ERROR),
|
||||
project
|
||||
);
|
||||
}
|
||||
else {
|
||||
Messages.showMessageDialog("Unsupported graphical environment. Please execute the following command from the shell:\n" + installScriptSrc,
|
||||
"Create Launcher Script",
|
||||
Messages.getInformationIcon());
|
||||
return true;
|
||||
LOG.error(e);
|
||||
}
|
||||
cmdLine.addParameter(installationScriptPath);
|
||||
cmdLine.createProcess();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static File createLauncherScriptFile() throws IOException {
|
||||
final File tempFile = FileUtil.createTempFile("launcher", "");
|
||||
|
||||
final InputStream stream = CreateLauncherScriptAction.class.getClassLoader().getResourceAsStream("launcher.py");
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
String launcherContents = FileUtil.loadTextAndClose(new InputStreamReader(stream));
|
||||
launcherContents = launcherContents.replace("$CONFIG_PATH$", PathManager.getConfigPath());
|
||||
|
||||
String homePath = PathManager.getHomePath();
|
||||
if (SystemInfo.isMac) {
|
||||
// Just use "*.app"
|
||||
launcherContents = launcherContents.replace("$RUN_PATH$", homePath);
|
||||
String runPath = PathManager.getHomePath();
|
||||
if (!SystemInfo.isMac) {
|
||||
// for Macs just use "*.app"
|
||||
final String productName = ApplicationNamesInfo.getInstance().getProductName().toLowerCase();
|
||||
runPath += "/bin/" + productName + ".sh";
|
||||
}
|
||||
else {
|
||||
String productName = ApplicationNamesInfo.getInstance().getProductName().toLowerCase();
|
||||
launcherContents = launcherContents.replace("$RUN_PATH$", homePath + "/bin/" + productName + ".sh");
|
||||
}
|
||||
|
||||
FileUtil.writeToFile(tempFile, launcherContents.getBytes(CharsetToolkit.UTF8_CHARSET));
|
||||
if (!tempFile.setExecutable(true)) {
|
||||
throw new IOException("Failed to mark the launcher script as executable");
|
||||
}
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
private static File createTempExecutableScript(final String fileNamePrefix,
|
||||
final String source) throws IOException {
|
||||
final File tempFile = FileUtil.createTempFile(fileNamePrefix, "");
|
||||
FileUtil.writeToFile(tempFile, source.getBytes(CharsetToolkit.UTF8_CHARSET));
|
||||
if (!tempFile.setExecutable(true)) {
|
||||
throw new IOException("Failed to mark the launcher installation script as executable: script path " + tempFile.getCanonicalPath());
|
||||
}
|
||||
return tempFile;
|
||||
final String launcherContents = ExecUtil.loadTemplate(CreateLauncherScriptAction.class.getClassLoader(), "launcher.py",
|
||||
hashMap(asList("$CONFIG_PATH$", "$RUN_PATH$"),
|
||||
asList(PathManager.getConfigPath(), runPath)));
|
||||
return ExecUtil.createTempExecutableScript("launcher", "", launcherContents);
|
||||
}
|
||||
|
||||
public static String defaultScriptName() {
|
||||
final String productName = ApplicationNamesInfo.getInstance().getScriptName();
|
||||
return StringUtil.isEmptyOrSpaces(productName) ? "idea" : productName;
|
||||
final String scriptName = ApplicationNamesInfo.getInstance().getScriptName();
|
||||
return StringUtil.isEmptyOrSpaces(scriptName) ? "idea" : scriptName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -532,6 +532,8 @@ auto.import=Auto Import
|
||||
checkbox.collapse.suppress.warnings=<html>@SuppressWarnings</html>
|
||||
checkbox.collapse.end.of.line.comments=<html>End of line comments sequence</html>
|
||||
title.other.languages=Other Languages
|
||||
launcher.script.overwrite=The file ''{0}'' already exists. Would you like to overwrite it?
|
||||
launcher.script.sudo.prompt=Please enter your password to create a launcher script in a ''{0}''
|
||||
desktop.entry.success=You may now exit {0} and start it from the system menu.
|
||||
desktop.entry.xdg.missing=Unfortunately, xdg-utils seem to be unavailable on your system.
|
||||
desktop.entry.icon.missing=Unable to locate suitable application icon in ''{0}''.
|
||||
|
||||
@@ -262,6 +262,12 @@ public class FileUtil {
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String loadTextAndClose(@NotNull InputStream stream) throws IOException {
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
return loadTextAndClose(new InputStreamReader(stream));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String loadTextAndClose(@NotNull Reader reader) throws IOException {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.util.system;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ExecUtil {
|
||||
private ExecUtil() { }
|
||||
|
||||
public static int execAndGetResult(final String... command) throws IOException, InterruptedException {
|
||||
assert command != null && command.length > 0;
|
||||
return execAndGetResult(Arrays.asList(command));
|
||||
}
|
||||
|
||||
public static int execAndGetResult(@NotNull final List<String> command) throws IOException, InterruptedException {
|
||||
assert command.size() > 0;
|
||||
final ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
final Process process = processBuilder.start();
|
||||
return process.waitFor();
|
||||
}
|
||||
|
||||
public static String loadTemplate(@NotNull final ClassLoader loader,
|
||||
@NotNull final String templateName,
|
||||
@Nullable final Map<String, String> variables) throws IOException {
|
||||
final InputStream stream = loader.getResourceAsStream(templateName);
|
||||
if (stream == null) {
|
||||
throw new IOException("Template '" + templateName + "' not found by " + loader);
|
||||
}
|
||||
|
||||
final StringBuilder template = new StringBuilder(FileUtil.loadTextAndClose(stream));
|
||||
if (variables != null) {
|
||||
for (Map.Entry<String, String> var : variables.entrySet()) {
|
||||
final String name = var.getKey();
|
||||
final int pos = template.indexOf(name);
|
||||
if (pos >= 0) {
|
||||
template.replace(pos, pos + name.length(), var.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return template.toString();
|
||||
}
|
||||
|
||||
public static File createTempExecutableScript(@NotNull final String prefix,
|
||||
@NotNull final String suffix,
|
||||
@NotNull final String source) throws IOException {
|
||||
final File tempFile = FileUtil.createTempFile(prefix, suffix);
|
||||
FileUtil.writeToFile(tempFile, source);
|
||||
if (!tempFile.setExecutable(true, true)) {
|
||||
throw new IOException("Failed to make temp file executable: " + tempFile);
|
||||
}
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
public static int sudo(@NotNull final String scriptPath,
|
||||
@NotNull final String prompt) throws IOException, ScriptException, InterruptedException {
|
||||
if (SystemInfo.isMac) {
|
||||
final ScriptEngine engine = new ScriptEngineManager(null).getEngineByName("AppleScript");
|
||||
if (engine == null) {
|
||||
throw new IOException("Could not find AppleScript engine");
|
||||
}
|
||||
engine.eval("do shell script \"" + scriptPath + "\" with administrator privileges");
|
||||
return 0;
|
||||
}
|
||||
else if (SystemInfo.isKDE) {
|
||||
return execAndGetResult("kdesudo", "--comment", prompt, scriptPath);
|
||||
}
|
||||
else if (SystemInfo.isGnome) {
|
||||
return execAndGetResult("gksudo", "--message", prompt, scriptPath);
|
||||
}
|
||||
else if (SystemInfo.isUnix) {
|
||||
final File sudo = createTempExecutableScript("sudo", ".sh",
|
||||
"#!/bin/sh\n" +
|
||||
"echo \"" + prompt + "\"\n" +
|
||||
"echo\n" +
|
||||
"sudo \"" + scriptPath + "\"\n" +
|
||||
"echo\n" +
|
||||
"read -p \"Press Enter to close this window...\" TEMP\n");
|
||||
return execAndGetResult("xterm", "-T", "Install", "-e", sudo.getAbsolutePath());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unsupported OS/desktop: " + System.getProperty("os.name") + '/' + SystemInfo.SUN_DESKTOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2011 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.
|
||||
@@ -23,6 +23,7 @@ import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
@@ -91,6 +92,18 @@ public class CollectionFactory {
|
||||
return Maps.newHashMap();
|
||||
}
|
||||
|
||||
public static <T, V> Map<T, V> hashMap(@NotNull final List<T> keys, @NotNull final List<V> values) {
|
||||
if (keys.size() != values.size()) {
|
||||
throw new IllegalArgumentException(keys + " should have some length as " + values);
|
||||
}
|
||||
|
||||
final HashMap<T,V> map = Maps.newHashMap();
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
map.put(keys.get(i), values.get(i));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <T, V> LinkedHashMap<T, V> linkedMap() {
|
||||
return Maps.newLinkedHashMap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user