Index: assemblies/features/framework/src/main/filtered-resources/resources/etc/org.apache.karaf.editor.cfg IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- assemblies/features/framework/src/main/filtered-resources/resources/etc/org.apache.karaf.editor.cfg (revision ) +++ assemblies/features/framework/src/main/filtered-resources/resources/etc/org.apache.karaf.editor.cfg (revision ) @@ -0,0 +1,25 @@ +################################################################################ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +################################################################################ + +# +# These properties are used to configure Karaf's text editor. +# + +editor = vi + Index: shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java (revision ) +++ shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java (revision ) @@ -0,0 +1,248 @@ +package org.apache.karaf.shell.commands.impl; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; +import java.net.URLConnection; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Pattern; +import jline.Terminal; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.console.AbstractAction; +import org.apache.karaf.util.StreamUtils; +import org.apache.sshd.common.util.NoCloseInputStream; +import org.apache.sshd.common.util.NoCloseOutputStream; + +@Command(scope = "shell", name = "edit", description = "Calls a native editor.") +public class EditAction extends AbstractAction { + + @Argument(index = 0, name = "url", description = "The url of the resource to edit.", required = true, multiValued = false) + private String url; + + private String editor; + private final Pattern urlPattern = Pattern.compile("[^: ]+:[^ ]+"); + + @Override + protected Object doExecute() throws Exception { + URLConnection connection = null; + InputStream is = null; + OutputStream os = null; + String path = null; + boolean isLocal = true; + + //If no url format found, assume file url. + if (!urlPattern.matcher(url).matches()) { + File f = new File(url); + url = "file://" + f.getAbsolutePath(); + } + + URL u = new URL(url); + + //If its not a file url. + if (!u.getProtocol().equals("file")) { + isLocal = false; + + try { + connection = u.openConnection(); + is = connection.getInputStream(); + } catch (IOException ex) { + System.out.println("Failed to open " + url + " for reading."); + return null; + } + try { + os = connection.getOutputStream(); + } catch (IOException ex) { + System.out.println("Failed to open " + url + " for writing."); + return null; + } + + //Copy the resource to a tmp location. + FileOutputStream fos = null; + try { + path = System.getProperty("karaf.data") + "/editor/" + UUID.randomUUID(); + File f = new File(path); + if (!f.exists()) { + if (!f.getParentFile().exists()) { + f.getParentFile().mkdirs(); + } + } + + fos = new FileOutputStream(f); + copy(is, fos); + } catch (Exception ex) { + System.out.println("Failed to copy resource from url:" + url + " to tmp file: " + path + " for editing."); + } finally { + StreamUtils.close(fos); + } + } else { + path = u.getFile(); + } + + + File file = new File(path); + if (!file.exists()) { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + } + + Terminal terminal = getTerminal(); + ProcessBuilder builder = new ProcessBuilder(editor, file.getAbsolutePath()); + builder.environment().put("COLUMNS", String.valueOf(terminal.getWidth())); + builder.environment().put("LINES", String.valueOf(terminal.getHeight())); + Process p = builder.start(); + OutputStreamWriter outWriter = new OutputStreamWriter(new NoCloseOutputStream(System.out)); + InputStreamReader inReader = new InputStreamReader(new NoCloseInputStream(session.getKeyboard())); + adapt(p, inReader, outWriter); + + Object terminalObject = session.get(".jline.terminal"); + if (terminalObject instanceof Terminal) { + ((Terminal) terminalObject).reset(); + } + + //If resource is not local, copy the resource back. + if (!isLocal) { + FileInputStream fis = new FileInputStream(path); + try { + copy(fis, os); + } finally { + StreamUtils.close(fis); + } + } + + if (is != null) { + StreamUtils.close(is); + } + + if (os != null) { + StreamUtils.close(os); + } + + + + return null; + } + + /** + * Gets the {@link Terminal} from the current {@link CommandSession}. + * + * @return + * @throws Exception + */ + private Terminal getTerminal() throws Exception { + Object terminalObject = session.get(".jline.terminal"); + if (terminalObject instanceof Terminal) { + return (Terminal) terminalObject; + + } + throw new IllegalStateException("Could not get Terminal from CommandSession."); + } + + /** + * Adapts the {@link Process} to the current shell. + * + * @param process + * @param reader + * @param out + */ + private void adapt( + Process process, + final Reader reader, + final Writer out) { + + final BufferedReader in = new BufferedReader(reader); + final BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream())); + final BufferedWriter stdIn = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); + + Runnable rOut = new Runnable() { + @Override + public void run() { + int c; + try { + while ((c = stdOut.read()) > 0) { + out.write(c); + out.flush(); + } + } catch (Exception e) { + throw new Error(e); + } + try { + out.flush(); + out.close(); + } catch (IOException e) { + //ignore + } + } + }; + + Runnable rIn = new Runnable() { + @Override + public void run() { + char c; + try { + while ((c = (char) in.read()) > 0) { + if (c == 8 || c == 127) { + stdIn.write(8); + } else { + stdIn.write(c); + } + stdIn.flush(); + } + } catch (Exception e) { + throw new Error(e); + } + + try { + stdIn.flush(); + stdIn.close(); + } catch (IOException e) { + //ignore + } + } + }; + + ExecutorService executorService = Executors.newFixedThreadPool(3); + executorService.submit(rIn); + executorService.submit(rOut); + try { + process.waitFor(); + + } catch (Exception e) { + throw new Error(e); + } finally { + executorService.shutdownNow(); + StreamUtils.close(stdIn, stdOut); + } + } + + private void copy(final InputStream input, final OutputStream output) throws IOException { + byte[] buffer = new byte[1024 * 16]; + int n = 0; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + output.flush(); + } + } + + + public String getEditor() { + return editor; + } + + public void setEditor(String editor) { + this.editor = editor; + } +} Index: shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml (revision 08715571e0fe23e10cd2d73f7f9b20ac8695637a) +++ shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml (revision ) @@ -17,8 +17,17 @@ limitations under the License. --> - + + + + + + + @@ -96,6 +105,11 @@ + + + + +